我发现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指令的设计是什么?
当然,你可以在没有 memcpy 的情况下做你的例子所展示的 - 只是有点难(好吧,也许不是只有 4 个字节,这可以在四个单字节移动中完成,不比 memcpy 难多少 - 另一方面,如果你初始化 str 的字符串是 128 个字节[并且str足够长以容纳它],128 个单字节移动的序列会相当笨拙,并且生成循环也有点笨拙)。
然而,内在函数的要点是允许编译器(后端)“理解发生了什么”,因为它将能够确定[至少对于常量]副本的大小,例如,生成两个将"str"值存储到str变量中的32 位移动。或者,如果数量很大,请调用 real memcpy,或为中间大小创建一个循环。
最后,简单的答案是“因为编译器可以生成比替代解决方案更好的代码”。
strcpy我猜,NOT 的原因是strcpy可以用memcpyfor 常量字符串替换(更有效),如果字符串不是常量,strcpy则比memcpy无论如何都要复杂一些,因此对进行内联优化并不有益.
从理论上讲,所有类型的功能都可以成为内在的,但必须进行“成本/收益”分析——您获得了多少,以及编写代码需要多长时间才能做到这一点。
[当然,我只是从我使用 LLVM 的经验中推断出来的,我不知道在 LLVM 中实现内在函数的人]
| 归档时间: |
|
| 查看次数: |
2942 次 |
| 最近记录: |