Skip to content

Instantly share code, notes, and snippets.

@omochi
Created November 16, 2018 11:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save omochi/58f374f2809fb1c9122d2b0b69948256 to your computer and use it in GitHub Desktop.
Save omochi/58f374f2809fb1c9122d2b0b69948256 to your computer and use it in GitHub Desktop.

slidenumbers: true

SwiftのGenericsとProtocolの実装

omochimetaru

言語処理系勉強会 Vol.1


自己紹介

  • omochimetaru
  • Qoncept, Inc.
  • iOS, Mac, Web Frontend, Unity, Android
  • Swift, C++, TypeScript, Kotlin
  • Twitter, GitHub, Qiita, Qrunch
  • ゲーム, Swiftコンパイラ

right


  • わいわいswiftc https://iosdiscord.connpass.com

  • iOSDC (2018/09/02) Swiftのジェネリクスはどうやって動いているのかコンパイラのソースから探る

  • Discord swift-developers-japan


Swift

  • Appleが開発
  • オープンソース
  • ネイティブコンパイル言語
  • 値型
  • Generics
  • プロトコル指向

オープンソース

https://github.com/apple/swift

https://forums.swift.org


ネイティブコンパイル

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

Generics

// 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

Genericsの実装


特徴

  • 値型と参照型に対応 値型は異なるサイズをもち、 自身にメタ情報を持たない

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
}

Signature

func takeX1<X>(_ x: X)
void @"$s1a6takeX1yyxlF"(
    %swift.opaque* noalias nocapture, 
    %swift.type* %X)

→ opaque pointer + metatype


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

libSwiftCore.dylib

標準ライブラリ(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の破棄, ストレージ解放

Value Witness Table

Metatypeから取り出せる関数テーブル

コピーや破棄など、値(Value)に対する一般的な操作をする関数が入っている

インターフェースはOpaqueな表現になっている

入っている関数は個別の型を期待しているため、 Opaqueな値と、その真の型のMetatypeをペアで取り回す


Valueの意味

値型(struct)の場合、そのメモリ上の表現のこと。

参照型(class)の場合、そのアドレスを格納する8バイトのポインタのこと。

https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md


コピー/破棄の処理内容

値型の場合、それのもつ stored property すべてを再帰的にコピー/破棄。

参照型の値の場合、その参照先のオブジェクトにある参照カウンタの増減操作。


VWTの固有、共有

値型のMetatypeは固有のVWTを持つ。

参照型のMetatypeは共通のVWTを持つ。


Value Witness Table

の詳細


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で確保されていたので、 解放用の命令は特になし


VWT操作処理の

コンパイラの実装


再掲

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


メソッドの定義

protocol Animal {
    func speak() -> String
}

class Cat : Animal {
    func speak() -> String { return "にゃー" }
}

class Dog : Animal {
    func speak() -> String { return "わん" }
}

staticメソッドの定義

protocol Animal {
    static func label() -> String
}

class Cat : Animal {
    static func label() -> String { return "" }
}

class Dog : Animal {
    static func label() -> String { return "" }
}

associated type

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) { }
}

Self型

protocol Animal {
    func spawn() -> Self
}

final class Cat : Animal {
    func spawn() -> Cat { return Cat() }
}

final class Dog : Animal {
    func spawn() -> Dog { return Dog() }
}

Genericsと組み合わせる

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

Protocolの実装


特徴

  • 値型と参照型に対応
  • 既存の型に後付可能
  • 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 Witness Table

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へ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment