mayHaveSideEffect

 mayHaveSideEffect

1405a601755e5fcbfdc93a2560368bb1?s=128

freddi(Yuki Aki)

May 22, 2020
Tweet

Transcript

  1. mayHaveSideEffects Θ͍Θ͍swi$c #20 22nd/May/2020 @___freddi___ 1

  2. ຊ೔ͷ࿩ͷྲྀΕɾझࢫ • Θ͍Θ͍swi%c ൪֎ฤϫʔΫγϣοϓ #3 - ෱Ԭ ͷ෮श • ʮ෭࡞༻͕͋Γͦ͏ʯͳίʔυΛίϯύΠϥ͕ݟ͚ͭํΛ஌Δ

    2
  3. Θ͍Θ͍swi$c ൪֎ฤϫʔΫγϣοϓ #3 - ෱Ԭ • ͝ࢀՃ͋Γ͕ͱ͏͍͟͝·ͨ͠ • ΈΜͳҰੜݒ໋ղ͍͍ͯͯخ͍͠Ͱ͢ •

    C++ ͷ෦෼͕೉͔ͬͨ͠ͷͰղ͚ͳͯ͘΋౰વͰ͢ 3
  4. Θ͍Θ͍swi$c ൪֎ฤϫʔΫγϣοϓ #3 - ෱Ԭ • ࢿྉ͸શͯઌिެ։͠·ͨ͠ • ͨͩ͠ϫʔΫγϣοϓͷϨϙδτϦ͸ফ͍ͯ͠·͢ •

    h#ps:/ /qiita.com/freddi_/items/aa604dd68697f823a41d 4
  5. ͪΐͬͱ෮श ~ SILͱ͸ • Swi%ͷதؒදݱݴޠ (Swi% Intermediate Language) • Swi%ͷίʔυΛίϯύΠϧ͍ͯ͠Δ్தͰݱΕΔ

    • ࠷దԽ͸SILͷίʔυͰߦΘΕΔ • ࠷దԽલͷSIL͕raw SILɺޙ͕canonical SIL 5
  6. ͪΐͬͱ෮श ~ SILʢྫʣ SILʹม׵લ var a = 10 6

  7. ͪΐͬͱ෮श ~ 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
  8. ͪΐͬͱ෮श ~ SILίʔυͷߏ଄ • SILͷߏ଄͸ҎԼͷͬ͟ͱҎԼͷ௨Γʢςʔϒϧͱ͔Ұ෦লུʣ • SIL Module (ιʔεϑΝΠϧશମ) •

    ͷதʹɺSIL Func.on (Swi*Ͱ࡞ͬͨؔ਺͔Βੜ੒) • ͷதʹɺSIL Basic Block (৚݅෼ذͷείʔϓͱ͔) • ͷதʹɺSIL Instruc.on (ίʔυͷҰߦҰߦ) 8
  9. ͪΐͬͱ෮श ~ 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
  10. ͪΐͬͱ෮श ~ SILOp(mizer • SIL Λ࠷దԽ͢ΔίϯύΠϥͷϞδϡʔϧ • ͦΕͧΕͷ࠷దԽͷ໾ׂΛ࣋ͭ Pass ͱ͍͏Ϟδϡʔϧ͔ΒͳΔ

    • Module શମΛݟΔ Pass ͱ Func2on ΛݟΔ Pass ͕͋Δ 10
  11. Dead Code Elimina-on • ࢖ΘΕ͍ͯͳ͍ίʔυΛ࡟আ͢Δ࠷దԽPass • ࢖ΘΕ͍ͯͳ͍ίʔυ == "ࢮΜͰΔίʔυ" ==

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

    ͯ͠Mark 2. Mark͞Ε͍ͯͳ͍ Insturc+on Λ Func+on ͔ΒऔΓআ͘ 3. Func+on ͔Β͍Βͳ͍ίʔυ͕ফ͍͑ͯΔ 4. (ƅдƅ)řŵŖ 12
  13. 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
  14. Dead Code Elimina-onͷ࢓૊Έ ༨ஊ • ❌ Live Insturc.on ੍͕ޚґଘ͍ͯ͠Δ৚݅෼ذ •

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

    Terminator ͱݺ͹ΕΔ Instruc*on ͰऴΘΒͳ͍ͱ͍͚ͳ͍ • return • noreturn • unreachable (FatalErrorͷ͋ͱʹ෇͍ͨΓ͢Δ) • throw ... 15
  16. ϫʔΫγϣοϓͰ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
  17. ϫʔΫγϣοϓͰ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
  18. ϫʔΫγϣοϓͰ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
  19. ϫʔΫγϣοϓͰreturn͞Εͨ஋Λusefulͱͯ͠ѻͬͨ ཧ༝ • minDCE ʹ͸໰୊఺ • noreturn ͷ࣌ͱ͔ແ৚݅Ͱ͢΂ͯͷίʔυΛফ͢ͷͰ͸ • ͦͷ࣌͸

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

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

    • seemUseful ͷ݁Ռ͕ trueͳΒ͹ • Instruction Λ markValueLive͢Δ • ݫີʹ͸ Insctruction தͷ SIL Value ΛMark 21
  22. mayHaveSideEffects • seemsUseful ͰUseful͔Ͳ͏͔ͷ൑அʹ࢖ΘΕ͍ͯΔؔ਺ • ͜ΕͰʮ෭࡞༻͕͋Δ͔Ͳ͏͔ʯΛ൑அͯ͠ΔΒ͍͠ • ৚݅ʹΑͬͯ͸෭࡞༻Λൃੜ͠ͳ͍͜ͱ΋͋ΔͷͰ may 22

  23. mayHaveSideEffects ΁ͷٙ໰ • mayHaveSideEffects ͸ɺ ԿΛʮ෭࡞༻ʯͱ͍ͯ͠Δͷ͔ʁ • ಺෦࣮૷Λݟ͔ͯ֬ΊͯΈ͍ͨ 23

  24. 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
  25. mayHaveSideEffects ͷ಺෦࣮૷ͷݟΔϙΠϯτʁ • ͜ͷ̎ͭΛϑΥʔΧε͢Ε͹ɺṖΛղ໌Ͱ͖ͦ͏ʂ • mayTrap • MemoryBehavior 25

  26. mayTrapʁ • / / If this instruc.on traps then it

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

    case SILInstructionKind::CondFailInst: case SILInstructionKind::UnconditionalCheckedCastInst: case SILInstructionKind::UnconditionalCheckedCastAddrInst: return true; default: return false; } } 27
  28. dyn_cast<I> ΍ isa<T> • PassͰ͸ɺίʔυதͰݟΔInsctruc+on͸SILInstructionܕ • ۩ମతͳInstruc+onͷछྨΛ஌Δʹ͸ʁ • dyn_cast<I> ΍

    isa<T> (Ωϟετ)Λ࢖ͬͯ֬ೝͰ͖Δ 28
  29. 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
  30. dyn_cast<I> ΍ isa<T> • ͦΕͧΕͷInstruc)on͸ɺSILInstruction ܕΛܧঝͨ͠ܕͰ ද͞ΕΔ • SILInstruction ܕ͸ɺίϯύΠϥ্Ͱ

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

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

    SILInstructionKind::CondFailInst: case SILInstructionKind::UnconditionalCheckedCastInst: case SILInstructionKind::UnconditionalCheckedCastAddrInst: return true; default: return false; } } 32
  33. ͭ·Γʁ • ͜ͷ3ͭͷInstruc*on͸trapͳͷͰUsefulʹͳ͍ͬͯΔ • CondFailInst • UnconditionalCheckedCastInst • UnconditionalCheckedCastAddrInst 33

  34. Θ͔Βͳ͍͜ͱ͸SIL.rstͰௐ΂Α͏ • SIL.rstʹ͸͍͍ͩͨͷInstruc,onͷ৘ใ͕৐͍ͬͯ·͢ 34

  35. SIL.rstͰInstruc+onΛௐ΂Δίπ • ΩϟϜϧέʔεʹͳͬͯΔͷΛεωʔΫέʔεʹ෼ղͯ͠Ctrl+F • cond_fail • unconditional_checked_cast • unconditional_checked_cast_addr •

    શ෦ώοτ͠·͢ 35
  36. 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
  37. 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
  38. 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
  39. 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
  40. unconditional_checked_cast_value ͸Ͳ͏ͳ ͷʁ • mayTrap ʹೖͬͯͳ͍ unconditional_checked ܥ౷ͷ Instruc*on •

    ೖΕ๨Ε͔ɺͦ͏Ͱͳ͍͔ෆ໌ • Run*me Failure ͢Δͷʹ .... 40
  41. 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
  42. getMemoryBehavior ͱ͸ • ͦͷ SIL Instruc,on ͕ϝϞϦ্ͰͲ͏ৼΔ෣͏͔Λௐ΂Δ • ಡΈղ͘ʹ͸ɺΘΓͱLLVMͷ஌͕ࣝඞཁ 42

  43. 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
  44. getMemoryBehavior • ௕͍;; • ·ͣ͸໭Γ஋ͷ enum ͔Βݟ͍ͯ͘ 44

  45. SILInstruction::MemoryBehavior • ϝϞϦ্ͷৼΔ෣͍Λఆٛ͢Δ enum • ҎԼͷ5͕ͭఆٛ͞Ε͍ͯΔ • None • MayRead

    • MayWrite • MayReadWrite • MayHaveSideEffects 45
  46. SILInstruction::MemoryBehavior::None • Կ΋͠ͳ͍΍ͭ 46

  47. SILInstruction::MemoryBehavior::MayRead • The instruc-on may read memory. • ௚༁) ϝϞϦΛಡΉ͔΋͠Εͳ͍

    47
  48. SILInstruction::MemoryBehavior::MayWrite • The instruc-on may write to memory. • ௚༁)

    ϝϞϦʹॻ͖ࠐΉ͔΋͠Εͳ͍ 48
  49. ...::MemoryBehavior::MayReadWrite • The instruc-on may read or write memory. •

    ௚༁) ಡΉ͔ॻ͖ࠐΉ͔΋͠Εͳ͍ʢ·ͨ͸ͦͷ྆ํʁʣ 49
  50. ...::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
  51. MemoryBehavior ? • ͭ·Γ͸ɺͦͷInstruc(on͕ɺͲͷΑ͏ʹϝϞϦ্ͰৼΔ෣͏͔ Λද͢ • ݟͨײͩ͡ͱɺ࣍ͷϝϞϦ্ͷৼΔ෣͍͕ʮ෭࡞༻ʯͱͯ֘͠౰͢ΔΑ͏ʹ͍ͯ͠Δ • MayWrite (ॻ͖)

    • MayReadWrite (ಡΈॻ͖) • MayHaveSideEffects (෭࡞༻͋Γ) • seemUseful ͸ɺࠓݟ͍ͯΔInscruc+onʹ෭࡞༻͕͋Δ͔ௐ΂͍ͯΔ 51
  52. 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
  53. getMemoryBehaviorͷ࣮૷ΛݟΔ • ΩϟετͰInstruc)on͕ BuiltinInst ͳͷ͔Λௐ΂ͯΔ if (auto *BI = dyn_cast<BuiltinInst>(this))

    { ... 53
  54. BuiltinInst ͱ͸ʁ • Represents an invoca/on of buil/n func/onality provided

    by the code generator. • ௚༁) ίʔυɾδΣωϨʔλ͕ఏڙ͢Δ૊ΈࠐΈػೳͷݺͼग़ ͠Λද͠·͢ɻ • ! ! ! ! ! 54
  55. 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
  56. Buil%nInst ͱ͸ʁ • BuiltinInst ʹ͸ҎԼͷ̎ͭͷछྨ͕͋Δ • Swi$ buil)n func)on •

    LLVM intrinsic func)on 56
  57. 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
  58. BuiltinInst ͱ͸ʁ Swi% buil)n func)on • Buil&ns.def ʹbuil&n func&onͷҰཡ͋Γ •

    ͪͳΈʹઌఔͷ cmp_eq_Int64 ͸ɺBuil&ns.def Ͱ͸ cmp_eq ͱͯ͠Ϧετ͞Ε͍ͯΔ 58
  59. BuiltinInstͱ͸ʁ LLVM intrinsic func-ons • LLVMʹɺطʹ͋Δؔ਺ΛಡΈࠐΉ ίʔυ 59

  60. 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
  61. 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
  62. BInfo.ID • BInfo.ID ͱ͸? • ໭Γ஋ʹͳͬͯΔͷ͸ɺBuiltinValueKindܕ • ܕͷৄࡉΛݟͯΈΔ 62

  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. isReadNone • buil&n func&on͕ ϝϞϦΞΫηεΛڐՄ͞Ε͍ͯΔ͔Λௐ΂Δ • LLVM IRͰ͸ؔ਺ʹ ଐੑ(A#ribute) ͕͚ͭΒΕΔ

    • Ͳ͏͍͏ৼΔ෣͍Λߦ͏͔ʁ͕ଐੑ͔ΒಡΈऔΕΔ • readnone ଐੑ͕͍͍ͭͯΔͱɺϝϞϦΞΫηε͕ڐՄ͞Εͳ͍ • ٯʹݴ͑͹ɺreadnone͕͍ͭͯͳ͚Ε͹ɺͳʹ͔ϝϞϦͰ΍Δ͔ ΋͠Εͳ͍ͱ͍͏͜ͱʹͳΔ 68
  69. 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
  70. 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
  71. 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
  72. LLVMͷؔ਺ͷଐੑ NoUnwind • ଐੑ NoUnwind • ྫ֎Λ౤͛ͳ͍ͱ͍͏ଐੑ 72

  73. 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
  74. getMemoryBehaviorͷ࣮૷ΛݟΔ ͜͜·Ͱͷ·ͱΊ • ·ͣ͸ɺͦͷInstruc)on͕bul)n instruc)on͔ݟΔ • ΋ͦ͠͏Ͱ͋Ε͹ɺLLVM IR ʹͳͬͨޙͷଐੑΛݟͯɺϝϞ Ϧ্ͷৼΔ෣͍Λ൑அ

    74
  75. 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
  76. FullApplySite • apply, begin_apply ͱ͍ͬͨؔ਺ݺͼग़͠ͷͨΊͷInsruc*on͕ ͋Δ • apply • begin_apply

    • try_apply • PassͷίʔυͰ͸ɺFullApplySite ͱ͍͏ܕͰ·ͱΊΒΕ͍ͯΔ 76
  77. 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
  78. 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
  79. 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
  80. getMemoryBehaviorͷ࣮૷ΛݟΔ ͜͜·ͰΘ͔ͬͨ͜ͱ • SIL Instruc,onͷϝϞϦͷৼΔ෣͍Λௐ΂Δͱ͖͸ɺLLVM ͷଐ ੑΛར༻͍ͯ͠Δ • ΋͘͠͸ SIL

    Func,on ͷଐੑ 80
  81. 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
  82. SILNodes.def ͷMEMBEHAVIORʹ͍ͭͯ • SILNodes.defʹ֤Instruc1on͕ͲͷΑ͏ʹϝϞϦ্ͷৼΔ෣͏͔ॻ͍ͯ͋Δ • FULL_INST ͱ͍͏৘ใͰ·ͱΊΒΕ͍ͯΔ • CLASS ʹ͸ɺ͖ͬ͞ͷ

    SILInstructionKind ͱಉ͡஋ׂ͕ΓৼΒΕ͍ͯ Δ ( getKind ͷ໭Γ஋ͷenumܕ) • MEMBEHAVIOR ʹ͸ɺMemoryBehavior ͱಉ͡஋ׂ͕ΓৼΒΕ͍ͯΔ ʢenumܕ) • ઌఔͷ Buil1ns.def ͷͱ͖ͱಉ͡ɹ 82
  83. 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
  84. getMemoryBehaviorͷ࣮૷ΛݟΔ ·ͱΊ • getMemoryBehavior ͸ҎԼͷ؍఺ͰInstruc*onͷϝϞϦͷৼΔ෣͍Λݟ͍ͯΔ • ม׵ઌͷ LLVM IR ͷ

    Instrucion ͸ɺͲΜͳଐੑʹͳΔ͔ʁ • Attrs in Buil*ns.def • ݺͼग़͢ LLVM IR ͷ Func0on ͸ɺͲΜͳଐੑ͔ʁ • ݺͼग़͍ͯ͠Δ SIL Function ͸ɺͲΜͳଐੑ͔ʁ • ↑ Ͱ΋Θ͔Μͳ͍ͳΒɺطʹ Instruc0on ʹఆٛ͞Ε͍ͯΔଐੑΛݟʹߦ͘ • MEMBEHAVIOR in SILNode.def 84
  85. getMemoryBehaviorͷ࣮૷ΛݟΔ શ෦ಡΊͨʂ 85

  86. 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
  87. ·ͱΊ 87

  88. ίϯύΠϥʹͱͬͯʮ෭࡞༻͕͋Γͦ͏ʯͳίʔυͱ͸ Ұମʁ • Run%me Error͕ى͜Γͦ͏ͳίʔυ • ϝϞϦॻ͖ࠐΈͳͲ͕ى͜Γͦ͏ͳίʔυ 88

  89. ίϯύΠϥʹͱͬͯʮ෭࡞༻͕͋Γͦ͏ʯͷ൑ผͷ࢓ํ • LLVM ͷଐੑͳͲΛར༻ͯ͠൑அ͍ͯ͠Δ • Buil*ns.def ΍ LLVM ͷؔ਺͔ΒಡΈऔͬͯ൑அ •

    SILNodes.def Ͱ SIL Instruc*on ͷϝϞϦͷৼΔ෣͍͸ఆٛ͞Ε ͍ͯΔ 89
  90. ࠓ೔ษڧͨ͜͠ͱ • LLVMɺSIL ͷ ଐੑ(A*ribute) • SILNodes.def • Buil:ns.def •

    mayHaveSideEffects • getMemoryBehavior 90
  91. ࢀߟจݙ • Θ͍Θ͍swi%c ϫʔΫγϣοϓ Vol.3 ෱Ԭ • Swi%ͷதؒݴޠSILΛಡΉ ͦͷ5 -

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