slidenumbers: true
- omochimetaru
- Qoncept, Inc.
- iOS, Mac, Web Frontend, Unity, Android
- Swift, C++, TypeScript, Kotlin
- Twitter, GitHub, Qiita, Qrunch
- ゲーム, Swiftコンパイラ
-
わいわいswiftc https://iosdiscord.connpass.com
-
iOSDC (2018/09/02) Swiftのジェネリクスはどうやって動いているのかコンパイラのソースから探る
-
Discord swift-developers-japan
- Appleが開発
- オープンソース
- ネイティブコンパイル言語
- 値型
- Generics
- プロトコル指向
https://github.com/apple/swift
Swift → SIL → LLVM IR → 実行ファイル
class Cat {
var name: String = "たま"
}
let a = Cat()
let b = a
b.name = "みけ"
print(a.name) // みけ
TraceGCは無し。参照カウンタを使う。
let a = [10, 20, 30]
var b = a
b[0] = 999
print(a) // [10, 20, 30]
print(b) // [999, 20, 30]
struct Stone {
var weight: Int = 5
}
let size = MemoryLayout<Stone>.size
print(size) // 8
struct BigStone {
var weight: Int = 5
var blob1: Int = 999
var blob2: Int = 999
var blob3: Int = 999
}
let size = MemoryLayout<BigStone>.size
print(size) // 32
// Array<Element>
let a: [Int] = [10, 20, 30]
let b: [String] = a.map { String($0) }
print(b) // ["10", "20", "30"]
func wrapArray<X>(_ x: X) -> Array<X> {
return [x]
}
let a = wrapArray(Stone())
print(a[0].weight) // 5
- 値型と参照型に対応 値型は異なるサイズをもち、 自身にメタ情報を持たない
func takeX1<X>(_ x: X) {
}
func main() {
takeX1(4)
}
$ swiftc -emit-ir a.swift
define hidden swiftcc void @"$s1a6takeX1yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
store %swift.type* %X, %swift.type** %X1, align 8
ret void
}
define hidden swiftcc void @"$s1a4mainyyF"() #0 {
entry:
%0 = alloca %TSi, align 8
%1 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %1)
%._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0
store i64 4, i64* %._value, align 8
%2 = bitcast %TSi* %0 to %swift.opaque*
call swiftcc void @"$s1a6takeX1yyxlF"(
%swift.opaque* noalias nocapture %2, %swift.type* @"$sSiN")
%3 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %3)
ret void
}
func takeX1<X>(_ x: X)
void @"$s1a6takeX1yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X)
→ opaque pointer + metatype
let t1: Int.Type = Int.self
let t2 = type(of: 3)
print(t1 == t2) // true
// static member access
print(Int.bitWidth) // 64
print(t1.bitWidth) // 64
第1引数の構築
[.code-highlight: 3, 8, 10]
define hidden swiftcc void @"$s1a4mainyyF"() #0 {
entry:
%0 = alloca %TSi, align 8
%1 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %1)
%._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0
store i64 4, i64* %._value, align 8
%2 = bitcast %TSi* %0 to %swift.opaque*
call swiftcc void @"$s1a6takeX1yyxlF"(
%swift.opaque* noalias nocapture %2,
%swift.type* @"$sSiN")
%3 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %3)
ret void
}
第2引数の構築
[.code-highlight: 11]
define hidden swiftcc void @"$s1a4mainyyF"() #0 {
entry:
%0 = alloca %TSi, align 8
%1 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %1)
%._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0
store i64 4, i64* %._value, align 8
%2 = bitcast %TSi* %0 to %swift.opaque*
call swiftcc void @"$s1a6takeX1yyxlF"(
%swift.opaque* noalias nocapture %2,
%swift.type* @"$sSiN")
%3 = bitcast %TSi* %0 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %3)
ret void
}
IntのMetatypeは外部定義される。
@"$sSiN" = external global %swift.type, align 8
標準ライブラリ(Swift) + ランタイムライブラリ(C++)
- IntはSwiftで実装
- Int内部のBuildin.Int64はC++で実装
stdlib/public/core/IntegerTypes.swift.gyb
public struct Int {
public var _value: Builtin.Int64
}
gybはテンプレート言語
include/swift/Runtime/Metadata.h
using FullOpaqueMetadata = FullMetadata<OpaqueMetadata>;
#define BUILTIN_TYPE(Symbol, Name) \
SWIFT_RUNTIME_EXPORT \
const FullOpaqueMetadata METADATA_SYM(Symbol);
#include "swift/Runtime/BuiltinTypes.def"
swift/Runtime/BuiltinTypes.def
BUILTIN_TYPE(Bi64_, "Builtin.Int64")
展開後
SWIFT_RUNTIME_EXPORT
const FullOpaqueMetadata $SBi64_N;
func takeX2<X>(_ x: X) {
let a = x
}
- 変数aのストレージ確保
- xからaに値のコピー
- aの破棄, ストレージ解放
Metatypeから取り出せる関数テーブル
コピーや破棄など、値(Value)に対する一般的な操作をする関数が入っている
インターフェースはOpaqueな表現になっている
入っている関数は個別の型を期待しているため、 Opaqueな値と、その真の型のMetatypeをペアで取り回す
値型(struct)の場合、そのメモリ上の表現のこと。
参照型(class)の場合、そのアドレスを格納する8バイトのポインタのこと。
https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md
値型の場合、それのもつ stored property すべてを再帰的にコピー/破棄。
参照型の値の場合、その参照先のオブジェクトにある参照カウンタの増減操作。
値型のMetatypeは固有のVWTを持つ。
参照型のMetatypeは共通のVWTを持つ。
include/swift/ABI/Metadata.h
template <typename Runtime> struct TargetValueWitnessTable;
using ValueWitnessTable = TargetValueWitnessTable<InProcess>;
template <typename Runtime> struct TargetValueWitnessTable {
#define WANT_ONLY_REQUIRED_VALUE_WITNESSES
#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \
typename TargetValueWitnessTypes<Runtime>::LOWER_ID LOWER_ID;
#include "swift/ABI/ValueWitness.def"
}
template <typename Runtime> struct TargetValueWitnessTable {
typename TargetValueWitnessTypes<Runtime>::initializeBufferWithCopyOfBuffer initializeBufferWithCopyOfBuffer;
typename TargetValueWitnessTypes<Runtime>::destroy destroy;
typename TargetValueWitnessTypes<Runtime>::initializeWithCopy initializeWithCopy;
typename TargetValueWitnessTypes<Runtime>::assignWithCopy assignWithCopy;
typename TargetValueWitnessTypes<Runtime>::initializeWithTake initializeWithTake;
typename TargetValueWitnessTypes<Runtime>::assignWithTake assignWithTake;
typename TargetValueWitnessTypes<Runtime>::getEnumTagSinglePayload getEnumTagSinglePayload;
typename TargetValueWitnessTypes<Runtime>::storeEnumTagSinglePayload storeEnumTagSinglePayload;
typename TargetValueWitnessTypes<Runtime>::size size;
typename TargetValueWitnessTypes<Runtime>::flags flags;
typename TargetValueWitnessTypes<Runtime>::stride stride;
}
見やすく省略
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
コピー4種類
[.code-highlight: 4,5,6,7]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
破棄
[.code-highlight: 3]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
メモリ確保用の情報
[.code-highlight: 10, 11, 12]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
再掲
func takeX2<X>(_ x: X) {
let a = x
}
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
VWTの取り出し
[.code-highlight: 3, 10, 11, 12, 13]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
VWTからsizeの取り出し
[.code-highlight: 14, 15, 16]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
[8] = size
[.code-highlight: 10]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
ストレージの確保
[.code-highlight: 17]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
VWTからinitializeWithCopyの取り出し
[.code-highlight: 21, 22, 23, 24]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
[2] = initializeWithCopy
[.code-highlight: 4]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
initializeWithCopyの呼び出し
[.code-highlight: 19, 3, 26]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
VWTからdestroyの取り出し
[.code-highlight: 27, 28, 29]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
[1] = destroy
[.code-highlight: 3]
struct TargetValueWitnessTable {
initializeBufferWithCopyOfBuffer;
destroy;
initializeWithCopy;
assignWithCopy;
initializeWithTake;
assignWithTake;
getEnumTagSinglePayload;
storeEnumTagSinglePayload;
size;
flags;
stride;
}
destroyの呼び出し
[.code-highlight: 19, 30]
define hidden swiftcc void @"$s1b6takeX2yyxlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X) #0 {
entry:
%X1 = alloca %swift.type*, align 8
%a.debug = alloca i8*, align 8
%1 = bitcast i8** %a.debug to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false)
store %swift.type* %X, %swift.type** %X1, align 8
%2 = bitcast %swift.type* %X to i8***
%3 = getelementptr inbounds i8**, i8*** %2, i64 -1
%X.valueWitnesses = load i8**, i8*** %3, align 8,
!invariant.load !13, !dereferenceable !14
%4 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 8
%5 = load i8*, i8** %4, align 8, !invariant.load !13
%size = ptrtoint i8* %5 to i64
%a = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a)
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
%10 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 1
%11 = load i8*, i8** %10, align 8, !invariant.load !13
%destroy = bitcast i8* %11 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %6, %swift.type* %X) #3
%12 = bitcast %swift.opaque* %6 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %12)
ret void
}
ストレージはallocaで確保されていたので、 解放用の命令は特になし
再掲
Swift → SIL → LLVM IR → 実行ファイル
LLVM IRの生成はSILからの変換として実装されている。
$ swiftc -emit-sil b.swift
// takeX2<A>(_:)
sil hidden @$s1b6takeX2yyxlF : $@convention(thin) <X> (@in_guaranteed X) -> () {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "x", argno 1 // id: %1
%2 = alloc_stack $X, let, name "a" // users: %5, %4, %3
copy_addr %0 to [initialization] %2 : $*X // id: %3
destroy_addr %2 : $*X // id: %4
dealloc_stack %2 : $*X // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
} // end sil function '$s1b6takeX2yyxlF'
copy_addr を見ていく
[.code-highlight: 7]
// takeX2<A>(_:)
sil hidden @$s1b6takeX2yyxlF : $@convention(thin) <X> (@in_guaranteed X) -> () {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "x", argno 1 // id: %1
%2 = alloc_stack $X, let, name "a" // users: %5, %4, %3
copy_addr %0 to [initialization] %2 : $*X // id: %3
destroy_addr %2 : $*X // id: %4
dealloc_stack %2 : $*X // id: %5
%6 = tuple () // user: %7
return %6 : $() // id: %7
} // end sil function '$s1b6takeX2yyxlF'
対応するLLVM-IR
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
SIL関数ごとにLLVM IRが生成される
swift/lib/IRGen/IRGenSIL.cpp
void IRGenModule::emitSILFunction(SILFunction *f)
SIL関数において、BasicBlockごとにLLVM IRが生成される
swift/lib/IRGen/IRGenSIL.cpp
void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB)
SIL BasicBlockにおいて、InstructionごとにLLVM IRが生成される 命令種類に対するVisitorパターンで書かれている
include/swift/SIL/SILVisitor.h
template <typename ImplClass, typename RetTy = void, typename... ArgTys>
class SILInstructionVisitor {
public:
RetTy visit(SILInstruction *inst, ArgTys... args) {
asImpl().beforeVisit(inst, args...);
switch (inst->getKind()) {
#define INST(CLASS, PARENT) \
case SILInstructionKind::CLASS: \
return asImpl().visit##CLASS(static_cast<CLASS*>(inst), \
std::forward<ArgTys>(args)...);
#include "swift/SIL/SILNodes.def"
}
llvm_unreachable("Not reachable, all cases handled");
}
}
copy_addr命令の処理中なのでvisitCopyAddrInstが呼ばれる
void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
SILType addrTy = i->getSrc()->getType();
const TypeInfo &addrTI = getTypeInfo(addrTy);
Address src = getLoweredAddress(i->getSrc());
// See whether we have a deferred fixed-size buffer initialization.
auto &loweredDest = getLoweredValue(i->getDest());
assert(!loweredDest.isUnallocatedAddressInBuffer());
Address dest = loweredDest.getAnyAddress();
if (i->isInitializationOfDest()) {
if (i->isTakeOfSrc()) {
addrTI.initializeWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.initializeWithCopy(*this, dest, src, addrTy, false);
}
} else {
if (i->isTakeOfSrc()) {
addrTI.assignWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.assignWithCopy(*this, dest, src, addrTy, false);
}
}
}
コピー元のコンパイル時型情報(TypeInfo)を取り出す
[.code-highlight: 1, 2, 3]
void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
SILType addrTy = i->getSrc()->getType();
const TypeInfo &addrTI = getTypeInfo(addrTy);
Address src = getLoweredAddress(i->getSrc());
// See whether we have a deferred fixed-size buffer initialization.
auto &loweredDest = getLoweredValue(i->getDest());
assert(!loweredDest.isUnallocatedAddressInBuffer());
Address dest = loweredDest.getAnyAddress();
if (i->isInitializationOfDest()) {
if (i->isTakeOfSrc()) {
addrTI.initializeWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.initializeWithCopy(*this, dest, src, addrTy, false);
}
} else {
if (i->isTakeOfSrc()) {
addrTI.assignWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.assignWithCopy(*this, dest, src, addrTy, false);
}
}
}
型情報のメソッドに転送する
[.code-highlight: 13]
void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i) {
SILType addrTy = i->getSrc()->getType();
const TypeInfo &addrTI = getTypeInfo(addrTy);
Address src = getLoweredAddress(i->getSrc());
// See whether we have a deferred fixed-size buffer initialization.
auto &loweredDest = getLoweredValue(i->getDest());
assert(!loweredDest.isUnallocatedAddressInBuffer());
Address dest = loweredDest.getAnyAddress();
if (i->isInitializationOfDest()) {
if (i->isTakeOfSrc()) {
addrTI.initializeWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.initializeWithCopy(*this, dest, src, addrTy, false);
}
} else {
if (i->isTakeOfSrc()) {
addrTI.assignWithTake(*this, dest, src, addrTy, false);
} else {
addrTI.assignWithCopy(*this, dest, src, addrTy, false);
}
}
}
型がなのでaddrTIはOpaqueArchetypeTypeInfo
lib/IRGen/GenArcheType.cpp
class OpaqueArchetypeTypeInfo
: public ResilientTypeInfo<OpaqueArchetypeTypeInfo>
{
};
親クラスのResilientTypeInfoの実装が呼ばれる
lib/IRGen/ResilientTypeInfo.h
template <class Impl>
class ResilientTypeInfo : public WitnessSizedTypeInfo<Impl> {
void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, bool isOutlined) const override {
emitInitializeWithCopyCall(IGF, T, dest, src);
}
};
lib/IRGen/GenOpaque.cpp
void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
auto destPtr = emitCastToOpaquePtr(IGF, dest);
auto srcPtr = emitCastToOpaquePtr(IGF, src);
IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
[.code-highlight: 8]
void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
auto destPtr = emitCastToOpaquePtr(IGF, dest);
auto srcPtr = emitCastToOpaquePtr(IGF, src);
IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
[.code-highlight: 1]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
[.code-highlight: 10]
void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
auto destPtr = emitCastToOpaquePtr(IGF, dest);
auto srcPtr = emitCastToOpaquePtr(IGF, src);
IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
[.code-highlight: 7, 8]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
[.code-highlight: 6, 7]
void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
auto destPtr = emitCastToOpaquePtr(IGF, dest);
auto srcPtr = emitCastToOpaquePtr(IGF, src);
IGF.Builder.CreateCall(fn, {destPtr, srcPtr, metadata});
}
[.code-highlight: 3, 4, 5, 6]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
lib/IRGen/GenOpaque.cpp
// index = ValueWitness::InitializeWithCopy
FunctionPointer
IRGenFunction::emitValueWitnessFunctionRef(SILType type,
llvm::Value *&metadataSlot,
ValueWitness index) {
assert(isValueWitnessFunction(index));
auto key = LocalTypeDataKind::forValueWitness(index);
if (auto witness = tryGetLocalTypeDataForLayout(type, key)) {
metadataSlot = emitTypeMetadataRefForLayout(type);
auto signature = IGM.getValueWitnessSignature(index);
return FunctionPointer(witness, signature);
}
auto vwtable = emitValueWitnessTableRef(type, &metadataSlot);
auto witness = emitLoadOfValueWitnessFunction(*this, vwtable, index);
setScopedLocalTypeDataForLayout(type, key, witness.getPointer());
return witness;
}
[.code-highlight: 1, 16]
// index = ValueWitness::InitializeWithCopy
FunctionPointer
IRGenFunction::emitValueWitnessFunctionRef(SILType type,
llvm::Value *&metadataSlot,
ValueWitness index) {
assert(isValueWitnessFunction(index));
auto key = LocalTypeDataKind::forValueWitness(index);
if (auto witness = tryGetLocalTypeDataForLayout(type, key)) {
metadataSlot = emitTypeMetadataRefForLayout(type);
auto signature = IGM.getValueWitnessSignature(index);
return FunctionPointer(witness, signature);
}
auto vwtable = emitValueWitnessTableRef(type, &metadataSlot);
auto witness = emitLoadOfValueWitnessFunction(*this, vwtable, index);
setScopedLocalTypeDataForLayout(type, key, witness.getPointer());
return witness;
}
// index = ValueWitness::InitializeWithCopy
static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF,
llvm::Value *table,
ValueWitness index) {
assert(isValueWitnessFunction(index));
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
auto label = getValueWitnessLabel(index);
auto signature = IGF.IGM.getValueWitnessSignature(index);
auto type = signature.getType()->getPointerTo();
witness = IGF.Builder.CreateBitCast(witness, type, label);
return FunctionPointer(witness, signature);
}
[.code-highlight: 11]
// index = ValueWitness::InitializeWithCopy
static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF,
llvm::Value *table,
ValueWitness index) {
assert(isValueWitnessFunction(index));
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
auto label = getValueWitnessLabel(index);
auto signature = IGF.IGM.getValueWitnessSignature(index);
auto type = signature.getType()->getPointerTo();
witness = IGF.Builder.CreateBitCast(witness, type, label);
return FunctionPointer(witness, signature);
}
[.code-highlight: 5, 6]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
[.code-highlight: 6]
// index = ValueWitness::InitializeWithCopy
static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF,
llvm::Value *table,
ValueWitness index) {
assert(isValueWitnessFunction(index));
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
auto label = getValueWitnessLabel(index);
auto signature = IGF.IGM.getValueWitnessSignature(index);
auto type = signature.getType()->getPointerTo();
witness = IGF.Builder.CreateBitCast(witness, type, label);
return FunctionPointer(witness, signature);
}
[.code-highlight: 3, 4]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
// index = ValueWitness::InitializeWithCopy
llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
llvm::Value *table,
WitnessIndex index) {
assert(table->getType() == IGF.IGM.WitnessTablePtrTy);
// GEP to the appropriate index, avoiding spurious IR in the trivial case.
llvm::Value *slot = table;
if (index.getValue() != 0)
slot = IGF.Builder.CreateConstInBoundsGEP1_32(
/*Ty=*/nullptr, table, index.getValue());
auto witness =
IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment()));
IGF.setInvariantLoad(witness);
return witness;
}
[.code-highlight: 1, 10, 11]
// index = ValueWitness::InitializeWithCopy
llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
llvm::Value *table,
WitnessIndex index) {
assert(table->getType() == IGF.IGM.WitnessTablePtrTy);
// GEP to the appropriate index, avoiding spurious IR in the trivial case.
llvm::Value *slot = table;
if (index.getValue() != 0)
slot = IGF.Builder.CreateConstInBoundsGEP1_32(
/*Ty=*/nullptr, table, index.getValue());
auto witness =
IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment()));
IGF.setInvariantLoad(witness);
return witness;
}
[.code-highlight: 3]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
[.code-highlight: 13, 14, 15]
// index = ValueWitness::InitializeWithCopy
llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF,
llvm::Value *table,
WitnessIndex index) {
assert(table->getType() == IGF.IGM.WitnessTablePtrTy);
// GEP to the appropriate index, avoiding spurious IR in the trivial case.
llvm::Value *slot = table;
if (index.getValue() != 0)
slot = IGF.Builder.CreateConstInBoundsGEP1_32(
/*Ty=*/nullptr, table, index.getValue());
auto witness =
IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment()));
IGF.setInvariantLoad(witness);
return witness;
}
[.code-highlight: 4]
%6 = bitcast i8* %a to %swift.opaque*
store i8* %a, i8** %a.debug, align 8
%7 = getelementptr inbounds i8*, i8** %X.valueWitnesses, i32 2
%8 = load i8*, i8** %7, align 8, !invariant.load !13
%initializeWithCopy = bitcast i8* %8 to
%swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
%9 = call %swift.opaque* %initializeWithCopy(
%swift.opaque* noalias %6, %swift.opaque* noalias %0, %swift.type* %X) #3
protocol Animal {
func speak() -> String
}
class Cat : Animal {
func speak() -> String { return "にゃー" }
}
class Dog : Animal {
func speak() -> String { return "わん" }
}
protocol Animal {
static func label() -> String
}
class Cat : Animal {
static func label() -> String { return "猫" }
}
class Dog : Animal {
static func label() -> String { return "犬" }
}
protocol Animal {
associatedtype Food
func eat(food: Food)
}
struct CatFood {}
class Cat : Animal {
typealias Food = CatFood
func eat(food: CatFood) { }
}
struct DogFood {}
class Dog : Animal {
typealias Food = DogFood
func eat(food: DogFood) { }
}
protocol Animal {
func spawn() -> Self
}
final class Cat : Animal {
func spawn() -> Cat { return Cat() }
}
final class Dog : Animal {
func spawn() -> Dog { return Dog() }
}
protocol Animal {
func speak() -> String
}
class Cat : Animal {
func speak() -> String { return "にゃー" }
}
func invokeSpeak<X: Animal>(animal: X) -> String {
return animal.speak()
}
print(invokeSpeak(animal: Cat())) // にゃー
protocol Addable {
static var zero: Self { get }
static func +(a: Self, b: Self) -> Self
}
extension Int : Addable {
static var zero: Int { return 0 }
}
extension Sequence where Element : Addable {
func sum() -> Element {
return reduce(Element.zero) { $0 + $1 }
}
}
let a = [1, 2, 3]
// Array (struct) は Sequence (protocol)
print(a.sum()) // 6
- 値型と参照型に対応
- 既存の型に後付可能
- staticメンバ
protocol Animal {
func speak() -> Int
}
class Cat : Animal {
func speak() -> Int { return 28 }
}
struct Stone : Animal {
func speak() -> Int { return 14 }
}
SILで見ると、CatとStoneそれぞれに、 Animalのwitness tableがある
sil_witness_table hidden Cat: Animal module c {
method #Animal.speak!1: <Self where Self : Animal> (Self) -> () -> Int :
@$s1c3CatCAA6AnimalA2aDP5speakSiyFTW
// protocol witness for Animal.speak() in conformance Cat
}
sil_witness_table hidden Stone: Animal module c {
method #Animal.speak!1: <Self where Self : Animal> (Self) -> () -> Int :
@$s1c5StoneVAA6AnimalA2aDP5speakSiyFTW
// protocol witness for Animal.speak() in conformance Stone
}
Protocolに準拠するための関数テーブル
そのProtocolで規定される操作をする関数が入っている
インターフェースはOpaqueな表現になっている
入っている関数は個別の型を期待しているため、 Opaqueな値と、その真の型のPWTをペアで取り回す
シンプルな例
func invokeSpeak<X: Animal>(animal: X) -> Int {
return animal.speak()
}
SILで見る
// invokeSpeak<A>(animal:)
sil hidden @$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF :
$@convention(thin) <X where X : Animal> (@in_guaranteed X) -> Int {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "animal", argno 1 // id: %1
%2 = witness_method $X, #Animal.speak!1 :
<Self where Self : Animal> (Self) -> () -> Int :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %3
%3 = apply %2<X>(%0) :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %4
return %3 : $Int // id: %4
} // end sil function '$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF'
witnessメソッドの取り出し
[.code-highlight: 7-10]
// invokeSpeak<A>(animal:)
sil hidden @$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF :
$@convention(thin) <X where X : Animal> (@in_guaranteed X) -> Int {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "animal", argno 1 // id: %1
%2 = witness_method $X, #Animal.speak!1 :
<Self where Self : Animal> (Self) -> () -> Int :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %3
%3 = apply %2<X>(%0) :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %4
return %3 : $Int // id: %4
} // end sil function '$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF'
関数の呼び出し
[.code-highlight: 11-13]
// invokeSpeak<A>(animal:)
sil hidden @$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF :
$@convention(thin) <X where X : Animal> (@in_guaranteed X) -> Int {
// %0 // users: %3, %1
bb0(%0 : $*X):
debug_value_addr %0 : $*X, let, name "animal", argno 1 // id: %1
%2 = witness_method $X, #Animal.speak!1 :
<Self where Self : Animal> (Self) -> () -> Int :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %3
%3 = apply %2<X>(%0) :
$@convention(witness_method: Animal) <τ_0_0 where τ_0_0 : Animal>
(@in_guaranteed τ_0_0) -> Int // user: %4
return %3 : $Int // id: %4
} // end sil function '$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF'
LLVM-IRでのPWT
@"$s1c3CatCAA6AnimalAAWP" = hidden constant [2 x i8*] [
i8* bitcast (%swift.protocol_conformance_descriptor*
@"$s1c3CatCAA6AnimalAAMc" to i8*),
i8* bitcast (i64 (%T1c3CatC**, %swift.type*, i8**)*
@"$s1c3CatCAA6AnimalA2aDP5speakSiyFTW" to i8*)
], align 8
@"$s1c5StoneVAA6AnimalAAWP" = hidden constant [2 x i8*] [
i8* bitcast (%swift.protocol_conformance_descriptor*
@"$s1c5StoneVAA6AnimalAAMc" to i8*),
i8* bitcast (i64 (%T1c5StoneV*, %swift.type*, i8**)*
@"$s1c5StoneVAA6AnimalA2aDP5speakSiyFTW" to i8*)
], align 8
LLVM-IRでの利用側
define hidden swiftcc i64 @"$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X, i8** %X.Animal) #0 {
entry:
%X1 = alloca %swift.type*, align 8
store %swift.type* %X, %swift.type** %X1, align 8
%1 = getelementptr inbounds i8*, i8** %X.Animal, i32 1
%2 = load i8*, i8** %1, align 8, !invariant.load !29
%3 = bitcast i8* %2 to i64 (%swift.opaque*, %swift.type*, i8**)*
%4 = call swiftcc i64 %3(%swift.opaque* noalias nocapture swiftself %0,
%swift.type* %X, i8** %X.Animal)
ret i64 %4
}
Signature
func invokeSpeak<X: Animal>(animal: X) -> Int
define hidden swiftcc i64
@"$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X, i8** %X.Animal)
<X: Animal> → opaque pointer + meta type + witness table
witnessメソッドの取り出し
[.code-highlight: 7, 8, 9]
define hidden swiftcc i64 @"$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X, i8** %X.Animal) #0 {
entry:
%X1 = alloca %swift.type*, align 8
store %swift.type* %X, %swift.type** %X1, align 8
%1 = getelementptr inbounds i8*, i8** %X.Animal, i32 1
%2 = load i8*, i8** %1, align 8, !invariant.load !29
%3 = bitcast i8* %2 to i64 (%swift.opaque*, %swift.type*, i8**)*
%4 = call swiftcc i64 %3(%swift.opaque* noalias nocapture swiftself %0,
%swift.type* %X, i8** %X.Animal)
ret i64 %4
}
[.code-highlight: 4-5, 11-12]
@"$s1c3CatCAA6AnimalAAWP" = hidden constant [2 x i8*] [
i8* bitcast (%swift.protocol_conformance_descriptor*
@"$s1c3CatCAA6AnimalAAMc" to i8*),
i8* bitcast (i64 (%T1c3CatC**, %swift.type*, i8**)*
@"$s1c3CatCAA6AnimalA2aDP5speakSiyFTW" to i8*)
], align 8
@"$s1c5StoneVAA6AnimalAAWP" = hidden constant [2 x i8*] [
i8* bitcast (%swift.protocol_conformance_descriptor*
@"$s1c5StoneVAA6AnimalAAMc" to i8*),
i8* bitcast (i64 (%T1c5StoneV*, %swift.type*, i8**)*
@"$s1c5StoneVAA6AnimalA2aDP5speakSiyFTW" to i8*)
], align 8
witnessメソッドの呼び出し
[.code-highlight: 10, 11]
define hidden swiftcc i64 @"$s1c11invokeSpeak6animalSix_tAA6AnimalRzlF"(
%swift.opaque* noalias nocapture,
%swift.type* %X, i8** %X.Animal) #0 {
entry:
%X1 = alloca %swift.type*, align 8
store %swift.type* %X, %swift.type** %X1, align 8
%1 = getelementptr inbounds i8*, i8** %X.Animal, i32 1
%2 = load i8*, i8** %1, align 8, !invariant.load !29
%3 = bitcast i8* %2 to i64 (%swift.opaque*, %swift.type*, i8**)*
%4 = call swiftcc i64 %3(%swift.opaque* noalias nocapture swiftself %0,
%swift.type* %X, i8** %X.Animal)
ret i64 %4
}
型クラス風の例
protocol Addable {
static var zero: Self { get }
static func +(a: Self, b: Self) -> Self
}
extension Int : Addable {
static var zero: Int { return 0 }
}
extension Sequence where Element : Addable {
func sum() -> Element {
return reduce(Element.zero) { $0 + $1 }
}
}
let a = [1, 2, 3]
// Array (struct) は Sequence (protocol)
print(a.sum()) // 6
IntのAddable
@"$sSi1d7AddableAAWP" = hidden constant [3 x i8*] [
i8* bitcast (%swift.protocol_conformance_descriptor* @"$sSi1d7AddableAAMc" to i8*),
i8* bitcast (
void (%TSi*, %swift.type*, %swift.type*, i8**)*
@"$sSi1d7AddableA2aBP4zeroxvgZTW"
to i8*),
i8* bitcast (
void (%TSi*, %TSi*, %TSi*, %swift.type*, %swift.type*, i8**)*
@"$sSi1d7AddableA2aBP1poiyxx_xtFZTW"
to i8*)
], align 8
sumメソッド
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
call swiftcc void @"$sSTsE6reduceyqd__qd___qd__qd___7ElementQztKXEtKlF"(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %8,
i8* bitcast (
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.refcounted*)*
@"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"
to i8*),
%swift.opaque* %21,
%swift.type* %Self,
%swift.type* %Self.Element,
i8** %Self.Sequence,
%swift.opaque* noalias nocapture swiftself %1,
%swift.error** noalias nocapture swifterror dereferenceable(8) %swifterror)
%22 = load %swift.error*, %swift.error** %swifterror, align 8
%23 = icmp ne %swift.error* %22, null
br i1 %23, label %28, label %24
; <label>:24: ; preds = %entry
call void @swift_release(%swift.refcounted* %12) #5
call void @swift_release(%swift.refcounted* %12) #5
%25 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 1
%26 = load i8*, i8** %25, align 8, !invariant.load !23
%destroy = bitcast i8* %26 to void (%swift.opaque*, %swift.type*)*
call void %destroy(%swift.opaque* noalias %8, %swift.type* %Self.Element) #5
%27 = bitcast %swift.opaque* %8 to i8*
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %27)
ret void
; <label>:28: ; preds = %entry
%29 = phi %swift.error* [ %22, %entry ]
store %swift.error* null, %swift.error** %swifterror, align 8
call void @swift_release(%swift.refcounted* %12) #5
unreachable
}
大まかな流れ
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
; Element.zeroの用意
; クロージャ環境の用意
; Sequence.reduceの呼び出し
; 例外ハンドリング
; <label>:24:
; 正常系, クリンナップ
; <label>:28:
; 異常系
}
Signature
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
; 返り値
%swift.opaque* noalias nocapture sret,
; Array metatype
%swift.type* %Self,
; Sequence PWT of Array
i8** %Self.Sequence,
; Addable PWT of Int
i8** %Self.Element.Addable,
; self (Array)
%swift.opaque* noalias nocapture swiftself)
Element.zeroの用意
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
Array.TypeからInt.Typeの取り出し
[.code-highlight: 13-17]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
IntのVWTの取り出し
[.code-highlight: 18-21]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
VWTからsizeの取り出し
[.code-highlight: 22-24]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
zeroの領域確保
[.code-highlight: 25]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
PWTからstatic funcの取り出し
[.code-highlight: 28-30]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
zeroの呼び出しと格納
[.code-highlight: 31-35]
define hidden swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyF"(
%swift.opaque* noalias nocapture sret,
%swift.type* %Self,
i8** %Self.Sequence,
i8** %Self.Element.Addable,
%swift.opaque* noalias nocapture swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
%swifterror = alloca swifterror %swift.error*, align 8
store %swift.error* null, %swift.error** %swifterror, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%2 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL",
%swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %2, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%3 = bitcast %swift.type* %Self.Element to i8***
%4 = getelementptr inbounds i8**, i8*** %3, i64 -1
%Self.Element.valueWitnesses = load i8**, i8*** %4, align 8, !invariant.load !23, !dereferenceable !24
%5 = getelementptr inbounds i8*, i8** %Self.Element.valueWitnesses, i32 8
%6 = load i8*, i8** %5, align 8, !invariant.load !23
%size = ptrtoint i8* %6 to i64
%7 = alloca i8, i64 %size, align 16
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7)
%8 = bitcast i8* %7 to %swift.opaque*
%9 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 1
%10 = load i8*, i8** %9, align 8, !invariant.load !23
%11 = bitcast i8* %10 to void (%swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %11(
%swift.opaque* noalias nocapture sret %8,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element,
i8** %Self.Element.Addable)
クロージャ環境の用意
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
3ワードのstorageを持つオブジェクトの生成
[.code-highlight: 1-5]
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
[0]にArray.Typeを格納
[.code-highlight: 6-10]
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
[1]にArrayのSequence PWTを格納
[.code-highlight: 11-13]
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
[2]にIntのAddable PWTを格納
[.code-highlight: 14-16]
%12 = call noalias %swift.refcounted* @swift_allocObject(
%swift.type* getelementptr inbounds (
%swift.full_boxmetadata, %swift.full_boxmetadata* @metadata,
i32 0, i32 2),
i64 40, i64 7) #5
%13 = bitcast %swift.refcounted* %12 to <{ %swift.refcounted, [24 x i8] }>*
%14 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %13, i32 0, i32 1
%15 = bitcast [24 x i8]* %14 to %swift.type**
store %swift.type* %Self, %swift.type** %15, align 8
%16 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 1
%17 = bitcast %swift.type** %16 to i8***
store i8** %Self.Sequence, i8*** %17, align 8
%18 = getelementptr inbounds %swift.type*, %swift.type** %15, i32 2
%19 = bitcast %swift.type** %18 to i8***
store i8** %Self.Element.Addable, i8*** %19, align 8
%20 = call %swift.refcounted* @swift_retain(%swift.refcounted* returned %12) #5
%21 = bitcast %swift.refcounted* %12 to %swift.opaque*
Sequence.reduceの呼び出し
call swiftcc void @"$sSTsE6reduceyqd__qd___qd__qd___7ElementQztKXEtKlF"(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %8,
i8* bitcast (
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.refcounted*)*
@"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"
to i8*),
%swift.opaque* %21,
%swift.type* %Self,
%swift.type* %Self.Element,
i8** %Self.Sequence,
%swift.opaque* noalias nocapture swiftself %1,
%swift.error** noalias nocapture swifterror dereferenceable(8) %swifterror)
call swiftcc void @"$sSTsE6reduceyqd__qd___qd__qd___7ElementQztKXEtKlF"(
; 返り値
%swift.opaque* noalias nocapture sret %0,
; 作ったzero
%swift.opaque* noalias nocapture %8,
; クロージャの関数ポインタ
i8* bitcast (
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.refcounted*)*
@"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"
to i8*),
; 作ったクロージャ環境
%swift.opaque* %21,
; Array.Type
%swift.type* %Self,
; Int.Type
%swift.type* %Self.Element,
; ArrayのSequence PWT
i8** %Self.Sequence,
; self (Array)
%swift.opaque* noalias nocapture swiftself %1,
; 例外
%swift.error** noalias nocapture swifterror dereferenceable(8) %swifterror)
渡してるクロージャ
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture,
%swift.opaque* noalias nocapture,
%swift.refcounted* swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%4 = bitcast %swift.refcounted* %3 to <{ %swift.refcounted, [24 x i8] }>*
%5 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %4, i32 0, i32 1
%6 = bitcast [24 x i8]* %5 to %swift.type**
%Self = load %swift.type*, %swift.type** %6, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%7 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 1
%8 = bitcast %swift.type** %7 to i8***
%Self.Sequence = load i8**, i8*** %8, align 8
%9 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 2
%10 = bitcast %swift.type** %9 to i8***
%Self.Element.Addable = load i8**, i8*** %10, align 8
tail call swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1,
%swift.opaque* noalias nocapture %2, %swift.type* %Self,
i8** %Self.Sequence, i8** %Self.Element.Addable)
ret void
}
Signature
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
; 返り値
%swift.opaque* noalias nocapture sret,
; 引数1
%swift.opaque* noalias nocapture,
; 引数2
%swift.opaque* noalias nocapture,
; クロージャ環境
%swift.refcounted* swiftself)
環境からArray.Typeの取り出し
[.code-highlight: 8, 9, 10, 11, 12, 13]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture,
%swift.opaque* noalias nocapture,
%swift.refcounted* swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%4 = bitcast %swift.refcounted* %3 to <{ %swift.refcounted, [24 x i8] }>*
%5 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %4, i32 0, i32 1
%6 = bitcast [24 x i8]* %5 to %swift.type**
%Self = load %swift.type*, %swift.type** %6, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%7 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 1
%8 = bitcast %swift.type** %7 to i8***
%Self.Sequence = load i8**, i8*** %8, align 8
%9 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 2
%10 = bitcast %swift.type** %9 to i8***
%Self.Element.Addable = load i8**, i8*** %10, align 8
tail call swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1,
%swift.opaque* noalias nocapture %2, %swift.type* %Self,
i8** %Self.Sequence, i8** %Self.Element.Addable)
ret void
}
環境からArrayのSequence PWTの取り出し
[.code-highlight: 14-16]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture,
%swift.opaque* noalias nocapture,
%swift.refcounted* swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%4 = bitcast %swift.refcounted* %3 to <{ %swift.refcounted, [24 x i8] }>*
%5 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %4, i32 0, i32 1
%6 = bitcast [24 x i8]* %5 to %swift.type**
%Self = load %swift.type*, %swift.type** %6, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%7 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 1
%8 = bitcast %swift.type** %7 to i8***
%Self.Sequence = load i8**, i8*** %8, align 8
%9 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 2
%10 = bitcast %swift.type** %9 to i8***
%Self.Element.Addable = load i8**, i8*** %10, align 8
tail call swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1,
%swift.opaque* noalias nocapture %2, %swift.type* %Self,
i8** %Self.Sequence, i8** %Self.Element.Addable)
ret void
}
環境からIntのAddable PWTの取り出し
[.code-highlight: 17-19]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture,
%swift.opaque* noalias nocapture,
%swift.refcounted* swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%4 = bitcast %swift.refcounted* %3 to <{ %swift.refcounted, [24 x i8] }>*
%5 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %4, i32 0, i32 1
%6 = bitcast [24 x i8]* %5 to %swift.type**
%Self = load %swift.type*, %swift.type** %6, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%7 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 1
%8 = bitcast %swift.type** %7 to i8***
%Self.Sequence = load i8**, i8*** %8, align 8
%9 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 2
%10 = bitcast %swift.type** %9 to i8***
%Self.Element.Addable = load i8**, i8*** %10, align 8
tail call swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1,
%swift.opaque* noalias nocapture %2, %swift.type* %Self,
i8** %Self.Sequence, i8** %Self.Element.Addable)
ret void
}
クロージャ本体の呼び出し
[.code-highlight: 20-23]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_TA"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture,
%swift.opaque* noalias nocapture,
%swift.refcounted* swiftself) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%4 = bitcast %swift.refcounted* %3 to <{ %swift.refcounted, [24 x i8] }>*
%5 = getelementptr inbounds <{ %swift.refcounted, [24 x i8] }>,
<{ %swift.refcounted, [24 x i8] }>* %4, i32 0, i32 1
%6 = bitcast [24 x i8]* %5 to %swift.type**
%Self = load %swift.type*, %swift.type** %6, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%7 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 1
%8 = bitcast %swift.type** %7 to i8***
%Self.Sequence = load i8**, i8*** %8, align 8
%9 = getelementptr inbounds %swift.type*, %swift.type** %6, i32 2
%10 = bitcast %swift.type** %9 to i8***
%Self.Element.Addable = load i8**, i8*** %10, align 8
tail call swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret %0, %swift.opaque* noalias nocapture %1,
%swift.opaque* noalias nocapture %2, %swift.type* %Self,
i8** %Self.Sequence, i8** %Self.Element.Addable)
ret void
}
クロージャ本体
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture,
%swift.type* %Self, i8** %Self.Sequence, i8** %Self.Element.Addable) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%3 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL", %swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %3, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%4 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 2
%5 = load i8*, i8** %4, align 8, !invariant.load !23
%6 = bitcast i8* %5 to
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %6(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %1, %swift.opaque* noalias nocapture %2,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element, i8** %Self.Element.Addable)
ret void
}
Array.TypeからInt.Typeの取り出し
[.code-highlight: 9-12]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture,
%swift.type* %Self, i8** %Self.Sequence, i8** %Self.Element.Addable) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%3 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL", %swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %3, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%4 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 2
%5 = load i8*, i8** %4, align 8, !invariant.load !23
%6 = bitcast i8* %5 to
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %6(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %1, %swift.opaque* noalias nocapture %2,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element, i8** %Self.Element.Addable)
ret void
}
PWTから+の取り出し
[.code-highlight: 14-17]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture,
%swift.type* %Self, i8** %Self.Sequence, i8** %Self.Element.Addable) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%3 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL", %swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %3, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%4 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 2
%5 = load i8*, i8** %4, align 8, !invariant.load !23
%6 = bitcast i8* %5 to
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %6(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %1, %swift.opaque* noalias nocapture %2,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element, i8** %Self.Element.Addable)
ret void
}
+の呼び出し
[.code-highlight: 18-22]
define internal swiftcc void @"$sST1dAA7Addable7ElementRpzrlE3sumADyFA2D_ADtXEfU_"(
%swift.opaque* noalias nocapture sret,
%swift.opaque* noalias nocapture, %swift.opaque* noalias nocapture,
%swift.type* %Self, i8** %Self.Sequence, i8** %Self.Element.Addable) #0 {
entry:
%Self1 = alloca %swift.type*, align 8
%Self.Element2 = alloca %swift.type*, align 8
store %swift.type* %Self, %swift.type** %Self1, align 8
%3 = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(
i64 0, i8** %Self.Sequence, %swift.type* %Self,
%swift.protocol_requirement* @"$sSTTL", %swift.protocol_requirement* @"$s7ElementSTTl") #6
%Self.Element = extractvalue %swift.metadata_response %3, 0
store %swift.type* %Self.Element, %swift.type** %Self.Element2, align 8
%4 = getelementptr inbounds i8*, i8** %Self.Element.Addable, i32 2
%5 = load i8*, i8** %4, align 8, !invariant.load !23
%6 = bitcast i8* %5 to
void (%swift.opaque*, %swift.opaque*, %swift.opaque*, %swift.type*, %swift.type*, i8**)*
call swiftcc void %6(
%swift.opaque* noalias nocapture sret %0,
%swift.opaque* noalias nocapture %1, %swift.opaque* noalias nocapture %2,
%swift.type* swiftself %Self.Element,
%swift.type* %Self.Element, i8** %Self.Element.Addable)
ret void
}
GenericはMetatypeとVWTで動く
ProtocolはPWTで動く
興味を持った人はぜひ Discordやわいわいswiftcへ