diff --git a/llvm/include/llvm/Bitcode/BitcodeWriter.h b/llvm/include/llvm/Bitcode/BitcodeWriter.h --- a/llvm/include/llvm/Bitcode/BitcodeWriter.h +++ b/llvm/include/llvm/Bitcode/BitcodeWriter.h @@ -28,81 +28,87 @@ class BitstreamWriter; class Module; class raw_ostream; +class ModuleBitcodeWriterBase; - class BitcodeWriter { - SmallVectorImpl &Buffer; - std::unique_ptr Stream; - - StringTableBuilder StrtabBuilder{StringTableBuilder::RAW}; - - // Owns any strings created by the irsymtab writer until we create the - // string table. - BumpPtrAllocator Alloc; - - bool WroteStrtab = false, WroteSymtab = false; - - void writeBlob(unsigned Block, unsigned Record, StringRef Blob); - - std::vector Mods; - - public: - /// Create a BitcodeWriter that writes to Buffer. - BitcodeWriter(SmallVectorImpl &Buffer, raw_fd_stream *FS = nullptr); - - ~BitcodeWriter(); - - /// Attempt to write a symbol table to the bitcode file. This must be called - /// at most once after all modules have been written. - /// - /// A reader does not require a symbol table to interpret a bitcode file; - /// the symbol table is needed only to improve link-time performance. So - /// this function may decide not to write a symbol table. It may so decide - /// if, for example, the target is unregistered or the IR is malformed. - void writeSymtab(); - - /// Write the bitcode file's string table. This must be called exactly once - /// after all modules and the optional symbol table have been written. - void writeStrtab(); - - /// Copy the string table for another module into this bitcode file. This - /// should be called after copying the module itself into the bitcode file. - void copyStrtab(StringRef Strtab); - - /// Write the specified module to the buffer specified at construction time. - /// - /// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a - /// Value in \c M. These will be reconstructed exactly when \a M is - /// deserialized. - /// - /// If \c Index is supplied, the bitcode will contain the summary index - /// (currently for use in ThinLTO optimization). - /// - /// \p GenerateHash enables hashing the Module and including the hash in the - /// bitcode (currently for use in ThinLTO incremental build). - /// - /// If \p ModHash is non-null, when GenerateHash is true, the resulting - /// hash is written into ModHash. When GenerateHash is false, that value - /// is used as the hash instead of computing from the generated bitcode. - /// Can be used to produce the same module hash for a minimized bitcode - /// used just for the thin link as in the regular full bitcode that will - /// be used in the backend. - void writeModule(const Module &M, bool ShouldPreserveUseListOrder = false, - const ModuleSummaryIndex *Index = nullptr, - bool GenerateHash = false, ModuleHash *ModHash = nullptr); - - /// Write the specified thin link bitcode file (i.e., the minimized bitcode - /// file) to the buffer specified at construction time. The thin link - /// bitcode file is used for thin link, and it only contains the necessary - /// information for thin link. - /// - /// ModHash is for use in ThinLTO incremental build, generated while the - /// IR bitcode file writing. - void writeThinLinkBitcode(const Module &M, const ModuleSummaryIndex &Index, - const ModuleHash &ModHash); - - void writeIndex( - const ModuleSummaryIndex *Index, - const std::map *ModuleToSummariesForIndex); +using CreateModuleWriterFn = std::unique_ptr (*)( + const Module &M, SmallVectorImpl &Buffer, + StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream, + bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, + bool GenerateHash, ModuleHash *ModHash); +class BitcodeWriter { + SmallVectorImpl &Buffer; + std::unique_ptr Stream; + + StringTableBuilder StrtabBuilder{StringTableBuilder::RAW}; + + // Owns any strings created by the irsymtab writer until we create the + // string table. + BumpPtrAllocator Alloc; + + bool WroteStrtab = false, WroteSymtab = false; + + void writeBlob(unsigned Block, unsigned Record, StringRef Blob); + + std::vector Mods; + +public: + /// Create a BitcodeWriter that writes to Buffer. + BitcodeWriter(SmallVectorImpl &Buffer, raw_fd_stream *FS = nullptr); + + ~BitcodeWriter(); + + /// Attempt to write a symbol table to the bitcode file. This must be called + /// at most once after all modules have been written. + /// + /// A reader does not require a symbol table to interpret a bitcode file; + /// the symbol table is needed only to improve link-time performance. So + /// this function may decide not to write a symbol table. It may so decide + /// if, for example, the target is unregistered or the IR is malformed. + void writeSymtab(); + + /// Write the bitcode file's string table. This must be called exactly once + /// after all modules and the optional symbol table have been written. + void writeStrtab(); + + /// Copy the string table for another module into this bitcode file. This + /// should be called after copying the module itself into the bitcode file. + void copyStrtab(StringRef Strtab); + + /// Write the specified module to the buffer specified at construction time. + /// + /// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a + /// Value in \c M. These will be reconstructed exactly when \a M is + /// deserialized. + /// + /// If \c Index is supplied, the bitcode will contain the summary index + /// (currently for use in ThinLTO optimization). + /// + /// \p GenerateHash enables hashing the Module and including the hash in the + /// bitcode (currently for use in ThinLTO incremental build). + /// + /// If \p ModHash is non-null, when GenerateHash is true, the resulting + /// hash is written into ModHash. When GenerateHash is false, that value + /// is used as the hash instead of computing from the generated bitcode. + /// Can be used to produce the same module hash for a minimized bitcode + /// used just for the thin link as in the regular full bitcode that will + /// be used in the backend. + void writeModule(const Module &M, bool ShouldPreserveUseListOrder = false, + const ModuleSummaryIndex *Index = nullptr, + bool GenerateHash = false, ModuleHash *ModHash = nullptr, + CreateModuleWriterFn CreateWriter = nullptr); + /// Write the specified thin link bitcode file (i.e., the minimized bitcode + /// file) to the buffer specified at construction time. The thin link + /// bitcode file is used for thin link, and it only contains the necessary + /// information for thin link. + /// + /// ModHash is for use in ThinLTO incremental build, generated while the + /// IR bitcode file writing. + void writeThinLinkBitcode(const Module &M, const ModuleSummaryIndex &Index, + const ModuleHash &ModHash); + + void writeIndex( + const ModuleSummaryIndex *Index, + const std::map *ModuleToSummariesForIndex); }; /// Write the specified module to the specified raw output stream. @@ -130,7 +136,8 @@ bool ShouldPreserveUseListOrder = false, const ModuleSummaryIndex *Index = nullptr, bool GenerateHash = false, - ModuleHash *ModHash = nullptr); + ModuleHash *ModHash = nullptr, + CreateModuleWriterFn CreateWriter = nullptr); /// Write the specified thin link bitcode file (i.e., the minimized bitcode /// file) to the given raw output stream, where it will be written in a new diff --git a/llvm/include/llvm/Bitcode/BitcodeWriterBase.h b/llvm/include/llvm/Bitcode/BitcodeWriterBase.h --- a/llvm/include/llvm/Bitcode/BitcodeWriterBase.h +++ b/llvm/include/llvm/Bitcode/BitcodeWriterBase.h @@ -128,6 +128,8 @@ uint64_t VSTOffsetPlaceholder = 0; public: + virtual ~ModuleBitcodeWriterBase() {} + /// Constructs a ModuleBitcodeWriterBase object for the given Module, /// writing to the provided \p Buffer. ModuleBitcodeWriterBase(const Module &M, StringTableBuilder &StrtabBuilder, @@ -157,6 +159,8 @@ assignValueId(CallEdge.first.getGUID()); } + virtual void write() = 0; + protected: void writePerModuleGlobalValueSummary(); @@ -226,7 +230,7 @@ BitcodeStartBit(Stream.GetCurrentBitNo()) {} /// Emit the current module to the bitstream. - void write(); + void write() override; private: uint64_t bitcodeStartBit() { return BitcodeStartBit; } diff --git a/llvm/include/llvm/Bitcode/BitcodeWriterPass.h b/llvm/include/llvm/Bitcode/BitcodeWriterPass.h --- a/llvm/include/llvm/Bitcode/BitcodeWriterPass.h +++ b/llvm/include/llvm/Bitcode/BitcodeWriterPass.h @@ -14,6 +14,7 @@ #ifndef LLVM_BITCODE_BITCODEWRITERPASS_H #define LLVM_BITCODE_BITCODEWRITERPASS_H +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/PassManager.h" namespace llvm { @@ -34,10 +35,10 @@ /// /// If \c EmitModuleHash, compute and emit the module hash in the bitcode /// (currently for use in ThinLTO incremental build). -ModulePass *createBitcodeWriterPass(raw_ostream &Str, - bool ShouldPreserveUseListOrder = false, - bool EmitSummaryIndex = false, - bool EmitModuleHash = false); +ModulePass *createBitcodeWriterPass( + raw_ostream &Str, bool ShouldPreserveUseListOrder = false, + bool EmitSummaryIndex = false, bool EmitModuleHash = false, + CreateModuleWriterFn CreateWriter = nullptr); /// Check whether a pass is a BitcodeWriterPass. bool isBitcodeWriterPass(Pass *P); @@ -51,6 +52,7 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + CreateModuleWriterFn CreateWriter; public: /// Construct a bitcode writer pass around a particular output stream. @@ -63,9 +65,11 @@ explicit BitcodeWriterPass(raw_ostream &OS, bool ShouldPreserveUseListOrder = false, bool EmitSummaryIndex = false, - bool EmitModuleHash = false) + bool EmitModuleHash = false, + CreateModuleWriterFn CreateWriterFn = nullptr) : OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) {} + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + CreateWriter(CreateWriterFn) {} /// Run the bitcode writer pass, and output the module to the selected /// output stream. diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -4304,7 +4304,8 @@ void BitcodeWriter::writeModule(const Module &M, bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, - bool GenerateHash, ModuleHash *ModHash) { + bool GenerateHash, ModuleHash *ModHash, + CreateModuleWriterFn CreateWriter) { assert(!WroteStrtab); // The Mods vector is used by irsymtab::build, which requires non-const @@ -4314,6 +4315,12 @@ assert(M.isMaterialized()); Mods.push_back(const_cast(&M)); + if (CreateWriter) { + std::unique_ptr ModuleWriter = + CreateWriter(M, Buffer, StrtabBuilder, *Stream, + ShouldPreserveUseListOrder, Index, GenerateHash, ModHash); + ModuleWriter->write(); + } ModuleBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream, ShouldPreserveUseListOrder, Index, GenerateHash, ModHash); @@ -4332,7 +4339,8 @@ void llvm::WriteBitcodeToFile(const Module &M, raw_ostream &Out, bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, - bool GenerateHash, ModuleHash *ModHash) { + bool GenerateHash, ModuleHash *ModHash, + CreateModuleWriterFn CreateWriter) { SmallVector Buffer; Buffer.reserve(256*1024); @@ -4344,7 +4352,7 @@ BitcodeWriter Writer(Buffer, dyn_cast(&Out)); Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash, - ModHash); + ModHash, CreateWriter); Writer.writeSymtab(); Writer.writeStrtab(); @@ -4404,7 +4412,7 @@ /*ShouldPreserveUseListOrder=*/false, &Index), ModHash(&ModHash) {} - void write(); + void write() override; private: void writeSimplifiedModuleInfo(); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriterPass.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriterPass.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriterPass.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriterPass.cpp @@ -23,7 +23,8 @@ const ModuleSummaryIndex *Index = EmitSummaryIndex ? &(AM.getResult(M)) : nullptr; - WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash); + WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, EmitModuleHash, + nullptr, CreateWriter); return PreservedAnalyses::all(); } @@ -33,18 +34,21 @@ bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; bool EmitModuleHash; + CreateModuleWriterFn CreateWriter; public: static char ID; // Pass identification, replacement for typeid - WriteBitcodePass() : ModulePass(ID), OS(dbgs()) { + WriteBitcodePass() : ModulePass(ID), OS(dbgs()), CreateWriter(nullptr) { initializeWriteBitcodePassPass(*PassRegistry::getPassRegistry()); } explicit WriteBitcodePass(raw_ostream &o, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) + bool EmitSummaryIndex, bool EmitModuleHash, + CreateModuleWriterFn CreateWriterFn) : ModulePass(ID), OS(o), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) { + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash), + CreateWriter(CreateWriterFn) { initializeWriteBitcodePassPass(*PassRegistry::getPassRegistry()); } @@ -56,7 +60,7 @@ ? &(getAnalysis().getIndex()) : nullptr; WriteBitcodeToFile(M, OS, ShouldPreserveUseListOrder, Index, - EmitModuleHash); + EmitModuleHash, nullptr, CreateWriter); return false; } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -76,9 +80,11 @@ ModulePass *llvm::createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder, - bool EmitSummaryIndex, bool EmitModuleHash) { - return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, - EmitSummaryIndex, EmitModuleHash); + bool EmitSummaryIndex, + bool EmitModuleHash, + CreateModuleWriterFn CreateWriter) { + return new WriteBitcodePass(Str, ShouldPreserveUseListOrder, EmitSummaryIndex, + EmitModuleHash, CreateWriter); } bool llvm::isBitcodeWriterPass(Pass *P) { diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -9,6 +9,7 @@ add_llvm_target(DirectXCodeGen DirectXSubtarget.cpp DirectXTargetMachine.cpp + DXILBitcodeWriter.cpp DXILPrepare.cpp LINK_COMPONENTS diff --git a/llvm/include/llvm/Bitcode/BitcodeWriterBase.h b/llvm/lib/Target/DirectX/DXILBitcodeWriter.h copy from llvm/include/llvm/Bitcode/BitcodeWriterBase.h copy to llvm/lib/Target/DirectX/DXILBitcodeWriter.h --- a/llvm/include/llvm/Bitcode/BitcodeWriterBase.h +++ b/llvm/lib/Target/DirectX/DXILBitcodeWriter.h @@ -1,4 +1,4 @@ -//===- llvm/Bitcode/BitcodeWriterBase.h - Bitcode writer --------*- C++ -*-===// +//===- Bitcode/Writer/DXILBitcodeWriter.cpp - DXIL Bitcode Writer ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,63 +6,20 @@ // //===----------------------------------------------------------------------===// // -// Base classes for writing LLVM objects to bitcode +// Bitcode writer implementation. // //===----------------------------------------------------------------------===// -#ifndef LLVM_BITCODE_BITCODEWRITERBASE_H -#define LLVM_BITCODE_BITCODEWRITERBASE_H - -#include "llvm/Bitcode/ValueEnumerator.h" -#include "llvm/Bitstream/BitstreamWriter.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/ModuleSummaryIndex.h" -#include "llvm/Support/SHA1.h" +#include "llvm/Bitcode/BitcodeCommon.h" +#include "llvm/Bitcode/BitcodeWriterBase.h" namespace llvm { -class GlobalValueSummary; -class Module; -class ModuleSummaryIndex; -class StringTableBuilder; - -// Generates an enum to use as an index in the Abbrev array of Metadata record. -enum MetadataAbbrev : unsigned { -#define HANDLE_MDNODE_LEAF(CLASS) CLASS##AbbrevID, -#include "llvm/IR/Metadata.def" - LastPlusOne -}; - -/// Abstract class to manage the bitcode writing, subclassed for each bitcode -/// file type. -class BitcodeWriterBase { -protected: - /// The stream created and owned by the client. - BitstreamWriter &Stream; - - StringTableBuilder &StrtabBuilder; - - /// These are manifest constants used by the bitcode writer. They do not need - /// to be kept in sync with the reader, but need to be consistent within this - /// file. - enum { - // VALUE_SYMTAB_BLOCK abbrev id's. - VST_ENTRY_8_ABBREV = bitc::FIRST_APPLICATION_ABBREV, - VST_ENTRY_7_ABBREV, - VST_ENTRY_6_ABBREV, - VST_BBENTRY_6_ABBREV, - - // CONSTANTS_BLOCK abbrev id's. - CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV, - CONSTANTS_INTEGER_ABBREV, - CONSTANTS_CE_CAST_Abbrev, - CONSTANTS_NULL_Abbrev, +class DXILBitcodeWriter : public ModuleBitcodeWriterBase { + enum class dxilc { // FUNCTION_BLOCK abbrev id's. FUNCTION_INST_LOAD_ABBREV = bitc::FIRST_APPLICATION_ABBREV, - FUNCTION_INST_UNOP_ABBREV, - FUNCTION_INST_UNOP_FLAGS_ABBREV, FUNCTION_INST_BINOP_ABBREV, FUNCTION_INST_BINOP_FLAGS_ABBREV, FUNCTION_INST_CAST_ABBREV, @@ -72,131 +29,6 @@ FUNCTION_INST_GEP_ABBREV, }; -public: - /// Constructs a BitcodeWriterBase object that writes to the provided - /// \p Stream. - BitcodeWriterBase(BitstreamWriter &Stream, StringTableBuilder &StrtabBuilder) - : Stream(Stream), StrtabBuilder(StrtabBuilder) {} - - static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind); - static void writeStringRecord(BitstreamWriter &Stream, unsigned Code, - StringRef Str, unsigned AbbrevToUse); - static void writeIdentificationBlock(BitstreamWriter &Stream); - static void emitSignedInt64(SmallVectorImpl &Vals, uint64_t V); - static void emitWideAPInt(SmallVectorImpl &Vals, const APInt &A); - - static unsigned getEncodedComdatSelectionKind(const Comdat &C); - static unsigned getEncodedLinkage(const GlobalValue::LinkageTypes Linkage); - static unsigned getEncodedLinkage(const GlobalValue &GV); - static unsigned getEncodedVisibility(const GlobalValue &GV); - static unsigned getEncodedThreadLocalMode(const GlobalValue &GV); - static unsigned getEncodedDLLStorageClass(const GlobalValue &GV); - static unsigned getEncodedCastOpcode(unsigned Opcode); - static unsigned getEncodedUnaryOpcode(unsigned Opcode); - static unsigned getEncodedBinaryOpcode(unsigned Opcode); - static unsigned getEncodedRMWOperation(AtomicRMWInst::BinOp Op); - static unsigned getEncodedOrdering(AtomicOrdering Ordering); - static uint64_t getOptimizationFlags(const Value *V); - -protected: - void writeModuleVersion(); -}; - -/// Base class to manage the module bitcode writing, currently subclassed for -/// ModuleBitcodeWriter and ThinLinkBitcodeWriter. -class ModuleBitcodeWriterBase : public BitcodeWriterBase { -protected: - /// The Module to write to bitcode. - const Module &M; - - /// Enumerates ids for all values in the module. - ValueEnumerator VE; - - /// Optional per-module index to write for ThinLTO. - const ModuleSummaryIndex *Index; - - /// Map that holds the correspondence between GUIDs in the summary index, - /// that came from indirect call profiles, and a value id generated by this - /// class to use in the VST and summary block records. - std::map GUIDToValueIdMap; - - /// Tracks the last value id recorded in the GUIDToValueMap. - unsigned GlobalValueId; - - /// Saves the offset of the VSTOffset record that must eventually be - /// backpatched with the offset of the actual VST. - uint64_t VSTOffsetPlaceholder = 0; - -public: - /// Constructs a ModuleBitcodeWriterBase object for the given Module, - /// writing to the provided \p Buffer. - ModuleBitcodeWriterBase(const Module &M, StringTableBuilder &StrtabBuilder, - BitstreamWriter &Stream, - bool ShouldPreserveUseListOrder, - const ModuleSummaryIndex *Index) - : BitcodeWriterBase(Stream, StrtabBuilder), M(M), - VE(M, ShouldPreserveUseListOrder), Index(Index) { - // Assign ValueIds to any callee values in the index that came from - // indirect call profiles and were recorded as a GUID not a Value* - // (which would have been assigned an ID by the ValueEnumerator). - // The starting ValueId is just after the number of values in the - // ValueEnumerator, so that they can be emitted in the VST. - GlobalValueId = VE.getValues().size(); - if (!Index) - return; - for (const auto &GUIDSummaryLists : *Index) - // Examine all summaries for this GUID. - for (auto &Summary : GUIDSummaryLists.second.SummaryList) - if (auto FS = dyn_cast(Summary.get())) - // For each call in the function summary, see if the call - // is to a GUID (which means it is for an indirect call, - // otherwise we would have a Value for it). If so, synthesize - // a value id. - for (auto &CallEdge : FS->calls()) - if (!CallEdge.first.haveGVs() || !CallEdge.first.getValue()) - assignValueId(CallEdge.first.getGUID()); - } - -protected: - void writePerModuleGlobalValueSummary(); - -private: - void writePerModuleFunctionSummaryRecord(SmallVector &NameVals, - GlobalValueSummary *Summary, - unsigned ValueID, - unsigned FSCallsAbbrev, - unsigned FSCallsProfileAbbrev, - const Function &F); - void writeModuleLevelReferences(const GlobalVariable &V, - SmallVector &NameVals, - unsigned FSModRefsAbbrev, - unsigned FSModVTableRefsAbbrev); - - void assignValueId(GlobalValue::GUID ValGUID) { - GUIDToValueIdMap[ValGUID] = ++GlobalValueId; - } - - unsigned getValueId(GlobalValue::GUID ValGUID) { - const auto &VMI = GUIDToValueIdMap.find(ValGUID); - // Expect that any GUID value had a value Id assigned by an - // earlier call to assignValueId. - assert(VMI != GUIDToValueIdMap.end() && - "GUID does not have assigned value Id"); - return VMI->second; - } - - // Helper to get the valueId for the type of value recorded in VI. - unsigned getValueId(ValueInfo VI) { - if (!VI.haveGVs() || !VI.getValue()) - return getValueId(VI.getGUID()); - return VE.getValueID(VI.getValue()); - } - - std::map &valueIds() { return GUIDToValueIdMap; } -}; - -/// Class to manage the bitcode writing for a module. -class ModuleBitcodeWriter : public ModuleBitcodeWriterBase { /// Pointer to the buffer allocated by caller for bitcode writing. const SmallVectorImpl &Buffer; @@ -215,24 +47,35 @@ public: /// Constructs a ModuleBitcodeWriter object for the given Module, /// writing to the provided \p Buffer. - ModuleBitcodeWriter(const Module &M, SmallVectorImpl &Buffer, - StringTableBuilder &StrtabBuilder, - BitstreamWriter &Stream, bool ShouldPreserveUseListOrder, - const ModuleSummaryIndex *Index, bool GenerateHash, - ModuleHash *ModHash = nullptr) + DXILBitcodeWriter(const Module &M, SmallVectorImpl &Buffer, + StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream, + bool ShouldPreserveUseListOrder, + const ModuleSummaryIndex *Index, bool GenerateHash, + ModuleHash *ModHash = nullptr) : ModuleBitcodeWriterBase(M, StrtabBuilder, Stream, ShouldPreserveUseListOrder, Index), Buffer(Buffer), GenerateHash(GenerateHash), ModHash(ModHash), BitcodeStartBit(Stream.GetCurrentBitNo()) {} /// Emit the current module to the bitstream. - void write(); + void write() override; + + static std::unique_ptr + Create(const Module &M, SmallVectorImpl &Buffer, + StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream, + bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, + bool GenerateHash, ModuleHash *ModHash); private: + void writeModuleVersion(); + uint64_t bitcodeStartBit() { return BitcodeStartBit; } size_t addToStrtab(StringRef Str); + unsigned createDILocationAbbrev(); + unsigned createGenericDINodeAbbrev(); + void writeAttributeGroupTable(); void writeAttributeTable(); void writeTypeTable(); @@ -243,23 +86,27 @@ SmallVectorImpl &Record); void writeMDTuple(const MDTuple *N, SmallVectorImpl &Record, unsigned Abbrev); - unsigned createDILocationAbbrev(); void writeDILocation(const DILocation *N, SmallVectorImpl &Record, unsigned &Abbrev); - unsigned createGenericDINodeAbbrev(); void writeGenericDINode(const GenericDINode *N, - SmallVectorImpl &Record, unsigned &Abbrev); + SmallVectorImpl &Record, unsigned &Abbrev) { + llvm_unreachable("DXIL cannot contain GenericDI Nodes"); + } void writeDISubrange(const DISubrange *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIGenericSubrange(const DIGenericSubrange *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIGenericSubrange Nodes"); + } void writeDIEnumerator(const DIEnumerator *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIBasicType(const DIBasicType *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIStringType(const DIStringType *N, - SmallVectorImpl &Record, unsigned Abbrev); + SmallVectorImpl &Record, unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIStringType Nodes"); + } void writeDIDerivedType(const DIDerivedType *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDICompositeType(const DICompositeType *N, @@ -279,15 +126,23 @@ SmallVectorImpl &Record, unsigned Abbrev); void writeDICommonBlock(const DICommonBlock *N, - SmallVectorImpl &Record, unsigned Abbrev); + SmallVectorImpl &Record, unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DICommonBlock Nodes"); + } void writeDINamespace(const DINamespace *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIMacro(const DIMacro *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIMacro Nodes"); + } void writeDIMacroFile(const DIMacroFile *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIMacroFile Nodes"); + } void writeDIArgList(const DIArgList *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DIArgList Nodes"); + } void writeDIModule(const DIModule *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDITemplateTypeParameter(const DITemplateTypeParameter *N, @@ -302,12 +157,16 @@ void writeDILocalVariable(const DILocalVariable *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDILabel(const DILabel *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain DILabel Nodes"); + } void writeDIExpression(const DIExpression *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIGlobalVariableExpression(const DIGlobalVariableExpression *N, SmallVectorImpl &Record, - unsigned Abbrev); + unsigned Abbrev) { + llvm_unreachable("DXIL cannot contain GlobalVariableExpression Nodes"); + } void writeDIObjCProperty(const DIObjCProperty *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIImportedEntity(const DIImportedEntity *N, @@ -346,9 +205,7 @@ DenseMap &FunctionToBitcodeIndex); void writeUseList(UseListOrder &&Order); void writeUseListBlock(const Function *F); - void - writeFunction(const Function &F, - DenseMap &FunctionToBitcodeIndex); + void writeFunction(const Function &F); void writeBlockInfo(); void writeModuleHash(size_t BlockStartPos); @@ -356,6 +213,4 @@ unsigned getEncodedAlign(MaybeAlign Alignment) { return encode(Alignment); } }; - } // namespace llvm -#endif // LLVM_BITCODE_BITCODEWRITERBASE_H diff --git a/llvm/lib/Target/DirectX/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILBitcodeWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILBitcodeWriter.cpp @@ -0,0 +1,2097 @@ +//===- Bitcode/Writer/DXILBitcodeWriter.cpp - DXIL Bitcode Writer ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Bitcode writer implementation. +// +//===----------------------------------------------------------------------===// + +#include "DXILBitcodeWriter.h" +#include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +std::unique_ptr DXILBitcodeWriter::Create( + const Module &M, SmallVectorImpl &Buffer, + StringTableBuilder &StrtabBuilder, BitstreamWriter &Stream, + bool ShouldPreserveUseListOrder, const ModuleSummaryIndex *Index, + bool GenerateHash, ModuleHash *ModHash) { + return std::make_unique( + M, Buffer, StrtabBuilder, Stream, ShouldPreserveUseListOrder, Index, + GenerateHash, ModHash); +} + +void DXILBitcodeWriter::writeAttributeGroupTable() { + const std::vector &AttrGrps = + VE.getAttributeGroups(); + if (AttrGrps.empty()) + return; + + Stream.EnterSubblock(bitc::PARAMATTR_GROUP_BLOCK_ID, 3); + + SmallVector Record; + for (ValueEnumerator::IndexAndAttrSet Pair : AttrGrps) { + unsigned AttrListIndex = Pair.first; + AttributeSet AS = Pair.second; + Record.push_back(VE.getAttributeGroupID(Pair)); + Record.push_back(AttrListIndex); + + for (Attribute Attr : AS) { + if (Attr.isEnumAttribute()) { + uint64_t Val = getAttrKindEncoding(Attr.getKindAsEnum()); + assert(Val <= bitc::ATTR_KIND_ARGMEMONLY && + "DXIL does not support attributes above ATTR_KIND_ARGMEMONLY"); + Record.push_back(0); + Record.push_back(Val); + } else if (Attr.isIntAttribute()) { + uint64_t Val = getAttrKindEncoding(Attr.getKindAsEnum()); + assert(Val <= bitc::ATTR_KIND_ARGMEMONLY && + "DXIL does not support attributes above ATTR_KIND_ARGMEMONLY"); + Record.push_back(1); + Record.push_back(Val); + Record.push_back(Attr.getValueAsInt()); + } else { + StringRef Kind = Attr.getKindAsString(); + StringRef Val = Attr.getValueAsString(); + + Record.push_back(Val.empty() ? 3 : 4); + Record.append(Kind.begin(), Kind.end()); + Record.push_back(0); + if (!Val.empty()) { + Record.append(Val.begin(), Val.end()); + Record.push_back(0); + } + } + } + + Stream.EmitRecord(bitc::PARAMATTR_GRP_CODE_ENTRY, Record); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeAttributeTable() { + const std::vector &Attrs = VE.getAttributeLists(); + if (Attrs.empty()) + return; + + Stream.EnterSubblock(bitc::PARAMATTR_BLOCK_ID, 3); + + SmallVector Record; + for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { + AttributeList AL = Attrs[i]; + for (unsigned i : AL.indexes()) { + AttributeSet AS = AL.getAttributes(i); + if (AS.hasAttributes()) + Record.push_back(VE.getAttributeGroupID({i, AS})); + } + + Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record); + Record.clear(); + } + + Stream.ExitBlock(); +} + +/// WriteTypeTable - Write out the type table for a module. +void DXILBitcodeWriter::writeTypeTable() { + const ValueEnumerator::TypeList &TypeList = VE.getTypes(); + + Stream.EnterSubblock(bitc::TYPE_BLOCK_ID_NEW, 4 /*count from # abbrevs */); + SmallVector TypeVals; + + uint64_t NumBits = VE.computeBitsRequiredForTypeIndicies(); + + // Abbrev for TYPE_CODE_POINTER. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_POINTER)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0 + unsigned PtrAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_FUNCTION. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isvararg + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned FunctionAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_ANON. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_ANON)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ispacked + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned StructAnonAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_NAME. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_NAME)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + unsigned StructNameAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_STRUCT_NAMED. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_STRUCT_NAMED)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ispacked + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned StructNamedAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for TYPE_CODE_ARRAY. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_ARRAY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // size + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, NumBits)); + unsigned ArrayAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Emit an entry count so the reader can reserve space. + TypeVals.push_back(TypeList.size()); + Stream.EmitRecord(bitc::TYPE_CODE_NUMENTRY, TypeVals); + TypeVals.clear(); + + // Loop over all of the types, emitting each in turn. + for (unsigned i = 0, e = TypeList.size(); i != e; ++i) { + Type *T = TypeList[i]; + int AbbrevToUse = 0; + unsigned Code = 0; + + switch (T->getTypeID()) { + case Type::BFloatTyID: + case Type::X86_AMXTyID: + case Type::TokenTyID: + llvm_unreachable("These should never be used!!!"); + break; + case Type::VoidTyID: + Code = bitc::TYPE_CODE_VOID; + break; + case Type::HalfTyID: + Code = bitc::TYPE_CODE_HALF; + break; + case Type::FloatTyID: + Code = bitc::TYPE_CODE_FLOAT; + break; + case Type::DoubleTyID: + Code = bitc::TYPE_CODE_DOUBLE; + break; + case Type::X86_FP80TyID: + Code = bitc::TYPE_CODE_X86_FP80; + break; + case Type::FP128TyID: + Code = bitc::TYPE_CODE_FP128; + break; + case Type::PPC_FP128TyID: + Code = bitc::TYPE_CODE_PPC_FP128; + break; + case Type::LabelTyID: + Code = bitc::TYPE_CODE_LABEL; + break; + case Type::MetadataTyID: + Code = bitc::TYPE_CODE_METADATA; + break; + case Type::X86_MMXTyID: + Code = bitc::TYPE_CODE_X86_MMX; + break; + case Type::IntegerTyID: + // INTEGER: [width] + Code = bitc::TYPE_CODE_INTEGER; + TypeVals.push_back(cast(T)->getBitWidth()); + break; + case Type::PointerTyID: { + PointerType *PTy = cast(T); + // POINTER: [pointee type, address space] + Code = bitc::TYPE_CODE_POINTER; + TypeVals.push_back(VE.getTypeID(PTy->getNonOpaquePointerElementType())); + unsigned AddressSpace = PTy->getAddressSpace(); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; + break; + } + case Type::FunctionTyID: { + FunctionType *FT = cast(T); + // FUNCTION: [isvararg, retty, paramty x N] + Code = bitc::TYPE_CODE_FUNCTION; + TypeVals.push_back(FT->isVarArg()); + TypeVals.push_back(VE.getTypeID(FT->getReturnType())); + for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) + TypeVals.push_back(VE.getTypeID(FT->getParamType(i))); + AbbrevToUse = FunctionAbbrev; + break; + } + case Type::StructTyID: { + StructType *ST = cast(T); + // STRUCT: [ispacked, eltty x N] + TypeVals.push_back(ST->isPacked()); + // Output all of the element types. + for (StructType::element_iterator I = ST->element_begin(), + E = ST->element_end(); + I != E; ++I) + TypeVals.push_back(VE.getTypeID(*I)); + + if (ST->isLiteral()) { + Code = bitc::TYPE_CODE_STRUCT_ANON; + AbbrevToUse = StructAnonAbbrev; + } else { + if (ST->isOpaque()) { + Code = bitc::TYPE_CODE_OPAQUE; + } else { + Code = bitc::TYPE_CODE_STRUCT_NAMED; + AbbrevToUse = StructNamedAbbrev; + } + + // Emit the name if it is present. + if (!ST->getName().empty()) + writeStringRecord(Stream, bitc::TYPE_CODE_STRUCT_NAME, ST->getName(), + StructNameAbbrev); + } + break; + } + case Type::ArrayTyID: { + ArrayType *AT = cast(T); + // ARRAY: [numelts, eltty] + Code = bitc::TYPE_CODE_ARRAY; + TypeVals.push_back(AT->getNumElements()); + TypeVals.push_back(VE.getTypeID(AT->getElementType())); + AbbrevToUse = ArrayAbbrev; + break; + } + case Type::FixedVectorTyID: + case Type::ScalableVectorTyID: { + VectorType *VT = cast(T); + // VECTOR [numelts, eltty] + Code = bitc::TYPE_CODE_VECTOR; + TypeVals.push_back(VT->getElementCount().getKnownMinValue()); + TypeVals.push_back(VE.getTypeID(VT->getElementType())); + break; + } + } + + // Emit the finished record. + Stream.EmitRecord(Code, TypeVals, AbbrevToUse); + TypeVals.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeComdats() { + SmallVector Vals; + for (const Comdat *C : VE.getComdats()) { + // COMDAT: [selection_kind, name] + Vals.push_back(getEncodedComdatSelectionKind(*C)); + size_t Size = C->getName().size(); + assert(isUInt<16>(Size)); + Vals.push_back(Size); + for (char Chr : C->getName()) + Vals.push_back((unsigned char)Chr); + Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0); + Vals.clear(); + } +} + +void DXILBitcodeWriter::writeValueSymbolTableForwardDecl() {} + +/// Emit top-level description of module, including target triple, inline asm, +/// descriptors for global variables, and function prototype info. +/// Returns the bit offset to backpatch with the location of the real VST. +void DXILBitcodeWriter::writeModuleInfo() { + // Emit various pieces of data attached to a module. + if (!M.getTargetTriple().empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_TRIPLE, M.getTargetTriple(), + 0 /*TODO*/); + const std::string &DL = M.getDataLayoutStr(); + if (!DL.empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/); + if (!M.getModuleInlineAsm().empty()) + writeStringRecord(Stream, bitc::MODULE_CODE_ASM, M.getModuleInlineAsm(), + 0 /*TODO*/); + + // Emit information about sections and GC, computing how many there are. Also + // compute the maximum alignment value. + std::map SectionMap; + std::map GCMap; + MaybeAlign MaxAlignment; + unsigned MaxGlobalType = 0; + const auto UpdateMaxAlignment = [&MaxAlignment](const MaybeAlign A) { + if (A) + MaxAlignment = !MaxAlignment ? *A : std::max(*MaxAlignment, *A); + }; + for (const GlobalVariable &GV : M.globals()) { + UpdateMaxAlignment(GV.getAlign()); + MaxGlobalType = std::max(MaxGlobalType, VE.getTypeID(GV.getValueType())); + if (GV.hasSection()) { + // Give section names unique ID's. + unsigned &Entry = SectionMap[std::string(GV.getSection())]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, + GV.getSection(), 0 /*TODO*/); + Entry = SectionMap.size(); + } + } + } + for (const Function &F : M) { + UpdateMaxAlignment(F.getAlign()); + if (F.hasSection()) { + // Give section names unique ID's. + unsigned &Entry = SectionMap[std::string(F.getSection())]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_SECTIONNAME, F.getSection(), + 0 /*TODO*/); + Entry = SectionMap.size(); + } + } + if (F.hasGC()) { + // Same for GC names. + unsigned &Entry = GCMap[F.getGC()]; + if (!Entry) { + writeStringRecord(Stream, bitc::MODULE_CODE_GCNAME, F.getGC(), + 0 /*TODO*/); + Entry = GCMap.size(); + } + } + } + + // Emit abbrev for globals, now that we know # sections and max alignment. + unsigned SimpleGVarAbbrev = 0; + if (!M.global_empty()) { + // Add an abbrev for common globals with no visibility or thread localness. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(MaxGlobalType + 1))); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2 + //| explicitType << 1 + //| constant + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Initializer. + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5)); // Linkage. + if (MaxAlignment == 0) // Alignment. + Abbv->Add(BitCodeAbbrevOp(0)); + else { + unsigned MaxEncAlignment = getEncodedAlign(MaxAlignment); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(MaxEncAlignment + 1))); + } + if (SectionMap.empty()) // Section. + Abbv->Add(BitCodeAbbrevOp(0)); + else + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(SectionMap.size() + 1))); + // Don't bother emitting vis + thread local. + SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + // Emit the global variable information. + SmallVector Vals; + for (const GlobalVariable &GV : M.globals()) { + unsigned AbbrevToUse = 0; + + // GLOBALVAR: [type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr, externally_initialized, dllstorageclass, + // comdat] + Vals.push_back(VE.getTypeID(GV.getValueType())); + Vals.push_back( + GV.getType()->getAddressSpace() << 2 | 2 | + (GV.isConstant() ? 1 : 0)); // HLSL Change - bitwise | was used with + // unsigned int and bool + Vals.push_back( + GV.isDeclaration() ? 0 : (VE.getValueID(GV.getInitializer()) + 1)); + Vals.push_back(getEncodedLinkage(GV)); + Vals.push_back(getEncodedAlign(GV.getAlign())); + Vals.push_back(GV.hasSection() ? SectionMap[std::string(GV.getSection())] + : 0); + if (GV.isThreadLocal() || + GV.getVisibility() != GlobalValue::DefaultVisibility || + GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None || + GV.isExternallyInitialized() || + GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass || + GV.hasComdat()) { + Vals.push_back(getEncodedVisibility(GV)); + Vals.push_back(getEncodedThreadLocalMode(GV)); + Vals.push_back(GV.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + Vals.push_back(GV.isExternallyInitialized()); + Vals.push_back(getEncodedDLLStorageClass(GV)); + Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0); + } else { + AbbrevToUse = SimpleGVarAbbrev; + } + + Stream.EmitRecord(bitc::MODULE_CODE_GLOBALVAR, Vals, AbbrevToUse); + Vals.clear(); + } + + // Emit the function proto information. + for (const Function &F : M) { + // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, + // section, visibility, gc, unnamed_addr, prologuedata, + // dllstorageclass, comdat, prefixdata, personalityfn] + Vals.push_back(VE.getTypeID(F.getFunctionType())); + Vals.push_back(F.getCallingConv()); + Vals.push_back(F.isDeclaration()); + Vals.push_back(getEncodedLinkage(F)); + Vals.push_back(VE.getAttributeListID(F.getAttributes())); + Vals.push_back(getEncodedAlign(F.getAlign())); + Vals.push_back(F.hasSection() ? SectionMap[std::string(F.getSection())] + : 0); + Vals.push_back(getEncodedVisibility(F)); + Vals.push_back(F.hasGC() ? GCMap[F.getGC()] : 0); + Vals.push_back(F.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + Vals.push_back( + F.hasPrologueData() ? (VE.getValueID(F.getPrologueData()) + 1) : 0); + Vals.push_back(getEncodedDLLStorageClass(F)); + Vals.push_back(F.hasComdat() ? VE.getComdatID(F.getComdat()) : 0); + Vals.push_back(F.hasPrefixData() ? (VE.getValueID(F.getPrefixData()) + 1) + : 0); + Vals.push_back( + F.hasPersonalityFn() ? (VE.getValueID(F.getPersonalityFn()) + 1) : 0); + + unsigned AbbrevToUse = 0; + Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); + Vals.clear(); + } + + // Emit the alias information. + for (const GlobalAlias &A : M.aliases()) { + // ALIAS: [alias type, aliasee val#, linkage, visibility] + Vals.push_back(VE.getTypeID(A.getValueType())); + Vals.push_back(VE.getValueID(A.getAliasee())); + Vals.push_back(getEncodedLinkage(A)); + Vals.push_back(getEncodedVisibility(A)); + Vals.push_back(getEncodedDLLStorageClass(A)); + Vals.push_back(getEncodedThreadLocalMode(A)); + Vals.push_back(A.getUnnamedAddr() != GlobalValue::UnnamedAddr::None); + unsigned AbbrevToUse = 0; + Stream.EmitRecord(bitc::MODULE_CODE_ALIAS_OLD, Vals, AbbrevToUse); + Vals.clear(); + } +} + +void DXILBitcodeWriter::writeValueAsMetadata( + const ValueAsMetadata *MD, SmallVectorImpl &Record) { + // Mimic an MDNode with a value as one operand. + Value *V = MD->getValue(); + Record.push_back(VE.getTypeID(V->getType())); + Record.push_back(VE.getValueID(V)); + Stream.EmitRecord(bitc::METADATA_VALUE, Record, 0); + Record.clear(); +} + +void DXILBitcodeWriter::writeMDTuple(const MDTuple *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + Metadata *MD = N->getOperand(i); + assert(!(MD && isa(MD)) && + "Unexpected function-local metadata"); + Record.push_back(VE.getMetadataOrNullID(MD)); + } + Stream.EmitRecord(N->isDistinct() ? bitc::METADATA_DISTINCT_NODE + : bitc::METADATA_NODE, + Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILocation(const DILocation *N, + SmallVectorImpl &Record, + unsigned &Abbrev) { + if (!Abbrev) + Abbrev = createDILocationAbbrev(); + Record.push_back(N->isDistinct()); + Record.push_back(N->getLine()); + Record.push_back(N->getColumn()); + Record.push_back(VE.getMetadataID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getInlinedAt())); + + Stream.EmitRecord(bitc::METADATA_LOCATION, Record, Abbrev); + Record.clear(); +} + +static uint64_t rotateSign(APInt Val) { + int64_t I = Val.getSExtValue(); + uint64_t U = I; + return I < 0 ? ~(U << 1) : U << 1; +} + +static uint64_t rotateSign(DISubrange::BoundType Val) { + return rotateSign(Val.get()->getValue()); +} + +void DXILBitcodeWriter::writeDISubrange(const DISubrange *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back( + N->getCount().get()->getValue().getSExtValue()); + Record.push_back(rotateSign(N->getLowerBound())); + + Stream.EmitRecord(bitc::METADATA_SUBRANGE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIEnumerator(const DIEnumerator *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(rotateSign(N->getValue())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + + Stream.EmitRecord(bitc::METADATA_ENUMERATOR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIBasicType(const DIBasicType *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getEncoding()); + + Stream.EmitRecord(bitc::METADATA_BASIC_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIDerivedType(const DIDerivedType *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getBaseType())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getOffsetInBits()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getExtraData())); + + Stream.EmitRecord(bitc::METADATA_DERIVED_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDICompositeType(const DICompositeType *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getBaseType())); + Record.push_back(N->getSizeInBits()); + Record.push_back(N->getAlignInBits()); + Record.push_back(N->getOffsetInBits()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getElements().get())); + Record.push_back(N->getRuntimeLang()); + Record.push_back(VE.getMetadataOrNullID(N->getVTableHolder())); + Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get())); + Record.push_back(VE.getMetadataOrNullID(N->getRawIdentifier())); + + Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDISubroutineType(const DISubroutineType *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getFlags()); + Record.push_back(VE.getMetadataOrNullID(N->getTypeArray().get())); + + Stream.EmitRecord(bitc::METADATA_SUBROUTINE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIFile(const DIFile *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawFilename())); + Record.push_back(VE.getMetadataOrNullID(N->getRawDirectory())); + + Stream.EmitRecord(bitc::METADATA_FILE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDICompileUnit(const DICompileUnit *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getSourceLanguage()); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getRawProducer())); + Record.push_back(N->isOptimized()); + Record.push_back(VE.getMetadataOrNullID(N->getRawFlags())); + Record.push_back(N->getRuntimeVersion()); + Record.push_back(VE.getMetadataOrNullID(N->getRawSplitDebugFilename())); + Record.push_back(N->getEmissionKind()); + Record.push_back(VE.getMetadataOrNullID(N->getEnumTypes().get())); + Record.push_back(VE.getMetadataOrNullID(N->getRetainedTypes().get())); + Record.push_back(/* subprograms */ 0); + Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables().get())); + Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities().get())); + Record.push_back(N->getDWOId()); + + Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDISubprogram(const DISubprogram *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isLocalToUnit()); + Record.push_back(N->isDefinition()); + Record.push_back(N->getScopeLine()); + Record.push_back(VE.getMetadataOrNullID(N->getContainingType())); + Record.push_back(N->getVirtuality()); + Record.push_back(N->getVirtualIndex()); + Record.push_back(N->getFlags()); + Record.push_back(N->isOptimized()); + Record.push_back(VE.getMetadataOrNullID(N->getRawUnit())); + Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get())); + Record.push_back(VE.getMetadataOrNullID(N->getDeclaration())); + Record.push_back(VE.getMetadataOrNullID(N->getRetainedNodes().get())); + + Stream.EmitRecord(bitc::METADATA_SUBPROGRAM, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILexicalBlock(const DILexicalBlock *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(N->getColumn()); + + Stream.EmitRecord(bitc::METADATA_LEXICAL_BLOCK, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILexicalBlockFile( + const DILexicalBlockFile *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getDiscriminator()); + + Stream.EmitRecord(bitc::METADATA_LEXICAL_BLOCK_FILE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDINamespace(const DINamespace *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(/* line number */ 0); + + Stream.EmitRecord(bitc::METADATA_NAMESPACE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIModule(const DIModule *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + for (auto &I : N->operands()) + Record.push_back(VE.getMetadataOrNullID(I)); + + Stream.EmitRecord(bitc::METADATA_MODULE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDITemplateTypeParameter( + const DITemplateTypeParameter *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + + Stream.EmitRecord(bitc::METADATA_TEMPLATE_TYPE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDITemplateValueParameter( + const DITemplateValueParameter *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(VE.getMetadataOrNullID(N->getValue())); + + Stream.EmitRecord(bitc::METADATA_TEMPLATE_VALUE, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIGlobalVariable(const DIGlobalVariable *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getRawLinkageName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isLocalToUnit()); + Record.push_back(N->isDefinition()); + Record.push_back(/* N->getRawVariable() */ 0); + Record.push_back(VE.getMetadataOrNullID(N->getStaticDataMemberDeclaration())); + + Stream.EmitRecord(bitc::METADATA_GLOBAL_VAR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDILocalVariable(const DILocalVariable *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->getArg()); + Record.push_back(N->getFlags()); + + Stream.EmitRecord(bitc::METADATA_LOCAL_VAR, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIExpression(const DIExpression *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.reserve(N->getElements().size() + 1); + + Record.push_back(N->isDistinct()); + Record.append(N->elements_begin(), N->elements_end()); + + Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev); + Record.clear(); +} + +void DXILBitcodeWriter::writeDIObjCProperty(const DIObjCProperty *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + llvm_unreachable("DXIL does not support objc!!!"); +} + +void DXILBitcodeWriter::writeDIImportedEntity(const DIImportedEntity *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getTag()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getEntity())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + + Stream.EmitRecord(bitc::METADATA_IMPORTED_ENTITY, Record, Abbrev); + Record.clear(); +} + +unsigned DXILBitcodeWriter::createDILocationAbbrev() { + // Abbrev for METADATA_LOCATION. + // + // Assume the column is usually under 128, and always output the inlined-at + // location (it's never more expensive than building an array size 1). + std::shared_ptr Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_LOCATION)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +unsigned DXILBitcodeWriter::createGenericDINodeAbbrev() { + // Abbrev for METADATA_GENERIC_DEBUG. + // + // Assume the column is usually under 128, and always output the inlined-at + // location (it's never more expensive than building an array size 1). + std::shared_ptr Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_GENERIC_DEBUG)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +void DXILBitcodeWriter::writeMetadataRecords(ArrayRef MDs, + SmallVectorImpl &Record, + std::vector *MDAbbrevs, + std::vector *IndexPos) { + if (MDs.empty()) + return; + + // Initialize MDNode abbreviations. +#define HANDLE_MDNODE_LEAF(CLASS) unsigned CLASS##Abbrev = 0; +#include "llvm/IR/Metadata.def" + + for (const Metadata *MD : MDs) { + if (IndexPos) + IndexPos->push_back(Stream.GetCurrentBitNo()); + if (const MDNode *N = dyn_cast(MD)) { + assert(N->isResolved() && "Expected forward references to be resolved"); + + switch (N->getMetadataID()) { + default: + llvm_unreachable("Invalid MDNode subclass"); +#define HANDLE_MDNODE_LEAF(CLASS) \ + case Metadata::CLASS##Kind: \ + if (MDAbbrevs) \ + write##CLASS(cast(N), Record, \ + (*MDAbbrevs)[MetadataAbbrev::CLASS##AbbrevID]); \ + else \ + write##CLASS(cast(N), Record, CLASS##Abbrev); \ + continue; +#include "llvm/IR/Metadata.def" + } + } + writeValueAsMetadata(cast(MD), Record); + } +} + +unsigned DXILBitcodeWriter::createMetadataStringsAbbrev() { + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_STRING_OLD)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + return Stream.EmitAbbrev(std::move(Abbv)); +} + +void DXILBitcodeWriter::writeMetadataStrings( + ArrayRef Strings, SmallVectorImpl &Record) { + for (const Metadata *MD : Strings) { + const MDString *MDS = cast(MD); + // Code: [strchar x N] + Record.append(MDS->bytes_begin(), MDS->bytes_end()); + + // Emit the finished record. + Stream.EmitRecord(bitc::METADATA_STRING_OLD, Record, + createMetadataStringsAbbrev()); + Record.clear(); + } +} + +void DXILBitcodeWriter::writeModuleMetadata() { + if (!VE.hasMDs() && M.named_metadata_empty()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 5); + + // Emit all abbrevs upfront, so that the reader can jump in the middle of the + // block and load any metadata. + std::vector MDAbbrevs; + + MDAbbrevs.resize(MetadataAbbrev::LastPlusOne); + MDAbbrevs[MetadataAbbrev::DILocationAbbrevID] = createDILocationAbbrev(); + MDAbbrevs[MetadataAbbrev::GenericDINodeAbbrevID] = + createGenericDINodeAbbrev(); + + unsigned NameAbbrev = 0; + if (!M.named_metadata_empty()) { + // Abbrev for METADATA_NAME. + std::shared_ptr Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_NAME)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + NameAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + SmallVector Record; + writeMetadataStrings(VE.getMDStrings(), Record); + + std::vector IndexPos; + IndexPos.reserve(VE.getNonMDStrings().size()); + writeMetadataRecords(VE.getNonMDStrings(), Record, &MDAbbrevs, &IndexPos); + + // Write named metadata. + for (const NamedMDNode &NMD : M.named_metadata()) { + // Write name. + StringRef Str = NMD.getName(); + Record.append(Str.bytes_begin(), Str.bytes_end()); + Stream.EmitRecord(bitc::METADATA_NAME, Record, NameAbbrev); + Record.clear(); + + // Write named metadata operands. + for (const MDNode *N : NMD.operands()) + Record.push_back(VE.getMetadataID(N)); + Stream.EmitRecord(bitc::METADATA_NAMED_NODE, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeFunctionMetadata(const Function &F) { + if (!VE.hasMDs()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 4); + SmallVector Record; + writeMetadataStrings(VE.getMDStrings(), Record); + writeMetadataRecords(VE.getNonMDStrings(), Record); + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeFunctionMetadataAttachment(const Function &F) { + Stream.EnterSubblock(bitc::METADATA_ATTACHMENT_ID, 3); + + SmallVector Record; + + // Write metadata attachments + // METADATA_ATTACHMENT - [m x [value, [n x [id, mdnode]]] + SmallVector, 4> MDs; + F.getAllMetadata(MDs); + if (!MDs.empty()) { + for (const auto &I : MDs) { + Record.push_back(I.first); + Record.push_back(VE.getMetadataID(I.second)); + } + Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Record.clear(); + } + + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) { + MDs.clear(); + I.getAllMetadataOtherThanDebugLoc(MDs); + + // If no metadata, ignore instruction. + if (MDs.empty()) + continue; + + Record.push_back(VE.getInstructionID(&I)); + + for (unsigned i = 0, e = MDs.size(); i != e; ++i) { + Record.push_back(MDs[i].first); + Record.push_back(VE.getMetadataID(MDs[i].second)); + } + Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleMetadataKinds() { + SmallVector Record; + + // Write metadata kinds + // METADATA_KIND - [n x [id, name]] + SmallVector Names; + M.getMDKindNames(Names); + + if (Names.empty()) + return; + + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); + + for (unsigned MDKindID = 0, e = Names.size(); MDKindID != e; ++MDKindID) { + Record.push_back(MDKindID); + StringRef KName = Names[MDKindID]; + Record.append(KName.begin(), KName.end()); + + Stream.EmitRecord(bitc::METADATA_KIND, Record, 0); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal, + bool isGlobal) { + if (FirstVal == LastVal) + return; + + Stream.EnterSubblock(bitc::CONSTANTS_BLOCK_ID, 4); + + unsigned AggregateAbbrev = 0; + unsigned String8Abbrev = 0; + unsigned CString7Abbrev = 0; + unsigned CString6Abbrev = 0; + // If this is a constant pool for the module, emit module-specific abbrevs. + if (isGlobal) { + // Abbrev for CST_CODE_AGGREGATE. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_AGGREGATE)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add( + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, Log2_32_Ceil(LastVal + 1))); + AggregateAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + + // Abbrev for CST_CODE_STRING. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_STRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + String8Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for CST_CODE_CSTRING. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CSTRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); + CString7Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for CST_CODE_CSTRING. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CSTRING)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + CString6Abbrev = Stream.EmitAbbrev(std::move(Abbv)); + } + + SmallVector Record; + + const ValueEnumerator::ValueList &Vals = VE.getValues(); + Type *LastTy = nullptr; + for (unsigned i = FirstVal; i != LastVal; ++i) { + const Value *V = Vals[i].first; + // If we need to switch types, do so now. + if (V->getType() != LastTy) { + LastTy = V->getType(); + Record.push_back(VE.getTypeID(LastTy)); + Stream.EmitRecord(bitc::CST_CODE_SETTYPE, Record, + CONSTANTS_SETTYPE_ABBREV); + Record.clear(); + } + + if (const InlineAsm *IA = dyn_cast(V)) { + Record.push_back(unsigned(IA->hasSideEffects()) | + unsigned(IA->isAlignStack()) << 1 | + unsigned(IA->getDialect() & 1) << 2); + + // Add the asm string. + const std::string &AsmStr = IA->getAsmString(); + Record.push_back(AsmStr.size()); + Record.append(AsmStr.begin(), AsmStr.end()); + + // Add the constraint string. + const std::string &ConstraintStr = IA->getConstraintString(); + Record.push_back(ConstraintStr.size()); + Record.append(ConstraintStr.begin(), ConstraintStr.end()); + Stream.EmitRecord(bitc::CST_CODE_INLINEASM, Record); + Record.clear(); + continue; + } + const Constant *C = cast(V); + unsigned Code = -1U; + unsigned AbbrevToUse = 0; + if (C->isNullValue()) { + Code = bitc::CST_CODE_NULL; + } else if (isa(C)) { + Code = bitc::CST_CODE_UNDEF; + } else if (const ConstantInt *IV = dyn_cast(C)) { + if (IV->getBitWidth() <= 64) { + uint64_t V = IV->getSExtValue(); + emitSignedInt64(Record, V); + Code = bitc::CST_CODE_INTEGER; + AbbrevToUse = CONSTANTS_INTEGER_ABBREV; + } else { // Wide integers, > 64 bits in size. + // We have an arbitrary precision integer value to write whose + // bit width is > 64. However, in canonical unsigned integer + // format it is likely that the high bits are going to be zero. + // So, we only write the number of active words. + unsigned NWords = IV->getValue().getActiveWords(); + const uint64_t *RawWords = IV->getValue().getRawData(); + for (unsigned i = 0; i != NWords; ++i) { + emitSignedInt64(Record, RawWords[i]); + } + Code = bitc::CST_CODE_WIDE_INTEGER; + } + } else if (const ConstantFP *CFP = dyn_cast(C)) { + Code = bitc::CST_CODE_FLOAT; + Type *Ty = CFP->getType(); + if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy()) { + Record.push_back(CFP->getValueAPF().bitcastToAPInt().getZExtValue()); + } else if (Ty->isX86_FP80Ty()) { + // api needed to prevent premature destruction + // bits are not in the same order as a normal i80 APInt, compensate. + APInt api = CFP->getValueAPF().bitcastToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back((p[1] << 48) | (p[0] >> 16)); + Record.push_back(p[0] & 0xffffLL); + } else if (Ty->isFP128Ty() || Ty->isPPC_FP128Ty()) { + APInt api = CFP->getValueAPF().bitcastToAPInt(); + const uint64_t *p = api.getRawData(); + Record.push_back(p[0]); + Record.push_back(p[1]); + } else { + assert(0 && "Unknown FP type!"); + } + } else if (isa(C) && + cast(C)->isString()) { + const ConstantDataSequential *Str = cast(C); + // Emit constant strings specially. + unsigned NumElts = Str->getNumElements(); + // If this is a null-terminated string, use the denser CSTRING encoding. + if (Str->isCString()) { + Code = bitc::CST_CODE_CSTRING; + --NumElts; // Don't encode the null, which isn't allowed by char6. + } else { + Code = bitc::CST_CODE_STRING; + AbbrevToUse = String8Abbrev; + } + bool isCStr7 = Code == bitc::CST_CODE_CSTRING; + bool isCStrChar6 = Code == bitc::CST_CODE_CSTRING; + for (unsigned i = 0; i != NumElts; ++i) { + unsigned char V = Str->getElementAsInteger(i); + Record.push_back(V); + isCStr7 &= (V & 128) == 0; + if (isCStrChar6) + isCStrChar6 = BitCodeAbbrevOp::isChar6(V); + } + + if (isCStrChar6) + AbbrevToUse = CString6Abbrev; + else if (isCStr7) + AbbrevToUse = CString7Abbrev; + } else if (const ConstantDataSequential *CDS = + dyn_cast(C)) { + Code = bitc::CST_CODE_DATA; + Type *EltTy = CDS->getType()->getArrayElementType(); + if (isa(EltTy)) { + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) + Record.push_back(CDS->getElementAsInteger(i)); + } else if (EltTy->isFloatTy()) { + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { + union { + float F; + uint32_t I; + }; + F = CDS->getElementAsFloat(i); + Record.push_back(I); + } + } else { + assert(EltTy->isDoubleTy() && "Unknown ConstantData element type"); + for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { + union { + double F; + uint64_t I; + }; + F = CDS->getElementAsDouble(i); + Record.push_back(I); + } + } + } else if (isa(C) || isa(C) || + isa(C)) { + Code = bitc::CST_CODE_AGGREGATE; + for (const Value *Op : C->operands()) + Record.push_back(VE.getValueID(Op)); + AbbrevToUse = AggregateAbbrev; + } else if (const ConstantExpr *CE = dyn_cast(C)) { + switch (CE->getOpcode()) { + default: + if (Instruction::isCast(CE->getOpcode())) { + Code = bitc::CST_CODE_CE_CAST; + Record.push_back(getEncodedCastOpcode(CE->getOpcode())); + Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(VE.getValueID(C->getOperand(0))); + AbbrevToUse = CONSTANTS_CE_CAST_Abbrev; + } else { + assert(CE->getNumOperands() == 2 && "Unknown constant expr!"); + Code = bitc::CST_CODE_CE_BINOP; + Record.push_back(getEncodedBinaryOpcode(CE->getOpcode())); + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + uint64_t Flags = getOptimizationFlags(CE); + if (Flags != 0) + Record.push_back(Flags); + } + break; + case Instruction::GetElementPtr: { + Code = bitc::CST_CODE_CE_GEP; + const auto *GO = cast(C); + if (GO->isInBounds()) + Code = bitc::CST_CODE_CE_INBOUNDS_GEP; + Record.push_back(VE.getTypeID(GO->getSourceElementType())); + for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) { + Record.push_back(VE.getTypeID(C->getOperand(i)->getType())); + Record.push_back(VE.getValueID(C->getOperand(i))); + } + break; + } + case Instruction::Select: + Code = bitc::CST_CODE_CE_SELECT; + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + Record.push_back(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ExtractElement: + Code = bitc::CST_CODE_CE_EXTRACTELT; + Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getTypeID(C->getOperand(1)->getType())); + Record.push_back(VE.getValueID(C->getOperand(1))); + break; + case Instruction::InsertElement: + Code = bitc::CST_CODE_CE_INSERTELT; + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + Record.push_back(VE.getTypeID(C->getOperand(2)->getType())); + Record.push_back(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ShuffleVector: + // If the return type and argument types are the same, this is a + // standard shufflevector instruction. If the types are different, + // then the shuffle is widening or truncating the input vectors, and + // the argument type must also be encoded. + if (C->getType() == C->getOperand(0)->getType()) { + Code = bitc::CST_CODE_CE_SHUFFLEVEC; + } else { + Code = bitc::CST_CODE_CE_SHUFVEC_EX; + Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + } + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + Record.push_back(VE.getValueID(C->getOperand(2))); + break; + case Instruction::ICmp: + case Instruction::FCmp: + Code = bitc::CST_CODE_CE_CMP; + Record.push_back(VE.getTypeID(C->getOperand(0)->getType())); + Record.push_back(VE.getValueID(C->getOperand(0))); + Record.push_back(VE.getValueID(C->getOperand(1))); + Record.push_back(CE->getPredicate()); + break; + } + } else if (const BlockAddress *BA = dyn_cast(C)) { + Code = bitc::CST_CODE_BLOCKADDRESS; + Record.push_back(VE.getTypeID(BA->getFunction()->getType())); + Record.push_back(VE.getValueID(BA->getFunction())); + Record.push_back(VE.getGlobalBasicBlockID(BA->getBasicBlock())); + } else { +#ifndef NDEBUG + C->dump(); +#endif + llvm_unreachable("Unknown constant!"); + } + Stream.EmitRecord(Code, Record, AbbrevToUse); + Record.clear(); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleConstants() { + const ValueEnumerator::ValueList &Vals = VE.getValues(); + + // Find the first constant to emit, which is the first non-globalvalue value. + // We know globalvalues have been emitted by WriteModuleInfo. + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + if (!isa(Vals[i].first)) { + writeConstants(i, Vals.size(), true); + return; + } + } +} + +/// pushValueAndType - The file has to encode both the value and type id for +/// many values, because we need to know what type to create for forward +/// references. However, most operands are not forward references, so this type +/// field is not needed. +/// +/// This function adds V's value ID to Vals. If the value ID is higher than the +/// instruction ID, then it is a forward reference, and it also includes the +/// type ID. The value ID that is written is encoded relative to the InstID. +bool DXILBitcodeWriter::pushValueAndType(const Value *V, unsigned InstID, + SmallVectorImpl &Vals) { + unsigned ValID = VE.getValueID(V); + // Make encoding relative to the InstID. + Vals.push_back(InstID - ValID); + if (ValID >= InstID) { + Vals.push_back(VE.getTypeID(V->getType())); + return true; + } + return false; +} + +/// pushValue - Like pushValueAndType, but where the type of the value is +/// omitted (perhaps it was already encoded in an earlier operand). +void DXILBitcodeWriter::pushValue(const Value *V, unsigned InstID, + SmallVectorImpl &Vals) { + unsigned ValID = VE.getValueID(V); + Vals.push_back(InstID - ValID); +} + +void DXILBitcodeWriter::pushValueSigned(const Value *V, unsigned InstID, + SmallVectorImpl &Vals) { + unsigned ValID = VE.getValueID(V); + int64_t diff = ((int32_t)InstID - (int32_t)ValID); + emitSignedInt64(Vals, diff); +} + +/// WriteInstruction - Emit an instruction +void DXILBitcodeWriter::writeInstruction(const Instruction &I, unsigned InstID, + SmallVectorImpl &Vals) { + unsigned Code = 0; + unsigned AbbrevToUse = 0; + VE.setInstructionID(&I); + switch (I.getOpcode()) { + default: + if (Instruction::isCast(I.getOpcode())) { + Code = bitc::FUNC_CODE_INST_CAST; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_CAST_ABBREV; + Vals.push_back(VE.getTypeID(I.getType())); + Vals.push_back(getEncodedCastOpcode(I.getOpcode())); + } else { + assert(isa(I) && "Unknown instruction!"); + Code = bitc::FUNC_CODE_INST_BINOP; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_BINOP_ABBREV; + pushValue(I.getOperand(1), InstID, Vals); + Vals.push_back(getEncodedBinaryOpcode(I.getOpcode())); + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) { + if (AbbrevToUse == (unsigned)dxilc::FUNCTION_INST_BINOP_ABBREV) + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_BINOP_FLAGS_ABBREV; + Vals.push_back(Flags); + } + } + break; + + case Instruction::GetElementPtr: { + Code = bitc::FUNC_CODE_INST_GEP; + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_GEP_ABBREV; + auto &GEPInst = cast(I); + Vals.push_back(GEPInst.isInBounds()); + Vals.push_back(VE.getTypeID(GEPInst.getSourceElementType())); + for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); + break; + } + case Instruction::ExtractValue: { + Code = bitc::FUNC_CODE_INST_EXTRACTVAL; + pushValueAndType(I.getOperand(0), InstID, Vals); + const ExtractValueInst *EVI = cast(&I); + Vals.append(EVI->idx_begin(), EVI->idx_end()); + break; + } + case Instruction::InsertValue: { + Code = bitc::FUNC_CODE_INST_INSERTVAL; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValueAndType(I.getOperand(1), InstID, Vals); + const InsertValueInst *IVI = cast(&I); + Vals.append(IVI->idx_begin(), IVI->idx_end()); + break; + } + case Instruction::Select: + Code = bitc::FUNC_CODE_INST_VSELECT; + pushValueAndType(I.getOperand(1), InstID, Vals); + pushValue(I.getOperand(2), InstID, Vals); + pushValueAndType(I.getOperand(0), InstID, Vals); + break; + case Instruction::ExtractElement: + Code = bitc::FUNC_CODE_INST_EXTRACTELT; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValueAndType(I.getOperand(1), InstID, Vals); + break; + case Instruction::InsertElement: + Code = bitc::FUNC_CODE_INST_INSERTELT; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + pushValueAndType(I.getOperand(2), InstID, Vals); + break; + case Instruction::ShuffleVector: + Code = bitc::FUNC_CODE_INST_SHUFFLEVEC; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + pushValue(I.getOperand(2), InstID, Vals); + break; + case Instruction::ICmp: + case Instruction::FCmp: { + // compare returning Int1Ty or vector of Int1Ty + Code = bitc::FUNC_CODE_INST_CMP2; + pushValueAndType(I.getOperand(0), InstID, Vals); + pushValue(I.getOperand(1), InstID, Vals); + Vals.push_back(cast(I).getPredicate()); + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) + Vals.push_back(Flags); + break; + } + + case Instruction::Ret: { + Code = bitc::FUNC_CODE_INST_RET; + unsigned NumOperands = I.getNumOperands(); + if (NumOperands == 0) + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_RET_VOID_ABBREV; + else if (NumOperands == 1) { + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_RET_VAL_ABBREV; + } else { + for (unsigned i = 0, e = NumOperands; i != e; ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); + } + } break; + case Instruction::Br: { + Code = bitc::FUNC_CODE_INST_BR; + const BranchInst &II = cast(I); + Vals.push_back(VE.getValueID(II.getSuccessor(0))); + if (II.isConditional()) { + Vals.push_back(VE.getValueID(II.getSuccessor(1))); + pushValue(II.getCondition(), InstID, Vals); + } + } break; + case Instruction::Switch: { + Code = bitc::FUNC_CODE_INST_SWITCH; + const SwitchInst &SI = cast(I); + Vals.push_back(VE.getTypeID(SI.getCondition()->getType())); + pushValue(SI.getCondition(), InstID, Vals); + Vals.push_back(VE.getValueID(SI.getDefaultDest())); + for (auto Case : SI.cases()) { + Vals.push_back(VE.getValueID(Case.getCaseValue())); + Vals.push_back(VE.getValueID(Case.getCaseSuccessor())); + } + } break; + case Instruction::IndirectBr: + Code = bitc::FUNC_CODE_INST_INDIRECTBR; + Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); + // Encode the address operand as relative, but not the basic blocks. + pushValue(I.getOperand(0), InstID, Vals); + for (unsigned i = 1, e = I.getNumOperands(); i != e; ++i) + Vals.push_back(VE.getValueID(I.getOperand(i))); + break; + + case Instruction::Invoke: { + const InvokeInst *II = cast(&I); + const Value *Callee = II->getCalledOperand(); + FunctionType *FTy = II->getFunctionType(); + Code = bitc::FUNC_CODE_INST_INVOKE; + + Vals.push_back(VE.getAttributeListID(II->getAttributes())); + Vals.push_back(II->getCallingConv() | 1 << 13); + Vals.push_back(VE.getValueID(II->getNormalDest())); + Vals.push_back(VE.getValueID(II->getUnwindDest())); + Vals.push_back(VE.getTypeID(FTy)); + pushValueAndType(Callee, InstID, Vals); + + // Emit value #'s for the fixed parameters. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) + pushValue(I.getOperand(i), InstID, Vals); // fixed param. + + // Emit type/value pairs for varargs params. + if (FTy->isVarArg()) { + for (unsigned i = FTy->getNumParams(), e = I.getNumOperands() - 3; i != e; + ++i) + pushValueAndType(I.getOperand(i), InstID, Vals); // vararg + } + break; + } + case Instruction::Resume: + Code = bitc::FUNC_CODE_INST_RESUME; + pushValueAndType(I.getOperand(0), InstID, Vals); + break; + case Instruction::Unreachable: + Code = bitc::FUNC_CODE_INST_UNREACHABLE; + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_UNREACHABLE_ABBREV; + break; + + case Instruction::PHI: { + const PHINode &PN = cast(I); + Code = bitc::FUNC_CODE_INST_PHI; + // With the newer instruction encoding, forward references could give + // negative valued IDs. This is most common for PHIs, so we use + // signed VBRs. + SmallVector Vals64; + Vals64.push_back(VE.getTypeID(PN.getType())); + for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { + pushValueSigned(PN.getIncomingValue(i), InstID, Vals64); + Vals64.push_back(VE.getValueID(PN.getIncomingBlock(i))); + } + // Emit a Vals64 vector and exit. + Stream.EmitRecord(Code, Vals64, AbbrevToUse); + Vals64.clear(); + return; + } + + case Instruction::LandingPad: { + const LandingPadInst &LP = cast(I); + Code = bitc::FUNC_CODE_INST_LANDINGPAD; + Vals.push_back(VE.getTypeID(LP.getType())); + Vals.push_back(LP.isCleanup()); + Vals.push_back(LP.getNumClauses()); + for (unsigned I = 0, E = LP.getNumClauses(); I != E; ++I) { + if (LP.isCatch(I)) + Vals.push_back(LandingPadInst::Catch); + else + Vals.push_back(LandingPadInst::Filter); + pushValueAndType(LP.getClause(I), InstID, Vals); + } + break; + } + + case Instruction::Alloca: { + Code = bitc::FUNC_CODE_INST_ALLOCA; + const AllocaInst &AI = cast(I); + Vals.push_back(VE.getTypeID(AI.getAllocatedType())); + Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); + Vals.push_back(VE.getValueID(I.getOperand(0))); // size. + using APV = AllocaPackedValues; + unsigned Record = 0; + unsigned EncodedAlign = getEncodedAlign(AI.getAlign()); + Bitfield::set( + Record, EncodedAlign & ((1 << APV::AlignLower::Bits) - 1)); + Bitfield::set(Record, + EncodedAlign >> APV::AlignLower::Bits); + Bitfield::set(Record, AI.isUsedWithInAlloca()); + Vals.push_back(Record); + break; + } + + case Instruction::Load: + if (cast(I).isAtomic()) { + Code = bitc::FUNC_CODE_INST_LOADATOMIC; + pushValueAndType(I.getOperand(0), InstID, Vals); + } else { + Code = bitc::FUNC_CODE_INST_LOAD; + if (!pushValueAndType(I.getOperand(0), InstID, Vals)) // ptr + AbbrevToUse = (unsigned)dxilc::FUNCTION_INST_LOAD_ABBREV; + } + Vals.push_back(VE.getTypeID(I.getType())); + Vals.push_back(Log2_32(cast(I).getAlignment()) + 1); + Vals.push_back(cast(I).isVolatile()); + if (cast(I).isAtomic()) { + Vals.push_back(getEncodedOrdering(cast(I).getOrdering())); + Vals.push_back(getEncodedSyncScopeID(cast(I).getSyncScopeID())); + } + break; + case Instruction::Store: + if (cast(I).isAtomic()) + Code = bitc::FUNC_CODE_INST_STOREATOMIC; + else + Code = bitc::FUNC_CODE_INST_STORE; + pushValueAndType(I.getOperand(1), InstID, Vals); // ptrty + ptr + pushValueAndType(I.getOperand(0), InstID, Vals); // valty + val + Vals.push_back(Log2_32(cast(I).getAlignment()) + 1); + Vals.push_back(cast(I).isVolatile()); + if (cast(I).isAtomic()) { + Vals.push_back(getEncodedOrdering(cast(I).getOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast(I).getSyncScopeID())); + } + break; + case Instruction::AtomicCmpXchg: + Code = bitc::FUNC_CODE_INST_CMPXCHG; + pushValueAndType(I.getOperand(0), InstID, Vals); // ptrty + ptr + pushValueAndType(I.getOperand(1), InstID, Vals); // cmp. + pushValue(I.getOperand(2), InstID, Vals); // newval. + Vals.push_back(cast(I).isVolatile()); + Vals.push_back( + getEncodedOrdering(cast(I).getSuccessOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast(I).getSyncScopeID())); + Vals.push_back( + getEncodedOrdering(cast(I).getFailureOrdering())); + Vals.push_back(cast(I).isWeak()); + break; + case Instruction::AtomicRMW: + Code = bitc::FUNC_CODE_INST_ATOMICRMW; + pushValueAndType(I.getOperand(0), InstID, Vals); // ptrty + ptr + pushValue(I.getOperand(1), InstID, Vals); // val. + Vals.push_back( + getEncodedRMWOperation(cast(I).getOperation())); + Vals.push_back(cast(I).isVolatile()); + Vals.push_back(getEncodedOrdering(cast(I).getOrdering())); + Vals.push_back( + getEncodedSyncScopeID(cast(I).getSyncScopeID())); + break; + case Instruction::Fence: + Code = bitc::FUNC_CODE_INST_FENCE; + Vals.push_back(getEncodedOrdering(cast(I).getOrdering())); + Vals.push_back(getEncodedSyncScopeID(cast(I).getSyncScopeID())); + break; + case Instruction::Call: { + const CallInst &CI = cast(I); + FunctionType *FTy = CI.getFunctionType(); + + Code = bitc::FUNC_CODE_INST_CALL; + + Vals.push_back(VE.getAttributeListID(CI.getAttributes())); + Vals.push_back((CI.getCallingConv() << 1) | unsigned(CI.isTailCall()) | + unsigned(CI.isMustTailCall()) << 14 | 1 << 15); + Vals.push_back(VE.getTypeID(FTy)); + pushValueAndType(CI.getCalledOperand(), InstID, Vals); // Callee + + // Emit value #'s for the fixed parameters. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) { + // Check for labels (can happen with asm labels). + if (FTy->getParamType(i)->isLabelTy()) + Vals.push_back(VE.getValueID(CI.getArgOperand(i))); + else + pushValue(CI.getArgOperand(i), InstID, Vals); // fixed param. + } + + // Emit type/value pairs for varargs params. + if (FTy->isVarArg()) { + for (unsigned i = FTy->getNumParams(), e = CI.arg_size(); i != e; ++i) + pushValueAndType(CI.getArgOperand(i), InstID, Vals); // varargs + } + break; + } + case Instruction::VAArg: + Code = bitc::FUNC_CODE_INST_VAARG; + Vals.push_back(VE.getTypeID(I.getOperand(0)->getType())); // valistty + pushValue(I.getOperand(0), InstID, Vals); // valist. + Vals.push_back(VE.getTypeID(I.getType())); // restype. + break; + } + + Stream.EmitRecord(Code, Vals, AbbrevToUse); + Vals.clear(); +} + +// Emit names for globals/functions etc. +void DXILBitcodeWriter::writeFunctionLevelValueSymbolTable( + const ValueSymbolTable &VST) { + if (VST.empty()) + return; + Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4); + + // FIXME: Set up the abbrev, we know how many values there are! + // FIXME: We know if the type names can use 7-bit ascii. + SmallVector NameVals; + + // HLSL Change - Begin + // Read the named values from a sorted list instead of the original list + // to ensure the binary is the same no matter what values ever existed. + SmallVector SortedTable; + + for (ValueSymbolTable::const_iterator SI = VST.begin(), SE = VST.end(); + SI != SE; ++SI) { + SortedTable.push_back(&(*SI)); + } + // The keys are unique, so there shouldn't be stability issues + std::sort(SortedTable.begin(), SortedTable.end(), + [](const ValueName *A, const ValueName *B) { + return (*A).first() < (*B).first(); + }); + + for (const ValueName *SI : SortedTable) { + auto &Name = *SI; +// HLSL Change - End +#if 0 // HLSL Change + for (ValueSymbolTable::const_iterator SI = VST.begin(), SE = VST.end(); + SI != SE; ++SI) { + const ValueName &Name = *SI; +#endif // HLSL Change + + // Figure out the encoding to use for the name. + bool is7Bit = true; + bool isChar6 = true; + for (const char *C = Name.getKeyData(), *E = C + Name.getKeyLength(); + C != E; ++C) { + if (isChar6) + isChar6 = BitCodeAbbrevOp::isChar6(*C); + if ((unsigned char)*C & 128) { + is7Bit = false; + break; // don't bother scanning the rest. + } + } + + unsigned AbbrevToUse = VST_ENTRY_8_ABBREV; + + // VST_ENTRY: [valueid, namechar x N] + // VST_BBENTRY: [bbid, namechar x N] + unsigned Code; + if (isa(SI->getValue())) { + Code = bitc::VST_CODE_BBENTRY; + if (isChar6) + AbbrevToUse = VST_BBENTRY_6_ABBREV; + } else { + Code = bitc::VST_CODE_ENTRY; + if (isChar6) + AbbrevToUse = VST_ENTRY_6_ABBREV; + else if (is7Bit) + AbbrevToUse = VST_ENTRY_7_ABBREV; + } + + NameVals.push_back(VE.getValueID(SI->getValue())); + for (const char *P = Name.getKeyData(), + *E = Name.getKeyData() + Name.getKeyLength(); + P != E; ++P) + NameVals.push_back((unsigned char)*P); + + // Emit the finished record. + Stream.EmitRecord(Code, NameVals, AbbrevToUse); + NameVals.clear(); + } + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeUseList(UseListOrder &&Order) { + assert(Order.Shuffle.size() >= 2 && "Shuffle too small"); + unsigned Code; + if (isa(Order.V)) + Code = bitc::USELIST_CODE_BB; + else + Code = bitc::USELIST_CODE_DEFAULT; + + SmallVector Record(Order.Shuffle.begin(), Order.Shuffle.end()); + Record.push_back(VE.getValueID(Order.V)); + Stream.EmitRecord(Code, Record); +} + +void DXILBitcodeWriter::writeUseListBlock(const Function *F) { + assert(VE.shouldPreserveUseListOrder() && + "Expected to be preserving use-list order"); + + auto hasMore = [&]() { + return !VE.UseListOrders.empty() && VE.UseListOrders.back().F == F; + }; + if (!hasMore()) + // Nothing to do. + return; + + Stream.EnterSubblock(bitc::USELIST_BLOCK_ID, 3); + while (hasMore()) { + writeUseList(std::move(VE.UseListOrders.back())); + VE.UseListOrders.pop_back(); + } + Stream.ExitBlock(); +} + +/// Emit a function body to the module stream. +void DXILBitcodeWriter::writeFunction(const Function &F) { + Stream.EnterSubblock(bitc::FUNCTION_BLOCK_ID, 4); + VE.incorporateFunction(F); + + SmallVector Vals; + + // Emit the number of basic blocks, so the reader can create them ahead of + // time. + Vals.push_back(VE.getBasicBlocks().size()); + Stream.EmitRecord(bitc::FUNC_CODE_DECLAREBLOCKS, Vals); + Vals.clear(); + + // If there are function-local constants, emit them now. + unsigned CstStart, CstEnd; + VE.getFunctionConstantRange(CstStart, CstEnd); + writeConstants(CstStart, CstEnd, false); + + // If there is function-local metadata, emit it now. + writeFunctionMetadata(F); + + // Keep a running idea of what the instruction ID is. + unsigned InstID = CstEnd; + + bool NeedsMetadataAttachment = F.hasMetadata(); + + DILocation *LastDL = nullptr; + + // Finally, emit all the instructions, in order. + for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; + ++I) { + writeInstruction(*I, InstID, Vals); + + if (!I->getType()->isVoidTy()) + ++InstID; + + // If the instruction has metadata, write a metadata attachment later. + NeedsMetadataAttachment |= I->hasMetadataOtherThanDebugLoc(); + + // If the instruction has a debug location, emit it. + DILocation *DL = I->getDebugLoc(); + if (!DL) + continue; + + if (DL == LastDL) { + // Just repeat the same debug loc as last time. + Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC_AGAIN, Vals); + continue; + } + + Vals.push_back(DL->getLine()); + Vals.push_back(DL->getColumn()); + Vals.push_back(VE.getMetadataOrNullID(DL->getScope())); + Vals.push_back(VE.getMetadataOrNullID(DL->getInlinedAt())); + Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC, Vals); + Vals.clear(); + + LastDL = DL; + } + + // Emit names for all the instructions etc. + if (auto *Symtab = F.getValueSymbolTable()) + writeFunctionLevelValueSymbolTable(*Symtab); + + if (NeedsMetadataAttachment) + writeFunctionMetadataAttachment(F); + if (VE.shouldPreserveUseListOrder()) + writeUseListBlock(&F); + VE.purgeFunction(); + Stream.ExitBlock(); +} + +// Emit blockinfo, which defines the standard abbreviations etc. +void DXILBitcodeWriter::writeBlockInfo() { + // We only want to emit block info records for blocks that have multiple + // instances: CONSTANTS_BLOCK, FUNCTION_BLOCK and VALUE_SYMTAB_BLOCK. + // Other blocks can define their abbrevs inline. + Stream.EnterBlockInfoBlock(); + + { // 8-bit fixed-width VST_ENTRY/VST_BBENTRY strings. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_8_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + { // 7-bit fixed width VST_ENTRY strings. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_ENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_7_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // 6-bit char6 VST_ENTRY strings. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_ENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_ENTRY_6_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // 6-bit char6 VST_BBENTRY strings. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_BBENTRY)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6)); + if (Stream.EmitBlockInfoAbbrev(bitc::VALUE_SYMTAB_BLOCK_ID, + std::move(Abbv)) != VST_BBENTRY_6_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + { // SETTYPE abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_SETTYPE)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + VE.computeBitsRequiredForTypeIndicies())); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_SETTYPE_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + { // INTEGER abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_INTEGER)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_INTEGER_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + { // CE_CAST abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CE_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // cast opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // typeid + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id + + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_CE_CAST_Abbrev) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // NULL abbrev for CONSTANTS_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_NULL)); + if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, std::move(Abbv)) != + CONSTANTS_NULL_Abbrev) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + // FIXME: This should only use space for first class types! + + { // INST_LOAD abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_LOAD)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Ptr + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // Align + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // volatile + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_LOAD_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // INST_BINOP abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // RHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_BINOP_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // INST_BINOP_FLAGS abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_BINOP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // RHS + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7)); // flags + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_BINOP_FLAGS_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // INST_CAST abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_CAST)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpVal + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + VE.computeBitsRequiredForTypeIndicies())); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_CAST_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + { // INST_RET abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_RET_VOID_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // INST_RET abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_RET)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ValID + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_RET_VAL_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { // INST_UNREACHABLE abbrev for FUNCTION_BLOCK. + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNREACHABLE)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_UNREACHABLE_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + { + auto Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_GEP)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, // dest ty + Log2_32_Ceil(VE.getTypes().size() + 1))); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); + if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, std::move(Abbv)) != + (unsigned)dxilc::FUNCTION_INST_GEP_ABBREV) + llvm_unreachable("Unexpected abbrev ordering!"); + } + + Stream.ExitBlock(); +} + +void DXILBitcodeWriter::writeModuleVersion() { + // VERSION: [version#] + Stream.EmitRecord(bitc::MODULE_CODE_VERSION, ArrayRef{1}); +} + +/// WriteModule - Emit the specified module to the bitstream. +void DXILBitcodeWriter::write() { + // The identification block is new since llvm-3.7, but the old bitcode reader + // will skip it. + // writeIdentificationBlock(Stream); + + Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); + + // It is redundant to fully-specify this here, but nice to make it explicit + // so that it is clear the DXIL module version is different. + DXILBitcodeWriter::writeModuleVersion(); + + // Emit blockinfo, which defines the standard abbreviations etc. + writeBlockInfo(); + + // Emit information about attribute groups. + writeAttributeGroupTable(); + + // Emit information about parameter attributes. + writeAttributeTable(); + + // Emit information describing all of the types in the module. + writeTypeTable(); + + writeComdats(); + + // Emit top-level description of module, including target triple, inline asm, + // descriptors for global variables, and function prototype info. + writeModuleInfo(); + + // Emit constants. + writeModuleConstants(); + + // Emit metadata. + writeModuleMetadataKinds(); + + // Emit metadata. + writeModuleMetadata(); + + // Emit names for globals/functions etc. + // DXIL uses the same format for module-level value symbol table as for the + // function level table. + writeFunctionLevelValueSymbolTable(M.getValueSymbolTable()); + + // Emit module-level use-lists. + if (VE.shouldPreserveUseListOrder()) + writeUseListBlock(nullptr); + + // Emit function bodies. + for (Module::const_iterator F = M.begin(), E = M.end(); F != E; ++F) + if (!F->isDeclaration()) + writeFunction(*F); + + Stream.ExitBlock(); +} diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp --- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "DirectXTargetMachine.h" +#include "DXILBitcodeWriter.h" #include "DirectX.h" #include "DirectXSubtarget.h" #include "DirectXTargetTransformInfo.h" @@ -92,8 +93,9 @@ PM.add(createPrintModulePass(Out, "", true)); break; case CGFT_ObjectFile: - // TODO: Write DXIL instead of bitcode - PM.add(createBitcodeWriterPass(Out, true, false, false)); + // TODO: Use MC Object streamer to write DXContainer + PM.add(createBitcodeWriterPass(Out, true, false, false, + &DXILBitcodeWriter::Create)); break; case CGFT_Null: break; diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -20,6 +20,7 @@ LLVM_INLINER_MODEL_AUTOGENERATED LLVM_RAEVICT_MODEL_AUTOGENERATED LLVM_ENABLE_EXPENSIVE_CHECKS + LLVM_INCLUDE_DXIL_TESTS ) configure_lit_site_cfg( @@ -211,6 +212,10 @@ ) endif() +if (LLVM_INCLUDE_DXIL_TESTS) + list(APPEND LLVM_TEST_DEPENDS dxil-dis) +endif() + add_custom_target(llvm-test-depends DEPENDS ${LLVM_TEST_DEPENDS}) set_target_properties(llvm-test-depends PROPERTIES FOLDER "Tests") diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -189,7 +189,8 @@ ToolSubst('OrcV2CBindingsRemovableCode', unresolved='ignore'), ToolSubst('OrcV2CBindingsReflectProcessSymbols', unresolved='ignore'), ToolSubst('OrcV2CBindingsLazy', unresolved='ignore'), - ToolSubst('OrcV2CBindingsVeryLazy', unresolved='ignore')]) + ToolSubst('OrcV2CBindingsVeryLazy', unresolved='ignore'), + ToolSubst('dxil-dis', unresolved='ignore')]) llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -57,6 +57,7 @@ config.llvm_inliner_model_autogenerated = @LLVM_INLINER_MODEL_AUTOGENERATED@ config.llvm_raevict_model_autogenerated = @LLVM_RAEVICT_MODEL_AUTOGENERATED@ config.expensive_checks = @LLVM_ENABLE_EXPENSIVE_CHECKS@ +config.dxil_tests = @LLVM_INCLUDE_DXIL_TESTS@ import lit.llvm lit.llvm.initialize(lit_config, config) diff --git a/llvm/test/tools/dxil-dis/BasicIR.ll b/llvm/test/tools/dxil-dis/BasicIR.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/BasicIR.ll @@ -0,0 +1,15 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s + +; CHECK: define i32 @foo(i32 %X, i32 %Y) { +; CHECK: %Z = sub i32 %X, %Y +; CHECK: %Q = add i32 %Z, %Y +; CHECK: ret i32 %Q +; CHECK: } + +target triple = "dxil-unknown-unknown" + +define i32 @foo(i32 %X, i32 %Y) { + %Z = sub i32 %X, %Y + %Q = add i32 %Z, %Y + ret i32 %Q +} diff --git a/llvm/test/tools/dxil-dis/FMA.ll b/llvm/test/tools/dxil-dis/FMA.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/FMA.ll @@ -0,0 +1,15 @@ +; RUN: llc %s --filetype=obj -o - | dxil-dis -o - | FileCheck %s + +; CHECK: target triple = "dxil-unknown-unknown" +target triple = "dxil-unknown-unknown" + +; CHECK: Function Attrs: nounwind readnone +; Function Attrs: norecurse nounwind readnone willreturn +define float @fma(float %0, float %1, float %2) #0 { + %4 = fmul float %0, %1 + %5 = fadd float %4, %2 + ret float %5 +} + +; CHECK: attributes #0 = { nounwind readnone "disable-tail-calls"="false" } +attributes #0 = { norecurse nounwind readnone willreturn "disable-tail-calls"="false" } diff --git a/llvm/test/tools/dxil-dis/debug-info.ll b/llvm/test/tools/dxil-dis/debug-info.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/debug-info.ll @@ -0,0 +1,66 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" + +; CHECK: define float @fma(float, float, float) unnamed_addr #0 !dbg !6 +; Function Attrs: norecurse nounwind readnone willreturn +define dso_local float @fma(float %0, float %1, float %2) local_unnamed_addr #0 !dbg !6 { +; CHECK-NEXT: call void @llvm.dbg.value(metadata float %0, metadata !11, metadata !14), !dbg !15 +; CHECK-NEXT: call void @llvm.dbg.value(metadata float %1, metadata !12, metadata !14), !dbg !15 +; CHECK-NEXT: call void @llvm.dbg.value(metadata float %2, metadata !13, metadata !14), !dbg !15 + call void @llvm.dbg.value(metadata float %0, metadata !11, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata float %1, metadata !12, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata float %2, metadata !13, metadata !DIExpression()), !dbg !14 +; CHECK-NEXT: %4 = fmul float %0, %1, !dbg !16 +; CHECK-NEXT: %5 = fadd float %4, %2, !dbg !17 + %4 = fmul float %0, %1, !dbg !15 + %5 = fadd float %4, %2, !dbg !16 + ret float %5, !dbg !17 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone willreturn } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +; Other tests verify that we come back with reasonable structure for the debug +; info types, this test just needs to ensure they are there. +; The patch this is paired with fixes a bug where function debug info wasn't +; being emitted correctly even though other tests verified the MD would be +; emitted if it was referenced as module metadata. + +; CHECK: !0 = distinct !DICompileUnit +; CHECK-NEXT: !1 = !DIFile(filename: +; CHECK: !6 = distinct !DISubprogram(name: "fma", +; CHECK: !11 = !DILocalVariable(tag: +; CHECK-NEXT: !12 = !DILocalVariable(tag: +; CHECK-NEXT: !13 = !DILocalVariable(tag: +; CHECK-NEXT: !14 = !DIExpression() +; CHECK-NEXT: !15 = !DILocation(line: +; CHECK-NEXT: !16 = !DILocation(line: +; CHECK-NEXT: !17 = !DILocation(line: +; CHECK-NEXT: !18 = !DILocation(line: + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "in.c", directory: "dir") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 2} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"Some Compiler"} +!6 = distinct !DISubprogram(name: "fma", scope: !1, file: !1, line: 1, type: !7, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !9, !9, !9} +!9 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!10 = !{!11, !12, !13} +!11 = !DILocalVariable(name: "x", arg: 1, scope: !6, file: !1, line: 1, type: !9) +!12 = !DILocalVariable(name: "y", arg: 2, scope: !6, file: !1, line: 1, type: !9) +!13 = !DILocalVariable(name: "z", arg: 3, scope: !6, file: !1, line: 1, type: !9) +!14 = !DILocation(line: 0, scope: !6) +!15 = !DILocation(line: 2, column: 12, scope: !6) +!16 = !DILocation(line: 2, column: 16, scope: !6) +!17 = !DILocation(line: 2, column: 3, scope: !6) diff --git a/llvm/test/tools/dxil-dis/di-compile-unit.ll b/llvm/test/tools/dxil-dis/di-compile-unit.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/di-compile-unit.ll @@ -0,0 +1,17 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "di-compile-unit.src", directory: "/some-path") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 2} +!4 = !{i32 2, !"Debug Info Version", i32 3} + +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2) +; CHECK: !1 = !DIFile(filename: "di-compile-unit.src", directory: "/some-path") +; CHECK: !2 = !{} +; CHECK: !3 = !{i32 7, !"Dwarf Version", i32 2} +; CHECK: !4 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/llvm/test/tools/dxil-dis/di-subprogram.ll b/llvm/test/tools/dxil-dis/di-subprogram.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/di-subprogram.ll @@ -0,0 +1,53 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.used = !{!5} +!llvm.lines = !{!13, !14, !15, !16} + +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2) +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Some Compiler", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +; CHECK: !1 = !DIFile(filename: "some-source", directory: "some-path") +!1 = !DIFile(filename: "some-source", directory: "some-path") +!2 = !{} + +; CHECK: !3 = !{i32 7, !"Dwarf Version", i32 2} +!3 = !{i32 7, !"Dwarf Version", i32 2} +; CHECK: !4 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 2, !"Debug Info Version", i32 3} + +; CHECK: !5 = distinct !DISubprogram(name: "fma", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, function: !0, variables: !9) +!5 = distinct !DISubprogram(name: "fma", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !9) + +; CHECK: !6 = !DISubroutineType(types: !7) +!6 = !DISubroutineType(types: !7) + +; CHECK: !7 = !{!8, !8, !8, !8} +!7 = !{!8, !8, !8, !8} + +; CHECK: !8 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!8 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + +; CHECK: !9 = !{!10, !11, !12} +!9 = !{!10, !11, !12} + +; CHECK: !10 = !DILocalVariable(tag: DW_TAG_variable, name: "x", arg: 1, scope: !5, file: !1, line: 1, type: !8) +!10 = !DILocalVariable(name: "x", arg: 1, scope: !5, file: !1, line: 1, type: !8) + +; CHECK: !11 = !DILocalVariable(tag: DW_TAG_variable, name: "y", arg: 2, scope: !5, file: !1, line: 1, type: !8) +!11 = !DILocalVariable(name: "y", arg: 2, scope: !5, file: !1, line: 1, type: !8) + +; CHECK: !12 = !DILocalVariable(tag: DW_TAG_variable, name: "z", arg: 3, scope: !5, file: !1, line: 1, type: !8) +!12 = !DILocalVariable(name: "z", arg: 3, scope: !5, file: !1, line: 1, type: !8) + + +; CHECK: !13 = !DILocation(line: 0, scope: !5) +; CHECK: !14 = !DILocation(line: 2, column: 12, scope: !5) +; CHECK: !15 = !DILocation(line: 2, column: 16, scope: !5) +; CHECK: !16 = !DILocation(line: 2, column: 3, scope: !5) + +!13 = !DILocation(line: 0, scope: !5) +!14 = !DILocation(line: 2, column: 12, scope: !5) +!15 = !DILocation(line: 2, column: 16, scope: !5) +!16 = !DILocation(line: 2, column: 3, scope: !5) diff --git a/llvm/test/tools/dxil-dis/di-subrotine.ll b/llvm/test/tools/dxil-dis/di-subrotine.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/di-subrotine.ll @@ -0,0 +1,12 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis -o - | FileCheck %s +target triple = "dxil-unknown-unknown" + +!llvm.used = !{!0} + +!0 = !DISubroutineType(types: !1) +!1 = !{!2, !2, !2, !2} +!2 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + +; CHECK: !0 = !DISubroutineType(types: !1) +; CHECK: !1 = !{!2, !2, !2, !2} +; CHECK: !2 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) diff --git a/llvm/test/tools/dxil-dis/lit.local.cfg b/llvm/test/tools/dxil-dis/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/lit.local.cfg @@ -0,0 +1,3 @@ +if not config.dxil_tests: + config.unsupported = True +config.suffixes = ['.ll'] diff --git a/llvm/test/tools/dxil-dis/metadata.ll b/llvm/test/tools/dxil-dis/metadata.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dxil-dis/metadata.ll @@ -0,0 +1,13 @@ +; RUN: llc --filetype=obj %s -o - | dxil-dis +target triple = "dxil-unknown-unknown" + +!llvm.foo = !{!0} +!llvm.bar = !{!1} + +!0 = !{i32 42} +!1 = !{!"Some MDString"} + +; CHECK: !llvm.foo = !{!0} +; CHECK: !llvm.bar = !{!1} +; CHECK: !0 = !{i32 42} +; CHECK: !1 = !{!"Some MDString"} diff --git a/llvm/tools/dxil-dis/CMakeLists.txt b/llvm/tools/dxil-dis/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/dxil-dis/CMakeLists.txt @@ -0,0 +1,48 @@ +option(LLVM_INCLUDE_DXIL_TESTS "Include DXIL tests" Off) +mark_as_advanced(LLVM_INCLUDE_DXIL_TESTS) + +if (NOT LLVM_INCLUDE_DXIL_TESTS) + return() +endif () + +if (NOT "DirectX" IN_LIST LLVM_EXPERIMENTAL_TARGETS_TO_BUILD) + message(FATAL_ERROR "Building dxil-dis tests is unsupported without the DirectX target") +endif () + +if (DXIL_DIS) + add_custom_target(dxil-dis + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${DXIL_DIS}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/dxil-dis") + return() +endif () + +include(ExternalProject) + +set(SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/DXC-src) +set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/DXC-bins) +set(GIT_SETTINGS GIT_REPOSITORY https://github.com/microsoft/DirectXShaderCompiler.git) + +if (DXC_SOURCE_DIR) + set(SOURCE_DIR ${DXC_SOURCE_DIR}) + unset(GIT_SETTINGS) +endif () + +ExternalProject_Add(DXC + ${GIT_SETTINGS} + SOURCE_DIR ${SOURCE_DIR} + BINARY_DIR ${BINARY_DIR} + CMAKE_ARGS -C ${SOURCE_DIR}/cmake/caches/PredefinedParams.cmake -DLLVM_INCLUDE_TESTS=On + BUILD_COMMAND ${CMAKE_COMMAND} --build ${BINARY_DIR} --target llvm-dis + BUILD_BYPRODUCTS ${BINARY_DIR}/bin/llvm-dis + INSTALL_COMMAND "" + ) + +if (CMAKE_HOST_UNIX) + set(LLVM_LINK_OR_COPY create_symlink) +else () + set(LLVM_LINK_OR_COPY copy) +endif () + +add_custom_target(dxil-dis + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${BINARY_DIR}/bin/llvm-dis${CMAKE_EXECUTABLE_SUFFIX}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/dxil-dis${CMAKE_EXECUTABLE_SUFFIX}" + DEPENDS DXC + )