为什么LLVM语言中有一些内在函数?

Hon*_*hen 10 llvm clang

我发现LLVM中有一些内在函数,比如llvm.memcpy,llvm.va_start.

但是我不知道为什么它们存在以及为什么其他人不存在.例如,由于memcpy原型是在里面string.h,为什么其他功能,例如strcpy,不被视为内在的?

我注意到在某些情况下前端可能会生成特殊的内部函数调用.对于一个简单的案例:

#include<string.h>

int foo(void){
    char str[10] = "str";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

fooclang生成的llvm IR 是:

define i32 @foo() #0 {
entry:
  %str = alloca [10 x i8], align 1
  %0 = bitcast [10 x i8]* %str to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* getelementptr inbounds ([10 x i8]* @foo.str, i32 0, i32 0), i64 10, i32 1, i1 false)
  ret i32 0
}
Run Code Online (Sandbox Code Playgroud)

llvm.memcpy在IR中调用,但不在源代码中.但前端是否可以在没有此内在函数的情况下生成LLVM IR?

我还隔着一个文件是约的LLVM语言参考更早的版本,发现一些特殊的功能,例如malloc,free被纳入LLVM指令(很明显,他们不再存在).

那么llvm指令的设计是什么?

Mat*_*son 5

当然,你可以在没有 memcpy 的情况下做你的例子所展示的 - 只是有点难(好吧,也许不是只有 4 个字节,这可以在四个单字节移动中完成,不比 memcpy 难多少 - 另一方面,如果你初始化 str 的字符串是 128 个字节[并且str足够长以容纳它],128 个单字节移动的序列会相当笨拙,并且生成循环也有点笨拙)。

然而,内在函数的要点是允许编译器(后端)“理解发生了什么”,因为它将能够确定[至少对于常量]副本的大小,例如,生成两个将"str"值存储到str变量中的32 位移动。或者,如果数量很大,请调用 real memcpy,或为中间大小创建一个循环。

最后,简单的答案是“因为编译器可以生成比替代解决方案更好的代码”。

strcpy我猜,NOT 的原因是strcpy可以用memcpyfor 常量字符串替换(更有效),如果字符串不是常量,strcpy则比memcpy无论如何都要复杂一些,因此对进行内联优化并不有益.

从理论上讲,所有类型的功能都可以成为内在的,但必须进行“成本/收益”分析——您获得了多少,以及编写代码需要多长时间才能做到这一点。

[当然,我只是从我使用 LLVM 的经验中推断出来的,我不知道在 LLVM 中实现内在函数的人]

  • 没有 strcpy 的另一个原因是它仅对以空字符结尾的 C 样式字符串有用。LLVM 不仅适用于 C,许多其他语言(例如 Fortran、C++)往往更喜欢已知长度的字符串,memcpy 对此更有效。 (2认同)
  • 本质上只是一个“将常量存储到 str[0..3]”的序列。 (2认同)