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

意外と知られてないXcode13の新しい参照カウンタ最適化オプションの挙動

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 意外と知られてないXcode13の新しい参照カウンタ最適化オプションの挙動

Avatar for freddi(Yuki Aki)

freddi(Yuki Aki)

November 16, 2021
Tweet

More Decks by freddi(Yuki Aki)

Other Decks in Technology

Transcript

  1. Swift Compiler ίϚϯυΛݟΔ Swiftc ͷ௥ՃΦϓγϣϯ /../swiftc ... -enforce-exclusivity\=checked -Xfrontend -enable-copy-propagation

    ... # Without OPTIMIZE_OBJECT_LIFETIME 
 /../swiftc ... -enforce-exclusivity\=checked ...
  2. -enable-copy-propagation swift ίϯύΠϥͷίʔυ͔ΒΦϓγϣϯΛಡΈղ͘ • Run SIL propagation to shorten object

    lifetime • SIL఻೻Λ૸ΒͤɺΦϒδΣΫτͷϥΠϑλΠϜΛ୹ॖ • Α͘Θ͔ΒΜ
  3. ࠷దԽςΫχοΫ • ίϐʔ఻೻ɺෳࣸͷ఻೻ʢ೔ຊޠ༁ʣ • a = b; c = a

    + d ͱ͍͏ίʔυΛ c = b + d ʹ͢Δ࠷దԽ Copy Propagation http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/note11.html
  4. SIL Ͱͷ ARC ͷදݱʹ͍ͭͯ Reference Count ΛݮΒ͢ɾ૿΍͢ίʔυ • strong_retain •

    Χ΢ϯτΛʴ̍͢Δ • strong_release • Χ΢ϯτΛʔ̍͢Δ • ͋ͱΧ΢ϯτ͕0ҎԼʹͳͬͨΦϒδΣΫτΛഁغ
  5. ࣮ࡍͷSILͰͷARCΧ΢ϯτΛݟΔ ࣮ࡍͷίʔυʹ͍ͭͯ(Ұ෦ൈਮ) … %4 = apply %3(%2) : $@convention(method) ...

    debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Reference Count͕͋Δ࠷దԽࡁΈ(canonical SIL)SIL
  6. copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ … %4 = apply %3(%2) : $@convention(method)

    ... debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … copy-propagation ൈ͖
  7. … %4 = apply %3(%2) : $@convention(method) ... debug_value %4

    : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Retain count (mike’s object to tama) copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ copy-propagation ൈ͖
  8. … %4 = apply %3(%2) : $@convention(method) ... debug_value %4

    : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, ... %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 … Retain count (mike’s object to tama) Decrease count (mike’s object to tama) Decrease count (mike) copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹ͢Δલͷίʔυ copy-propagation ൈ͖
  9. … %4 = apply %3(%2) : $@convention(method) … debug_value %4

    : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> () … %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 … copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹͨ͠ޙͷίʔυ copy-propagation Ϛγ
  10. … %4 = apply %3(%2) : $@convention(method) … debug_value %4

    : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> () … %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 … Decrease count (mike) No retain count for tama copy-propagation ΛΦϯʹͯ͠ΈΔ Φϯʹͨ͠ޙͷίʔυ copy-propagation Ϛγ
  11. // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32

    { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): %2 = metatype $@thick Cat.Type // user: %4 // function_ref Cat.__allocating_init() %3 = function_ref @$s4test3CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %4 %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %11, %10, %7, %9, %8, %6, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 strong_retain %4 : $Cat // id: %6 debug_value %4 : $Cat, let, name "tama" // id: %7 %8 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %9 %9 = apply %8(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %10 strong_release %4 : $Cat // id: %11 %12 = integer_literal $Builtin.Int32, 0 // user: %13 %13 = struct $Int32 (%12 : $Builtin.Int32) // user: %14 return %13 : $Int32 // id: %14 } // end sil function 'main' copy-propagation ͋Γ/ͳ͠ൺֱ Φϯʹ͢Δલͷίʔυ
  12. // main sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32

    { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): %2 = metatype $@thick Cat.Type // user: %4 // function_ref Cat.__allocating_init() %3 = function_ref @$s5test23CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %4 %4 = apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %9, %6, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 debug_value %4 : $Cat, let, name "tama" // id: %6 %7 = class_method %4 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %8 %8 = apply %7(%4) : $@convention(method) (@guaranteed Cat) -> () strong_release %4 : $Cat // id: %9 %10 = integer_literal $Builtin.Int32, 0 // user: %11 %11 = struct $Int32 (%10 : $Builtin.Int32) // user: %12 return %11 : $Int32 // id: %12 } // end sil function 'main' copy-propagation ͋Γ/ͳ͠ൺֱ Φϯʹͨ͠ޙͷίʔυ
  13. ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸ • weak ʹΑΔࢀর (ऑࢀর) ΋ಉ͡Α͏ʹಇ͘આ class Cat { func

    meow(){} } do { let mike = Cat() weak var tama = mike tama?.meow() } weak/unownedͱͷൺֱʁ
  14. ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸ ࣮͸ weak ͸ΊͬͪΌ௕͘ͳΔ … %4 = apply %3(%2) :

    $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %39, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 %6 = alloc_stack $@sil_weak Optional<Cat>, var, name "tama" // users: %38, %37, %9, %11 strong_retain %4 : $Cat // id: %7 %8 = enum $Optional<Cat>, #Optional.some!enumelt, %4 : $Cat // users: %10, %9 store_weak %8 to [initialization] %6 : $*@sil_weak Optional<Cat> // id: %9 release_value %8 : $Optional<Cat> // id: %10 %11 = begin_access [read] [static] %6 : $*@sil_weak Optional<Cat> // users: %28, %21, %13 %12 = alloc_stack $Optional<Cat> // users: %14, %32, %27, %24, %20, %19, %17 %13 = load_weak %11 : $*@sil_weak Optional<Cat> // user: %14 store %13 to %12 : $*Optional<Cat> // id: %14 %15 = integer_literal $Builtin.Int1, -1 // user: %17 %16 = integer_literal $Builtin.Int1, 0 // user: %17 %17 = select_enum_addr %12 : $*Optional<Cat>, case #Optional.some!enumelt: %15, default %16 : $Builtin.Int1 // user: %18 cond_br %17, bb2, bb1 // id: %18 bb1: // Preds: bb0 destroy_addr %12 : $*Optional<Cat> // id: %19 dealloc_stack %12 : $*Optional<Cat> // id: %20 end_access %11 : $*@sil_weak Optional<Cat> // id: %21 %22 = enum $Optional<()>, #Optional.none!enumelt // user: %23 br bb3(%22 : $Optional<()>) // id: %23 … weak/unownedͱͷൺֱʁ
  15. weak/unownedͱͷൺֱʁ weak ͱ Optional ʹ͍ͭͯ • Optional ͷ ? ͸

    SIL ্ͩͱ nil ͡Όͳ͍͔ΛνΣοΫ͢Δ ৚݅෼ذ͕ൃੜ͢Δ • ͳͷͰͦͷ෼ͷ৚݅෼ذ͕૿͍͑ͯΔͱ͍͏͜ͱ
  16. weak/unownedͱͷൺֱʁ • unowned ʹॻ͖׵͑ͯࢼͯ͠ΈΔ class Cat { func meow(){} }

    do { let mike = Cat() unowned let tama = mike tama.meow() } ͡Ό͋ unowned ͸Ͳ͏Α
  17. unowned ͷ΄͏͕ copy-propagation ༗ΓΑΓ௕͍ ͡Ό͋ unowned ͸Ͳ͏Α … %4 =

    apply %3(%2) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %20, %12, %8, %7, %5 debug_value %4 : $Cat, let, name "mike" // id: %5 %6 = alloc_stack $@sil_unowned Cat, let, name "tama" // users: %11, %19, %18 strong_retain %4 : $Cat // id: %7 %8 = ref_to_unowned %4 : $Cat to $@sil_unowned Cat // users: %14, %11, %13, %10, %9 unowned_retain %8 : $@sil_unowned Cat // id: %9 unowned_retain %8 : $@sil_unowned Cat // id: %10 store %8 to %6 : $*@sil_unowned Cat // id: %11 strong_release %4 : $Cat // id: %12 %13 = strong_copy_unowned_value %8 : $@sil_unowned Cat // users: %17, %16, %15 unowned_release %8 : $@sil_unowned Cat // id: %14 %15 = class_method %13 : $Cat, #Cat.meow : (Cat) -> () -> (), $@convention(method) (@guaranteed Cat) -> () // user: %16 %16 = apply %15(%13) : $@convention(method) (@guaranteed Cat) -> () strong_release %13 : $Cat // id: %17 destroy_addr %6 : $*@sil_unowned Cat // id: %18 dealloc_stack %6 : $*@sil_unowned Cat // id: %19 strong_release %4 : $Cat // id: %20 … weak/unownedͱͷൺֱʁ
  18. LLVMIRίʔυͷൺֱ Կ΋ͳ͠ vs copy-propagation vs unowned vs weak vs μʔΫϥΠ

    • ҎԼͷॱ൪Ͱ୹͍ • copy-propagation • Կ΋ͳ͠ • unowned • weak
  19. Points of this talk Why we need to optimize it

    • OPTIMIZE_OBJECT_LIFETIME from Xcode 13 • -Xfrontend -enable-copy-propagation for swiftc • copy-propagation Ͱίʔυ΍ARCͷΦʔόʔϔουݮΒͤΔ • unowned ΍ weak ΑΓ΋୹͍