Slide 1

Slide 1 text

SwiftͷϦϯΫ࣌࠷దԽϓϩδΣΫτ Θ͍Θ͍swiftc #21 @kateinoigakukun 1

Slide 2

Slide 2 text

Swiftͷ࠷దԽϨϕϧ • ϑΝΠϧ୯Ґ ( -O ) • Ϟδϡʔϧ୯Ґ ( -whole-module-optimization ) http://llvm.org/devmtg/2016-10/slides/GroffLattner-SILHighLevelIR.pdf 2

Slide 3

Slide 3 text

Swiftͷ࠷దԽϨϕϧ • ϑΝΠϧ୯Ґ ( -O ) • Ϟδϡʔϧ୯Ґ ( -whole-module-optimization ) • (New ➕ ) ϓϩάϥϜશମ at LLVMϨϕϧ • (New ➕ ) ϓϩάϥϜશମ at SILϨϕϧ 3

Slide 4

Slide 4 text

LTO (Link Time Optimization) ίϯύΠϥͰ͸ͳ͘ɼϦϯΧ͕࣮ߦ͢Δ࠷దԽɽϓϩάϥϜશ ମΛҰͭͷ୯Ґͱͯ͠࠷దԽ͢Δɽ 4

Slide 5

Slide 5 text

LTO (Link Time Optimization) ϝϦοτ • όΠφϦͷґଘ෺͢΂ͯͷ৘ใΛ࢖͑Δ • ϦϯΧ಺෦ͷγϯϘϧςʔϒϧΛ࠶ར༻Ͱ͖Δ 5

Slide 6

Slide 6 text

LLVM Ϩϕϧ LTO ΦϒδΣΫτϑΝΠϧͰ͸ͳ͘ɼLLVMϏοτίʔυΛೖྗϑΝ Πϧͱͯ͠ड͚෇͚Δɽ 6

Slide 7

Slide 7 text

LLVM Ϩϕϧ LTO ಛ௃ • ந৅౓ͷߴ͍࠷దԽ • LLVMͷ࠷దԽύεΛ࠶ར༻ 7

Slide 8

Slide 8 text

ྫ͑͹ // LibX.swift public func unusedPublicFunc() {} public func publicFunc() {} // main.swift import LibX publicFunc() 8

Slide 9

Slide 9 text

// LibX.ll define swiftcc void @"$s4LibX16unusedPublicFuncyyF"() #0 { entry: ret void } define swiftcc void @"$s4LibX10publicFuncyyF"() #0 { entry: ret void } // main.ll define i32 @main(i32 %0, i8** %1) #0 { entry: %2 = bitcast i8** %1 to i8* call swiftcc void @"$s4LibX10publicFuncyyF"() ret i32 0 } 9

Slide 10

Slide 10 text

// LibX.ll define swiftcc void @"$s4LibX16unusedPublicFuncyyF"() #0 { entry: ret void } define swiftcc void @"$s4LibX10publicFuncyyF"() #0 { entry: ret void } // main.ll define i32 @main(i32 %0, i8** %1) #0 { entry: %2 = bitcast i8** %1 to i8* call swiftcc void @"$s4LibX10publicFuncyyF"() ret i32 0 } 9

Slide 11

Slide 11 text

LLVM Ϩϕϧͩͱ೉͍͠࠷దԽ • ݴޠʹґଘͨ͠ϝλσʔλͷऔΓѻ͍ • ܕύϥϝʔλͷεϖγϟϥΠζ • ؔ਺ςʔϒϧʹࡌͬͨؔ਺ͷDFE (Dead Function Elimination) 10

Slide 12

Slide 12 text

ྫ͑͹ // LibX.swift public protocol P { func foo() func unusedMethod() } public struct S: P { public func foo() {} public func unusedMethod() {} } // main.swift import LibX func useP(_ value: T) { value.foo() } useP(S()) 11

Slide 13

Slide 13 text

