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

mayHaveSideEffect

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

 mayHaveSideEffect

Avatar for freddi(Yuki Aki)

freddi(Yuki Aki)

May 22, 2020
Tweet

More Decks by freddi(Yuki Aki)

Other Decks in Technology

Transcript

  1. ͪΐͬͱ෮श ~ SILͱ͸ • Swi%ͷதؒදݱݴޠ (Swi% Intermediate Language) • Swi%ͷίʔυΛίϯύΠϧ͍ͯ͠Δ్தͰݱΕΔ

    • ࠷దԽ͸SILͷίʔυͰߦΘΕΔ • ࠷దԽલͷSIL͕raw SILɺޙ͕canonical SIL 5
  2. ͪΐͬͱ෮श ~ SILʢྫʣ SILʹม׵ޙ sil_stage canonical import Builtin import Swift

    import SwiftShims @_hasStorage @_hasInitialValue var a: Int { get set } // a sil_global hidden @$s5swift1aSivp : $Int // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s5swift1aSivp // id: %2 %3 = global_addr @$s5swift1aSivp : $*Int // user: %6 %4 = integer_literal $Builtin.Int64, 10 // user: %5 %5 = struct $Int (%4 : $Builtin.Int64) // user: %6 store %5 to %3 : $*Int // id: %6 %7 = integer_literal $Builtin.Int32, 0 // user: %8 %8 = struct $Int32 (%7 : $Builtin.Int32) // user: %9 return %8 : $Int32 // id: %9 } // end sil function 'main' // Int.init(_builtinIntegerLiteral:) sil public_external [transparent] [serialized] @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int { // %0 // user: %2 bb0(%0 : $Builtin.IntLiteral, %1 : $@thin Int.Type): %2 = builtin "s_to_s_checked_trunc_IntLiteral_Int64"(%0 : $Builtin.IntLiteral) : $(Builtin.Int64, Builtin.Int1) // user: %3 %3 = tuple_extract %2 : $(Builtin.Int64, Builtin.Int1), 0 // user: %4 %4 = struct $Int (%3 : $Builtin.Int64) // user: %5 return %4 : $Int // id: %5 } // end sil function '$sSi22_builtinIntegerLiteralSiBI_tcfC' 7
  3. ͪΐͬͱ෮श ~ SILίʔυͷߏ଄ • SILͷߏ଄͸ҎԼͷͬ͟ͱҎԼͷ௨Γʢςʔϒϧͱ͔Ұ෦লུʣ • SIL Module (ιʔεϑΝΠϧશମ) •

    ͷதʹɺSIL Func.on (Swi*Ͱ࡞ͬͨؔ਺͔Βੜ੒) • ͷதʹɺSIL Basic Block (৚݅෼ذͷείʔϓͱ͔) • ͷதʹɺSIL Instruc.on (ίʔυͷҰߦҰߦ) 8
  4. ͪΐͬͱ෮श ~ SILίʔυͷߏ଄ʢྫʣ // ϑΝΠϧશମ͕SIL Module sil_stage canonical import Builtin

    ... // SIL Function // main sil @main : $@convention(c) (Int32, ...) -> Int32 { // bb ͔Β࢝·Δ SIL Basic Block bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional .. // ͜͜Β͔Β SIL Instruction alloc_global @$s5valueAASivp // id: %2 ... return %8 : $Int32 // id: %9 } // end sil function 'main' Ҏ߱ɺ֤୯ޠͷ๯಄ͷSIL͸লུͰ͖ͦ͏ͳͱ͖͸লུ 9
  5. Dead Code Elimina-on • ࢖ΘΕ͍ͯͳ͍ίʔυΛ࡟আ͢Δ࠷దԽPass • ࢖ΘΕ͍ͯͳ͍ίʔυ == "ࢮΜͰΔίʔυ" ==

    Dead Code • େମͷ৔໘Ͱ DCE ͱུ͞Ε͍ͯΔ • ίϯύΠϥͷίʔυͱ͔ • ϫʔΫγϣοϓͷ՝୊Ͱ࡞Β͞Εͨ Pass • ϫʔΫγϣοϓͷ͸࡟আͷ৚͕݅ݫ͘͠ͳ͍minDCE 11
  6. Dead Code Elimina-onͷ࢓૊Έ 1. ࡟আ͠ͳ͍৚݅ʹ౰ͯ͸·Δ Instruc+on Λ Live Insturc-on ͱ

    ͯ͠Mark 2. Mark͞Ε͍ͯͳ͍ Insturc+on Λ Func+on ͔ΒऔΓআ͘ 3. Func+on ͔Β͍Βͳ͍ίʔυ͕ফ͍͑ͯΔ 4. (ƅдƅ)řŵŖ 12
  7. Dead Code Elimina-onͷ࢓૊Έ • ຊՈͰͷ Live Insturc.on ͷ͍͍ͩͨͷ৚݅ • ⭕

    return ΍ noreturn ͱ͍ͬͨ Insturc.onɻ • ϫʔΫγϣοϓͰ͸ return ͷΈ • ❌ ෭࡞༻ͷ͋ΔՄೳੑ͕͋Δ Insturc.on • ⭕ Live Instruc.on ʹґଘ͍ͯ͠Δ Instruc.on • ❌ Live Insturc.on ͕ ੍ޚґଘ ͍ͯ͠Δ৚݅෼ذ • ෳ਺ͷ Basic Block ͷؒͷ૸ࠪ • ϫʔΫγϣοϓͰ࣮૷ͨ͠ minDCE ͸ ⭕ ͕͍ͭͨ৚͚݅ͩΛར༻ 13
  8. Dead Code Elimina-onͷ࢓૊Έ ༨ஊ • ❌ Live Insturc.on ੍͕ޚґଘ͍ͯ͠Δ৚݅෼ذ •

    ෳ਺ͷ Basic Block ͷؒͷ૸ࠪ • h5ps:/ /blog.wa=.me/2018/02/19/swi=-sil-5/ ΛಡΜͰͶ 14
  9. return ΍ noreturn ͱ͍ͬͨ Insturc+on • Basic Block ͷϧʔϧ •

    Terminator ͱݺ͹ΕΔ Instruc*on ͰऴΘΒͳ͍ͱ͍͚ͳ͍ • return • noreturn • unreachable (FatalErrorͷ͋ͱʹ෇͍ͨΓ͢Δ) • throw ... 15
  10. ϫʔΫγϣοϓͰreturn͞Εͨ஋Λusefulͱͯ͠ѻͬͨ ཧ༝ • ྫ͑͹ԼͷSILίʔυ store %5 to %3 : $*Int

    // id: %6 %7 = integer_literal $Builtin.Int32, 0 // user: %8 %8 = struct $Int32 (%7 : $Builtin.Int32) // user: %9 return %8 : $Int32 // id: %9 16
  11. ϫʔΫγϣοϓͰreturn͞Εͨ஋Λusefulͱͯ͠ѻͬͨ ཧ༝ • ͜ͷίʔυ͸ ࠷ޙʹ return %8 ͯ͠Δʢid: %9ʣ •

    id: %9 ͸ return (Terminator) => Live • %8 ͷ஋Λੜ੒͍ͯ͠Δ Instruc,on ͸ ґଘ ͍ͯ͠Δ => Live • %8 Λฦ͍ͯ͠Δ Instruc,on ͸ id: %8 ͷ Inscruc,onͱݺͿ • id: %8 ͕ར༻͍ͯ͠Δ %7ʢid: %7ʣ΋ґଘ => Live • %7 ͔Β΋ɹґଘΛҶͮΔࣜʹ૸ࠪͯ͠ɹLive ͱͯ͠Markͱ͍͚ͳ͍ 17
  12. ϫʔΫγϣοϓͰreturn͞Εͨ஋Λusefulͱͯ͠ѻͬͨ ཧ༝ • ྫ͑͹ԼͷSILίʔυ͸ id: %6 ͕ফ͑Δ͔΋͠Εͳ͍ • return ʹґଘ͍ͯ͠ͳ͍Instruc,on

    • %7, %8, %9 ʹґଘ͍ͯ͠ͳ͍͔Β store %5 to %3 : $*Int // id: %6 %7 = integer_literal $Builtin.Int32, 0 // user: %8 %8 = struct $Int32 (%7 : $Builtin.Int32) // user: %9 return %8 : $Int32 // id: %9 18
  13. ϫʔΫγϣοϓͰreturn͞Εͨ஋Λusefulͱͯ͠ѻͬͨ ཧ༝ • minDCE ʹ͸໰୊఺ • noreturn ͷ࣌ͱ͔ແ৚݅Ͱ͢΂ͯͷίʔυΛফ͢ͷͰ͸ • ͦͷ࣌͸

    Instruc/onʹ ෭࡞༻͕͋Δ͔Ͳ͏͔ Λௐ΂Δ • ϫʔΫγϣοϓͰ͸͕࣌ؒ଍ΓΜͷͰলུ • ࠓ೔ͷ࿩୊͸ίϨ • ʮInstruc/onʹ ෭࡞༻͕͋Δ͔Ͳ͏͔ Λௐ΂Δʯؔ਺ͷ࿩ 19
  14. seemsUseful • ҎԼ͸ɺຊՈ DCE ʹ͋Δ seemsUseful ͱ͍͏ؔ਺ͷҰ෦ • ໊લͷ௨ΓʮUsefulͳInstruc1onʯ͔Λ true/false

    Ͱฦ͢ • Live ͱ Useful ͸ಉ͡ҙຯͱࢥͬͯྑ͍ • ઌ΄Ͳ঺հͨ͠ Terminator ͷνΣοΫ΋͜͜Ͱ൑அͯ͠Δ • Instruc1on ͷґଘͷ૸ࠪ͸·ͨผͷ৔ॴ static bool seemsUseful(SILInstruction *I) { if (I->mayHaveSideEffects()) return true; ... 20
  15. seemsUseful • Func&on தͷ Instruc&on Λ Mark ͢Δ markLive ؔ਺Ͱར༻

    • seemUseful ͷ݁Ռ͕ trueͳΒ͹ • Instruction Λ markValueLive͢Δ • ݫີʹ͸ Insctruction தͷ SIL Value ΛMark 21
  16. mayHaveSideEffects ͷ಺෦࣮૷ • ͜Μͳ͔Μ͡ bool SILInstruction::mayHaveSideEffects() const { // If

    this instruction traps then it must have side effects. if (mayTrap()) return true; MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayWrite || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } 24
  17. mayTrapʁ • / / If this instruc.on traps then it

    must have side effects. • ௚༁: ͜ͷ໋ྩ͕τϥοϓ͢Δ৔߹ɺ෭࡞༻͕͋Δ͸ͣ • trap == ϓϩάϥϜͷҟৗऴྃ 26
  18. mayTrap ͷ಺෦࣮૷ΛͱΓ͋͑ͣ೷͘ • ׂͱγϯϓϧͰ΍͍͞͠ bool SILInstruction::mayTrap() const { switch(getKind()) {

    case SILInstructionKind::CondFailInst: case SILInstructionKind::UnconditionalCheckedCastInst: case SILInstructionKind::UnconditionalCheckedCastAddrInst: return true; default: return false; } } 27
  19. dyn_cast<I> ΍ isa<T> αϯϓϧίʔυ • ࠓݟ͍ͯΔInstruc)on͕Interger Literal Instruc)on͔ݟ͍ͯΔ // Inst͕

    Interger Literal Instruction͔͠Β΂Δ // $0 = integer_literal $Builtin.Int64, 100 if (auto *BI = dyn_cast<IntegerLiteralInst>(Inst)) { 29
  20. dyn_cast<I> ΍ isa<T> • ͦΕͧΕͷInstruc)on͸ɺSILInstruction ܕΛܧঝͨ͠ܕͰ ද͞ΕΔ • SILInstruction ܕ͸ɺίϯύΠϥ্Ͱ

    SIL Instruc)on Λද ݱ͍ͯ͠Δ • ໨తͷInstruc)onܕ΁ͷμ΢ϯΩϟετ͕੒ޭ͢Ε͹ྑ͍ 30
  21. getKind • getKind ͸ΩϟετΛ࢖Θͳ͍ํ๏ • enumΛฦ͍ͯͯ͠ɺswitchͱ͔࢖͑ͯྑ͍ • SILInstructionKind ͸ɺenumͷ஋ͰInstruction͕Ͳͷछ ྨͷ΋ͷ͔Λද͢

    switch(I->getKind()) { case SILInstructionKind::IntegerLiteralInst: ... case SILInstructionKind:: ReturnLiteralInst: ... 31
  22. mayTrap ͷ಺෦࣮૷ΛͱΓ͋͑ͣ೷͘ (࠶ܝ) bool SILInstruction::mayTrap() const { switch(getKind()) { case

    SILInstructionKind::CondFailInst: case SILInstructionKind::UnconditionalCheckedCastInst: case SILInstructionKind::UnconditionalCheckedCastAddrInst: return true; default: return false; } } 32
  23. cond_fail // BNF sil-instruction ::= 'cond_fail' sil-operand, string-literal • ΋͠Φϖϥϯυ͕

    1 ͷͱ͖Run'me Failure • Φϖϥϯυ == Ҿ਺ͱߟ͑ΔͱΘ͔Γ΍͍͢ • sil-operand ͕Φϖϥϯυ cond_fail %0 : $Builtin.Int1, "failure reason" // %0 must be of type $Builtin.Int1 • h#ps:/ /github.com/apple/swi5/blob/master/docs/SIL.rst#cond_fail 36
  24. unconditional_checked_cast // BNF sil-instruction ::= 'unconditional_checked_cast' sil-operand 'to' sil-type •

    ΩϟετͰ͖Δ͔Λ͔֬ΊΔ • ΦϖϥϯυͷΦϒδΣΫτ͕ΩϟετෆՄͷ৔߹Run%me Failure • as! ͷΑ͏ͳ΋ͷ %1 = unconditional_checked_cast %0 : $A to $B %1 = unconditional_checked_cast %0 : $*A to $*B // $A and $B must be both objects or both addresses // %1 will be of type $B or $*B • h#ps:/ /github.com/apple/swi5/blob/master/docs/SIL.rst#uncondi=onal_checked_cast 37
  25. unconditional_checked_cast_addr // BNF sil-instruction ::= 'unconditional_checked_cast_addr' sil-type 'in' sil-operand 'to'

    sil-type 'in' sil-operand • Ωϟετ • ࠷ॳͷΦϖϥϯυ͕ɺ࠷ޙͷΦϖϥϯυͷܕʹ͕ΩϟετෆՄ ͷ৔߹Run%me Failure 38
  26. unconditional_checked_cast_addr • unconditional_checked_cast ͱಉ͡Α͏ʹݟ͑Δ͚Ͳ • Ͳ͏΍ΒΩϟετݩͷΦϒδΣΫτ͸ഁغ͞ΕΔΒ͍͠ unconditional_checked_cast_addr $A in %0

    : $*@thick A to $B in $*@thick B // $A and $B must be both addresses // %1 will be of type $*B // $A is destroyed during the conversion. There is no implicit copy. • h#ps:/ /github.com/apple/swi5/blob/master/docs/ SIL.rst#uncondi=onal_checked_cast • h#ps:/ /it1.jp/?p=1231 ͕Θ͔Γ΍͍͔͢΋ 39
  27. mayHaveSideEffects ͷ಺෦࣮૷ʢ࠶ܝʣ bool SILInstruction::mayHaveSideEffects() const { // If this instruction

    traps then it must have side effects. if (mayTrap()) return true; MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayWrite || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } • ͭ·ΓɺϓϩάϥϜ͕৚݅ʹΑͬͯ͸ҟৗऴྃ͢ΔͳΒʮ෭࡞༻͋Γʯͱଊ͑Δ • ͭ͗͸ Memory Behavior! 41
  28. getMemoryBehavior ͷ࣮૷ SILInstruction::MemoryBehavior SILInstruction::getMemoryBehavior() const { if (auto *BI =

    dyn_cast<BuiltinInst>(this)) { // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; // Handle LLVM intrinsic functions. const IntrinsicInfo &IInfo = BI->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) { // Read-only. if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) && IInfo.hasAttribute(llvm::Attribute::NoUnwind)) return MemoryBehavior::MayRead; // Read-none? return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } // Handle full apply sites that have a resolvable callee function with an // effects attribute. if (isa<FullApplySite>(this)) { FullApplySite Site(const_cast<SILInstruction *>(this)); if (auto *F = Site.getCalleeFunction()) { return F->getEffectsKind() == EffectsKind::ReadNone ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } switch (getKind()) { #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ return MemoryBehavior::MEMBEHAVIOR; #include "swift/SIL/SILNodes.def" } llvm_unreachable("We've just exhausted the switch."); } 43
  29. ...::MemoryBehavior::MayReadWrite • The instruc-on may read or write memory. •

    ௚༁) ಡΉ͔ॻ͖ࠐΉ͔΋͠Εͳ͍ʢ·ͨ͸ͦͷ྆ํʁʣ 49
  30. ...::MemoryBehavior::MayHaveSideEffects • The instruc-on may have side effects not captured

    solely by its users. Specifically, it can return, release memory, or store. Note, alloc is not considered to have side effects because its result/users represent its effect. • ௚༁) Instruc-on͸ɺͦͷར༻ऀ͚ͩͰ͸ଊ͑ΒΕͳ͍෭࡞༻Λ࣋ͭ͜ͱ͕ ͋Γ·͢ɻ۩ମతʹ͸ɺϦλʔϯɺϝϞϦղ์ɺετΞͳͲͰ͢ɻ஫ҙɿ alloc͸ɺͦͷ݁Ռ/ར༻ऀ͕ͦͷ࡞༻Λද͢ͷͰɺ෭࡞༻͕͋Δͱ͸ߟ͑ ΒΕ·ͤΜɻ • ҙ༁ʣͳʹ͔͠Βɺͷͪͷͪ෭࡞༻͕͋Δ 50
  31. MemoryBehavior ? • ͭ·Γ͸ɺͦͷInstruc(on͕ɺͲͷΑ͏ʹϝϞϦ্ͰৼΔ෣͏͔ Λද͢ • ݟͨײͩ͡ͱɺ࣍ͷϝϞϦ্ͷৼΔ෣͍͕ʮ෭࡞༻ʯͱͯ֘͠౰͢ΔΑ͏ʹ͍ͯ͠Δ • MayWrite (ॻ͖)

    • MayReadWrite (ಡΈॻ͖) • MayHaveSideEffects (෭࡞༻͋Γ) • seemUseful ͸ɺࠓݟ͍ͯΔInscruc+onʹ෭࡞༻͕͋Δ͔ௐ΂͍ͯΔ 51
  32. getMemoryBehaviorͷ࣮૷ΛݟΔ ࠷ॳͷ if ʹϑΥʔΧεΛ౰ͯΔ if (auto *BI = dyn_cast<BuiltinInst>(this)) {

    // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; // Handle LLVM intrinsic functions. const IntrinsicInfo &IInfo = BI->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) { // Read-only. if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) && IInfo.hasAttribute(llvm::Attribute::NoUnwind)) return MemoryBehavior::MayRead; // Read-none? return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } 52
  33. BuiltinInst ͱ͸ʁ • Represents an invoca/on of buil/n func/onality provided

    by the code generator. • ௚༁) ίʔυɾδΣωϨʔλ͕ఏڙ͢Δ૊ΈࠐΈػೳͷݺͼग़ ͠Λද͠·͢ɻ • ! ! ! ! ! 54
  34. BuiltinInst ͱ͸ʁ • SIL.rst ʹ͋ͬͨ • h+ps:/ /github.com/apple/swi:/blob/master/docs/SIL.rst#buil=n • Invokes

    func=onality built into the backend code generator, such as LLVM- level instruc=ons and intrinsics. • SIL Instruc=on ͷ๯಄ʹ builtin ͱ͍͍ͭͯΔͷ͕ϙΠϯτ • ௚༁) LLVMϨϕϧͷ໋ྩ΍૊ΈࠐΈؔ਺ͳͲɺόοΫΤϯυίʔυδΣωϨʔλʔʹ૊Έࠐ·ΕͨػೳΛ ݺͼग़͠·͢ɻ swift // Example %1 = builtin "foo"(%1 : $T, %2 : $U) : $V 55
  35. BuiltinInst ͱ͸ʁ Swi% buil)n func)on • Swi$(SIL)ͷίʔυϨϕϧͰදݱͰ͖ͳ͍ॲཧ ͷݺͼग़͠ • LLVMͷॲཧʹॻ͖׵ΘΔ΂͖৔ॴ

    • ྫ) Int(64)ಉ࢜ͷൺֱԋࢉ // SIL %5 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %4 : $Builtin.Int64) ... ↓ LLVM IRͩͱ͜͏ͳΔ // LLVM IR %10 = icmp eq i64 %8, 10 57
  36. BuiltinInst ͱ͸ʁ Swi% buil)n func)on • Buil&ns.def ʹbuil&n func&onͷҰཡ͋Γ •

    ͪͳΈʹઌఔͷ cmp_eq_Int64 ͸ɺBuil&ns.def Ͱ͸ cmp_eq ͱͯ͠Ϧετ͞Ε͍ͯΔ 58
  37. getMemoryBehaviorͷ࣮૷ΛݟΔ Swi$ buil)n func)ons • ݟͨײ͡ɺͦͷ̎ͭͰ৚݅Λ෼͚͍ͯΔ • Swi% buil*n func*ons

    ΁ͷΞϓϩʔνΛ·ͣ͸ݟͯΈΔ if (auto *BI = dyn_cast<BuiltinInst>(this)) { // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); ... // Handle LLVM intrinsic functions. const IntrinsicInfo &IInfo = BI->getIntrinsicInfo(); ... } 60
  38. getMemoryBehaviorͷ࣮૷ΛݟΔ Swi$ buil)n func)ons if (auto *BI = dyn_cast<BuiltinInst>(this)) {

    // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; • Ͳ͏΍Β͜ͷbuil&nͷfunc&onͷ৘ใΛͱͬͯɺҎԼͷ৘ใΛ΋ͱʹMemory BehaviorΛ൑அ • BInfo.ID • BInfo.isReadNone() 61
  39. BInfo.ID • ݟͨײ͡ BuiltinValueKind ͸ enum /// BuiltinValueKind - The

    set of (possibly overloaded) builtin functions. enum class BuiltinValueKind { None = 0, #define BUILTIN(Id, Name, Attrs) Id, #include "swift/AST/Builtins.def" }; • Ͳ͏΍Βઌఔݴٴͨ͠ Buil'ns.def ͔ΒɺͳΜ͔औ͍ͬͯΔʁ 63
  40. BInfo.ID • Buil&ns.def Λ೷͘ • ͖ͬ͞ݴٴͨ͠ cmp_eq_Int64 पลͷ෦෼ΛݟͯΈΔ ... #ifndef

    BUILTIN_BINARY_PREDICATE #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \ BUILTIN(Id, Name, Attrs) #endif BUILTIN_BINARY_PREDICATE(ICMP_EQ, "cmp_eq", "n", IntegerOrRawPointerOrVector) BUILTIN_BINARY_PREDICATE(ICMP_NE, "cmp_ne", "n", IntegerOrRawPointerOrVector) BUILTIN_BINARY_PREDICATE(ICMP_SLE, "cmp_sle", "n", IntegerOrVector) ... 64
  41. BInfo.ID BUILTIN_BINARY_PREDICATEͱ͍͏΋ͷ͕ఆٛ͞Ε͍ͯΔ // ϚΫϩ BUILTIN_BINARY_PREDICATE(ICMP_EQ, "cmp_eq", "n", IntegerOrRawPointerOrVector) ICMP_EQ͕͖ͬ͞ྫͰࡌ͍ͬͯͨ cmp_eq

    ͷId ҎԼͰBUILTINʹม׵Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ // ϚΫϩ #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \ BUILTIN(Id, Name, Attrs) 65
  42. BInfo.ID /// BuiltinValueKind - The set of (possibly overloaded) builtin

    functions. enum class BuiltinValueKind { None = 0, #define BUILTIN(Id, Name, Attrs) Id, #include "swift/AST/Builtins.def" }; • ͭ·ΓɺBInfo.ID ͸Builtns.defͰఆٛ͞Εͨɺbuil/n func/onͷID • Buil/ns.defͷ಺෦ͷϚΫϩͰ BUILTIN(Id, Name, Attrs) ʹ͔͑ͯɺ • ͦͷBUILTIN - Id Λenumͷ஋ʹ͍ͯ͠Δ 66
  43. getMemoryBehaviorͷ࣮૷ΛݟΔ Swi$ buil)n func)ons • if (BInfo.ID != BuiltinValueKind::None) •

    false ͳΒLLVM intrinsic func.on ͱͯ࣍͠ͷύʔτͰϋϯυϦϯά if (auto *BI = dyn_cast<BuiltinInst>(this)) { // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; • ࣍͸ isReadNoneɻ͚ͩͲ͍͍ͩͨಉ͡ϝΧχζϜͳͷͰαοͱ঺հ 67
  44. isReadNone • buil&n func&on͕ ϝϞϦΞΫηεΛڐՄ͞Ε͍ͯΔ͔Λௐ΂Δ • LLVM IRͰ͸ؔ਺ʹ ଐੑ(A#ribute) ͕͚ͭΒΕΔ

    • Ͳ͏͍͏ৼΔ෣͍Λߦ͏͔ʁ͕ଐੑ͔ΒಡΈऔΕΔ • readnone ଐੑ͕͍͍ͭͯΔͱɺϝϞϦΞΫηε͕ڐՄ͞Εͳ͍ • ٯʹݴ͑͹ɺreadnone͕͍ͭͯͳ͚Ε͹ɺͳʹ͔ϝϞϦͰ΍Δ͔ ΋͠Εͳ͍ͱ͍͏͜ͱʹͳΔ 68
  45. isReadNone // Builtins.def ͔Β·ͨൈਮ #ifndef BUILTIN_BINARY_PREDICATE #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs,

    Overload) \ BUILTIN(Id, Name, Attrs) #endif BUILTIN_BINARY_PREDICATE(ICMP_EQ, "cmp_eq", "n", IntegerOrRawPointerOrVector) • BUILTIN(Id, Name, Attrs) ͷͳ͔Ͱ Attrs="n" ͩͬͨΒ readnone • ϝϞϦΞΫηε͕Ͱ͖ͳ͍ॲཧʹม׵͞ΕΔͱ͍͏͜ͱ • bul&n func&ons ͸ Bul&ns.def Ͱ ଐੑΛҰͭҰͭ ϥϕϦϯάͯ͠Δ • ม׵ઌ͸ɺଐੑ͕͚ͭΕͳ͍ Instruc&on ୯ମ͔ͩΒʁ 69
  46. getMemoryBehavior ͷ࣮૷ΛݟΔ Swi$ buil)n func)ons if (auto *BI = dyn_cast<BuiltinInst>(this))

    { // Handle Swift builtin functions. const BuiltinInfo &BInfo = BI->getBuiltinInfo(); if (BInfo.ID != BuiltinValueKind::None) return BInfo.isReadNone() ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; • ͭ·Γ↑͸ ҎԼͷΑ͏ʹಡΈऔΕΔ • Insruc*onͷ৘ใ͔Βɺbuil*n func*on ͷଐੑΛݟΔ • ΋͠ɺreadnone (ϝϞϦΞΫηε͕ڐՄ͞Εͯͳ͍ʣͳΒ෭࡞༻͸౰વͳ͠ • ͦ͏Ͱͳ͍ͳΒɺ෭࡞༻͸ԿΒ͔ͷܗͰ͋Δ͔΋͠Εͳ͍ 70
  47. getMemoryBehaviorͷ࣮૷ΛݟΔ Swi$ buil)n func)ons • ͜ͷ·ͰͷϊϦ͕Θ͔Δͱޙ൒΋Θ͔Δ • ࣍͸ɺLLVM intrinsic func.onsͷϋϯυϦϯά

    • ͬͪ͜΋ଐੑΛݟͯΔͷ͕ϊϦͰΘ͔Δ // Handle LLVM intrinsic functions. const IntrinsicInfo &IInfo = BI->getIntrinsicInfo(); if (IInfo.ID != llvm::Intrinsic::not_intrinsic) { // Read-only. if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) && IInfo.hasAttribute(llvm::Attribute::NoUnwind)) return MemoryBehavior::MayRead; // Read-none? return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } 71
  48. getMemoryBehaviorͷ࣮૷ΛݟΔ Swi$ buil)n func)ons if (IInfo.hasAttribute(llvm::Attribute::ReadOnly) && IInfo.hasAttribute(llvm::Attribute::NoUnwind)) return MemoryBehavior::MayRead;

    // Read-none? return IInfo.hasAttribute(llvm::Attribute::ReadNone) && IInfo.hasAttribute(llvm::Attribute::NoUnwind) ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; • ͭ·Γ↑ͷίʔυ͸ • ྫ֎Λ֎ʹ౤͛ͳ͍Ͱɺ͔ͭಡΈࠐΈΦϯϦʔͷؔ਺͸ MayRead • ྫ֎Λ֎ʹ౤͛Δɺ·ͨ͸ɺϝϞϦΞΫηεͰ͖Δؔ਺͸ MayHaveSideEffects • ͦΕҎ֎͸ None 73
  49. getMemoryBehaviorͷ࣮૷ΛݟΔ • bul%n instruc%on Ͱ͸ͳ͍৔߹͸Ͳ͏͔ • ࣍ͷύʔτΛݟͯΈΔ // Handle full

    apply sites that have a resolvable callee function with an // effects attribute. if (isa<FullApplySite>(this)) { FullApplySite Site(const_cast<SILInstruction *>(this)); if (auto *F = Site.getCalleeFunction()) { return F->getEffectsKind() == EffectsKind::ReadNone ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } 75
  50. FullApplySite • apply, begin_apply ͱ͍ͬͨؔ਺ݺͼग़͠ͷͨΊͷInsruc*on͕ ͋Δ • apply • begin_apply

    • try_apply • PassͷίʔυͰ͸ɺFullApplySite ͱ͍͏ܕͰ·ͱΊΒΕ͍ͯΔ 76
  51. SIL Func)onͷA,ribute • SIL Func)on ʹ΋ଐੑ͸͋Δ • h#ps:/ /github.com/apple/swi5/blob/master/docs/SIL.rst#func>ons //

    BNF sil-function-attribute ::= '[' sil-function-effects ']' sil-function-effects ::= 'readonly' sil-function-effects ::= 'readnone' sil-function-effects ::= 'readwrite' sil-function-effects ::= 'releasenone' 77
  52. SIL Func)onͷA,ribute • sil-function-attribute ͸SIL Func)onͷએݴ࣌ʹඞਢ // BNF sil-function ::=

    'sil' sil-linkage? sil-function-attribute+ sil-function-name ':' sil-type '{' sil-basic-block+ '}' 78
  53. getMemoryBehaviorͷ࣮૷ΛݟΔ • Έ͔ͨΜ͡ • ؔ਺ݺͼग़͠ͷInstruc)on͔Ͳ͏͔ௐ΂͍ͯΔ • ؔ਺ݺͼग़ͩͬͨ͠Β callee(ݺͼͨؔ͢਺)ͷଐੑΛௐ΂Δ • ReadNone

    ͡Όͳ͍ͳΒ MayHaveSideEffects if (isa<FullApplySite>(this)) { FullApplySite Site(const_cast<SILInstruction *>(this)); if (auto *F = Site.getCalleeFunction()) { return F->getEffectsKind() == EffectsKind::ReadNone ? MemoryBehavior::None : MemoryBehavior::MayHaveSideEffects; } } 79
  54. getMemoryBehaviorͷ࣮૷ΛݟΔ • ࠷ޙͷύʔτ • Ͳ͏ݟͯ΋Buil&n.def(Swi/ buil&n funcion)ͷͱ͖ͱಉ͡ύλʔϯ switch (getKind()) {

    #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ return MemoryBehavior::MEMBEHAVIOR; #include "swift/SIL/SILNodes.def" } llvm_unreachable("We've just exhausted the switch."); 81
  55. SILNodes.def ͷMEMBEHAVIORʹ͍ͭͯ • SILNodes.defʹ֤Instruc1on͕ͲͷΑ͏ʹϝϞϦ্ͷৼΔ෣͏͔ॻ͍ͯ͋Δ • FULL_INST ͱ͍͏৘ใͰ·ͱΊΒΕ͍ͯΔ • CLASS ʹ͸ɺ͖ͬ͞ͷ

    SILInstructionKind ͱಉ͡஋ׂ͕ΓৼΒΕ͍ͯ Δ ( getKind ͷ໭Γ஋ͷenumܕ) • MEMBEHAVIOR ʹ͸ɺMemoryBehavior ͱಉ͡஋ׂ͕ΓৼΒΕ͍ͯΔ ʢenumܕ) • ઌఔͷ Buil1ns.def ͷͱ͖ͱಉ͡ɹ 82
  56. getMemoryBehavior ͷ࣮૷ΛݟΔ • ͱ͍͏͜ͱ͸ɺ • SILNodes.def ʹ͋ΔɺʮInscrutc2on͕ϝϞϦ্ͰͲͷΑ͏ʹৼΔ෣͏͔ ʢMEMBEHAVIORʣʯͷఆٛΛϚΫϩͰ switch-case ʹల։͍ͯ͠Δ

    switch (getKind()) { #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ return MemoryBehavior::MEMBEHAVIOR; #include "swift/SIL/SILNodes.def" } llvm_unreachable("We've just exhausted the switch."); 83
  57. getMemoryBehaviorͷ࣮૷ΛݟΔ ·ͱΊ • getMemoryBehavior ͸ҎԼͷ؍఺ͰInstruc*onͷϝϞϦͷৼΔ෣͍Λݟ͍ͯΔ • ม׵ઌͷ LLVM IR ͷ

    Instrucion ͸ɺͲΜͳଐੑʹͳΔ͔ʁ • Attrs in Buil*ns.def • ݺͼग़͢ LLVM IR ͷ Func0on ͸ɺͲΜͳଐੑ͔ʁ • ݺͼग़͍ͯ͠Δ SIL Function ͸ɺͲΜͳଐੑ͔ʁ • ↑ Ͱ΋Θ͔Μͳ͍ͳΒɺطʹ Instruc0on ʹఆٛ͞Ε͍ͯΔଐੑΛݟʹߦ͘ • MEMBEHAVIOR in SILNode.def 84
  58. mayHaveSideEffects ·ͱΊ • ࣍ͷ৔߹ɺSIL Instruc,on ʹ෭࡞༻͕͋ΔͱίϯύΠϥ͸൑அ͢Δ • ৚݅ʹΑͬͯ͸ɺRun,me Failure ͢Δ͔ʁ

    • ৚݅ʹΑͬͯ͸ɺϝϞϦ্Ͱॻ͖ࠐΈͳͲͱ͍ͬͨ͜ͱΛߦ͏͔ʁ bool SILInstruction::mayHaveSideEffects() const { // If this instruction traps then it must have side effects. if (mayTrap()) return true; MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayWrite || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } 86
  59. ࢀߟจݙ • Θ͍Θ͍swi%c ϫʔΫγϣοϓ Vol.3 ෱Ԭ • Swi%ͷதؒݴޠSILΛಡΉ ͦͷ5 -

    Dead Code Elimina:on • SILOp:mizerʹܰ͘ೖ໳͢Δ • SIL.rst • LLVM/Clang࣮ફ׆༻ϋϯυϒοΫ 91