2016-05-01 8 views
8

LLVM के साथ इस कोड संकलन जबकि:LLVM struct सरणी यात्रा

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; 
} 

किसी कारण संकलक एक अजीब तरीके से इस सरणी के माध्यम से पुनरावृति करने का फैसला करता है। सबसे पहले यह मध्य में या संरचना के अंत में पर एक मनमाना बिंदु का चयन करता है और उसके बाद उपयुक्त मानों को मनमाने ढंग से बिंदु के सापेक्ष तत्काल के साथ संग्रहीत करता है।

मुझे पता चला है कि मनमाने बिंदु इस आईआर कोड से चयन किया जाता है:

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

कहाँ 4 char3 की ऑफसेट है।

इस उदाहरण में int1, INT2, char1, char2 नकारात्मक immediates होगा के लिए दुकान, char3 होगा तत्काल 0.

ऐसा लगता है कि struct बार के विभिन्न व्यवस्था में आपकी अलग ऑफसेट अंदर या कम से मिलता है, लेकिन हमेशा संरचना का अंत

उदाहरण के लिए struct बार बदल रहा है के लिए:

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

निम्नलिखित आईआर लाइन के साथ परिणाम होगा:

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

जिसका मतलब है कि char1, char2 और चार 3 के लिए दुकान नकारात्मक immediates होगा, int1 में तत्काल 0 होगा, और int2 के पास तत्काल सकारात्मक होगा।

यह एक बिंदु के सापेक्ष फिर से संरचना का आधार क्यों है?

+0

पढ़ें http://llvm.org/docs/GetElementPtr.html –

+0

'scev' स्केलर विकास के लिए खड़ा है। मुझे नहीं पता कि यह अनुकूलन क्यों होता है, लेकिन आप वहां से शुरू कर सकते हैं। –

+1

क्या आप अपने बिल्ड विकल्प और पूरे llvm ir पोस्ट कर सकते हैं? कम से कम स्टोर हिस्से के लिए? –

उत्तर

1

क्लैंग का एक हालिया निर्माण getelementptr निर्देश का वर्णन नहीं करता है जो आप वर्णन करते हैं। यह सामान्य अनुक्रमण का उपयोग करता है।

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 यह उत्पादन खुश हूँ: अजीब बात यह है unrolled पाश के शरीर में दो बार के साथ एक संस्करण का उत्पादन होता है , लेकिन मैं निर्देश के नाम पर आधारित अनुमान नहीं लेना चाहता हूं।