// LibX.ll @"$s4LibX1SVAA1PAAWP" = constant [3 x i8*] [ ..., i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP3fooyyFTW" to i8*), i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW" to i8*) ], align 8 define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP3fooyyFTW"(...) { ... } define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW"(...) { ... } // main.ll define i32 @main(i32 %0, i8** %1) #0 { entry: ... call swiftcc void @"$s4main4usePyyx4LibX1PRzlF"( %swift.opaque* noalias nocapture undef, %swift.type* @"$s4LibX1SVN", i8** @"$s4LibX1SVAA1PAAWP" ) ret i32 0 } define hidden swiftcc void @"$s4main4usePyyx4LibX1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.P) { entry: %1 = getelementptr inbounds i8*, i8** %T.P, i32 1 %2 = load i8*, i8** %1, align 8, !invariant.load !14 %3 = bitcast i8* %2 to void (%swift.opaque*, %swift.type*, i8**)* call swiftcc void %3(%swift.opaque* noalias nocapture swiftself %0, %swift.type* %T, i8** %T.P) ret void } 12

Slide 14

Slide 14 text

// LibX.ll @"$s4LibX1SVAA1PAAWP" = constant [3 x i8*] [ ..., i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP3fooyyFTW" to i8*), i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW" to i8*) ], align 8 define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP3fooyyFTW"(...) { ... } define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW"(...) { ... } // main.ll define i32 @main(i32 %0, i8** %1) #0 { entry: ... call swiftcc void @"$s4main4usePyyx4LibX1PRzlF"( %swift.opaque* noalias nocapture undef, %swift.type* @"$s4LibX1SVN", i8** @"$s4LibX1SVAA1PAAWP" ) ret i32 0 } define hidden swiftcc void @"$s4main4usePyyx4LibX1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.P) { entry: %1 = getelementptr inbounds i8*, i8** %T.P, i32 1 %2 = load i8*, i8** %1, align 8, !invariant.load !14 %3 = bitcast i8* %2 to void (%swift.opaque*, %swift.type*, i8**)* call swiftcc void %3(%swift.opaque* noalias nocapture swiftself %0, %swift.type* %T, i8** %T.P) ret void } 12

Slide 15

Slide 15 text

// LibX.ll @"$s4LibX1SVAA1PAAWP" = constant [3 x i8*] [ ..., i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP3fooyyFTW" to i8*), i8* bitcast (void (%T4LibX1SV*, %swift.type*, i8**)* @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW" to i8*) ], align 8 define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP3fooyyFTW"(...) { ... } define linkonce_odr hidden swiftcc void @"$s4LibX1SVAA1PA2aDP12unusedMethodyyFTW"(...) { ... } // main.ll define i32 @main(i32 %0, i8** %1) #0 { entry: ... call swiftcc void @"$s4main4usePyyx4LibX1PRzlF"( %swift.opaque* noalias nocapture undef, %swift.type* @"$s4LibX1SVN", i8** @"$s4LibX1SVAA1PAAWP" ) ret i32 0 } define hidden swiftcc void @"$s4main4usePyyx4LibX1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T, i8** %T.P) { entry: %1 = getelementptr inbounds i8*, i8** %T.P, i32 1 %2 = load i8*, i8** %1, align 8, !invariant.load !14 %3 = bitcast i8* %2 to void (%swift.opaque*, %swift.type*, i8**)* call swiftcc void %3(%swift.opaque* noalias nocapture swiftself %0, %swift.type* %T, i8** %T.P) ret void } 12

Slide 16

Slide 16 text

SIL Ϩϕϧ LTO 13

Slide 17

Slide 17 text

SIL Ϩϕϧ LTO 14

Slide 18

Slide 18 text

SIL Ϩϕϧ LTO ͷ Ϟνϕʔγϣϯ • LLVM IRΑΓந৅౓ͷߴ͍࠷దԽ • SwiftͷηϚϯςΟΫεΛҡ࣋ͨ͠··LTO͍ͨ͠ • Ͳ͏ͤ੩తϦϯΫ͢ΔͳΒɺABI resiliencyΛແࢹͨ͠࠷దԽ Λ͍ͨ͠ɻ • ࣮ߦ࣌ύϑΥʔϚϯεͷվળͱόΠφϦαΠζͷॖখΛظ଴ 15

Slide 19

Slide 19 text

࠷దԽϙΠϯτ (ະ࣮૷) 16

Slide 20

Slide 20 text

