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.7k
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
300
SwiftとCPUレジスタ
rikusouda
2
690
OSSを育てながらiOSアプリでパンくずリストを実現した
rikusouda
2
5.6k
fastlaneはともだち こわくないよ
rikusouda
1
1.1k
Other Decks in Programming
See All in Programming
ALB ログから Trace を気合で繋げる技術
fohte
7
820
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
8k
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
400
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
580
Flow は今どうなっているか
mizdra
PRO
0
800
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
590
高専キャリア LT 発表内容
crysta1221
6
5.3k
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
280
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
240
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.3k
DroidKaigi 2026 「個人開発という実験場: Android エンジニアが手にする4つの自由」
slashnephy
0
120
プロポーザルを書いてもらう
pvcresin
0
590
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
810
Building the Perfect Custom Keyboard
takai
2
860
Mind Mapping
helmedeiros
PRO
1
340
Game over? The fight for quality and originality in the time of robots
wayneb77
1
260
[SF Ruby Conf 2025] Rails X
palkan
2
1.3k
How to Ace a Technical Interview
jacobian
281
24k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
300
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.8k
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