//===--- SerializeSIL.cpp - Read and write SIL ----------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/Module.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "llvm/ADT/MapVector.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/EndianStream.h" #include "llvm/Support/OnDiskHashTable.h" 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::UTF8: return SIL_UTF8; case StringLiteralInst::Encoding::UTF16: return SIL_UTF16; } llvm_unreachable("bad string encoding"); } static unsigned toStableSILLinkage(SILLinkage linkage) { switch (linkage) { case SILLinkage::Public: return SIL_LINKAGE_PUBLIC; 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::HiddenExternal: return SIL_LINKAGE_HIDDEN_EXTERNAL; case SILLinkage::SharedExternal: return SIL_LINKAGE_SHARED_EXTERNAL; case SILLinkage::PrivateExternal: return SIL_LINKAGE_PRIVATE_EXTERNAL; } llvm_unreachable("bad linkage"); } 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; } llvm_unreachable("bad cast consumption kind"); } namespace { /// Used to serialize the on-disk func hash table. class FuncTableInfo { public: using key_type = Identifier; 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; hash_value_type ComputeHash(key_type_ref key) { assert(!key.empty()); return llvm::HashString(key.str()); } std::pair EmitKeyDataLength(raw_ostream &out, key_type_ref key, data_type_ref data) { uint32_t keyLength = key.str().size(); uint32_t dataLength = sizeof(DeclID); endian::Writer writer(out); writer.write(keyLength); writer.write(dataLength); return { keyLength, dataLength }; } void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) { out << key.str(); } void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data, unsigned len) { static_assert(sizeof(DeclID) <= 32, "DeclID too large"); endian::Writer(out).write(data); } }; class SILSerializer { Serializer &S; ASTContext &Ctx; llvm::BitstreamWriter &Out; /// A reusable buffer for emitting records. SmallVector ScratchRecord; /// In case we want to encode the relative of InstID vs ValueID. ValueID InstID = 0; llvm::DenseMap ValueIDs; ValueID addValueRef(const ValueBase *Val); public: using TableData = FuncTableInfo::data_type; using Table = llvm::MapVector; private: /// FuncTable maps function name to an ID. Table FuncTable; std::vector Funcs; /// The current function ID. DeclID FuncID = 1; /// Maps class name to a VTable ID. Table VTableList; /// Holds the list of VTables. std::vector VTableOffset; DeclID VTableID = 1; /// Maps global variable name to an ID. Table GlobalVarList; /// Holds the list of SIL global variables. std::vector GlobalVarOffset; DeclID GlobalVarID = 1; /// Maps witness table identifier to an ID. Table WitnessTableList; /// Holds the list of WitnessTables. std::vector WitnessTableOffset; DeclID WitnessTableID = 1; /// Give each SILBasicBlock a unique ID. llvm::DenseMap BasicBlockMap; /// Functions that we've emitted a reference to. llvm::SmallSet FuncsToDeclare; 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); DEBUG(llvm::dbgs() << "SIL abbre code " << SILAbbrCodes[Layout::Code] << " for layout " << Layout::Code << "\n"); } bool ShouldSerializeAll; /// Helper function to update ListOfValues for MethodInst. Format: /// Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), 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 writeSILGlobalVar(const SILGlobalVariable &g); void writeSILWitnessTable(const SILWitnessTable &wt); void writeSILBlock(const SILModule *SILMod); void writeIndexTables(); void writeConversionLikeInstruction(const SILInstruction *I); void writeOneTypeLayout(ValueKind valueKind, SILType type); void writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned attrs, SILType type, SILValue operand); void writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned attrs, CanType type, SILValue operand); void writeOneOperandLayout(ValueKind valueKind, unsigned attrs, SILValue operand); /// 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); public: SILSerializer(Serializer &S, ASTContext &Ctx, llvm::BitstreamWriter &Out, bool serializeAll) : S(S), Ctx(Ctx), Out(Out), ShouldSerializeAll(serializeAll) {} void writeSILModule(const SILModule *SILMod); }; } // end anonymous namespace /// We enumerate all values in a SILFunction beforehand to correctly /// handle forward references of values. ValueID SILSerializer::addValueRef(const ValueBase *Val) { if (!Val || isa(Val)) return 0; 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) { ValueIDs.clear(); InstID = 0; FuncTable[Ctx.getIdentifier(F.getName())] = FuncID++; Funcs.push_back(Out.GetCurrentBitNo()); unsigned abbrCode = SILAbbrCodes[SILFunctionLayout::Code]; TypeID FnID = S.addTypeRef(F.getLoweredType().getSwiftType()); DEBUG(llvm::dbgs() << "SILFunction " << F.getName() << " @ BitNo " << Out.GetCurrentBitNo() << " abbrCode " << abbrCode << " FnID " << FnID << "\n"); DEBUG(llvm::dbgs() << "Serialized SIL:\n"; F.dump()); SmallVector SemanticsIDs; for (auto SemanticAttr : F.getSemanticsAttrs()) { SemanticsIDs.push_back(S.addIdentifierRef(Ctx.getIdentifier(SemanticAttr))); } SILLinkage Linkage = F.getLinkage(); // We serialize shared_external linkage as shared since: // // 1. shared_external linkage is just a hack to tell the optimizer that a // shared function was deserialized. // // 2. We cannot just serialize a declaration to a shared_external function // since shared_external functions still have linkonce_odr linkage at the LLVM // level. This means they must be defined not just declared. // // TODO: When serialization is reworked, this should be removed. if (hasSharedVisibility(Linkage)) Linkage = SILLinkage::Shared; // 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); } SILFunctionLayout::emitRecord( Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isFragile(), (unsigned)F.isThunk(), (unsigned)F.isGlobalInit(), (unsigned)F.getInlineStrategy(), (unsigned)F.getEffectsKind(), FnID, SemanticsIDs); if (NoBody) return; // Write the body's context archetypes, unless we don't actually have a body. if (!F.isExternalDeclaration()) { if (auto gp = F.getContextGenericParams()) { // To help deserializing the context generic params, we serialize the // outer-most list first. In most cases, we do not have decls associated // with these parameter lists, so serialize the lists directly. std::vector paramLists; for (; gp; gp = gp->getOuterParameters()) paramLists.push_back(gp); for (unsigned i = 0, e = paramLists.size(); i < e; i++) S.writeGenericParams(paramLists.rbegin()[i], SILAbbrCodes); } } // 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. unsigned ValueID = 0; for (const SILBasicBlock &BB : F) { BasicBlockMap.insert(std::make_pair(&BB, BasicID++)); for (auto I = BB.bbarg_begin(), E = BB.bbarg_end(); I != E; ++I) ValueIDs[static_cast(*I)] = ++ValueID; for (const SILInstruction &SI : BB) if (SI.hasValue()) ValueIDs[&SI] = ++ValueID; } for (const SILBasicBlock &BB : F) writeSILBasicBlock(BB); } void SILSerializer::writeSILBasicBlock(const SILBasicBlock &BB) { SmallVector Args; for (auto I = BB.bbarg_begin(), E = BB.bbarg_end(); I != E; ++I) { SILArgument *SA = *I; DeclID tId = S.addTypeRef(SA->getType().getSwiftRValueType()); DeclID vId = addValueRef(static_cast(SA)); Args.push_back(tId); Args.push_back((unsigned)SA->getType().getCategory()); Args.push_back(vId); } unsigned abbrCode = SILAbbrCodes[SILBasicBlockLayout::Code]; SILBasicBlockLayout::emitRecord(Out, ScratchRecord, abbrCode, Args); for (const SILInstruction &SI : BB) 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((unsigned)Ref.getResilienceExpansion()); ListOfValues.push_back(Ref.uncurryLevel); ListOfValues.push_back(Ref.isForeign); } /// Helper function to update ListOfValues for MethodInst. Format: /// Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and an operand. void SILSerializer::handleMethodInst(const MethodInst *MI, SILValue operand, SmallVectorImpl &ListOfValues) { ListOfValues.push_back(MI->isVolatile()); handleSILDeclRef(S, MI->getMember(), ListOfValues); ListOfValues.push_back( S.addTypeRef(operand->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)operand->getType().getCategory()); ListOfValues.push_back(addValueRef(operand)); } void SILSerializer::writeOneTypeLayout(ValueKind valueKind, SILType type) { unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned) valueKind, S.addTypeRef(type.getSwiftRValueType()), (unsigned)type.getCategory()); } void SILSerializer::writeOneOperandLayout(ValueKind valueKind, unsigned attrs, SILValue operand) { auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); auto operandRef = addValueRef(operand); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], unsigned(valueKind), attrs, operandTypeRef, unsigned(operandType.getCategory()), operandRef); } void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind, unsigned attrs, SILType type, SILValue operand) { auto typeRef = S.addTypeRef(type.getSwiftRValueType()); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); 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(ValueKind valueKind, unsigned attrs, CanType type, SILValue operand) { auto typeRef = S.addTypeRef(type); auto operandType = operand->getType(); auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType()); auto operandRef = addValueRef(operand); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], unsigned(valueKind), attrs, typeRef, 0, 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 SILInstruction *I) { assert(I->getNumOperands() == 1); writeOneTypeOneOperandLayout(I->getKind(), 0, I->getType(), I->getOperand(0)); } void SILSerializer::writeSILInstruction(const SILInstruction &SI) { switch (SI.getKind()) { case ValueKind::SILArgument: case ValueKind::SILUndef: llvm_unreachable("not an instruction"); case ValueKind::UnreachableInst: { unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code]; SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind()); break; } case ValueKind::AllocExistentialBoxInst: case ValueKind::InitExistentialAddrInst: case ValueKind::InitExistentialMetatypeInst: case ValueKind::InitExistentialRefInst: { SILValue operand; SILType Ty; CanType FormalConcreteType; ArrayRef conformances; switch (SI.getKind()) { default: llvm_unreachable("out of sync with parent"); case ValueKind::InitExistentialAddrInst: { auto &IEI = cast(SI); operand = IEI.getOperand(); Ty = IEI.getLoweredConcreteType(); FormalConcreteType = IEI.getFormalConcreteType(); conformances = IEI.getConformances(); break; } case ValueKind::InitExistentialRefInst: { auto &IERI = cast(SI); operand = IERI.getOperand(); Ty = IERI.getType(); FormalConcreteType = IERI.getFormalConcreteType(); conformances = IERI.getConformances(); break; } case ValueKind::InitExistentialMetatypeInst: { auto &IEMI = cast(SI); operand = IEMI.getOperand(); Ty = IEMI.getType(); conformances = IEMI.getConformances(); break; } case ValueKind::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().getSwiftRValueType()); operandCategory = operand->getType().getCategory(); operandID = addValueRef(operand); } unsigned abbrCode = SILAbbrCodes[SILInitExistentialLayout::Code]; SILInitExistentialLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), operandType, (unsigned)operandCategory, operandID, S.addTypeRef(FormalConcreteType), conformances.size()); for (auto conformance : conformances) { S.writeConformance(conformance, SILAbbrCodes); } break; } case ValueKind::DeallocValueBufferInst: { auto DVBI = cast(&SI); writeOneTypeOneOperandLayout(DVBI->getKind(), 0, DVBI->getValueType(), DVBI->getOperand()); break; } case ValueKind::DeallocBoxInst: { auto DBI = cast(&SI); writeOneTypeOneOperandLayout(DBI->getKind(), 0, DBI->getElementType(), DBI->getOperand()); break; } case ValueKind::DeallocExistentialBoxInst: { auto DBI = cast(&SI); writeOneTypeOneOperandLayout(DBI->getKind(), 0, DBI->getConcreteType(), DBI->getOperand()); break; } case ValueKind::ValueMetatypeInst: { auto VMI = cast(&SI); writeOneTypeOneOperandLayout(VMI->getKind(), 0, VMI->getType(), VMI->getOperand()); break; } case ValueKind::ExistentialMetatypeInst: { auto EMI = cast(&SI); writeOneTypeOneOperandLayout(EMI->getKind(), 0, EMI->getType(), EMI->getOperand()); break; } case ValueKind::AllocValueBufferInst: { auto AVBI = cast(&SI); writeOneTypeOneOperandLayout(AVBI->getKind(), 0, AVBI->getValueType(), AVBI->getOperand()); break; } case ValueKind::AllocBoxInst: { const AllocBoxInst *ABI = cast(&SI); writeOneTypeLayout(ABI->getKind(), ABI->getElementType()); break; } case ValueKind::AllocRefInst: { const AllocRefInst *ARI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code]; ValueID Args[1] = { (unsigned)ARI->isObjC() | ((unsigned)ARI->canAllocOnStack() << 1) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef( ARI->getType().getSwiftRValueType()), (unsigned)ARI->getType().getCategory(), llvm::makeArrayRef(Args)); break; } case ValueKind::AllocRefDynamicInst: { const AllocRefDynamicInst* ARD = cast(&SI); unsigned flags = 0; if (ARD->isObjC()) flags = 1; writeOneTypeOneOperandLayout(SI.getKind(), flags, ARD->getType(), ARD->getOperand()); break; } case ValueKind::AllocStackInst: { const AllocStackInst *ASI = cast(&SI); writeOneTypeLayout(ASI->getKind(), ASI->getElementType()); break; } case ValueKind::ProjectValueBufferInst: { auto PVBI = cast(&SI); writeOneTypeOneOperandLayout(PVBI->getKind(), 0, PVBI->getValueType(), PVBI->getOperand()); break; } case ValueKind::ProjectBoxInst: { auto PBI = cast(&SI); writeOneTypeOneOperandLayout(PBI->getKind(), 0, PBI->getValueType(), PBI->getOperand()); break; } case ValueKind::ProjectExistentialBoxInst: { auto PEBI = cast(&SI); writeOneTypeOneOperandLayout(PEBI->getKind(), 0, PEBI->getValueType(), PEBI->getOperand()); break; } case ValueKind::BuiltinInst: { // Format: number of substitutions, 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().getSwiftRValueType())); Args.push_back((unsigned)Arg->getType().getCategory()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_BUILTIN, BI->getSubstitutions().size(), S.addTypeRef(BI->getType().getSwiftRValueType()), (unsigned)BI->getType().getCategory(), S.addIdentifierRef(BI->getName()), Args); S.writeSubstitutions(BI->getSubstitutions(), SILAbbrCodes); break; } case ValueKind::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)); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], AI->isNonThrowing() ? SIL_NON_THROWING_APPLY : SIL_APPLY, AI->getSubstitutions().size(), S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), Args); S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes); break; } case ValueKind::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()]); SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], SIL_TRY_APPLY, AI->getSubstitutions().size(), S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(AI->getSubstCalleeType()), addValueRef(AI->getCallee()), Args); S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes); break; } case ValueKind::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, PAI->getSubstitutions().size(), S.addTypeRef(PAI->getCallee()->getType().getSwiftRValueType()), S.addTypeRef(PAI->getSubstCalleeType()), addValueRef(PAI->getCallee()), Args); S.writeSubstitutions(PAI->getSubstitutions(), SILAbbrCodes); break; } case ValueKind::AllocGlobalInst: { // Format: Name and type. Use SILOneOperandLayout. const AllocGlobalInst *AGI = cast(&SI); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, 0, 0, S.addIdentifierRef( Ctx.getIdentifier(AGI->getReferencedGlobal()->getName()))); break; } case ValueKind::GlobalAddrInst: { // Format: Name and type. Use SILOneOperandLayout. const GlobalAddrInst *GAI = cast(&SI); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addTypeRef(GAI->getType().getSwiftRValueType()), (unsigned)GAI->getType().getCategory(), S.addIdentifierRef( Ctx.getIdentifier(GAI->getReferencedGlobal()->getName()))); break; } case ValueKind::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().getSwiftRValueType())); 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 ValueKind::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().getSwiftRValueType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } for (auto Elt : CBI->getFalseArgs()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); 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().getSwiftRValueType()), (unsigned)CBI->getCondition()->getType().getCategory(), ListOfValues); break; } case ValueKind::SwitchEnumInst: case ValueKind::SwitchEnumAddrInst: { // Format: condition, a list of cases (EnumElementDecl + Basic Block ID), // default basic block ID. Use SILOneTypeValuesLayout: the type is // for condition, the list has value for condition, hasDefault, default // basic block ID, a list of (DeclID, BasicBlock ID). const SwitchEnumInstBase *SOI = cast(&SI); 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]); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SOI->getOperand()->getType().getSwiftRValueType()), (unsigned)SOI->getOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::SelectEnumInst: case ValueKind::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). const SelectEnumInstBase *SOI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SOI->getEnumOperand())); ListOfValues.push_back(S.addTypeRef(SOI->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)SOI->getType().getCategory()); ListOfValues.push_back((unsigned)SOI->hasDefault()); if (SOI->hasDefault()) { ListOfValues.push_back(addValueRef(SOI->getDefaultResult())); } else { ListOfValues.push_back(0); } for (unsigned i = 0, e = SOI->getNumCases(); i < e; ++i) { EnumElementDecl *elt; SILValue result; std::tie(elt, result) = SOI->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(SOI->getEnumOperand()->getType().getSwiftRValueType()), (unsigned)SOI->getEnumOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::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().getSwiftRValueType()), (unsigned)SII->getOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::SelectValueInst: { // Format: condition, a list of cases (Value ID + 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 (Value ID, Value ID). const SelectValueInst *SVI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(SVI->getOperand())); ListOfValues.push_back(S.addTypeRef(SVI->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)SVI->getType().getCategory()); ListOfValues.push_back((unsigned)SVI->hasDefault()); if (SVI->hasDefault()) { ListOfValues.push_back(addValueRef(SVI->getDefaultResult())); } else { ListOfValues.push_back(0); } for (unsigned i = 0, e = SVI->getNumCases(); i < e; ++i) { SILValue casevalue; SILValue result; std::tie(casevalue, result) = SVI->getCase(i); ListOfValues.push_back(addValueRef(casevalue)); ListOfValues.push_back(addValueRef(result)); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SVI->getOperand()->getType().getSwiftRValueType()), (unsigned)SVI->getOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::CondFailInst: case ValueKind::RetainValueInst: case ValueKind::ReleaseValueInst: case ValueKind::AutoreleaseValueInst: case ValueKind::DeallocStackInst: case ValueKind::DeallocRefInst: case ValueKind::DeinitExistentialAddrInst: case ValueKind::DestroyAddrInst: case ValueKind::IsNonnullInst: case ValueKind::LoadInst: case ValueKind::LoadUnownedInst: case ValueKind::LoadWeakInst: case ValueKind::MarkUninitializedInst: case ValueKind::FixLifetimeInst: case ValueKind::CopyBlockInst: case ValueKind::StrongPinInst: case ValueKind::StrongReleaseInst: case ValueKind::StrongRetainInst: case ValueKind::StrongUnpinInst: case ValueKind::StrongRetainUnownedInst: case ValueKind::UnownedRetainInst: case ValueKind::UnownedReleaseInst: case ValueKind::IsUniqueInst: case ValueKind::IsUniqueOrPinnedInst: case ValueKind::ReturnInst: case ValueKind::ThrowInst: case ValueKind::DebugValueInst: case ValueKind::DebugValueAddrInst: { unsigned Attr = 0; if (auto *LWI = dyn_cast(&SI)) Attr = LWI->isTake(); else if (auto *LUI = dyn_cast(&SI)) Attr = LUI->isTake(); else if (auto *MUI = dyn_cast(&SI)) Attr = (unsigned)MUI->getKind(); else if (auto *DRI = dyn_cast(&SI)) Attr = (unsigned)DRI->canAllocOnStack(); writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0)); break; } case ValueKind::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().getSwiftRValueType()), (unsigned)FRI->getType().getCategory(), S.addIdentifierRef(Ctx.getIdentifier(ReferencedFunction->getName()))); // Make sure we declare the referenced function. FuncsToDeclare.insert(ReferencedFunction); break; } case ValueKind::DeallocPartialRefInst: case ValueKind::MarkDependenceInst: case ValueKind::IndexAddrInst: case ValueKind::IndexRawPointerInst: { SILValue operand, operand2; unsigned Attr = 0; if (SI.getKind() == ValueKind::DeallocPartialRefInst) { const DeallocPartialRefInst *DPRI = cast(&SI); operand = DPRI->getInstance(); operand2 = DPRI->getMetatype(); } else if (SI.getKind() == ValueKind::IndexRawPointerInst) { const IndexRawPointerInst *IRP = cast(&SI); operand = IRP->getBase(); operand2 = IRP->getIndex(); } else if (SI.getKind() == ValueKind::MarkDependenceInst) { const MarkDependenceInst *MDI = cast(&SI); operand = MDI->getValue(); operand2 = MDI->getBase(); } else { const IndexAddrInst *IAI = cast(&SI); operand = IAI->getBase(); operand2 = IAI->getIndex(); } SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), Attr, S.addTypeRef(operand->getType().getSwiftRValueType()), (unsigned)operand->getType().getCategory(), addValueRef(operand), S.addTypeRef(operand2->getType().getSwiftRValueType()), (unsigned)operand2->getType().getCategory(), addValueRef(operand2)); break; } case ValueKind::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.addIdentifierRef(Ctx.getIdentifier(Str))); break; } case ValueKind::FloatLiteralInst: case ValueKind::IntegerLiteralInst: { // Use SILOneOperandLayout to specify the type and the literal. std::string Str; SILType Ty; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::IntegerLiteralInst: Str = cast(&SI)->getValue().toString(10, true); Ty = cast(&SI)->getType(); break; case ValueKind::FloatLiteralInst: Str = cast(&SI)->getBits().toString(16, /*Signed*/false); Ty = cast(&SI)->getType(); break; } unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), S.addIdentifierRef(Ctx.getIdentifier(Str))); break; } case ValueKind::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().getSwiftRValueType())); 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 ValueKind::MetatypeInst: writeOneTypeLayout(SI.getKind(), SI.getType()); break; case ValueKind::ObjCProtocolInst: { const ObjCProtocolInst *PI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(PI->getType().getSwiftRValueType()), (unsigned)PI->getType().getCategory(), S.addDeclRef(PI->getProtocol())); break; } // Conversion instructions (and others of similar form). case ValueKind::OpenExistentialAddrInst: case ValueKind::OpenExistentialRefInst: case ValueKind::OpenExistentialMetatypeInst: case ValueKind::OpenExistentialBoxInst: case ValueKind::UncheckedRefCastInst: case ValueKind::UncheckedAddrCastInst: case ValueKind::UncheckedTrivialBitCastInst: case ValueKind::UncheckedBitwiseCastInst: case ValueKind::BridgeObjectToRefInst: case ValueKind::BridgeObjectToWordInst: case ValueKind::UpcastInst: case ValueKind::AddressToPointerInst: case ValueKind::PointerToAddressInst: case ValueKind::RefToRawPointerInst: case ValueKind::RawPointerToRefInst: case ValueKind::RefToUnownedInst: case ValueKind::UnownedToRefInst: case ValueKind::RefToUnmanagedInst: case ValueKind::UnmanagedToRefInst: case ValueKind::ThinToThickFunctionInst: case ValueKind::ThickToObjCMetatypeInst: case ValueKind::ObjCToThickMetatypeInst: case ValueKind::ConvertFunctionInst: case ValueKind::ThinFunctionToPointerInst: case ValueKind::PointerToThinFunctionInst: case ValueKind::ObjCMetatypeToObjectInst: case ValueKind::ObjCExistentialMetatypeToObjectInst: case ValueKind::ProjectBlockStorageInst: { writeConversionLikeInstruction(&SI); break; } case ValueKind::RefToBridgeObjectInst: { auto RI = cast(&SI); SILTwoOperandsLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(), /*attr*/ 0, S.addTypeRef(RI->getConverted()->getType().getSwiftRValueType()), (unsigned)RI->getConverted()->getType().getCategory(), addValueRef(RI->getConverted()), S.addTypeRef(RI->getBitsOperand()->getType().getSwiftRValueType()), (unsigned)RI->getBitsOperand()->getType().getCategory(), addValueRef(RI->getBitsOperand())); break; } // Checked Conversion instructions. case ValueKind::UnconditionalCheckedCastInst: { auto CI = cast(&SI); SILInstCastLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstCastLayout::Code], (unsigned)SI.getKind(), /*attr*/ 0, S.addTypeRef(CI->getType().getSwiftRValueType()), (unsigned)CI->getType().getCategory(), S.addTypeRef(CI->getOperand()->getType().getSwiftRValueType()), (unsigned)CI->getOperand()->getType().getCategory(), addValueRef(CI->getOperand())); break; } case ValueKind::UnconditionalCheckedCastAddrInst: { auto CI = cast(&SI); ValueID listOfValues[] = { toStableCastConsumptionKind(CI->getConsumptionKind()), S.addTypeRef(CI->getSourceType()), addValueRef(CI->getSrc()), S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()), (unsigned)CI->getSrc()->getType().getCategory(), S.addTypeRef(CI->getTargetType()), addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()), (unsigned)CI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } case ValueKind::UncheckedRefCastAddrInst: { auto CI = cast(&SI); ValueID listOfValues[] = { S.addTypeRef(CI->getSourceType()), addValueRef(CI->getSrc()), S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()), (unsigned)CI->getSrc()->getType().getCategory(), S.addTypeRef(CI->getTargetType()), addValueRef(CI->getDest()) }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()), (unsigned)CI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } case ValueKind::AssignInst: case ValueKind::CopyAddrInst: case ValueKind::StoreInst: case ValueKind::StoreUnownedInst: case ValueKind::StoreWeakInst: { SILValue operand, value; unsigned Attr = 0; if (SI.getKind() == ValueKind::StoreWeakInst) { Attr = cast(&SI)->isInitializationOfDest(); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == ValueKind::StoreUnownedInst) { Attr = cast(&SI)->isInitializationOfDest(); operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == ValueKind::StoreInst) { operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == ValueKind::AssignInst) { operand = cast(&SI)->getDest(); value = cast(&SI)->getSrc(); } else if (SI.getKind() == ValueKind::CopyAddrInst) { const CopyAddrInst *CAI = cast(&SI); Attr = (CAI->isInitializationOfDest() << 1) | CAI->isTakeOfSrc(); operand = cast(&SI)->getDest(); value = cast(&SI)->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().getSwiftRValueType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case ValueKind::RefElementAddrInst: case ValueKind::StructElementAddrInst: case ValueKind::StructExtractInst: case ValueKind::InitEnumDataAddrInst: case ValueKind::UncheckedEnumDataInst: case ValueKind::UncheckedTakeEnumDataAddrInst: case ValueKind::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; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::RefElementAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); break; case ValueKind::StructElementAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); break; case ValueKind::StructExtractInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getField(); break; case ValueKind::InitEnumDataAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case ValueKind::UncheckedEnumDataInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case ValueKind::UncheckedTakeEnumDataAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; case ValueKind::InjectEnumAddrInst: operand = cast(&SI)->getOperand(); tDecl = cast(&SI)->getElement(); break; } SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneValueOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addDeclRef(tDecl), S.addTypeRef(operand->getType().getSwiftRValueType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case ValueKind::StructInst: { // Format: a type followed by a list of typed values. A typed value is // expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber. const StructInst *StrI = cast(&SI); SmallVector ListOfValues; for (auto Elt : StrI->getElements()) { ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)Elt->getType().getCategory()); ListOfValues.push_back(addValueRef(Elt)); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(StrI->getType().getSwiftRValueType()), (unsigned)StrI->getType().getCategory(), ListOfValues); break; } case ValueKind::TupleElementAddrInst: case ValueKind::TupleExtractInst: { SILValue operand; unsigned FieldNo; switch (SI.getKind()) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::TupleElementAddrInst: operand = cast(&SI)->getOperand(); FieldNo = cast(&SI)->getFieldNo(); break; case ValueKind::TupleExtractInst: operand = cast(&SI)->getOperand(); FieldNo = cast(&SI)->getFieldNo(); 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().getSwiftRValueType()), (unsigned)operand->getType().getCategory(), addValueRef(operand)); break; } case ValueKind::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().getSwiftRValueType()), (unsigned)TI->getType().getCategory(), ListOfValues); break; } case ValueKind::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().getSwiftRValueType()) : (TypeID)0; 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().getSwiftRValueType()), (unsigned)UI->getType().getCategory(), S.addDeclRef(UI->getElement()), OperandTy, OperandTyCategory, UI->hasOperand() ? addValueRef(UI->getOperand()) : (ValueID)0); break; } case ValueKind::WitnessMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type. const WitnessMethodInst *AMI = cast(&SI); CanType Ty = AMI->getLookupType(); SILType Ty2 = AMI->getType(); SmallVector ListOfValues; handleSILDeclRef(S, AMI->getMember(), ListOfValues); // Add an optional operand. TypeID OperandTy = AMI->hasOperand() ? S.addTypeRef(AMI->getOperand()->getType().getSwiftRValueType()) : (TypeID)0; unsigned OperandTyCategory = AMI->hasOperand() ? (unsigned)AMI->getOperand()->getType().getCategory() : 0; SILValue OptionalOpenedExistential = AMI->hasOperand() ? AMI->getOperand() : SILValue(); auto OperandValueId = addValueRef(OptionalOpenedExistential); SILInstWitnessMethodLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[SILInstWitnessMethodLayout::Code], S.addTypeRef(Ty), 0, AMI->isVolatile(), S.addTypeRef(Ty2.getSwiftRValueType()), (unsigned)Ty2.getCategory(), OperandTy, OperandTyCategory, OperandValueId, ListOfValues); S.writeConformance(AMI->getConformance(), SILAbbrCodes); break; } case ValueKind::ClassMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), // 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.getSwiftRValueType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case ValueKind::SuperMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), // 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.getSwiftRValueType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case ValueKind::DynamicMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), // and an operand. const DynamicMethodInst *DMI = cast(&SI); SILType Ty = DMI->getType(); SmallVector ListOfValues; handleMethodInst(DMI, DMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case ValueKind::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().getSwiftRValueType()), (unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues); break; } case ValueKind::CheckedCastBranchInst: { // Format: the cast kind, a typed value, a BasicBlock ID for success, // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout. const CheckedCastBranchInst *CBI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(CBI->isExact()), ListOfValues.push_back(addValueRef(CBI->getOperand())); ListOfValues.push_back( S.addTypeRef(CBI->getOperand()->getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)CBI->getOperand()->getType().getCategory()); ListOfValues.push_back(BasicBlockMap[CBI->getSuccessBB()]); ListOfValues.push_back(BasicBlockMap[CBI->getFailureBB()]); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CBI->getCastType().getSwiftRValueType()), (unsigned)CBI->getCastType().getCategory(), ListOfValues); break; } case ValueKind::CheckedCastAddrBranchInst: { // Format: the cast kind, two typed values, a BasicBlock ID for // success, a BasicBlock ID for failure. Uses SILOneTypeValuesLayout; // the type is the type of the second (dest) operand. auto CBI = cast(&SI); ValueID listOfValues[] = { toStableCastConsumptionKind(CBI->getConsumptionKind()), S.addTypeRef(CBI->getSourceType()), addValueRef(CBI->getSrc()), S.addTypeRef(CBI->getSrc()->getType().getSwiftRValueType()), (unsigned)CBI->getSrc()->getType().getCategory(), S.addTypeRef(CBI->getTargetType()), addValueRef(CBI->getDest()), BasicBlockMap[CBI->getSuccessBB()], BasicBlockMap[CBI->getFailureBB()] }; SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(CBI->getDest()->getType().getSwiftRValueType()), (unsigned)CBI->getDest()->getType().getCategory(), llvm::makeArrayRef(listOfValues)); break; } case ValueKind::InitBlockStorageHeaderInst: { auto IBSHI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage())); ListOfValues.push_back( S.addTypeRef(IBSHI->getBlockStorage()->getType().getSwiftRValueType())); // Always an address, don't need to save category ListOfValues.push_back(addValueRef(IBSHI->getInvokeFunction())); ListOfValues.push_back( S.addTypeRef(IBSHI->getInvokeFunction()->getType().getSwiftRValueType())); // Always a value, don't need to save category SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(IBSHI->getType().getSwiftRValueType()), (unsigned)IBSHI->getType().getCategory(), ListOfValues); } } // Non-void values get registered in the value table. if (SI.hasValue()) { addValueRef(&SI); ++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(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_GLOBALVAR_NAMES || kind == sil_index_block::SIL_WITNESSTABLE_NAMES) && "SIL function table, global, vtable and witness table are supported"); llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { llvm::OnDiskChainedHashTableGenerator generator; for (auto &entry : table) generator.insert(entry.first, entry.second); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0. endian::Writer(blobStream).write(0); tableOffset = generator.Emit(blobStream); } SmallVector scratch; List.emit(scratch, kind, tableOffset, hashTableBlob); } void SILSerializer::writeIndexTables() { BCBlockRAII restoreBlock(Out, SIL_INDEX_BLOCK_ID, 4); sil_index_block::ListLayout List(Out); sil_index_block::OffsetLayout Offset(Out); if (!FuncTable.empty()) { writeIndexTable(List, sil_index_block::SIL_FUNC_NAMES, FuncTable); Offset.emit(ScratchRecord, sil_index_block::SIL_FUNC_OFFSETS, Funcs); } if (!VTableList.empty()) { writeIndexTable(List, sil_index_block::SIL_VTABLE_NAMES, VTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_VTABLE_OFFSETS, VTableOffset); } if (!GlobalVarList.empty()) { writeIndexTable(List, sil_index_block::SIL_GLOBALVAR_NAMES, GlobalVarList); Offset.emit(ScratchRecord, sil_index_block::SIL_GLOBALVAR_OFFSETS, GlobalVarOffset); } if (!WitnessTableList.empty()) { writeIndexTable(List, sil_index_block::SIL_WITNESSTABLE_NAMES, WitnessTableList); Offset.emit(ScratchRecord, sil_index_block::SIL_WITNESSTABLE_OFFSETS, WitnessTableOffset); } } void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) { GlobalVarList[Ctx.getIdentifier(g.getName())] = GlobalVarID++; GlobalVarOffset.push_back(Out.GetCurrentBitNo()); TypeID TyID = S.addTypeRef(g.getLoweredType().getSwiftType()); DeclID dID = S.addDeclRef(g.getDecl()); GlobalVarLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[GlobalVarLayout::Code], toStableSILLinkage(g.getLinkage()), (unsigned)g.isFragile(), TyID, dID, unsigned(!g.isDefinition()), unsigned(g.isLet())); } void SILSerializer::writeSILVTable(const SILVTable &vt) { VTableList[vt.getClass()->getName()] = VTableID++; VTableOffset.push_back(Out.GetCurrentBitNo()); VTableLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[VTableLayout::Code], S.addDeclRef(vt.getClass())); for (auto &entry : vt.getEntries()) { SmallVector ListOfValues; handleSILDeclRef(S, entry.first, ListOfValues); FuncsToDeclare.insert(entry.second); // Each entry is a pair of SILDeclRef and SILFunction. VTableEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[VTableEntryLayout::Code], // SILFunction name S.addIdentifierRef(Ctx.getIdentifier(entry.second->getName())), ListOfValues); } } void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) { WitnessTableList[wt.getIdentifier()] = WitnessTableID++; WitnessTableOffset.push_back(Out.GetCurrentBitNo()); WitnessTableLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[WitnessTableLayout::Code], toStableSILLinkage(wt.getLinkage()), unsigned(wt.isDeclaration()), unsigned(wt.isFragile())); S.writeConformance(wt.getConformance(), SILAbbrCodes); // If we have a declaration, do not attempt to serialize entries. if (wt.isDeclaration()) return; for (auto &entry : wt.getEntries()) { if (entry.getKind() == SILWitnessTable::BaseProtocol) { auto &baseWitness = entry.getBaseProtocolWitness(); WitnessBaseEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessBaseEntryLayout::Code], S.addDeclRef(baseWitness.Requirement)); S.writeConformance(baseWitness.Witness, SILAbbrCodes); continue; } if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) { auto &assoc = entry.getAssociatedTypeProtocolWitness(); WitnessAssocProtocolLayout::emitRecord( Out, ScratchRecord, SILAbbrCodes[WitnessAssocProtocolLayout::Code], S.addDeclRef(assoc.Requirement), S.addDeclRef(assoc.Protocol)); S.writeConformance(assoc.Witness, SILAbbrCodes); continue; } if (entry.getKind() == SILWitnessTable::AssociatedType) { auto &assoc = entry.getAssociatedTypeWitness(); WitnessAssocEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessAssocEntryLayout::Code], S.addDeclRef(assoc.Requirement), S.addTypeRef(assoc.Witness)); continue; } auto &methodWitness = entry.getMethodWitness(); SmallVector ListOfValues; handleSILDeclRef(S, methodWitness.Requirement, ListOfValues); FuncsToDeclare.insert(methodWitness.Witness); IdentifierID witnessID = 0; if (SILFunction *witness = methodWitness.Witness) { witnessID = S.addIdentifierRef(Ctx.getIdentifier(witness->getName())); } WitnessMethodEntryLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[WitnessMethodEntryLayout::Code], // SILFunction name witnessID, ListOfValues); } } /// Helper function for whether to emit a function body. bool SILSerializer::shouldEmitFunctionBody(const SILFunction &F) { // If F is a declaration, it has no body to emit... if (F.isExternalDeclaration()) return false; // If F is transparent, we should always emit its body. if (F.isFragile()) return true; // Otherwise serialize the body of the function only if we are asked to // serialize everything. 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(); // Register the abbreviation codes so these layouts can exist in both // decl blocks and sil blocks. // We have to make sure BOUND_GENERIC_SUBSTITUTION does not overlap with // SIL-specific records. registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); for (const SILGlobalVariable &g : SILMod->getSILGlobals()) writeSILGlobalVar(g); // 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. const DeclContext *assocDC = SILMod->getAssociatedContext(); for (const SILVTable &vt : SILMod->getVTables()) { if (ShouldSerializeAll && vt.getClass()->isChildContextOf(assocDC)) writeSILVTable(vt); } // Write out WitnessTables. For now, write out only if EnableSerializeAll. for (const SILWitnessTable &wt : SILMod->getWitnessTables()) { if (ShouldSerializeAll && wt.getConformance()->getDeclContext()->isChildContextOf(assocDC)) writeSILWitnessTable(wt); } // Go through all the SILFunctions in SILMod and write out any // mandatory function bodies. for (const SILFunction &F : *SILMod) { if (shouldEmitFunctionBody(F) || ShouldSerializeAll) writeSILFunction(F); } if (ShouldSerializeAll) return; // Now write function declarations for every function we've // emitted a reference to without emitting a function body for. for (const SILFunction &F : *SILMod) { if (!shouldEmitFunctionBody(F) && FuncsToDeclare.count(&F)) writeSILFunction(F, true); } } void SILSerializer::writeSILModule(const SILModule *SILMod) { writeSILBlock(SILMod); writeIndexTables(); } void Serializer::writeSIL(const SILModule *SILMod, bool serializeAllSIL) { if (!SILMod) return; SILSerializer SILSer(*this, M->getASTContext(), Out, serializeAllSIL); SILSer.writeSILModule(SILMod); }