2016-11-24 9 views
0

Я пишу генератор LLVM IR для языка псевдокодов. Этот язык должен позволить переопределить функцию.Ошибка LLVM: неверное переопределение функции

Вот один случай, когда у меня есть две функции с именем «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 не допускают перегрузку функции? Тогда хорошая идея, что я генерирую последовательный счетчик и выделяю все эти функции, добавляя этот последовательный счетчик в качестве суффикса i.e define i32 @f.1() и define i32 @f.2()?

+0

Я m сделать то же самое для динамически типизированного языка, и я взял генерацию сигнатур функций как '@ modulename_functionname_xyz', где' xy' кодирует arity. В вашем случае вы можете кодировать тип. Например. @ foo.f_if и @ foo.f_ff. –

+0

@FrankC. Я собираюсь изменить эту вещь позже, но пока я буду ее дифференцировать с помощью счетчика, так как я не единственный человек, который работает над этим. –

ответ

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, каким-то образом кодируя сигнатуру типа функции в свое имя, чтобы она была уникальной при наличии перегрузок.

+0

Вы правы, я забыл, что библиотека времени выполнения также может иметь функции с тем же именем. –

1

Мой генератор был написан в java, поэтому каждый раз, когда я разбираю определение функции, я увеличиваю счетчик для того же имени функции, если имя функции уже существует в таблице областей.

Моя таблица определяется по карте с именем функции в качестве ключа, и список функций опр в качестве значения:

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++; 
}