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.2k
Swiftのスタック変数とCPUレジスタの関係を読み解いた
iOSDC Japan 2019 でお話ししたLTです。
rikusouda
September 07, 2019
Tweet
Share
More Decks by rikusouda
See All by rikusouda
SwiftとCPUレジスタ
rikusouda
2
610
OSSを育てながらiOSアプリでパンくずリストを実現した
rikusouda
2
5k
fastlaneはともだち こわくないよ
rikusouda
1
950
Other Decks in Programming
See All in Programming
とにかくAWS GameDay!AWSは世界の共通言語! / Anyway, AWS GameDay! AWS is the world's lingua franca!
seike460
PRO
1
860
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
PHP でアセンブリ言語のように書く技術
memory1994
PRO
1
170
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
OSSで起業してもうすぐ10年 / Open Source Conference 2024 Shimane
furukawayasuto
0
100
シェーダーで魅せるMapLibreの動的ラスタータイル
satoshi7190
1
480
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
610
詳細解説! ArrayListの仕組みと実装
yujisoftware
0
580
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
220
Contemporary Test Cases
maaretp
0
130
CSC509 Lecture 11
javiergs
PRO
0
180
Amazon Qを使ってIaCを触ろう!
maruto
0
400
Featured
See All Featured
Automating Front-end Workflow
addyosmani
1366
200k
A designer walks into a library…
pauljervisheath
203
24k
GraphQLとの向き合い方2022年版
quramy
43
13k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
[RailsConf 2023] Rails as a piece of cake
palkan
52
4.9k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
Product Roadmaps are Hard
iamctodd
PRO
49
11k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
How STYLIGHT went responsive
nonsquared
95
5.2k
GitHub's CSS Performance
jonrohan
1030
460k
Adopting Sorbet at Scale
ufuk
73
9.1k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
26
1.4k
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