Slide 1

Slide 1 text

SwiftͷελοΫม਺ͱ CPUϨδελͷؔ܎Λ ಡΈղ͍ͨ 2019/09/07 iOSDC Japan 2019 LT @rikusouda #iosdc #a

Slide 2

Slide 2 text

ࣗݾ঺հ • @rikusouda (٢Ԭ༞थ) • גࣜձࣾGunosy ͜ΕͷJ04ΞϓϦ࡞͍ͬͯΔ

Slide 3

Slide 3 text

௿ϨΠϠʔ޷͖ • جຊ৘ใٕज़ऀࢼݧͷݴޠ໰୊ ͸ΞηϯϒϥΛબ୒ͨ͠ • iOSΞϓϦ։ൃͷલ͸C++Ͱ WindowsΞϓϦ։ൃ͍ͯͨ͠

Slide 4

Slide 4 text

SwiftͷϨδελར༻͕ؾʹͳΔ • WWDC16#416ΑΓɺ஋ܕϩʔΧ ϧม਺͸ελοΫϝϞϦΛ࢖͏ • ࣮ߦ࣌͸Ϩδελ࢖͏͔ΒɺϝϞ Ϧ΁ͷॻ͖ࠐΈ͸লུͰ͖Δ?

Slide 5

Slide 5 text

Tips:ϨδελͬͯԿ? • CPU಺ʹ͋ΔϝϞϦΈ͍ͨͳͷ • Ξηϯϒϥ(࣮ߦϑΝΠϧ)͕࢖͏ • ϝϞϦΑΓ௒ઈߴ଎ • ͨͩ͠௒ઈখ༰ྔ

Slide 6

Slide 6 text

SwiftͷϨδελར༻͕ؾʹͳͬ ͨ • WWDC16#416ΑΓɺ஋ܕϩʔΧ ϧม਺͸ελοΫϝϞϦΛ࢖͏ • ࣮ߦ࣌͸Ϩδελ࢖͏͔ΒɺϝϞ Ϧ΁ͷॻ͖ࠐΈ͸লུͰ͖Δ?

Slide 7

Slide 7 text

୊ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }

Slide 8

Slide 8 text

୊ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }

Slide 9

Slide 9 text

୊ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } Λฦ͢

Slide 10

Slide 10 text

func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 } ୊ࡐͷSwiftίʔυ ͜ͷWBSJBCMF͸ɺϝϞϦʹ ॻ͖ࠐ·ͳͯ͘΋ྑ͍ͱࢥͬͨ ϨδελͰࣄ଍ΓΔͷͰ

Slide 11

Slide 11 text

ίϯύΠϥͷίʔυΛ ಡΊ͹Θ͔ΔΒ͍͠

Slide 12

Slide 12 text

Ͱ΋ίϯύΠϥΘ͔Βͳ͍ • C++஌͍ͬͯͯ΋ίϯύΠϥ Θ͔ΔΘ͚͡Όͳ͍ • ௐ΂Δ·Ͱͷϋʔυϧ͕ߴͦ ͏

Slide 13

Slide 13 text

ௐ΂͖͔͚ͨͬ

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

WWDC19ʹߦ͖ͬͯͨ • ॳΊͯWWDCʹߦͬͨ • WWDCͰ͸Labͱ͍͏ͱ͜ΖͰ AppleͷΤϯδχΞʹ࣭໰Ͱ͖Δ

Slide 16

Slide 16 text

ࣗ෼Ͱௐ΂ͳͯ͘΋ ౴͑Θ͔ΔͷͰ͸

Slide 17

Slide 17 text

WWDCͷLabͰฉ͍ͯΈͨ • CݴޠͰͷ౴͑͸ฉ͚͚ͨͲɺ SwiftͰͷ౴͑͸ฉ͚ͳ͔ͬͨ • LLVM IRͱ͔ΞηϯϒϥಡΉͱ ͍Ζ͍ΖΘ͔Δͱฉ͍ͨ

Slide 18

Slide 18 text

Tips: LLVM IRͬͯԿ? • ࣮ߦϑΝΠϧ(Ξηϯϒϥ)ʹͳΔ Ұาखલͷதؒදݱ • BitcodeʹରԠ͢Διʔείʔυ

Slide 19

Slide 19 text

WWDCͷLabͰฉ͍ͯΈͨ • CݴޠͰͷ౴͑͸ฉ͚͚ͨͲɺ SwiftͰͷ౴͑͸ฉ͚ͳ͔ͬͨ • LLVM IRͱ͔ΞηϯϒϥಡΉͱ ͍Ζ͍ΖΘ͔Δͱฉ͍ͨ

Slide 20

Slide 20 text

LLVM IR΍ΞηϯϒϥΛग़ྗ͠ ͯಡΉํ๏Λख΄Ͳ͖ͯ͘͠Ε ͨ (ͨͩ͠CݴޠΛݩʹͯ͠)

