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.3k
Swiftのスタック変数とCPUレジスタの関係を読み解いた
iOSDC Japan 2019 でお話ししたLTです。
rikusouda
September 07, 2019
Tweet
Share
More Decks by rikusouda
See All by rikusouda
SwiftとCPUレジスタ
rikusouda
2
630
OSSを育てながらiOSアプリでパンくずリストを実現した
rikusouda
2
5.1k
fastlaneはともだち こわくないよ
rikusouda
1
990
Other Decks in Programming
See All in Programming
自力でTTSモデルを作った話
zgock999
0
100
PHPのバージョンアップ時にも役立ったAST
matsuo_atsushi
0
230
How mixi2 Uses TiDB for SNS Scalability and Performance
kanmo
40
16k
Rubyで始める関数型ドメインモデリング
shogo_tksk
0
140
.NET Frameworkでも汎用ホストが使いたい!
tomokusaba
0
200
5分で理解する SOLID 原則 #phpcon_nagoya
shogogg
1
300
AIの力でお手軽Chrome拡張機能作り
taiseiue
0
190
新宿駅構内を三人称視点で探索してみる
satoshi7190
2
120
Domain-Driven Transformation
hschwentner
2
1.9k
pylint custom ruleで始めるレビュー自動化
shogoujiie
0
150
データベースのオペレーターであるCloudNativePGがStatefulSetを使わない理由に迫る
nnaka2992
0
230
責務と認知負荷を整える! 抽象レベルを意識した関心の分離
yahiru
8
1.3k
Featured
See All Featured
Visualization
eitanlees
146
15k
Speed Design
sergeychernyshev
27
810
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Scaling GitHub
holman
459
140k
Automating Front-end Workflow
addyosmani
1368
200k
It's Worth the Effort
3n
184
28k
Practical Orchestrator
shlominoach
186
10k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5.3k
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