LLVM error: invalid redefinition of function

LLVM error: invalid redefinition of function

我正在为伪代码语言编写 LLVM IR 生成器。这种语言应该允许重新定义功能。

这是一个例子,我有两个函数都命名为 "f" 但它们有不同的参数。

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

我认为 LLVM 可以区分这一点,但我得到

error: invalid redefinition of function

我生成的代码是:

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
}

所以,我认为 LLVM 不允许函数重载?那么我生成一个顺序计数器并通过添加这个顺序计数器作为后缀来区分所有这些函数是个好主意,即 define i32 @f.1()define i32 @f.2()?

你说得对,LLVM IR 没有函数重载。

根据您的语言代码的组织方式,使用顺序计数器可能不是一个好主意。如果您只是分配递增的整数,那么在不同文件的编译中这些可能不是确定性的。例如,在 C++ 中,您可能会想像

// 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); }

在编译 user.cpp 时,编译器无法知道被引用的 f 实际上会被命名为 f.2.

实现函数重载的典型方法是使用 name mangling,以某种方式将函数的类型签名编码到它的名称中,以便它在存在重载时是唯一的。

我的生成器是用java写的,所以每次解析函数定义时,如果函数名已经存在于范围table,我会增加相同函数名的计数器.

我的table是用Map定义的,以函数名为键,函数def列表为值:

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

然后构造函数将如下所示:

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