Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Generics 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Generics ͷ࣮૷ ग़ྗͷ؍࡯ 20

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

4ͭͷίϐʔ 67

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

Value Witness Table ࢖༻͢Δଆ, Swift 71

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Value Witness Table ࢖༻͢Δଆ, SIL 73

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

%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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

%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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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