2012-02-05 5 views
17

私が打ち鳴らすは、次の2つの方法のために異なるコードを放出している理由として少し混乱している:なぜこれらの単純な方法は異なる方法でコンパイルされますか?

@interface ClassA : NSObject 
@end 

@implementation ClassA 
+ (ClassA*)giveMeAnObject1 { 
    return [[ClassA alloc] init]; 
} 
+ (id)giveMeAnObject2 { 
    return [[ClassA alloc] init]; 
} 
@end 

我々は放出されたARMv7を見ればARCを有効にして、我々は、O3で、これを参照してください。

 .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject1]" 
"+[ClassA giveMeAnObject1]": 
     push {r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
     mov  r7, sp 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_0: 
     add  r1, pc 
LPC0_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC0_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC0_2+4)) 
LPC0_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r7, lr} 
     b.w  _objc_autorelease 

     .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject2]" 
"+[ClassA giveMeAnObject2]": 
     push {r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     mov  r7, sp 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
LPC2_0: 
     add  r1, pc 
LPC2_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
LPC2_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

の相違点は、objc_autoreleaseReturnValueobjc_autoreleaseの末尾の呼び出しです。私は両方ともobjc_autoreleaseReturnValueと正直に電話すると期待します。事実、objc_autoreleaseReturnValueを使用しない最初の方法は、ARCがサポートされている場合に実行できるこの冗長な呼び出しのより高速なバイパスではなく、自動解放となり、発信者による保持が確実に行われるため、ランタイム

define internal %1* @"\01+[ClassA giveMeAnObject1]"(i8* nocapture %self, i8* nocapture %_cmd) { 
    %1 = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_", align 4 
    %2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 4 
    %3 = bitcast %struct._class_t* %1 to i8* 
    %4 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %3, i8* %2) 
    %5 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2", align 4 
    %6 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %4, i8* %5) 
    %7 = tail call i8* @objc_autorelease(i8* %6) nounwind 
    %8 = bitcast i8* %6 to %1* 
    ret %1* %8 
} 

define internal i8* @"\01+[ClassA giveMeAnObject2]"(i8* nocapture %self, i8* nocapture %_cmd) { 
    %1 = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_", align 4 
    %2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 4 
    %3 = bitcast %struct._class_t* %1 to i8* 
    %4 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %3, i8* %2) 
    %5 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2", align 4 
    %6 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %4, i8* %5) 
    %7 = tail call i8* @objc_autoreleaseReturnValue(i8* %6) nounwind 
    ret i8* %6 
} 

しかし、私は異なっこれら二つのメソッドをコンパイルすることを決めている理由を参照するのに苦労しています:

放出されるLLVMは、それはそのようなものだ理由のいくつかの種類を提供します。誰かがそれに光を当てることはできますか?これらの他の方法され

がさえ奇妙:

+ (ClassA*)giveMeAnObject3 { 
    ClassA *a = [[ClassA alloc] init]; 
    return a; 
} 

+ (id)giveMeAnObject4 { 
    ClassA *a = [[ClassA alloc] init]; 
    return a; 
} 

これらはにコンパイルします。

更新

 .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject3]" 
"+[ClassA giveMeAnObject3]": 
     push {r4, r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     add  r7, sp, #4 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
LPC2_0: 
     add  r1, pc 
LPC2_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
LPC2_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     blx  _objc_retainAutoreleasedReturnValue 
     mov  r4, r0 
     mov  r0, r4 
     blx  _objc_release 
     mov  r0, r4 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

     .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject4]" 
"+[ClassA giveMeAnObject4]": 
     push {r4, r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC3_0+4)) 
     add  r7, sp, #4 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC3_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC3_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC3_1+4)) 
LPC3_0: 
     add  r1, pc 
LPC3_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC3_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC3_2+4)) 
LPC3_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     blx  _objc_retainAutoreleasedReturnValue 
     mov  r4, r0 
     mov  r0, r4 
     blx  _objc_release 
     mov  r0, r4 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

今回、それらが同一であるしかしこれは可能性がいくつかありますここでさらに最適化してください:

  1. mov r4, r0に冗長性があり、その後にが続きます。

  2. リテンションの後にリリースがあります。

確かに、これらのメソッドの両方の下のビットがになることができます:私たちは実際に、それ以上にそれを壊していないので、明らかに私たちは、その後もr4をポップ省略することができ

LPC3_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

。その後、メソッドは正確に私たちが期待するものであるgiveMeAnObject2と同じに変わります。

なぜクラングは巧妙ではなく、これをやっているのですか?

+0

奇数、はい。異なる最適化レベルを試しましたか? -Os?いずれにしても、バグを報告してください(ここに#を投稿してください)。 – bbum

+0

私はさまざまな最適化レベルを試しましたが、報告するのに特別なものは何もありません。私はまだもう少しそれを介して作業する必要がありますが。まあ、私はバグを提出するだろうが、実際にバグであることを確認したい。私は非常に奇妙ですが、単純なものを見逃しているかもしれません。 – mattjgalloway

+0

@bbum - 実際には、私は嘘をついた。 'O0'はやや面白いです。ケース1とケース2は同じになります。明らかにテールコールの最適化やそのようなものはありません。だから、テールコールを最適化するのとは何かが関係していると思います。 – mattjgalloway

答えて

5

これはオプティマイザのバグであり、rdar:// problem/10813093として追跡されています。

+0

素晴らしいです。私を見てくれてありがとう!確かに奇妙なものです! – mattjgalloway

関連する問題