Slide 1

Slide 1 text

SwiftͷThin Cross Module Optimization (WIP) Θ͍Θ͍swiftc #22 @kateinoigakukun 1

Slide 2

Slide 2 text

GSoC (Google Summer of Code) https://summerofcode.withgoogle.com • Google͕ೝఆͨ͠ΦʔϓϯιʔεͷϓϩδΣΫτʹࢀՃ͢Δ ͱGoogle͔ΒใुΛ΋Β͑Δɺֶੜ޲͚Πϕϯτ • Swift΋ࢀՃ͍ͯ͠Δ 2

Slide 3

Slide 3 text

https://summerofcode.withgoogle.com/projects/#6691362033893376 3

Slide 4

Slide 4 text

ݱࡏͷεςʔλε • GSoCظ͕ؒऴΘͬͨ • ࣗ෼ͷϒϥϯνͰͷ࡞ۀ͸େମऴΘ͍ͬͯΔ • Ϛʔδ͞Ε͍ͯͳ͍PR͕ͨ͘͞Μ࢒͍ͬͯΔͷͰϨϏϡΞʔ Λ୳ͯ͠ఆظతʹಥ෇͍ͯΔ 4

Slide 5

Slide 5 text

౰ॳͷܭը libLTO.dylibతͳϦϯΧϓϥάΠϯΛ࡞Δ༧ఆͩͬͨɻ $ clang -flto file1.c file2.c -c $ ls file1.c file1.o file2.c file2.o $ file file1.o file1.o: LLVM bitcode, wrapper x86_64 $ ld file1.o file2.o -lto_library path/to/libLTO.dylib 5

Slide 6

Slide 6 text

6

Slide 7

Slide 7 text

7

Slide 8

Slide 8 text

͜ͷΞʔΩςΫνϟͷ໰୊఺ ϦϯΧ͕SIBશମΛಡΜͰղੳ͢Δ͜ͱʹͳΔͷͰɺ࠷దԽ࣌ؒ తʹεέʔϥϒϧͰͳ͍ -> LLVM ͷLTOͰ΋Ҏલಉ༷ͷ໰୊͕͋ͬͨɻ 8

Slide 9

Slide 9 text

http://llvm.org/devmtg/2016-11/Slides/Amini-Johnson-ThinLTO.pdf 9

Slide 10

Slide 10 text

http://llvm.org/devmtg/2016-11/Slides/Amini-Johnson-ThinLTO.pdf 10

Slide 11

Slide 11 text

LLVM Thin LTO • Bitcode͔Βͷίʔυੜ੒ΛฒྻԽͰ͖Δ • αϚϦʔΛૢ࡞͢ΔThin Link͸௚ྻʹͳΔ͕ɺLLVM໋ྩΛ ղੳ͠ͳ͍ͷͰ͍ܰ 11

Slide 12

Slide 12 text

LLVM Thin LTOϞσϧΛࢀߟʹ৽͍͠ύΠϓϥΠϯΛ࣮૷ͯ͠Έ ͨɻ • SwiftϞδϡʔϧͷαϚϦΛग़ྗ • ΫϩεϞδϡʔϧͰղੳ͢Δͱ͖SIBΛશͯύʔε͢Δඞཁ͕ ແ͘ͳΔ 12

Slide 13

Slide 13 text

13

Slide 14

Slide 14 text

14

Slide 15

Slide 15 text

࣮ࡍͷίϚϯυ 15

Slide 16

Slide 16 text

Compile Module A $ swift-frontend A1.swift A2.swift \ -whole-module-optimization \ -emit-module -emit-module-summary -emit-sib \ -o A.swiftmodule ग़ྗ: A.swiftmodule, A.swiftmodulesummary, A.sib 16

Slide 17

Slide 17 text

Compile Module B $ swift-frontend B1.swift B2.swift \ -whole-module-optimization \ -emit-module -emit-module-summary -emit-sib \ -I. \ -o B.swiftmodule ग़ྗ: B.swiftmodule, B.swiftmodulesummary, B.sib 17

Slide 18

Slide 18 text

Merge Module Summary ௚ྻϙΠϯτ $ swift-frontend -merge-module-summary \ A.swiftmodulesummary B.swiftmodulesummary \ -o merged-module.swiftmodulesummary 18

Slide 19

Slide 19 text

CodeGen ͜͜͸ฒྻʹͰ͖Δ $ swift-frontend -emit-object A.sib -o A.o \ -module-summary-path merged-module.swiftmodulesummary $ swift-frontend -emit-object B.sib -o B.o \ -module-summary-path merged-module.swiftmodulesummary 19

