Files
swift-mirror/lib/Serialization/SerializeSIL.cpp
Erik Eckstein 1eb3a0532b DeadFunctionElimination: don’t eliminate public methods which are called via a thunk.
For this we need to store the linkage of the “original” method implementation in the vtable.
Otherwise DeadFunctionElimination thinks that the method implementation is not public but private (which is the linkage of the thunk).

The big part of this change is to extend SILVTable to store the linkage (+ serialization, printing, etc.).

fixes rdar://problem/29841635
2017-01-06 16:06:32 -08:00

2003 lines
80 KiB
C++

//===--- SerializeSIL.cpp - Read and write SIL ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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/Strings.h"
#include "swift/AST/Module.h"
#include "swift/SIL/CFG.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILOptimizer/Utils/Generics.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/EndianStream.h"
#include "llvm/Support/OnDiskHashTable.h"
using namespace swift;
using namespace swift::serialization;
using namespace swift::serialization::sil_block;
using namespace llvm::support;
using llvm::BCBlockRAII;
static unsigned toStableStringEncoding(StringLiteralInst::Encoding encoding) {
switch (encoding) {
case StringLiteralInst::Encoding::UTF8: return SIL_UTF8;
case StringLiteralInst::Encoding::UTF16: return SIL_UTF16;
case StringLiteralInst::Encoding::ObjCSelector: return SIL_OBJC_SELECTOR;
}
llvm_unreachable("bad string encoding");
}
static unsigned toStableSILLinkage(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Public: return SIL_LINKAGE_PUBLIC;
case SILLinkage::Hidden: return SIL_LINKAGE_HIDDEN;
case SILLinkage::Shared: return SIL_LINKAGE_SHARED;
case SILLinkage::Private: return SIL_LINKAGE_PRIVATE;
case SILLinkage::PublicExternal: return SIL_LINKAGE_PUBLIC_EXTERNAL;
case SILLinkage::HiddenExternal: return SIL_LINKAGE_HIDDEN_EXTERNAL;
case SILLinkage::SharedExternal: return SIL_LINKAGE_SHARED_EXTERNAL;
case SILLinkage::PrivateExternal: return SIL_LINKAGE_PRIVATE_EXTERNAL;
}
llvm_unreachable("bad linkage");
}
static unsigned toStableCastConsumptionKind(CastConsumptionKind kind) {
switch (kind) {
case CastConsumptionKind::TakeAlways:
return SIL_CAST_CONSUMPTION_TAKE_ALWAYS;
case CastConsumptionKind::TakeOnSuccess:
return SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS;
case CastConsumptionKind::CopyOnSuccess:
return SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS;
}
llvm_unreachable("bad cast consumption kind");
}
namespace {
/// Used to serialize the on-disk func hash table.
class FuncTableInfo {
public:
using key_type = Identifier;
using key_type_ref = key_type;
using data_type = DeclID;
using data_type_ref = const data_type &;
using hash_value_type = uint32_t;
using offset_type = unsigned;
hash_value_type ComputeHash(key_type_ref key) {
assert(!key.empty());
return llvm::HashString(key.str());
}
std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
key_type_ref key,
data_type_ref data) {
uint32_t keyLength = key.str().size();
uint32_t dataLength = sizeof(uint32_t);
endian::Writer<little> writer(out);
writer.write<uint16_t>(keyLength);
writer.write<uint16_t>(dataLength);
return { keyLength, dataLength };
}
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
out << key.str();
}
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
unsigned len) {
endian::Writer<little>(out).write<uint32_t>(data);
}
};
class SILSerializer {
Serializer &S;
ASTContext &Ctx;
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>;
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 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;
/// 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;
/// Additional functions we might need to serialize.
llvm::SmallVector<const SILFunction *, 16> Worklist;
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);
DEBUG(llvm::dbgs() << "SIL abbre code " << SILAbbrCodes[Layout::Code]
<< " for layout " << Layout::Code << "\n");
}
bool ShouldSerializeAll;
void addMandatorySILFunction(const SILFunction *F,
bool emitDeclarationsForOnoneSupport);
void addReferencedSILFunction(const SILFunction *F,
bool DeclOnly = false);
void processSILFunctionWorklist();
/// Helper function to update ListOfValues for MethodInst. Format:
/// Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and an operand.
void handleMethodInst(const MethodInst *MI, SILValue operand,
SmallVectorImpl<ValueID> &ListOfValues);
void writeSILFunction(const SILFunction &F, bool DeclOnly = false);
void writeSILBasicBlock(const SILBasicBlock &BB);
void writeSILInstruction(const SILInstruction &SI);
void writeSILVTable(const SILVTable &vt);
void writeSILGlobalVar(const SILGlobalVariable &g);
void writeSILWitnessTable(const SILWitnessTable &wt);
void writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt);
void writeSILBlock(const SILModule *SILMod);
void writeIndexTables();
void writeConversionLikeInstruction(const SILInstruction *I);
void writeOneTypeLayout(ValueKind valueKind, SILType type);
void writeOneTypeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
SILType type,
SILValue operand);
void writeOneTypeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
CanType type,
SILValue operand);
void writeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
SILValue operand);
/// Helper function to determine if given the current state of the
/// deserialization if the function body for F should be deserialized.
bool shouldEmitFunctionBody(const SILFunction *F);
public:
SILSerializer(Serializer &S, ASTContext &Ctx,
llvm::BitstreamWriter &Out, bool serializeAll)
: S(S), Ctx(Ctx), Out(Out), ShouldSerializeAll(serializeAll) {}
void writeSILModule(const SILModule *SILMod);
};
} // end anonymous namespace
void SILSerializer::addMandatorySILFunction(const SILFunction *F,
bool emitDeclarationsForOnoneSupport) {
// If this function is not fragile, don't do anything.
if (!shouldEmitFunctionBody(F))
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;
if (!emitDeclarationsForOnoneSupport)
Worklist.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;
Worklist.push_back(F);
return;
}
// If we referenced a non-fragile shared function from a fragile
// function, serialize it too. In practice, it will either be a
// thunk, or an optimizer specialization. In both cases, we don't
// have enough information at the time we emit the function to
// know if it should be marked fragile or not.
if (F->getLinkage() == SILLinkage::Shared && !DeclOnly) {
assert(F->isThunk() == IsReabstractionThunk || F->hasForeignBody());
FuncsToEmit[F] = false;
Worklist.push_back(F);
return;
}
// Ok, we just need to emit a declaration.
FuncsToEmit[F] = true;
}
void SILSerializer::processSILFunctionWorklist() {
while (Worklist.size() > 0) {
const SILFunction *F = Worklist.back();
Worklist.pop_back();
assert(F != nullptr);
assert(FuncsToEmit.count(F) > 0);
writeSILFunction(*F, FuncsToEmit[F]);
}
}
/// We enumerate all values in a SILFunction beforehand to correctly
/// handle forward references of values.
ValueID SILSerializer::addValueRef(const ValueBase *Val) {
if (!Val || isa<SILUndef>(Val))
return 0;
ValueID id = ValueIDs[Val];
assert(id != 0 && "We should have assigned a value ID to each value.");
return id;
}
void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) {
ValueIDs.clear();
InstID = 0;
FuncTable[Ctx.getIdentifier(F.getName())] = NextFuncID++;
Funcs.push_back(Out.GetCurrentBitNo());
unsigned abbrCode = SILAbbrCodes[SILFunctionLayout::Code];
TypeID FnID = S.addTypeRef(F.getLoweredType().getSwiftType());
DEBUG(llvm::dbgs() << "SILFunction " << F.getName() << " @ BitNo "
<< Out.GetCurrentBitNo() << " abbrCode " << abbrCode
<< " FnID " << FnID << "\n");
DEBUG(llvm::dbgs() << "Serialized SIL:\n"; F.dump());
SmallVector<IdentifierID, 1> SemanticsIDs;
for (auto SemanticAttr : F.getSemanticsAttrs()) {
SemanticsIDs.push_back(S.addIdentifierRef(Ctx.getIdentifier(SemanticAttr)));
}
SILLinkage Linkage = F.getLinkage();
// We serialize shared_external linkage as shared since:
//
// 1. shared_external linkage is just a hack to tell the optimizer that a
// shared function was deserialized.
//
// 2. We cannot just serialize a declaration to a shared_external function
// since shared_external functions still have linkonce_odr linkage at the LLVM
// level. This means they must be defined not just declared.
//
// TODO: When serialization is reworked, this should be removed.
if (hasSharedVisibility(Linkage))
Linkage = SILLinkage::Shared;
// Check if we need to emit a body for this function.
bool NoBody = DeclOnly || isAvailableExternally(Linkage) ||
F.isExternalDeclaration();
// If we don't emit a function body then make sure to mark the declaration
// as available externally.
if (NoBody) {
Linkage = addExternalToLinkage(Linkage);
}
// If we have a body, we might have a generic environment.
GenericEnvironmentID genericEnvID = 0;
if (!F.isExternalDeclaration())
genericEnvID = S.addGenericEnvironmentRef(F.getGenericEnvironment());
DeclID clangNodeOwnerID;
if (F.hasClangNode())
clangNodeOwnerID = S.addDeclRef(F.getClangNodeOwner());
unsigned numSpecAttrs = NoBody ? 0 : F.getSpecializeAttrs().size();
SILFunctionLayout::emitRecord(
Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage),
(unsigned)F.isTransparent(), (unsigned)F.isFragile(),
(unsigned)F.isThunk(), (unsigned)F.isGlobalInit(),
(unsigned)F.getInlineStrategy(), (unsigned)F.getEffectsKind(),
(unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(), FnID,
genericEnvID, clangNodeOwnerID, SemanticsIDs);
if (NoBody)
return;
for (auto *SA : F.getSpecializeAttrs()) {
unsigned specAttrAbbrCode = SILAbbrCodes[SILSpecializeAttrLayout::Code];
auto subs = SA->getSubstitutions();
SILSpecializeAttrLayout::emitRecord(
Out, ScratchRecord, specAttrAbbrCode, (unsigned)subs.size());
S.writeSubstitutions(subs, SILAbbrCodes);
}
// Assign a unique ID to each basic block of the SILFunction.
unsigned BasicID = 0;
BasicBlockMap.clear();
// Assign a value ID to each SILInstruction that has value and to each basic
// block argument.
unsigned ValueID = 0;
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)
if (SI.hasValue())
ValueIDs[&SI] = ++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().getSwiftRValueType());
DeclID vId = addValueRef(static_cast<const ValueBase*>(SA));
Args.push_back(tId);
Args.push_back((unsigned)SA->getType().getCategory());
Args.push_back(vId);
}
unsigned abbrCode = SILAbbrCodes[SILBasicBlockLayout::Code];
SILBasicBlockLayout::emitRecord(Out, ScratchRecord, abbrCode, Args);
for (const SILInstruction &SI : BB)
writeSILInstruction(SI);
}
/// Add SILDeclRef to ListOfValues, so we can reconstruct it at
/// deserialization.
static void handleSILDeclRef(Serializer &S, const SILDeclRef &Ref,
SmallVectorImpl<ValueID> &ListOfValues) {
ListOfValues.push_back(S.addDeclRef(Ref.getDecl()));
ListOfValues.push_back((unsigned)Ref.kind);
ListOfValues.push_back((unsigned)Ref.getResilienceExpansion());
ListOfValues.push_back(Ref.uncurryLevel);
ListOfValues.push_back(Ref.isForeign);
}
/// Helper function to update ListOfValues for MethodInst. Format:
/// Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and an operand.
void SILSerializer::handleMethodInst(const MethodInst *MI,
SILValue operand,
SmallVectorImpl<ValueID> &ListOfValues) {
ListOfValues.push_back(MI->isVolatile());
handleSILDeclRef(S, MI->getMember(), ListOfValues);
ListOfValues.push_back(
S.addTypeRef(operand->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)operand->getType().getCategory());
ListOfValues.push_back(addValueRef(operand));
}
void SILSerializer::writeOneTypeLayout(ValueKind valueKind,
SILType type) {
unsigned abbrCode = SILAbbrCodes[SILOneTypeLayout::Code];
SILOneTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned) valueKind,
S.addTypeRef(type.getSwiftRValueType()),
(unsigned)type.getCategory());
}
void SILSerializer::writeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
SILValue operand) {
auto operandType = operand->getType();
auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType());
auto operandRef = addValueRef(operand);
SILOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneOperandLayout::Code],
unsigned(valueKind), attrs,
operandTypeRef, unsigned(operandType.getCategory()),
operandRef);
}
void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
SILType type,
SILValue operand) {
auto typeRef = S.addTypeRef(type.getSwiftRValueType());
auto operandType = operand->getType();
auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType());
auto operandRef = addValueRef(operand);
SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeOneOperandLayout::Code],
unsigned(valueKind), attrs,
typeRef, unsigned(type.getCategory()),
operandTypeRef, unsigned(operandType.getCategory()),
operandRef);
}
void SILSerializer::writeOneTypeOneOperandLayout(ValueKind valueKind,
unsigned attrs,
CanType type,
SILValue operand) {
auto typeRef = S.addTypeRef(type);
auto operandType = operand->getType();
auto operandTypeRef = S.addTypeRef(operandType.getSwiftRValueType());
auto operandRef = addValueRef(operand);
SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeOneOperandLayout::Code],
unsigned(valueKind), attrs,
typeRef, 0,
operandTypeRef, unsigned(operandType.getCategory()),
operandRef);
}
/// Write an instruction that looks exactly like a conversion: all
/// important information is encoded in the operand and the result type.
void SILSerializer::writeConversionLikeInstruction(const SILInstruction *I) {
assert(I->getNumOperands() - I->getTypeDependentOperands().size() == 1);
writeOneTypeOneOperandLayout(I->getKind(), 0, I->getType(),
I->getOperand(0));
}
void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
switch (SI.getKind()) {
case ValueKind::SILPHIArgument:
case ValueKind::SILFunctionArgument:
case ValueKind::SILUndef:
llvm_unreachable("not an instruction");
case ValueKind::DebugValueInst:
case ValueKind::DebugValueAddrInst:
// Currently we don't serialize debug variable infos, so it doesn't make
// sense to write the instruction at all.
// TODO: decide if we want to serialize those instructions.
return;
case ValueKind::UnreachableInst: {
unsigned abbrCode = SILAbbrCodes[SILInstNoOperandLayout::Code];
SILInstNoOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind());
break;
}
case ValueKind::AllocExistentialBoxInst:
case ValueKind::InitExistentialAddrInst:
case ValueKind::InitExistentialMetatypeInst:
case ValueKind::InitExistentialRefInst: {
SILValue operand;
SILType Ty;
CanType FormalConcreteType;
ArrayRef<ProtocolConformanceRef> conformances;
switch (SI.getKind()) {
default: llvm_unreachable("out of sync with parent");
case ValueKind::InitExistentialAddrInst: {
auto &IEI = cast<InitExistentialAddrInst>(SI);
operand = IEI.getOperand();
Ty = IEI.getLoweredConcreteType();
FormalConcreteType = IEI.getFormalConcreteType();
conformances = IEI.getConformances();
break;
}
case ValueKind::InitExistentialRefInst: {
auto &IERI = cast<InitExistentialRefInst>(SI);
operand = IERI.getOperand();
Ty = IERI.getType();
FormalConcreteType = IERI.getFormalConcreteType();
conformances = IERI.getConformances();
break;
}
case ValueKind::InitExistentialMetatypeInst: {
auto &IEMI = cast<InitExistentialMetatypeInst>(SI);
operand = IEMI.getOperand();
Ty = IEMI.getType();
conformances = IEMI.getConformances();
break;
}
case ValueKind::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().getSwiftRValueType());
operandCategory = operand->getType().getCategory();
operandID = addValueRef(operand);
}
unsigned abbrCode = SILAbbrCodes[SILInitExistentialLayout::Code];
SILInitExistentialLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind(),
S.addTypeRef(Ty.getSwiftRValueType()),
(unsigned)Ty.getCategory(),
operandType,
(unsigned)operandCategory,
operandID,
S.addTypeRef(FormalConcreteType),
conformances.size());
for (auto conformance : conformances) {
S.writeConformance(conformance, SILAbbrCodes);
}
break;
}
case ValueKind::DeallocValueBufferInst: {
auto DVBI = cast<DeallocValueBufferInst>(&SI);
writeOneTypeOneOperandLayout(DVBI->getKind(), 0,
DVBI->getValueType(),
DVBI->getOperand());
break;
}
case ValueKind::DeallocBoxInst: {
auto DBI = cast<DeallocBoxInst>(&SI);
writeOneTypeOneOperandLayout(DBI->getKind(), 0,
DBI->getOperand()->getType(),
DBI->getOperand());
break;
}
case ValueKind::DeallocExistentialBoxInst: {
auto DBI = cast<DeallocExistentialBoxInst>(&SI);
writeOneTypeOneOperandLayout(DBI->getKind(), 0,
DBI->getConcreteType(),
DBI->getOperand());
break;
}
case ValueKind::ValueMetatypeInst: {
auto VMI = cast<ValueMetatypeInst>(&SI);
writeOneTypeOneOperandLayout(VMI->getKind(), 0,
VMI->getType(),
VMI->getOperand());
break;
}
case ValueKind::ExistentialMetatypeInst: {
auto EMI = cast<ExistentialMetatypeInst>(&SI);
writeOneTypeOneOperandLayout(EMI->getKind(), 0,
EMI->getType(),
EMI->getOperand());
break;
}
case ValueKind::AllocValueBufferInst: {
auto AVBI = cast<AllocValueBufferInst>(&SI);
writeOneTypeOneOperandLayout(AVBI->getKind(), 0,
AVBI->getValueType(),
AVBI->getOperand());
break;
}
case ValueKind::AllocBoxInst: {
const AllocBoxInst *ABI = cast<AllocBoxInst>(&SI);
writeOneTypeLayout(ABI->getKind(), ABI->getType());
break;
}
case ValueKind::AllocRefInst:
case ValueKind::AllocRefDynamicInst: {
const AllocRefInstBase *ARI = cast<AllocRefInstBase>(&SI);
unsigned abbrCode = SILAbbrCodes[SILOneTypeValuesLayout::Code];
SmallVector<ValueID, 4> Args;
Args.push_back((unsigned)ARI->isObjC() |
((unsigned)ARI->canAllocOnStack() << 1));
ArrayRef<SILType> TailTypes = ARI->getTailAllocatedTypes();
ArrayRef<Operand> AllOps = ARI->getAllOperands();
unsigned NumTailAllocs = TailTypes.size();
unsigned NumOpsToWrite = NumTailAllocs;
if (SI.getKind() == ValueKind::AllocRefDynamicInst)
++NumOpsToWrite;
for (unsigned Idx = 0; Idx < NumOpsToWrite; ++Idx) {
if (Idx < NumTailAllocs) {
assert(TailTypes[Idx].isObject());
Args.push_back(S.addTypeRef(TailTypes[Idx].getSwiftRValueType()));
}
SILValue OpVal = AllOps[Idx].get();
Args.push_back(addValueRef(OpVal));
SILType OpType = OpVal->getType();
assert(OpType.isObject());
Args.push_back(S.addTypeRef(OpType.getSwiftRValueType()));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind(),
S.addTypeRef(
ARI->getType().getSwiftRValueType()),
(unsigned)ARI->getType().getCategory(),
Args);
break;
}
case ValueKind::AllocStackInst: {
const AllocStackInst *ASI = cast<AllocStackInst>(&SI);
writeOneTypeLayout(ASI->getKind(), ASI->getElementType());
break;
}
case ValueKind::ProjectValueBufferInst: {
auto PVBI = cast<ProjectValueBufferInst>(&SI);
writeOneTypeOneOperandLayout(PVBI->getKind(), 0,
PVBI->getType(),
PVBI->getOperand());
break;
}
case ValueKind::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.getSwiftRValueType());
SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeOneOperandLayout::Code],
unsigned(PBI->getKind()), 0,
PBI->getFieldIndex(), 0,
boxTypeRef, unsigned(boxType.getCategory()),
boxRef);
break;
}
case ValueKind::ProjectExistentialBoxInst: {
auto PEBI = cast<ProjectExistentialBoxInst>(&SI);
writeOneTypeOneOperandLayout(PEBI->getKind(), 0,
PEBI->getType(),
PEBI->getOperand());
break;
}
case ValueKind::BuiltinInst: {
// Format: number of substitutions, the builtin name, result type, and
// a list of values for the arguments. Each value in the list
// is represented with 4 IDs:
// ValueID, ValueResultNumber, TypeID, TypeCategory.
// The record is followed by the substitution list.
const BuiltinInst *BI = cast<BuiltinInst>(&SI);
SmallVector<ValueID, 4> Args;
for (auto Arg : BI->getArguments()) {
Args.push_back(addValueRef(Arg));
Args.push_back(S.addTypeRef(Arg->getType().getSwiftRValueType()));
Args.push_back((unsigned)Arg->getType().getCategory());
}
SILInstApplyLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILInstApplyLayout::Code],
SIL_BUILTIN,
BI->getSubstitutions().size(),
S.addTypeRef(BI->getType().getSwiftRValueType()),
(unsigned)BI->getType().getCategory(),
S.addIdentifierRef(BI->getName()),
Args);
S.writeSubstitutions(BI->getSubstitutions(), SILAbbrCodes);
break;
}
case ValueKind::ApplyInst: {
// Format: attributes such as transparent and number of substitutions,
// the callee's substituted and unsubstituted types, a value for
// the callee and a list of values for the arguments. Each value in the list
// is represented with 2 IDs: ValueID and ValueResultNumber. The record
// is followed by the substitution list.
const ApplyInst *AI = cast<ApplyInst>(&SI);
SmallVector<ValueID, 4> Args;
for (auto Arg: AI->getArguments()) {
Args.push_back(addValueRef(Arg));
}
SILInstApplyLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILInstApplyLayout::Code],
AI->isNonThrowing() ? SIL_NON_THROWING_APPLY : SIL_APPLY,
AI->getSubstitutions().size(),
S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()),
S.addTypeRef(AI->getSubstCalleeType()),
addValueRef(AI->getCallee()),
Args);
S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes);
break;
}
case ValueKind::TryApplyInst: {
// Format: attributes such as transparent and number of substitutions,
// the callee's substituted and unsubstituted types, a value for
// the callee and a list of values for the arguments. Each value in the list
// is represented with 2 IDs: ValueID and ValueResultNumber. The final two
// entries in the list are the basic block destinations. The record
// is followed by the substitution list.
const TryApplyInst *AI = cast<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()]);
SILInstApplyLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILInstApplyLayout::Code], SIL_TRY_APPLY,
AI->getSubstitutions().size(),
S.addTypeRef(AI->getCallee()->getType().getSwiftRValueType()),
S.addTypeRef(AI->getSubstCalleeType()),
addValueRef(AI->getCallee()),
Args);
S.writeSubstitutions(AI->getSubstitutions(), SILAbbrCodes);
break;
}
case ValueKind::PartialApplyInst: {
const PartialApplyInst *PAI = cast<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,
PAI->getSubstitutions().size(),
S.addTypeRef(PAI->getCallee()->getType().getSwiftRValueType()),
S.addTypeRef(PAI->getType().getSwiftRValueType()),
addValueRef(PAI->getCallee()),
Args);
S.writeSubstitutions(PAI->getSubstitutions(), SILAbbrCodes);
break;
}
case ValueKind::AllocGlobalInst: {
// Format: Name and type. Use SILOneOperandLayout.
const AllocGlobalInst *AGI = cast<AllocGlobalInst>(&SI);
SILOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneOperandLayout::Code],
(unsigned)SI.getKind(), 0, 0, 0,
S.addIdentifierRef(
Ctx.getIdentifier(AGI->getReferencedGlobal()->getName())));
break;
}
case ValueKind::GlobalAddrInst: {
// Format: Name and type. Use SILOneOperandLayout.
const GlobalAddrInst *GAI = cast<GlobalAddrInst>(&SI);
SILOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneOperandLayout::Code],
(unsigned)SI.getKind(), 0,
S.addTypeRef(GAI->getType().getSwiftRValueType()),
(unsigned)GAI->getType().getCategory(),
S.addIdentifierRef(
Ctx.getIdentifier(GAI->getReferencedGlobal()->getName())));
break;
}
case ValueKind::BranchInst: {
// Format: destination basic block ID, a list of arguments. Use
// SILOneTypeValuesLayout.
const BranchInst *BrI = cast<BranchInst>(&SI);
SmallVector<ValueID, 4> ListOfValues;
for (auto Elt : BrI->getArgs()) {
ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)Elt->getType().getCategory());
ListOfValues.push_back(addValueRef(Elt));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
BasicBlockMap[BrI->getDestBB()], 0, ListOfValues);
break;
}
case ValueKind::CondBranchInst: {
// Format: condition, true basic block ID, a list of arguments, false basic
// block ID, a list of arguments. Use SILOneTypeValuesLayout: the type is
// for condition, the list has value for condition, true basic block ID,
// false basic block ID, number of true arguments, and a list of true|false
// arguments.
const CondBranchInst *CBI = cast<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().getSwiftRValueType()));
ListOfValues.push_back((unsigned)Elt->getType().getCategory());
ListOfValues.push_back(addValueRef(Elt));
}
for (auto Elt : CBI->getFalseArgs()) {
ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)Elt->getType().getCategory());
ListOfValues.push_back(addValueRef(Elt));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(CBI->getCondition()->getType().getSwiftRValueType()),
(unsigned)CBI->getCondition()->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::SwitchEnumInst:
case ValueKind::SwitchEnumAddrInst: {
// Format: condition, a list of cases (EnumElementDecl + Basic Block ID),
// default basic block ID. Use SILOneTypeValuesLayout: the type is
// for condition, the list has value for condition, hasDefault, default
// basic block ID, a list of (DeclID, BasicBlock ID).
const SwitchEnumInstBase *SOI = cast<SwitchEnumInstBase>(&SI);
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]);
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(SOI->getOperand()->getType().getSwiftRValueType()),
(unsigned)SOI->getOperand()->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::SelectEnumInst:
case ValueKind::SelectEnumAddrInst: {
// Format: condition, a list of cases (EnumElementDecl + Value ID),
// default value ID. Use SILOneTypeValuesLayout: the type is
// for condition, the list has value for condition, result type,
// hasDefault, default
// basic block ID, a list of (DeclID, BasicBlock ID).
const SelectEnumInstBase *SOI = cast<SelectEnumInstBase>(&SI);
SmallVector<ValueID, 4> ListOfValues;
ListOfValues.push_back(addValueRef(SOI->getEnumOperand()));
ListOfValues.push_back(S.addTypeRef(SOI->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)SOI->getType().getCategory());
ListOfValues.push_back((unsigned)SOI->hasDefault());
if (SOI->hasDefault()) {
ListOfValues.push_back(addValueRef(SOI->getDefaultResult()));
} else {
ListOfValues.push_back(0);
}
for (unsigned i = 0, e = SOI->getNumCases(); i < e; ++i) {
EnumElementDecl *elt;
SILValue result;
std::tie(elt, result) = SOI->getCase(i);
ListOfValues.push_back(S.addDeclRef(elt));
ListOfValues.push_back(addValueRef(result));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(SOI->getEnumOperand()->getType().getSwiftRValueType()),
(unsigned)SOI->getEnumOperand()->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::SwitchValueInst: {
// Format: condition, a list of cases (Value ID + Basic Block ID),
// default basic block ID. Use SILOneTypeValuesLayout: the type is
// for condition, the list contains value for condition, hasDefault, default
// basic block ID, a list of (Value ID, BasicBlock ID).
const SwitchValueInst *SII = cast<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().getSwiftRValueType()),
(unsigned)SII->getOperand()->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::SelectValueInst: {
// Format: condition, a list of cases (Value ID + Value ID),
// default value ID. Use SILOneTypeValuesLayout: the type is
// for condition, the list has value for condition, result type,
// hasDefault, default
// basic block ID, a list of (Value ID, Value ID).
const SelectValueInst *SVI = cast<SelectValueInst>(&SI);
SmallVector<ValueID, 4> ListOfValues;
ListOfValues.push_back(addValueRef(SVI->getOperand()));
ListOfValues.push_back(S.addTypeRef(SVI->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)SVI->getType().getCategory());
ListOfValues.push_back((unsigned)SVI->hasDefault());
if (SVI->hasDefault()) {
ListOfValues.push_back(addValueRef(SVI->getDefaultResult()));
} else {
ListOfValues.push_back(0);
}
for (unsigned i = 0, e = SVI->getNumCases(); i < e; ++i) {
SILValue casevalue;
SILValue result;
std::tie(casevalue, result) = SVI->getCase(i);
ListOfValues.push_back(addValueRef(casevalue));
ListOfValues.push_back(addValueRef(result));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(SVI->getOperand()->getType().getSwiftRValueType()),
(unsigned)SVI->getOperand()->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::CondFailInst:
case ValueKind::RetainValueInst:
case ValueKind::CopyValueInst:
case ValueKind::CopyUnownedValueInst:
case ValueKind::DestroyValueInst:
case ValueKind::ReleaseValueInst:
case ValueKind::AutoreleaseValueInst:
case ValueKind::SetDeallocatingInst:
case ValueKind::DeallocStackInst:
case ValueKind::DeallocRefInst:
case ValueKind::DeinitExistentialAddrInst:
case ValueKind::DestroyAddrInst:
case ValueKind::IsNonnullInst:
case ValueKind::LoadInst:
case ValueKind::LoadBorrowInst:
case ValueKind::BeginBorrowInst:
case ValueKind::LoadUnownedInst:
case ValueKind::LoadWeakInst:
case ValueKind::MarkUninitializedInst:
case ValueKind::FixLifetimeInst:
case ValueKind::CopyBlockInst:
case ValueKind::StrongPinInst:
case ValueKind::StrongReleaseInst:
case ValueKind::StrongRetainInst:
case ValueKind::StrongUnpinInst:
case ValueKind::StrongRetainUnownedInst:
case ValueKind::UnownedRetainInst:
case ValueKind::UnownedReleaseInst:
case ValueKind::IsUniqueInst:
case ValueKind::IsUniqueOrPinnedInst:
case ValueKind::ReturnInst:
case ValueKind::ThrowInst: {
unsigned Attr = 0;
if (auto *LI = dyn_cast<LoadInst>(&SI))
Attr = unsigned(LI->getOwnershipQualifier());
else if (auto *LWI = dyn_cast<LoadWeakInst>(&SI))
Attr = LWI->isTake();
else if (auto *LUI = dyn_cast<LoadUnownedInst>(&SI))
Attr = LUI->isTake();
else if (auto *MUI = dyn_cast<MarkUninitializedInst>(&SI))
Attr = (unsigned)MUI->getKind();
else if (auto *DRI = dyn_cast<DeallocRefInst>(&SI))
Attr = (unsigned)DRI->canAllocOnStack();
else if (auto *RCI = dyn_cast<RefCountingInst>(&SI))
Attr = RCI->isNonAtomic();
writeOneOperandLayout(SI.getKind(), Attr, SI.getOperand(0));
break;
}
case ValueKind::FunctionRefInst: {
// Use SILOneOperandLayout to specify the function type and the function
// name (IdentifierID).
const FunctionRefInst *FRI = cast<FunctionRefInst>(&SI);
SILFunction *ReferencedFunction = FRI->getReferencedFunction();
unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind(), 0,
S.addTypeRef(FRI->getType().getSwiftRValueType()),
(unsigned)FRI->getType().getCategory(),
S.addIdentifierRef(Ctx.getIdentifier(ReferencedFunction->getName())));
// Make sure we declare the referenced function.
addReferencedSILFunction(ReferencedFunction);
break;
}
case ValueKind::DeallocPartialRefInst:
case ValueKind::MarkDependenceInst:
case ValueKind::IndexAddrInst:
case ValueKind::IndexRawPointerInst: {
SILValue operand, operand2;
unsigned Attr = 0;
if (SI.getKind() == ValueKind::DeallocPartialRefInst) {
const DeallocPartialRefInst *DPRI = cast<DeallocPartialRefInst>(&SI);
operand = DPRI->getInstance();
operand2 = DPRI->getMetatype();
} else if (SI.getKind() == ValueKind::IndexRawPointerInst) {
const IndexRawPointerInst *IRP = cast<IndexRawPointerInst>(&SI);
operand = IRP->getBase();
operand2 = IRP->getIndex();
} else if (SI.getKind() == ValueKind::MarkDependenceInst) {
const MarkDependenceInst *MDI = cast<MarkDependenceInst>(&SI);
operand = MDI->getValue();
operand2 = MDI->getBase();
} else {
const IndexAddrInst *IAI = cast<IndexAddrInst>(&SI);
operand = IAI->getBase();
operand2 = IAI->getIndex();
}
SILTwoOperandsLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILTwoOperandsLayout::Code],
(unsigned)SI.getKind(), Attr,
S.addTypeRef(operand->getType().getSwiftRValueType()),
(unsigned)operand->getType().getCategory(),
addValueRef(operand),
S.addTypeRef(operand2->getType().getSwiftRValueType()),
(unsigned)operand2->getType().getCategory(),
addValueRef(operand2));
break;
}
case ValueKind::TailAddrInst: {
const TailAddrInst *TAI = cast<TailAddrInst>(&SI);
SILTailAddrLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILTailAddrLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(TAI->getBase()->getType().getSwiftRValueType()),
addValueRef(TAI->getBase()),
S.addTypeRef(TAI->getIndex()->getType().getSwiftRValueType()),
addValueRef(TAI->getIndex()),
S.addTypeRef(TAI->getTailType().getSwiftRValueType()));
break;
}
case ValueKind::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.addIdentifierRef(Ctx.getIdentifier(Str)));
break;
}
case ValueKind::FloatLiteralInst:
case ValueKind::IntegerLiteralInst: {
// Use SILOneOperandLayout to specify the type and the literal.
std::string Str;
SILType Ty;
switch (SI.getKind()) {
default: llvm_unreachable("Out of sync with parent switch");
case ValueKind::IntegerLiteralInst:
Str = cast<IntegerLiteralInst>(&SI)->getValue().toString(10, true);
Ty = cast<IntegerLiteralInst>(&SI)->getType();
break;
case ValueKind::FloatLiteralInst:
Str = cast<FloatLiteralInst>(&SI)->getBits().toString(16,
/*Signed*/false);
Ty = cast<FloatLiteralInst>(&SI)->getType();
break;
}
unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind(), 0,
S.addTypeRef(Ty.getSwiftRValueType()),
(unsigned)Ty.getCategory(),
S.addIdentifierRef(Ctx.getIdentifier(Str)));
break;
}
case ValueKind::MarkFunctionEscapeInst: {
// Format: a list of typed values. A typed value is expressed by 4 IDs:
// TypeID, TypeCategory, ValueID, ValueResultNumber.
const MarkFunctionEscapeInst *MFE = cast<MarkFunctionEscapeInst>(&SI);
SmallVector<ValueID, 4> ListOfValues;
for (auto Elt : MFE->getElements()) {
ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)Elt->getType().getCategory());
ListOfValues.push_back(addValueRef(Elt));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(), 0, 0, ListOfValues);
break;
}
case ValueKind::MetatypeInst:
writeOneTypeLayout(SI.getKind(), SI.getType());
break;
case ValueKind::ObjCProtocolInst: {
const ObjCProtocolInst *PI = cast<ObjCProtocolInst>(&SI);
unsigned abbrCode = SILAbbrCodes[SILOneOperandLayout::Code];
SILOneOperandLayout::emitRecord(Out, ScratchRecord, abbrCode,
(unsigned)SI.getKind(), 0,
S.addTypeRef(PI->getType().getSwiftRValueType()),
(unsigned)PI->getType().getCategory(),
S.addDeclRef(PI->getProtocol()));
break;
}
// Conversion instructions (and others of similar form).
case ValueKind::OpenExistentialAddrInst:
case ValueKind::OpenExistentialRefInst:
case ValueKind::OpenExistentialMetatypeInst:
case ValueKind::OpenExistentialBoxInst:
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::UncheckedBitwiseCastInst:
case ValueKind::BridgeObjectToRefInst:
case ValueKind::BridgeObjectToWordInst:
case ValueKind::UpcastInst:
case ValueKind::AddressToPointerInst:
case ValueKind::RefToRawPointerInst:
case ValueKind::RawPointerToRefInst:
case ValueKind::RefToUnownedInst:
case ValueKind::UnownedToRefInst:
case ValueKind::RefToUnmanagedInst:
case ValueKind::UnmanagedToRefInst:
case ValueKind::ThinToThickFunctionInst:
case ValueKind::ThickToObjCMetatypeInst:
case ValueKind::ObjCToThickMetatypeInst:
case ValueKind::ConvertFunctionInst:
case ValueKind::ThinFunctionToPointerInst:
case ValueKind::PointerToThinFunctionInst:
case ValueKind::ObjCMetatypeToObjectInst:
case ValueKind::ObjCExistentialMetatypeToObjectInst:
case ValueKind::ProjectBlockStorageInst: {
writeConversionLikeInstruction(&SI);
break;
}
case ValueKind::PointerToAddressInst: {
assert(SI.getNumOperands() - SI.getTypeDependentOperands().size() == 1);
unsigned attrs = cast<PointerToAddressInst>(SI).isStrict() ? 1 : 0;
writeOneTypeOneOperandLayout(SI.getKind(), attrs, SI.getType(),
SI.getOperand(0));
break;
}
case ValueKind::RefToBridgeObjectInst: {
auto RI = cast<RefToBridgeObjectInst>(&SI);
SILTwoOperandsLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILTwoOperandsLayout::Code], (unsigned)SI.getKind(),
/*attr*/ 0,
S.addTypeRef(RI->getConverted()->getType().getSwiftRValueType()),
(unsigned)RI->getConverted()->getType().getCategory(),
addValueRef(RI->getConverted()),
S.addTypeRef(RI->getBitsOperand()->getType().getSwiftRValueType()),
(unsigned)RI->getBitsOperand()->getType().getCategory(),
addValueRef(RI->getBitsOperand()));
break;
}
// Checked Conversion instructions.
case ValueKind::UnconditionalCheckedCastInst: {
auto CI = cast<UnconditionalCheckedCastInst>(&SI);
SILInstCastLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILInstCastLayout::Code],
(unsigned)SI.getKind(), /*attr*/ 0,
S.addTypeRef(CI->getType().getSwiftRValueType()),
(unsigned)CI->getType().getCategory(),
S.addTypeRef(CI->getOperand()->getType().getSwiftRValueType()),
(unsigned)CI->getOperand()->getType().getCategory(),
addValueRef(CI->getOperand()));
break;
}
case ValueKind::UnconditionalCheckedCastAddrInst: {
auto CI = cast<UnconditionalCheckedCastAddrInst>(&SI);
ValueID listOfValues[] = {
toStableCastConsumptionKind(CI->getConsumptionKind()),
S.addTypeRef(CI->getSourceType()),
addValueRef(CI->getSrc()),
S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()),
(unsigned)CI->getSrc()->getType().getCategory(),
S.addTypeRef(CI->getTargetType()),
addValueRef(CI->getDest())
};
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()),
(unsigned)CI->getDest()->getType().getCategory(),
llvm::makeArrayRef(listOfValues));
break;
}
case ValueKind::UncheckedRefCastAddrInst: {
auto CI = cast<UncheckedRefCastAddrInst>(&SI);
ValueID listOfValues[] = {
S.addTypeRef(CI->getSourceType()),
addValueRef(CI->getSrc()),
S.addTypeRef(CI->getSrc()->getType().getSwiftRValueType()),
(unsigned)CI->getSrc()->getType().getCategory(),
S.addTypeRef(CI->getTargetType()),
addValueRef(CI->getDest())
};
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(CI->getDest()->getType().getSwiftRValueType()),
(unsigned)CI->getDest()->getType().getCategory(),
llvm::makeArrayRef(listOfValues));
break;
}
case ValueKind::EndBorrowInst: {
unsigned abbrCode = SILAbbrCodes[SILTwoOperandsLayout::Code];
unsigned Attr = 0;
auto *EBI = cast<EndBorrowInst>(&SI);
SILValue Src = EBI->getSrc();
SILValue Dest = EBI->getDest();
SILTwoOperandsLayout::emitRecord(
Out, ScratchRecord, abbrCode, (unsigned)SI.getKind(), Attr,
S.addTypeRef(Src->getType().getSwiftRValueType()),
(unsigned)Src->getType().getCategory(), addValueRef(Src),
S.addTypeRef(Dest->getType().getSwiftRValueType()),
(unsigned)Dest->getType().getCategory(), addValueRef(Dest));
break;
}
case ValueKind::AssignInst:
case ValueKind::CopyAddrInst:
case ValueKind::StoreInst:
case ValueKind::StoreBorrowInst:
case ValueKind::StoreUnownedInst:
case ValueKind::StoreWeakInst: {
SILValue operand, value;
unsigned Attr = 0;
if (SI.getKind() == ValueKind::StoreWeakInst) {
Attr = cast<StoreWeakInst>(&SI)->isInitializationOfDest();
operand = cast<StoreWeakInst>(&SI)->getDest();
value = cast<StoreWeakInst>(&SI)->getSrc();
} else if (SI.getKind() == ValueKind::StoreUnownedInst) {
Attr = cast<StoreUnownedInst>(&SI)->isInitializationOfDest();
operand = cast<StoreUnownedInst>(&SI)->getDest();
value = cast<StoreUnownedInst>(&SI)->getSrc();
} else if (SI.getKind() == ValueKind::StoreInst) {
Attr = unsigned(cast<StoreInst>(&SI)->getOwnershipQualifier());
operand = cast<StoreInst>(&SI)->getDest();
value = cast<StoreInst>(&SI)->getSrc();
} else if (SI.getKind() == ValueKind::AssignInst) {
operand = cast<AssignInst>(&SI)->getDest();
value = cast<AssignInst>(&SI)->getSrc();
} else if (SI.getKind() == ValueKind::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 (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().getSwiftRValueType()),
(unsigned)operand->getType().getCategory(),
addValueRef(operand));
break;
}
case ValueKind::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().getSwiftRValueType()));
ListOfValues.push_back((unsigned)baseOperand->getType().getCategory());
ListOfValues.push_back(addValueRef(baseOperand));
ListOfValues.push_back(S.addTypeRef(
indexOperand->getType().getSwiftRValueType()));
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.getSwiftRValueType()),
(unsigned)boundType.getCategory(),
ListOfValues);
break;
}
case ValueKind::RefElementAddrInst:
case ValueKind::StructElementAddrInst:
case ValueKind::StructExtractInst:
case ValueKind::InitEnumDataAddrInst:
case ValueKind::UncheckedEnumDataInst:
case ValueKind::UncheckedTakeEnumDataAddrInst:
case ValueKind::InjectEnumAddrInst: {
// Has a typed valueref and a field decl. We use SILOneValueOneOperandLayout
// where the field decl is streamed as a ValueID.
SILValue operand;
Decl *tDecl;
switch (SI.getKind()) {
default: llvm_unreachable("Out of sync with parent switch");
case ValueKind::RefElementAddrInst:
operand = cast<RefElementAddrInst>(&SI)->getOperand();
tDecl = cast<RefElementAddrInst>(&SI)->getField();
break;
case ValueKind::StructElementAddrInst:
operand = cast<StructElementAddrInst>(&SI)->getOperand();
tDecl = cast<StructElementAddrInst>(&SI)->getField();
break;
case ValueKind::StructExtractInst:
operand = cast<StructExtractInst>(&SI)->getOperand();
tDecl = cast<StructExtractInst>(&SI)->getField();
break;
case ValueKind::InitEnumDataAddrInst:
operand = cast<InitEnumDataAddrInst>(&SI)->getOperand();
tDecl = cast<InitEnumDataAddrInst>(&SI)->getElement();
break;
case ValueKind::UncheckedEnumDataInst:
operand = cast<UncheckedEnumDataInst>(&SI)->getOperand();
tDecl = cast<UncheckedEnumDataInst>(&SI)->getElement();
break;
case ValueKind::UncheckedTakeEnumDataAddrInst:
operand = cast<UncheckedTakeEnumDataAddrInst>(&SI)->getOperand();
tDecl = cast<UncheckedTakeEnumDataAddrInst>(&SI)->getElement();
break;
case ValueKind::InjectEnumAddrInst:
operand = cast<InjectEnumAddrInst>(&SI)->getOperand();
tDecl = cast<InjectEnumAddrInst>(&SI)->getElement();
break;
}
SILOneValueOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneValueOneOperandLayout::Code],
(unsigned)SI.getKind(), 0, S.addDeclRef(tDecl),
S.addTypeRef(operand->getType().getSwiftRValueType()),
(unsigned)operand->getType().getCategory(),
addValueRef(operand));
break;
}
case ValueKind::RefTailAddrInst: {
auto *RTAI = cast<RefTailAddrInst>(&SI);
writeOneTypeOneOperandLayout(RTAI->getKind(), 0,
RTAI->getType(),
RTAI->getOperand());
break;
}
case ValueKind::StructInst: {
// Format: a type followed by a list of typed values. A typed value is
// expressed by 4 IDs: TypeID, TypeCategory, ValueID, ValueResultNumber.
const StructInst *StrI = cast<StructInst>(&SI);
SmallVector<ValueID, 4> ListOfValues;
for (auto Elt : StrI->getElements()) {
ListOfValues.push_back(S.addTypeRef(Elt->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)Elt->getType().getCategory());
ListOfValues.push_back(addValueRef(Elt));
}
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code],
(unsigned)SI.getKind(),
S.addTypeRef(StrI->getType().getSwiftRValueType()),
(unsigned)StrI->getType().getCategory(), ListOfValues);
break;
}
case ValueKind::TupleElementAddrInst:
case ValueKind::TupleExtractInst: {
SILValue operand;
unsigned FieldNo;
switch (SI.getKind()) {
default: llvm_unreachable("Out of sync with parent switch");
case ValueKind::TupleElementAddrInst:
operand = cast<TupleElementAddrInst>(&SI)->getOperand();
FieldNo = cast<TupleElementAddrInst>(&SI)->getFieldNo();
break;
case ValueKind::TupleExtractInst:
operand = cast<TupleExtractInst>(&SI)->getOperand();
FieldNo = cast<TupleExtractInst>(&SI)->getFieldNo();
break;
}
// Use OneTypeOneOperand layout where the field number is stored in TypeID.
SILOneTypeOneOperandLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeOneOperandLayout::Code],
(unsigned)SI.getKind(), 0,
FieldNo, 0,
S.addTypeRef(operand->getType().getSwiftRValueType()),
(unsigned)operand->getType().getCategory(),
addValueRef(operand));
break;
}
case ValueKind::TupleInst: {
// Format: a type followed by a list of values. A value is expressed by
// 2 IDs: ValueID, ValueResultNumber.
const TupleInst *TI = cast<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().getSwiftRValueType()),
(unsigned)TI->getType().getCategory(),
ListOfValues);
break;
}
case ValueKind::EnumInst: {
// Format: a type, an operand and a decl ID. Use SILTwoOperandsLayout: type,
// (DeclID + hasOperand), and an operand.
const EnumInst *UI = cast<EnumInst>(&SI);
TypeID OperandTy = UI->hasOperand() ?
S.addTypeRef(UI->getOperand()->getType().getSwiftRValueType()) : 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().getSwiftRValueType()),
(unsigned)UI->getType().getCategory(),
S.addDeclRef(UI->getElement()),
OperandTy, OperandTyCategory,
UI->hasOperand() ? addValueRef(UI->getOperand()) : ValueID());
break;
}
case ValueKind::WitnessMethodInst: {
// Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
// type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type.
const WitnessMethodInst *AMI = cast<WitnessMethodInst>(&SI);
CanType Ty = AMI->getLookupType();
SILType Ty2 = AMI->getType();
SmallVector<ValueID, 8> ListOfValues;
handleSILDeclRef(S, AMI->getMember(), ListOfValues);
// Add an optional operand.
TypeID OperandTy = TypeID();
unsigned OperandTyCategory = 0;
SILValue OptionalOpenedExistential = SILValue();
auto OperandValueId = addValueRef(OptionalOpenedExistential);
SILInstWitnessMethodLayout::emitRecord(
Out, ScratchRecord, SILAbbrCodes[SILInstWitnessMethodLayout::Code],
S.addTypeRef(Ty), 0, AMI->isVolatile(),
S.addTypeRef(Ty2.getSwiftRValueType()), (unsigned)Ty2.getCategory(),
OperandTy, OperandTyCategory, OperandValueId, ListOfValues);
S.writeConformance(AMI->getConformance(), SILAbbrCodes);
break;
}
case ValueKind::ClassMethodInst: {
// Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
// type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
// and an operand.
const ClassMethodInst *CMI = cast<ClassMethodInst>(&SI);
SILType Ty = CMI->getType();
SmallVector<ValueID, 9> ListOfValues;
handleMethodInst(CMI, CMI->getOperand(), ListOfValues);
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(Ty.getSwiftRValueType()),
(unsigned)Ty.getCategory(), ListOfValues);
break;
}
case ValueKind::SuperMethodInst: {
// Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
// type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
// and an operand.
const SuperMethodInst *SMI = cast<SuperMethodInst>(&SI);
SILType Ty = SMI->getType();
SmallVector<ValueID, 9> ListOfValues;
handleMethodInst(SMI, SMI->getOperand(), ListOfValues);
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(Ty.getSwiftRValueType()),
(unsigned)Ty.getCategory(), ListOfValues);
break;
}
case ValueKind::DynamicMethodInst: {
// Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout:
// type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC),
// and an operand.
const DynamicMethodInst *DMI = cast<DynamicMethodInst>(&SI);
SILType Ty = DMI->getType();
SmallVector<ValueID, 9> ListOfValues;
handleMethodInst(DMI, DMI->getOperand(), ListOfValues);
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(Ty.getSwiftRValueType()),
(unsigned)Ty.getCategory(), ListOfValues);
break;
}
case ValueKind::DynamicMethodBranchInst: {
// Format: a typed value, a SILDeclRef, a BasicBlock ID for method,
// a BasicBlock ID for no method. Use SILOneTypeValuesLayout.
const DynamicMethodBranchInst *DMB = cast<DynamicMethodBranchInst>(&SI);
SmallVector<ValueID, 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().getSwiftRValueType()),
(unsigned)DMB->getOperand()->getType().getCategory(), ListOfValues);
break;
}
case ValueKind::CheckedCastBranchInst: {
// Format: the cast kind, a typed value, a BasicBlock ID for success,
// a BasicBlock ID for failure. Uses SILOneTypeValuesLayout.
const CheckedCastBranchInst *CBI = cast<CheckedCastBranchInst>(&SI);
SmallVector<ValueID, 8> ListOfValues;
ListOfValues.push_back(CBI->isExact()),
ListOfValues.push_back(addValueRef(CBI->getOperand()));
ListOfValues.push_back(
S.addTypeRef(CBI->getOperand()->getType().getSwiftRValueType()));
ListOfValues.push_back((unsigned)CBI->getOperand()->getType().getCategory());
ListOfValues.push_back(BasicBlockMap[CBI->getSuccessBB()]);
ListOfValues.push_back(BasicBlockMap[CBI->getFailureBB()]);
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(CBI->getCastType().getSwiftRValueType()),
(unsigned)CBI->getCastType().getCategory(),
ListOfValues);
break;
}
case ValueKind::CheckedCastAddrBranchInst: {
// Format: the cast kind, two typed values, a BasicBlock ID for
// success, a BasicBlock ID for failure. Uses SILOneTypeValuesLayout;
// the type is the type of the second (dest) operand.
auto CBI = cast<CheckedCastAddrBranchInst>(&SI);
ValueID listOfValues[] = {
toStableCastConsumptionKind(CBI->getConsumptionKind()),
S.addTypeRef(CBI->getSourceType()),
addValueRef(CBI->getSrc()),
S.addTypeRef(CBI->getSrc()->getType().getSwiftRValueType()),
(unsigned)CBI->getSrc()->getType().getCategory(),
S.addTypeRef(CBI->getTargetType()),
addValueRef(CBI->getDest()),
BasicBlockMap[CBI->getSuccessBB()],
BasicBlockMap[CBI->getFailureBB()]
};
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(CBI->getDest()->getType().getSwiftRValueType()),
(unsigned)CBI->getDest()->getType().getCategory(),
llvm::makeArrayRef(listOfValues));
break;
}
case ValueKind::InitBlockStorageHeaderInst: {
auto IBSHI = cast<InitBlockStorageHeaderInst>(&SI);
SmallVector<ValueID, 6> ListOfValues;
ListOfValues.push_back(addValueRef(IBSHI->getBlockStorage()));
ListOfValues.push_back(
S.addTypeRef(IBSHI->getBlockStorage()->getType().getSwiftRValueType()));
// Always an address, don't need to save category
ListOfValues.push_back(addValueRef(IBSHI->getInvokeFunction()));
ListOfValues.push_back(
S.addTypeRef(IBSHI->getInvokeFunction()->getType().getSwiftRValueType()));
// Always a value, don't need to save category
ListOfValues.push_back(IBSHI->getSubstitutions().size());
SILOneTypeValuesLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILOneTypeValuesLayout::Code], (unsigned)SI.getKind(),
S.addTypeRef(IBSHI->getType().getSwiftRValueType()),
(unsigned)IBSHI->getType().getCategory(),
ListOfValues);
S.writeSubstitutions(IBSHI->getSubstitutions(), SILAbbrCodes);
break;
}
case ValueKind::MarkUninitializedBehaviorInst:
llvm_unreachable("todo");
}
// Non-void values get registered in the value table.
if (SI.hasValue()) {
addValueRef(&SI);
++InstID;
}
}
/// Depending on the RecordKind, we write the SILFunction table, the global
/// variable table, the table for SILVTable, or the table for SILWitnessTable.
static void writeIndexTable(const sil_index_block::ListLayout &List,
sil_index_block::RecordKind kind,
const SILSerializer::Table &table) {
assert((kind == sil_index_block::SIL_FUNC_NAMES ||
kind == sil_index_block::SIL_VTABLE_NAMES ||
kind == sil_index_block::SIL_GLOBALVAR_NAMES ||
kind == sil_index_block::SIL_WITNESS_TABLE_NAMES ||
kind == sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES) &&
"SIL function table, global, vtable and (default) witness table "
"are supported");
llvm::SmallString<4096> hashTableBlob;
uint32_t tableOffset;
{
llvm::OnDiskChainedHashTableGenerator<FuncTableInfo> generator;
for (auto &entry : table)
generator.insert(entry.first, entry.second);
llvm::raw_svector_ostream blobStream(hashTableBlob);
// Make sure that no bucket is at offset 0.
endian::Writer<little>(blobStream).write<uint32_t>(0);
tableOffset = generator.Emit(blobStream);
}
SmallVector<uint64_t, 8> scratch;
List.emit(scratch, kind, tableOffset, hashTableBlob);
}
void SILSerializer::writeIndexTables() {
BCBlockRAII restoreBlock(Out, SIL_INDEX_BLOCK_ID, 4);
sil_index_block::ListLayout List(Out);
sil_index_block::OffsetLayout Offset(Out);
if (!FuncTable.empty()) {
writeIndexTable(List, sil_index_block::SIL_FUNC_NAMES, FuncTable);
Offset.emit(ScratchRecord, sil_index_block::SIL_FUNC_OFFSETS, Funcs);
}
if (!VTableList.empty()) {
writeIndexTable(List, sil_index_block::SIL_VTABLE_NAMES, VTableList);
Offset.emit(ScratchRecord, sil_index_block::SIL_VTABLE_OFFSETS,
VTableOffset);
}
if (!GlobalVarList.empty()) {
writeIndexTable(List, sil_index_block::SIL_GLOBALVAR_NAMES, GlobalVarList);
Offset.emit(ScratchRecord, sil_index_block::SIL_GLOBALVAR_OFFSETS,
GlobalVarOffset);
}
if (!WitnessTableList.empty()) {
writeIndexTable(List, sil_index_block::SIL_WITNESS_TABLE_NAMES,
WitnessTableList);
Offset.emit(ScratchRecord, sil_index_block::SIL_WITNESS_TABLE_OFFSETS,
WitnessTableOffset);
}
if (!DefaultWitnessTableList.empty()) {
writeIndexTable(List, sil_index_block::SIL_DEFAULT_WITNESS_TABLE_NAMES,
DefaultWitnessTableList);
Offset.emit(ScratchRecord,
sil_index_block::SIL_DEFAULT_WITNESS_TABLE_OFFSETS,
DefaultWitnessTableOffset);
}
}
void SILSerializer::writeSILGlobalVar(const SILGlobalVariable &g) {
GlobalVarList[Ctx.getIdentifier(g.getName())] = NextGlobalVarID++;
GlobalVarOffset.push_back(Out.GetCurrentBitNo());
TypeID TyID = S.addTypeRef(g.getLoweredType().getSwiftType());
DeclID dID = S.addDeclRef(g.getDecl());
SILGlobalVarLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[SILGlobalVarLayout::Code],
toStableSILLinkage(g.getLinkage()),
(unsigned)g.isFragile(),
(unsigned)!g.isDefinition(),
(unsigned)g.isLet(),
TyID, dID);
}
void SILSerializer::writeSILVTable(const SILVTable &vt) {
VTableList[vt.getClass()->getName()] = NextVTableID++;
VTableOffset.push_back(Out.GetCurrentBitNo());
VTableLayout::emitRecord(Out, ScratchRecord, SILAbbrCodes[VTableLayout::Code],
S.addDeclRef(vt.getClass()));
for (auto &entry : vt.getEntries()) {
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, entry.Method, ListOfValues);
addReferencedSILFunction(entry.Implementation, true);
// Each entry is a pair of SILDeclRef and SILFunction.
VTableEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[VTableEntryLayout::Code],
// SILFunction name
S.addIdentifierRef(Ctx.getIdentifier(entry.Implementation->getName())),
toStableSILLinkage(entry.Linkage),
ListOfValues);
}
}
void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) {
WitnessTableList[wt.getIdentifier()] = NextWitnessTableID++;
WitnessTableOffset.push_back(Out.GetCurrentBitNo());
WitnessTableLayout::emitRecord(
Out, ScratchRecord,
SILAbbrCodes[WitnessTableLayout::Code],
toStableSILLinkage(wt.getLinkage()),
unsigned(wt.isDeclaration()),
unsigned(wt.isFragile()));
S.writeConformance(wt.getConformance(), SILAbbrCodes);
// If we have a declaration, do not attempt to serialize entries.
if (wt.isDeclaration())
return;
for (auto &entry : wt.getEntries()) {
if (entry.getKind() == SILWitnessTable::BaseProtocol) {
auto &baseWitness = entry.getBaseProtocolWitness();
WitnessBaseEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[WitnessBaseEntryLayout::Code],
S.addDeclRef(baseWitness.Requirement));
S.writeConformance(baseWitness.Witness, SILAbbrCodes);
continue;
}
if (entry.getKind() == SILWitnessTable::AssociatedTypeProtocol) {
auto &assoc = entry.getAssociatedTypeProtocolWitness();
WitnessAssocProtocolLayout::emitRecord(
Out, ScratchRecord,
SILAbbrCodes[WitnessAssocProtocolLayout::Code],
S.addDeclRef(assoc.Requirement),
S.addDeclRef(assoc.Protocol));
S.writeConformance(assoc.Witness, SILAbbrCodes);
continue;
}
if (entry.getKind() == SILWitnessTable::AssociatedType) {
auto &assoc = entry.getAssociatedTypeWitness();
WitnessAssocEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[WitnessAssocEntryLayout::Code],
S.addDeclRef(assoc.Requirement),
S.addTypeRef(assoc.Witness));
continue;
}
auto &methodWitness = entry.getMethodWitness();
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, methodWitness.Requirement, ListOfValues);
IdentifierID witnessID = 0;
if (SILFunction *witness = methodWitness.Witness) {
addReferencedSILFunction(witness, true);
witnessID = S.addIdentifierRef(Ctx.getIdentifier(witness->getName()));
}
WitnessMethodEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[WitnessMethodEntryLayout::Code],
// SILFunction name
witnessID,
ListOfValues);
}
}
void SILSerializer::
writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt) {
if (wt.isDeclaration())
return;
DefaultWitnessTableList[wt.getIdentifier()] = 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;
}
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, entry.getRequirement(), ListOfValues);
SILFunction *witness = entry.getWitness();
addReferencedSILFunction(witness, true);
IdentifierID witnessID = S.addIdentifierRef(
Ctx.getIdentifier(witness->getName()));
DefaultWitnessTableEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[DefaultWitnessTableEntryLayout::Code],
// SILFunction name
witnessID,
ListOfValues);
}
}
/// Helper function for whether to emit a function body.
bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F) {
// If we are asked to serialize everything, go ahead and do it.
if (ShouldSerializeAll)
return true;
// If F is a declaration, it has no body to emit...
if (F->isExternalDeclaration())
return false;
// If F is transparent, we should always emit its body.
if (F->isFragile())
return true;
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<SILOneTypeOneOperandLayout>();
registerSILAbbr<SILInitExistentialLayout>();
registerSILAbbr<SILOneTypeValuesLayout>();
registerSILAbbr<SILTwoOperandsLayout>();
registerSILAbbr<SILTailAddrLayout>();
registerSILAbbr<SILInstApplyLayout>();
registerSILAbbr<SILInstNoOperandLayout>();
registerSILAbbr<VTableLayout>();
registerSILAbbr<VTableEntryLayout>();
registerSILAbbr<SILGlobalVarLayout>();
registerSILAbbr<WitnessTableLayout>();
registerSILAbbr<WitnessMethodEntryLayout>();
registerSILAbbr<WitnessBaseEntryLayout>();
registerSILAbbr<WitnessAssocProtocolLayout>();
registerSILAbbr<WitnessAssocEntryLayout>();
registerSILAbbr<DefaultWitnessTableLayout>();
registerSILAbbr<DefaultWitnessTableEntryLayout>();
registerSILAbbr<DefaultWitnessTableNoEntryLayout>();
registerSILAbbr<SILInstCastLayout>();
registerSILAbbr<SILInstWitnessMethodLayout>();
registerSILAbbr<SILSpecializeAttrLayout>();
// Register the abbreviation codes so these layouts can exist in both
// decl blocks and sil blocks.
// We have to make sure BOUND_GENERIC_SUBSTITUTION does not overlap with
// SIL-specific records.
registerSILAbbr<decls_block::BoundGenericSubstitutionLayout>();
registerSILAbbr<decls_block::AbstractProtocolConformanceLayout>();
registerSILAbbr<decls_block::NormalProtocolConformanceLayout>();
registerSILAbbr<decls_block::SpecializedProtocolConformanceLayout>();
registerSILAbbr<decls_block::InheritedProtocolConformanceLayout>();
registerSILAbbr<decls_block::NormalProtocolConformanceIdLayout>();
registerSILAbbr<decls_block::ProtocolConformanceXrefLayout>();
registerSILAbbr<decls_block::GenericRequirementLayout>();
for (const SILGlobalVariable &g : SILMod->getSILGlobals())
writeSILGlobalVar(g);
// Write out VTables first because it may require serializations of
// non-transparent SILFunctions (body is not needed).
// Go through all SILVTables in SILMod and write them if we should
// serialize everything.
// FIXME: Resilience: could write out vtable for fragile classes.
const DeclContext *assocDC = SILMod->getAssociatedContext();
assert(assocDC && "cannot serialize SIL without an associated DeclContext");
for (const SILVTable &vt : SILMod->getVTables()) {
if (ShouldSerializeAll &&
vt.getClass()->isChildContextOf(assocDC))
writeSILVTable(vt);
}
// Write out fragile WitnessTables.
for (const SILWitnessTable &wt : SILMod->getWitnessTables()) {
if ((ShouldSerializeAll || wt.isFragile()) &&
wt.getConformance()->getDeclContext()->isChildContextOf(assocDC))
writeSILWitnessTable(wt);
}
// Write out DefaultWitnessTables.
for (const SILDefaultWitnessTable &wt : SILMod->getDefaultWitnessTables()) {
// FIXME: Don't need to serialize private and internal default witness
// tables.
if (wt.getProtocol()->getDeclContext()->isChildContextOf(assocDC))
writeSILDefaultWitnessTable(wt);
}
// Emit only declarations if it is a module with pre-specializations.
// And only do it in optimized builds.
bool emitDeclarationsForOnoneSupport =
SILMod->getSwiftModule()->getName().str() == SWIFT_ONONE_SUPPORT &&
SILMod->getOptions().Optimization > SILOptions::SILOptMode::Debug;
// Go through all the SILFunctions in SILMod and write out any
// mandatory function bodies.
for (const SILFunction &F : *SILMod) {
if (emitDeclarationsForOnoneSupport) {
// Only declarations of whitelisted pre-specializations from with
// public linkage need to be serialized as they will be used
// by UsePrespecializations pass during -Onone compilation to
// check for availability of concrete pre-specializations.
if (!hasPublicVisibility(F.getLinkage()) ||
!isWhitelistedSpecialization(F.getName()))
continue;
}
addMandatorySILFunction(&F, emitDeclarationsForOnoneSupport);
processSILFunctionWorklist();
}
// Now write function declarations for every function we've
// emitted a reference to without emitting a function body for.
for (const SILFunction &F : *SILMod) {
auto iter = FuncsToEmit.find(&F);
if (iter != FuncsToEmit.end() && iter->second) {
assert((emitDeclarationsForOnoneSupport ||
!shouldEmitFunctionBody(&F)) &&
"Should have emitted function body earlier");
writeSILFunction(F, true);
}
}
assert(Worklist.empty() && "Did not emit everything in worklist");
}
void SILSerializer::writeSILModule(const SILModule *SILMod) {
writeSILBlock(SILMod);
writeIndexTables();
}
void Serializer::writeSIL(const SILModule *SILMod, bool serializeAllSIL) {
if (!SILMod)
return;
SILSerializer SILSer(*this, M->getASTContext(), Out, serializeAllSIL);
SILSer.writeSILModule(SILMod);
}