LLVM内在函数
使用LLVM构建项目时,一些函数调用将被内在函数替换。更换是由前端(如clang)还是LLVM后端完成的 通过互联网进行的讨论表明,内在函数替换与优化选项有关。那么,这是否意味着如果没有优化选项,那么就不会发生内在替代?或者事实上,存在一些无法禁用的默认内在函数LLVM内在函数,llvm,Llvm,使用LLVM构建项目时,一些函数调用将被内在函数替换。更换是由前端(如clang)还是LLVM后端完成的 通过互联网进行的讨论表明,内在函数替换与优化选项有关。那么,这是否意味着如果没有优化选项,那么就不会发生内在替代?或者事实上,存在一些无法禁用的默认内在函数 如果有任何方法可以禁用所有的内在函数,我应该怎么做?这取决于具体情况。用代码编写的内部函数直接通过前端发出。诸如llvm.memset之类的内部函数在IR级别的优化过程中被引入到代码中(前端和后端都执行此优化) 下面是一个(相当愚蠢的)
如果有任何方法可以禁用所有的内在函数,我应该怎么做?这取决于具体情况。用代码编写的内部函数直接通过前端发出。诸如llvm.memset之类的内部函数在IR级别的优化过程中被引入到代码中(前端和后端都执行此优化) 下面是一个(相当愚蠢的)例子:
int main(int argc, char** argv)
{
int a[8];
for (int i = 0; i != 8; ++i)
a[i] = 0;
for (int i = 7; i >= 0; --i)
a[i] = a[i+1] + argc;
return a[0];
}
使用clang3.5(clang-S-emit llvm)编译后,您将获得以下IR,而不需要任何内部函数:
; Function Attrs: nounwind uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i8**, align 8
%a = alloca [8 x i32], align 16
%i = alloca i32, align 4
%i1 = alloca i32, align 4
store i32 0, i32* %1
store i32 %argc, i32* %2, align 4
store i8** %argv, i8*** %3, align 8
store i32 0, i32* %i, align 4
br label %4
; <label>:4 ; preds = %11, %0
%5 = load i32* %i, align 4
%6 = icmp ne i32 %5, 8
br i1 %6, label %7, label %14
; <label>:7 ; preds = %4
%8 = load i32* %i, align 4
%9 = sext i32 %8 to i64
%10 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 %9
store i32 0, i32* %10, align 4
br label %11
; <label>:11 ; preds = %7
%12 = load i32* %i, align 4
%13 = add nsw i32 %12, 1
store i32 %13, i32* %i, align 4
br label %4
; <label>:14 ; preds = %4
store i32 7, i32* %i1, align 4
br label %15
; <label>:15 ; preds = %29, %14
%16 = load i32* %i1, align 4
%17 = icmp sge i32 %16, 0
br i1 %17, label %18, label %32
; <label>:18 ; preds = %15
%19 = load i32* %i1, align 4
%20 = add nsw i32 %19, 1
%21 = sext i32 %20 to i64
%22 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 %21
%23 = load i32* %22, align 4
%24 = load i32* %2, align 4
%25 = add nsw i32 %23, %24
%26 = load i32* %i1, align 4
%27 = sext i32 %26 to i64
%28 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 %27
store i32 %25, i32* %28, align 4
br label %29
; <label>:29 ; preds = %18
%30 = load i32* %i1, align 4
%31 = add nsw i32 %30, -1
store i32 %31, i32* %i1, align 4
br label %15
; <label>:32 ; preds = %15
%33 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 0
%34 = load i32* %33, align 4
ret i32 %34
}
初始化循环已被llvm.memset内部文件替换。后端可以随意处理内部函数,但通常llvm.memset会降低为libc库调用
回答您的第一个问题:是的,如果您不优化您的代码,那么您将无法在IR中获得内部函数
为了防止在代码中引入内部函数,您所要做的就是在IR上找到优化传递,而不要运行它。下面是一个相关的问题,如何找出在IR上进行了哪些传递:
对于-O1
,我们得到:
prune eh-内联成本-始终内联-函数trs-sroa-domtree
-早期cse-惰性值信息-跳转线程-相关传播-SimpleCfg-instcombine-tailcallelim-SimpleCfg-reassociate-domtree-循环-循环简化-lcssa-循环旋转-licm-循环取消开关-instcombine-标量进化-lcssa-indvars-循环习惯用法-循环删除-循环展开-memdep-memcpyopt-sccp-instcombine-惰性值信息-跳转线程-相关传播-domtree-memdep-dse-adce-SimpleCfg-instcombine-barrier-domtree-循环-循环简化-lcssa-分支问题-块频率-标量演化-循环向量化-instcombine-SimpleCfg-带死原型-验证
猜测:instcombine正在引入llvm.memset。我在不使用instcombine的情况下运行通行证,并选择未优化的IR,得到以下结果:
; Function Attrs: nounwind readnone uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
%a = alloca [8 x i32], align 16
%1 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 8
%2 = load i32* %1, align 4
%3 = add nsw i32 %2, %argc
%4 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 7
store i32 %3, i32* %4, align 4
%5 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 7
%6 = load i32* %5, align 4
%7 = add nsw i32 %6, %argc
%8 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 6
store i32 %7, i32* %8, align 4
%9 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 6
%10 = load i32* %9, align 4
%11 = add nsw i32 %10, %argc
%12 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 5
store i32 %11, i32* %12, align 4
%13 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 5
%14 = load i32* %13, align 4
%15 = add nsw i32 %14, %argc
%16 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 4
store i32 %15, i32* %16, align 4
%17 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 4
%18 = load i32* %17, align 4
%19 = add nsw i32 %18, %argc
%20 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 3
store i32 %19, i32* %20, align 4
%21 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 3
%22 = load i32* %21, align 4
%23 = add nsw i32 %22, %argc
%24 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 2
store i32 %23, i32* %24, align 4
%25 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 2
%26 = load i32* %25, align 4
%27 = add nsw i32 %26, %argc
%28 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 1
store i32 %27, i32* %28, align 4
%29 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 1
%30 = load i32* %29, align 4
%31 = add nsw i32 %30, %argc
%32 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 0
store i32 %31, i32* %32, align 4
%33 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 0
%34 = load i32* %33, align 4
ret i32 %34
}
没有指示。因此,为了防止(至少是memset)代码中的内部函数,不要在IR上运行instcombine。然而,instcombine是一个强大的opt pass,它确实缩短了代码
现在您有两个选择:
我希望这对你有所帮助。干杯 clang 5即使使用-O0@TongZhou这将是伟大的一个例子,内在的叮当声5+
; Function Attrs: nounwind readnone uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
%a = alloca [8 x i32], align 16
%1 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 8
%2 = load i32* %1, align 4
%3 = add nsw i32 %2, %argc
%4 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 7
store i32 %3, i32* %4, align 4
%5 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 7
%6 = load i32* %5, align 4
%7 = add nsw i32 %6, %argc
%8 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 6
store i32 %7, i32* %8, align 4
%9 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 6
%10 = load i32* %9, align 4
%11 = add nsw i32 %10, %argc
%12 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 5
store i32 %11, i32* %12, align 4
%13 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 5
%14 = load i32* %13, align 4
%15 = add nsw i32 %14, %argc
%16 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 4
store i32 %15, i32* %16, align 4
%17 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 4
%18 = load i32* %17, align 4
%19 = add nsw i32 %18, %argc
%20 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 3
store i32 %19, i32* %20, align 4
%21 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 3
%22 = load i32* %21, align 4
%23 = add nsw i32 %22, %argc
%24 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 2
store i32 %23, i32* %24, align 4
%25 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 2
%26 = load i32* %25, align 4
%27 = add nsw i32 %26, %argc
%28 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 1
store i32 %27, i32* %28, align 4
%29 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 1
%30 = load i32* %29, align 4
%31 = add nsw i32 %30, %argc
%32 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 0
store i32 %31, i32* %32, align 4
%33 = getelementptr inbounds [8 x i32]* %a, i32 0, i64 0
%34 = load i32* %33, align 4
ret i32 %34
}