//===--- SerializeSIL.cpp - Read and write SIL ----------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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 // //===----------------------------------------------------------------------===// #include "SILFormat.h" #include "Serialization.h" #include "swift/AST/Module.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILModule.h" // This is a template-only header; eventually it should move to llvm/Support. #include "clang/Basic/OnDiskHashTable.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" // To help testing serialization, deserialization, we turn on sil-serialize-all. static llvm::cl::opt EnableSerializeAll("sil-serialize-all", llvm::cl::Hidden, llvm::cl::init(false)); static llvm::cl::opt EnableSerialize("enable-sil-serialization", llvm::cl::Hidden, llvm::cl::init(true)); using namespace swift; using namespace swift::serialization; using namespace swift::serialization::sil_block; 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 &; uint32_t 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) { using namespace clang::io; uint32_t keyLength = key.str().size(); uint32_t dataLength = sizeof(DeclID); Emit16(out, keyLength); Emit16(out, 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"); using namespace clang::io; Emit32(out, 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 LastValueID = 0; ValueID addValueRef(SILValue SV) { return addValueRef(SV.getDef()); } ValueID addValueRef(const ValueBase *Val); /// FuncTable maps function name to an ID. using TableData = FuncTableInfo::data_type; using Table = llvm::DenseMap; Table FuncTable; std::vector Funcs; /// The current function ID. DeclID FuncID; /// Give each SILBasicBlock a unique ID. llvm::DenseMap BasicBlockMap; 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] << "\n"); } /// 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); void writeSILBasicBlock(const SILBasicBlock &BB); void writeSILInstruction(const SILInstruction &SI); void writeFuncTable(); public: SILSerializer(Serializer &S, ASTContext &Ctx, llvm::BitstreamWriter &Out); void writeAllSILFunctions(const SILModule *M); }; } // end anonymous namespace SILSerializer::SILSerializer(Serializer &S, ASTContext &Ctx, llvm::BitstreamWriter &Out) : S(S), Ctx(Ctx), Out(Out), FuncID(1) { } /// We enumerate all values to update ValueIDs in a separate pass /// to correctly handle forward reference of a value. ValueID SILSerializer::addValueRef(const ValueBase *Val) { if (!Val) return 0; ValueID &id = ValueIDs[Val]; if (id != 0) return id; id = ++LastValueID; return id; } void SILSerializer::writeSILFunction(const SILFunction &F) { DEBUG(llvm::dbgs() << "Serialize SIL:\n"; F.dump()); LastValueID = 0; 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 @" << Out.GetCurrentBitNo() << " abbrCode " << abbrCode << " FnID " << FnID << "\n"); SILFunctionLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)F.getLinkage(), FnID); // Assign a unique ID to each basic block of the SILFunction. unsigned BasicID = 0; BasicBlockMap.clear(); for (const SILBasicBlock &BB : F) BasicBlockMap.insert(std::make_pair(&BB, BasicID++)); 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); } /// 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()); ListOfValues.push_back(S.addDeclRef(MI->getMember().getDecl())); ListOfValues.push_back((unsigned)MI->getMember().kind); ListOfValues.push_back(MI->getMember().uncurryLevel); ListOfValues.push_back(MI->getMember().isObjC); ListOfValues.push_back( S.addTypeRef(operand.getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)operand.getType().getCategory()); ListOfValues.push_back(addValueRef(operand)); ListOfValues.push_back(operand.getResultNumber()); } void SILSerializer::writeSILInstruction(const SILInstruction &SI) { switch (SI.getKind()) { default: { unsigned abbrCode = SILAbbrCodes[SILInstTodoLayout::Code]; SILInstTodoLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind()); break; } case ValueKind::DeallocBoxInst: case ValueKind::InitExistentialInst: case ValueKind::InitExistentialRefInst: case ValueKind::ArchetypeMetatypeInst: case ValueKind::ClassMetatypeInst: case ValueKind::ProtocolMetatypeInst: case ValueKind::AllocArrayInst: { SILValue operand; SILType Ty; switch (SI.getKind()) { default: assert(0 && "Out of sync with parent switch"); case ValueKind::ArchetypeMetatypeInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ClassMetatypeInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::InitExistentialInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getConcreteType(); break; case ValueKind::InitExistentialRefInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ProtocolMetatypeInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::DeallocBoxInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getElementType(); break; case ValueKind::AllocArrayInst: operand = cast(&SI)->getNumElements(); Ty = cast(&SI)->getElementType(); break; } unsigned abbrCode = SILAbbrCodes[SILOneTypeOneOperandLayout::Code]; SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), 0, S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), S.addTypeRef(operand.getType().getSwiftRValueType()), (unsigned)operand.getType().getCategory(), addValueRef(operand), operand.getResultNumber()); break; } case ValueKind::AllocBoxInst: { const AllocBoxInst *ABI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(ABI->getElementType().getSwiftRValueType()), (unsigned)ABI->getElementType().getCategory()); break; } case ValueKind::AllocRefInst: { const AllocRefInst *ARI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(ARI->getType().getSwiftRValueType()), (unsigned)ARI->getType().getCategory()); break; } case ValueKind::AllocStackInst: { const AllocStackInst *ASI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(ASI->getElementType().getSwiftRValueType()), (unsigned)ASI->getElementType().getCategory()); break; } case ValueKind::BuiltinZeroInst: { const BuiltinZeroInst *BZI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(BZI->getType().getSwiftRValueType()), (unsigned)BZI->getType().getCategory()); break; } case ValueKind::ApplyInst: { // Format: attributes such as transparent, the callee's type, 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. const ApplyInst *AI = cast(&SI); SmallVector Args; for (auto Arg: AI->getArguments()) { Args.push_back(addValueRef(Arg)); Args.push_back(Arg.getResultNumber()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], 0/*Transparent*/, (unsigned)AI->isTransparent(), S.addTypeRef(AI->getCallee().getType().getSwiftRValueType()), (unsigned)AI->getCallee().getType().getCategory(), addValueRef(AI->getCallee()), AI->getCallee().getResultNumber(), Args); break; } case ValueKind::PartialApplyInst: { const PartialApplyInst *PAI = cast(&SI); SmallVector Args; for (auto Arg: PAI->getArguments()) { Args.push_back(addValueRef(Arg)); Args.push_back(Arg.getResultNumber()); } SILInstApplyLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILInstApplyLayout::Code], 1/*PartialApply*/, 0/*Transparent*/, S.addTypeRef(PAI->getCallee().getType().getSwiftRValueType()), (unsigned)PAI->getCallee().getType().getCategory(), addValueRef(PAI->getCallee()), PAI->getCallee().getResultNumber(), Args); break; } case ValueKind::BuiltinFunctionRefInst: { // Format: FuncDecl and type. Use SILOneOperandLayout. const BuiltinFunctionRefInst *BFR = cast(&SI); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addTypeRef(BFR->getType().getSwiftRValueType()), (unsigned)BFR->getType().getCategory(), S.addDeclRef(BFR->getFunction()), 0); break; } case ValueKind::GlobalAddrInst: { // Format: VarDecl 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.addDeclRef(GAI->getGlobal()), 0); 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)); ListOfValues.push_back(Elt.getResultNumber()); } 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(CBI->getCondition().getResultNumber()); 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)); ListOfValues.push_back(Elt.getResultNumber()); } 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)); ListOfValues.push_back(Elt.getResultNumber()); } 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::DestructiveSwitchEnumAddrInst: { // 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(SOI->getOperand().getResultNumber()); 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::DeallocStackInst: case ValueKind::DeallocRefInst: case ValueKind::DeinitExistentialInst: case ValueKind::DestroyAddrInst: case ValueKind::InitializeVarInst: case ValueKind::IsNonnullInst: case ValueKind::LoadInst: case ValueKind::LoadWeakInst: case ValueKind::MarkUninitializedInst: case ValueKind::StrongReleaseInst: case ValueKind::StrongRetainInst: case ValueKind::StrongRetainAutoreleasedInst: case ValueKind::AutoreleaseReturnInst: case ValueKind::StrongRetainUnownedInst: case ValueKind::UnownedRetainInst: case ValueKind::UnownedReleaseInst: case ValueKind::ReturnInst: { unsigned Attr = 0; if (SI.getKind() == ValueKind::LoadWeakInst) Attr = cast(&SI)->isTake(); else if (SI.getKind() == ValueKind::InitializeVarInst) Attr = cast(&SI)->canDefaultConstruct(); unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code]; SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), Attr, S.addTypeRef(SI.getOperand(0).getType().getSwiftRValueType()), (unsigned)SI.getOperand(0).getType().getCategory(), addValueRef(SI.getOperand(0)), SI.getOperand(0).getResultNumber()); break; } case ValueKind::FunctionRefInst: { // Use SILOneOperandLayout to specify the function type and the function // name (IdentifierID). const FunctionRefInst *FRI = cast(&SI); 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(FRI->getFunction()->getName())), 0); break; } case ValueKind::IndexAddrInst: case ValueKind::IndexRawPointerInst: case ValueKind::UpcastExistentialInst: { SILValue operand, operand2; unsigned Attr = 0; if (SI.getKind() == ValueKind::IndexRawPointerInst) { const IndexRawPointerInst *IRP = cast(&SI); operand = IRP->getBase(); operand2 = IRP->getIndex(); } else if (SI.getKind() == ValueKind::UpcastExistentialInst) { Attr = cast(&SI)->isTakeOfSrc(); operand = cast(&SI)->getSrcExistential(); operand2 = cast(&SI)->getDestExistential(); } 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), operand.getResultNumber(), S.addTypeRef(operand2.getType().getSwiftRValueType()), (unsigned)operand2.getType().getCategory(), addValueRef(operand2), operand2.getResultNumber()); break; } case ValueKind::FloatLiteralInst: case ValueKind::IntegerLiteralInst: case ValueKind::StringLiteralInst: { // Use SILOneOperandLayout to specify the type and the literal. StringRef Str; SILType Ty; switch (SI.getKind()) { default: assert(0 && "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; case ValueKind::StringLiteralInst: Str = cast(&SI)->getValue(); 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)), 0); 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)); ListOfValues.push_back(Elt.getResultNumber()); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), 0, 0, ListOfValues); break; } case ValueKind::MetatypeInst: { const MetatypeInst *MI = cast(&SI); unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code]; SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), S.addTypeRef(MI->getType().getSwiftRValueType()), (unsigned)MI->getType().getCategory()); break; } case ValueKind::ModuleInst: { // Has IdentifierID for the module reference. Use SILOneTypeLayout. const ModuleInst *MI = cast(&SI); ModuleType *MT = MI->getType().castTo(); SILOneTypeLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeLayout::Code], (unsigned)SI.getKind(), S.addModuleRef(MT->getModule()), 0); break; } case ValueKind::ProjectExistentialInst: { const ProjectExistentialInst *PEI = cast(&SI); SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addTypeRef(PEI->getType().getSwiftRValueType()), (unsigned)PEI->getType().getCategory(), S.addTypeRef(PEI->getOperand().getType().getSwiftRValueType()), (unsigned)PEI->getOperand().getType().getCategory(), addValueRef(PEI->getOperand()), PEI->getOperand().getResultNumber()); break; } case ValueKind::ProjectExistentialRefInst: { const ProjectExistentialRefInst *PEI = cast(&SI); SILOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addTypeRef(PEI->getOperand().getType().getSwiftRValueType()), (unsigned)PEI->getOperand().getType().getCategory(), addValueRef(PEI->getOperand()), PEI->getOperand().getResultNumber()); break; } // Conversion instructions. case ValueKind::RefToObjectPointerInst: case ValueKind::UpcastInst: case ValueKind::CoerceInst: case ValueKind::AddressToPointerInst: case ValueKind::PointerToAddressInst: case ValueKind::ObjectPointerToRefInst: case ValueKind::RefToRawPointerInst: case ValueKind::RawPointerToRefInst: case ValueKind::RefToUnownedInst: case ValueKind::UnownedToRefInst: case ValueKind::ConvertCCInst: case ValueKind::ThinToThickFunctionInst: case ValueKind::BridgeToBlockInst: case ValueKind::ArchetypeRefToSuperInst: case ValueKind::ConvertFunctionInst: case ValueKind::UpcastExistentialRefInst: { SILValue operand; SILType Ty; switch (SI.getKind()) { default: assert(0 && "Out of sync with parent switch"); case ValueKind::RefToObjectPointerInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::UpcastInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::CoerceInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::AddressToPointerInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::PointerToAddressInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ObjectPointerToRefInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::RefToRawPointerInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::RawPointerToRefInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::RefToUnownedInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::UnownedToRefInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ConvertCCInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ThinToThickFunctionInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::BridgeToBlockInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ArchetypeRefToSuperInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::ConvertFunctionInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; case ValueKind::UpcastExistentialRefInst: operand = cast(&SI)->getOperand(); Ty = cast(&SI)->getType(); break; } SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), 0, S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), S.addTypeRef(operand.getType().getSwiftRValueType()), (unsigned)operand.getType().getCategory(), addValueRef(operand), operand.getResultNumber()); break; } // Checked Conversion instructions. case ValueKind::DowncastInst: case ValueKind::SuperToArchetypeRefInst: case ValueKind::DowncastArchetypeAddrInst: case ValueKind::DowncastArchetypeRefInst: case ValueKind::ProjectDowncastExistentialAddrInst: case ValueKind::DowncastExistentialRefInst: { SILValue operand; const CheckedConversionInst *CI; switch (SI.getKind()) { default: assert(0 && "Out of sync with parent switch"); case ValueKind::DowncastInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; case ValueKind::SuperToArchetypeRefInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; case ValueKind::DowncastArchetypeAddrInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; case ValueKind::DowncastArchetypeRefInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; case ValueKind::ProjectDowncastExistentialAddrInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; case ValueKind::DowncastExistentialRefInst: operand = cast(&SI)->getOperand(); CI = cast(&SI); break; } SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeOneOperandLayout::Code], (unsigned)SI.getKind(), (unsigned)CI->getMode(), S.addTypeRef(CI->getType().getSwiftRValueType()), (unsigned)CI->getType().getCategory(), S.addTypeRef(operand.getType().getSwiftRValueType()), (unsigned)operand.getType().getCategory(), addValueRef(operand), operand.getResultNumber()); break; } case ValueKind::AssignInst: case ValueKind::CopyAddrInst: case ValueKind::StoreInst: 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::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), value.getResultNumber(), S.addTypeRef(operand.getType().getSwiftRValueType()), (unsigned)operand.getType().getCategory(), addValueRef(operand), operand.getResultNumber()); break; } case ValueKind::RefElementAddrInst: case ValueKind::StructElementAddrInst: case ValueKind::StructExtractInst: case ValueKind::EnumDataAddrInst: 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: assert(0 && "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::EnumDataAddrInst: 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), 0, S.addTypeRef(operand.getType().getSwiftRValueType()), (unsigned)operand.getType().getCategory(), addValueRef(operand), operand.getResultNumber()); 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)); ListOfValues.push_back(Elt.getResultNumber()); } 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: assert(0 && "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), operand.getResultNumber()); 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)); ListOfValues.push_back(Elt.getResultNumber()); } 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(), 0, S.addTypeRef(UI->getType().getSwiftRValueType()), (unsigned)UI->getType().getCategory(), S.addDeclRef(UI->getElement()), UI->hasOperand(), OperandTy, OperandTyCategory, UI->hasOperand() ? addValueRef(UI->getOperand()) : (ValueID)0, UI->hasOperand() ? UI->getOperand().getResultNumber() : 0); break; } case ValueKind::ArchetypeMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type. const ArchetypeMethodInst *AMI = cast(&SI); SILType Ty = AMI->getLookupArchetype(); SILType Ty2 = AMI->getType(0); SmallVector ListOfValues; ListOfValues.push_back(AMI->isVolatile()); ListOfValues.push_back(S.addDeclRef(AMI->getMember().getDecl())); ListOfValues.push_back((unsigned)AMI->getMember().kind); ListOfValues.push_back(AMI->getMember().uncurryLevel); ListOfValues.push_back(AMI->getMember().isObjC); ListOfValues.push_back(S.addTypeRef(Ty2.getSwiftRValueType())); ListOfValues.push_back((unsigned)Ty2.getCategory()); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), ListOfValues); break; } case ValueKind::ProtocolMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), // and an operand. const ProtocolMethodInst *PMI = cast(&SI); SILType Ty = PMI->getType(); SmallVector ListOfValues; handleMethodInst(PMI, PMI->getOperand(), ListOfValues); SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(Ty.getSwiftRValueType()), (unsigned)Ty.getCategory(), ListOfValues); 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())); ListOfValues.push_back(DMB->getOperand().getResultNumber()); ListOfValues.push_back(S.addDeclRef(DMB->getMember().getDecl())); ListOfValues.push_back((unsigned)DMB->getMember().kind); ListOfValues.push_back(DMB->getMember().uncurryLevel); ListOfValues.push_back(DMB->getMember().isObjC); 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::SpecializeInst: { // Format: a typed value, a type, a list of substitutions (Archetype name, // Replacement type). Use SILOneTypeValuesLayout. const SpecializeInst *SpI = cast(&SI); SmallVector ListOfValues; ListOfValues.push_back(S.addTypeRef( SpI->getOperand().getType().getSwiftRValueType())); ListOfValues.push_back((unsigned)SpI->getOperand().getType().getCategory()); ListOfValues.push_back(addValueRef(SpI->getOperand())); ListOfValues.push_back(SpI->getOperand().getResultNumber()); for (auto Sub : SpI->getSubstitutions()) { ListOfValues.push_back(S.addTypeRef(Sub.Archetype)); ListOfValues.push_back(S.addTypeRef(Sub.Replacement)); } SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(), S.addTypeRef(SpI->getType().getSwiftRValueType()), (unsigned)SpI->getType().getCategory(), ListOfValues); break; } } // Non-void values get registered in the value table. if (SI.hasValue()) { addValueRef(&SI); ++InstID; } } void SILSerializer::writeFuncTable() { using clang::OnDiskChainedHashTableGenerator; if (FuncTable.empty()) return; SmallVector scratch; llvm::SmallString<4096> hashTableBlob; uint32_t tableOffset; { OnDiskChainedHashTableGenerator generator; for (auto &entry : FuncTable) generator.insert(entry.first, entry.second); llvm::raw_svector_ostream blobStream(hashTableBlob); // Make sure that no bucket is at offset 0 clang::io::Emit32(blobStream, 0); tableOffset = generator.Emit(blobStream); } unsigned abbrCode = SILAbbrCodes[FuncListLayout::Code]; FuncListLayout::emitRecord(Out, ScratchRecord, abbrCode, tableOffset, hashTableBlob); abbrCode = SILAbbrCodes[FuncOffsetLayout::Code]; FuncOffsetLayout::emitRecord(Out, ScratchRecord, abbrCode, Funcs); } void SILSerializer::writeAllSILFunctions(const SILModule *M) { { BCBlockRAII subBlock(Out, SIL_BLOCK_ID, 4); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); registerSILAbbr(); // Go through all SILFunctions in M, and if it is transparent, // write out the SILFunction. for (const SILFunction &F : *M) { if ((EnableSerialize || EnableSerializeAll) && (EnableSerializeAll || F.isTransparent()) && !F.empty()) writeSILFunction(F); } } { BCBlockRAII restoreBlock(Out, SIL_INDEX_BLOCK_ID, 4); registerSILAbbr(); registerSILAbbr(); writeFuncTable(); } } void Serializer::writeSILFunctions(const SILModule *M) { if (!M) return; SILSerializer SILSer(*this, TU->Ctx, Out); SILSer.writeAllSILFunctions(M); }