Slide 21

Slide 21 text

ͳΜ͔Ͱ͖ͦ͏ͳ ؾ࣋ͪʹͳΓ·ͨ͠

Slide 22

Slide 22 text

͖ͬ͞ͷSwiftͷ LLVM IRΛಡΜͰΈΑ͏

Slide 23

Slide 23 text

୊ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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 ; :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 ; :9: ; preds = %entry call void @llvm.trap() unreachable }

Slide 26

Slide 26 text

΍ͬͺΓ೉͍͠

Slide 27

Slide 27 text

ݕࡧΛۦ࢖ͯ͠ղಡ

Slide 28

Slide 28 text

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 ; :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 ; :9: ; preds = %entry call void @llvm.trap() unreachable }

Slide 29

Slide 29 text

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 }

Slide 30

Slide 30 text

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͸ϝϞϦ ελοΫ Λ֬อ͠ ͦͷྖҬͷΞυϨεΛฦ͢

Slide 31

Slide 31 text

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 }

Slide 32

Slide 32 text

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͸ࢦఆΞυϨεͷ ϝϞϦʹ஋Λॻ͖ࠐΉ

Slide 33

Slide 33 text

ͳΜͱɺϝϞϦʹ ॻ͖ࠐΜͰ͍·ͨ͠

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

͋ͬɺ࠷దԽ ͍ͯ͠ͳ͔ͬͨ

Slide 36

Slide 36 text

୊ࡐͷSwiftίʔυ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofold(_ arg: Int) -> Int { return arg * 2 }

Slide 37

Slide 37 text

୊ࡐͷ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

Slide 38

Slide 38 text

LLVM IRίʔυ: ࠷దԽ define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() local_unnamed_addr #0 { entry: ret i64 1200 }

Slide 39

Slide 39 text

define hidden swiftcc i64 @"$s8register14doAnExperimentSiyF"() local_unnamed_addr #0 { entry: ret i64 1200 } LLVM IRίʔυ: ࠷దԽ

Slide 40

Slide 40 text

define hidden swiftcc @"$s8register14doAnEx local_unnamed_addr #0 entry: ret i64 1200 }

Slide 41

Slide 41 text

͏Θͬ…ࢲͷSwift ࠷దԽ͞Ε͗͢…?

Slide 42

Slide 42 text

ରࡦ

Slide 43

Slide 43 text

୊ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl

Slide 44

Slide 44 text

୊ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl

Slide 45

Slide 45 text

୊ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable = twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl ͜ΕΛܦ༝ͯ͠ݺͼग़͢

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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 ; :6: ; preds = %entry %7 = extractvalue { i64, i1 } %4, 0 ret i64 %7 ; :8: ; preds = %entry tail call void asm sideeffect "", "n"(i32 0) #3 tail call void @llvm.trap() unreachable }

Slide 48

Slide 48 text

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 ; :6: ; preds = %entry %7 = extractvalue { i64, i1 } %4, 0 ret i64 %7 ; :8: ; preds = %entry tail call void asm sideeffect "", "n"(i32 0) #3 tail call void @llvm.trap() unreachable } LLVM IRίʔυվ: ࠷దԽ

Slide 49

Slide 49 text

func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3 = twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ

Slide 50

Slide 50 text

func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3 = twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ

Slide 51

Slide 51 text

func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3 = twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ

Slide 52

Slide 52 text

func doAnExperiment() -> Int { let cpu = CPU.shared cpu.r3 = twofold(100) cpu.r7 = cpu.r3 + 1000 return cpu.r7 } LLVM IRվ࠷దԽ: ݕࡧͷྗ

Slide 53

Slide 53 text

ແବͳϝϞϦॻ͖ࠐΈ ͳͦ͞͏

Slide 54

Slide 54 text

೦ͷҝ Ξηϯϒϥ΋֬ೝ

Slide 55

Slide 55 text

୊ࡐͷSwiftίʔυ: վ func doAnExperiment() -> Int { var variable: Int = twofold(100) variable += 1000 return variable } func twofoldImpl(_ arg: Int) -> Int { return arg * 2 } let twofold = twofoldImpl

Slide 56

Slide 56 text

୊ࡐͷ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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

_$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Ξηϯϒϥվ: ࠷దԽ

Slide 59

Slide 59 text

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 }

Slide 60

Slide 60 text

΍ͬͺΓແବͳϝϞϦ ॻ͖ࠐΈ͋Γ·ͤΜ

Slide 61

Slide 61 text

·ͱΊ • SwiftίϯύΠϥಡΊͳͯ͘΋׬ શʹ͖͋ΒΊͳͯ͘Α͍ • SwiftίϯύΠϥͷੌ͞Λମײ • ࠓճͷiOSDC΋ɺԿ͔Λ࢝ΊΔ
 ͖͔͚ͬʹ͍ͨ͠

Slide 62

Slide 62 text

ࢀߟࢿྉ • 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