特に次のコードがある場合:
func sum(n: Int, acc: Int) -> Int {
if n == 0 { return acc }
else { return sum(n - 1, acc + n) }
}
Swiftコンパイラーはそれをループに最適化しますか?そして、以下のより興味深いケースでそうしますか?
func isOdd(n: Int) -> Bool {
if n == 0 { return false; }
else { return isEven(n - 1) }
}
func isEven(n: Int) -> Bool {
if n == 0 { return true }
else { return isOdd(n - 1) }
}
チェックする最善の方法は、コンパイラーによって生成されたアセンブリー言語コードを調べることです。上記のコードを取得してコンパイルしました:
Swift -O3 -S tco.Swift >tco.asm
出力の関連部分
.globl __TF3tco3sumFTSiSi_Si
.align 4, 0x90
__TF3tco3sumFTSiSi_Si:
pushq %rbp
movq %rsp, %rbp
testq %rdi, %rdi
je LBB0_4
.align 4, 0x90
LBB0_1:
movq %rdi, %rax
decq %rax
jo LBB0_5
addq %rdi, %rsi
jo LBB0_5
testq %rax, %rax
movq %rax, %rdi
jne LBB0_1
LBB0_4:
movq %rsi, %rax
popq %rbp
retq
LBB0_5:
ud2
.globl __TF3tco5isOddFSiSb
.align 4, 0x90
__TF3tco5isOddFSiSb:
pushq %rbp
movq %rsp, %rbp
testq %rdi, %rdi
je LBB1_1
decq %rdi
jo LBB1_9
movb $1, %al
LBB1_5:
testq %rdi, %rdi
je LBB1_2
decq %rdi
jo LBB1_9
testq %rdi, %rdi
je LBB1_1
decq %rdi
jno LBB1_5
LBB1_9:
ud2
LBB1_1:
xorl %eax, %eax
LBB1_2:
popq %rbp
retq
.globl __TF3tco6isEvenFSiSb
.align 4, 0x90
__TF3tco6isEvenFSiSb:
pushq %rbp
movq %rsp, %rbp
movb $1, %al
LBB2_1:
testq %rdi, %rdi
je LBB2_5
decq %rdi
jo LBB2_7
testq %rdi, %rdi
je LBB2_4
decq %rdi
jno LBB2_1
LBB2_7:
ud2
LBB2_4:
xorl %eax, %eax
LBB2_5:
popq %rbp
retq
生成されたコードには呼び出し命令はなく、条件付きジャンプ(je
/jne
/jo
/jno
)のみがあります。これは、Swiftがbothの場合に末尾呼び出しの最適化を行うことを明確に示唆しています。
さらに、isOdd
/isEven
関数は、コンパイラがTCOを実行するように見えるだけでなく、それぞれの場合に他の関数をインライン化するという点で興味深いです。
はい、Swiftコンパイラは、場合によっては末尾呼び出しの最適化を実行します。
func sum(n: Int, acc: Int) -> Int {
if n == 0 { return acc }
else { return sum(n - 1, acc: acc + 1) }
}
グローバル関数として、これは「最速」最適化レベル(-O
)。
構造体内にある場合、一定のスタックスペースを使用します。ただし、クラス内では、メソッドは実行時にオーバーライドされる可能性があるため、コンパイラはtcoを実行しません。
ClangはObjective-Cのtcoもサポートしますが、多くの場合、ARCは再帰呼び出しの後にrelease
を呼び出し、この最適化を防ぎます。詳細については この記事のJonathon Mah を参照してください。
ARCはSwiftのTCOを防ぐようにも思われます:
func sum(n: Int, acc: Int, s: String?) -> Int {
if n == 0 { return acc }
else { return sum(n - 1, acc + 1, s) }
}
私のテストではTCOは実行されませんでした。