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

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

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

freddi(Yuki Aki)

November 16, 2021
Tweet

More Decks by freddi(Yuki Aki)

Other Decks in Technology

Transcript

  1. Θ͍Θ͍swiftc Vol 31
    ARC in Swift: So, what’s new?
    freddi, iOS Engineer

    View Slide

  2. Auto Reference Counting (ARC) ͱ͸

    View Slide

  3. ARCͱ͸?
    ΦϒδΣΫτͷϥΠϑαΠΫϧ؅ཧ
    • ϦϑΝϨϯεΧ΢ϯτʹΑΔΦϒδΣΫτͷ؅ཧ


    • ΦϒδΣΫτ͕ࢀর → “retain͢Δ” ʢΧ΢ϯτΛ૿΍͢ʣ


    • “Retain Cycle” ͕͍ΘΏΔϝϞϦϦʔΫΛى͜͢


    • “Reference Cycle”, “॥؀ࢀর” ͱ΋

    View Slide

  4. ARC ͷ঺հ at WWDC21

    View Slide

  5. https://developer.apple.com/videos/play/wwdc2021/10216/

    View Slide

  6. https://developer.apple.com/videos/play/wwdc2021/10216/
    ARCؔ࿈ͷΦϓγϣϯ૿͑ͨ from Xcode 13

    View Slide

  7. OPTIMIZE_OBJECT_LIFETIME in Xcode
    Xcode 13͔Βͷ৽͍͠Φϓγϣϯ
    • ʮΦϒδΣΫτण໋ͷ࠷దԽʯͱ͍͏ײ͡Ͱ঺հ


    • ୹ॖARC࠷దԽͱ͔ݺ͹Εͯͨ


    • ࣮ݧతͳΦϓγϣϯ


    • 20ඵ͘Β͍͔͠঺հ͞Εͯͳ͍ṖͷΦϓγϣϯ

    View Slide

  8. ARCͷ୹ॖͱ͸?

    View Slide

  9. Swift Compiler ίϚϯυΛݟΔ
    • Ϗϧυ࣌ʹͲΜͳswiftcίϚϯυ͕ݺ͹Ε͔ͨ


    • ͭ͡͸↓ͷͱ͜Ζ͔ΒݟΕͨΓ͢Δ
    ΞϓϦΛϏϧυ͢Δࡍʹݺ͹ΕΔίϚϯυΛݟΔ

    View Slide

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


    # Without OPTIMIZE_OBJECT_LIFETIME

    /../swiftc ... -enforce-exclusivity\=checked ...

    View Slide

  11. -enable-copy-propagation
    swift ίϯύΠϥͷίʔυ͔ΒΦϓγϣϯΛಡΈղ͘
    https://github.com/apple/swift/blob/main/include/swift/Option/FrontendOptions.td#L202

    View Slide

  12. -enable-copy-propagation
    swift ίϯύΠϥͷίʔυ͔ΒΦϓγϣϯΛಡΈղ͘
    • Run SIL propagation to shorten object lifetime


    • SIL఻೻Λ૸ΒͤɺΦϒδΣΫτͷϥΠϑλΠϜΛ୹ॖ


    • Α͘Θ͔ΒΜ

    View Slide

  13. ࠷దԽςΫχοΫ
    • ίϐʔ఻೻ɺෳࣸͷ఻೻ʢ೔ຊޠ༁ʣ


    • a = b; c = a + d ͱ͍͏ίʔυΛ c = b + d ʹ͢Δ࠷దԽ
    Copy Propagation
    http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/note11.html

    View Slide

  14. Θ͔Γқ͍ྫ
    Copy Propagation
    http://itdoc.hitachi.co.jp/manuals/3000/30003D0800/GD080480.HTM

    View Slide

  15. ARCͷཁ఺
    ͳͥ࠷దԽ͕ඞཁͳͷʁ
    • ARCʹ͸ARCͳΓʹΦʔόʔϔου͕͋Δ


    • ҰํɺARCͷ৔߹ɺม਺ʹΠϯελϯεΛ୅ೖͨ͠Γ ….ɺͦͷม਺͕είʔϓ
    Λൈ͚ͨΓ͢Δ౓ʹࢀরΧ΢ϯλͷνΣοΫॲཧ͕ೖΔͷͰɺͦͷ෼ɺΦʔ
    όʔϔου͕͔͔Δͱ͍͏σϝϦοτ͕͋Γ·͢ɻ
    https://rakusui.org/swift_arc/

    View Slide

  16. ARCͷཁ఺
    ͳͥ࠷దԽ͕ඞཁͳͷʁ
    • SwiftͷதؒݴޠͰ͋ΔSwift Intermediate Language Ͱ͸
    ARC͕ͲͷΑ͏ʹॲཧ͞Ε͍ͯΔͷ͔͕໨ʹݟ͑ͯΘ͔Δ


    • தؒݴޠ͕ੜ੒͞ΕΔͱ͖ʹΧ΢ϯτͷॲཧ͕ૠೖ͞ΕΔ


    • ௨ৗͷSwiftͷίʔυͩͱݟ͑ͳ͍

    View Slide

  17. Swift Intermedia Language
    ๻ͷొஃͩͱ਌ͷإΑΓ΋ݟΔ͜ͱʹͳΔ SILʹ͍ͭͯ
    • Swift͕ίϯύΠϧ͞ΕΔͱ͖ͷϑϩʔதͷதؒݴޠ


    • Swiftಛ༗ͷ࠷దԽ΍਍அ͕ߦΘΕΔ


    • Լͷਤ֮͑ͯؼ͍ͬͯͩ͘͞
    AST AS
    T

    (Typed)
    SIL I
    R

    (LLVM)
    📱
    App

    View Slide

  18. SIL Ͱͷ ARC ͷදݱʹ͍ͭͯ
    Reference Count ΛݮΒ͢ɾ૿΍͢ίʔυ
    • strong_retain


    • Χ΢ϯτΛʴ̍͢Δ


    • strong_release


    • Χ΢ϯτΛʔ̍͢Δ


    • ͋ͱΧ΢ϯτ͕0ҎԼʹͳͬͨΦϒδΣΫτΛഁغ

    View Slide

  19. ࣮ࡍͷSILͰͷARCΧ΢ϯτΛݟΔ
    ҎԼͷίʔυΛม׵
    class Cat {


    func meow(){}


    }


    do {


    let mike = Cat()


    let tama = mike


    tama.meow()


    }

    View Slide

  20. ࣮ࡍͷSILͰͷARCΧ΢ϯτΛݟΔ
    ࣮ࡍͷίʔυʹ͍ͭͯ(Ұ෦ൈਮ)



    %4 = apply %3(%2) : [email protected](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) : [email protected](method) (@guaranteed Cat) -> ()


    strong_release %4 : $Cat // id: %10


    strong_release %4 : $Cat // id: %11



    Reference Count͕͋Δ࠷దԽࡁΈ(canonical SIL)SIL

    View Slide

  21. copy-propagation ΛΦϯʹͯ͠ΈΔ
    ࠶ͼ͜ͷίʔυ
    class Cat {


    func meow(){}


    }


    do {


    let mike = Cat()


    let tama = mike


    tama.meow()


    }

    View Slide

  22. copy-propagation ΛΦϯʹͯ͠ΈΔ
    Φϯʹ͢Δલͷίʔυ



    %4 = apply %3(%2) : [email protected](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) : [email protected](method) (@guaranteed Cat) -> ()


    strong_release %4 : $Cat // id: %10


    strong_release %4 : $Cat // id: %11



    copy-propagation ൈ͖

    View Slide




  23. %4 = apply %3(%2) : [email protected](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) : [email protected](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 ൈ͖

    View Slide




  24. %4 = apply %3(%2) : [email protected](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) : [email protected](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 ൈ͖

    View Slide




  25. %4 = apply %3(%2) : [email protected](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) : [email protected](method) (@guaranteed Cat) -> ()


    strong_release %4 : $Cat // id: %9



    copy-propagation ΛΦϯʹͯ͠ΈΔ
    Φϯʹͨ͠ޙͷίʔυ
    copy-propagation Ϛγ

    View Slide




  26. %4 = apply %3(%2) : [email protected](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) : [email protected](method) (@guaranteed Cat) -> ()


    strong_release %4 : $Cat // id: %9



    Decrease count (mike)
    No retain count for tama
    copy-propagation ΛΦϯʹͯ͠ΈΔ
    Φϯʹͨ͠ޙͷίʔυ
    copy-propagation Ϛγ

    View Slide

  27. // main


    sil @main : [email protected](c) (Int32, UnsafeMutablePointer>>) -> Int32 {


    bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>):


    %2 = metatype [email protected] Cat.Type // user: %4


    // function_ref Cat.__allocating_init()


    %3 = function_ref @$s4test3CatCACycfC : [email protected](method) (@thick Cat.Type) -> @owned Cat // user: %4


    %4 = apply %3(%2) : [email protected](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) -> () -> (), [email protected](method) (@guaranteed Cat) -> () // user: %9


    %9 = apply %8(%4) : [email protected](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 ͋Γ/ͳ͠ൺֱ
    Φϯʹ͢Δલͷίʔυ

    View Slide

  28. // main


    sil @main : [email protected](c) (Int32, UnsafeMutablePointer>>) -> Int32 {


    bb0(%0 : $Int32, %1 : $UnsafeMutablePointer>>):


    %2 = metatype [email protected] Cat.Type // user: %4


    // function_ref Cat.__allocating_init()


    %3 = function_ref @$s5test23CatCACycfC : [email protected](method) (@thick Cat.Type) -> @owned Cat // user: %4


    %4 = apply %3(%2) : [email protected](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) -> () -> (), [email protected](method) (@guaranteed Cat) -> () // user: %8


    %8 = apply %7(%4) : [email protected](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 ͋Γ/ͳ͠ൺֱ
    Φϯʹͨ͠ޙͷίʔυ

    View Slide

  29. ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸
    • weak ʹΑΔࢀর (ऑࢀর) ΋ಉ͡Α͏ʹಇ͘આ
    class Cat {


    func meow(){}


    }


    do {


    let mike = Cat()


    weak var tama = mike


    tama?.meow()


    }
    weak/unownedͱͷൺֱʁ

    View Slide

  30. ࢀরΧ΢ϯλফඅ͠ͳ͍ͷͰಉ͡ͳͷͰ͸
    ࣮͸ weak ͸ΊͬͪΌ௕͘ͳΔ



    %4 = apply %3(%2) : [email protected](method) (@thick Cat.Type) -> @owned Cat // users: %39, %8, %7, %5


    debug_value %4 : $Cat, let, name "mike" // id: %5


    %6 = alloc_stack [email protected]_weak Optional, var, name "tama" // users: %38, %37, %9, %11


    strong_retain %4 : $Cat // id: %7


    %8 = enum $Optional, #Optional.some!enumelt, %4 : $Cat // users: %10, %9


    store_weak %8 to [initialization] %6 : $*@sil_weak Optional // id: %9


    release_value %8 : $Optional // id: %10


    %11 = begin_access [read] [static] %6 : $*@sil_weak Optional // users: %28, %21, %13


    %12 = alloc_stack $Optional // users: %14, %32, %27, %24, %20, %19, %17


    %13 = load_weak %11 : $*@sil_weak Optional // user: %14


    store %13 to %12 : $*Optional // id: %14


    %15 = integer_literal $Builtin.Int1, -1 // user: %17


    %16 = integer_literal $Builtin.Int1, 0 // user: %17


    %17 = select_enum_addr %12 : $*Optional, 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 // id: %19


    dealloc_stack %12 : $*Optional // id: %20


    end_access %11 : $*@sil_weak Optional // id: %21


    %22 = enum $Optional, #Optional.none!enumelt // user: %23


    br bb3(%22 : $Optional) // id: %23



    weak/unownedͱͷൺֱʁ

    View Slide

  31. weak/unownedͱͷൺֱʁ
    weak ͱ Optional ʹ͍ͭͯ
    • Optional ͷ ? ͸ SIL ্ͩͱ nil ͡Όͳ͍͔ΛνΣοΫ͢Δ
    ৚݅෼ذ͕ൃੜ͢Δ


    • ͳͷͰͦͷ෼ͷ৚݅෼ذ͕૿͍͑ͯΔͱ͍͏͜ͱ

    View Slide

  32. weak/unownedͱͷൺֱʁ
    • unowned ʹॻ͖׵͑ͯࢼͯ͠ΈΔ
    class Cat {


    func meow(){}


    }


    do {


    let mike = Cat()


    unowned let tama = mike


    tama.meow()


    }
    ͡Ό͋ unowned ͸Ͳ͏Α

    View Slide

  33. unowned ͷ΄͏͕ copy-propagation ༗ΓΑΓ௕͍
    ͡Ό͋ unowned ͸Ͳ͏Α



    %4 = apply %3(%2) : [email protected](method) (@thick Cat.Type) -> @owned Cat // users: %20, %12, %8, %7, %5


    debug_value %4 : $Cat, let, name "mike" // id: %5


    %6 = alloc_stack [email protected]_unowned Cat, let, name "tama" // users: %11, %19, %18


    strong_retain %4 : $Cat // id: %7


    %8 = ref_to_unowned %4 : $Cat to [email protected]_unowned Cat // users: %14, %11, %13, %10, %9


    unowned_retain %8 : [email protected]_unowned Cat // id: %9


    unowned_retain %8 : [email protected]_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 : [email protected]_unowned Cat // users: %17, %16, %15


    unowned_release %8 : [email protected]_unowned Cat // id: %14


    %15 = class_method %13 : $Cat, #Cat.meow : (Cat) -> () -> (), [email protected](method) (@guaranteed Cat) -> () // user: %16


    %16 = apply %15(%13) : [email protected](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ͱͷൺֱʁ

    View Slide

  34. weak/unownedͱͷൺֱʁ
    unowned ʹ͍ͭͯ
    • unowned ΋ unowned Ͱಛ༗ͷॲཧ͕͋ΔͷͰ݁ہ௕͍


    • unowned_retain ͱ͔

    View Slide

  35. LLVMIRίʔυͷൺֱ
    Կ΋ͳ͠ vs copy-propagation vs unowned vs weak vs μʔΫϥΠ
    • ҎԼͷॱ൪Ͱ୹͍


    • copy-propagation


    • Կ΋ͳ͠


    • unowned


    • weak

    View Slide

  36. Conclusion

    View Slide

  37. 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 ΑΓ΋୹͍

    View Slide

  38. ࣍ճ༧ࠂ

    View Slide

  39. ࣍ճ͸͕࣌ؒ͋Ε͹࣮૷ΛಡΜͰ͍͘
    ָ͓͠Έʹ
    • https://github.com/apple/swift/blob/
    6bafc8498dd727f05ba14bf573e3f3d78de93a4e/lib/
    SILOptimizer/Transforms/CopyPropagation.cpp

    View Slide