LLVM内在函数

LLVM内在函数,llvm,Llvm,使用LLVM构建项目时,一些函数调用将被内在函数替换。更换是由前端(如clang)还是LLVM后端完成的 通过互联网进行的讨论表明,内在函数替换与优化选项有关。那么,这是否意味着如果没有优化选项,那么就不会发生内在替代?或者事实上,存在一些无法禁用的默认内在函数 如果有任何方法可以禁用所有的内在函数,我应该怎么做?这取决于具体情况。用代码编写的内部函数直接通过前端发出。诸如llvm.memset之类的内部函数在IR级别的优化过程中被引入到代码中(前端和后端都执行此优化) 下面是一个(相当愚蠢的)

使用LLVM构建项目时,一些函数调用将被内在函数替换。更换是由前端(如clang)还是LLVM后端完成的

通过互联网进行的讨论表明,内在函数替换与优化选项有关。那么,这是否意味着如果没有优化选项,那么就不会发生内在替代?或者事实上,存在一些无法禁用的默认内在函数


如果有任何方法可以禁用所有的内在函数,我应该怎么做?

这取决于具体情况。用代码编写的内部函数直接通过前端发出。诸如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,它确实缩短了代码

现在您有两个选择:

  • 不要使用引入内部函数的opt过程
  • 编写自己的llvm 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
    }