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