Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
わいわいswiftc#19Genericsの特殊化
Search
Iceman
April 20, 2020
Programming
500
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
わいわいswiftc#19Genericsの特殊化
Iceman
April 20, 2020
More Decks by Iceman
See All by Iceman
わいわいswift#39 Swiftの型をTypeScriptで表す
sidepelican
0
380
わいわいswiftc#35夢が広がる!コード生成でどこでもSwift
sidepelican
0
500
元ゲーム開発者が贈る描画パフォーマンス改善 / Rendering performance improvement from a game developer
sidepelican
4
1.9k
わいわいswiftc#17Genericsの特殊化
sidepelican
0
110
SwiftUI: 更新検知と値の生存期間
sidepelican
2
1.2k
クックパッドiOSアプリのパフォーマンス改善
sidepelican
0
830
DispatchQueue.syncが動作するスレッド
sidepelican
0
400
Other Decks in Programming
See All in Programming
AIがコードを書いてくれる時代、我々は何を確かめるのか
yosuke_furukawa
PRO
13
5.4k
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
3
1.3k
S3 TablesのIcebergデータに、AIエージェントからアクセスしてみた / 20261016developersio2026joetsu-accessing-iceberg-in-s3tables-via-agent
kasacchiful
PRO
0
250
Inertia Rails: The One-Person Framework with React & Friends
skryukov
0
200
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
4
3.5k
Zero-Tap Sign-In対応、結局何をすればいいの?
mitohato14
0
1.2k
AI時代のIaC入門 〜なぜインフラをコードで管理したいのか?〜 / Introduction to IaC in the AI Era
akihisaikeda
6
1.3k
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
3
1.6k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
530
個人開発者よ、Honoを使え(おじさんver)
tanahiro2010
2
300
Coding with AI: How to trust the storyteller (AWS Community Day Adria, Ljubljana 2026)
slobodan
0
130
Getting Started with Vibe Coding
miccheng
0
140
Featured
See All Featured
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8.2k
Ethics towards AI in product and experience design
skipperchong
2
450
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
640
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
A Tale of Four Properties
chriscoyier
163
24k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
440
Paper Plane (Part 1)
katiecoart
PRO
2
12k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.3k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.5k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Docker and Python
trallard
47
4.2k
Transcript
わいわいswiftc #19 SwiftのGenerics関数の特殊化 Twitter @iceman5499 2020年4⽉20⽇ 1
Generics関数の特殊化とは 実際に使⽤される型パラメータをコンパイル時に埋め込んで 展開し、その型専⽤の実装を⽣やす最適化 func f<T>(_ v: T) {} f(Int(1)) ↓
Intをあらかじめ埋め込む func f<T>(_ v: T) {} func f(_ v: Int) {} // Int に特殊化された関数 f(Int(1)) 2
Generics関数の特殊化の利点 Swiftのジェネリクスは実⾏時にいろいろなことをやるのでオ ーバーヘッドがある 特殊化されているとそのいろいろを無視できるので速い いろいろの例 メタタイプの取り出し witness table経由での関数の呼び出し swiftc p3.swift
-emit-sil | code - 3
特殊化が⾏われるタイミング SILOptimizerのフェーズで⾏われる (引⽤元: https://www.slideshare.net/kitasuke/sil-for-first-time-leaners/1 by kitasuke) 4
特殊化される様⼦を観察する func f<T>(_ v: T) -> T { v }
@inline(never) func g() -> UInt16 { f(UInt16(5)) // ← これが特殊化される } g() このコードをコンパイルしてみて、最適化前と最適化後で g 関数 のSILの変化を観察してみる 5
最適化する前の g の状態 $ swiftc -emit-sil p5.swift // g() sil
hidden [noinline] @$s2p51gs6UInt16VyF : $@convention(thin) () -> UInt16 { bb0: %0 = alloc_stack $UInt16 // users: %8, %9, %6 %1 = integer_literal $Builtin.Int16, 5 // user: %2 %2 = struct $UInt16 (%1 : $Builtin.Int16) // user: %4 %3 = alloc_stack $UInt16 // users: %4, %7, %6 store %2 to %3 : $*UInt16 // id: %4 // function_ref f<A>(_:) %5 = function_ref @$s2p51fyxxlF : $@convention(thin) <τ_0_0> (@in_guaran... %6 = apply %5<UInt16>(%0, %3) : $@convention(thin) <τ_0_0> (@in_guaran... dealloc_stack %3 : $*UInt16 // id: %7 %8 = load %0 : $*UInt16 // user: %10 dealloc_stack %0 : $*UInt16 // id: %9 return %8 : $UInt16 // id: %10 } // end sil function '$s2p51gs6UInt16VyF' 6
UInt16のメタタイプを渡して呼出をしている (↓前ページの⼀部を抜粋) // function_ref f<A>(_:) %5 = function_ref @$s2p51fyxxlF :
$@convention(thin) <τ_0_0> (@in_guaran... %6 = apply %5<UInt16>(%0, %3) : $@convention(thin) <τ_0_0> (@in_guaran... $ swift demangle s2p51fyxxlF $s2p51fyxxlF ---> p5.f<A>(A) -> A 7
最適化するとどうなるか。 $ swiftc -O -Xllvm -sil-print-all p5.swift *** SIL function
after #60, stage HighLevel+EarlyLoopOpt, pass 12: GenericSpecializer (generic-specializer) // g() sil hidden [noinline] @$s2p51gs6UInt16VyF : $@convention(thin) () -> UInt16 { bb0: %0 = alloc_stack $UInt16 // users: %8, %10, %11 %1 = integer_literal $Builtin.Int16, 5 // user: %2 %2 = struct $UInt16 (%1 : $Builtin.Int16) // user: %4 %3 = alloc_stack $UInt16 // users: %6, %4, %9 store %2 to %3 : $*UInt16 // id: %4 // function_ref specialized f<A>(_:) %5 = function_ref @$s2p51fyxxlFs6UInt16V_Tg5 : $@convention(thin) (UInt16… %6 = load %3 : $*UInt16 // user: %7 %7 = apply %5(%6) : $@convention(thin) (UInt16) -> UInt16 // user: %8 store %7 to %0 : $*UInt16 // id: %8 dealloc_stack %3 : $*UInt16 // id: %9 %10 = load %0 : $*UInt16 // user: %12 dealloc_stack %0 : $*UInt16 // id: %11 return %10 : $UInt16 // id: %12 } // end sil function '$s2p51gs6UInt16VyF' 8
GenericSpecializerを通過すると特殊化された実装が⽣える // function_ref specialized f<A>(_:) %5 = function_ref @$s2p51fyxxlFs6UInt16V_Tg5 :
$@convention(thin) (UInt16… %6 = load %3 : $*UInt16 // user: %7 %7 = apply %5(%6) : $@convention(thin) (UInt16) -> UInt16 // user: %8 $ swift demangle s2p51fyxxlFs6UInt16V_Tg5 $s2p51fyxxlFs6UInt16V_Tg5 ---> generic specialization <Swift.UInt16> of p5.f<A>(A) -> A 9
最適化完了後の g の状態 // g() sil hidden [noinline] @$s2p51gs6UInt16VyF :
$@convention(thin) () -> UInt16 { bb0: %0 = integer_literal $Builtin.Int16, 5 // user: %1 %1 = struct $UInt16 (%0 : $Builtin.Int16) // user: %2 return %1 : $UInt16 // id: %2 } // end sil function '$s2p51gs6UInt16VyF' 最終的には f の呼び出しが全部消えた 10
特殊化されたf<A>(_:)ができてから消える様⼦ $ swift -O -Xllvm -sil-print-all -Xllvm -sil-print-only-functions=s2p51fyxxlFs6UInt16V_Tg5 p5.swift 途中から⽣えて最後には無くなってる様⼦が確認できる
11
特殊化されるための条件を調べる 特殊化は実⾏時パフォーマンスの観点で積極的に⾏われてほ しい SILOptimizerの実装を⾒て、特殊化のための条件を調べる 具体的な実装はこのへん GenericSpecializer.cpp Generics.cpp 12
特殊化の流れ . 型パラつきの apply 命令(関数呼び出し)を集める . 特殊化できないものを除外する . 集めた apply
ごとに特殊化 ここでも精査され特殊化に失敗しうる . 特殊化に成功した apply の呼び出し先を新しい関数に置き換 えて、既存の呼び出しを削除 特殊化できないものを除外する 特殊化できないものとは? 13
特殊化できない呼び出し① いろいろな条件がある 呼び出し先の実装が参照不可能(外部モジュールなど) 特殊なアノテーションがついてる @_semantics(optimize.sil.specialize.generic.never) func f<T>() {} dynamicがついてる dynamic
func f<T>() {} 14
特殊化できない呼び出し② archetype(実⾏時に決まる型)がある 特殊化の過程でarchetypeがすべて潰されると最適化で きるようになることがある 型が複雑すぎる 型パラがネストを含め50個以上ある NTDの要素が2000個以上ある 要素2000個以上のタプル 引数2000個以上のクロージャ 15
archetype(実⾏時に決まる型)があって失敗する例 f の呼び出しに対して特殊化が失敗する例(左)。右はどうだろうか。 16
archetype(実⾏時に決まる型)があって失敗する例 classのほう(前ページ右)は特殊化に成功する 事前にdevirtualizeが適⽤されてよりシンプルなコードに なっているため これは1⽉ごろの挙動で、現在のmaster(364d2dc2)で はdevirtualizeが⾏われなくなっていて特殊化できなくな った // 特殊化までにこのようなコードに変形されている func
g() -> Bool { let result = makeAorB() if let a = result as? A { return a.f(UInt16(9)) } else let b = result as? B { return b.f(UInt16(9)) } else { return result.f(UInt16(9)) } } 17
型が複雑すぎる 型パラがネストを含め50個以上ある struct A<T> { var v: T init(_ v:
T) { self.v = v } } func use<T>(_ v: T) -> T { v } let a49 = A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A( A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A( A(A(A(A(A(A(A(A(A(Int16(9))))))))))))))) ))))))))))))))))))))))))))))))))))) let a50 = A(a49) use(a49) // ← 特殊化される use(a50) // ← されない 18
型が複雑すぎる 要素2000個以上のタプル typealias Width1999 = (Int8,Int8,Int8,Int8, ... ,Int8) func use<T>(_
v: T.Type) -> Int8 { 9 } func f() -> Int8 { use(Width1999.self) // ← 特殊化されない } $ swiftc -O typetoowidth1998.swift $ swiftc -O typetoowidth1999.swift 19
特殊化できない呼び出し③ -Osize がついてる 特殊化の無限ループが起こるとき どういう状況でそうなるかわからなかった 20
型⾃体の特殊化は⾏われない struct A<T> {} に対して struct A<Int> {} みたいな型パラ 埋め込み済みの型は⽣成されない?
他に特殊化を⾏ってる箇所がなさそう、実際のSILを⾒てもそ れっぽい動きがなさそう そもそも型⾃体を特殊化するメリットはほとんど無いのか も?意⾒募集 21
おまけ: @_specializeによる特殊化 @_specializeをつけると型を指定して特殊化できる 内部で型による分岐が⾛る特殊化が⾏われる // @_specialize(where T == Int) func
f<T: CustomStringConvertible>(_ v: T) -> String { v.description } 22
特殊化後のコードのイメージ // @_specialize(where T == Int) func f<T: CustomStringConvertible>(_ v:
T) -> String { if let v = v as? Int { return v.description } else { return v.description } } 同じ .description 呼び出しだが後者はwitness tableの参 照を⾏うのでオーバーヘッドがある 23
24