Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swiftのリンク時最適化プロジェクト

 Swiftのリンク時最適化プロジェクト

Yuta Saito

June 18, 2020
Tweet

More Decks by Yuta Saito

Other Decks in Programming

Transcript

  1. Swiftͷ࠷దԽϨϕϧ • ϑΝΠϧ୯Ґ ( -O ) • Ϟδϡʔϧ୯Ґ ( -whole-module-optimization

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

    ) • (New ➕ ) ϓϩάϥϜશମ at LLVMϨϕϧ • (New ➕ ) ϓϩάϥϜશମ at SILϨϕϧ 3
  3. // 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
  4. // 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
  5. ྫ͑͹ // 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<T: P>(_ value: T) { value.foo() } useP(S()) 11
  6. // 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
  7. // 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
  8. // 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
  9. SIL Ϩϕϧ LTO ͷ Ϟνϕʔγϣϯ • LLVM IRΑΓந৅౓ͷߴ͍࠷దԽ • SwiftͷηϚϯςΟΫεΛҡ࣋ͨ͠··LTO͍ͨ͠

    • Ͳ͏ͤ੩తϦϯΫ͢ΔͳΒɺABI resiliencyΛແࢹͨ͠࠷దԽ Λ͍ͨ͠ɻ • ࣮ߦ࣌ύϑΥʔϚϯεͷվળͱόΠφϦαΠζͷॖখΛظ଴ 15
  10. 20

  11. // 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
  12. // LibX.swift public protocol Animal { func bark() } public

    struct Cat: Animal { func bark() { } } // main.swift import LibX public callBark<T: Animal>(_ animal: T) { animal.bark() } 25
  13. Dead Table Elimination • ௨ৗɺpublicͳVTable΍Protocol Witness Table͸ৗʹग़ྗ͞ ΕΔ • LTOͷ৔߹ɺΫϩεϞδϡʔϧͰ࢖ΘΕ͍ͯΔ৔߹͚ͩग़ྗ

    ͢Ε͹͍͍ɻ • devirtͱεϖγϟϥΠζͰςʔϒϧ΁ͷࢀর͕ফ͑Δͱɺ͜ͷ ύε͕ΑΓޮՌతʹͳΔ 27
  14. Dead public Function Elimination • ௨ৗͷDFE͸internalͳؔ਺͕ର৅ • LTOͷ৔߹ɺpublicؔ਺΋ফͤΔ • ࣮ࡍʹ͸Dead

    Table Eliminationͱಉ࣌ʹ΍Δ • mainؔ਺͔Βґଘ͢Δؔ਺Λ෯༏ઌ୳ࡧͰϚʔΫ͍ͯ͘͠ 29