Clang 为什么在LLVM语言中有一些内在的东西?
我发现在中有一些内在函数,例如Clang 为什么在LLVM语言中有一些内在的东西?,clang,llvm,Clang,Llvm,我发现在中有一些内在函数,例如llvm.memcpy,llvm.va_start 然而,我不知道他们为什么存在,为什么其他人不存在。例如,由于memcpy的原型在string.h中,为什么其他函数,如strcpy,不被视为内在函数 我注意到前端在某些情况下可能会生成特殊的内在函数调用。对于一个简单的情况: #include<string.h> int foo(void){ char str[10] = "str"; return 0; } llvm.memcpy在
llvm.memcpy
,llvm.va_start
然而,我不知道他们为什么存在,为什么其他人不存在。例如,由于memcpy
的原型在string.h
中,为什么其他函数,如strcpy
,不被视为内在函数
我注意到前端在某些情况下可能会生成特殊的内在函数调用。对于一个简单的情况:
#include<string.h>
int foo(void){
char str[10] = "str";
return 0;
}
llvm.memcpy
在IR中调用,但不在源代码中。但是,前端能否在没有这种内在特性的情况下生成LLVM IR
我还看到了一篇关于的文档,发现一些特殊函数,如malloc
,free
,包含在LLVM指令中(显然它们已经不存在了)
那么,llvm指令的设计理念是什么呢?具有内在功能使得扩展llvm更容易,从而利用硬件的功能来执行专门的操作,否则这些操作必须在软件中进行编码 在某些CPU类型中,某些操作(如将数据从一个位置复制到另一个位置)可以完全由硬件执行,但在另一些CPU类型中,必须作为正常功能进行编码 使用这些内在函数允许LLVM输出对内在函数的调用,然后(由编码器)将内在函数转换为目标处理器最有效的形式——专用机器指令或对实际函数的调用 理论上,您可以使用单独的特殊IR指令来覆盖所有这些情况,但是这并不是很容易扩展的。随着时间的推移,必须创建的指令数量将显著增加 它说,在未来 几乎所有对LLVM的扩展都应该作为一个内在函数开始,然后在保证的情况下转换为一条指令
当然,您可以在没有memcpy的情况下完成示例中显示的操作-只是稍微难一点(好吧,可能不是只有4个字节,这可以通过四个单字节移动完成,比memcpy难不了多少-另一方面,如果您初始化str的字符串是128字节[并且
str
足够长以容纳它],一个128个单字节移动的序列将相当笨拙,生成循环也有点笨拙)
但是,内部函数的要点是允许编译器(后端)“理解发生了什么”,因为它将能够确定[至少对于常数]副本的大小,例如,生成两个32位移动,以将“str”
值存储到str
变量中。或者,如果金额较大,请调用realmemcpy
,或对中间大小进行循环
最后,简单的答案是“因为编译器可以生成比其他解决方案更好的代码”
我猜没有strcpy
的原因是strcpy
可以(更有效地)替换为memcpy
用于常量字符串,如果字符串不是常量,strcpy
比memcpy
要复杂一点,因此对字符串进行内联优化没有那么大的好处
从理论上讲,所有类型的功能都是固有的,但这是必须进行的“成本/收益”分析——您获得了多少收益,以及编写代码需要多长时间才能做到这一点
[当然,我只是从我使用LLVM的经验中推断出这一点,我从在LLVM中实现内在函数的人那里不知道这一点]不使用strcpy的另一个原因是它只对以null结尾的C样式字符串有用。LLVM不仅适用于C,许多其他语言(如Fortran、C++)倾向于使用已知长度的字符串,memcpy更有效。非常感谢!你能告诉我如果没有
llvm.memcpy
(伪)IR会是什么样子吗?本质上就是一个“将常量存储到str[0..3]中”的序列。
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
}