$30 off During Our Annual Pro Sale. View Details »

Swiftのジェネリクスはどうやって動いているのかコンパイラのソースから探る

omochimetaru
September 02, 2018

 Swiftのジェネリクスはどうやって動いているのかコンパイラのソースから探る

iOSDC2018で発表しました
https://fortee.jp/iosdc-japan-2018/proposal/3d60b2ae-5841-4f60-8dd7-830377dc110e

Swiftにはジェネリクスという言語機能があり、
利用時の型が不確定なコードを書くことできます。
Swiftには厳密な型システムや、余計なメタ情報を持たない値型などがあるのに、
どのようにしてジェネリクスを動作させているのでしょうか。
このトークではそれを実現する言語機能である
witness tableについて、
コンパイラのソースコードを追いながら解説します。

omochimetaru

September 02, 2018
Tweet

More Decks by omochimetaru

Other Decks in Programming

Transcript

  1. SwiftͷδΣωϦΫε͸
    Ͳ͏΍ͬͯಈ͍͍ͯΔͷ
    ͔ίϯύΠϥͷιʔε͔
    Β୳Δ
    1

    View Slide

  2. ࣗݾ঺հ
    • omochimetaru
    • Qoncept, Inc
    • ήʔϜ
    • Swift
    • SwiftίϯύΠϥ
    2

    View Slide

  3. ͜ͷൃදͷझࢫ
    • δΣωϦΫεͷ࢓૊ΈΛղઆ
    • ίϯύΠϥΛྲྀߦΒͤΔ
    3

    View Slide

  4. Generics
    4

    View Slide

  5. Generics
    // δΣωϦοΫؔ਺
    func takeX(_ x: X)
    // δΣωϦοΫܕ
    class Box {
    var value: T
    }
    5

    View Slide

  6. ͲΜͳܕͰ΋౉ͤΔ
    func takeX(_ x: X)
    6

    View Slide

  7. func takeX(_ x: X)
    takeX(3)
    7

    View Slide

  8. func takeX(_ x: X)
    takeX(3)
    takeX("hello")
    8

    View Slide

  9. func takeX(_ x: X)
    takeX(3)
    takeX("hello")
    struct Stone { ... }
    takeX(Stone())
    9

    View Slide

  10. func takeX(_ x: X)
    takeX(3)
    takeX("hello")
    struct Stone { ... }
    takeX(Stone())
    class Cat { ... }
    takeX(Cat())
    10

    View Slide

  11. ෆࢥٞ
    • Swift͸੩తܕ෇͚
    • ͔͠͠, ࣮ߦ࣌·Ͱܕ͕Θ͔Βͳ͍
    11

    View Slide

  12. ෆࢥٞ
    • αΠζͷҧ͏Ҿ਺ͷड͚౉͠
    struct Stone { ... }
    class Cat { ... }
    Stone() // 24όΠτ
    Cat() // 8όΠτ
    12

    View Slide

  13. ෆࢥٞ
    • ࢀরܕ͚ͩͳΒΫϥε৘ใʹΞΫηεͰ͖Δ
    • SwiftͷδΣωϦΫε͸஋ܕʹ΋ରԠ
    • ஋ܕʹ͸ͦͷΑ͏ͳϝλ৘ใ͕ແ͍
    13

    View Slide

  14. Swiftͷٙ໰
    • ݴޠ࢓༷ͷٙ໰
    • จॻ͕ͨ͘͞Μ͋Δ
    • ݴޠ ࣮૷ ࢓༷ͷٙ໰
    • จॻ͕গͳ͍
    • ͜ͷ࿩ͷςʔϚ͸ͪ͜Β
    14

    View Slide

  15. ݴޠ࣮૷࢓༷ΛֶͿཧ༝
    • ϓϩάϥϛϯάݴޠΛબ୒͢Δࡍͷ൑அࡐྉ
    • ྫ͑͹ɺ Swift vs Objective-C
    • ύϑΥʔϚϯε࠷దԽʹ໾ཱͭ
    • ଎͍ॻ͖ํɺ஗͍ॻ͖ํɺͦͷཧ༝
    • ָ͍͠
    • ίϯύΠϥ͸ٕज़ͷਮ
    15

    View Slide

  16. Swiftݴޠ࣮૷࢓༷ͷֶͼํ
    • จॻ
    • গͳ͍
    • ݹ͘ͳΔ
    • ਅِͷ֬ೝ͕Ͱ͖ͳ͍
    • ίϯύΠϥͷग़ྗ
    • ίϯύΠϥͷιʔείʔυ
    16

    View Slide

  17. ίϯύΠϥͷಈ͖
    • Swift͸ଟஈ֊ʹม׵
    • Swift → SIL → LLVM-IR → X86_64
    17

    View Slide

  18. ίϯύΠϥͷग़ྗΛ؍࡯
    • ίϯύΠϥͷ్தঢ়ଶΛग़ྗ
    • ࢼͨ͠έʔε͔͠Θ͔Βͳ͍
    18

    View Slide

  19. ίϯύΠϥͷιʔείʔυΛಡΉ
    • ໢ཏతͳ೺Ѳ͕Մೳ
    • Φʔϓϯιʔε
    • https://github.com/apple/swift
    19

    View Slide

  20. Generics ͷ࣮૷
    ग़ྗͷ؍࡯
    20

    View Slide

  21. ίϯύΠϧखॱͷ࠶ܝ
    Swift → SIL → LLVM-IR → X86_64
    21

    View Slide

  22. SIL ʹม׵ͯ͠ΈΔ
    func takeX(_ x: X) { ... }
    22

    View Slide

  23. SIL ʹม׵ͯ͠ΈΔ
    // aaa.swift
    func takeX(_ x: X) { ... }
    $ swiftc -emit-sil aaa.swift > aaa.sil
    23

    View Slide

  24. SIL Ͱͷ takeX
    sil hidden @$S3aaa5takeXyyxlF :
    $@convention(thin) (@in_guaranteed X) -> ()
    24

    View Slide

  25. sil hidden @$S3aaa5takeXyyxlF :
    $@convention(thin) (@in_guaranteed X) -> ()
    : δΣωϦοΫύϥϝʔλɻ
    25

    View Slide

  26. SILͷܕγεςϜ
    • SIL͸SwiftͷܕγεςϜΛ࣋ͭ
    • δΣωϦΫε΋࣋ͭ
    26

    View Slide

  27. LLVM-IR ʹม׵ͯ͠ΈΔ
    func takeX(_ x: X)
    27

    View Slide

  28. LLVM-IR ʹม׵ͯ͠ΈΔ
    // aaa.swift
    func takeX(_ x: X)
    $ swiftc -emit-ir aaa.swift > aaa.ll
    28

    View Slide

  29. LLVM-IR Ͱͷ takeX
    ; aaa.ll
    define hidden swiftcc
    void @"$S3aaa5takeXyyxlF"(
    %swift.opaque* noalias nocapture,
    %swift.type* %X)
    ߏจ
    define ଐੑ...
    ฦΓ஋ͷܕ ؔ਺໊ (
    ୈ1Ҿ਺ͷܕ ୈ1Ҿ਺ͷ໊લ,
    ୈ2Ҿ਺ͷܕ ୈ2Ҿ਺ͷ໊લ, ...)
    29

    View Slide

  30. define hidden swiftcc
    void @"$S3aaa5takeXyyxlF"(
    %swift.opaque* noalias nocapture,
    %swift.type* %X)
    • ୈ1Ҿ਺ͷܕ͸ %swift.opaque*
    • * ͸ϙΠϯλ
    • opaque͸ʮෆ໌ͳԿ͔ʯ
    • Swiftʹ͓͚ΔҾ਺ x: X ͱରԠʁ
    • ৗʹϙΠϯλͳΒαΠζ͸Ұఆ
    30

    View Slide

  31. define hidden swiftcc
    void @"$S3aaa5takeXyyxlF"(
    %swift.opaque* noalias nocapture,
    %swift.type* %X)
    • ୈ2Ҿ਺ͷܕ͸ %swift.type*
    • ୈ2Ҿ਺ͷ໊લ͸ %X
    • Swiftʹ͓͚Δܕύϥϝʔλ ͱରԠʁ
    31

    View Slide

  32. δΣωϦΫεͷ͘͠Έ
    • X ܕͷ஋͸ৗʹϙΠϯλ౉͠
    • Swiftͷܕύϥϝʔλ → Ҿ਺ %X
    • ʹ͍ͭͯͷϝλ৘ใʁ
    32

    View Slide

  33. ༧૝͕ͨ͘͞Μ
    • ܕ͔͠ௐ΂͍ͯͳ͍
    • ݺͼग़͠ଆ΋ௐ΂ΒΕΔ
    • ݺͼग़͞Εଆ΋ௐ΂ΒΕΔ
    33

    View Slide

  34. ΫΠζ
    func take2X(_ x1: X, _ x2: X)
    • LLVM-IR Ͱ %swift.type* ͸͍ͭ͘ʁ
    • X ͸ x1 ͱ x2 ͕͋Δ͔Βɺ2ͭʁ
    • ͸1͔ͭͩΒɺ1ͭʁ
    34

    View Slide

  35. LLVM-IR Ͱͷ take2X
    define hidden swiftcc
    void @"$S3aaa6take2Xyyx_xtlF"(
    %swift.opaque* noalias nocapture,
    %swift.opaque* noalias nocapture,
    %swift.type* %X)
    35

    View Slide

  36. ؍࡯ख๏ͷ݀
    • ؍࡯ͨ͠ࣄ͔͠Θ͔Βͳ͍ɻ
    • Ҿ਺͕3ͭͷ৔߹͸ʁ
    36

    View Slide

  37. Genericsͷ࣮૷
    ίϯύΠϥͷιʔεΛಡΉ
    37

    View Slide

  38. IRGen
    SIL → LLVM-IR ͷม׵Ϟδϡʔϧ
    swift/lib/IRGen
    38

    View Slide

  39. swift/lib/IRGen/GenDecl.cpp
    llvm::Function *
    IRGenModule::getAddrOfSILFunction(SILFunction *f,
    ForDefinition_t forDefinition)
    SILͷؔ਺ʹରԠ͢ΔLLVM-IRͷؔ਺Λऔಘɺ
    ·ͨ͸ੜ੒͢Δؔ਺ɻ
    39

    View Slide

  40. llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
    ForDefinition_t forDefinition) {
    LinkEntity entity = LinkEntity::forSILFunction(f);
    // Check whether we've created the function already.
    // FIXME: We should integrate this into the LinkEntity cache more cleanly.
    llvm::Function *fn = Module.getFunction(f->getName());
    if (fn) {
    if (forDefinition) updateLinkageForDefinition(*this, fn, entity);
    return fn;
    }
    // If it's a Clang declaration, ask Clang to generate the IR declaration.
    // This might generate new functions, so we should do it before computing
    // the insert-before point.
    llvm::Constant *clangAddr = nullptr;
    if (auto clangDecl = f->getClangDecl()) {
    auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
    clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
    }
    bool isDefinition = f->isDefinition();
    bool hasOrderNumber = isDefinition;
    unsigned orderNumber = ~0U;
    llvm::Function *insertBefore = nullptr;
    // If the SIL function has a definition, we should have an order
    // number for it; make sure to insert it in that position relative
    // to other ordered functions.
    if (hasOrderNumber) {
    orderNumber = IRGen.getFunctionOrder(f);
    if (auto emittedFunctionIterator
    = EmittedFunctionsByOrder.findLeastUpperBound(orderNumber))
    insertBefore = *emittedFunctionIterator;
    }
    // If it's a Clang declaration, check whether Clang gave us a declaration.
    if (clangAddr) {
    fn = dyn_cast(clangAddr->stripPointerCasts());
    // If we have a function, move it to the appropriate position.
    if (fn) {
    if (hasOrderNumber) {
    auto &fnList = Module.getFunctionList();
    fnList.remove(fn);
    fnList.insert(llvm::Module::iterator(insertBefore), fn);
    EmittedFunctionsByOrder.insert(orderNumber, fn);
    }
    return fn;
    }
    // Otherwise, if we have a lazy definition for it, be sure to queue that up.
    } else if (isDefinition && !forDefinition && !f->isPossiblyUsedExternally() &&
    !hasCodeCoverageInstrumentation(*f, getSILModule())) {
    IRGen.addLazyFunction(f);
    }
    Signature signature = getSignature(f->getLoweredFunctionType());
    auto &attrs = signature.getMutableAttributes();
    LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
    switch (f->getInlineStrategy()) {
    case NoInline:
    attrs = attrs.addAttribute(signature.getType()->getContext(),
    llvm::AttributeList::FunctionIndex,
    llvm::Attribute::NoInline);
    break;
    case AlwaysInline:
    // FIXME: We do not currently transfer AlwaysInline since doing so results
    // in test failures, which must be investigated first.
    case InlineDefault:
    break;
    }
    if (isReadOnlyFunction(f)) {
    attrs = attrs.addAttribute(signature.getType()->getContext(),
    llvm::AttributeList::FunctionIndex,
    llvm::Attribute::ReadOnly);
    }
    fn = createFunction(*this, link, signature, insertBefore,
    f->getOptimizationMode());
    // If `hasCReferences` is true, then the function is either marked with
    // @_silgen_name OR @_cdecl. If it is the latter, it must have a definition
    // associated with it. The combination of the two allows us to identify the
    // @_silgen_name functions. These are locally defined function thunks used in
    // the standard library. Do not give them DLLImport DLL Storage.
    if (useDllStorage() && f->hasCReferences() && !forDefinition)
    fn->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
    // If we have an order number for this function, set it up as appropriate.
    if (hasOrderNumber) {
    EmittedFunctionsByOrder.insert(orderNumber, fn);
    }
    return fn;
    }
    40

    View Slide

  41. llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
    ForDefinition_t forDefinition) {
    ...
    llvm::Function *fn = Module.getFunction(f->getName());
    if (fn) {
    ...
    return fn;
    }
    ...
    Signature signature = getSignature(f->getLoweredFunctionType());
    ...
    fn = createFunction(*this, link, signature, insertBefore,
    f->getOptimizationMode());
    ...
    return fn;
    }
    Ωϟογϡύλʔϯ
    41

    View Slide

  42. llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
    ForDefinition_t forDefinition) {
    ...
    llvm::Function *fn = Module.getFunction(f->getName());
    if (fn) {
    ...
    return fn;
    }
    ...
    Signature signature = getSignature(f->getLoweredFunctionType());
    ...
    fn = createFunction(*this, link, signature, insertBefore,
    f->getOptimizationMode());
    ...
    return fn;
    }
    SILؔ਺ͷܕˠLLVM-IRؔ਺ͷܕ
    42

    View Slide

  43. Signature
    IRGenModule::getSignature(CanSILFunctionType type) {
    auto &sigInfo = getFuncSignatureInfoForLowered(*this, type);
    return sigInfo.getSignature(*this);
    }
    ॲཧΛܕʹ੾Γग़͍ͯ͠Δ
    43

    View Slide

  44. Signature FuncSignatureInfo::getSignature(IRGenModule &IGM) const {
    // If it's already been filled in, we're done.
    if (TheSignature.isValid())
    return TheSignature;
    // Update the cache and return.
    TheSignature = Signature::getUncached(IGM, FormalType);
    assert(TheSignature.isValid());
    return TheSignature;
    }
    Ωϟογϡύλʔϯ
    44

    View Slide

  45. Signature Signature::getUncached(IRGenModule &IGM,
    CanSILFunctionType formalType) {
    GenericContextScope scope(IGM, formalType->getGenericSignature());
    SignatureExpansion expansion(IGM, formalType);
    expansion.expandFunctionType();
    return expansion.getSignature();
    }
    ॲཧΛܕʹ੾Γग़͍ͯ͠Δ
    45

    View Slide

  46. Signature Signature::getUncached(IRGenModule &IGM,
    CanSILFunctionType formalType) {
    GenericContextScope scope(IGM, formalType->getGenericSignature());
    SignatureExpansion expansion(IGM, formalType);
    expansion.expandFunctionType();
    return expansion.getSignature();
    }
    ؔ਺ͷܕΛੜ੒
    46

    View Slide

  47. void SignatureExpansion::expandFunctionType() {
    switch (FnType->getLanguage()) {
    case SILFunctionLanguage::Swift: {
    expandResult();
    expandParameters();
    return;
    }
    case SILFunctionLanguage::C:
    expandExternalSignatureTypes();
    return;
    }
    llvm_unreachable("bad abstract calling convention");
    }
    47

    View Slide

  48. void SignatureExpansion::expandFunctionType() {
    switch (FnType->getLanguage()) {
    case SILFunctionLanguage::Swift: {
    expandResult();
    expandParameters();
    return;
    }
    case SILFunctionLanguage::C:
    expandExternalSignatureTypes();
    return;
    }
    llvm_unreachable("bad abstract calling convention");
    }
    ฦΓ஋ͷܕΛੜ੒
    48

    View Slide

  49. void SignatureExpansion::expandFunctionType() {
    switch (FnType->getLanguage()) {
    case SILFunctionLanguage::Swift: {
    expandResult();
    expandParameters();
    return;
    }
    case SILFunctionLanguage::C:
    expandExternalSignatureTypes();
    return;
    }
    llvm_unreachable("bad abstract calling convention");
    }
    Ҿ਺ͷܕΛੜ੒
    49

    View Slide

  50. void SignatureExpansion::expandParameters() {
    assert(FnType->getRepresentation() != SILFunctionTypeRepresentation::Block
    && "block with non-C calling conv?!");
    // First, if this is a coroutine, add the coroutine-context parameter.
    switch (FnType->getCoroutineKind()) {
    case SILCoroutineKind::None:
    break;
    case SILCoroutineKind::YieldOnce:
    case SILCoroutineKind::YieldMany:
    addCoroutineContextParameter();
    break;
    }
    // Next, the formal parameters. But 'self' is treated as the
    // context if it has pointer representation.
    auto params = FnType->getParameters();
    bool hasSelfContext = false;
    if (hasSelfContextParameter(FnType)) {
    hasSelfContext = true;
    params = params.drop_back();
    }
    for (auto param : params) {
    expand(param);
    }
    // Next, the generic signature.
    if (hasPolymorphicParameters(FnType))
    expandPolymorphicSignature(IGM, FnType, ParamIRTypes);
    // Context is next.
    if (hasSelfContext) {
    auto curLength = ParamIRTypes.size(); (void) curLength;
    if (claimSelf())
    IGM.addSwiftSelfAttributes(Attrs, curLength);
    expand(FnType->getSelfParameter());
    assert(ParamIRTypes.size() == curLength + 1 &&
    "adding 'self' added unexpected number of parameters");
    } else {
    auto needsContext = [=]() -> bool {
    switch (FnType->getRepresentation()) {
    case SILFunctionType::Representation::Block:
    llvm_unreachable("adding block parameter in Swift CC expansion?");
    // Always leave space for a context argument if we have an error result.
    case SILFunctionType::Representation::CFunctionPointer:
    case SILFunctionType::Representation::Method:
    case SILFunctionType::Representation::WitnessMethod:
    case SILFunctionType::Representation::ObjCMethod:
    case SILFunctionType::Representation::Thin:
    case SILFunctionType::Representation::Closure:
    return FnType->hasErrorResult();
    case SILFunctionType::Representation::Thick:
    return true;
    }
    llvm_unreachable("bad representation kind");
    };
    if (needsContext()) {
    if (claimSelf())
    IGM.addSwiftSelfAttributes(Attrs, ParamIRTypes.size());
    ParamIRTypes.push_back(IGM.RefCountedPtrTy);
    }
    }
    // Error results are last. We always pass them as a pointer to the
    // formal error type; LLVM will magically turn this into a non-pointer
    // if we set the right attribute.
    if (FnType->hasErrorResult()) {
    if (claimError())
    IGM.addSwiftErrorAttributes(Attrs, ParamIRTypes.size());
    llvm::Type *errorType = IGM.getStorageType(
    getSILFuncConventions().getSILType(FnType->getErrorResult()));
    ParamIRTypes.push_back(errorType->getPointerTo());
    }
    // Witness methods have some extra parameter types.
    if (FnType->getRepresentation() ==
    SILFunctionTypeRepresentation::WitnessMethod) {
    expandTrailingWitnessSignature(IGM, FnType, ParamIRTypes);
    }
    }
    50

    View Slide

  51. void SignatureExpansion::expandParameters() {
    ...
    auto params = FnType->getParameters();
    ...
    for (auto param : params) {
    expand(param);
    }
    // Next, the generic signature.
    if (hasPolymorphicParameters(FnType))
    expandPolymorphicSignature(IGM, FnType, ParamIRTypes);
    ...
    }
    51

    View Slide

  52. void SignatureExpansion::expandParameters() {
    ...
    auto params = FnType->getParameters();
    ...
    for (auto param : params) {
    expand(param);
    }
    // Next, the generic signature.
    if (hasPolymorphicParameters(FnType))
    expandPolymorphicSignature(IGM, FnType, ParamIRTypes);
    ...
    }
    SILؔ਺ͷҾ਺ͦΕͧΕʹ͍ͭͯɺ
    LLVM-IRؔ਺ͷҾ਺Λੜ੒
    52

    View Slide

  53. void SignatureExpansion::expandParameters() {
    ...
    auto params = FnType->getParameters();
    ...
    for (auto param : params) {
    expand(param);
    }
    // Next, the generic signature.
    if (hasPolymorphicParameters(FnType))
    expandPolymorphicSignature(IGM, FnType, ParamIRTypes);
    ...
    }
    δΣωϦΫεͷ৘ใʹ͍ͭͯɺ
    LLVM-IRؔ਺ͷҾ਺Λੜ੒
    53

    View Slide

  54. void irgen::expandPolymorphicSignature(IRGenModule &IGM,
    CanSILFunctionType polyFn,
    SmallVectorImpl &out) {
    ExpandPolymorphicSignature(IGM, polyFn).expand(out);
    }
    ॲཧΛܕʹ੾Γग़͍ͯ͠Δ
    54

    View Slide

  55. class ExpandPolymorphicSignature : public PolymorphicConvention {
    ...
    void expand(SmallVectorImpl &out) {
    ...
    enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
    out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
    : IGM.TypeMetadataPtrTy);
    });
    }
    ...
    }
    55

    View Slide

  56. class ExpandPolymorphicSignature : public PolymorphicConvention {
    ...
    void expand(SmallVectorImpl &out) {
    ...
    enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
    out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
    : IGM.TypeMetadataPtrTy);
    });
    }
    ...
    }
    δΣωϦοΫύϥϝʔλͱɺϓϩτίϧ੍໿ʹ͍ͭͯ܁Γฦ
    ͢ɻ
    56

    View Slide

  57. class ExpandPolymorphicSignature : public PolymorphicConvention {
    ...
    void expand(SmallVectorImpl &out) {
    ...
    enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
    out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
    : IGM.TypeMetadataPtrTy);
    });
    }
    ...
    }
    IGM.TypeMetadataPtrTy = %swift.type*
    57

    View Slide

  58. ͜͜·Ͱ·ͱΊ
    ܕύϥϝʔλ͸ίϯύΠϧޙ͸ܕͷ৘ใΛද͢஋ͷҾ਺ʹͳΔ
    58

    View Slide

  59. X ͷऔѻ
    • X ΛऔΓѻ͏ͨΊͷ৘ใ͕ɺҾ਺Ͱ౉͞ΕΔ
    • ͲΜͳ৘ใʁ
    • X ΛऔΓѻ͏ ͱ͸Կ͔ʁ
    59

    View Slide

  60. X ʹରͯ͠Կ͕Ͱ͖Δʁ
    func takeX(_ x: X) {
    ...
    }
    • ϝιουݺ΂ͳ͍
    • initͰ͖ͳ͍
    60

    View Slide

  61. X ʹରͯ͠Ͱ͖Δ͜ͱ
    func take(_ x: X) {
    let x2: X = x
    }
    • ֓Ͷ͜ΕͰશͯ
    61

    View Slide

  62. func take(_ x: X) {
    let x2: X = x
    }
    • x2ͷྖҬͷ֬อ
    • x2΁ͷίϐʔ
    • x2ͷഁغ (ؔ਺୤ग़࣌)
    • x2ͷྖҬͷղ์ (ؔ਺୤ग़࣌)
    62

    View Slide

  63. ྖҬͷ֬อʹඞཁͳ৘ใ
    • ܕͷαΠζͱΞϥΠϝϯτ
    • ղ์͸֬อ࣌ͷ৘ใͷΈͰOK
    63

    View Slide

  64. ίϐʔͱഁغʹඞཁͳૢ࡞
    ࢀরܕͷ৔߹: retain countૢ࡞
    ஋ܕͷ৔߹: stored property ͝ͱʹૢ࡞
    struct Entry {
    var id: Int
    var name: String
    var view: UIView
    }
    64

    View Slide

  65. Value Witness Table
    • ܕΛऔΓѻ͏ͨΊͷؔ਺΍஋Λఆٛͨ͠ςʔϒϧ
    • ܕ͝ͱʹ1ͭఆٛ
    • ϝλλΠϓ(Int.self ͳͲ)͔ΒऔΓग़ͤΔ
    https://github.com/apple/swift/blob/master/docs/ABI/
    TypeMetadata.rst
    65

    View Slide

  66. Value Witness Table ͷٙࣅίʔυ
    var vwt = VWT()
    vwt[0] = ...
    vwt[1] = destroy
    vwt[2] = initializeWithCopy
    vwt[3] = assignWithCopy
    vwt[4] = initializeWithTake
    vwt[5] = assignWithTake
    vwt[6] = ...
    vwt[7] = ...
    vwt[8] = size
    vwt[9] = flags (alignment)
    vwt[10] = stride
    66

    View Slide

  67. 4ͭͷίϐʔ
    67

    View Slide

  68. • ίϐʔઌ ͕ະॳظԽ͔Ͳ͏͔ɻ
    • ະॳظԽ: initialize
    • ॳظԽࡁΈ: assign
    • ίϐʔݩ Λഁغ͢Δ͔Ͳ͏͔ɻ
    • ഁغ͠ͳ͍: copy
    • ഁغ͢Δ: take
    • 2x2ͷ૊Έ߹ΘͤͰ4छྨ
    68

    View Slide

  69. ૊Έ߹Θͤͷྫ
    initializeWithTake
    • initialize: ະॳظԽͷίϐʔઌΛॳظԽ͢Δ
    • take: ίϐʔݩ͸ഁغ͢Δ
    69

    View Slide

  70. Value Witness Table Λௐ΂Δ
    • ࢖༻͢Δଆ, ݺͼग़͞Εଆ
    • ݺͼग़͠ଆ
    • ςʔϒϧͷੜ੒ॲཧ
    70

    View Slide

  71. Value Witness Table
    ࢖༻͢Δଆ, Swift
    71

    View Slide

  72. func takeX(_ x: X) {
    let x2 = x
    }
    72

    View Slide

  73. Value Witness Table
    ࢖༻͢Δଆ, SIL
    73

    View Slide

  74. // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@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 "x2" // 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 '$S3aaa5takeXyyxlF'
    74

    View Slide

  75. // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@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 "x2" // 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 '$S3aaa5takeXyyxlF'
    75

    View Slide

  76. // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@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 "x2" // 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 '$S3aaa5takeXyyxlF'
    76

    View Slide

  77. // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@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 "x2" // 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 '$S3aaa5takeXyyxlF'
    77

    View Slide

  78. // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@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 "x2" // 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 '$S3aaa5takeXyyxlF'
    78

    View Slide

  79. Value Witness Table
    ࢖༻͢Δଆ, LLVM-IR
    79

    View Slide

  80. define hidden swiftcc void @"$S3aaa5takeXyyxlF"(%swift.opaque* noalias nocapture, %swift.type* %X) #0 {
    entry:
    %X1 = alloca %swift.type*, align 8
    %x2.addr = alloca i8*, align 8
    %1 = bitcast i8** %x2.addr to %swift.opaque**
    store %swift.opaque* null, %swift.opaque** %1, align 8
    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
    %x2 = alloca i8, i64 %size, align 16
    call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x2)
    %6 = bitcast i8* %x2 to %swift.opaque*
    store i8* %x2, i8** %x2.addr, 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
    }
    80

    View Slide

  81. define hidden swiftcc void @"$S3aaa5takeXyyxlF"(
    %swift.opaque* noalias nocapture, %swift.type* %X) #0 {
    entry:
    %X1 = alloca %swift.type*, align 8
    %x2.addr = alloca i8*, align 8
    %1 = bitcast i8** %x2.addr to %swift.opaque**
    store %swift.opaque* null, %swift.opaque** %1, align 8
    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
    %x2 = alloca i8, i64 %size, align 16
    81

    View Slide

  82. define hidden swiftcc void @"$S3aaa5takeXyyxlF"(
    %swift.opaque* noalias nocapture, %swift.type* %X) #0 {
    entry:
    %X1 = alloca %swift.type*, align 8
    %x2.addr = alloca i8*, align 8
    %1 = bitcast i8** %x2.addr to %swift.opaque**
    store %swift.opaque* null, %swift.opaque** %1, align 8
    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
    %x2 = alloca i8, i64 %size, align 16
    82

    View Slide

  83. var vwt = VWT()
    vwt[0] = ...
    vwt[1] = destroy
    vwt[2] = initializeWithCopy
    vwt[3] = assignWithCopy
    vwt[4] = initializeWithTake
    vwt[5] = assignWithTake
    vwt[6] = ...
    vwt[7] = ...
    vwt[8] = size
    vwt[9] = flags (alignment)
    vwt[10] = stride
    83

    View Slide

  84. %x2 = alloca i8, i64 %size, align 16
    call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x2)
    %6 = bitcast i8* %x2 to %swift.opaque*
    store i8* %x2, i8** %x2.addr, 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
    }
    84

    View Slide

  85. var vwt = VWT()
    vwt[0] = ...
    vwt[1] = destroy
    vwt[2] = initializeWithCopy
    vwt[3] = assignWithCopy
    vwt[4] = initializeWithTake
    vwt[5] = assignWithTake
    vwt[6] = ...
    vwt[7] = ...
    vwt[8] = size
    vwt[9] = flags (alignment)
    vwt[10] = stride
    85

    View Slide

  86. %x2 = alloca i8, i64 %size, align 16
    call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x2)
    %6 = bitcast i8* %x2 to %swift.opaque*
    store i8* %x2, i8** %x2.addr, 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
    }
    86

    View Slide

  87. var vwt = VWT()
    vwt[0] = ...
    vwt[1] = destroy
    vwt[2] = initializeWithCopy
    vwt[3] = assignWithCopy
    vwt[4] = initializeWithTake
    vwt[5] = assignWithTake
    vwt[6] = ...
    vwt[7] = ...
    vwt[8] = size
    vwt[9] = flags (alignment)
    vwt[10] = stride
    87

    View Slide

  88. Value Witness Table
    ࢖༻͢Δଆ, ίϯύΠϥ
    88

    View Slide

  89. SIL: copy_addr ໋ྩ
    // takeX(_:)
    sil hidden @$S3aaa5takeXyyxlF : $@convention(thin) (@in_guaranteed X) -> () {
    ...
    copy_addr %0 to [initialization] %2 : $*X // id: %3
    ...
    } // end sil function '$S3aaa5takeXyyxlF'
    LLVM-IR
    %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
    89

    View Slide

  90. IRGenSILFunction
    VisitorύλʔϯͰSIL໋ྩ͝ͱʹม׵
    void IRGenSILFunction::visitCopyAddrInst(swift::CopyAddrInst *i)
    90

    View Slide

  91. 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);
    }
    }
    }
    91

    View Slide

  92. 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();
    92

    View Slide

  93. 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);
    }
    }
    }
    93

    View Slide

  94. TypeInfo
    ΫϥεܧঝΛ࢖ͬͯܕͷ෼ྨ͝ͱʹ
    ίϯύΠϧॲཧΛ੾Γସ͑Δɻ
    struct: LoadableStructTypeInfo
    class: ClassTypeInfo
    : OpaqueArchetypeTypeInfo
    94

    View Slide

  95. OpaqueArchetypeTypeInfo
    initializeWithCopy͸਌Ϋϥεͷ
    ResilientTypeInfoͷ࣮૷Λܧঝɻ
    template
    class ResilientTypeInfo {
    ...
    void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
    SILType T, bool isOutlined) const override {
    emitInitializeWithCopyCall(IGF, T, dest, src);
    }
    ...
    };
    95

    View Slide

  96. 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});
    }
    96

    View Slide

  97. C++
    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});
    LLVM-IR
    %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
    97

    View Slide

  98. C++
    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});
    LLVM-IR
    %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
    98

    View Slide

  99. 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;
    }
    99

    View Slide

  100. FunctionPointer
    IRGenFunction::emitValueWitnessFunctionRef(SILType type,
    llvm::Value *&metadataSlot,
    ValueWitness index) {
    ...
    auto vwtable = emitValueWitnessTableRef(type, &metadataSlot);
    auto witness = emitLoadOfValueWitnessFunction(*this, vwtable, index);
    ...
    return witness;
    }
    ValueWitness::InitializeWithCopy == 2
    100

    View Slide

  101. 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);
    }
    101

    View Slide

  102. C++
    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);
    LLVM-IR
    %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
    102

    View Slide

  103. C++
    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);
    LLVM-IR
    %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
    103

    View Slide

  104. 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;
    }
    104

    View Slide

  105. C++; index.getValue() == 2
    // 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;
    LLVM-IR
    %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
    105

    View Slide

  106. C++
    // 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;
    LLVM-IR
    %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
    106

    View Slide

  107. Value Witness Table
    • ݺͼग़͠ଆ
    • ςʔϒϧͷੜ੒
    λΠϜΞοϓ
    107

    View Slide

  108. ·ͱΊ
    • δΣωϦοΫύϥϝʔλ͸࣮ߦ࣌ʹ͸ܕ৘ใͷҾ਺ʹͳΔ
    • ܕ৘ใʹ͸ Value Witness Table ͕ೖ͍ͬͯͯɺ
    औΓѻ͏ͨΊͷؔ਺܈͕ೖ͍ͬͯΔɻ
    • Swift࣮૷͸தؒग़ྗͱίϯύΠϥιʔεͷ྆ํ͔Βֶ΅͏ɻ
    108

    View Slide

  109. એ఻
    Θ͍Θ͍swiftc: SwiftίϯύΠϥͷษڧձ
    https://iosdiscord.connpass.com/event/92738/
    ࣍ճ ୈ5ճ 9/12
    109

    View Slide

  110. એ఻
    Θ͍Θ͍swiftc: SwiftίϯύΠϥͷษڧձ
    https://iosdiscord.connpass.com/event/92738/
    ࣍ճ ୈ5ճ 9/12
    110

    View Slide

  111. એ఻
    Θ͍Θ͍swiftc: SwiftίϯύΠϥͷษڧձ
    https://iosdiscord.connpass.com/event/92738/
    ͜ͷ͋ͱ͙͢ʂ
    ࣍࣍ճ ୈ5ճ 9/12
    111

    View Slide