Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Swiftのスタック変数とCPUレジスタの関係を読み解いた
Search
rikusouda
September 07, 2019
Programming
2.8k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swiftのスタック変数とCPUレジスタの関係を読み解いた
iOSDC Japan 2019 でお話ししたLTです。
rikusouda
September 07, 2019
More Decks by rikusouda
See All by rikusouda
末尾再帰なら安心でしょ?って信じてたSwiftコードが落ちた夜
rikusouda
0
330
SwiftとCPUレジスタ
rikusouda
2
700
OSSを育てながらiOSアプリでパンくずリストを実現した
rikusouda
2
5.7k
fastlaneはともだち こわくないよ
rikusouda
1
1.2k
Other Decks in Programming
See All in Programming
flutter_test のその先へ — Flutter アプリの LLM 機能に「評価」という品質保証を
kosukesaigusa
0
200
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
1.8k
Modernizing iOS Apps
seyfoyun
0
150
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
600
まずはコードより業務と向き合う:テーブル解体のためにPdMを呼んだ話
sakawe_ee
0
170
Apple Intelligenceとオンデバイス時代の到来
yahir0
0
220
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
16
8.7k
クラウドゲーミングのパフォーマンス最適化に挑む / Cloud Gaming Performance Tuning
vivion
0
330
TanStack Vue Query と Pinia Colada から学ぶ非同期状態の型設計
aoshi
0
620
Event is what happens
moro
2
3.7k
Distance field of Julia set
kinakomoti321
0
290
SFCで実現する病院・医療システムの動的組み立て式UI
koukimiura
1
170
Featured
See All Featured
A Modern Web Designer's Workflow
chriscoyier
699
190k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
The Spectacular Lies of Maps
axbom
PRO
1
1.1k
Thoughts on Productivity
jonyablonski
76
5.5k
Design in an AI World
tapps
1
380
GraphQLとの向き合い方2022年版
quramy
50
15k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.9k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.6k
The Invisible Side of Design
smashingmag
301
52k
The Language of Interfaces
destraynor
162
27k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
520
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