LLVM / Clang分配器的特例

时间:2013-10-13 23:16:24

标签: c compiler-construction clang llvm

如果“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一样。

2 个答案:

答案 0 :(得分:5)

  

有没有办法告诉Clang / LLVM特定功能是“仅限分配”功能?

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

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


*:如果函数被标记为绝对没有可能的副作用,那么可能是有可能的,但目前无法在LLVM中标记这样的内容,请参阅this related discussion;在任何情况下,分配内存的函数当然都会产生副作用。

答案 1 :(得分:-1)

在头文件中很明显 - 它是calloc声明中的“属性((malloc))”。整个事情说“这个函数永远不会抛出异常,它返回一个用新的malloc调用分配的指针”。这允许多种优化:

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

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