Slide 20

Slide 20 text

Swift Module Summary SILModuleΛཁ໿ͨ͠ΦϒδΣΫτɻ • ؔ਺ͷίʔϧάϥϑ • ؔ਺ςʔϒϧͷந৅ͱ࣮૷ͷରԠؔ܎ Λ࣋ͭ 20

Slide 21

Slide 21 text

ྫ func myPrint(_ text: String) { ... } public protocol Animal { func bark() } public struct Cat: Animal { public func bark() { myPrint("mew") } } public struct Dog: Animal { public func bark() { myPrint("bow")} } public func callBark(_ animal: T) { animal.bark() } 21

Slide 22

Slide 22 text

ϚʔδͷλΠϛϯάͰ΍͍ͬͯΔ͜ͱ 1. swiftmodulesummaryΛҰͭͷαϚϦʔΦϒδΣΫτʹϩʔ υͯ͠ϦϯΫ 2. PreservedͳγϯϘϧΛऩू 3. PreservedͳγϯϘϧ͔Βḷ࣮ͬͯߦ࣌ࢀরՄೳͳܕΛϚʔΫ 4. PreservedͳγϯϘϧ͔Β౸ୡՄೳͳؔ਺Λliveͱͯ͠ϚʔΫ ͯ͠౸ୡෆೳͳؔ਺Λચ͍ग़͢ 22

Slide 23

Slide 23 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 24

Slide 24 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 25

Slide 25 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 26

Slide 26 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 27

Slide 27 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 28

Slide 28 text

౸ୡෆೳͳؔ਺Λચ͍ग़͢ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { SmallVector Worklist; for (auto GUID : PreservedGUIDs) { Worklist.push_back(GUID); } while (!Worklist.empty()) { auto GUID = Worklist.pop_back_val(); auto Func = summary.getFunction(GUID); if (Func->isLive()) continue; Func->setLive(true); for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } } } 23

Slide 29

Slide 29 text

void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { ... for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } ... } 24

Slide 30

Slide 30 text

void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { ... for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { Worklist.push_back(Impl); } break; } } ... } 24

Slide 31

Slide 31 text

