2
votes

I'm writing a LLVM IR generator for a pseudo code language. This language should allow redefinition of function.

Here is one case that I have two functions both named "f" but they have different parameters.

function f(int i, float r) returns int { return i; }
function f(float r, float r2) returns int {return i; } 

I thought LLVM could distinct that, but I get

error: invalid redefinition of function

And the code I generated is:

define i32 @f(i32 %i, float %r) {
    %var.i.0 = alloca i32
    store i32 %i, i32* %var.i.0
    %var.r.1 = alloca float
    store float %r, float* %var.r.1
    %int.2 = load i32* %var.i.0
    ret i32 %int.2
    ; -- 0 :: i32
    %int.3 = add i32 0, 0

    ret i32 %int.3
}

define i32 @f(float %r, float %r2) {
    %var.r.2 = alloca float
    store float %r, float* %var.r.2
    %var.r2.3 = alloca float
    store float %r2, float* %var.r2.3
    %var.i.4 = alloca i32
    %float.3 = load float* %var.r.2
    %int.7 = fptosi float %float.3 to i32
    store i32 %int.7, i32* %var.i.4
    %int.8 = load i32* %var.i.4
    ret i32 %int.8
    ; -- 0 :: i32
    %int.9 = add i32 0, 0

    ret i32 %int.9
}

So, I think LLVM do not allow function overloading? Then is it a good idea that I generate a sequential counter, and distinct all these functions by adding this sequential counter as a suffix i.e define i32 @f.1() and define i32 @f.2()?

2
I'm doing the same for a dynamically typed language and I've taken to generating function signatures as @modulename_functionname_xyz where xy encodes the arity. In your case you could encode the type. E.g. @foo.f_if and @foo.f_ff. - Frank C.
@FrankC. I'm thinking changing this thing later, but for now I'll keep it differentiated by counter, since I'm not the only person who work on this thing. - RandomEli

2 Answers

3
votes

You're correct that LLVM IR doesn't have function overloading.

Using a sequential counter is probably not a good idea depending on how code in your language is organized. If you're just assigning incrementing integers, those may not be deterministic across the compilation of different files. For example, in C++, you might imagine something like

// library.cpp
int f(int i, float r) { ... }
int f(float r, float r2) { ... }

// user.cpp
extern int f(float r, float r2);
int foo() { return f(1.0, 2.0); }

When compiling user.cpp, there would be no way for the compiler to know that the f being referenced will actually be named f.2.

The typical way to implement function overloading is to use name mangling, somehow encoding the type signature of the function into its name so that it'll be unique in the presence of overloads.

1
votes

My generator was written in java, so every time I parse a function definition, I will increase the counter for the same function name if the function name has already existed in the scope table.

My table is defined by Map with function name as key, and a list of function def as value:

Map<String,ArrayList<functionSymbol>> = new HashMap<>();

and then the constructor will look like:

static int counter = 0;
public FunctionSymbol(String functionName, Type retType,  List<Variable> paramList){
     this.functionName = functionName+counter;
     this.paramList = paramList;
     this.retType = retType;
     counter++;
}