1. Cross Module Devirtualization 17

Slide 21

Slide 21 text

https://speakerdeck.com/kateinoigakukun/konpairakaraniu-jie-kuswift-method-dispatch-1?slide=39 18

Slide 22

Slide 22 text

https://speakerdeck.com/kateinoigakukun/konpairakaraniu-jie-kuswift-method-dispatch-1?slide=55 19

Slide 23

Slide 23 text

20

Slide 24

Slide 24 text

Cross Module Devirtualization • ͢΂ͯͷϞδϡʔϧ͕LTOର৅ͳΒɺϝιου͕Φʔόʔϥ Πυ͞Ε͍ͯΔ͔ඞͣ෼͔Δ • ࣮࣭finalೝఆͰ͖Δݺͼग़͕͠૿͑Δ • ABI resiliencyͷͨΊͷςʔϒϧܦ༝ݺͼग़͠Λ੩తݺͼग़͠ ʹͰ͖Δɻ 21

Slide 25

Slide 25 text

// LibX.swift open class A { public func foo1() {} open func foo2() {} } public func invokeFoo1InModule(_ a: A) { // ͜Ε͸ݱঢ়ͷ࠷దԽύεͰdevirtͰ͖Δ a.foo1() } // main.swift import LibX func invokeFoo1(_ a: A) { // [LTO] ֎෦Ϟδϡʔϧͷؔ਺͕ͩɺABI resiliencyແࢹͰdevirtͰ͖Δɻ a.foo1() // [LTO] ֎෦Ϟδϡʔϧͷؔ਺͕ͩɺ୭΋override͍ͯ͠ͳ͍ͷͰdevirtͰ͖Δɻ a.foo2() } 22

Slide 26

Slide 26 text

2. Cross Module Specialization 23

Slide 27

Slide 27 text

Cross Module Specialization • ϞδϡʔϧΛ·͍ͨͩεϖγϟϥΠζ • ABI resiliencyΛແࢹͯ͠ɺશͯʹ@inlinable ͕͍͍ͭͯΔ Πϝʔδ • όΠφϦαΠζͷංେԽ͕৺഑ 24

Slide 28

Slide 28 text

// LibX.swift public protocol Animal { func bark() } public struct Cat: Animal { func bark() { } } // main.swift import LibX public callBark(_ animal: T) { animal.bark() } 25

Slide 29

Slide 29 text

3. Dead Table Elimination 26

Slide 30

Slide 30 text

Dead Table Elimination • ௨ৗɺpublicͳVTable΍Protocol Witness Table͸ৗʹग़ྗ͞ ΕΔ • LTOͷ৔߹ɺΫϩεϞδϡʔϧͰ࢖ΘΕ͍ͯΔ৔߹͚ͩग़ྗ ͢Ε͹͍͍ɻ • devirtͱεϖγϟϥΠζͰςʔϒϧ΁ͷࢀর͕ফ͑Δͱɺ͜ͷ ύε͕ΑΓޮՌతʹͳΔ 27

Slide 31

Slide 31 text

4. Dead public Function Elimination 28

Slide 32

Slide 32 text

Dead public Function Elimination • ௨ৗͷDFE͸internalͳؔ਺͕ର৅ • LTOͷ৔߹ɺpublicؔ਺΋ফͤΔ • ࣮ࡍʹ͸Dead Table Eliminationͱಉ࣌ʹ΍Δ • mainؔ਺͔Βґଘ͢Δؔ਺Λ෯༏ઌ୳ࡧͰϚʔΫ͍ͯ͘͠ 29

Slide 33

Slide 33 text

࡞ۀਐḿ िใΛϑΥʔϥϜʹॻ͍ͯΔ https://forums.swift.org/t/gsoc-lto-support-progress-report/ 37149 30

Slide 34

Slide 34 text

LTO͕ಛʹخ͍͠৔໘ 31

Slide 35

Slide 35 text

stdlibΛؙ͝ͱ੩తϦϯΫ͢ΔͨΊɺ࢖͍ͬͯͳ͍ػೳ΋όΠφ Ϧʹೖͬͯ͠·͏ɻ Hello, worldͰ͢Β10MBɻ·͞ʹLTOͷग़൪ 32