ܕ͕࢖ΘΕ͍ͯͳ͚Ε͹ςʔϒϧܦ༝Ͱϝιου͕ݺ͹ΕΔ͜ ͱ΋ͳ͍ͷͰফͤΔ void markDeadSymbols(ModuleSummaryIndex &summary, llvm::DenseSet &PreservedGUIDs) { ... for (auto Call : Func->calls()) { switch (Call.getKind()) { case EdgeTy::Kind::Static: { Worklist.push_back(Call.getCallee()); continue; } case EdgeTy::Kind::Witness: case EdgeTy::Kind::VTable: { auto Impls = summary.getImplementations(Call); for (auto Impl : Impls) { if (UsedTypes.find(Impl.Type) == UsedTypes.end()) { continue; } Worklist.push_back(Impl); } break; } } ... } 25

Slide 32

Slide 32 text

ϕϯνϚʔΫ https://github.com/kateinoigakukun/swift-lto-benchmark 26

Slide 33

Slide 33 text

Stdlib ର৅ίʔυ: https:// github.com/kateinoigakukun/ swift-lto-benchmark/blob/ master/Example/ SwiftStdlibExample.swift let alphabet = "abcdefghijklmnopqrstuvwxyz" /// All edits that are one edit away from `word` func edits(_ word: String) -> Set { let splits = word.indices.map { (String(word[..<$0]), String(word[$0...])) } var result: Array = [] for (left, right) in splits { // drop a character result.append(left + right.dropFirst()) // transpose two characters if let fst = right.first { let drop1 = right.dropFirst() if let snd = drop1.first { result.append(left + [snd,fst] + drop1.dropFirst()) } } // replace each character with another for letter in alphabet { result.append(left + [letter] + right.dropFirst()) } // insert rogue characters for letter in alphabet { result.append(left + [letter] + right) } } // have to map back to strings right at the end return Set(result) } 27

Slide 34

Slide 34 text

όΠφϦαΠζ 28

Slide 35

Slide 35 text

Ϗϧυ࣌ؒ 29

Slide 36

Slide 36 text

• 60%ऑͷόΠφϦαΠζ࡟ݮ • SIL -> IRͷม׵ύε͕ߴίετͳͷͰɺ߱Լͤ͞Δؔ਺͕ ݮͬͨ͜ͱʹΑͬͯίϯύΠϧ࣌ؒ΋ݮগ͍ͯ͠Δɻ 30

Slide 37

Slide 37 text

Ϗϧυ࣌ؒͷ಺༁ ninjatracing ͱ͍͏πʔϧͰninjaͷϏϧυϩά͔ΒϏϧυ࣌ ؒΛChromeͰϏδϡΞϥΠζͰ͖ΔϑΥʔϚοτʹม׵Ͱ͖ Δ https://github.com/nico/ninjatracing 31

Slide 38

Slide 38 text

32

Slide 39

Slide 39 text

ফͤͳ͍ؔ਺ͷղੳ ཧ૝తʹ͸ফ͍͕ͨ͠liveϚʔΫ͕෇͍ͯ͠·͍ͬͯΔؔ਺͕ ࢒͍ͬͯΔͷͰղੳ͍ͨ͠ɻ ղੳͷΞΠσΟΞ • ίʔϧάϥϑΛϏδϡΞϥΠζͯ͠ΈΔ • ίʔϧάϥϑ͔Βࢧ഑໦(Dominator Tree)Λߏஙͯ͠େ͖ͳ ؔ਺ΛҾ͖࿈Εͯ͘ΔݪҼΛݟ͚ͭΔ 33

Slide 40

Slide 40 text

ίʔϧάϥϑΛϏδϡΞϥΠζͯ͠ΈΔ ΍ͬͯΈͨɻ 34

Slide 41

Slide 41 text

35

Slide 42

Slide 42 text

ਓ͕ؒݟΒΕΔάϥϑ͡Όͳ͔ͬͨ 36

Slide 43

Slide 43 text

Dominator Tree (ࢧ഑໦) • ίϯύΠϥͷϑϩʔղੳʹΑ͘࢖ΘΕΔ • ༗޲άϥϑʹରͯ͠ߏஙͰ͖Δ໦ߏ଄ • ͋Δϊʔυʹ౸ୡ͢ΔͨΊʹඞͣ௨ΔҰ൪͍ۙϊʔυΛ਌ʹ ͱΔߏ଄ 37

Slide 44

Slide 44 text

ྫ ݩͷ༗޲άϥϑ ࢧ഑໦ 1 2 3 4 5 6 https://en.wikipedia.org/wiki/Dominator(graphtheory) 38

Slide 45

Slide 45 text

Dominator TreeΛ࢖͏ͱͲͷؔ਺͕୔ࢁ໋ྩΛҾ͖࿈Ε͍ͯΔ ͔ղੳ͠΍͘͢ͳΔɻ 39

Slide 46

Slide 46 text

ղੳͨ݁͠Ռ • RxSwiftͷ৔߹͸ɺdeinit ͕৭ʑҾ͖࿈Ε͖͍ͯͯͨɻ • disposeΛεέδϡʔϥʹࡌ͍ͤͯΔॲཧ͕ॏ͍ • deinit͸ϥϯλΠϜ͕ಈతʹݺͿͷͰpreserve͍ͯͨ͠ɻ • Stdlibͷ৔߹͸ɺΫϥογϡ࣌ʹϥϯλΠϜ͔Βݺ͹ΕΔ debugPrint͕ॏ͔ͬͨɻ 40

Slide 47

Slide 47 text

ରԠͷߏ૝ • deinit • ʮalloc ͞Εͳ͚Ε͹deinit΋ݺ͹Εͳ͍ʯΛ࢖ͬͯফ͠ ͯΈΔ • debugPrint • Ϋϥογϡ࣌ʹԿ΋ग़ྗ͠ͳ͍Ͱࢮ͵ϞʔυΛ௥Ճͯ͠Έ Δʁ 41

Slide 48

Slide 48 text

ײ૝ • λΠϜκʔϯͷҧ͍͕େม • ίϯύΠϥΤϯδχΞͬΆ͍࢓ࣄ͕Ͱָ͖͔ͯͬͨ͠ • ํ਑స׵͸͠ΜͲ͔͕ͬͨɺσΟεΧογϣϯͯ͠ྑ͍Ξϓ ϩʔνʹͳͬͨͷ͸ྑ͔ͬͨ 42

Slide 49

Slide 49 text

֤छϦϯΫ ϓϩϙʔβϧ: https://docs.google.com/document/d/ 1qT77pc7rJaisuds4msSMfGPYCjy4uiJ-J1U7-nEW2Y0 ϑΥʔϥϜ: • https://forums.swift.org/t/refactoring-plan-of-silvisitor-for- lto/37678 • https://forums.swift.org/t/gsoc-lto-support-progress-report/ 37149 43