//===--- DeserializeSIL.cpp - Read 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 "deserialize" #include "DeserializeSIL.h" #include "swift/Serialization/ModuleFile.h" #include "SILFormat.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/Serialization/BCReadingExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/OnDiskHashTable.h" using namespace swift; using namespace swift::serialization; using namespace swift::serialization::sil_block; using namespace llvm::support; STATISTIC(NumDeserializedFunc, "Number of deserialized SIL functions"); static Optional fromStableStringEncoding(unsigned value) { switch (value) { case SIL_UTF8: return StringLiteralInst::Encoding::UTF8; case SIL_UTF16: return StringLiteralInst::Encoding::UTF16; case SIL_OBJC_SELECTOR: return StringLiteralInst::Encoding::ObjCSelector; default: return None; } } static Optional fromStableSILLinkage(unsigned value) { switch (value) { case SIL_LINKAGE_PUBLIC: return SILLinkage::Public; case SIL_LINKAGE_HIDDEN: return SILLinkage::Hidden; case SIL_LINKAGE_SHARED: return SILLinkage::Shared; case SIL_LINKAGE_PRIVATE: return SILLinkage::Private; case SIL_LINKAGE_PUBLIC_EXTERNAL: return SILLinkage::PublicExternal; case SIL_LINKAGE_HIDDEN_EXTERNAL: return SILLinkage::HiddenExternal; case SIL_LINKAGE_SHARED_EXTERNAL: return SILLinkage::SharedExternal; case SIL_LINKAGE_PRIVATE_EXTERNAL: return SILLinkage::PrivateExternal; default: return None; } } /// Used to deserialize entries in the on-disk func hash table. class SILDeserializer::FuncTableInfo { public: using internal_key_type = StringRef; using external_key_type = StringRef; using data_type = DeclID; using hash_value_type = uint32_t; using offset_type = unsigned; internal_key_type GetInternalKey(external_key_type ID) { return ID; } external_key_type GetExternalKey(internal_key_type ID) { return ID; } hash_value_type ComputeHash(internal_key_type key) { return llvm::HashString(key); } static bool EqualKey(internal_key_type lhs, internal_key_type rhs) { return lhs == rhs; } static std::pair ReadKeyDataLength(const uint8_t *&data) { unsigned keyLength = endian::readNext(data); unsigned dataLength = endian::readNext(data); return { keyLength, dataLength }; } static internal_key_type ReadKey(const uint8_t *data, unsigned length) { return StringRef(reinterpret_cast(data), length); } static data_type ReadData(internal_key_type key, const uint8_t *data, unsigned length) { assert(length == 4 && "Expect a single DeclID."); data_type result = endian::readNext(data); return result; } }; SILDeserializer::SILDeserializer(ModuleFile *MF, SILModule &M, SerializedSILLoader::Callback *callback) : MF(MF), SILMod(M), Callback(callback) { SILCursor = MF->getSILCursor(); SILIndexCursor = MF->getSILIndexCursor(); // Early return if either sil block or sil index block does not exist. if (!SILCursor.getBitStreamReader() || !SILIndexCursor.getBitStreamReader()) return; // Load any abbrev records at the start of the block. SILCursor.advance(); llvm::BitstreamCursor cursor = SILIndexCursor; // We expect SIL_FUNC_NAMES first, then SIL_VTABLE_NAMES, then // SIL_GLOBALVAR_NAMES, and SIL_WITNESSTABLE_NAMES. But each one can be // omitted if no entries exist in the module file. unsigned kind = 0; while (kind != sil_index_block::SIL_WITNESSTABLE_NAMES) { auto next = cursor.advance(); if (next.Kind == llvm::BitstreamEntry::EndBlock) return; SmallVector scratch; StringRef blobData; unsigned prevKind = kind; kind = cursor.readRecord(next.ID, scratch, &blobData); assert((next.Kind == llvm::BitstreamEntry::Record && kind > prevKind && (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)) && "Expect SIL_FUNC_NAMES, SIL_VTABLE_NAMES, SIL_GLOBALVAR_NAMES or \ SIL_WITNESSTABLE_NAMES."); (void)prevKind; if (kind == sil_index_block::SIL_FUNC_NAMES) FuncTable = readFuncTable(scratch, blobData); else if (kind == sil_index_block::SIL_VTABLE_NAMES) VTableList = readFuncTable(scratch, blobData); else if (kind == sil_index_block::SIL_GLOBALVAR_NAMES) GlobalVarList = readFuncTable(scratch, blobData); else if (kind == sil_index_block::SIL_WITNESSTABLE_NAMES) WitnessTableList = readFuncTable(scratch, blobData); // Read SIL_FUNC|VTABLE|GLOBALVAR_OFFSETS record. next = cursor.advance(); scratch.clear(); unsigned offKind = cursor.readRecord(next.ID, scratch, &blobData); (void)offKind; if (kind == sil_index_block::SIL_FUNC_NAMES) { assert((next.Kind == llvm::BitstreamEntry::Record && offKind == sil_index_block::SIL_FUNC_OFFSETS) && "Expect a SIL_FUNC_OFFSETS record."); Funcs.assign(scratch.begin(), scratch.end()); } else if (kind == sil_index_block::SIL_VTABLE_NAMES) { assert((next.Kind == llvm::BitstreamEntry::Record && offKind == sil_index_block::SIL_VTABLE_OFFSETS) && "Expect a SIL_VTABLE_OFFSETS record."); VTables.assign(scratch.begin(), scratch.end()); } else if (kind == sil_index_block::SIL_GLOBALVAR_NAMES) { assert((next.Kind == llvm::BitstreamEntry::Record && offKind == sil_index_block::SIL_GLOBALVAR_OFFSETS) && "Expect a SIL_GLOBALVAR_OFFSETS record."); GlobalVars.assign(scratch.begin(), scratch.end()); } else if (kind == sil_index_block::SIL_WITNESSTABLE_NAMES) { assert((next.Kind == llvm::BitstreamEntry::Record && offKind == sil_index_block::SIL_WITNESSTABLE_OFFSETS) && "Expect a SIL_WITNESSTABLE_OFFSETS record."); WitnessTables.assign(scratch.begin(), scratch.end()); } } } std::unique_ptr SILDeserializer::readFuncTable(ArrayRef fields, StringRef blobData) { uint32_t tableOffset; sil_index_block::ListLayout::readRecord(fields, tableOffset); auto base = reinterpret_cast(blobData.data()); using OwnedTable = std::unique_ptr; return OwnedTable(SerializedFuncTable::Create(base + tableOffset, base + sizeof(uint32_t), base)); } /// A high-level overview of how forward references work in serializer and /// deserializer: /// In serializer, we pre-assign a value ID in order, to each basic block /// argument and each SILInstruction that has a value. /// In deserializer, we use LocalValues to store the definitions and /// ForwardLocalValues for forward-referenced values (values that are /// used but not yet defined). LocalValues are updated in setLocalValue where /// the ID passed in assumes the same ordering as in serializer: in-order /// for each basic block argument and each SILInstruction that has a value. /// We update ForwardLocalValues in getLocalValue and when a value is defined /// in setLocalValue, the corresponding entry in ForwardLocalValues will be /// erased. void SILDeserializer::setLocalValue(ValueBase *Value, ValueID Id) { ValueBase *&Entry = LocalValues[Id]; assert(!Entry && "We should not redefine the same value."); auto It = ForwardLocalValues.find(Id); if (It != ForwardLocalValues.end()) { // Take the information about the forward ref out of the map. ValueBase *Placeholder = It->second; // Remove the entries from the map. ForwardLocalValues.erase(It); Placeholder->replaceAllUsesWith(Value); } // Store it in our map. Entry = Value; } SILValue SILDeserializer::getLocalValue(ValueID Id, SILType Type) { if (Id == 0) return SILUndef::get(Type, &SILMod); // Check to see if this is already defined. ValueBase *Entry = LocalValues.lookup(Id); if (Entry) { // If this value was already defined, check it to make sure types match. assert(Entry->getType() == Type && "Value Type mismatch?"); return Entry; } // Otherwise, this is a forward reference. Create a dummy node to represent // it until we see a real definition. ValueBase *&Placeholder = ForwardLocalValues[Id]; if (!Placeholder) Placeholder = new (SILMod) GlobalAddrInst(SILDebugLocation(), Type); return Placeholder; } /// Return the SILBasicBlock of a given ID. SILBasicBlock *SILDeserializer::getBBForDefinition(SILFunction *Fn, SILBasicBlock *Prev, unsigned ID) { SILBasicBlock *&BB = BlocksByID[ID]; // If the block has never been named yet, just create it. if (BB == nullptr) return BB = new (SILMod) SILBasicBlock(Fn, Prev); // If it already exists, it was either a forward reference or a redefinition. // The latter should never happen. bool wasForwardReferenced = UndefinedBlocks.erase(BB); assert(wasForwardReferenced); (void)wasForwardReferenced; if (Prev) BB->moveAfter(Prev); return BB; } /// Return the SILBasicBlock of a given ID. SILBasicBlock *SILDeserializer::getBBForReference(SILFunction *Fn, unsigned ID) { SILBasicBlock *&BB = BlocksByID[ID]; if (BB != nullptr) return BB; // Otherwise, create it and remember that this is a forward reference BB = new (SILMod) SILBasicBlock(Fn); UndefinedBlocks[BB] = ID; return BB; } /// Helper function to convert from Type to SILType. static SILType getSILType(Type Ty, SILValueCategory Category) { auto TyLoc = TypeLoc::withoutLoc(Ty); return SILType::getPrimitiveType(TyLoc.getType()->getCanonicalType(), Category); } /// Helper function to create a bogus SILFunction to appease error paths. static SILFunction *createBogusSILFunction(SILModule &M, StringRef name, SILType type) { SourceLoc loc; return M.getOrCreateFunction( SILLinkage::Private, name, type.castTo(), nullptr, RegularLocation(loc), IsNotBare, IsNotTransparent, IsNotFragile, IsNotThunk, SILFunction::NotRelevant); } /// Helper function to find a SILFunction, given its name and type. SILFunction *SILDeserializer::getFuncForReference(StringRef name, SILType type) { // Check to see if we have a function by this name already. SILFunction *fn = SILMod.lookUpFunction(name); if (!fn) { // Otherwise, look for a function with this name in the module. auto iter = FuncTable->find(name); if (iter != FuncTable->end()) { fn = readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true); } } // FIXME: check for matching types. // Always return something of the right type. if (!fn) fn = createBogusSILFunction(SILMod, name, type); return fn; } /// Helper function to find a SILFunction, given its name and type. SILFunction *SILDeserializer::getFuncForReference(StringRef name) { // Check to see if we have a function by this name already. SILFunction *fn = SILMod.lookUpFunction(name); if (fn) return fn; // Otherwise, look for a function with this name in the module. auto iter = FuncTable->find(name); if (iter == FuncTable->end()) return nullptr; return readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true); } /// Helper function to find a SILGlobalVariable given its name. It first checks /// in the module. If we cannot find it in the module, we attempt to /// deserialize it. SILGlobalVariable *SILDeserializer::getGlobalForReference(StringRef name) { // Check to see if we have a global by this name already. if (SILGlobalVariable *g = SILMod.lookUpGlobalVariable(name)) return g; // Otherwise, look for a global with this name in the module. return readGlobalVar(name); } /// Deserialize a SILFunction if it is not already deserialized. The input /// SILFunction can either be an empty declaration or null. If it is an empty /// declaration, we fill in the contents. If the input SILFunction is /// null, we create a SILFunction. SILFunction *SILDeserializer::readSILFunction(DeclID FID, SILFunction *existingFn, StringRef name, bool declarationOnly, bool errorIfEmptyBody) { if (FID == 0) return nullptr; assert(FID <= Funcs.size() && "invalid SILFunction ID"); auto &cacheEntry = Funcs[FID-1]; if (cacheEntry.isFullyDeserialized() || (cacheEntry.isDeserialized() && declarationOnly)) return cacheEntry.get(); BCOffsetRAII restoreOffset(SILCursor); SILCursor.JumpToBit(cacheEntry.getOffset()); auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::Error) { DEBUG(llvm::dbgs() << "Cursor advance error in readSILFunction.\n"); MF->error(); return nullptr; } SmallVector scratch; StringRef blobData; unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); assert(kind == SIL_FUNCTION && "expect a sil function"); (void)kind; TypeID funcTyID; unsigned rawLinkage, isTransparent, isFragile, isThunk, isGlobal, inlineStrategy, effect; ArrayRef SemanticsIDs; // TODO: read fragile SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isFragile, isThunk, isGlobal, inlineStrategy, effect, funcTyID, SemanticsIDs); if (funcTyID == 0) { DEBUG(llvm::dbgs() << "SILFunction typeID is 0.\n"); MF->error(); return nullptr; } auto ty = getSILType(MF->getType(funcTyID), SILValueCategory::Object); if (!ty.is()) { DEBUG(llvm::dbgs() << "not a function type for SILFunction\n"); MF->error(); return nullptr; } auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage << " for SILFunction\n"); MF->error(); return nullptr; } // If we weren't handed a function, check for an existing // declaration in the output module. if (!existingFn) existingFn = SILMod.lookUpFunction(name); auto fn = existingFn; // TODO: use the correct SILLocation from module. SILLocation loc = RegularLocation(SourceLoc()); // If we have an existing function, verify that the types match up. if (fn) { if (fn->getLoweredType() != ty) { DEBUG(llvm::dbgs() << "SILFunction type mismatch.\n"); MF->error(); return nullptr; } if (isFragile) fn->setFragile(IsFragile); // Don't override the transparency or linkage of a function with // an existing declaration. // Otherwise, create a new function. } else { fn = SILMod.getOrCreateFunction( linkage.getValue(), name, ty.castTo(), nullptr, loc, IsNotBare, IsTransparent_t(isTransparent == 1), IsFragile_t(isFragile == 1), IsThunk_t(isThunk), SILFunction::NotRelevant, (Inline_t)inlineStrategy); fn->setGlobalInit(isGlobal == 1); fn->setEffectsKind((EffectsKind)effect); for (auto ID : SemanticsIDs) { fn->addSemanticsAttr(MF->getIdentifier(ID).str()); } if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), fn); } assert(fn->empty() && "SILFunction to be deserialized starts being empty."); fn->setBare(IsBare); if (!fn->hasLocation()) fn->setLocation(loc); const SILDebugScope *DS = fn->getDebugScope(); if (!DS) { DS = new (SILMod) SILDebugScope(loc, fn); fn->setDebugScope(DS); } GenericParamList *contextParams = nullptr; if (!declarationOnly) { // We need to construct a linked list of GenericParamList. The outermost // list appears first in the module file. Force the declaration's context to // be the current module, not the original module associated with this // module file. A generic param decl at module scope cannot refer to another // module because we would have no way lookup the original module when // serializing a copy of the function. This comes up with generic // reabstraction thunks which have shared linkage. DeclContext *outerParamContext = SILMod.getSwiftModule(); while(true) { // Params' OuterParameters will point to contextParams. auto *Params = MF->maybeReadGenericParams(outerParamContext, SILCursor, contextParams); if (!Params) break; // contextParams will point to the last deserialized list, which is the // innermost one. contextParams = Params; } } // If the next entry is the end of the block, then this function has // no contents. entry = SILCursor.advance(AF_DontPopBlockAtEnd); bool isEmptyFunction = (entry.Kind == llvm::BitstreamEntry::EndBlock); assert((!isEmptyFunction || !contextParams) && "context params without body?!"); // Remember this in our cache in case it's a recursive function. // Increase the reference count to keep it alive. bool isFullyDeserialized = (isEmptyFunction || !declarationOnly); if (cacheEntry.isDeserialized()) { assert(fn == cacheEntry.get() && "changing SIL function during deserialization!"); } else { fn->incrementRefCount(); } cacheEntry.set(fn, isFullyDeserialized); // Stop here if we have nothing else to do. if (isEmptyFunction || declarationOnly) { return fn; } NumDeserializedFunc++; scratch.clear(); assert(!(fn->getContextGenericParams() && !fn->empty()) && "function already has context generic params?!"); if (contextParams) fn->setContextGenericParams(contextParams); kind = SILCursor.readRecord(entry.ID, scratch); SILBasicBlock *CurrentBB = nullptr; // Clear up at the beginning of each SILFunction. BasicBlockID = 0; BlocksByID.clear(); UndefinedBlocks.clear(); LastValueID = 0; LocalValues.clear(); ForwardLocalValues.clear(); // Another SIL_FUNCTION record means the end of this SILFunction. // SIL_VTABLE or SIL_GLOBALVAR or SIL_WITNESSTABLE record also means the end // of this SILFunction. while (kind != SIL_FUNCTION && kind != SIL_VTABLE && kind != SIL_GLOBALVAR && kind != SIL_WITNESSTABLE) { if (kind == SIL_BASIC_BLOCK) // Handle a SILBasicBlock record. CurrentBB = readSILBasicBlock(fn, CurrentBB, scratch); else { // If CurrentBB is empty, just return fn. The code in readSILInstruction // assumes that such a situation means that fn is a declaration. Thus it // is using return false to mean two different things, error a failure // occurred and this is a declaration. Work around that for now. if (!CurrentBB) return fn; // Handle a SILInstruction record. if (readSILInstruction(fn, CurrentBB, kind, scratch)) { DEBUG(llvm::dbgs() << "readSILInstruction returns error.\n"); MF->error(); return fn; } } // Fetch the next record. scratch.clear(); entry = SILCursor.advance(AF_DontPopBlockAtEnd); // EndBlock means the end of this SILFunction. if (entry.Kind == llvm::BitstreamEntry::EndBlock) break; kind = SILCursor.readRecord(entry.ID, scratch); } // If fn is empty, we failed to deserialize its body. Return nullptr to signal // error. if (fn->empty() && errorIfEmptyBody) return nullptr; if (Callback) Callback->didDeserializeFunctionBody(MF->getAssociatedModule(), fn); return fn; } SILBasicBlock *SILDeserializer::readSILBasicBlock(SILFunction *Fn, SILBasicBlock *Prev, SmallVectorImpl &scratch) { ArrayRef Args; SILBasicBlockLayout::readRecord(scratch, Args); // Args should be a list of pairs, the first number is a TypeID, the // second number is a ValueID. SILBasicBlock *CurrentBB = getBBForDefinition(Fn, Prev, BasicBlockID++); for (unsigned I = 0, E = Args.size(); I < E; I += 3) { TypeID TyID = Args[I]; if (!TyID) return nullptr; ValueID ValId = Args[I+2]; if (!ValId) return nullptr; auto ArgTy = MF->getType(TyID); auto Arg = new (SILMod) SILArgument(CurrentBB, getSILType(ArgTy, (SILValueCategory)Args[I+1])); LastValueID = LastValueID + 1; setLocalValue(Arg, LastValueID); } return CurrentBB; } static CastConsumptionKind getCastConsumptionKind(unsigned attr) { switch (attr) { case SIL_CAST_CONSUMPTION_TAKE_ALWAYS: return CastConsumptionKind::TakeAlways; case SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS: return CastConsumptionKind::TakeOnSuccess; case SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS: return CastConsumptionKind::CopyOnSuccess; default: llvm_unreachable("not a valid CastConsumptionKind for SIL"); } } /// Construct a SILDeclRef from ListOfValues. static SILDeclRef getSILDeclRef(ModuleFile *MF, ArrayRef ListOfValues, unsigned &NextIdx) { assert(ListOfValues.size() >= NextIdx+5 && "Expect 5 numbers for SILDeclRef"); SILDeclRef DRef(cast(MF->getDecl(ListOfValues[NextIdx])), (SILDeclRef::Kind)ListOfValues[NextIdx+1], (ResilienceExpansion)ListOfValues[NextIdx+2], ListOfValues[NextIdx+3], ListOfValues[NextIdx+4] > 0); NextIdx += 5; return DRef; } bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, unsigned RecordKind, SmallVectorImpl &scratch) { // Return error if Basic Block is null. if (!BB) return true; SILBuilder Builder(BB); Builder.setCurrentDebugScope(Fn->getDebugScope()); unsigned OpCode = 0, TyCategory = 0, TyCategory2 = 0, TyCategory3 = 0, Attr = 0, NumSubs = 0, NumConformances = 0, IsNonThrowingApply = 0; ValueID ValID, ValID2, ValID3; TypeID TyID, TyID2, TyID3; TypeID ConcreteTyID; ModuleID OwningModuleID; SourceLoc SLoc; ArrayRef ListOfValues; SILLocation Loc = RegularLocation(SLoc); switch (RecordKind) { default: llvm_unreachable("Record kind for a SIL instruction is not supported."); case SIL_ONE_VALUE_ONE_OPERAND: SILOneValueOneOperandLayout::readRecord(scratch, OpCode, Attr, ValID, TyID, TyCategory, ValID2); break; case SIL_ONE_TYPE: SILOneTypeLayout::readRecord(scratch, OpCode, TyID, TyCategory); break; case SIL_ONE_OPERAND: SILOneOperandLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, ValID); break; case SIL_ONE_TYPE_ONE_OPERAND: SILOneTypeOneOperandLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, TyID2, TyCategory2, ValID); break; case SIL_INIT_EXISTENTIAL: SILInitExistentialLayout::readRecord(scratch, OpCode, TyID, TyCategory, TyID2, TyCategory2, ValID, ConcreteTyID, NumConformances); break; case SIL_INST_CAST: SILInstCastLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, TyID2, TyCategory2, ValID); break; case SIL_ONE_TYPE_VALUES: SILOneTypeValuesLayout::readRecord(scratch, OpCode, TyID, TyCategory, ListOfValues); break; case SIL_TWO_OPERANDS: SILTwoOperandsLayout::readRecord(scratch, OpCode, Attr, TyID, TyCategory, ValID, TyID2, TyCategory2, ValID2); break; case SIL_INST_APPLY: { unsigned IsPartial; SILInstApplyLayout::readRecord(scratch, IsPartial, NumSubs, TyID, TyID2, ValID, ListOfValues); switch (IsPartial) { case SIL_APPLY: OpCode = (unsigned)ValueKind::ApplyInst; break; case SIL_PARTIAL_APPLY: OpCode = (unsigned)ValueKind::PartialApplyInst; break; case SIL_BUILTIN: OpCode = (unsigned)ValueKind::BuiltinInst; break; case SIL_TRY_APPLY: OpCode = (unsigned)ValueKind::TryApplyInst; break; case SIL_NON_THROWING_APPLY: OpCode = (unsigned)ValueKind::ApplyInst; IsNonThrowingApply = true; break; default: llvm_unreachable("unexpected apply inst kind"); } break; } case SIL_INST_NO_OPERAND: SILInstNoOperandLayout::readRecord(scratch, OpCode); break; case SIL_INST_WITNESS_METHOD: SILInstWitnessMethodLayout::readRecord( scratch, TyID, TyCategory, Attr, TyID2, TyCategory2, TyID3, TyCategory3, ValID3, ListOfValues); OpCode = (unsigned)ValueKind::WitnessMethodInst; break; } ValueBase *ResultVal; switch ((ValueKind)OpCode) { case ValueKind::SILArgument: case ValueKind::SILUndef: llvm_unreachable("not an instruction"); #define ONETYPE_INST(ID) \ case ValueKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); \ ResultVal = Builder.create##ID(Loc, \ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));\ break; ONETYPE_INST(AllocBox) ONETYPE_INST(AllocStack) ONETYPE_INST(Metatype) #undef ONETYPE_INST #define ONETYPE_ONEOPERAND_INST(ID) \ case ValueKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ ResultVal = Builder.create##ID(Loc, \ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), \ getLocalValue(ValID, \ getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2))); \ break; ONETYPE_ONEOPERAND_INST(DeallocBox) ONETYPE_ONEOPERAND_INST(ValueMetatype) ONETYPE_ONEOPERAND_INST(ExistentialMetatype) ONETYPE_ONEOPERAND_INST(AllocValueBuffer) ONETYPE_ONEOPERAND_INST(ProjectValueBuffer) ONETYPE_ONEOPERAND_INST(ProjectBox) ONETYPE_ONEOPERAND_INST(ProjectExistentialBox) ONETYPE_ONEOPERAND_INST(DeallocValueBuffer) #undef ONETYPE_ONEOPERAND_INST #define ONEOPERAND_ONETYPE_INST(ID) \ case ValueKind::ID##Inst: \ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ "Layout should be OneTypeOneOperand."); \ ResultVal = Builder.create##ID(Loc, \ getLocalValue(ValID, \ getSILType(MF->getType(TyID2), \ (SILValueCategory)TyCategory2)), \ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));\ break; ONEOPERAND_ONETYPE_INST(OpenExistentialAddr) ONEOPERAND_ONETYPE_INST(OpenExistentialRef) ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype) ONEOPERAND_ONETYPE_INST(OpenExistentialBox) // Conversion instructions. ONEOPERAND_ONETYPE_INST(UncheckedRefCast) ONEOPERAND_ONETYPE_INST(UncheckedAddrCast) ONEOPERAND_ONETYPE_INST(UncheckedTrivialBitCast) ONEOPERAND_ONETYPE_INST(UncheckedBitwiseCast) ONEOPERAND_ONETYPE_INST(BridgeObjectToRef) ONEOPERAND_ONETYPE_INST(BridgeObjectToWord) ONEOPERAND_ONETYPE_INST(Upcast) ONEOPERAND_ONETYPE_INST(AddressToPointer) ONEOPERAND_ONETYPE_INST(PointerToAddress) ONEOPERAND_ONETYPE_INST(RefToRawPointer) ONEOPERAND_ONETYPE_INST(RawPointerToRef) ONEOPERAND_ONETYPE_INST(RefToUnowned) ONEOPERAND_ONETYPE_INST(UnownedToRef) ONEOPERAND_ONETYPE_INST(RefToUnmanaged) ONEOPERAND_ONETYPE_INST(UnmanagedToRef) ONEOPERAND_ONETYPE_INST(ThinToThickFunction) ONEOPERAND_ONETYPE_INST(ThickToObjCMetatype) ONEOPERAND_ONETYPE_INST(ObjCToThickMetatype) ONEOPERAND_ONETYPE_INST(ObjCMetatypeToObject) ONEOPERAND_ONETYPE_INST(ObjCExistentialMetatypeToObject) ONEOPERAND_ONETYPE_INST(ConvertFunction) ONEOPERAND_ONETYPE_INST(ThinFunctionToPointer) ONEOPERAND_ONETYPE_INST(PointerToThinFunction) ONEOPERAND_ONETYPE_INST(ProjectBlockStorage) #undef ONEOPERAND_ONETYPE_INST case ValueKind::DeallocExistentialBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); ResultVal = Builder.createDeallocExistentialBox(Loc, MF->getType(TyID)->getCanonicalType(), getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2))); break; } case ValueKind::RefToBridgeObjectInst: { auto RefTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto Ref = getLocalValue(ValID, RefTy); auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2); auto Bits = getLocalValue(ValID2, BitsTy); ResultVal = Builder.createRefToBridgeObject(Loc, Ref, Bits); break; } case ValueKind::ObjCProtocolInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto Proto = MF->getDecl(ValID); ResultVal = Builder.createObjCProtocol(Loc, cast(Proto), Ty); break; } case ValueKind::InitExistentialAddrInst: case ValueKind::InitExistentialMetatypeInst: case ValueKind::InitExistentialRefInst: case ValueKind::AllocExistentialBoxInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto Ty2 = MF->getType(TyID2); CanType ConcreteTy; if ((ValueKind) OpCode != ValueKind::InitExistentialMetatypeInst) ConcreteTy = MF->getType(ConcreteTyID)->getCanonicalType(); SILValue operand; if ((ValueKind) OpCode != ValueKind::AllocExistentialBoxInst) operand = getLocalValue(ValID, getSILType(Ty2, (SILValueCategory)TyCategory2)); SmallVector conformances; while (NumConformances--) { auto conformance = MF->readConformance(SILCursor); conformances.push_back(conformance); } auto ctxConformances = MF->getContext().AllocateCopy(conformances); switch ((ValueKind)OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::InitExistentialAddrInst: ResultVal = Builder.createInitExistentialAddr(Loc, operand, ConcreteTy, Ty, ctxConformances); break; case ValueKind::InitExistentialMetatypeInst: ResultVal = Builder.createInitExistentialMetatype(Loc, operand, Ty, ctxConformances); break; case ValueKind::InitExistentialRefInst: ResultVal = Builder.createInitExistentialRef(Loc, Ty, ConcreteTy, operand, ctxConformances); break; case ValueKind::AllocExistentialBoxInst: ResultVal = Builder.createAllocExistentialBox(Loc, Ty, ConcreteTy, ctxConformances); break; } break; } case ValueKind::AllocRefInst: { assert(RecordKind == SIL_ONE_TYPE_VALUES && "Layout should be OneTypeValues."); assert(ListOfValues.size() >= 1 && "Not enough values"); unsigned Value = ListOfValues[0]; ResultVal = Builder.createAllocRef( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), (bool)(Value & 1), (bool)((Value >> 1) & 1)); break; } case ValueKind::AllocRefDynamicInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); bool isObjC = Attr & 0x01; ResultVal = Builder.createAllocRefDynamic( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)), getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), isObjC); 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. auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); SILType FnTy = getSILType(Ty, SILValueCategory::Object); SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object); SILFunctionType *FTI = SubstFnTy.castTo(); assert(FTI->getNumSILArguments() == ListOfValues.size() && "Argument number mismatch in ApplyInst."); SmallVector Args; for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) Args.push_back(getLocalValue(ListOfValues[I],FTI->getSILArgumentType(I))); unsigned NumSub = NumSubs; SmallVector Substitutions; while (NumSub--) { auto sub = MF->maybeReadSubstitution(SILCursor); assert(sub.hasValue() && "missing substitution"); Substitutions.push_back(*sub); } ResultVal = Builder.createApply(Loc, getLocalValue(ValID, FnTy), SubstFnTy, FTI->getSILResult(), Substitutions, Args, IsNonThrowingApply != 0); break; } case ValueKind::TryApplyInst: { // 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. The final // two values in the list are the basic block identifiers. auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); SILType FnTy = getSILType(Ty, SILValueCategory::Object); SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object); SILBasicBlock *errorBB = getBBForReference(Fn, ListOfValues.back()); ListOfValues = ListOfValues.drop_back(); SILBasicBlock *normalBB = getBBForReference(Fn, ListOfValues.back()); ListOfValues = ListOfValues.drop_back(); SILFunctionType *FTI = SubstFnTy.castTo(); assert(FTI->getNumSILArguments() == ListOfValues.size() && "Argument number mismatch in ApplyInst."); SmallVector Args; for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) Args.push_back(getLocalValue(ListOfValues[I],FTI->getSILArgumentType(I))); unsigned NumSub = NumSubs; SmallVector Substitutions; while (NumSub--) { auto sub = MF->maybeReadSubstitution(SILCursor); assert(sub.hasValue() && "missing substitution"); Substitutions.push_back(*sub); } ResultVal = Builder.createTryApply(Loc, getLocalValue(ValID, FnTy), SubstFnTy, Substitutions, Args, normalBB, errorBB); break; } case ValueKind::PartialApplyInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); SILType FnTy = getSILType(Ty, SILValueCategory::Object); SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object); SILFunctionType *FTI = SubstFnTy.castTo(); auto ArgTys = FTI->getParameterSILTypes(); assert(ArgTys.size() >= ListOfValues.size() && "Argument number mismatch in PartialApplyInst."); SILValue FnVal = getLocalValue(ValID, FnTy); SmallVector Args; unsigned unappliedArgs = ArgTys.size() - ListOfValues.size(); for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) Args.push_back(getLocalValue(ListOfValues[I], ArgTys[I + unappliedArgs])); // Compute the result type of the partial_apply, based on which arguments // are getting applied. SILType closureTy = SILBuilder::getPartialApplyResultType(SubstFnTy, Args.size(), Fn->getModule(), {}); unsigned NumSub = NumSubs; SmallVector Substitutions; while (NumSub--) { auto sub = MF->maybeReadSubstitution(SILCursor); assert(sub.hasValue() && "missing substitution"); Substitutions.push_back(*sub); } // FIXME: Why the arbitrary order difference in IRBuilder type argument? ResultVal = Builder.createPartialApply(Loc, FnVal, SubstFnTy, Substitutions, Args, closureTy); break; } case ValueKind::BuiltinInst: { auto ASTTy = MF->getType(TyID); auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2); SmallVector Args; for (unsigned i = 0, e = ListOfValues.size(); i < e; i += 3) { auto ArgASTTy = MF->getType(ListOfValues[i+1]); auto ArgTy = getSILType(ArgASTTy, (SILValueCategory)(unsigned)ListOfValues[i+2]); Args.push_back(getLocalValue(ListOfValues[i], ArgTy)); } unsigned NumSub = NumSubs; SmallVector Substitutions; while (NumSub--) { auto sub = MF->maybeReadSubstitution(SILCursor); assert(sub.hasValue() && "missing substitution"); Substitutions.push_back(*sub); } Identifier Name = MF->getIdentifier(ValID); ResultVal = Builder.createBuiltin(Loc, Name, ResultTy, Substitutions, Args); break; } case ValueKind::AllocGlobalInst: { // Format: Name and type. Use SILOneOperandLayout. Identifier Name = MF->getIdentifier(ValID); // Find the global variable. SILGlobalVariable *g = getGlobalForReference(Name.str()); assert(g && "Can't deserialize global variable"); ResultVal = Builder.createAllocGlobal(Loc, g); break; } case ValueKind::GlobalAddrInst: { // Format: Name and type. Use SILOneOperandLayout. auto Ty = MF->getType(TyID); Identifier Name = MF->getIdentifier(ValID); // Find the global variable. SILGlobalVariable *g = getGlobalForReference(Name.str()); assert(g && "Can't deserialize global variable"); assert(g->getLoweredType().getAddressType() == getSILType(Ty, (SILValueCategory)TyCategory) && "Type of a global variable does not match GlobalAddr."); (void)Ty; ResultVal = Builder.createGlobalAddr(Loc, g); break; } case ValueKind::DeallocStackInst: { auto Ty = MF->getType(TyID); ResultVal = Builder.createDeallocStack(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory))); break; } case ValueKind::DeallocRefInst: { auto Ty = MF->getType(TyID); bool OnStack = (bool)Attr; ResultVal = Builder.createDeallocRef(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), OnStack); break; } case ValueKind::DeallocPartialRefInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createDeallocPartialRef(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } case ValueKind::FunctionRefInst: { auto Ty = MF->getType(TyID); Identifier FuncName = MF->getIdentifier(ValID); ResultVal = Builder.createFunctionRef(Loc, getFuncForReference(FuncName.str(), getSILType(Ty, (SILValueCategory)TyCategory))); break; } case ValueKind::MarkDependenceInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createMarkDependence(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } case ValueKind::IndexAddrInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createIndexAddr(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } case ValueKind::IndexRawPointerInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createIndexRawPointer(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); break; } case ValueKind::IntegerLiteralInst: { auto Ty = MF->getType(TyID); auto intTy = Ty->getAs(); Identifier StringVal = MF->getIdentifier(ValID); // Build APInt from string. APInt value(intTy->getGreatestWidth(), StringVal.str(), 10); ResultVal = Builder.createIntegerLiteral(Loc, getSILType(Ty, (SILValueCategory)TyCategory), value); break; } case ValueKind::FloatLiteralInst: { auto Ty = MF->getType(TyID); auto floatTy = Ty->getAs(); Identifier StringVal = MF->getIdentifier(ValID); // Build APInt from string. APInt bits(floatTy->getBitWidth(), StringVal.str(), 16); if (bits.getBitWidth() != floatTy->getBitWidth()) bits = bits.zextOrTrunc(floatTy->getBitWidth()); APFloat value(floatTy->getAPFloatSemantics(), bits); ResultVal = Builder.createFloatLiteral(Loc, getSILType(Ty, (SILValueCategory)TyCategory), value); break; } case ValueKind::StringLiteralInst: { Identifier StringVal = MF->getIdentifier(ValID); auto encoding = fromStableStringEncoding(Attr); if (!encoding) return true; ResultVal = Builder.createStringLiteral(Loc, StringVal.str(), encoding.getValue()); break; } case ValueKind::MarkFunctionEscapeInst: { // Format: a list of typed values. A typed value is expressed by 4 IDs: // TypeID, TypeCategory, ValueID, ValueResultNumber. SmallVector OpList; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); OpList.push_back( getLocalValue(ListOfValues[I+2], getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); } ResultVal = Builder.createMarkFunctionEscape(Loc, OpList); break; } // Checked Conversion instructions. case ValueKind::UnconditionalCheckedCastInst: { SILValue Val = getLocalValue(ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); ResultVal = Builder.createUnconditionalCheckedCast(Loc, Val, Ty); break; } #define UNARY_INSTRUCTION(ID) \ case ValueKind::ID##Inst: \ assert(RecordKind == SIL_ONE_OPERAND && \ "Layout should be OneOperand."); \ ResultVal = Builder.create##ID(Loc, getLocalValue(ValID, \ getSILType(MF->getType(TyID), \ (SILValueCategory)TyCategory))); \ break; UNARY_INSTRUCTION(CondFail) UNARY_INSTRUCTION(RetainValue) UNARY_INSTRUCTION(ReleaseValue) UNARY_INSTRUCTION(AutoreleaseValue) UNARY_INSTRUCTION(DeinitExistentialAddr) UNARY_INSTRUCTION(DestroyAddr) UNARY_INSTRUCTION(IsNonnull) UNARY_INSTRUCTION(Load) UNARY_INSTRUCTION(Return) UNARY_INSTRUCTION(Throw) UNARY_INSTRUCTION(FixLifetime) UNARY_INSTRUCTION(CopyBlock) UNARY_INSTRUCTION(StrongPin) UNARY_INSTRUCTION(StrongUnpin) UNARY_INSTRUCTION(StrongRetain) UNARY_INSTRUCTION(StrongRelease) UNARY_INSTRUCTION(StrongRetainUnowned) UNARY_INSTRUCTION(UnownedRetain) UNARY_INSTRUCTION(UnownedRelease) UNARY_INSTRUCTION(IsUnique) UNARY_INSTRUCTION(IsUniqueOrPinned) UNARY_INSTRUCTION(DebugValue) UNARY_INSTRUCTION(DebugValueAddr) #undef UNARY_INSTRUCTION case ValueKind::LoadUnownedInst: { auto Ty = MF->getType(TyID); bool isTake = (Attr > 0); ResultVal = Builder.createLoadUnowned(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), IsTake_t(isTake)); break; } case ValueKind::LoadWeakInst: { auto Ty = MF->getType(TyID); bool isTake = (Attr > 0); ResultVal = Builder.createLoadWeak(Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), IsTake_t(isTake)); break; } case ValueKind::MarkUninitializedInst: { auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto Kind = (MarkUninitializedInst::Kind)Attr; auto Val = getLocalValue(ValID, Ty); ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind); break; } case ValueKind::StoreInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); SILType ValType = addrType.getObjectType(); ResultVal = Builder.createStore(Loc, getLocalValue(ValID, ValType), getLocalValue(ValID2, addrType)); break; } case ValueKind::StoreUnownedInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); auto refType = addrType.getAs(); auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); bool isInit = (Attr > 0); ResultVal = Builder.createStoreUnowned(Loc, getLocalValue(ValID, ValType), getLocalValue(ValID2, addrType), IsInitialization_t(isInit)); break; } case ValueKind::StoreWeakInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); auto refType = addrType.getAs(); auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); bool isInit = (Attr > 0); ResultVal = Builder.createStoreWeak(Loc, getLocalValue(ValID, ValType), getLocalValue(ValID2, addrType), IsInitialization_t(isInit)); break; } case ValueKind::CopyAddrInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); bool isInit = (Attr & 0x2) > 0; bool isTake = (Attr & 0x1) > 0; ResultVal = Builder.createCopyAddr(Loc, getLocalValue(ValID, addrType), getLocalValue(ValID2, addrType), IsTake_t(isTake), IsInitialization_t(isInit)); break; } case ValueKind::AssignInst: { auto Ty = MF->getType(TyID); SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); SILType ValType = addrType.getObjectType(); ResultVal = Builder.createAssign(Loc, getLocalValue(ValID, ValType), getLocalValue(ValID2, addrType)); break; } case ValueKind::StructElementAddrInst: case ValueKind::StructExtractInst: { // Use SILOneValueOneOperandLayout. VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); auto Val = getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)); auto ResultTy = Val->getType().getFieldType(Field, SILMod); if ((ValueKind)OpCode == ValueKind::StructElementAddrInst) ResultVal = Builder.createStructElementAddr(Loc, Val, Field, ResultTy.getAddressType()); else ResultVal = Builder.createStructExtract(Loc, Val, Field, ResultTy.getObjectType()); 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. auto Ty = MF->getType(TyID); SmallVector OpList; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); OpList.push_back( getLocalValue(ListOfValues[I+2], getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); } ResultVal = Builder.createStruct(Loc, getSILType(Ty, (SILValueCategory)TyCategory), OpList); break; } case ValueKind::TupleElementAddrInst: case ValueKind::TupleExtractInst: { // Use OneTypeOneOperand layout where the field number is stored in TypeID. auto Ty2 = MF->getType(TyID2); SILType ST = getSILType(Ty2, (SILValueCategory)TyCategory2); TupleType *TT = ST.getAs(); auto ResultTy = TT->getElement(TyID).getType(); switch ((ValueKind)OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::TupleElementAddrInst: ResultVal = Builder.createTupleElementAddr(Loc, getLocalValue(ValID, ST), TyID, getSILType(ResultTy, SILValueCategory::Address)); break; case ValueKind::TupleExtractInst: ResultVal = Builder.createTupleExtract(Loc, getLocalValue(ValID,ST), TyID, getSILType(ResultTy, SILValueCategory::Object)); break; } break; } case ValueKind::TupleInst: { // Format: a type followed by a list of values. A value is expressed by // 2 IDs: ValueID, ValueResultNumber. auto Ty = MF->getType(TyID); TupleType *TT = Ty->getAs(); assert(TT && "Type of a TupleInst should be TupleType"); SmallVector OpList; for (unsigned I = 0, E = ListOfValues.size(); I < E; I++) { Type EltTy = TT->getElement(I).getType(); OpList.push_back( getLocalValue(ListOfValues[I], getSILType(EltTy, SILValueCategory::Object))); } ResultVal = Builder.createTuple(Loc, getSILType(Ty, (SILValueCategory)TyCategory), OpList); break; } case ValueKind::BranchInst: { SmallVector Args; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) Args.push_back( getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); ResultVal = Builder.createBranch(Loc, getBBForReference(Fn, TyID), Args); 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. SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); unsigned NumTrueArgs = ListOfValues[3]; unsigned StartOfTrueArg = 4; unsigned StartOfFalseArg = StartOfTrueArg + 3*NumTrueArgs; SmallVector TrueArgs; for (unsigned I = StartOfTrueArg, E = StartOfFalseArg; I < E; I += 3) TrueArgs.push_back( getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); SmallVector FalseArgs; for (unsigned I = StartOfFalseArg, E = ListOfValues.size(); I < E; I += 3) FalseArgs.push_back( getLocalValue(ListOfValues[I+2], getSILType(MF->getType(ListOfValues[I]), (SILValueCategory)ListOfValues[I+1]))); ResultVal = Builder.createCondBranch(Loc, Cond, getBBForReference(Fn, ListOfValues[1]), TrueArgs, getBBForReference(Fn, ListOfValues[2]), FalseArgs); 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). SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); SILBasicBlock *DefaultBB = nullptr; if (ListOfValues[1]) DefaultBB = getBBForReference(Fn, ListOfValues[2]); SmallVector, 4> CaseBBs; for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) { CaseBBs.push_back( {cast(MF->getDecl(ListOfValues[I])), getBBForReference(Fn, ListOfValues[I+1])} ); } if ((ValueKind)OpCode == ValueKind::SwitchEnumInst) ResultVal = Builder.createSwitchEnum(Loc, Cond, DefaultBB, CaseBBs); else ResultVal = Builder.createSwitchEnumAddr(Loc, Cond, DefaultBB, CaseBBs); 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). SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); Type ResultLoweredTy = MF->getType(ListOfValues[1]); SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); SILValue DefaultVal = nullptr; if (ListOfValues[3]) DefaultVal = getLocalValue(ListOfValues[4], ResultTy); SmallVector, 4> CaseVals; for (unsigned I = 5, E = ListOfValues.size(); I < E; I += 2) { auto Value = getLocalValue(ListOfValues[I+1], ResultTy); CaseVals.push_back({cast(MF->getDecl(ListOfValues[I])), Value}); } if ((ValueKind)OpCode == ValueKind::SelectEnumInst) ResultVal = Builder.createSelectEnum(Loc, Cond, ResultTy, DefaultVal, CaseVals); else ResultVal = Builder.createSelectEnumAddr(Loc, Cond, ResultTy, DefaultVal, CaseVals); 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). SILType ResultTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); SILBasicBlock *DefaultBB = nullptr; if (ListOfValues[1]) DefaultBB = getBBForReference(Fn, ListOfValues[2]); SmallVector, 4> CaseBBs; for (unsigned I = 3, E = ListOfValues.size(); I < E; I += 2) { auto value = getLocalValue(ListOfValues[I], ResultTy); CaseBBs.push_back( {value, getBBForReference(Fn, ListOfValues[I+1])} ); } ResultVal = Builder.createSwitchValue(Loc, Cond, DefaultBB, CaseBBs); break; } case ValueKind::SelectValueInst: { // Format: condition, a list of cases (ValueID + 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). SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); Type ResultLoweredTy = MF->getType(ListOfValues[1]); SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); SILValue DefaultVal = nullptr; if (ListOfValues[3]) DefaultVal = getLocalValue(ListOfValues[4], ResultTy); SmallVector, 4> CaseValuesAndResults; for (unsigned I = 5, E = ListOfValues.size(); I < E; I += 2) { auto CaseValue = getLocalValue(ListOfValues[I], Cond->getType()); auto Result = getLocalValue(ListOfValues[I+1], ResultTy); CaseValuesAndResults.push_back({CaseValue, Result}); } ResultVal = Builder.createSelectValue(Loc, Cond, ResultTy, DefaultVal, CaseValuesAndResults); break; } case ValueKind::EnumInst: { // Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type, // (DeclID + hasOperand), and an operand. SILValue Operand; if (Attr) Operand = getLocalValue(ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); ResultVal = Builder.createEnum(Loc, Operand, cast(MF->getDecl(ValID)), getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); break; } case ValueKind::InitEnumDataAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); SILType OperandTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createInitEnumDataAddr(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case ValueKind::UncheckedEnumDataInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); SILType OperandTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createUncheckedEnumData(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case ValueKind::UncheckedTakeEnumDataAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); SILType OperandTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); ResultVal = Builder.createUncheckedTakeEnumDataAddr(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); break; } case ValueKind::InjectEnumAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); ResultVal = Builder.createInjectEnumAddr(Loc, getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)), Elt); break; } case ValueKind::RefElementAddrInst: { // Use SILOneValueOneOperandLayout. VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); auto Val = getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory)); auto ResultTy = Val->getType().getFieldType(Field, SILMod); ResultVal = Builder.createRefElementAddr(Loc, Val, Field, ResultTy); break; } case ValueKind::ClassMethodInst: case ValueKind::SuperMethodInst: case ValueKind::DynamicMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), // and an operand. unsigned NextValueIndex = 1; SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); assert(ListOfValues.size() >= NextValueIndex + 2 && "Out of entries for MethodInst"); SILType operandTy = getSILType(MF->getType(ListOfValues[NextValueIndex]), (SILValueCategory)ListOfValues[NextValueIndex+1]); NextValueIndex += 2; bool IsVolatile = ListOfValues[0] > 0; switch ((ValueKind)OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::ClassMethodInst: ResultVal = Builder.createClassMethod(Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; case ValueKind::SuperMethodInst: ResultVal = Builder.createSuperMethod(Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; case ValueKind::DynamicMethodInst: ResultVal = Builder.createDynamicMethod(Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty, IsVolatile); break; } break; } case ValueKind::WitnessMethodInst: { unsigned NextValueIndex = 0; SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() >= NextValueIndex && "Out of entries for MethodInst"); CanType Ty = MF->getType(TyID)->getCanonicalType(); SILType OperandTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2); auto Conformance = MF->readConformance(SILCursor); // Read the optional opened existential. SILValue ExistentialOperand; if (TyID3) { SILType ExistentialOperandTy = getSILType(MF->getType(TyID3), (SILValueCategory)TyCategory3); if (ValID3) ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy); } ResultVal = Builder.createWitnessMethod( Loc, Ty, Conformance, DRef, OperandTy, ExistentialOperand, Attr); break; } case ValueKind::DynamicMethodBranchInst: { // Format: a typed value, a SILDeclRef, a BasicBlock ID for method, // a BasicBlock ID for no method. Use SILOneTypeValuesLayout. unsigned NextValueIndex = 1; SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() == NextValueIndex + 2 && "Wrong number of entries for DynamicMethodBranchInst"); ResultVal = Builder.createDynamicMethodBranch(Loc, getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)), DRef, getBBForReference(Fn, ListOfValues[NextValueIndex]), getBBForReference(Fn, ListOfValues[NextValueIndex+1])); break; } case ValueKind::CheckedCastBranchInst: { // Format: the cast kind, a typed value, a BasicBlock ID for success, // a BasicBlock ID for failure. Uses SILOneTypeValuesLayout. assert(ListOfValues.size() == 6 && "expect 7 numbers for CheckedCastBranchInst"); bool isExact = ListOfValues[0] != 0; SILType opTy = getSILType(MF->getType(ListOfValues[2]), (SILValueCategory)ListOfValues[3]); SILValue op = getLocalValue(ListOfValues[1], opTy); SILType castTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); auto *successBB = getBBForReference(Fn, ListOfValues[4]); auto *failureBB = getBBForReference(Fn, ListOfValues[5]); ResultVal = Builder.createCheckedCastBranch(Loc, isExact, op, castTy, successBB, failureBB); break; } case ValueKind::UnconditionalCheckedCastAddrInst: case ValueKind::CheckedCastAddrBranchInst: { CastConsumptionKind consumption = getCastConsumptionKind(ListOfValues[0]); CanType sourceType = MF->getType(ListOfValues[1])->getCanonicalType(); SILType srcAddrTy = getSILType(MF->getType(ListOfValues[3]), (SILValueCategory)ListOfValues[4]); SILValue src = getLocalValue(ListOfValues[2], srcAddrTy); CanType targetType = MF->getType(ListOfValues[5])->getCanonicalType(); SILType destAddrTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); SILValue dest = getLocalValue(ListOfValues[6], destAddrTy); if (OpCode == (unsigned) ValueKind::UnconditionalCheckedCastAddrInst) { ResultVal = Builder.createUnconditionalCheckedCastAddr(Loc, consumption, src, sourceType, dest, targetType); break; } auto *successBB = getBBForReference(Fn, ListOfValues[7]); auto *failureBB = getBBForReference(Fn, ListOfValues[8]); ResultVal = Builder.createCheckedCastAddrBranch(Loc, consumption, src, sourceType, dest, targetType, successBB, failureBB); break; } case ValueKind::UncheckedRefCastAddrInst: { CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType(); SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]), (SILValueCategory)ListOfValues[3]); SILValue src = getLocalValue(ListOfValues[1], srcAddrTy); CanType targetType = MF->getType(ListOfValues[4])->getCanonicalType(); SILType destAddrTy = getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); ResultVal = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, dest, targetType); break; } case ValueKind::InitBlockStorageHeaderInst: { assert(ListOfValues.size() == 4 && "expected 6 values for InitBlockStorageHeader"); SILType blockTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); SILType storageTy = getSILType(MF->getType(ListOfValues[1]), SILValueCategory::Address); SILValue storage = getLocalValue(ListOfValues[0], storageTy); SILType invokeTy = getSILType(MF->getType(ListOfValues[3]), SILValueCategory::Object); SILValue invoke = getLocalValue(ListOfValues[2], invokeTy); ResultVal = Builder.createInitBlockStorageHeader(Loc, storage, invoke, blockTy); break; } case ValueKind::UnreachableInst: { ResultVal = Builder.createUnreachable(Loc); break; } case ValueKind::MarkUninitializedBehaviorInst: llvm_unreachable("todo"); } if (ResultVal->hasValue()) { LastValueID = LastValueID + 1; setLocalValue(ResultVal, LastValueID); } return false; } SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) { StringRef name = InFunc->getName(); if (!FuncTable) return nullptr; auto iter = FuncTable->find(name); if (iter == FuncTable->end()) return nullptr; auto Func = readSILFunction(*iter, InFunc, name, /*declarationOnly*/ false); if (Func) { DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Func->dump()); assert(InFunc->getName() == Func->getName()); } return Func; } SILFunction *SILDeserializer::lookupSILFunction(StringRef name, bool declarationOnly) { if (!FuncTable) return nullptr; auto iter = FuncTable->find(name); if (iter == FuncTable->end()) return nullptr; auto Func = readSILFunction(*iter, nullptr, name, declarationOnly); if (Func) DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Func->dump()); return Func; } SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { if (!GlobalVarList) return nullptr; // Find Id for the given name. auto iter = GlobalVarList->find(Name); if (iter == GlobalVarList->end()) return nullptr; auto VId = *iter; if (VId == 0) return nullptr; assert(VId <= GlobalVars.size() && "invalid GlobalVar ID"); auto &globalVarOrOffset = GlobalVars[VId-1]; if (globalVarOrOffset.isComplete()) return globalVarOrOffset; BCOffsetRAII restoreOffset(SILCursor); SILCursor.JumpToBit(globalVarOrOffset); auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::Error) { DEBUG(llvm::dbgs() << "Cursor advance error in readGlobalVar.\n"); return nullptr; } SmallVector scratch; StringRef blobData; unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); assert(kind == SIL_GLOBALVAR && "expect a sil global var"); (void)kind; TypeID TyID; DeclID dID; unsigned rawLinkage, isFragile, IsDeclaration, IsLet; GlobalVarLayout::readRecord(scratch, rawLinkage, isFragile, TyID, dID, IsDeclaration, IsLet); if (TyID == 0) { DEBUG(llvm::dbgs() << "SILGlobalVariable typeID is 0.\n"); return nullptr; } auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage << " for SILGlobalVariable\n"); return nullptr; } auto Ty = MF->getType(TyID); SILGlobalVariable *v = SILGlobalVariable::create( SILMod, linkage.getValue(), (IsFragile_t)isFragile, Name.str(), getSILType(Ty, SILValueCategory::Object), None, dID ? cast(MF->getDecl(dID)): nullptr); v->setLet(IsLet); globalVarOrOffset = v; v->setDeclaration(IsDeclaration); if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), v); return v; } void SILDeserializer::getAllSILFunctions() { if (!FuncTable) return; for (auto KI = FuncTable->key_begin(), KE = FuncTable->key_end(); KI != KE; ++KI) { // Attempt to lookup our name from the output module. If we have a // definition already, don't do anything. if (SILFunction *F = SILMod.lookUpFunction(*KI)) if (!F->isExternalDeclaration()) continue; auto DI = FuncTable->find(*KI); assert(DI != FuncTable->end() && "There should never be a key without data."); SILFunction *fn = readSILFunction(*DI, nullptr, *KI, false, false/*errorIfEmptyBody*/); // Update linkage for global addressors to make it pass verifier. if (fn && fn->isGlobalInit() && fn->isExternalDeclaration() && fn->getLinkage() == SILLinkage::Public) fn->setLinkage(SILLinkage::PublicExternal); } } SILVTable *SILDeserializer::readVTable(DeclID VId) { if (VId == 0) return nullptr; assert(VId <= VTables.size() && "invalid VTable ID"); auto &vTableOrOffset = VTables[VId-1]; if (vTableOrOffset.isComplete()) return vTableOrOffset; BCOffsetRAII restoreOffset(SILCursor); SILCursor.JumpToBit(vTableOrOffset); auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::Error) { DEBUG(llvm::dbgs() << "Cursor advance error in readVTable.\n"); return nullptr; } SmallVector scratch; StringRef blobData; unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); assert(kind == SIL_VTABLE && "expect a sil vtable"); (void)kind; DeclID ClassID; VTableLayout::readRecord(scratch, ClassID); if (ClassID == 0) { DEBUG(llvm::dbgs() << "VTable classID is 0.\n"); return nullptr; } ClassDecl *theClass = cast(MF->getDecl(ClassID)); // Fetch the next record. scratch.clear(); entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // This vtable has no contents. return nullptr; kind = SILCursor.readRecord(entry.ID, scratch); std::vector vtableEntries; // Another SIL_VTABLE record means the end of this VTable. while (kind != SIL_VTABLE && kind != SIL_WITNESSTABLE && kind != SIL_FUNCTION) { assert(kind == SIL_VTABLE_ENTRY && "Content of Vtable should be in SIL_VTABLE_ENTRY."); ArrayRef ListOfValues; DeclID NameID; VTableEntryLayout::readRecord(scratch, NameID, ListOfValues); SILFunction *Func = getFuncForReference(MF->getIdentifier(NameID).str()); if (Func) { unsigned NextValueIndex = 0; vtableEntries.emplace_back(getSILDeclRef(MF, ListOfValues, NextValueIndex), Func); } // Fetch the next record. scratch.clear(); entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // EndBlock means the end of this VTable. break; kind = SILCursor.readRecord(entry.ID, scratch); } SILVTable *vT = SILVTable::create(SILMod, theClass, vtableEntries); vTableOrOffset = vT; if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), vT); return vT; } SILVTable *SILDeserializer::lookupVTable(Identifier Name) { if (!VTableList) return nullptr; auto iter = VTableList->find(Name.str()); if (iter == VTableList->end()) return nullptr; auto VT = readVTable(*iter); return VT; } /// Deserialize all VTables inside the module and add them to SILMod. void SILDeserializer::getAllVTables() { if (!VTableList) return; for (unsigned I = 0, E = VTables.size(); I < E; I++) readVTable(I+1); } SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, SILWitnessTable *existingWt, bool declarationOnly) { if (WId == 0) return nullptr; assert(WId <= WitnessTables.size() && "invalid WitnessTable ID"); auto &wTableOrOffset = WitnessTables[WId-1]; if (wTableOrOffset.isFullyDeserialized() || (wTableOrOffset.isDeserialized() && declarationOnly)) return wTableOrOffset.get(); BCOffsetRAII restoreOffset(SILCursor); SILCursor.JumpToBit(wTableOrOffset.getOffset()); auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::Error) { DEBUG(llvm::dbgs() << "Cursor advance error in readWitnessTable.\n"); return nullptr; } SmallVector scratch; StringRef blobData; unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); assert(kind == SIL_WITNESSTABLE && "expect a sil witnesstable"); (void)kind; unsigned RawLinkage; unsigned IsDeclaration; unsigned IsFragile; WitnessTableLayout::readRecord(scratch, RawLinkage, IsDeclaration, IsFragile); auto Linkage = fromStableSILLinkage(RawLinkage); if (!Linkage) { DEBUG(llvm::dbgs() << "invalid linkage code " << RawLinkage << " for SILFunction\n"); MF->error(); return nullptr; } // Deserialize Conformance. auto theConformance = cast( MF->readConformance(SILCursor).getConcrete()); if (!existingWt) existingWt = SILMod.lookUpWitnessTable(theConformance, false); auto wT = existingWt; // If we have an existing witness table, verify that the conformance matches // up. if (wT) { if (wT->getConformance() != theConformance) { DEBUG(llvm::dbgs() << "Conformance mismatch.\n"); MF->error(); return nullptr; } // Don't override the linkage of a witness table with an existing // declaration. } else { // Otherwise, create a new witness table declaration. wT = SILWitnessTable::create(SILMod, *Linkage, theConformance); if (Callback) Callback->didDeserialize(MF->getAssociatedModule(), wT); } assert(wT->isDeclaration() && "Our witness table at this point must be a " "declaration."); // If we are asked to just emit a declaration, return the declaration and say // that the witness table is not fully deserialized. if (IsDeclaration || declarationOnly) { wTableOrOffset.set(wT, /*fully deserialized*/ false); return wT; } // Fetch the next record. scratch.clear(); entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::EndBlock) return nullptr; kind = SILCursor.readRecord(entry.ID, scratch); std::vector witnessEntries; // Another SIL_WITNESSTABLE record means the end of this WitnessTable. while (kind != SIL_WITNESSTABLE && kind != SIL_FUNCTION) { if (kind == SIL_WITNESS_BASE_ENTRY) { DeclID protoId; WitnessBaseEntryLayout::readRecord(scratch, protoId); ProtocolDecl *proto = cast(MF->getDecl(protoId)); auto conformance = MF->readConformance(SILCursor); witnessEntries.push_back(SILWitnessTable::BaseProtocolWitness{ proto, conformance.getConcrete() }); } else if (kind == SIL_WITNESS_ASSOC_PROTOCOL) { DeclID assocId, protoId; WitnessAssocProtocolLayout::readRecord(scratch, assocId, protoId); ProtocolDecl *proto = cast(MF->getDecl(protoId)); auto conformance = MF->readConformance(SILCursor); witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{ cast(MF->getDecl(assocId)), proto, conformance }); } else if (kind == SIL_WITNESS_ASSOC_ENTRY) { DeclID assocId; TypeID tyId; WitnessAssocEntryLayout::readRecord(scratch, assocId, tyId); AssociatedTypeDecl *assoc = cast(MF->getDecl(assocId)); witnessEntries.push_back(SILWitnessTable::AssociatedTypeWitness{ assoc, MF->getType(tyId)->getCanonicalType() }); } else { assert(kind == SIL_WITNESS_METHOD_ENTRY && "Content of WitnessTable should be in SIL_WITNESS_METHOD_ENTRY."); ArrayRef ListOfValues; DeclID NameID; WitnessMethodEntryLayout::readRecord(scratch, NameID, ListOfValues); SILFunction *Func = nullptr; if (NameID != 0) { Func = getFuncForReference(MF->getIdentifier(NameID).str()); } if (Func || NameID == 0) { unsigned NextValueIndex = 0; witnessEntries.push_back(SILWitnessTable::MethodWitness{ getSILDeclRef(MF, ListOfValues, NextValueIndex), Func }); } } // Fetch the next record. scratch.clear(); entry = SILCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // EndBlock means the end of this WitnessTable. break; kind = SILCursor.readRecord(entry.ID, scratch); } wT->convertToDefinition(witnessEntries, IsFragile != 0); wTableOrOffset.set(wT, /*fully deserialized*/ true); if (Callback) Callback->didDeserializeWitnessTableEntries(MF->getAssociatedModule(), wT); return wT; } /// Deserialize all WitnessTables inside the module and add them to SILMod. void SILDeserializer::getAllWitnessTables() { if (!WitnessTableList) return; for (unsigned I = 0, E = WitnessTables.size(); I < E; I++) readWitnessTable(I + 1, nullptr, false); } SILWitnessTable * SILDeserializer::lookupWitnessTable(SILWitnessTable *existingWt) { assert(existingWt && "Cannot deserialize a null witness table declaration."); assert(existingWt->isDeclaration() && "Cannot deserialize a witness table " "definition."); // If we don't have a witness table list, we can't look anything up. if (!WitnessTableList) return nullptr; // Use the name of the given witness table to lookup the partially // deserialized value from the witness table list. auto iter = WitnessTableList->find(existingWt->getName()); if (iter == WitnessTableList->end()) return nullptr; // Attempt to read the witness table. auto Wt = readWitnessTable(*iter, existingWt, /*declarationOnly*/ false); if (Wt) DEBUG(llvm::dbgs() << "Deserialize SIL:\n"; Wt->dump()); return Wt; } SILDeserializer::~SILDeserializer() { // Drop our references to anything we've deserialized. for (auto &fnEntry : Funcs) { if (fnEntry.isDeserialized()) fnEntry.get()->decrementRefCount(); } } // Invalidate all cached SILFunctions. void SILDeserializer::invalidateFunctionCache() { for (auto &fnEntry : Funcs) if (fnEntry.isDeserialized()) { fnEntry.get()->decrementRefCount(); fnEntry.reset(); } } bool SILDeserializer::invalidateFunction(SILFunction *F) { for (auto &fnEntry : Funcs) { if (fnEntry.isDeserialized() && fnEntry.get() == F) { fnEntry.get()->decrementRefCount(); fnEntry.reset(); return true; } } return false; }