2015-06-12 3 views
6

Ich bin gespannt, ob der Swift 1.2 Compiler leere Closures optimiert. Sind die folgenden zwei Aussagen äquivalent?Optimiert der Swift-Compiler leere Verschlüsse?

1:

self.presentViewController(alertController, animated: true) {} 

2:

self.presentViewController(alertController, animated: true, completion: nil) 

Dank!

+0

Dunno sicher selbst, aber Sie könnten herausfinden, indem Sie auf die generierte Baugruppe in Xcode. – rickster

+0

Ich bin nicht sicher, dass dies eine gültige Optimierung wäre. 1 ist ein Verschluss, der nichts tut, während 2 keinen Verschluss anzeigt. Kein Abschluss könnte "Standardverhalten verwenden" bedeuten, aber ein leerer Abschluss bedeutet "tue nichts", was nicht unbedingt dasselbe ist. – Ferruccio

Antwort

5

Als @rickster vorgeschlagen hatte ich einen Blick auf die erzeugte x86 Montage dieser Datei (simple.swift):

func thingWithClosure(a: Int, b: (() -> Void)?) { 
    println(a) 
    b?() 
} 


thingWithClosure(3) { 
    println("i'm a closure") 
} 

thingWithClosure(5, nil) 

thingWithClosure(2) {} 

Meine Montage ziemlich rostig ist, aber ich kann ein bisschen es ein bisschen schielen. ..

der .main Abschnitt der nicht optimierte x86-Assembler erzeugt oder zumindest ein Teil davon, sieht wie folgt aus:

callq _swift_once 
    movq __TZvO[email protected]GOTPCREL(%rip), %rax 
    movq -64(%rbp), %rcx 
    movq %rcx, (%rax) 
    leaq l_metadata+16(%rip), %rdi 
    movl $32, %r9d 
    movl %r9d, %eax 
    movl $7, %r9d 
    movl %r9d, %edx 
    movq %rax, %rsi 
    movq %rdx, -80(%rbp) 
    movq %rax, -88(%rbp) 
    callq _swift_allocObject 
    leaq __TF6simpleU_FT_T_(%rip), %rcx 
    movq %rcx, 16(%rax) 
    movq $0, 24(%rax) 
    leaq __TPA__TTRXFo__dT__XFo_iT__iT__(%rip), %rcx 
    movq %rcx, -16(%rbp) 
    movq %rax, -8(%rbp) 
    movq -16(%rbp), %rsi 
    movl $3, %r9d 
    movl %r9d, %edi 
    movq %rax, %rdx 
     --> callq __TF6simple16thingWithClosureFTSiGSqFT_T___T_ 
    movq $0, -24(%rbp) 
    movq $0, -32(%rbp) 
    movl $5, %r9d 
    movl %r9d, %edi 
    movq -72(%rbp), %rsi 
    movq -72(%rbp), %rdx 
     --> callq __TF6simple16thingWithClosureFTSiGSqFT_T___T_ 
    leaq l_metadata2+16(%rip), %rdi 
    movq -88(%rbp), %rsi 
    movq -80(%rbp), %rdx 
    callq _swift_allocObject 
    leaq __TF6simpleU0_FT_T_(%rip), %rcx 
    movq %rcx, 16(%rax) 
    movq $0, 24(%rax) 
    leaq __TPA__TTRXFo__dT__XFo_iT__iT__3(%rip), %rcx 
    movq %rcx, -48(%rbp) 
    movq %rax, -40(%rbp) 
    movq -48(%rbp), %rsi 
    movl $2, %r9d 
    movl %r9d, %edi 
    movq %rax, %rdx 
     --> callq __TF6simple16thingWithClosureFTSiGSqFT_T___T_ 
    xorl %eax, %eax 
    addq $96, %rsp 
    popq %rbp 
    retq 
    .cfi_endproc 

ich habe darauf hingewiesen, wo die Funktion mit 012.391.031 aufgerufen. Wenn Sie sich einige Anweisungen von jeder callq Anweisung ansehen, können Sie sehen, wo das a Argument in das r9d Register verschoben wird.

Auch die optimierte Ausgabe:

callq _swift_once 
    movq __TZvO[email protected]GOTPCREL(%rip), %rax 
    movq %r14, (%rax) 
    movq $3, -24(%rbp) 
    movq [email protected](%rip), %rbx 
    addq $8, %rbx 
    leaq -24(%rbp), %rdi 
    movq %rbx, %rsi 
    callq __TFSs7printlnU__FQ_T_ 
    leaq L___unnamed_1(%rip), %rax 
    movq %rax, -48(%rbp) 
    movq $13, -40(%rbp) 
    movq $0, -32(%rbp) 
    movq [email protected](%rip), %rsi 
    addq $8, %rsi 
    leaq -48(%rbp), %rdi 
     --> callq __TFSs7printlnU__FQ_T_ 
    movq $5, -56(%rbp) 
    leaq -56(%rbp), %rdi 
    movq %rbx, %rsi 
     --> callq __TFSs7printlnU__FQ_T_ 
    movq $2, -64(%rbp) 
    leaq -64(%rbp), %rdi 
    movq %rbx, %rsi 
     --> callq __TFSs7printlnU__FQ_T_ 
    xorl %eax, %eax 
    addq $48, %rsp 
    popq %rbx 
    popq %r14 
    popq %rbp 
    retq 
    .cfi_endproc 

Hier hat der Compiler die Funktion inlined, also habe ich stattdessen die println Anrufe mit --> hingewiesen.

Ich nahm ein Intro zu x86 Assembly mit einer emulierten 16-Bit-CPU vor Jahren, so werde ich nicht tun, ich weiß genau, was hier vor sich geht, aber es scheint mir, wenn kompiliert mit -O, der Compiler gibt ungefähr gleichwertigen Code aus (in Bezug auf die Befehlsanzahl, aber möglicherweise nicht im Hinblick auf Speicher-Look-Ups usw.). Es scheint, als wären die Aufrufe an println mit leaq (load effektive Adresse) Anweisungen durchsetzt, so dass wir überall springen könnten, aber ich bin mir nicht sicher, wo (könnte mehr Anweisungen sein? Könnte statische Daten laden?), Oder wenn es darauf ankommt.

Die nicht optimierte Version gibt merklich mehr Anweisungen für den nil-Parameter case, so dass der Hauptunterschied Debug-Leistung sein kann.

Natürlich ist das x86, also kann es auf ARM ganz anders sein .... Vielleicht würden die ARM-Assembly, LLVM IR oder Swift IR-Ausgänge mehr Licht abgeben?

Wenn jemand mit einem besseren Verständnis klären kann, werde ich gerne diese Antwort aktualisieren.