【问题标题】:LLVM/Clang special case for allocators分配器的 LLVM/Clang 特殊情况
【发布时间】:2013-10-21 11:57:45
【问题描述】:

如果你在“alloc.c”中有如下代码:

typedef __typeof__(sizeof(int)) size_t;

extern void *calloc (size_t __nmemb, size_t __size)
  __attribute__ ((__nothrow__ )) __attribute__ ((__malloc__)) ;
extern void free (void *__ptr) __attribute__ ((__nothrow__ ));

struct _astruct {
  int l;
};


int main() {
  struct _astruct *f = (struct _astruct*)calloc(1, sizeof(struct _astruct));
  f->l = 99;
  int x = f->l;
  free(f);
  return x;
}

(我知道这不是声明 calloc/free 的首选方式,但它是为了简化下面的输出。)

然后你用 Clang/LLVM 3.3 运行“clang -O3 -S -emit-llvm alloc.c”,你会得到:

; ModuleID = 'alloc.c'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind readnone uwtable
define i32 @main() #0 {
entry:
  ret i32 99
}

attributes #0 = { nounwind readnone uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }

您可以看到它完全消除了对 calloc 的调用。惊人的。但是,一般来说,编译器不能消除对它没有源的函数的调用(可能有副作用)。因此,Clang 似乎有 calloc/free 的特殊情况代码。支持这一点的事实是,如果您将代码中所有出现的“calloc”更改为“_calloc”,“分配”就会返回。

所以我的问题是,是否有任何方法可以告诉 Clang/LLVM 某个特定函数是“仅分配”函数?也许我可以在我自己的一个函数的定义上添加一些注释,这将允许 LLVM 优化分配,就像它对 calloc/malloc 一样。

【问题讨论】:

    标签: c compiler-construction clang llvm


    【解决方案1】:

    有没有办法告诉 Clang/LLVM 一个特定的函数是一个“仅分配”函数?

    不。正如您所说的那样,在一般情况下,只有编译器有权访问其实现*,才能消除调用。对 calloc 的支持在 LLVM 中是硬编码的(请参阅 LLVM 的“MemoryBuiltins”和“TargetLibraryInfo”类),这就是在您的示例中消除调用的方式。

    没有属性向编译器发出信号表明某个函数将尝试分配内存。


    *:如果函数被标记为绝对没有可能的副作用,那么它是可能的,但是目前没有办法在 LLVM 中标记这样的东西,请参阅this related discussion;无论如何,分配内存的函数肯定会产生副作用。

    【讨论】:

      【解决方案2】:

      在头文件中很明显——就是calloc声明中的“attribute((malloc))”。整件事说“这个函数从不抛出异常,它返回一个用新的 malloc 调用分配的指针”。这允许进行多项优化:

      1. 保证返回的指针不是任何其他指针的别名。如果你有两个指针 int* p 和 int* q,那么 *p = 1; 可能改变 *q。如果 p 或 q 刚刚被分配了一个不会发生的 malloc 函数。

      2. 如果编译器找到匹配的 free() 调用,则编译器有时可以在堆栈上分配数据并消除 malloc 和 free 调用。

      【讨论】:

      • 来自问题:“如果您将代码中所有出现的“calloc”更改为“_calloc”,“分配”就会返回。 attribute ((malloc)) 是 GCC 的东西。
      猜你喜欢
      • 1970-01-01
      • 2012-07-13
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 2011-02-02
      • 2020-12-29
      • 1970-01-01
      相关资源
      最近更新 更多