8

「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 -O3 -S -emit-llvm alloc.c次に、Clang/LLVM 3.3 で" " を実行すると、次のようになります。

; 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に伝える方法はありますか? おそらく、calloc/malloc の場合と同様に、LLVM が割り当てを最適化できるようにする独自の関数の 1 つの定義に注釈を付けることができます。

4

2 に答える 2

-1

これはヘッダー ファイルで明らかです。calloc の宣言の" attribute ((malloc)) " です。全体として、「この関数は決して例外をスローせず、新しい malloc 呼び出しで割り当てられたポインターを返します」と書かれています。これにより、いくつかの最適化が可能になります。

  1. 返されるポインタは、他のポインタのエイリアスではないことが保証されています。int* p と int* q の 2 つのポインターがある場合、*p = 1; 変わるかもしれません*q. p または q が malloc 関数で新しく割り当てられた場合、これは発生しません。

  2. コンパイラが一致する free () 呼び出しを見つけた場合、コンパイラはデータをスタックに割り当て、malloc 呼び出しと free 呼び出しの両方を排除できる場合があります。

于 2014-02-23T21:07:56.760 に答える