$30 off During Our Annual Pro Sale. View Details »

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

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

Yuta Saito

June 18, 2020
Tweet

More Decks by Yuta Saito

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

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

    ) ϓϩάϥϜશମ at LLVMϨϕϧ
    • (New

    ) ϓϩάϥϜશମ at SILϨϕϧ
    3

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  9. // 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

    View Slide

  10. // 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

    View Slide

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

    View Slide

  12. ྫ͑͹
    // 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

    View Slide

  13. // 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

    View Slide

  14. // 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

    View Slide

  15. // 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

    View Slide

  16. SIL Ϩϕϧ LTO
    13

    View Slide

  17. SIL Ϩϕϧ LTO
    14

    View Slide

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

    View Slide

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

    View Slide

  20. 1. Cross Module Devirtualization
    17

    View Slide

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

    View Slide

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

    View Slide

  23. 20

    View Slide

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

    View Slide

  25. // 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

    View Slide

  26. 2. Cross Module Specialization
    23

    View Slide

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

    View Slide

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

    View Slide

  29. 3. Dead Table Elimination
    26

    View Slide

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

    View Slide

  31. 4. Dead public Function
    Elimination
    28

    View Slide

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

    View Slide

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

    View Slide

  34. LTO͕ಛʹخ͍͠৔໘
    31

    View Slide

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

    View Slide