这是我的整个计划;我使用愚蠢的递归算法来熟悉LLVM汇编:
declare void @print_int(i32)
define i32 @rec_add(i32 %a, i32 %b) {
entry:
%tmp1 = icmp eq i32 %a, 0
br i1 %tmp1, label %done, label %recurse
recurse:
%tmp2 = sub i32 %a, 1
%tmp3 = add i32 %b, 1
ret i32 @rec_add(i32 %tmp2, i32 %tmp3)
done:
ret i32 %b
}
define i32 @main() {
%tmp4 = i32 4;
%tmp5 = i32 1;
%cast = call i32 @rec_add(i32 %tmp4, i32 %tmp5)
call void @print_int(i32 %cast)
}
当我使用$ llvm-as rec_add.ll
编译此程序时,收到此错误消息:
llvm-as: rec_add.ll:10:11: error: global variable reference must have pointer type
ret i32 @rec_add(i32 %tmp2, i32 %tmp3)
^
我不明白这个错误消息的含义,因为我的程序没有全局变量。我知道LLVM程序集不需要指针作为其参数。
答案 0 :(得分:2)
与高级语言不同,LLVM指令不能由复合表达式组成。所以这不是一个有效的指令:
ret i32 @rec_add(i32 %tmp2, i32 %tmp3)
您可以ret
或call
,而不是同时执行* {。你在这里写的是试图返回函数的地址 - 当然不是i32
,因此类型错误。相反,你需要做类似的事情:
%something = call i32 @rec_add(i32 %tmp2, i32 %tmp3)
ret i32 %something
*如果那些是constant expressions,你可以做复合的东西,但这不是这里的情况。
答案 1 :(得分:1)
我甚至不知道llvm存在,但是将递归调用结果赋给变量工作。然后回来。即使在-O0
,这也会优化。有关正确的术语,请参阅Oak的答案/评论。
define i32 @rec_add(i32 %a, i32 %b) {
entry:
%tmp1 = icmp eq i32 %a, 0
br i1 %tmp1, label %done, label %recurse
recurse:
%tmp2 = sub i32 %a, 1
%tmp3 = add i32 %b, 1
%tmp4 = call i32 @rec_add(i32 %tmp2, i32 %tmp3)
ret i32 %tmp4
done:
ret i32 %b
}
使用clang-3.8 -O0 -S -o-
编译递归调用。
使用clang-3.8 -Wall -O3 rec-add.ll -S -masm=intel -o-
,llvm会看到递归:
rec_add: # @rec_add
# BB#0: # %entry
lea eax, [rdi + rsi]
ret
您的main
无法编译:
rec-add.ll:17:13: error: expected instruction opcode
%tmp4 = i32 4;
这就是诀窍:
define i32 @main() {
%cast = call i32 @rec_add(i32 4, i32 1)
call void @print_int(i32 %cast)
ret i32 0
}