Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swiftのスタック変数とCPUレジスタの関係を読み解いた
Search
rikusouda
September 07, 2019
Programming
2
2.4k
Swiftのスタック変数とCPUレジスタの関係を読み解いた
iOSDC Japan 2019 でお話ししたLTです。
rikusouda
September 07, 2019
Tweet
Share
More Decks by rikusouda
See All by rikusouda
SwiftとCPUレジスタ
rikusouda
2
650
OSSを育てながらiOSアプリでパンくずリストを実現した
rikusouda
2
5.2k
fastlaneはともだち こわくないよ
rikusouda
1
1k
Other Decks in Programming
See All in Programming
マイコンでもRustのtestがしたい/KernelVM Kansai 11
tnishinaga
0
880
Vibe Coding の話をしよう
schroneko
14
3.8k
Golangci-lint v2爆誕: 君たちはどうすべきか
logica0419
1
250
データベースの技術選定を突き詰める ~複数事例から考える最適なデータベースの選び方~
nnaka2992
0
440
KANNA Android の技術的課題と取り組み
watabee
1
470
Road to Ruby for A Linguistics Nerd
hayat01sh1da
PRO
0
190
「理解」を重視したAI活用開発
fast_doctor
0
300
VibeCoding時代のエンジニアリング
daisuketakeda
0
170
VitestのIn-Source Testingが便利
taro28
8
2.4k
生成AI時代のフルスタック開発
kenn
4
460
generative-ai-use-cases(GenU)の推しポイント ~2025年4月版~
hideg
1
390
Orleans + Sekiban + SignalR でリアルタイムWeb作ってみた
tomohisa
0
240
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
790
Gamification - CAS2011
davidbonilla
81
5.3k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
700
Java REST API Framework Comparison - PWX 2021
mraible
31
8.6k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
160
15k
Building Adaptive Systems
keathley
41
2.5k
How to Ace a Technical Interview
jacobian
276
23k
KATA
mclloyd
29
14k
Done Done
chrislema
184
16k
Visualization
eitanlees
146
16k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Transcript
SwiftͷελοΫมͱ CPUϨδελͷؔΛ ಡΈղ͍ͨ 2019/09/07 iOSDC Japan 2019 LT @rikusouda #iosdc
#a
ࣗݾհ • @rikusouda (٢Ԭ༞थ) • גࣜձࣾGunosy ͜ΕͷJ04ΞϓϦ࡞͍ͬͯΔ
ϨΠϠʔ͖ • جຊใٕज़ऀࢼݧͷݴޠ ΞηϯϒϥΛબͨ͠ • iOSΞϓϦ։ൃͷલC++Ͱ WindowsΞϓϦ։ൃ͍ͯͨ͠
SwiftͷϨδελར༻͕ؾʹͳΔ • WWDC16#416ΑΓɺܕϩʔΧ ϧมελοΫϝϞϦΛ͏ • ࣮ߦ࣌Ϩδελ͏͔ΒɺϝϞ Ϧͷॻ͖ࠐΈলུͰ͖Δ?
Tips:ϨδελͬͯԿ? • CPUʹ͋ΔϝϞϦΈ͍ͨͳͷ • Ξηϯϒϥ(࣮ߦϑΝΠϧ)͕͏ • ϝϞϦΑΓઈߴ • ͨͩ͠ઈখ༰ྔ
SwiftͷϨδελར༻͕ؾʹͳͬ ͨ • WWDC16#416ΑΓɺܕϩʔΧ ϧมελοΫϝϞϦΛ͏ • ࣮ߦ࣌Ϩδελ͏͔ΒɺϝϞ Ϧͷॻ͖ࠐΈলུͰ͖Δ?
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } Λฦ͢
func doAnExperiment() -> Int { var variable = twofold(100) variable
+= 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } ࡐͷSwiftίʔυ ͜ͷWBSJBCMFɺϝϞϦʹ ॻ͖ࠐ·ͳͯ͘ྑ͍ͱࢥͬͨ ϨδελͰࣄΓΔͷͰ
ίϯύΠϥͷίʔυΛ ಡΊΘ͔ΔΒ͍͠
ͰίϯύΠϥΘ͔Βͳ͍ • C++͍ͬͯͯίϯύΠϥ Θ͔ΔΘ͚͡Όͳ͍ • ௐΔ·Ͱͷϋʔυϧ͕ߴͦ ͏
ௐ͖͔͚ͨͬ
None
WWDC19ʹߦ͖ͬͯͨ • ॳΊͯWWDCʹߦͬͨ • WWDCͰLabͱ͍͏ͱ͜ΖͰ AppleͷΤϯδχΞʹ࣭Ͱ͖Δ
ࣗͰௐͳͯ͘ ͑Θ͔ΔͷͰ
WWDCͷLabͰฉ͍ͯΈͨ • CݴޠͰͷ͑ฉ͚͚ͨͲɺ SwiftͰͷ͑ฉ͚ͳ͔ͬͨ • LLVM IRͱ͔ΞηϯϒϥಡΉͱ ͍Ζ͍ΖΘ͔Δͱฉ͍ͨ
Tips: LLVM IRͬͯԿ? • ࣮ߦϑΝΠϧ(Ξηϯϒϥ)ʹͳΔ Ұาखલͷதؒදݱ • BitcodeʹରԠ͢Διʔείʔυ
WWDCͷLabͰฉ͍ͯΈͨ • CݴޠͰͷ͑ฉ͚͚ͨͲɺ SwiftͰͷ͑ฉ͚ͳ͔ͬͨ • LLVM IRͱ͔ΞηϯϒϥಡΉͱ ͍Ζ͍ΖΘ͔Δͱฉ͍ͨ
LLVM IRΞηϯϒϥΛग़ྗ͠ ͯಡΉํ๏Λख΄Ͳ͖ͯ͘͠Ε ͨ (ͨͩ͠CݴޠΛݩʹͯ͠)
ͳΜ͔Ͱ͖ͦ͏ͳ ؾ࣋ͪʹͳΓ·ͨ͠
͖ͬ͞ͷSwiftͷ LLVM IRΛಡΜͰΈΑ͏
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }
func doAnExperiment() -> Int { var variable = twofold(100) variable
+= 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } ࡐͷSwiftίʔυ swiftc -emit-ir register.swift > register.ll
LLVM IRίʔυ define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() #0 { entry:
%0 = alloca %TSi, align 8 %1 = bitcast %TSi* %0 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false) %2 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* %2) %3 = call swiftcc i64 @"$s8register7twofoldyS2iF"(i64 100) %._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 %3, i64* %._value, align 8 %4 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 1000) %5 = extractvalue { i64, i1 } %4, 0 %6 = extractvalue { i64, i1 } %4, 1 br i1 %6, label %9, label %7 ; <label>:7: ; preds = %entry %._value1 = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 %5, i64* %._value1, align 8 %8 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.end.p0i8(i64 8, i8* %8) ret i64 %5 ; <label>:9: ; preds = %entry call void @llvm.trap() unreachable }
ͬͺΓ͍͠
ݕࡧΛۦͯ͠ղಡ
LLVM IRίʔυ define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() #0 { entry:
%0 = alloca %TSi, align 8 %1 = bitcast %TSi* %0 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false) %2 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* %2) %3 = call swiftcc i64 @"$s8register7twofoldyS2iF"(i64 100) %._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 %3, i64* %._value, align 8 %4 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 1000) %5 = extractvalue { i64, i1 } %4, 0 %6 = extractvalue { i64, i1 } %4, 1 br i1 %6, label %9, label %7 ; <label>:7: ; preds = %entry %._value1 = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 %5, i64* %._value1, align 8 %8 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.end.p0i8(i64 8, i8* %8) ret i64 %5 ; <label>:9: ; preds = %entry call void @llvm.trap() unreachable }
LLVM IRίʔυ: ݕࡧͷྗ func doAnExperiment() -> Int { let cpu
= CPU.shared cpu.r0 = alloca() cpu.r3 = twofold(100) store(cpu.r3, address: cpu.r0) cpu.r5 = cpu.r3 + 1000 store(cpu.r5, address: cpu.r0) return cpu.r5 }
LLVM IRίʔυ: ݕࡧͷྗ func doAnExperiment() -> Int { let cpu
= CPU.shared cpu.r0 = alloca() cpu.r3 = twofold(100) store(cpu.r3, address: cpu.r0) cpu.r5 = cpu.r3 + 1000 store(cpu.r5, address: cpu.r0) return cpu.r5 } BMMPDBϝϞϦ ελοΫ Λ֬อ͠ ͦͷྖҬͷΞυϨεΛฦ͢
LLVM IRίʔυ: ݕࡧͷྗ func doAnExperiment() -> Int { let cpu
= CPU.shared cpu.r0 = alloca() cpu.r3 = twofold(100) store(cpu.r3, address: cpu.r0) cpu.r5 = cpu.r3 + 1000 store(cpu.r5, address: cpu.r0) return cpu.r5 }
LLVM IRίʔυ: ݕࡧͷྗ func doAnExperiment() -> Int { let cpu
= CPU.shared cpu.r0 = alloca() cpu.r3 = twofold(100) store(cpu.r3, address: cpu.r0) cpu.r5 = cpu.r3 + 1000 store(cpu.r5, address: cpu.r0) return cpu.r5 } TUPSFࢦఆΞυϨεͷ ϝϞϦʹΛॻ͖ࠐΉ
ͳΜͱɺϝϞϦʹ ॻ͖ࠐΜͰ͍·ͨ͠
None
͋ͬɺ࠷దԽ ͍ͯ͠ͳ͔ͬͨ
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }
ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100)
variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } Ճ swiftc -emit-ir -O register2.swift > register2.ll
LLVM IRίʔυ: ࠷దԽ define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() local_unnamed_addr #0
{ entry: ret i64 1200 }
define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() local_unnamed_addr #0 { entry: ret
i64 1200 } LLVM IRίʔυ: ࠷దԽ
define hidden swiftcc @"$s8register14doAnEx local_unnamed_addr #0 entry: ret i64 1200
}
͏Θͬ…ࢲͷSwift ࠷దԽ͞Ε͗͢…?
ରࡦ
ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable =
twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl
ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable =
twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl
ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable =
twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl ͜ΕΛܦ༝ͯ͠ݺͼग़͢
func doAnExperiment() -> Int { var variable = twofold(100) variable
+= 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl ࡐͷSwiftίʔυ: վ swiftc -emit-ir -O register2.swift > register2.ll
LLVM IRίʔυվ: ࠷దԽ define hidden swiftcc i64 @"$s9register214doAnExperimentSiyF"() local_unnamed_addr #1
{ entry: %0 = load i64 (i64, %swift.refcounted*)*, i64 (i64, %swift.refcounted*)** bitcast (%swift.function* @"$s9register27twofoldyS2icvp" to i64 (i64, %swift.refcounted*)**), align 8 %1 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s9register27twofoldyS2icvp", i64 0, i32 1), align 8 %2 = tail call %swift.refcounted* @swift_retain(%swift.refcounted* returned %1) #3 %3 = tail call swiftcc i64 %0(i64 100, %swift.refcounted* swiftself %1) tail call void @swift_release(%swift.refcounted* %1) #3 %4 = tail call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 1000) %5 = extractvalue { i64, i1 } %4, 1 br i1 %5, label %8, label %6 ; <label>:6: ; preds = %entry %7 = extractvalue { i64, i1 } %4, 0 ret i64 %7 ; <label>:8: ; preds = %entry tail call void asm sideeffect "", "n"(i32 0) #3 tail call void @llvm.trap() unreachable }
define hidden swiftcc i64 @"$s9register214doAnExperimentSiyF"() local_unnamed_addr #1 { entry: %0
= load i64 (i64, %swift.refcounted*)*, i64 (i64, %swift.refcounted*)** bitcast (%swift.function* @"$s9register27twofoldyS2icvp" to i64 (i64, %swift.refcounted*)**), align 8 %1 = load %swift.refcounted*, %swift.refcounted** getelementptr inbounds (%swift.function, %swift.function* @"$s9register27twofoldyS2icvp", i64 0, i32 1), align 8 %2 = tail call %swift.refcounted* @swift_retain(%swift.refcounted* returned %1) #3 %3 = tail call swiftcc i64 %0(i64 100, %swift.refcounted* swiftself %1) tail call void @swift_release(%swift.refcounted* %1) #3 %4 = tail call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 1000) %5 = extractvalue { i64, i1 } %4, 1 br i1 %5, label %8, label %6 ; <label>:6: ; preds = %entry %7 = extractvalue { i64, i1 } %4, 0 ret i64 %7 ; <label>:8: ; preds = %entry tail call void asm sideeffect "", "n"(i32 0) #3 tail call void @llvm.trap() unreachable } LLVM IRίʔυվ: ࠷దԽ
func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3
= twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ
func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3
= twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ
func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3
= twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ
func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3
= twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ
ແବͳϝϞϦॻ͖ࠐΈ ͳͦ͞͏
೦ͷҝ Ξηϯϒϥ֬ೝ
ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable: Int
= twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl
ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable: Int
= twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl xcrun -sdk iphoneos swiftc -emit-assembly -O -target arm64- apple-ios12.0 register2.swift > register2.s
ARM64Ξηϯϒϥվ: ࠷దԽ _$s9register214doAnExperimentSiyF: .cfi_startproc stp x20, x19, [sp, #-32]! stp
x29, x30, [sp, #16] add x29, sp, #16 .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 .cfi_offset w19, -24 .cfi_offset w20, -32 Lloh4: adrp x8, _$s9register27twofoldyS2icvp@PAGE Lloh5: add x8, x8, _$s9register27twofoldyS2icvp@PAGEOFF ldp x19, x20, [x8] mov x0, x20 bl _swift_retain mov w0, #100 blr x19 mov x19, x0 mov x0, x20 bl _swift_release adds x0, x19, #1000 b.vs LBB1_2 ldp x29, x30, [sp, #16] ldp x20, x19, [sp], #32 ret
_$s9register214doAnExperimentSiyF: .cfi_startproc stp x20, x19, [sp, #-32]! stp x29, x30,
[sp, #16] add x29, sp, #16 .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 .cfi_offset w19, -24 .cfi_offset w20, -32 Lloh4: adrp x8, _$s9register27twofoldyS2icvp@PAGE Lloh5: add x8, x8, _$s9register27twofoldyS2icvp@PAGEOFF ldp x19, x20, [x8] mov x0, x20 bl _swift_retain mov w0, #100 blr x19 mov x19, x0 mov x0, x20 bl _swift_release adds x0, x19, #1000 b.vs LBB1_2 ldp x29, x30, [sp, #16] ldp x20, x19, [sp], #32 ret ARM64Ξηϯϒϥվ: ࠷దԽ
ARM64Ξηϯϒϥ: ݕࡧͷྗ func doAnExperiment() -> Int { let cpu =
CPU.shared cpu.w0 = 100 cpu.x0 = twofold(cpu.w0) cpu.x19 = cpu.x0 cpu.x0 = cpu.x19 + 1000 return cpu.x0 }
ͬͺΓແବͳϝϞϦ ॻ͖ࠐΈ͋Γ·ͤΜ
·ͱΊ • SwiftίϯύΠϥಡΊͳͯ͘ શʹ͖͋ΒΊͳͯ͘Α͍ • SwiftίϯύΠϥͷੌ͞Λମײ • ࠓճͷiOSDCɺԿ͔Λ࢝ΊΔ ͖͔͚ͬʹ͍ͨ͠
ࢀߟࢿྉ • WWDC16#416: Understanding Swift Performance • https://developer.apple.com/videos/play/wwdc2016/416/ • Contributing
to Open Source Swift • https://academy.realm.io/jp/posts/tryswift-jesse-squires-contributing-open- source-swift/ • LLVM Language Reference Manual • https://llvm.org/docs/LangRef.html • Arm64(ARMv8) Assembly Programming (00) • https://www.mztn.org/dragon/arm6400idx.html