2016-05-01 16 views
8

LLVMでこのコードをコンパイルしている間:コンパイラは奇妙な方法でこの配列を反復処理することを決定したいくつかの理由LLVM構造体配列の繰り返し

struct bar { 
    int int1; 
    int int2; 
    char char1; 
    char char2; 
    char char3; 
}; 


struct foo { 
    struct bar array[16]; 
}; 


int func(struct foo *f, int num) { 

    for(int i = 0; i < num; i++){ 
     f->array[i].int1 = 1; 
     f->array[i].int2 = 2; 
     f->array[i].char1 = 'a'; 
     f->array[i].char2 = 'b';   
     f->array[i].char3 = 'c';   
    } 
    return num; 
} 

。 最初に構造体の中央または終わりの一見した任意の点を選択し、 とし、任意の点を基準にして適切な値を即座に格納します。

Iは、任意の点は、このIRコードから選択されていることが判明:4 char3オフセットさ

%scevgep = getelementptr %struct.foo* %f, i32 0, i32 0, i32 0, i32 4 

。 INT1、INT2、CHAR1のためにこの例では

店、CHAR2が負の即値を持つことになり、char3が即時0

を持っています構造体のバーの異なる配置で、あなたがたが、常に内部またはで異なるオフセットを取得しているようです構造体の終わりです。以下のIRラインとなります

struct bar { 
    char char1; 
    char char2; 
    char char3; 
    int int1; 
    int int2; 
}; 

:に構造体のバーを変更たとえば

CHAR1、CHAR2チャー3のための店が負の即値を持っていることを意味し
%scevgep = getelementptr %struct.foo* %f, i32 0, i32 0, i32 0, i32 3 

、 int1は直ちに0を持ち、int2は正の即値を持ちます。

構造体のベース以外の点を基準に反復処理を行うのはなぜですか?

+0

http://llvm.org/docs/GetElementPtr.htmlを参照してください。 –

+0

「scev」はスカラー進化を表します。なぜこの最適化が起こるのかは分かりませんが、そこから始めることができます。 –

+1

ビルドオプションとllvm ir全体を投稿できますか?少なくとも店舗の部分は? –

答えて

1

Clangの最近のビルドでは、あなたが記述するgetelementptr命令が生成されません。通常の索引付けを使用します。それがない奇妙なものが二回アンロールループの本体でバージョンを作成することです:あなたは、あなたの質問は、あなたが見たIRを再現するための手順で更新した場合

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 
target triple = "x86_64-unknown-linux-gnu" 

%struct.foo = type { [16 x %struct.bar] } 
%struct.bar = type { i32, i32, i8, i8, i8 } 

define i32 @func(%struct.foo* nocapture %f, i32 %num) { 
entry: 
    %cmp25 = icmp sgt i32 %num, 0 
    br i1 %cmp25, label %for.body.preheader, label %for.cond.cleanup 

for.body.preheader:        ; preds = %entry 
    %xtraiter = and i32 %num, 1 
    %0 = icmp eq i32 %num, 1 
    br i1 %0, label %for.cond.cleanup.loopexit.unr-lcssa, label %for.body.preheader.new 

for.body.preheader.new:       ; preds = %for.body.preheader 
    %unroll_iter = sub i32 %num, %xtraiter 
    br label %for.body 

for.cond.cleanup.loopexit.unr-lcssa.loopexit:  ; preds = %for.body 
    %indvars.iv.next.1.lcssa = phi i64 [ %indvars.iv.next.1, %for.body ] 
    br label %for.cond.cleanup.loopexit.unr-lcssa 

for.cond.cleanup.loopexit.unr-lcssa:    ; preds = %for.cond.cleanup.loopexit.unr-lcssa.loopexit, %for.body.preheader 
    %indvars.iv.unr = phi i64 [ 0, %for.body.preheader ], [ %indvars.iv.next.1.lcssa, %for.cond.cleanup.loopexit.unr-lcssa.loopexit ] 
    %lcmp.mod = icmp eq i32 %xtraiter, 0 
    br i1 %lcmp.mod, label %for.cond.cleanup.loopexit, label %for.body.epil.preheader 

for.body.epil.preheader:       ; preds = %for.cond.cleanup.loopexit.unr-lcssa 
    br label %for.body.epil 

for.body.epil:         ; preds = %for.body.epil.preheader 
    %int1.epil = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.unr, i32 0 
    store i32 1, i32* %int1.epil, align 4, !tbaa !1 
    %int2.epil = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.unr, i32 1 
    store i32 2, i32* %int2.epil, align 4, !tbaa !6 
    %char1.epil = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.unr, i32 2 
    store i8 97, i8* %char1.epil, align 4, !tbaa !7 
    %char2.epil = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.unr, i32 3 
    store i8 98, i8* %char2.epil, align 1, !tbaa !8 
    %char3.epil = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.unr, i32 4 
    store i8 99, i8* %char3.epil, align 2, !tbaa !9 
    br label %for.cond.cleanup.loopexit.epilog-lcssa 

for.cond.cleanup.loopexit.epilog-lcssa:   ; preds = %for.body.epil 
    br label %for.cond.cleanup.loopexit 

for.cond.cleanup.loopexit:      ; preds = %for.cond.cleanup.loopexit.unr-lcssa, %for.cond.cleanup.loopexit.epilog-lcssa 
    br label %for.cond.cleanup 

for.cond.cleanup:         ; preds = %for.cond.cleanup.loopexit, %entry 
    ret i32 %num 

for.body:           ; preds = %for.body, %for.body.preheader.new 
    %indvars.iv = phi i64 [ 0, %for.body.preheader.new ], [ %indvars.iv.next.1, %for.body ] 
    %niter = phi i32 [ %unroll_iter, %for.body.preheader.new ], [ %niter.nsub.1, %for.body ] 
    %int1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv, i32 0 
    store i32 1, i32* %int1, align 4, !tbaa !1 
    %int2 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv, i32 1 
    store i32 2, i32* %int2, align 4, !tbaa !6 
    %char1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv, i32 2 
    store i8 97, i8* %char1, align 4, !tbaa !7 
    %char2 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv, i32 3 
    store i8 98, i8* %char2, align 1, !tbaa !8 
    %char3 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv, i32 4 
    store i8 99, i8* %char3, align 2, !tbaa !9 
    %indvars.iv.next = or i64 %indvars.iv, 1 
    %int1.1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.next, i32 0 
    store i32 1, i32* %int1.1, align 4, !tbaa !1 
    %int2.1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.next, i32 1 
    store i32 2, i32* %int2.1, align 4, !tbaa !6 
    %char1.1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.next, i32 2 
    store i8 97, i8* %char1.1, align 4, !tbaa !7 
    %char2.1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.next, i32 3 
    store i8 98, i8* %char2.1, align 1, !tbaa !8 
    %char3.1 = getelementptr inbounds %struct.foo, %struct.foo* %f, i64 0, i32 0, i64 %indvars.iv.next, i32 4 
    store i8 99, i8* %char3.1, align 2, !tbaa !9 
    %indvars.iv.next.1 = add nsw i64 %indvars.iv, 2 
    %niter.nsub.1 = add i32 %niter, -2 
    %niter.ncmp.1 = icmp eq i32 %niter.nsub.1, 0 
    br i1 %niter.ncmp.1, label %for.cond.cleanup.loopexit.unr-lcssa.loopexit, label %for.body 
} 

、私はLLVMは、それを生成した理由を説明して満足していますしかし、私は命令の名前に基づいて推測したくありません。