//===--- SerializeSIL.cpp - Read and write SIL ----------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-serialize" #include "SILFormat.h" #include "Serialization.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Module.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Assertions.h" #include "swift/SIL/CFG.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TerminatorUtils.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/Strings.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/DJB.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/OnDiskHashTable.h" #include using namespace swift; using namespace swift::serialization; using namespace swift::serialization::sil_block; using namespace llvm::support; using llvm::BCBlockRAII; static unsigned toStableStringEncoding(StringLiteralInst::Encoding encoding) { switch (encoding) { case StringLiteralInst::Encoding::Bytes: return SIL_BYTES; case StringLiteralInst::Encoding::UTF8: return SIL_UTF8; case StringLiteralInst::Encoding::ObjCSelector: return SIL_OBJC_SELECTOR; case StringLiteralInst::Encoding::UTF8_OSLOG: return SIL_UTF8_OSLOG; } llvm_unreachable("bad string encoding"); } static unsigned toStableSILLinkage(SILLinkage linkage) { switch (linkage) { case SILLinkage::Public: return SIL_LINKAGE_PUBLIC; case SILLinkage::PublicNonABI: return SIL_LINKAGE_PUBLIC_NON_ABI; case SILLinkage::Package: return SIL_LINKAGE_PACKAGE; case SILLinkage::PackageNonABI: return SIL_LINKAGE_PACKAGE_NON_ABI; case SILLinkage::Hidden: return SIL_LINKAGE_HIDDEN; case SILLinkage::Shared: return SIL_LINKAGE_SHARED; case SILLinkage::Private: return SIL_LINKAGE_PRIVATE; case SILLinkage::PublicExternal: return SIL_LINKAGE_PUBLIC_EXTERNAL; case SILLinkage::PackageExternal: return SIL_LINKAGE_PACKAGE_EXTERNAL; case SILLinkage::HiddenExternal: return SIL_LINKAGE_HIDDEN_EXTERNAL; } llvm_unreachable("bad linkage"); } static unsigned toStableVTableEntryKind(SILVTable::Entry::Kind kind) { switch (kind) { case SILVTable::Entry::Kind::Normal: return SIL_VTABLE_ENTRY_NORMAL; case SILVTable::Entry::Kind::Inherited: return SIL_VTABLE_ENTRY_INHERITED; case SILVTable::Entry::Kind::Override: return SIL_VTABLE_ENTRY_OVERRIDE; } llvm_unreachable("bad vtable entry kind"); } static unsigned toStableCastConsumptionKind(CastConsumptionKind kind) { switch (kind) { case CastConsumptionKind::TakeAlways: return SIL_CAST_CONSUMPTION_TAKE_ALWAYS; case CastConsumptionKind::TakeOnSuccess: return SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS; case CastConsumptionKind::CopyOnSuccess: return SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS; case CastConsumptionKind::BorrowAlways: return SIL_CAST_CONSUMPTION_BORROW_ALWAYS; } llvm_unreachable("bad cast consumption kind"); } static unsigned toStableDifferentiabilityKind(swift::DifferentiabilityKind kind) { switch (kind) { case swift::DifferentiabilityKind::NonDifferentiable: return (unsigned)serialization::DifferentiabilityKind::NonDifferentiable; case swift::DifferentiabilityKind::Forward: return (unsigned)serialization::DifferentiabilityKind::Forward; case swift::DifferentiabilityKind::Reverse: return (unsigned)serialization::DifferentiabilityKind::Reverse; case swift::DifferentiabilityKind::Normal: return (unsigned)serialization::DifferentiabilityKind::Normal; case swift::DifferentiabilityKind::Linear: return (unsigned)serialization::DifferentiabilityKind::Linear; } llvm_unreachable("covered switch"); } static unsigned encodeValueOwnership(ValueOwnershipKind ownership) { assert(ownership.value > 0 && "invalid value ownership"); return ownership.value - 1; } namespace { /// Used to serialize the on-disk func hash table. class FuncTableInfo { Serializer &S; public: using key_type = StringRef; using key_type_ref = key_type; using data_type = DeclID; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = unsigned; explicit FuncTableInfo(Serializer &S) : S(S) {} hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { return { sizeof(uint32_t), sizeof(uint32_t) }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { uint32_t keyID = S.addUniquedStringRef(key); endian::write(out, keyID, llvm::endianness::little); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { endian::write(out, data, llvm::endianness::little); } }; class StringTableInfo { public: using key_type = StringRef; using key_type_ref = key_type; using data_type = StringRef; using data_type_ref = const data_type &; using hash_value_type = uint32_t; using offset_type = uint32_t; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::djbHash(key, SWIFTMODULE_HASH_SEED); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { offset_type keyLength = static_cast(key.size()); llvm::support::endian::write(out, keyLength, llvm::endianness::little); offset_type dataLength = static_cast(data.size()); llvm::support::endian::write(out, dataLength, llvm::endianness::little); return {keyLength, dataLength}; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key; } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { out << data; } }; class SILSerializer { using TypeID = serialization::TypeID; using DebugScopeID = DeclID; using DebugScopeIDField = DeclIDField; using LocationID = DeclID; using LocationIDField = DeclIDField; Serializer &S; llvm::BitstreamWriter &Out; /// A reusable buffer for emitting records. SmallVector ScratchRecord; /// In case we want to encode the relative of InstID vs ValueID. uint32_t /*ValueID*/ InstID = 0; llvm::DenseMap ValueIDs; ValueID addValueRef(const ValueBase *Val); public: using TableData = FuncTableInfo::data_type; using Table = llvm::MapVector; using StringMapTable = llvm::MapVector; private: /// FuncTable maps function name to an ID. Table FuncTable; std::vector Funcs; /// The current function ID. uint32_t /*DeclID*/ NextFuncID = 1; /// Maps class name to a VTable ID. Table VTableList; /// Holds the list of VTables. std::vector VTableOffset; uint32_t /*DeclID*/ NextVTableID = 1; /// Maps nominal type name to a MoveOnlyDeinit ID. Table MoveOnlyDeinitList; /// Holds the list of MoveOnlyDeinits. std::vector MoveOnlyDeinitOffset; uint32_t /*DeclID*/ NextMoveOnlyDeinitOffsetID = 1; /// Maps global variable name to an ID. Table GlobalVarList; /// Holds the list of SIL global variables. std::vector GlobalVarOffset; uint32_t /*DeclID*/ NextGlobalVarID = 1; /// Maps witness table identifier to an ID. Table WitnessTableList; /// Holds the list of WitnessTables. std::vector WitnessTableOffset; uint32_t /*DeclID*/ NextWitnessTableID = 1; /// Maps default witness table identifier to an ID. Table DefaultWitnessTableList; /// Holds the list of DefaultWitnessTables. std::vector DefaultWitnessTableOffset; uint32_t /*DeclID*/ NextDefaultWitnessTableID = 1; /// Maps default witness table identifier to an ID. Table DefaultOverrideTableList; /// Holds the list of DefaultOverrideTables. std::vector DefaultOverrideTableOffset; uint32_t /*DeclID*/ NextDefaultOverrideTableID = 1; /// Holds the list of Properties. std::vector PropertyOffset; /// Maps differentiability witness identifier to an ID. Table DifferentiabilityWitnessList; /// Holds the list of SIL differentiability witnesses. std::vector DifferentiabilityWitnessOffset; uint32_t /*DeclID*/ NextDifferentiabilityWitnessID = 1; /// Maps asmname of SIL functions and global variables to their SIL names, /// which will generally be mangled names. StringMapTable AsmNameTable; llvm::DenseMap, DeclID> DebugScopeMap; llvm::DenseMap SourceLocMap; /// Give each SILBasicBlock a unique ID. llvm::DenseMap BasicBlockMap; /// Functions that we've emitted a reference to. If the key maps /// to true, we want to emit a declaration only. llvm::DenseMap FuncsToEmit; bool OnlyReferencedByDebugInfo = false; llvm::DenseSet FuncsToEmitDebug; /// Global variables that we've emitted a reference to. llvm::DenseSet GlobalsToEmit; /// Referenced differentiability witnesses that need to be emitted. llvm::DenseSet DifferentiabilityWitnessesToEmit; /// Additional functions we might need to serialize. llvm::SmallVector functionWorklist; llvm::SmallVector globalWorklist; /// String storage for temporarily created strings which are referenced from /// the tables. llvm::BumpPtrAllocator StringTable; std::array SILAbbrCodes; template void registerSILAbbr() { using AbbrArrayTy = decltype(SILAbbrCodes); static_assert(Layout::Code <= std::tuple_size::value, "layout has invalid record code"); SILAbbrCodes[Layout::Code] = Layout::emitAbbrev(Out); LLVM_DEBUG(llvm::dbgs() << "SIL abbre code " << SILAbbrCodes[Layout::Code] << " for layout " << Layout::Code << "\n"); } const SerializationOptions &Options; void addMandatorySILFunction(const SILFunction *F, bool emitDeclarationsForOnoneSupport); void addReferencedSILFunction(const SILFunction *F, bool DeclOnly = false); void addReferencedGlobalVariable(const SILGlobalVariable *gl); void processWorklists(); /// Helper function to update ListOfValues for MethodInst. Format: /// Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand. void handleMethodInst(const MethodInst *MI, SILValue operand, SmallVectorImpl &ListOfValues); void writeSILFunction(const SILFunction &F, bool DeclOnly = false); void writeSILBasicBlock(const SILBasicBlock &BB); void writeSILInstruction(const SILInstruction &SI); void writeSILVTable(const SILVTable &vt); void writeSILMoveOnlyDeinit(const SILMoveOnlyDeinit &deinit); void writeSILGlobalVar(const SILGlobalVariable &g); void writeSILWitnessTable(const SILWitnessTable &wt); void writeSILWitnessTableEntry(const SILWitnessTable::Entry &entry, SerializedKind_t serializedKind); void writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt); void writeSILDefaultOverrideTableEntry( const SILDefaultOverrideTable::Entry &entry, SerializedKind_t serializedKind); void writeSILDefaultOverrideTable(const SILDefaultOverrideTable &ot); void writeSILDifferentiabilityWitness(const SILDifferentiabilityWitness &dw); void writeSILProperty(const SILProperty &prop); void writeSILBlock(const SILModule *SILMod); void writeIndexTables(); /// Write an extra-string record if the string itself is non-empty. void writeExtraStringIfNonEmpty(ExtraStringFlavor flavor, StringRef string); /// Serialize and write SILDebugScope graph in post order. void writeDebugScopes(const SILDebugScope *Scope, const SourceManager &SM); void writeSourceLoc(SILLocation SLoc, const SourceManager &SM); void writeNoOperandLayout(const SILInstruction *I) { unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)I->getKind()); } void writeConversionLikeInstruction(const SingleValueInstruction *I, unsigned attrs); void writeOneTypeLayout(SILInstructionKind valueKind, unsigned attrs, SILType type); void writeOneTypeLayout(SILInstructionKind valueKind, unsigned attrs, CanType type); void writeOneTypeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand); void writeOneTypeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, CanType type, SILValue operand); void writeOneTypeOneOperandExtraAttributeLayout( SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand); void writeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, SILValue operand); void writeOneOperandExtraAttributeLayout(SILInstructionKind valueKind, unsigned attrs, SILValue operand); void writeKeyPathPatternComponent( const KeyPathPatternComponent &component, SmallVectorImpl &ListOfValues); /// Helper function to determine if given the current state of the /// deserialization if the function body for F should be deserialized. bool shouldEmitFunctionBody(const SILFunction *F, bool isReference = true); IdentifierID addSILFunctionRef(SILFunction *F); public: SILSerializer(Serializer &S, llvm::BitstreamWriter &Out, const SerializationOptions &options) : S(S), Out(Out), Options(options) {} void writeSILModule(const SILModule *SILMod); }; } // end anonymous namespace void SILSerializer::addMandatorySILFunction(const SILFunction *F, bool emitDeclarationsForOnoneSupport) { // If this function is not fragile, don't do anything. if (!emitDeclarationsForOnoneSupport && !shouldEmitFunctionBody(F, /* isReference */ false)) return; auto iter = FuncsToEmit.find(F); if (iter != FuncsToEmit.end()) { // We've already visited this function. Make sure that we decided // to emit its body the first time around. assert(iter->second == emitDeclarationsForOnoneSupport && "Already emitting declaration"); return; } // We haven't seen this function before. Record that we want to // emit its body, and add it to the worklist. FuncsToEmit[F] = emitDeclarationsForOnoneSupport; // Function body should be serialized unless it is a KeepAsPublic function // (which is typically a pre-specialization). if (!emitDeclarationsForOnoneSupport) functionWorklist.push_back(F); } void SILSerializer::addReferencedSILFunction(const SILFunction *F, bool DeclOnly) { assert(F != nullptr); if (FuncsToEmit.count(F) > 0) return; // We haven't seen this function before. Let's see if we should // serialize the body or just the declaration. if (shouldEmitFunctionBody(F)) { FuncsToEmit[F] = false; functionWorklist.push_back(F); return; } if (F->getLinkage() == SILLinkage::Shared) { assert(F->isAnySerialized() || F->hasForeignBody()); FuncsToEmit[F] = false; functionWorklist.push_back(F); return; } // Ok, we just need to emit a declaration. FuncsToEmit[F] = true; } void SILSerializer::addReferencedGlobalVariable(const SILGlobalVariable *gl) { if (GlobalsToEmit.insert(gl).second) globalWorklist.push_back(gl); } void SILSerializer::processWorklists() { do { while (!functionWorklist.empty()) { const SILFunction *F = functionWorklist.pop_back_val(); assert(F != nullptr); assert(FuncsToEmit.count(F) > 0); writeSILFunction(*F, FuncsToEmit[F]); } while (!globalWorklist.empty()) { const SILGlobalVariable *gl = globalWorklist.pop_back_val(); assert(GlobalsToEmit.count(gl) > 0); writeSILGlobalVar(*gl); } } while (!functionWorklist.empty()); } /// We enumerate all values in a SILFunction beforehand to correctly /// handle forward references of values. ValueID SILSerializer::addValueRef(const ValueBase *Val) { if (!Val) return 0; if (auto *Undef = dyn_cast(Val)) { // The first two IDs are reserved for SILUndef. if (Undef->getOwnershipKind() == OwnershipKind::None) return 0; assert(Undef->getOwnershipKind() == OwnershipKind::Owned); return 1; } ValueID id = ValueIDs[Val]; assert(id != 0 && "We should have assigned a value ID to each value."); return id; } void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { PrettyStackTraceSILFunction stackTrace("Serializing", &F); ValueIDs.clear(); InstID = 0; FuncTable[F.getName()] = NextFuncID++; Funcs.push_back(Out.GetCurrentBitNo()); unsigned abbrCode = SILAbbrCodes[SILFunctionLayout::Code]; TypeID FnID = S.addTypeRef(F.getLoweredType().getRawASTType()); LLVM_DEBUG(llvm::dbgs() << "SILFunction " << F.getName() << " @ BitNo " << Out.GetCurrentBitNo() << " abbrCode " << abbrCode << " FnID " << FnID << "\n"); LLVM_DEBUG(llvm::dbgs() << "Serialized SIL:\n"; F.dump()); SmallVector SemanticsIDs; for (auto SemanticAttr : F.getSemanticsAttrs()) { SemanticsIDs.push_back(S.addUniquedStringRef(SemanticAttr)); } SILLinkage Linkage = F.getLinkage(); // Check if we need to emit a body for this function. bool NoBody = DeclOnly || isAvailableExternally(Linkage) || F.isExternalDeclaration(); // If we don't emit a function body then make sure to mark the declaration // as available externally. if (NoBody) { Linkage = addExternalToLinkage(Linkage); } assert(F.getCapturedEnvironments().empty() && "Captured local environments should not survive past SILGen"); // If we have a body, we might have a generic environment. GenericSignatureID genericSigID = 0; // Generic environment information is needed while serializing debug scopes. // Otherwise, the generic specializer fails to remap references to functions // in debug scopes to their specialized versions which breaks IRGen. // TODO: add an assertion in IRGen when the specializer fails to remap. if (!NoBody || Options.SerializeDebugInfoSIL) if (auto *genericEnv = F.getGenericEnvironment()) genericSigID = S.addGenericSignatureRef(genericEnv->getGenericSignature()); DeclID clangNodeOwnerID; if (F.hasClangNode()) clangNodeOwnerID = S.addDeclRef(F.getClangNodeOwner()); ModuleID parentModuleID; if (auto *parentModule = F.getParentModule()) parentModuleID = S.addModuleRef(parentModule); IdentifierID replacedFunctionID = 0; if (auto *fun = F.getDynamicallyReplacedFunction()) { addReferencedSILFunction(fun, true); replacedFunctionID = S.addUniquedStringRef(fun->getName()); } else if (F.hasObjCReplacement()) { replacedFunctionID = S.addUniquedStringRef(F.getObjCReplacement().str()); } IdentifierID usedAdHocWitnessFunctionID = 0; if (auto *fun = F.getReferencedAdHocRequirementWitnessFunction()) { addReferencedSILFunction(fun, true); usedAdHocWitnessFunctionID = S.addUniquedStringRef(fun->getName()); } unsigned numTrailingRecords = NoBody ? 0 : F.getSpecializeAttrs().size(); auto resilience = F.getModule().getSwiftModule()->getResilienceStrategy(); bool serializeDerivedEffects = // We must not serialize computed effects if library evolution is turned on, // because the copy of the function, which is emitted into the current module, // might have different effects in different versions of the library. (resilience != ResilienceStrategy::Resilient || // But we can serialize computed effects for @alwaysEmitIntoClient functions, // even when library evolution is enabled, because no copy of the function is // emitted in the original module. F.getLinkage() == SILLinkage::PublicNonABI) && !F.hasSemanticsAttr("optimize.no.crossmodule"); F.visitArgEffects( [&](int effectIdx, int argumentIndex, bool isDerived) { if (isDerived && !serializeDerivedEffects) return; numTrailingRecords++; }); std::optional available; auto availability = F.getAvailabilityForLinkage(); if (!availability.isAlwaysAvailable()) { available = availability.getRawMinimumVersion(); } ENCODE_VER_TUPLE(available, available) // Each extra string emitted below needs to update the trailing record // count here. if (!F.asmName().empty()) { ++numTrailingRecords; // Record asmname mapping. if (F.asmName() != F.getName()) { AsmNameTable[F.asmName()] = F.getName(); } } if (!F.section().empty()) ++numTrailingRecords; SILFunctionLayout::emitRecord( Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.getSerializedKind(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), (unsigned)F.getPerfConstraints(), (unsigned)F.getClassSubclassScope(), (unsigned)F.hasCReferences(), (unsigned)F.markedAsUsed(), (unsigned)F.getEffectsKind(), (unsigned)numTrailingRecords, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), (unsigned)F.isDistributed(), (unsigned)F.isRuntimeAccessible(), (unsigned)F.forceEnableLexicalLifetimes(), OnlyReferencedByDebugInfo, FnID, replacedFunctionID, usedAdHocWitnessFunctionID, genericSigID, clangNodeOwnerID, parentModuleID, SemanticsIDs); F.visitArgEffects( [&](int effectIdx, int argumentIndex, bool isDerived) { if (isDerived && !serializeDerivedEffects) return; llvm::SmallString<64> buffer; llvm::raw_svector_ostream OS(buffer); F.writeEffect(OS, effectIdx); IdentifierID effectsStrID = S.addUniquedStringRef(OS.str()); unsigned abbrCode = SILAbbrCodes[SILArgEffectsAttrLayout::Code]; bool isGlobalSideEffects = (argumentIndex < 0); unsigned argIdx = (isGlobalSideEffects ? 0 : (unsigned)argumentIndex); SILArgEffectsAttrLayout::emitRecord( Out, ScratchRecord, abbrCode, effectsStrID, argIdx, (unsigned)isGlobalSideEffects, (unsigned)isDerived); }); // Each extra string emitted here needs to be reflected in the trailing // record count above. writeExtraStringIfNonEmpty(ExtraStringFlavor::AsmName, F.asmName()); writeExtraStringIfNonEmpty(ExtraStringFlavor::Section, F.section()); if (NoBody) return; for (auto *SA : F.getSpecializeAttrs()) { unsigned specAttrAbbrCode = SILAbbrCodes[SILSpecializeAttrLayout::Code]; IdentifierID targetFunctionNameID = 0; if (auto *target = SA->getTargetFunction()) { addReferencedSILFunction(target, true); targetFunctionNameID = S.addUniquedStringRef(target->getName()); } IdentifierID spiGroupID = 0; IdentifierID spiModuleDeclID = 0; auto ident = SA->getSPIGroup(); if (!ident.empty()) { spiGroupID = S.addUniquedStringRef(ident.str()); spiModuleDeclID = S.addModuleRef(SA->getSPIModule()); } auto availability = SA->getAvailability(); if (!availability.isAlwaysAvailable()) { available = availability.getRawMinimumVersion(); } ENCODE_VER_TUPLE(available, available) llvm::SmallVector typeErasedParamsIDs; for (auto ty : SA->getTypeErasedParams()) { typeErasedParamsIDs.push_back(S.addTypeRef(ty)); } SILSpecializeAttrLayout::emitRecord( Out, ScratchRecord, specAttrAbbrCode, (unsigned)SA->isExported(), (unsigned)SA->getSpecializationKind(), S.addGenericSignatureRef(SA->getSpecializedSignature()), targetFunctionNameID, spiGroupID, spiModuleDeclID, LIST_VER_TUPLE_PIECES(available), typeErasedParamsIDs ); } DebugScopeMap.clear(); SourceLocMap.clear(); if (Options.SerializeDebugInfoSIL) writeDebugScopes(F.getDebugScope(), F.getModule().getSourceManager()); // Assign a unique ID to each basic block of the SILFunction. unsigned BasicID = 0; BasicBlockMap.clear(); // Assign a value ID to each SILInstruction that has value and to each basic // block argument. // // FIXME: Add reverse iteration to SILSuccessor and convert this to a "stable" // RPO order. Currently, the serializer inverts the order of successors each // time they are processed. // // The first valid value ID is 2. 0 and 1 are reserved for SILUndef. unsigned ValueID = 2; llvm::ReversePostOrderTraversal RPOT( const_cast(&F)); for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) { auto &BB = **Iter; BasicBlockMap.insert(std::make_pair(&BB, BasicID++)); for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I) ValueIDs[static_cast(*I)] = ValueID++; for (const SILInstruction &SI : BB) for (auto result : SI.getResults()) ValueIDs[result] = ValueID++; } // Write SIL basic blocks in the RPOT order // to make sure that instructions defining open archetypes // are serialized before instructions using those opened // archetypes. unsigned SerializedBBNum = 0; for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) { auto *BB = *Iter; writeSILBasicBlock(*BB); SerializedBBNum++; } assert(BasicID == SerializedBBNum && "Wrong number of BBs was serialized"); } void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) { SmallVector Args; for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I) { SILArgument *SA = *I; DeclID tId = S.addTypeRef(SA->getType().getRawASTType()); DeclID vId = addValueRef(static_cast(SA)); Args.push_back(tId); // We put these static asserts here to formalize our assumption that both // SILValueCategory and ValueOwnershipKind have uint8_t as their underlying // pointer values. static_assert( std::is_same< std::underlying_typegetType().getCategory())>::type, uint8_t>::value, "Expected an underlying uint8_t type"); // We put these static asserts here to formalize our assumption that both // SILValueCategory and ValueOwnershipKind have uint8_t as their underlying // pointer values. static_assert(std::is_samegetOwnershipKind())::innerty>::type, uint8_t>::value, "Expected an underlying uint8_t type"); // This is 31 bits in size. unsigned packedMetadata = 0; packedMetadata |= unsigned(SA->getType().getCategory()); // 8 bits packedMetadata |= unsigned(SA->getOwnershipKind()) << 8; // 3 bits packedMetadata |= unsigned(SA->isReborrow()) << 11; // 1 bit packedMetadata |= unsigned(SA->hasPointerEscape()) << 12; // 1 bit if (auto *SFA = dyn_cast(SA)) { packedMetadata |= unsigned(SFA->isNoImplicitCopy()) << 13; // 1 bit packedMetadata |= unsigned(SFA->getLifetimeAnnotation()) << 14; // 2 bits packedMetadata |= unsigned(SFA->isClosureCapture()) << 16; // 1 bit packedMetadata |= unsigned(SFA->isFormalParameterPack()) << 17; // 1 bit } // Used: 17 bits. Free: 15. // // TODO: We should be able to shrink the packed metadata of the first two. Args.push_back(packedMetadata); Args.push_back(vId); } unsigned abbrCode = SILAbbrCodes[SILBasicBlockLayout::Code]; SILBasicBlockLayout::emitRecord(Out, ScratchRecord, abbrCode, Args); const SILDebugScope *Prev = nullptr; auto &SM = BB.getParent()->getModule().getSourceManager(); for (const SILInstruction &SI : BB) { if (Options.SerializeDebugInfoSIL) { if (SI.getDebugScope() != Prev) { Prev = SI.getDebugScope(); writeDebugScopes(Prev, SM); } } if (Options.SerializeDebugInfoSIL) { writeSourceLoc(SI.getLoc(), SM); } writeSILInstruction(SI); } } /// Add SILDeclRef to ListOfValues, so we can reconstruct it at /// deserialization. static void handleSILDeclRef(Serializer &S, const SILDeclRef &Ref, SmallVectorImpl &ListOfValues) { ListOfValues.push_back(S.addDeclRef(Ref.getDecl())); ListOfValues.push_back((unsigned)Ref.kind); ListOfValues.push_back(Ref.isForeign); } /// Get an identifier ref for a SILFunction and add it to the list of referenced /// functions. IdentifierID SILSerializer::addSILFunctionRef(SILFunction *F) { addReferencedSILFunction(F); return S.addUniquedStringRef(F->getName()); } /// Helper function to update ListOfValues for MethodInst. Format: /// Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand. void SILSerializer::handleMethodInst(const MethodInst *MI, SILValue operand, SmallVectorImpl &ListOfValues) { handleSILDeclRef(S, MI->getMember(), ListOfValues); ListOfValues.push_back( S.addTypeRef(operand->getType().getRawASTType())); ListOfValues.push_back((unsigned)operand->getType().getCategory()); ListOfValues.push_back(addValueRef(operand)); } void SILSerializer::writeOneTypeLayout(SILInstructionKind valueKind, unsigned attrs, SILType type) { unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned) valueKind, attrs, S.addTypeRef(type.getRawASTType()), (unsigned)type.getCategory()); } void SILSerializer::writeOneTypeLayout(SILInstructionKind valueKind, unsigned attrs, CanType type) { unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned) valueKind, attrs, S.addTypeRef(type), 0); } void SILSerializer::writeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, SILValue operand) { auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], unsigned(valueKind), attrs, operandTypeRef, unsigned(operandType.getCategory()), operandRef); } void SILSerializer:: writeOneOperandExtraAttributeLayout(SILInstructionKind valueKind, unsigned attrs, SILValue operand) { auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneOperandExtraAttributeLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneOperandExtraAttributeLayout::Code], unsigned(valueKind), attrs, operandTypeRef, unsigned(operandType.getCategory()), operandRef); } void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand) { auto typeRef = S.addTypeRef(type.getRawASTType()); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], unsigned(valueKind), attrs, typeRef, unsigned(type.getCategory()), operandTypeRef, unsigned(operandType.getCategory()), operandRef); } void SILSerializer::writeOneTypeOneOperandLayout(SILInstructionKind valueKind, unsigned attrs, CanType type, SILValue operand) { auto typeRef = S.addTypeRef(type); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], unsigned(valueKind), attrs, typeRef, 0, operandTypeRef, unsigned(operandType.getCategory()), operandRef); } void SILSerializer:: writeOneTypeOneOperandExtraAttributeLayout(SILInstructionKind valueKind, unsigned attrs, SILType type, SILValue operand) { auto typeRef = S.addTypeRef(type.getRawASTType()); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandExtraAttributeLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandExtraAttributeLayout::Code], unsigned(valueKind), attrs, typeRef, unsigned(type.getCategory()), operandTypeRef, unsigned(operandType.getCategory()), operandRef); } /// Write an instruction that looks exactly like a conversion: all /// important information is encoded in the operand and the result type. void SILSerializer::writeConversionLikeInstruction( const SingleValueInstruction *I, unsigned attrs) { assert(I->getNumOperands() - I->getTypeDependentOperands().size() == 1); writeOneTypeOneOperandLayout(I->getKind(), attrs, I->getType(), I->getOperand(0)); } void SILSerializer::writeKeyPathPatternComponent( const KeyPathPatternComponent &component, SmallVectorImpl &ListOfValues) { auto handleComponentCommon = [&](KeyPathComponentKindEncoding kind) { ListOfValues.push_back((unsigned)kind); ListOfValues.push_back(S.addTypeRef(component.getComponentType())); }; auto handleComputedId = [&](KeyPathPatternComponent::ComputedPropertyId id) { switch (id.getKind()) { case KeyPathPatternComponent::ComputedPropertyId::Property: ListOfValues.push_back( (unsigned)KeyPathComputedComponentIdKindEncoding::Property); ListOfValues.push_back(S.addDeclRef(id.getProperty())); break; case KeyPathPatternComponent::ComputedPropertyId::Function: ListOfValues.push_back( (unsigned)KeyPathComputedComponentIdKindEncoding::Function); ListOfValues.push_back(addSILFunctionRef(id.getFunction())); break; case KeyPathPatternComponent::ComputedPropertyId::DeclRef: ListOfValues.push_back( (unsigned)KeyPathComputedComponentIdKindEncoding::DeclRef); handleSILDeclRef(S, id.getDeclRef(), ListOfValues); break; } }; auto handleComputedExternalReferenceAndIndices = [&](const KeyPathPatternComponent &component) { ListOfValues.push_back(S.addDeclRef(component.getExternalDecl())); ListOfValues.push_back( S.addSubstitutionMapRef(component.getExternalSubstitutions())); auto indices = component.getArguments(); ListOfValues.push_back(indices.size()); for (auto &index : indices) { ListOfValues.push_back(index.Operand); ListOfValues.push_back(S.addTypeRef(index.FormalType)); ListOfValues.push_back( S.addTypeRef(index.LoweredType.getRawASTType())); ListOfValues.push_back((unsigned)index.LoweredType.getCategory()); ListOfValues.push_back(S.addConformanceRef(index.Hashable)); } if (!indices.empty()) { ListOfValues.push_back(addSILFunctionRef(component.getIndexEquals())); ListOfValues.push_back(addSILFunctionRef(component.getIndexHash())); } }; switch (component.getKind()) { case KeyPathPatternComponent::Kind::Method: printf("SerializeSIL:writeKeyPathPatternComponent"); break; case KeyPathPatternComponent::Kind::StoredProperty: handleComponentCommon(KeyPathComponentKindEncoding::StoredProperty); ListOfValues.push_back(S.addDeclRef(component.getStoredPropertyDecl())); break; case KeyPathPatternComponent::Kind::GettableProperty: handleComponentCommon(KeyPathComponentKindEncoding::GettableProperty); handleComputedId(component.getComputedPropertyId()); ListOfValues.push_back( addSILFunctionRef(component.getComputedPropertyForGettable())); handleComputedExternalReferenceAndIndices(component); break; case KeyPathPatternComponent::Kind::SettableProperty: handleComponentCommon(KeyPathComponentKindEncoding::SettableProperty); handleComputedId(component.getComputedPropertyId()); ListOfValues.push_back( addSILFunctionRef(component.getComputedPropertyForGettable())); ListOfValues.push_back( addSILFunctionRef(component.getComputedPropertyForSettable())); handleComputedExternalReferenceAndIndices(component); break; case KeyPathPatternComponent::Kind::OptionalChain: handleComponentCommon(KeyPathComponentKindEncoding::OptionalChain); break; case KeyPathPatternComponent::Kind::OptionalForce: handleComponentCommon(KeyPathComponentKindEncoding::OptionalForce); break; case KeyPathPatternComponent::Kind::OptionalWrap: handleComponentCommon(KeyPathComponentKindEncoding::OptionalWrap); break; case KeyPathPatternComponent::Kind::TupleElement: handleComponentCommon(KeyPathComponentKindEncoding::TupleElement); ListOfValues.push_back((unsigned)component.getTupleIndex()); break; } } void SILSerializer::writeSILInstruction(const SILInstruction &SI) { PrettyStackTraceSILNode stackTrace("Serializing", &SI); switch (SI.getKind()) { case SILInstructionKind::ObjectInst: { const ObjectInst *OI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; SmallVector Args; Args.push_back((unsigned)OI->getBaseElements().size()); for (const Operand &op : OI->getAllOperands()) { SILValue OpVal = op.get(); Args.push_back(addValueRef(OpVal)); SILType OpType = OpVal->getType(); assert(OpType.isObject()); Args.push_back(S.addTypeRef(OpType.getRawASTType())); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(OI->getType().getRawASTType()), (unsigned)OI->getType().getCategory(), Args); break; } case SILInstructionKind::VectorInst: { auto *vi = cast(&SI); SmallVector ListOfValues; for (auto Elt : vi->getElements()) { ListOfValues.push_back(addValueRef(Elt)); } unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(vi->getType().getRawASTType()), (unsigned)vi->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::DebugValueInst: { if (!Options.SerializeDebugInfoSIL) return; auto DVI = cast(&SI); unsigned attrs = unsigned(DVI->poisonRefs() & 0x1); attrs |= unsigned(DVI->usesMoveableValueDebugInfo()) << 1; attrs |= unsigned(DVI->hasTrace()) << 2; auto Operand = DVI->getOperand(); auto Type = Operand->getType(); unsigned DebugVarTypeCategory = 0; auto DebugVar = DVI->getVarInfo(); const SILDebugScope *ScopeToWrite = nullptr; auto &SM = SI.getFunction()->getModule().getSourceManager(); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(Operand)); ListOfValues.push_back(S.addTypeRef(Type.getRawASTType())); if (DebugVar) { // Is a DebugVariable being serialized. attrs |= 1 << 3; attrs |= DebugVar->isLet() << 4; // isDenseMapSingleton needs two bits. attrs |= DebugVar->isDenseMapSingleton << 5; ListOfValues.push_back(S.addUniquedStringRef(DebugVar->Name)); ListOfValues.push_back(DebugVar->ArgNo); if (DebugVar->Type.has_value()) { attrs |= 1 << 7; ListOfValues.push_back(S.addTypeRef(DebugVar->Type->getRawASTType())); DebugVarTypeCategory = (unsigned)DebugVar->Type->getCategory(); } if (DebugVar->Scope) { attrs |= 1 << 8; ScopeToWrite = DebugVar->Scope; } if (DebugVar->Loc) { auto RawLoc = DebugVar->Loc.value(); SourceLoc Loc = RawLoc.getSourceLoc(); if (Loc.isValid()) { attrs |= 1 << 9; auto LC = SM.getPresumedLineAndColumnForLoc(Loc); auto FName = SM.getDisplayNameForLoc(Loc); auto FNameID = S.addUniquedStringRef(FName); ListOfValues.push_back(LC.first); ListOfValues.push_back(LC.second); ListOfValues.push_back(FNameID); } else if (RawLoc.isFilenameAndLocation()) { // getSourceLoc produces an empty SourceLoc for FilenameAndLocation, // so this needs to be handled separately. rdar://25225083. attrs |= 1 << 9; auto FNameLoc = RawLoc.getFilenameAndLocation(); ListOfValues.push_back(FNameLoc->line); ListOfValues.push_back(FNameLoc->column); ListOfValues.push_back(S.addUniquedStringRef(FNameLoc->filename)); } } for (auto &Expr : DebugVar->DIExpr.elements()) { attrs |= 1 << 10; ListOfValues.push_back(Expr.getKind()); switch (Expr.getKind()) { case SILDIExprElement::Kind::OperatorKind: ListOfValues.push_back((unsigned)Expr.getAsOperator()); break; case SILDIExprElement::Kind::DeclKind: ListOfValues.push_back(S.addDeclRef(Expr.getAsDecl())); break; case SILDIExprElement::Kind::ConstIntKind: { llvm::SmallString<10> Str; APInt(64, Expr.getAsConstInt().value()).toStringUnsigned(Str); ListOfValues.push_back(S.addUniquedStringRef(Str)); break; } case SILDIExprElement::Kind::TypeKind: ListOfValues.push_back(S.addTypeRef(Expr.getAsType())); } } } SILDebugValueLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILDebugValueLayout::Code], (unsigned)Type.getCategory(), DebugVarTypeCategory, attrs, ListOfValues); if (ScopeToWrite) { assert(DebugVar->Scope->getInlinedFunction() == DVI->getDebugScope()->getInlinedFunction()); writeDebugScopes(ScopeToWrite, SM); // Add a delimiter record since debug scope records are read by the // deserializer in a loop until the first non debug scope record is // found. As a result, the deserializer might read debug scopes of // subsequent instructions while deserializing scopes for the current // DebugValue instruction. // TODO: Maybe add a bit to the debug scope layout to mark the ending. DebugValueDelimiterLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[DebugValueDelimiterLayout::Code]); } break; } case SILInstructionKind::DebugStepInst: // Currently we don't serialize debug info, so it doesn't make // sense to write those instructions at all. // TODO: decide if we want to serialize those instructions. return; case SILInstructionKind::SpecifyTestInst: // Instruction exists only for tests. Ignore it. return; case SILInstructionKind::AllocPackMetadataInst: case SILInstructionKind::DeallocPackMetadataInst: // Shoulud never be serialized: only introduced in an IRGen pass // (PackMetadataMarkerInserter). return; case SILInstructionKind::UnwindInst: case SILInstructionKind::ThrowAddrInst: case SILInstructionKind::UnreachableInst: { writeNoOperandLayout(&SI); break; } case SILInstructionKind::AllocExistentialBoxInst: case SILInstructionKind::InitExistentialAddrInst: case SILInstructionKind::InitExistentialValueInst: case SILInstructionKind::InitExistentialMetatypeInst: case SILInstructionKind::InitExistentialRefInst: { SILValue operand; SILType Ty; CanType FormalConcreteType; ArrayRef conformances; switch (SI.getKind()) { default: llvm_unreachable("out of sync with parent"); case SILInstructionKind::InitExistentialAddrInst: { auto &IEI = cast(SI); operand = IEI.getOperand(); Ty = IEI.getLoweredConcreteType(); FormalConcreteType = IEI.getFormalConcreteType(); conformances = IEI.getConformances(); break; } case SILInstructionKind::InitExistentialValueInst: { auto &IEOI = cast(SI); operand = IEOI.getOperand(); Ty = IEOI.getType(); FormalConcreteType = IEOI.getFormalConcreteType(); conformances = IEOI.getConformances(); break; } case SILInstructionKind::InitExistentialRefInst: { auto &IERI = cast(SI); operand = IERI.getOperand(); Ty = IERI.getType(); FormalConcreteType = IERI.getFormalConcreteType(); conformances = IERI.getConformances(); break; } case SILInstructionKind::InitExistentialMetatypeInst: { auto &IEMI = cast(SI); operand = IEMI.getOperand(); Ty = IEMI.getType(); conformances = IEMI.getConformances(); break; } case SILInstructionKind::AllocExistentialBoxInst: { auto &AEBI = cast(SI); Ty = AEBI.getExistentialType(); FormalConcreteType = AEBI.getFormalConcreteType(); conformances = AEBI.getConformances(); break; } } TypeID operandType = 0; SILValueCategory operandCategory = SILValueCategory::Object; ValueID operandID = 0; if (operand) { operandType = S.addTypeRef(operand->getType().getRawASTType()); operandCategory = operand->getType().getCategory(); operandID = addValueRef(operand); } TypeID formalConcreteTypeID = S.addTypeRef(FormalConcreteType); auto conformanceIDs = S.addConformanceRefs(conformances); unsigned abbrCode = SILAbbrCodes[SILInitExistentialLayout::Code]; SILInitExistentialLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), operandType, (unsigned)operandCategory, operandID, formalConcreteTypeID, conformanceIDs); break; } case SILInstructionKind::DeallocBoxInst: { auto DBI = cast(&SI); unsigned Attr = unsigned(DBI->isDeadEnd()); writeOneTypeOneOperandLayout( DBI->getKind(), Attr, DBI->getOperand()->getType(), DBI->getOperand()); break; } case SILInstructionKind::DeallocExistentialBoxInst: { auto DBI = cast(&SI); writeOneTypeOneOperandLayout(DBI->getKind(), 0, DBI->getConcreteType(), DBI->getOperand()); break; } case SILInstructionKind::ValueMetatypeInst: { auto VMI = cast(&SI); writeOneTypeOneOperandLayout(VMI->getKind(), 0, VMI->getType(), VMI->getOperand()); break; } case SILInstructionKind::ExistentialMetatypeInst: { auto EMI = cast(&SI); writeOneTypeOneOperandLayout(EMI->getKind(), 0, EMI->getType(), EMI->getOperand()); break; } case SILInstructionKind::AllocBoxInst: { const AllocBoxInst *ABI = cast(&SI); unsigned flags = 0; flags |= unsigned(ABI->hasDynamicLifetime()); flags |= unsigned(ABI->emitReflectionMetadata()) << 1; flags |= unsigned(ABI->usesMoveableValueDebugInfo()) << 2; flags |= unsigned(ABI->hasPointerEscape()) << 3; writeOneTypeLayout(ABI->getKind(), flags, ABI->getType()); break; } case SILInstructionKind::AllocRefInst: case SILInstructionKind::AllocRefDynamicInst: { const AllocRefInstBase *ARI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; SmallVector Args; bool isBare = false; if (auto *ar = dyn_cast(&SI)) isBare = ar->isBare(); Args.push_back((unsigned)ARI->isObjC() | ((unsigned)ARI->canAllocOnStack() << 1) | ((unsigned)isBare << 2)); ArrayRef TailTypes = ARI->getTailAllocatedTypes(); ArrayRef AllOps = ARI->getAllOperands(); unsigned NumTailAllocs = TailTypes.size(); unsigned NumOpsToWrite = NumTailAllocs; if (SI.getKind() == SILInstructionKind::AllocRefDynamicInst) ++NumOpsToWrite; for (unsigned Idx = 0; Idx < NumOpsToWrite; ++Idx) { if (Idx < NumTailAllocs) { assert(TailTypes[Idx].isObject()); Args.push_back(S.addTypeRef(TailTypes[Idx].getRawASTType())); } SILValue OpVal = AllOps[Idx].get(); Args.push_back(addValueRef(OpVal)); SILType OpType = OpVal->getType(); assert(OpType.isObject()); Args.push_back(S.addTypeRef(OpType.getRawASTType())); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(ARI->getType().getRawASTType()), (unsigned)ARI->getType().getCategory(), Args); break; } case SILInstructionKind::AllocStackInst: { const AllocStackInst *ASI = cast(&SI); unsigned attr = 0; attr |= unsigned(ASI->hasDynamicLifetime()); attr |= unsigned(ASI->isLexical()) << 1; attr |= unsigned(ASI->isFromVarDecl()) << 2; attr |= unsigned(ASI->usesMoveableValueDebugInfo()) << 3; attr |= unsigned(ASI->isStackAllocationNested()) << 4; writeOneTypeLayout(ASI->getKind(), attr, ASI->getElementType()); break; } case SILInstructionKind::AllocPackInst: { const AllocPackInst *API = cast(&SI); writeOneTypeLayout(API->getKind(), 0, API->getPackType()); break; } case SILInstructionKind::PackLengthInst: { const PackLengthInst *PLI = cast(&SI); writeOneTypeLayout(PLI->getKind(), 0, PLI->getPackType()); break; } case SILInstructionKind::ProjectBoxInst: { auto PBI = cast(&SI); // Use SILOneTypeOneOperandLayout with the field index crammed in the TypeID auto boxOperand = PBI->getOperand(); auto boxRef = addValueRef(boxOperand); auto boxType = boxOperand->getType(); auto boxTypeRef = S.addTypeRef(boxType.getRawASTType()); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], unsigned(PBI->getKind()), 0, PBI->getFieldIndex(), 0, boxTypeRef, unsigned(boxType.getCategory()), boxRef); break; } case SILInstructionKind::ProjectExistentialBoxInst: { auto PEBI = cast(&SI); writeOneTypeOneOperandLayout(PEBI->getKind(), 0, PEBI->getType(), PEBI->getOperand()); break; } case SILInstructionKind::BuiltinInst: { // Format: substitutions map ID, the builtin name, result type, and // a list of values for the arguments. Each value in the list // is represented with 4 IDs: // ValueID, ValueResultNumber, TypeID, TypeCategory. // The record is followed by the substitution list. const BuiltinInst *BI = cast(&SI); SmallVector Args; for (auto Arg : BI->getArguments()) { Args.push_back(addValueRef(Arg)); Args.push_back(S.addTypeRef(Arg->getType().getRawASTType())); Args.push_back((unsigned)Arg->getType().getCategory()); } SILInstApplyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_BUILTIN, 0, S.addSubstitutionMapRef(BI->getSubstitutions()), S.addTypeRef(BI->getType().getRawASTType()), (unsigned)BI->getType().getCategory(), S.addDeclBaseNameRef(BI->getName()), unsigned(swift::ActorIsolation::Unspecified), unsigned(swift::ActorIsolation::Unspecified), Args); break; } case SILInstructionKind::ApplyInst: { // Format: attributes such as transparent and number of substitutions, // the callee's substituted and unsubstituted types, a value for // the callee and a list of values for the arguments. Each value in the list // is represented with 2 IDs: ValueID and ValueResultNumber. The record // is followed by the substitution list. const ApplyInst *AI = cast(&SI); SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); } auto callerIsolation = swift::ActorIsolation::Unspecified; auto calleeIsolation = swift::ActorIsolation::Unspecified; if (auto isolationCrossing = AI->getIsolationCrossing()) { callerIsolation = isolationCrossing->getCallerIsolation(); calleeIsolation = isolationCrossing->getCalleeIsolation(); } SILInstApplyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), unsigned(callerIsolation), unsigned(calleeIsolation), Args); break; } case SILInstructionKind::BeginApplyInst: { // Format: attributes such as transparent and number of substitutions, // the callee's substituted and unsubstituted types, a value for // the callee and a list of values for the arguments. Each value in the list // is represented with 2 IDs: ValueID and ValueResultNumber. The record // is followed by the substitution list. const BeginApplyInst *AI = cast(&SI); SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); } auto callerIsolation = swift::ActorIsolation::Unspecified; auto calleeIsolation = swift::ActorIsolation::Unspecified; if (auto isolationCrossing = AI->getIsolationCrossing()) { callerIsolation = isolationCrossing->getCallerIsolation(); calleeIsolation = isolationCrossing->getCalleeIsolation(); } SILInstApplyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_BEGIN_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), unsigned(callerIsolation), unsigned(calleeIsolation), Args); break; } case SILInstructionKind::TryApplyInst: { // Format: attributes such as transparent and number of substitutions, // the callee's substituted and unsubstituted types, a value for // the callee and a list of values for the arguments. Each value in the list // is represented with 2 IDs: ValueID and ValueResultNumber. The final two // entries in the list are the basic block destinations. The record // is followed by the substitution list. const TryApplyInst *AI = cast(&SI); SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); } Args.push_back(BasicBlockMap[AI->getNormalBB()]); Args.push_back(BasicBlockMap[AI->getErrorBB()]); auto callerIsolation = swift::ActorIsolation::Unspecified; auto calleeIsolation = swift::ActorIsolation::Unspecified; if (auto isolationCrossing = AI->getIsolationCrossing()) { callerIsolation = isolationCrossing->getCallerIsolation(); calleeIsolation = isolationCrossing->getCalleeIsolation(); } SILInstApplyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_TRY_APPLY, unsigned(AI->getApplyOptions().toRaw()), S.addSubstitutionMapRef(AI->getSubstitutionMap()), S.addTypeRef(AI->getCallee()->getType().getRawASTType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), unsigned(callerIsolation), unsigned(calleeIsolation), Args); break; } case SILInstructionKind::PartialApplyInst: { const PartialApplyInst *PAI = cast(&SI); SmallVector Args; for (auto Arg: PAI->getArguments()) { Args.push_back(addValueRef(Arg)); } SILInstApplyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_PARTIAL_APPLY, 0, S.addSubstitutionMapRef(PAI->getSubstitutionMap()), S.addTypeRef(PAI->getCallee()->getType().getRawASTType()), S.addTypeRef(PAI->getType().getRawASTType()), addValueRef(PAI->getCallee()), unsigned(swift::ActorIsolation::Unspecified), unsigned(swift::ActorIsolation::Unspecified), Args); break; } case SILInstructionKind::AllocGlobalInst: { // Format: Name and type. Use SILOneOperandLayout. const AllocGlobalInst *AGI = cast(&SI); auto *G = AGI->getReferencedGlobal(); addReferencedGlobalVariable(G); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, 0, 0, S.addUniquedStringRef(G->getName())); break; } case SILInstructionKind::GlobalValueInst: { // Format: Name and type. Use SILOneOperandLayout. auto *gv = cast(&SI); auto *G = gv->getReferencedGlobal(); addReferencedGlobalVariable(G); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), gv->isBare() ? 1 : 0, S.addTypeRef(gv->getType().getRawASTType()), (unsigned)gv->getType().getCategory(), S.addUniquedStringRef(G->getName())); break; } case SILInstructionKind::GlobalAddrInst: { // Format: Name and type. Use SILOneOperandLayout. auto *ga = cast(&SI); auto *G = ga->getReferencedGlobal(); addReferencedGlobalVariable(G); SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneValueOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addUniquedStringRef(G->getName()), S.addTypeRef(ga->getType().getRawASTType()), (unsigned)ga->getType().getCategory(), addValueRef(ga->getDependencyToken())); break; } case SILInstructionKind::BaseAddrForOffsetInst: { const BaseAddrForOffsetInst *BAI = cast(&SI); writeOneTypeLayout(BAI->getKind(), /*attrs*/ 0, BAI->getType()); break; } case SILInstructionKind::BranchInst: { // Format: destination basic block ID, a list of arguments. Use // SILOneTypeValuesLayout. const BranchInst *BrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : BrI->getArgs()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), BasicBlockMap[BrI->getDestBB()], 0, ListOfValues); break; } case SILInstructionKind::CondBranchInst: { // Format: condition, true basic block ID, a list of arguments, false basic // block ID, a list of arguments. Use SILOneTypeValuesLayout: the type is // for condition, the list has value for condition, true basic block ID, // false basic block ID, number of true arguments, and a list of true|false // arguments. const CondBranchInst *CBI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(CBI->getCondition())); ListOfValues.push_back(BasicBlockMap[CBI->getTrueBB()]); ListOfValues.push_back(BasicBlockMap[CBI->getFalseBB()]); ListOfValues.push_back(CBI->getTrueArgs().size()); for (auto Elt : CBI->getTrueArgs()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } for (auto Elt : CBI->getFalseArgs()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CBI->getCondition()->getType().getRawASTType()), (unsigned)CBI->getCondition()->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::AwaitAsyncContinuationInst: { const AwaitAsyncContinuationInst *AACI = cast(&SI); // Format: continuation, resume block ID, error block ID if given SmallVector ListOfValues; ListOfValues.push_back(addValueRef(AACI->getOperand())); ListOfValues.push_back(BasicBlockMap[AACI->getResumeBB()]); if (auto errorBB = AACI->getErrorBB()) { ListOfValues.push_back(BasicBlockMap[errorBB]); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(AACI->getOperand()->getType().getRawASTType()), (unsigned)AACI->getOperand()->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::SwitchEnumInst: case SILInstructionKind::SwitchEnumAddrInst: { // Format: // - [ownership] // - the type of the condition operand, // - a list a values: operand, hasDefault, defaultBB, // [EnumElementDecl, Basic Block ID]* SwitchEnumTermInst SOI(&SI); assert(SOI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SOI.getOperand())); ListOfValues.push_back((unsigned)SOI.hasDefault()); if (SOI.hasDefault()) ListOfValues.push_back(BasicBlockMap[SOI.getDefaultBB()]); else ListOfValues.push_back(0); for (unsigned i = 0, e = SOI.getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILBasicBlock *dest; std::tie(elt, dest) = SOI.getCase(i); ListOfValues.push_back(S.addDeclRef(elt)); ListOfValues.push_back(BasicBlockMap[dest]); } if (auto *switchEnum = dyn_cast(&SI)) { unsigned ownershipField = encodeValueOwnership(switchEnum->getForwardingOwnershipKind()); SILOneTypeOwnershipValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeOwnershipValuesLayout::Code], (unsigned)SI.getKind(), ownershipField, S.addTypeRef(SOI.getOperand()->getType().getRawASTType()), (unsigned)SOI.getOperand()->getType().getCategory(), ListOfValues); } else { SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SOI.getOperand()->getType().getRawASTType()), (unsigned)SOI.getOperand()->getType().getCategory(), ListOfValues); } break; } case SILInstructionKind::SelectEnumInst: case SILInstructionKind::SelectEnumAddrInst: { // Format: condition, a list of cases (EnumElementDecl + Value ID), // default value ID. Use SILOneTypeValuesLayout: the type is // for condition, the list has value for condition, result type, // hasDefault, default // basic block ID, a list of (DeclID, BasicBlock ID). auto SEO = SelectEnumOperation(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SEO.getEnumOperand())); ListOfValues.push_back(S.addTypeRef(SEO->getType().getRawASTType())); ListOfValues.push_back((unsigned)SEO->getType().getCategory()); ListOfValues.push_back((unsigned)SEO.hasDefault()); if (SEO.hasDefault()) { ListOfValues.push_back(addValueRef(SEO.getDefaultResult())); } else { ListOfValues.push_back(0); } for (unsigned i = 0, e = SEO.getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILValue result; std::tie(elt, result) = SEO.getCase(i); ListOfValues.push_back(S.addDeclRef(elt)); ListOfValues.push_back(addValueRef(result)); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SEO.getEnumOperand()->getType().getRawASTType()), (unsigned)SEO.getEnumOperand()->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::SwitchValueInst: { // Format: condition, a list of cases (Value ID + Basic Block ID), // default basic block ID. Use SILOneTypeValuesLayout: the type is // for condition, the list contains value for condition, hasDefault, default // basic block ID, a list of (Value ID, BasicBlock ID). const SwitchValueInst *SII = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SII->getOperand())); ListOfValues.push_back((unsigned)SII->hasDefault()); if (SII->hasDefault()) ListOfValues.push_back(BasicBlockMap[SII->getDefaultBB()]); else ListOfValues.push_back(0); for (unsigned i = 0, e = SII->getNumCases(); i < e; ++i) { SILValue value; SILBasicBlock *dest; std::tie(value, dest) = SII->getCase(i); ListOfValues.push_back(addValueRef(value)); ListOfValues.push_back(BasicBlockMap[dest]); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SII->getOperand()->getType().getRawASTType()), (unsigned)SII->getOperand()->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::UnownedCopyValueInst: case SILInstructionKind::WeakCopyValueInst: #define UNCHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::StrongCopy##Name##ValueInst: \ case SILInstructionKind::Load##Name##Inst: #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Name##RetainInst: \ case SILInstructionKind::Name##ReleaseInst: \ case SILInstructionKind::StrongRetain##Name##Inst: \ case SILInstructionKind::StrongCopy##Name##ValueInst: #define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Load##Name##Inst: \ case SILInstructionKind::Name##RetainInst: \ case SILInstructionKind::Name##ReleaseInst: \ case SILInstructionKind::StrongRetain##Name##Inst: \ case SILInstructionKind::StrongCopy##Name##ValueInst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::RetainValueInst: case SILInstructionKind::DestructureStructInst: case SILInstructionKind::DestructureTupleInst: case SILInstructionKind::RetainValueAddrInst: case SILInstructionKind::UnmanagedRetainValueInst: case SILInstructionKind::EndBorrowInst: case SILInstructionKind::CopyValueInst: case SILInstructionKind::ExplicitCopyValueInst: case SILInstructionKind::MoveValueInst: case SILInstructionKind::DropDeinitInst: case SILInstructionKind::MarkUnresolvedReferenceBindingInst: case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: case SILInstructionKind::DestroyValueInst: case SILInstructionKind::ReleaseValueInst: case SILInstructionKind::ReleaseValueAddrInst: case SILInstructionKind::UnmanagedReleaseValueInst: case SILInstructionKind::AutoreleaseValueInst: case SILInstructionKind::UnmanagedAutoreleaseValueInst: case SILInstructionKind::DeallocStackInst: case SILInstructionKind::DeallocStackRefInst: case SILInstructionKind::DeallocPackInst: case SILInstructionKind::DeallocRefInst: case SILInstructionKind::DeinitExistentialAddrInst: case SILInstructionKind::DeinitExistentialValueInst: case SILInstructionKind::DestroyAddrInst: case SILInstructionKind::LoadInst: case SILInstructionKind::LoadBorrowInst: case SILInstructionKind::BeginBorrowInst: case SILInstructionKind::ClassifyBridgeObjectInst: case SILInstructionKind::ValueToBridgeObjectInst: case SILInstructionKind::FixLifetimeInst: case SILInstructionKind::EndLifetimeInst: case SILInstructionKind::ExtendLifetimeInst: case SILInstructionKind::CopyBlockInst: case SILInstructionKind::StrongReleaseInst: case SILInstructionKind::StrongRetainInst: case SILInstructionKind::IsUniqueInst: case SILInstructionKind::BeginCOWMutationInst: case SILInstructionKind::EndCOWMutationInst: case SILInstructionKind::EndCOWMutationAddrInst: case SILInstructionKind::EndInitLetRefInst: case SILInstructionKind::HopToExecutorInst: case SILInstructionKind::ExtractExecutorInst: case SILInstructionKind::FunctionExtractIsolationInst: case SILInstructionKind::AbortApplyInst: case SILInstructionKind::ReturnInst: case SILInstructionKind::UncheckedOwnershipConversionInst: case SILInstructionKind::DestroyNotEscapedClosureInst: case SILInstructionKind::ThrowInst: { unsigned Attr = 0; if (auto *LI = dyn_cast(&SI)) Attr = unsigned(LI->getOwnershipQualifier()); #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ else if (auto *LI = dyn_cast(&SI)) \ Attr = LI->isTake(); #include "swift/AST/ReferenceStorage.def" else if (auto *RCI = dyn_cast(&SI)) Attr = RCI->isNonAtomic(); else if (auto *UOCI = dyn_cast(&SI)) { Attr = encodeValueOwnership(UOCI->getOwnershipKind()); } else if (auto *IEC = dyn_cast(&SI)) { Attr = IEC->getVerificationType(); } else if (auto *HTE = dyn_cast(&SI)) { Attr = HTE->isMandatory(); } else if (auto *DVI = dyn_cast(&SI)) { Attr = unsigned(DVI->poisonRefs()) | (unsigned(DVI->isDeadEnd()) << 1); } else if (auto *BCMI = dyn_cast(&SI)) { Attr = BCMI->isNative(); } else if (auto *ECMI = dyn_cast(&SI)) { Attr = ECMI->doKeepUnique(); } else if (auto *BBI = dyn_cast(&SI)) { Attr = unsigned(BBI->isLexical()) | (unsigned(BBI->hasPointerEscape() << 1)) | (unsigned(BBI->isFromVarDecl() << 2)) | (unsigned(BBI->isFixed() << 3)); } else if (auto *MVI = dyn_cast(&SI)) { Attr = unsigned(MVI->getAllowDiagnostics()) | (unsigned(MVI->isLexical() << 1)) | (unsigned(MVI->hasPointerEscape() << 2)) | (unsigned(MVI->isFromVarDecl() << 3)); } else if (auto *I = dyn_cast(&SI)) { Attr = unsigned(I->getCheckKind()); assert(Attr < (1 << 3)); Attr |= unsigned(I->isStrict()) << 3; } else if (auto *I = dyn_cast(&SI)) { Attr = unsigned(I->getKind()); } else if (auto *I = dyn_cast(&SI)) { Attr = I->getForwardingOwnershipKind() == OwnershipKind::Owned ? true : false; } else if (auto *I = dyn_cast(&SI)) { Attr = I->getForwardingOwnershipKind() == OwnershipKind::Owned ? true : false; } else if (auto *LB = dyn_cast(&SI)) { Attr = LB->isUnchecked(); } writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0)); break; } case SILInstructionKind::EndApplyInst: { const auto *eai = cast(&SI); writeOneTypeOneOperandLayout( eai->getKind(), 0, eai->getType(), eai->getOperand()); break; } case SILInstructionKind::MarkUnresolvedNonCopyableValueInst: { unsigned Attr = unsigned(cast(&SI)->getCheckKind()); writeOneOperandExtraAttributeLayout(SI.getKind(), Attr, SI.getOperand(0)); break; } case SILInstructionKind::MarkUninitializedInst: { unsigned Attr = (unsigned)cast(&SI)->getMarkUninitializedKind(); writeOneOperandExtraAttributeLayout(SI.getKind(), Attr, SI.getOperand(0)); break; } case SILInstructionKind::UncheckedOwnershipInst: { llvm_unreachable("Invalid unchecked_ownership during serialzation"); } case SILInstructionKind::YieldInst: { auto YI = cast(&SI); SmallVector args; for (auto arg: YI->getYieldedValues()) { args.push_back(S.addTypeRef(arg->getType().getRawASTType())); args.push_back((unsigned)arg->getType().getCategory()); args.push_back(addValueRef(arg)); } args.push_back(BasicBlockMap[YI->getResumeBB()]); args.push_back(BasicBlockMap[YI->getUnwindBB()]); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)YI->getKind(), 0, 0, args); break; } case SILInstructionKind::FunctionRefInst: { // Use SILOneOperandLayout to specify the function type and the function // name (IdentifierID). const FunctionRefInst *FRI = cast(&SI); SILFunction *ReferencedFunction = FRI->getReferencedFunction(); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); break; } case SILInstructionKind::IgnoredUseInst: { // Use SILOneOperandLayout to specify our operand. auto *iui = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)iui->getKind(), 0, S.addTypeRef(iui->getOperand()->getType().getRawASTType()), (unsigned)iui->getOperand()->getType().getCategory(), addValueRef(iui->getOperand())); break; } case SILInstructionKind::DynamicFunctionRefInst: { // Use SILOneOperandLayout to specify the function type and the function // name (IdentifierID). const auto *FRI = cast(&SI); SILFunction *ReferencedFunction = FRI->getInitiallyReferencedFunction(); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); break; } case SILInstructionKind::PreviousDynamicFunctionRefInst: { // Use SILOneOperandLayout to specify the function type and the function // name (IdentifierID). const auto *FRI = cast(&SI); SILFunction *ReferencedFunction = FRI->getInitiallyReferencedFunction(); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(FRI->getType().getRawASTType()), (unsigned)FRI->getType().getCategory(), addSILFunctionRef(ReferencedFunction)); break; } case SILInstructionKind::CopyBlockWithoutEscapingInst: case SILInstructionKind::DeallocPartialRefInst: case SILInstructionKind::BeginDeallocRefInst: case SILInstructionKind::MarkDependenceInst: case SILInstructionKind::MarkDependenceAddrInst: case SILInstructionKind::IndexAddrInst: case SILInstructionKind::IndexRawPointerInst: { SILValue operand, operand2; unsigned Attr = 0; if (SI.getKind() == SILInstructionKind::CopyBlockWithoutEscapingInst) { const CopyBlockWithoutEscapingInst *C = cast(&SI); operand = C->getBlock(); operand2 = C->getClosure(); } else if (SI.getKind() == SILInstructionKind::DeallocPartialRefInst) { const DeallocPartialRefInst *DPRI = cast(&SI); operand = DPRI->getInstance(); operand2 = DPRI->getMetatype(); } else if (SI.getKind() == SILInstructionKind::BeginDeallocRefInst) { const BeginDeallocRefInst *bdr = cast(&SI); operand = bdr->getReference(); operand2 = bdr->getAllocation(); } else if (SI.getKind() == SILInstructionKind::IndexRawPointerInst) { const IndexRawPointerInst *IRP = cast(&SI); operand = IRP->getBase(); operand2 = IRP->getIndex(); } else if (SI.getKind() == SILInstructionKind::MarkDependenceInst) { const MarkDependenceInst *MDI = cast(&SI); operand = MDI->getValue(); operand2 = MDI->getBase(); Attr = unsigned(MDI->dependenceKind()); } else if (SI.getKind() == SILInstructionKind::MarkDependenceAddrInst) { const MarkDependenceAddrInst *MDI = cast(&SI); operand = MDI->getAddress(); operand2 = MDI->getBase(); Attr = unsigned(MDI->dependenceKind()); } else { const IndexAddrInst *IAI = cast(&SI); operand = IAI->getBase(); operand2 = IAI->getIndex(); Attr = (IAI->needsStackProtection() ? 1 : 0); } SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), Attr, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand), S.addTypeRef(operand2->getType().getRawASTType()), (unsigned)operand2->getType().getCategory(), addValueRef(operand2)); break; } case SILInstructionKind::PackElementGetInst: { auto PEGI = cast(&SI); auto elementType = PEGI->getElementType(); auto elementTypeRef = S.addTypeRef(elementType.getRawASTType()); auto pack = PEGI->getPack(); auto packType = pack->getType(); auto packTypeRef = S.addTypeRef(packType.getRawASTType()); auto packRef = addValueRef(pack); auto indexRef = addValueRef(PEGI->getIndex()); SILPackElementGetLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILPackElementGetLayout::Code], (unsigned)SI.getKind(), elementTypeRef, (unsigned) elementType.getCategory(), packTypeRef, (unsigned) packType.getCategory(), packRef, indexRef); break; } case SILInstructionKind::PackElementSetInst: { auto PESI = cast(&SI); auto value = PESI->getValue(); auto valueType = value->getType(); auto valueTypeRef = S.addTypeRef(valueType.getRawASTType()); auto valueRef = addValueRef(value); auto pack = PESI->getPack(); auto packType = pack->getType(); auto packTypeRef = S.addTypeRef(packType.getRawASTType()); auto packRef = addValueRef(pack); auto indexRef = addValueRef(PESI->getIndex()); SILPackElementSetLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILPackElementSetLayout::Code], valueTypeRef, (unsigned) valueType.getCategory(), valueRef, packTypeRef, (unsigned) packType.getCategory(), packRef, indexRef); break; } case SILInstructionKind::TuplePackElementAddrInst: { auto TPEAI = cast(&SI); auto elementType = TPEAI->getElementType(); auto elementTypeRef = S.addTypeRef(elementType.getRawASTType()); auto tuple = TPEAI->getTuple(); auto tupleType = tuple->getType(); auto tupleTypeRef = S.addTypeRef(tupleType.getRawASTType()); auto tupleRef = addValueRef(tuple); auto indexRef = addValueRef(TPEAI->getIndex()); SILPackElementGetLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILPackElementGetLayout::Code], (unsigned)SI.getKind(), elementTypeRef, (unsigned)elementType.getCategory(), tupleTypeRef, (unsigned)tupleType.getCategory(), tupleRef, indexRef); break; } case SILInstructionKind::TuplePackExtractInst: { auto TPEI = cast(&SI); auto elementType = TPEI->getElementType(); auto elementTypeRef = S.addTypeRef(elementType.getRawASTType()); auto tuple = TPEI->getTuple(); auto tupleType = tuple->getType(); auto tupleTypeRef = S.addTypeRef(tupleType.getRawASTType()); auto tupleRef = addValueRef(tuple); auto indexRef = addValueRef(TPEI->getIndex()); SILPackElementGetLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILPackElementGetLayout::Code], (unsigned)SI.getKind(), elementTypeRef, (unsigned)elementType.getCategory(), tupleTypeRef, (unsigned)tupleType.getCategory(), tupleRef, indexRef); break; } case SILInstructionKind::TailAddrInst: { const TailAddrInst *TAI = cast(&SI); SILTailAddrLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTailAddrLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(TAI->getBase()->getType().getRawASTType()), addValueRef(TAI->getBase()), S.addTypeRef(TAI->getIndex()->getType().getRawASTType()), addValueRef(TAI->getIndex()), S.addTypeRef(TAI->getTailType().getRawASTType())); break; } case SILInstructionKind::CondFailInst: { auto *CFI = cast(&SI); SILValue operand = CFI->getOperand(); SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attributes*/ 0, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand), 0, 0, S.addUniquedStringRef(CFI->getMessage())); break; } case SILInstructionKind::IncrementProfilerCounterInst: { auto *IPCI = cast(&SI); llvm::SmallString<10> HashStr; APInt(64, IPCI->getPGOFuncHash()).toStringUnsigned(HashStr); SILInstIncrementProfilerCounterLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstIncrementProfilerCounterLayout::Code], S.addUniquedStringRef(IPCI->getPGOFuncName()), S.addUniquedStringRef(HashStr), IPCI->getCounterIndex(), IPCI->getNumCounters()); break; } case SILInstructionKind::StringLiteralInst: { auto SLI = cast(&SI); StringRef Str = SLI->getValue(); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; unsigned encoding = toStableStringEncoding(SLI->getEncoding()); SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), encoding, 0, 0, S.addUniquedStringRef(Str)); break; } case SILInstructionKind::FloatLiteralInst: case SILInstructionKind::IntegerLiteralInst: { // Use SILOneOperandLayout to specify the type and the literal. llvm::SmallString<10> Str; SILType Ty; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::IntegerLiteralInst: cast(&SI)->getValue().toString(Str, 10, /*signed*/ true); Ty = cast(&SI)->getType(); break; case SILInstructionKind::FloatLiteralInst: cast(&SI)->getBits().toString(Str, 16, /*signed*/ true); Ty = cast(&SI)->getType(); break; } unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), S.addUniquedStringRef(Str.str())); break; } case SILInstructionKind::MarkFunctionEscapeInst: { // Format: a list of typed values. A typed value is expressed by 4 IDs: // TypeID, TypeCategory, ValueID, ValueResultNumber. const MarkFunctionEscapeInst *MFE = cast(&SI); SmallVector ListOfValues; for (auto Elt : MFE->getElements()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), 0, 0, ListOfValues); break; } case SILInstructionKind::MetatypeInst: { auto &MI = cast(SI); writeOneTypeLayout(MI.getKind(), 0, MI.getType()); break; } case SILInstructionKind::ObjCProtocolInst: { const ObjCProtocolInst *PI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(PI->getType().getRawASTType()), (unsigned)PI->getType().getCategory(), S.addDeclRef(PI->getProtocol())); break; } case SILInstructionKind::OpenExistentialAddrInst: { auto &open = cast(SI); assert(open.getNumOperands() - open.getTypeDependentOperands().size() == 1); unsigned attrs = open.getAccessKind() == OpenedExistentialAccess::Immutable ? 0 : 1; writeOneTypeOneOperandLayout(open.getKind(), attrs, open.getType(), open.getOperand()); break; } case SILInstructionKind::DynamicPackIndexInst: { auto &dpii = cast(SI); writeOneTypeOneOperandLayout(dpii.getKind(), 0, dpii.getIndexedPackType(), dpii.getOperand()); break; } case SILInstructionKind::PackPackIndexInst: { auto &ppii = cast(SI); writeOneTypeOneOperandLayout(ppii.getKind(), ppii.getComponentStartIndex(), ppii.getIndexedPackType(), ppii.getOperand()); break; } case SILInstructionKind::ScalarPackIndexInst: { auto &spii = cast(SI); writeOneTypeLayout(spii.getKind(), spii.getComponentIndex(), spii.getIndexedPackType()); break; } case SILInstructionKind::OpenPackElementInst: { auto &opei = cast(SI); auto envRef = S.addGenericEnvironmentRef(opei.getOpenedGenericEnvironment()); auto operand = opei.getIndexOperand(); auto operandRef = addValueRef(operand); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); SILOpenPackElementLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOpenPackElementLayout::Code], envRef, operandTypeRef, unsigned(operandType.getCategory()), operandRef); break; } case SILInstructionKind::GetAsyncContinuationAddrInst: { auto &gaca = cast(SI); writeOneTypeOneOperandLayout(gaca.getKind(), gaca.throws(), gaca.getFormalResumeType(), gaca.getOperand()); break; } case SILInstructionKind::GetAsyncContinuationInst: { auto &gaca = cast(SI); writeOneTypeLayout(gaca.getKind(), gaca.throws(), gaca.getFormalResumeType()); break; } case SILInstructionKind::ThunkInst: { auto &ti = cast(SI); auto operandType = ti.getOperand()->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto operandRef = addValueRef(ti.getOperand()); SILThunkLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILThunkLayout::Code], unsigned(ti.getThunkKind()), operandTypeRef, unsigned(operandType.getCategory()), operandRef, S.addSubstitutionMapRef(ti.getSubstitutionMap())); break; } // Conversion instructions (and others of similar form). #define LOADABLE_REF_STORAGE(Name, ...) \ case SILInstructionKind::RefTo##Name##Inst: \ case SILInstructionKind::Name##ToRefInst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::OpenExistentialRefInst: case SILInstructionKind::OpenExistentialMetatypeInst: case SILInstructionKind::OpenExistentialBoxInst: case SILInstructionKind::OpenExistentialValueInst: case SILInstructionKind::OpenExistentialBoxValueInst: case SILInstructionKind::UncheckedRefCastInst: case SILInstructionKind::UncheckedAddrCastInst: case SILInstructionKind::UncheckedTrivialBitCastInst: case SILInstructionKind::UncheckedBitwiseCastInst: case SILInstructionKind::UncheckedValueCastInst: case SILInstructionKind::VectorBaseAddrInst: case SILInstructionKind::BridgeObjectToRefInst: case SILInstructionKind::BridgeObjectToWordInst: case SILInstructionKind::UpcastInst: case SILInstructionKind::AddressToPointerInst: case SILInstructionKind::RefToRawPointerInst: case SILInstructionKind::RawPointerToRefInst: case SILInstructionKind::ThinToThickFunctionInst: case SILInstructionKind::ThickToObjCMetatypeInst: case SILInstructionKind::ObjCToThickMetatypeInst: case SILInstructionKind::ConvertFunctionInst: case SILInstructionKind::ConvertEscapeToNoEscapeInst: case SILInstructionKind::ObjCMetatypeToObjectInst: case SILInstructionKind::ObjCExistentialMetatypeToObjectInst: case SILInstructionKind::ProjectBlockStorageInst: { unsigned attrs = 0; if (SI.getKind() == SILInstructionKind::ConvertEscapeToNoEscapeInst) { if (cast(SI).isLifetimeGuaranteed()) attrs |= 0x01; } if (SI.getKind() == SILInstructionKind::ConvertFunctionInst) { if (cast(SI).withoutActuallyEscaping()) attrs |= 0x01; } else if (auto *refCast = dyn_cast(&SI)) { attrs = encodeValueOwnership(refCast->getOwnershipKind()); } else if (auto *atp = dyn_cast(&SI)) { attrs = atp->needsStackProtection() ? 1 : 0; } writeConversionLikeInstruction(cast(&SI), attrs); break; } case SILInstructionKind::PointerToAddressInst: { auto &PAI = cast(SI); assert(PAI.getNumOperands() - PAI.getTypeDependentOperands().size() == 1); uint8_t encodedAlignment = llvm::encode(PAI.alignment()); assert(encodedAlignment == llvm::encode(PAI.alignment()) && "pointer_to_address alignment overflow"); unsigned attrs = encodedAlignment | (PAI.isStrict() ? 0x100 : 0) | (PAI.isInvariant() ? 0x200 : 0); writeOneTypeOneOperandExtraAttributeLayout( PAI.getKind(), attrs, PAI.getType(), PAI.getOperand()); break; } case SILInstructionKind::RefToBridgeObjectInst: { auto RI = cast(&SI); auto op = RI->getOperand(0); SILTwoOperandsLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/ 0, S.addTypeRef(op->getType().getRawASTType()), (unsigned)op->getType().getCategory(), addValueRef(op), S.addTypeRef(RI->getBitsOperand()->getType().getRawASTType()), (unsigned)RI->getBitsOperand()->getType().getCategory(), addValueRef(RI->getBitsOperand())); break; } // Checked Conversion instructions. case SILInstructionKind::UnconditionalCheckedCastInst: { auto CI = cast(&SI); unsigned flags = CI->getCheckedCastOptions().getStorage(); ValueID listOfValues[] = { addValueRef(CI->getOperand()), S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()), flags }; SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::ArrayRef(listOfValues)); break; } case SILInstructionKind::UnconditionalCheckedCastAddrInst: { auto CI = cast(&SI); unsigned flags = CI->getCheckedCastOptions().getStorage(); ValueID listOfValues[] = { S.addTypeRef(CI->getSourceFormalType()), addValueRef(CI->getSrc()), S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()), addValueRef(CI->getDest()), flags }; SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::ArrayRef(listOfValues)); break; } case SILInstructionKind::UncheckedRefCastAddrInst: { auto CI = cast(&SI); ValueID listOfValues[] = { S.addTypeRef(CI->getSourceFormalType()), addValueRef(CI->getSrc()), S.addTypeRef(CI->getSourceLoweredType().getRawASTType()), (unsigned)CI->getSourceLoweredType().getCategory(), S.addTypeRef(CI->getTargetFormalType()), addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CI->getTargetLoweredType().getRawASTType()), (unsigned)CI->getTargetLoweredType().getCategory(), llvm::ArrayRef(listOfValues)); break; } case SILInstructionKind::BeginAccessInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandExtraAttributeLayout::Code]; auto *BAI = cast(&SI); unsigned attr = unsigned(BAI->getAccessKind()) + (unsigned(BAI->getEnforcement()) << 2) + (BAI->hasNoNestedConflict() << 5) + (BAI->isFromBuiltin() << 6); SILValue operand = BAI->getOperand(); SILOneOperandExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto *BAI = cast(&SI); SILValue operand = BAI->getOperand(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto *BAI = cast(&SI); SILValue operand = BAI->getOperand(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto *BAI = cast(&SI); SILValue operand = BAI->getOperand(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::EndAccessInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto *EAI = cast(&SI); unsigned attr = unsigned(EAI->isAborting()); SILValue operand = EAI->getOperand(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::ImplicitActorToOpaqueIsolationCastInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; auto operand = cast(&SI)->getOperand(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0 /*attr*/, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::BeginUnpairedAccessInst: { unsigned abbrCode = SILAbbrCodes[SILTwoOperandsExtraAttributeLayout::Code]; auto *BAI = cast(&SI); unsigned attr = unsigned(BAI->getAccessKind()) + (unsigned(BAI->getEnforcement()) << 2) + (unsigned(BAI->hasNoNestedConflict()) << 5) + (unsigned(BAI->isFromBuiltin()) << 6); SILValue source = BAI->getSource(); SILValue buffer = BAI->getBuffer(); SILTwoOperandsExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, S.addTypeRef(source->getType().getRawASTType()), (unsigned)source->getType().getCategory(), addValueRef(source), S.addTypeRef(buffer->getType().getRawASTType()), (unsigned)buffer->getType().getCategory(), addValueRef(buffer)); break; } case SILInstructionKind::EndUnpairedAccessInst: { unsigned abbrCode = SILAbbrCodes[SILOneOperandExtraAttributeLayout::Code]; auto *EAI = cast(&SI); unsigned attr = unsigned(EAI->isAborting()) + (unsigned(EAI->getEnforcement()) << 1) + (unsigned(EAI->isFromBuiltin()) << 4); SILValue operand = EAI->getOperand(); SILOneOperandExtraAttributeLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), attr, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Store##Name##Inst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::AssignInst: case SILInstructionKind::CopyAddrInst: case SILInstructionKind::ExplicitCopyAddrInst: case SILInstructionKind::MarkUnresolvedMoveAddrInst: case SILInstructionKind::StoreInst: case SILInstructionKind::StoreBorrowInst: { SILValue operand, value; unsigned Attr = 0; if (SI.getKind() == SILInstructionKind::StoreInst) { Attr = unsigned(cast(&SI)->getOwnershipQualifier()); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ } else if (SI.getKind() == SILInstructionKind::Store##Name##Inst) { \ Attr = cast(&SI)->isInitializationOfDest(); \ operand = cast(&SI)->getDest(); \ value = cast(&SI)->getSrc(); #include "swift/AST/ReferenceStorage.def" } else if (SI.getKind() == SILInstructionKind::AssignInst) { Attr = unsigned(cast(&SI)->getOwnershipQualifier()); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == SILInstructionKind::CopyAddrInst) { const CopyAddrInst *CAI = cast(&SI); Attr = (CAI->isInitializationOfDest() << 1) | CAI->isTakeOfSrc(); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == SILInstructionKind::ExplicitCopyAddrInst) { const auto *CAI = cast(&SI); Attr = (CAI->isInitializationOfDest() << 1) | CAI->isTakeOfSrc(); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == SILInstructionKind::MarkUnresolvedMoveAddrInst) { auto *mai = cast(&SI); operand = mai->getDest(); value = mai->getSrc(); } else if (auto *SBI = dyn_cast(&SI)) { operand = SBI->getDest(); value = SBI->getSrc(); } else { llvm_unreachable("switch out of sync"); } unsigned abbrCode = SILAbbrCodes[SILOneValueOneOperandLayout::Code]; SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), Attr, addValueRef(value), S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::AssignOrInitInst: llvm_unreachable("not supported"); case SILInstructionKind::BindMemoryInst: { auto *BI = cast(&SI); SILValue baseOperand = BI->getBase(); SILValue indexOperand = BI->getIndex(); SILType boundType = BI->getBoundType(); SmallVector ListOfValues; ListOfValues.push_back(S.addTypeRef( baseOperand->getType().getRawASTType())); ListOfValues.push_back((unsigned)baseOperand->getType().getCategory()); ListOfValues.push_back(addValueRef(baseOperand)); ListOfValues.push_back(S.addTypeRef( indexOperand->getType().getRawASTType())); ListOfValues.push_back((unsigned)indexOperand->getType().getCategory()); ListOfValues.push_back(addValueRef(indexOperand)); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(boundType.getRawASTType()), (unsigned)boundType.getCategory(), ListOfValues); break; } case SILInstructionKind::RebindMemoryInst: { auto *RBI = cast(&SI); SILValue baseOperand = RBI->getBase(); SILValue inToken = RBI->getInToken(); SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/0, S.addTypeRef(baseOperand->getType().getRawASTType()), (unsigned)baseOperand->getType().getCategory(), addValueRef(baseOperand), S.addTypeRef(inToken->getType().getRawASTType()), (unsigned)inToken->getType().getCategory(), addValueRef(inToken)); break; } case SILInstructionKind::RefElementAddrInst: case SILInstructionKind::StructElementAddrInst: case SILInstructionKind::StructExtractInst: case SILInstructionKind::InitEnumDataAddrInst: case SILInstructionKind::UncheckedEnumDataInst: case SILInstructionKind::UncheckedTakeEnumDataAddrInst: case SILInstructionKind::InjectEnumAddrInst: { // Has a typed valueref and a field decl. We use SILOneValueOneOperandLayout // where the field decl is streamed as a ValueID. SILValue operand; Decl *tDecl; unsigned attr = 0; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::RefElementAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); attr = unsigned(cast(&SI)->isImmutable()); break; case SILInstructionKind::StructElementAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); break; case SILInstructionKind::StructExtractInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); break; case SILInstructionKind::InitEnumDataAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case SILInstructionKind::UncheckedEnumDataInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case SILInstructionKind::UncheckedTakeEnumDataAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case SILInstructionKind::InjectEnumAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; } SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneValueOneOperandLayout::Code], (unsigned)SI.getKind(), attr, S.addDeclRef(tDecl), S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::RefTailAddrInst: { auto *RTAI = cast(&SI); writeOneTypeOneOperandLayout(RTAI->getKind(), unsigned(RTAI->isImmutable()), RTAI->getType(), RTAI->getOperand()); break; } case SILInstructionKind::StructInst: case SILInstructionKind::BorrowedFromInst: { // Format: a type followed by a list of typed values. A typed value is // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber. const auto *svi = cast(&SI); SmallVector ListOfValues; for (auto Elt : svi->getOperandValues()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(svi->getType().getRawASTType()), (unsigned)svi->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::ReturnBorrowInst: { // Format: a type followed by a list of typed values. A typed value is // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber. const auto *rbi = cast(&SI); SmallVector ListOfValues; for (auto Elt : rbi->getOperandValues()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getRawASTType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILValuesLayout::Code], (unsigned)SI.getKind(), ListOfValues); break; } case SILInstructionKind::TupleElementAddrInst: case SILInstructionKind::TupleExtractInst: { SILValue operand; unsigned FieldNo; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::TupleElementAddrInst: operand = cast(&SI)->getOperand(); FieldNo = cast(&SI)->getFieldIndex(); break; case SILInstructionKind::TupleExtractInst: operand = cast(&SI)->getOperand(); FieldNo = cast(&SI)->getFieldIndex(); break; } // Use OneTypeOneOperand layout where the field number is stored in TypeID. SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), 0, FieldNo, 0, S.addTypeRef(operand->getType().getRawASTType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case SILInstructionKind::TupleInst: { // Format: a type followed by a list of values. A value is expressed by // 2 IDs: ValueID, ValueResultNumber. const TupleInst *TI = cast(&SI); SmallVector ListOfValues; for (auto Elt : TI->getElements()) { ListOfValues.push_back(addValueRef(Elt)); } unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(TI->getType().getRawASTType()), (unsigned)TI->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::MergeIsolationRegionInst: { const auto *mir = cast(&SI); SmallVector ListOfValues; auto getValue = [&](SILValue value) -> uint64_t { uint32_t result = addValueRef(value); // Set the top bit if we are an address. We only transfer raw ast types, // so we lose this bit otherwise. This is safe since all of our IDs are // guaranteed to be 31 bits meaning we can always take the top bit. result |= value->getType().isObject() ? 0 : 0x80000000; return result; }; for (auto value : mir->getArguments()) { ListOfValues.push_back(getValue(value)); ListOfValues.push_back(S.addTypeRef(value->getType().getRawASTType())); } unsigned abbrCode = SILAbbrCodes[SILValuesLayout::Code]; SILValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), ListOfValues); break; } case SILInstructionKind::TupleAddrConstructorInst: { // Format: a type followed by a list of values. A value is expressed by // 2 IDs: ValueID, ValueResultNumber. const auto *TI = cast(&SI); SmallVector ListOfValues; auto getValue = [&](SILValue value) -> uint64_t { uint32_t result = addValueRef(value); // Set the top bit if we are an address. result |= value->getType().isObject() ? 0 : 0x80000000; return result; }; ListOfValues.push_back(getValue(TI->getDest())); for (auto Elt : TI->getElements()) { ListOfValues.push_back(getValue(Elt)); } unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesCategoriesLayout::Code]; unsigned options = 0; options |= bool(TI->isInitializationOfDest()); SILOneTypeValuesCategoriesLayout::emitRecord( Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(TI->getDest()->getType().getRawASTType()), (unsigned)SILValueCategory::Address, options, ListOfValues); break; } case SILInstructionKind::EnumInst: { // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type, // (DeclID + hasOperand), and an operand. const EnumInst *UI = cast(&SI); TypeID OperandTy = UI->hasOperand() ? S.addTypeRef(UI->getOperand()->getType().getRawASTType()) : TypeID(); unsigned OperandTyCategory = UI->hasOperand() ? (unsigned)UI->getOperand()->getType().getCategory() : 0; SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), UI->hasOperand(), S.addTypeRef(UI->getType().getRawASTType()), (unsigned)UI->getType().getCategory(), S.addDeclRef(UI->getElement()), OperandTy, OperandTyCategory, UI->hasOperand() ? addValueRef(UI->getOperand()) : ValueID()); break; } case SILInstructionKind::WitnessMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type. const WitnessMethodInst *WMI = cast(&SI); CanType Ty = WMI->getLookupType(); SILType Ty2 = WMI->getType(); SmallVector ListOfValues; handleSILDeclRef(S, WMI->getMember(), ListOfValues); // Add an optional operand. TypeID OperandTy = TypeID(); unsigned OperandTyCategory = 0; SILValue OptionalOpenedExistential = SILValue(); auto OperandValueId = addValueRef(OptionalOpenedExistential); auto ConformanceId = S.addConformanceRef(WMI->getConformance()); SILInstWitnessMethodLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstWitnessMethodLayout::Code], S.addTypeRef(Ty), 0, 0, S.addTypeRef(Ty2.getRawASTType()), (unsigned)Ty2.getCategory(), OperandTy, OperandTyCategory, OperandValueId, ConformanceId, ListOfValues); break; } case SILInstructionKind::ClassMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), // and an operand. const ClassMethodInst *CMI = cast(&SI); SILType Ty = CMI->getType(); SmallVector ListOfValues; handleMethodInst(CMI, CMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case SILInstructionKind::SuperMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), // and an operand. const SuperMethodInst *SMI = cast(&SI); SILType Ty = SMI->getType(); SmallVector ListOfValues; handleMethodInst(SMI, SMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case SILInstructionKind::ObjCMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), // and an operand. const ObjCMethodInst *OMI = cast(&SI); SILType Ty = OMI->getType(); SmallVector ListOfValues; handleMethodInst(OMI, OMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case SILInstructionKind::ObjCSuperMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), // and an operand. const ObjCSuperMethodInst *SMI = cast(&SI); SILType Ty = SMI->getType(); SmallVector ListOfValues; handleMethodInst(SMI, SMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getRawASTType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case SILInstructionKind::DynamicMethodBranchInst: { // Format: a typed value, a SILDeclRef, a BasicBlock ID for method, // a BasicBlock ID for no method. Use SILOneTypeValuesLayout. const DynamicMethodBranchInst *DMB = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(DMB->getOperand())); handleSILDeclRef(S, DMB->getMember(), ListOfValues); ListOfValues.push_back(BasicBlockMap[DMB->getHasMethodBB()]); ListOfValues.push_back(BasicBlockMap[DMB->getNoMethodBB()]); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(DMB->getOperand()->getType().getRawASTType()), (unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::CheckedCastBranchInst: { const CheckedCastBranchInst *CBI = cast(&SI); unsigned flags = 0; if (CBI->isExact()) flags |= 0x01; flags |= (CBI->getCheckedCastOptions().getStorage() << 1); ValueID listOfValues[] = { flags, S.addTypeRef(CBI->getSourceFormalType()), addValueRef(CBI->getOperand()), S.addTypeRef(CBI->getSourceLoweredType().getRawASTType()), (unsigned)CBI->getSourceLoweredType().getCategory(), S.addTypeRef(CBI->getTargetFormalType()), BasicBlockMap[CBI->getSuccessBB()], BasicBlockMap[CBI->getFailureBB()] }; unsigned ownershipField = encodeValueOwnership(CBI->getForwardingOwnershipKind()); SILOneTypeOwnershipValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeOwnershipValuesLayout::Code], (unsigned)SI.getKind(), ownershipField, S.addTypeRef(CBI->getTargetLoweredType().getRawASTType()), (unsigned)CBI->getTargetLoweredType().getCategory(), llvm::ArrayRef(listOfValues)); break; } case SILInstructionKind::CheckedCastAddrBranchInst: { auto CBI = cast(&SI); unsigned flags = toStableCastConsumptionKind(CBI->getConsumptionKind()) << 8; flags |= CBI->getCheckedCastOptions().getStorage(); ValueID listOfValues[] = { flags, S.addTypeRef(CBI->getSourceFormalType()), addValueRef(CBI->getSrc()), S.addTypeRef(CBI->getSourceLoweredType().getRawASTType()), (unsigned)CBI->getSourceLoweredType().getCategory(), S.addTypeRef(CBI->getTargetFormalType()), addValueRef(CBI->getDest()), BasicBlockMap[CBI->getSuccessBB()], BasicBlockMap[CBI->getFailureBB()] }; SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CBI->getTargetLoweredType().getRawASTType()), (unsigned)CBI->getTargetLoweredType().getCategory(), llvm::ArrayRef(listOfValues)); break; } case SILInstructionKind::InitBlockStorageHeaderInst: { auto IBSHI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage())); ListOfValues.push_back( S.addTypeRef(IBSHI->getBlockStorage()->getType().getRawASTType())); // Always an address, don't need to save category ListOfValues.push_back(addValueRef(IBSHI->getInvokeFunction())); ListOfValues.push_back( S.addTypeRef(IBSHI->getInvokeFunction()->getType().getRawASTType())); // Always a value, don't need to save category ListOfValues.push_back(S.addSubstitutionMapRef(IBSHI->getSubstitutions())); SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(IBSHI->getType().getRawASTType()), (unsigned)IBSHI->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::KeyPathInst: { auto KPI = cast(&SI); SmallVector ListOfValues; auto pattern = KPI->getPattern(); ListOfValues.push_back(S.addTypeRef(pattern->getRootType())); ListOfValues.push_back(S.addTypeRef(pattern->getValueType())); ListOfValues.push_back(pattern->getComponents().size()); ListOfValues.push_back(pattern->getNumOperands()); ListOfValues.push_back(S.addSubstitutionMapRef(KPI->getSubstitutions())); ListOfValues.push_back(S.addUniquedStringRef(pattern->getObjCString())); if (auto sig = pattern->getGenericSignature()) { assert(sig.getGenericParams().size() > 0); ListOfValues.push_back(sig.getGenericParams().size()); for (auto param : sig.getGenericParams()) ListOfValues.push_back(S.addTypeRef(param)); auto reqts = sig.getRequirements(); S.serializeGenericRequirements(reqts, ListOfValues); } else { ListOfValues.push_back(0); } for (auto &component : pattern->getComponents()) { writeKeyPathPatternComponent(component, ListOfValues); } for (auto &operand : KPI->getPatternOperands()) { auto value = operand.get(); ListOfValues.push_back(addValueRef(value)); ListOfValues.push_back(S.addTypeRef(value->getType().getRawASTType())); ListOfValues.push_back((unsigned)value->getType().getCategory()); } SILOneTypeValuesLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(KPI->getType().getRawASTType()), (unsigned)KPI->getType().getCategory(), ListOfValues); break; } case SILInstructionKind::DifferentiableFunctionInst: { auto *dfi = cast(&SI); SmallVector trailingInfo; auto *paramIndices = dfi->getParameterIndices(); for (unsigned i : paramIndices->getIndices()) trailingInfo.push_back(i); auto *resultIndices = dfi->getResultIndices(); for (unsigned i : resultIndices->getIndices()) trailingInfo.push_back(i); for (auto &op : dfi->getAllOperands()) { auto val = op.get(); trailingInfo.push_back(S.addTypeRef(val->getType().getRawASTType())); trailingInfo.push_back((unsigned)val->getType().getCategory()); trailingInfo.push_back(addValueRef(val)); } SILInstDifferentiableFunctionLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstDifferentiableFunctionLayout::Code], paramIndices->getCapacity(), resultIndices->getCapacity(), paramIndices->getNumIndices(), dfi->hasDerivativeFunctions(), trailingInfo); break; } case SILInstructionKind::LinearFunctionInst: { auto *lfi = cast(&SI); SmallVector trailingInfo; auto *paramIndices = lfi->getParameterIndices(); for (unsigned idx : paramIndices->getIndices()) trailingInfo.push_back(idx); for (auto &op : lfi->getAllOperands()) { auto val = op.get(); trailingInfo.push_back(S.addTypeRef(val->getType().getRawASTType())); trailingInfo.push_back((unsigned)val->getType().getCategory()); trailingInfo.push_back(addValueRef(val)); } SILInstLinearFunctionLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstLinearFunctionLayout::Code], paramIndices->getCapacity(), lfi->hasTransposeFunction(), trailingInfo); break; } case SILInstructionKind::DifferentiableFunctionExtractInst: { auto *dfei = cast(&SI); auto operandRef = addValueRef(dfei->getOperand()); auto operandType = dfei->getOperand()->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto rawExtractee = (unsigned)dfei->getExtractee(); auto extracteeTypeRef = S.addTypeRef(dfei->getType().getRawASTType()); SILInstDifferentiableFunctionExtractLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstDifferentiableFunctionExtractLayout::Code], operandTypeRef, (unsigned)operandType.getCategory(), operandRef, rawExtractee, (unsigned)dfei->hasExplicitExtracteeType(), extracteeTypeRef); break; } case SILInstructionKind::LinearFunctionExtractInst: { auto *lfei = cast(&SI); auto operandRef = addValueRef(lfei->getOperand()); auto operandType = lfei->getOperand()->getType(); auto operandTypeRef = S.addTypeRef(operandType.getRawASTType()); auto rawExtractee = (unsigned)lfei->getExtractee(); SILInstLinearFunctionExtractLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstLinearFunctionExtractLayout::Code], operandTypeRef, (unsigned)operandType.getCategory(), operandRef, rawExtractee); break; } case SILInstructionKind::DifferentiabilityWitnessFunctionInst: { auto *dwfi = cast(&SI); auto *witness = dwfi->getWitness(); DifferentiabilityWitnessesToEmit.insert(witness); Mangle::ASTMangler mangler(witness->getOriginalFunction()->getASTContext()); auto mangledKey = mangler.mangleSILDifferentiabilityWitness( witness->getOriginalFunction()->getName(), witness->getKind(), witness->getConfig()); auto rawWitnessKind = (unsigned)dwfi->getWitnessKind(); // We only store the type when the instruction has an explicit type. bool hasExplicitFnTy = dwfi->getHasExplicitFunctionType(); SILOneOperandLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)dwfi->getKind(), rawWitnessKind, hasExplicitFnTy ? S.addTypeRef(dwfi->getType().getRawASTType()) : TypeID(), hasExplicitFnTy ? (unsigned)dwfi->getType().getCategory() : 0, S.addUniquedStringRef(mangledKey)); break; } case SILInstructionKind::HasSymbolInst: { auto *hsi = cast(&SI); auto *decl = hsi->getDecl(); // Although the instruction doesn't have them as members, we need to // ensure that any SILFunctions that are technically referenced by the // instruction get serialized. SmallVector fns; hsi->getReferencedFunctions(fns); SmallVector functionRefs; for (auto fn : fns) { functionRefs.push_back(addSILFunctionRef(fn)); } SILInstHasSymbolLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstHasSymbolLayout::Code], S.addDeclRef(decl), functionRefs); break; } case SILInstructionKind::TypeValueInst: { auto *tvi = cast(&SI); auto valueTy = tvi->getType(); SILTypeValueLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTypeValueLayout::Code], S.addTypeRef(valueTy.getRawASTType()), (unsigned)valueTy.getCategory(), S.addTypeRef(tvi->getParamType())); break; } } // Non-void values get registered in the value table. for (auto result : SI.getResults()) { addValueRef(result); ++InstID; } } /// Depending on the RecordKind, we write the SILFunction table, the global /// variable table, the table for SILVTable, or the table for SILWitnessTable. static void writeIndexTable(Serializer &S, const sil_index_block::ListLayout &List, sil_index_block::RecordKind kind, const SILSerializer::Table &table) { assert((kind == sil_index_block::SIL_FUNC_NAMES || kind == sil_index_block::SIL_VTABLE_NAMES || kind == sil_index_block::SIL_MOVEONLYDEINIT_NAMES || kind == sil_index_block::SIL_GLOBALVAR_NAMES || kind == sil_index_block::SIL_WITNESS_TABLE_NAMES || kind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES || kind == sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_NAMES || kind == sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES) && "SIL function table, global, vtable, (default) witness table, default " "override table and differentiability witness table are supported"); llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; FuncTableInfo tableInfo(S); for (auto &entry : table) generator.insert(entry.first, entry.second, tableInfo); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0. endian::write(blobStream, 0, llvm::endianness::little); tableOffset = generator.Emit(blobStream, tableInfo); } SmallVector scratch; List.emit(scratch, kind, tableOffset, hashTableBlob); } static void writeStringTable(Serializer &S, const sil_index_block::ListLayout &List, sil_index_block::RecordKind kind, const SILSerializer::StringMapTable &table) { assert((kind == sil_index_block::SIL_ASM_NAMES) && "Only SIL asm names table is supported"); llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; StringTableInfo tableInfo; for (auto &entry : table) generator.insert(entry.first, entry.second, tableInfo); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0. endian::write(blobStream, 0, llvm::endianness::little); tableOffset = generator.Emit(blobStream, tableInfo); } SmallVector scratch; List.emit(scratch, kind, tableOffset, hashTableBlob); } void SILSerializer::writeIndexTables() { BCBlockRAII restoreBlock(Out, SIL_INDEX_BLOCK_ID, 5); sil_index_block::ListLayout List(Out); sil_index_block::OffsetLayout Offset(Out); if (!FuncTable.empty()) { writeIndexTable(S, List, sil_index_block::SIL_FUNC_NAMES, FuncTable); Offset.emit(ScratchRecord, sil_index_block::SIL_FUNC_OFFSETS, Funcs); } if (!VTableList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_VTABLE_NAMES, VTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_VTABLE_OFFSETS, VTableOffset); } if (!MoveOnlyDeinitList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_MOVEONLYDEINIT_NAMES, MoveOnlyDeinitList); Offset.emit(ScratchRecord, sil_index_block::SIL_MOVEONLYDEINIT_OFFSETS, MoveOnlyDeinitOffset); } if (!GlobalVarList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_GLOBALVAR_NAMES, GlobalVarList); Offset.emit(ScratchRecord, sil_index_block::SIL_GLOBALVAR_OFFSETS, GlobalVarOffset); } if (!WitnessTableList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_WITNESS_TABLE_NAMES, WitnessTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_WITNESS_TABLE_OFFSETS, WitnessTableOffset); } if (!DefaultWitnessTableList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES, DefaultWitnessTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_DEFAULT_WITNESS_TABLE_OFFSETS, DefaultWitnessTableOffset); } if (!DefaultOverrideTableList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_NAMES, DefaultOverrideTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_DEFAULT_OVERRIDE_TABLE_OFFSETS, DefaultOverrideTableOffset); } if (!PropertyOffset.empty()) { Offset.emit(ScratchRecord, sil_index_block::SIL_PROPERTY_OFFSETS, PropertyOffset); } if (!DifferentiabilityWitnessList.empty()) { writeIndexTable(S, List, sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_NAMES, DifferentiabilityWitnessList); Offset.emit(ScratchRecord, sil_index_block::SIL_DIFFERENTIABILITY_WITNESS_OFFSETS, DifferentiabilityWitnessOffset); } if (!AsmNameTable.empty()) { writeStringTable(S, List, sil_index_block::SIL_ASM_NAMES, AsmNameTable); } } void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { GlobalVarList[g.getName()] = NextGlobalVarID++; GlobalVarOffset.push_back(Out.GetCurrentBitNo()); TypeID TyID = S.addTypeRef(g.getLoweredType().getRawASTType()); DeclID dID = S.addDeclRef(g.getDecl()); ModuleID parentModuleID; if (auto *parentModule = g.getParentModule()) parentModuleID = S.addModuleRef(parentModule); unsigned numTrailingRecords = 0; // Each extra string emitted below needs to update the trailing record // count here. if (!g.asmName().empty()) { ++numTrailingRecords; // Record asmname mapping. if (g.asmName() != g.getName()) { AsmNameTable[g.asmName()] = g.getName(); } } if (!g.section().empty()) ++numTrailingRecords; SILGlobalVarLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILGlobalVarLayout::Code], toStableSILLinkage(g.getLinkage()), (unsigned)g.getSerializedKind(), (unsigned)!g.isDefinition(), (unsigned)g.isLet(), (unsigned)g.markedAsUsed(), numTrailingRecords, TyID, dID, parentModuleID); writeExtraStringIfNonEmpty(ExtraStringFlavor::AsmName, g.asmName()); writeExtraStringIfNonEmpty(ExtraStringFlavor::Section, g.section()); // Don't emit the initializer instructions if not marked as "serialized". if (!g.isAnySerialized()) return; ValueIDs.clear(); InstID = 0; unsigned ValueID = 2; for (const SILInstruction &initInst : g) { for (auto result : initInst.getResults()) { ValueIDs[result] = ValueID++; } } for (const SILInstruction &initInst : g) { writeSILInstruction(initInst); } } void SILSerializer::writeSILVTable(const SILVTable &vt) { // Do not emit vtables for non-public classes unless everything has to be // serialized. if (!Options.SerializeAllSIL && vt.getClass()->getEffectiveAccess() < swift::AccessLevel::Package) return; if (vt.isSpecialized()) return; // Use the mangled name of the class as a key to distinguish between classes // which have the same name (but are in different contexts). Mangle::ASTMangler mangler(vt.getClass()->getASTContext()); std::string mangledClassName = mangler.mangleNominalType(vt.getClass()); size_t nameLength = mangledClassName.size(); char *stringStorage = (char *)StringTable.Allocate(nameLength, 1); std::memcpy(stringStorage, mangledClassName.data(), nameLength); VTableList[StringRef(stringStorage, nameLength)] = NextVTableID++; VTableOffset.push_back(Out.GetCurrentBitNo()); VTableLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[VTableLayout::Code], S.addDeclRef(vt.getClass()), (unsigned)vt.getSerializedKind()); for (auto &entry : vt.getEntries()) { SmallVector ListOfValues; SILFunction *impl = entry.getImplementation(); if (Options.SerializeAllSIL || (vt.isAnySerialized() && impl->hasValidLinkageForFragileRef(vt.getSerializedKind()))) { handleSILDeclRef(S, entry.getMethod(), ListOfValues); addReferencedSILFunction(impl, true); // Each entry is a pair of SILDeclRef and SILFunction. VTableEntryLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[VTableEntryLayout::Code], // SILFunction name S.addUniquedStringRef(impl->getName()), toStableVTableEntryKind(entry.getKind()), entry.isNonOverridden(), ListOfValues); } } } void SILSerializer::writeSILMoveOnlyDeinit(const SILMoveOnlyDeinit &deinit) { // Do not emit deinit for non-public nominal types unless everything has to be // serialized. if (!Options.SerializeAllSIL && deinit.getNominalDecl()->getEffectiveAccess() < swift::AccessLevel::Package) return; SILFunction *impl = deinit.getImplementation(); if (!Options.SerializeAllSIL && // Package CMO for MoveOnlyDeinit is not supported so // pass the IsSerialized argument to keep the behavior // consistent with or without the optimization. !impl->hasValidLinkageForFragileRef(IsSerialized)) return; // Use the mangled name of the class as a key to distinguish between classes // which have the same name (but are in different contexts). Mangle::ASTMangler mangler(deinit.getNominalDecl()->getASTContext()); std::string mangledNominalName = mangler.mangleNominalType(deinit.getNominalDecl()); size_t nameLength = mangledNominalName.size(); char *stringStorage = (char *)StringTable.Allocate(nameLength, 1); std::memcpy(stringStorage, mangledNominalName.data(), nameLength); MoveOnlyDeinitList[StringRef(stringStorage, nameLength)] = NextMoveOnlyDeinitOffsetID++; MoveOnlyDeinitOffset.push_back(Out.GetCurrentBitNo()); addReferencedSILFunction(impl, true); MoveOnlyDeinitLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[MoveOnlyDeinitLayout::Code], S.addDeclRef(deinit.getNominalDecl()), S.addUniquedStringRef(impl->getName()), deinit.getSerializedKind()); } void SILSerializer::writeSILProperty(const SILProperty &prop) { PropertyOffset.push_back(Out.GetCurrentBitNo()); SmallVector componentValues; if (auto component = prop.getComponent()) { writeKeyPathPatternComponent(*component, componentValues); } else { componentValues.push_back((unsigned)KeyPathComponentKindEncoding::Trivial); } PropertyLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[PropertyLayout::Code], S.addDeclRef(prop.getDecl()), prop.getSerializedKind(), componentValues); } void SILSerializer::writeSourceLoc(SILLocation Loc, const SourceManager &SM) { auto SLoc = Loc.getSourceLoc(); auto OpaquePtr = SLoc.getOpaquePointerValue(); uint8_t LocationKind; switch(Loc.getKind()) { case SILLocation::ReturnKind: LocationKind = SILLocation::ReturnKind; break; case SILLocation::ImplicitReturnKind: LocationKind = SILLocation::ImplicitReturnKind; break; case SILLocation::InlinedKind: case SILLocation::MandatoryInlinedKind: case SILLocation::CleanupKind: case SILLocation::ArtificialUnreachableKind: case SILLocation::RegularKind: LocationKind = SILLocation::RegularKind; break; } if (SourceLocMap.find(OpaquePtr) != SourceLocMap.end()) { SourceLocRefLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SourceLocRefLayout::Code], SourceLocMap[OpaquePtr], LocationKind, (unsigned)Loc.isImplicit()); return; } ValueID Row = 0; ValueID Column = 0; ValueID FNameID = 0; if (!SLoc.isValid()) { //emit empty source loc SourceLocRefLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SourceLocRefLayout::Code], 0, 0, (unsigned)0); return; } std::tie(Row, Column) = SM.getPresumedLineAndColumnForLoc(SLoc); FNameID = S.addUniquedStringRef(SM.getDisplayNameForLoc(SLoc)); SourceLocMap.insert({OpaquePtr, SourceLocMap.size() + 1}); SourceLocLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SourceLocLayout::Code], Row, Column, FNameID, LocationKind, (unsigned)Loc.isImplicit()); } void SILSerializer::writeExtraStringIfNonEmpty( ExtraStringFlavor flavor, StringRef string) { if (string.empty()) return; SILExtraStringLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILExtraStringLayout::Code], static_cast(flavor), string); } void SILSerializer::writeDebugScopes(const SILDebugScope *Scope, const SourceManager &SM) { if (DebugScopeMap.find(Scope) != DebugScopeMap.end()) { // We won't be in a recursive call here. SILDebugScopeRefLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILDebugScopeRefLayout::Code], DebugScopeMap[Scope]); return; } ValueID ParentID = 0, InlinedID = 0; TypeID ParentType = 0; SILValueCategory ParentCat = (SILValueCategory)0; unsigned isFuncParent = 0; assert(!Scope->Parent.isNull()); if (!Scope->Parent) return; // A debug scope's parent can either be a function or a debug scope. // Handle both cases appropriately. if (isa(Scope->Parent)) { auto Parent = cast(Scope->Parent); if (DebugScopeMap.find(Parent) == DebugScopeMap.end()) writeDebugScopes(Parent, SM); ParentID = DebugScopeMap[Parent]; } else { const SILFunction *ParentFn = cast(Scope->Parent); assert(ParentFn); isFuncParent = true; FuncsToEmitDebug.insert(ParentFn); ParentID = S.addUniquedStringRef(ParentFn->getName()); } assert(ParentID != 0); if (auto Inlined = Scope->InlinedCallSite) { if (DebugScopeMap.find(Inlined) == DebugScopeMap.end()) writeDebugScopes(Inlined, SM); InlinedID = DebugScopeMap[Inlined]; } SourceLoc SLoc = Scope->getLoc().getSourceLoc(); ValueID Row = 0; ValueID Column = 0; ValueID FNameID = 0; // TODO: we can emit SourceLocRef here if (SLoc.isValid()) { std::tie(Row, Column) = SM.getPresumedLineAndColumnForLoc(SLoc); FNameID = S.addUniquedStringRef(SM.getDisplayNameForLoc(SLoc)); } else if (Scope->Loc.isFilenameAndLocation()) { // getSourceLoc produces an empty SourceLoc for FilenameAndLocation, so // this needs to be handled separately. rdar://25225083. auto FNameLoc = Scope->Loc.getFilenameAndLocation(); Row = FNameLoc->line; Column = FNameLoc->column; FNameID = S.addUniquedStringRef(FNameLoc->filename); } DebugScopeMap.insert({Scope, DebugScopeMap.size() + 1}); SILDebugScopeLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILDebugScopeLayout::Code], isFuncParent, ParentID, InlinedID, Row, Column, FNameID, ParentType, (unsigned)ParentCat); } void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) { if (Options.SkipImplementationOnlyDecls && wt.getConformingNominal()->getAttrs().hasAttribute< ImplementationOnlyAttr>()) { return; } WitnessTableList[wt.getName()] = NextWitnessTableID++; WitnessTableOffset.push_back(Out.GetCurrentBitNo()); auto conformanceID = S.addConformanceRef(wt.getConformance()); WitnessTableLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[WitnessTableLayout::Code], toStableSILLinkage(wt.getLinkage()), unsigned(wt.isDeclaration()), unsigned(wt.isSpecialized()), unsigned(wt.getSerializedKind()), conformanceID); // If we have a declaration, do not attempt to serialize entries. if (wt.isDeclaration()) return; for (auto &entry : wt.getEntries()) { writeSILWitnessTableEntry(entry, wt.getSerializedKind()); } for (auto conditional : wt.getConditionalConformances()) { auto conformanceID = S.addConformanceRef(conditional); WitnessConditionalConformanceLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[WitnessConditionalConformanceLayout::Code], conformanceID); } } void SILSerializer::writeSILWitnessTableEntry( const SILWitnessTable::Entry &entry, SerializedKind_t serializedKind) { if (entry.getKind() == SILWitnessTable::BaseProtocol) { auto &baseWitness = entry.getBaseProtocolWitness(); auto requirementID = S.addDeclRef(baseWitness.Requirement); auto conformanceID = S.addConformanceRef(baseWitness.Witness); WitnessBaseEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessBaseEntryLayout::Code], requirementID, conformanceID); return; } if (entry.getKind() == SILWitnessTable::AssociatedConformance) { auto &assoc = entry.getAssociatedConformanceWitness(); auto requirementID = S.addTypeRef(assoc.Requirement); auto conformanceID = S.addConformanceRef(assoc.Witness); WitnessAssocProtocolLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[WitnessAssocProtocolLayout::Code], requirementID, conformanceID); return; } if (entry.getKind() == SILWitnessTable::AssociatedType) { auto &assoc = entry.getAssociatedTypeWitness(); WitnessAssocEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessAssocEntryLayout::Code], S.addDeclRef(assoc.Requirement), S.addTypeRef(assoc.Witness)); return; } auto &methodWitness = entry.getMethodWitness(); SmallVector ListOfValues; handleSILDeclRef(S, methodWitness.Requirement, ListOfValues); IdentifierID witnessID = 0; SILFunction *witness = methodWitness.Witness; if (witness && serializedKind != IsNotSerialized && witness->hasValidLinkageForFragileRef(serializedKind)) { addReferencedSILFunction(witness, true); witnessID = S.addUniquedStringRef(witness->getName()); } WitnessMethodEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessMethodEntryLayout::Code], // SILFunction name witnessID, ListOfValues); } void SILSerializer:: writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt) { if (wt.isDeclaration()) return; StringRef name = S.addUniquedString(wt.getUniqueName()).first; DefaultWitnessTableList[name] = NextDefaultWitnessTableID++; DefaultWitnessTableOffset.push_back(Out.GetCurrentBitNo()); DefaultWitnessTableLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[DefaultWitnessTableLayout::Code], S.addDeclRef(wt.getProtocol()), toStableSILLinkage(wt.getLinkage())); for (auto &entry : wt.getEntries()) { if (!entry.isValid()) { DefaultWitnessTableNoEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[DefaultWitnessTableNoEntryLayout::Code]); continue; } // Default witness table is not serialized. The IsSerialized // argument is passed here to call hasValidLinkageForFragileRef // to keep the behavior consistent with or without any optimizations. writeSILWitnessTableEntry(entry, IsSerialized); } } void SILSerializer::writeSILDefaultOverrideTableEntry( const SILDefaultOverrideTable::Entry &entry, SerializedKind_t serializedKind) { SmallVector ListOfValues; handleSILDeclRef(S, entry.method, ListOfValues); handleSILDeclRef(S, entry.original, ListOfValues); IdentifierID implID = 0; SILFunction *impl = entry.impl; if (impl && serializedKind != IsNotSerialized && impl->hasValidLinkageForFragileRef(serializedKind)) { addReferencedSILFunction(impl, true); implID = S.addUniquedStringRef(impl->getName()); } DefaultOverrideTableEntryLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[DefaultOverrideTableEntryLayout::Code], // SILFunction name implID, ListOfValues); } void SILSerializer::writeSILDefaultOverrideTable( const SILDefaultOverrideTable &ot) { if (ot.isDeclaration()) return; StringRef name = S.addUniquedString(ot.getUniqueName()).first; DefaultOverrideTableList[name] = NextDefaultOverrideTableID++; DefaultOverrideTableOffset.push_back(Out.GetCurrentBitNo()); DefaultOverrideTableLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[DefaultOverrideTableLayout::Code], S.addDeclRef(ot.getClass()), toStableSILLinkage(ot.getLinkage())); for (auto &entry : ot.getEntries()) { // Default override table is not serialized. The IsSerialized // argument is passed here to call hasValidLinkageForFragileRef // to keep the behavior consistent with or without any optimizations. writeSILDefaultOverrideTableEntry(entry, IsSerialized); } } void SILSerializer::writeSILDifferentiabilityWitness( const SILDifferentiabilityWitness &dw) { Mangle::ASTMangler mangler(dw.getOriginalFunction()->getASTContext()); auto mangledKey = mangler.mangleSILDifferentiabilityWitness( dw.getOriginalFunction()->getName(), dw.getKind(), dw.getConfig()); size_t nameLength = mangledKey.size(); char *stringStorage = static_cast(StringTable.Allocate(nameLength, 1)); std::memcpy(stringStorage, mangledKey.data(), nameLength); DifferentiabilityWitnessList[StringRef(stringStorage, nameLength)] = NextDifferentiabilityWitnessID++; DifferentiabilityWitnessOffset.push_back(Out.GetCurrentBitNo()); auto *original = dw.getOriginalFunction(); IdentifierID jvpID = 0; IdentifierID vjpID = 0; if (auto *jvp = dw.getJVP()) jvpID = addSILFunctionRef(jvp); if (auto *vjp = dw.getVJP()) vjpID = addSILFunctionRef(vjp); SmallVector parameterAndResultIndices( dw.getParameterIndices()->begin(), dw.getParameterIndices()->end()); parameterAndResultIndices.append(dw.getResultIndices()->begin(), dw.getResultIndices()->end()); auto originalFnType = original->getLoweredFunctionType(); assert(originalFnType->getNumParameters() == dw.getParameterIndices()->getCapacity() && "Original function parameter count should match differentiability " "witness parameter indices capacity"); unsigned numInoutParameters = llvm::count_if( originalFnType->getParameters(), [](SILParameterInfo paramInfo) { return paramInfo.isIndirectMutating(); }); assert(originalFnType->getNumResults() + numInoutParameters == dw.getResultIndices()->getCapacity() && "Original function result count should match differentiability " "witness result indices capacity"); DifferentiabilityWitnessLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[DifferentiabilityWitnessLayout::Code], addSILFunctionRef(original), toStableSILLinkage(dw.getLinkage()), dw.isDeclaration(), dw.isSerialized(), toStableDifferentiabilityKind(dw.getKind()), S.addGenericSignatureRef(dw.getDerivativeGenericSignature()), jvpID, vjpID, dw.getParameterIndices()->getNumIndices(), dw.getResultIndices()->getNumIndices(), parameterAndResultIndices); } /// Helper function for whether to emit a function body. bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F, bool isReference) { // If F is a declaration, it has no body to emit... // The declaration will be serialized anyways if it is referenced anywhere. if (F->isExternalDeclaration()) return false; // Never serialize any function definitions available externally. if (F->isAvailableExternally()) return false; if (F->getDeclRef().hasDecl()) { if (auto decl = F->getDeclRef().getDecl()) if (decl->isNeverEmittedIntoClient()) return false; } // If we are asked to serialize everything, go ahead and do it. if (Options.SerializeAllSIL) return true; // If F is serialized, we should always emit its body. // Shared functions are only serialized if they are referenced from another // serialized function. This is handled in `addReferencedSILFunction`. if (F->isAnySerialized() && !hasSharedVisibility(F->getLinkage())) return true; return false; } void SILSerializer::writeSILBlock(const SILModule *SILMod) { BCBlockRAII subBlock(Out, SIL_BLOCK_ID, 6); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); // Write out VTables first because it may require serializations of // non-transparent SILFunctions (body is not needed). // Go through all SILVTables in SILMod and write them if we should // serialize everything. // FIXME: Resilience: could write out vtable for fragile classes. for (const auto &vt : SILMod->getVTables()) { if ((Options.SerializeAllSIL || vt->isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext(vt->getClass())) writeSILVTable(*vt); } for (const auto &deinit : SILMod->getMoveOnlyDeinits()) { if ((Options.SerializeAllSIL || deinit->isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( deinit->getNominalDecl())) writeSILMoveOnlyDeinit(*deinit); } // Write out property descriptors. for (const SILProperty &prop : SILMod->getPropertyList()) { if ((Options.SerializeAllSIL || prop.isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( prop.getDecl()->getInnermostDeclContext())) writeSILProperty(prop); } // Write out fragile WitnessTables. for (const SILWitnessTable &wt : SILMod->getWitnessTables()) { if ((Options.SerializeAllSIL || wt.isAnySerialized()) && SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( wt.getConformance()->getDeclContext())) writeSILWitnessTable(wt); } // Write out DefaultWitnessTables. for (const SILDefaultWitnessTable &wt : SILMod->getDefaultWitnessTables()) { // FIXME: Don't need to serialize private and internal default witness // tables. if (SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( wt.getProtocol())) writeSILDefaultWitnessTable(wt); } for (const SILDefaultOverrideTable &ot : SILMod->getDefaultOverrideTables()) { if (!SILMod->shouldSerializeEntitiesAssociatedWithDeclContext( ot.getClass())) continue; writeSILDefaultOverrideTable(ot); } // Add global variables that must be emitted to the list. for (const SILGlobalVariable &g : SILMod->getSILGlobals()) { if (g.isAnySerialized() || Options.SerializeAllSIL) addReferencedGlobalVariable(&g); } // Emit only declarations if it is a module with pre-specializations. // And only do it in optimized builds. bool emitDeclarationsForOnoneSupport = SILMod->isOptimizedOnoneSupportModule(); // Go through all the SILFunctions in SILMod and write out any // mandatory function bodies. for (const SILFunction &F : *SILMod) { if (emitDeclarationsForOnoneSupport) { // Only declarations of hardcoded pre-specializations with // public linkage need to be serialized as they will be used // by the UsePrespecializations pass during -Onone compilation to // check for availability of concrete pre-specializations. if (!hasPublicVisibility(F.getLinkage()) || !isKnownPrespecialization(F.getName())) continue; } addMandatorySILFunction(&F, emitDeclarationsForOnoneSupport); processWorklists(); } // Write out differentiability witnesses. // Note: this must be done after visiting SIL functions above so that // differentiability witness references (`differentiability_witness_function` // instructions) have been tracked. for (const auto &diffWitness : SILMod->getDifferentiabilityWitnessList()) { // TODO(TF-893): Consider checking // `SILMod->shouldSerializeEntitiesAssociatedWithDeclContext` on the JVP/VJP // functions. if ((Options.SerializeAllSIL || diffWitness.isSerialized())) DifferentiabilityWitnessesToEmit.insert(&diffWitness); } for (auto *diffWitness : DifferentiabilityWitnessesToEmit) writeSILDifferentiabilityWitness(*diffWitness); // Process SIL functions referenced by differentiability witnesses. // Note: this is necessary despite processing `FuncsToEmit` below because // `Worklist` is processed separately. processWorklists(); // Now write function declarations for every function we've // emitted a reference to without emitting a function body for. auto resilience = SILMod->getSwiftModule()->getResilienceStrategy(); for (const SILFunction &F : *SILMod) { auto iter = FuncsToEmit.find(&F); if (iter != FuncsToEmit.end()) { if (iter->second) { assert((emitDeclarationsForOnoneSupport || !shouldEmitFunctionBody(&F)) && "Should have emitted function body earlier"); writeSILFunction(F, true); } } else if (F.getLinkage() == SILLinkage::Public && resilience != ResilienceStrategy::Resilient && F.hasArgumentEffects()) { writeSILFunction(F, true); } } for (auto Fn : FuncsToEmitDebug) { if (FuncsToEmit.count(Fn) == 0) { FuncsToEmit[Fn] = true; // emit decl only functionWorklist.push_back(Fn); } } OnlyReferencedByDebugInfo = true; processWorklists(); OnlyReferencedByDebugInfo = false; FuncsToEmitDebug.clear(); assert(functionWorklist.empty() && globalWorklist.empty() && "Did not emit everything in worklists"); } void SILSerializer::writeSILModule(const SILModule *SILMod) { writeSILBlock(SILMod); writeIndexTables(); } void Serializer::writeSIL(const SILModule *SILMod) { if (!SILMod) return; SILSerializer SILSer(*this, Out, Options); SILSer.writeSILModule(SILMod); }