Pointers 什么';在LLVM程序集中递归的正确方法是什么?

Pointers 什么';在LLVM程序集中递归的正确方法是什么?,pointers,recursion,assembly,llvm,Pointers,Recursion,Assembly,Llvm,这是我的全部计划;我正在使用一个愚蠢的递归算法来熟悉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

这是我的全部计划;我正在使用一个愚蠢的递归算法来熟悉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作为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程序集不需要指针作为其参数。

我甚至不知道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
}

我甚至不知道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
}

与高级语言不同,LLVM指令不能由复合表达式组成。所以这不是一个有效的指令:

ret i32 @rec_add(i32 %tmp2, i32 %tmp3)
您可以执行
ret
call
,但不能同时执行这两项操作*。您在这里实际编写的内容是试图返回函数的地址,当然这不是
i32
,因此类型错误。相反,您需要执行以下操作:

%something = call i32 @rec_add(i32 %tmp2, i32 %tmp3)
ret i32 %something



*如果是的话,你可以做复合的东西,但这里不是这样。

与高级语言不同,LLVM指令不能由复合表达式组成。所以这不是一个有效的指令:

ret i32 @rec_add(i32 %tmp2, i32 %tmp3)
您可以执行
ret
call
,但不能同时执行这两项操作*。您在这里实际编写的内容是试图返回函数的地址,当然这不是
i32
,因此类型错误。相反,您需要执行以下操作:

%something = call i32 @rec_add(i32 %tmp2, i32 %tmp3)
ret i32 %something



*如果是的话,你可以做复合的东西,但这里不是这样。

我不知道LLVM汇编,但你确定你不需要在那里调用
,可能是另一个语句?否则,它看起来像是在试图返回函数,除非通过指针间接返回,否则无法返回。@RossRidge:IDK LLVM asm,但如果没有一个临时命令,它似乎无法正常工作,并且对代码生成没有不良影响。对于缺少的
调用
,捕捉得很好。我同意OP的语法可能试图返回函数指针。我不知道LLVM程序集,但您确定不需要在其中调用
调用
,可能是另一个语句?否则,它看起来像是在试图返回函数,除非通过指针间接返回,否则无法返回。@RossRidge:IDK LLVM asm,但如果没有一个临时命令,它似乎无法正常工作,并且对代码生成没有不良影响。对于缺少的
调用
,捕捉得很好。我同意OP的语法可能试图返回函数指针。如果我删除变量并将
ret i32 0
(return 0)添加到末尾,我的
main
将编译。向下投票是因为尽管这是正确的,但您的术语和解释是关闭的,这可能会令人困惑<代码>%tmp不是临时的,它是一个指令-不管怎样,问题在于同时使用
ret
调用
,而不是缺少“使用临时的”,请参见我的答案。@Oak:感谢术语更正。尝试和错误并不是我回答问题的通常依据:如果我删除变量并在末尾添加
ret i32 0
(返回0),PMy
main
将编译。尽管这是正确的,但您的术语和解释是错误的,这可能会让人困惑<代码>%tmp不是临时的,它是一个指令-不管怎样,问题在于同时使用
ret
调用
,而不是缺少“使用临时的”,请参见我的答案。@Oak:感谢术语更正。尝试和错误并不是我回答问题的通常依据:P