From f6e8e78bbf1a12497521b0d49cf1b3c67dd5e290 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 1 Sep 2021 15:38:20 +0100 Subject: [PATCH] Emit global var and function records in module * The value IDs currently aren't fetched in LLVM-matching order so we don't have those yet for global var initialisers --- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 8 + .../shaders/dxil/dxil_bytecode_editor.cpp | 141 +++++++++++++++++- .../driver/shaders/dxil/llvm_encoder.cpp | 83 ++++++++++- renderdoc/driver/shaders/dxil/llvm_encoder.h | 12 +- 4 files changed, 238 insertions(+), 6 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 0d2572fe9..000a0b610 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -123,6 +123,12 @@ struct Symbol Symbol(SymbolType type = SymbolType::Unknown, uint64_t idx = 0) : type(type), idx(idx) {} SymbolType type; uint64_t idx; + bool operator<(const Symbol &o) const + { + if(type != o.type) + return type < o.type; + return idx < o.idx; + } }; enum class GlobalFlags : uint32_t @@ -163,6 +169,8 @@ struct GlobalVar struct Alias { rdcstr name; + const Type *type = NULL; + uint64_t valID = 0; }; // this enum is ordered to match the serialised order of these attributes diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp index 3038f010f..38d25d6ce 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp @@ -44,14 +44,32 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const { bytebuf ret; + std::map valueId; + LLVMBC::BitcodeWriter writer(ret); + uint64_t maxAlign = 0; + uint32_t maxGlobalType = 0; + + for(size_t i = 0; i < m_GlobalVars.size(); i++) + { + maxAlign = RDCMAX(m_GlobalVars[i].align, maxAlign); + RDCASSERT(m_GlobalVars[i].type->type == Type::Pointer); + uint32_t typeIndex = uint32_t(m_GlobalVars[i].type->inner - m_Types.begin()); + maxGlobalType = RDCMAX(typeIndex, maxGlobalType); + } + + for(size_t i = 0; i < m_Functions.size(); i++) + maxAlign = RDCMAX(m_Functions[i].align, maxAlign); + + writer.ConfigureSizes(m_Types.size(), m_Sections.size(), maxAlign, maxGlobalType); + writer.BeginBlock(LLVMBC::KnownBlock::MODULE_BLOCK); writer.Record(LLVMBC::ModuleRecord::VERSION, 1U); { - writer.ModuleBlockInfo((uint32_t)m_Types.size()); + writer.ModuleBlockInfo(); } if(!m_AttributeGroups.empty()) @@ -245,6 +263,127 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const writer.EndBlock(); } + // COMDAT would be next, but we don't read these (DXIL seems not to use them...?) + + if(!m_Triple.empty()) + writer.Record(LLVMBC::ModuleRecord::TRIPLE, m_Triple); + + if(!m_Datalayout.empty()) + writer.Record(LLVMBC::ModuleRecord::DATALAYOUT, m_Datalayout); + + // inline asm would go here + + // write the sections + for(size_t i = 0; i < m_Sections.size(); i++) + writer.Record(LLVMBC::ModuleRecord::SECTIONNAME, m_Sections[i]); + + if(!m_GlobalVars.empty()) + writer.EmitGlobalVarAbbrev(); + + for(size_t i = 0; i < m_GlobalVars.size(); i++) + { + const GlobalVar &g = m_GlobalVars[i]; + + // global vars write the value type, not the pointer + size_t typeIndex = g.type->inner - m_Types.begin(); + + uint64_t linkageValue = 0; + + switch(g.flags & GlobalFlags::LinkageMask) + { + case GlobalFlags::ExternalLinkage: linkageValue = 0; break; + case GlobalFlags::WeakAnyLinkage: linkageValue = 16; break; + case GlobalFlags::AppendingLinkage: linkageValue = 2; break; + case GlobalFlags::InternalLinkage: linkageValue = 3; break; + case GlobalFlags::LinkOnceAnyLinkage: linkageValue = 18; break; + case GlobalFlags::ExternalWeakLinkage: linkageValue = 7; break; + case GlobalFlags::CommonLinkage: linkageValue = 8; break; + case GlobalFlags::PrivateLinkage: linkageValue = 9; break; + case GlobalFlags::WeakODRLinkage: linkageValue = 17; break; + case GlobalFlags::LinkOnceODRLinkage: linkageValue = 19; break; + case GlobalFlags::AvailableExternallyLinkage: linkageValue = 12; break; + default: break; + } + + uint64_t unnamedAddr = 0; + + if(g.flags & GlobalFlags::GlobalUnnamedAddr) + unnamedAddr = 1; + else if(g.flags & GlobalFlags::LocalUnnamedAddr) + unnamedAddr = 2; + + writer.Record(LLVMBC::ModuleRecord::GLOBALVAR, + { + typeIndex, uint64_t(((g.flags & GlobalFlags::IsConst) ? 1 : 0) | 0x2 | + ((uint32_t)g.type->addrSpace << 2)), + g.initialiser.type != SymbolType::Unknown ? valueId[g.initialiser] + 1 : 0, + linkageValue, 32 - Bits::CountLeadingZeroes(g.align), uint64_t(g.section + 1), + // visibility + 0U, + // TLS mode + 0U, + // unnamed addr + unnamedAddr, (g.flags & GlobalFlags::ExternallyInitialised) ? 1U : 0U, + // DLL storage class + 0U, + // comdat + 0U, + }); + } + + for(size_t i = 0; i < m_Functions.size(); i++) + { + const Function &f = m_Functions[i]; + size_t typeIndex = f.funcType - m_Types.begin(); + + writer.Record(LLVMBC::ModuleRecord::FUNCTION, + { + typeIndex, + // calling convention + 0U, + // external/declaration + f.external ? 1U : 0U, + // linkage + 0U, + // attributes + uint64_t(f.attrs ? 1U + (f.attrs - m_Attributes.begin()) : 0U), + // alignment + f.align, + // section + 0U, + // visibility + 0U, + // gc + 0U, + // unnamed_addr + 0U, + // prologuedata + 0U, + // dllstorageclass + 0U, + // comdat + 0U, + // prefixdata + 0U, + // personality + 0U, + }); + } + + for(size_t i = 0; i < m_Aliases.size(); i++) + { + const Alias &a = m_Aliases[i]; + size_t typeIndex = a.type - m_Types.begin(); + + writer.Record(LLVMBC::ModuleRecord::ALIAS, { + typeIndex, a.valID, + // linkage + 0U, + // visibility + 0U, + }); + } + writer.EndBlock(); ProgramHeader header; diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp index 56172a476..7548bf277 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp @@ -262,6 +262,10 @@ BitcodeWriter::BitcodeWriter(bytebuf &buf) : b(buf) curBlock = KnownBlock::Count; abbrevSize = 2; + + numAbbrevs = 0; + + m_GlobalVarAbbrev = ~0U; } BitcodeWriter::~BitcodeWriter() @@ -373,10 +377,31 @@ void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev) } } -void BitcodeWriter::ModuleBlockInfo(uint32_t numTypes) +void BitcodeWriter::ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign, + uint32_t maxGlobalType) { - m_NumTypeBits = 32 - Bits::CountLeadingZeroes(numTypes); + m_NumTypeBits = 32 - Bits::CountLeadingZeroes((uint32_t)numTypes); + m_GlobalTypeBits = 32 - Bits::CountLeadingZeroes(maxGlobalType); + + if(numSections == 0) + m_NumSectionBits = 0; + else + m_NumSectionBits = 32 - Bits::CountLeadingZeroes((uint32_t)numSections); + + if(maxAlign == 0) + { + m_AlignBits = 0; + } + else + { + uint32_t encodedAlign = 32 - Bits::CountLeadingZeroes((uint32_t)maxAlign); + m_AlignBits = 32 - Bits::CountLeadingZeroes(encodedAlign); + } +} + +void BitcodeWriter::ModuleBlockInfo() +{ // these abbrevs are hardcoded in llvm, at least at dxc's version BeginBlock(KnownBlock::BLOCKINFO); @@ -396,6 +421,29 @@ void BitcodeWriter::ModuleBlockInfo(uint32_t numTypes) EndBlock(); } +void BitcodeWriter::EmitGlobalVarAbbrev() +{ + m_GlobalVarAbbrev = numAbbrevs; + + AbbrevParam align = AbbFixed(m_AlignBits); + if(m_AlignBits == 0) + align = AbbLiteral(0); + + AbbrevParam section = AbbFixed(m_NumSectionBits); + if(m_NumSectionBits == 0) + section = AbbLiteral(0); + + m_GlobalVarAbbrevDef[0] = AbbLiteral(ModuleRecord::GLOBALVAR); + m_GlobalVarAbbrevDef[1] = AbbFixed(m_GlobalTypeBits); + m_GlobalVarAbbrevDef[2] = AbbVBR(6); + m_GlobalVarAbbrevDef[3] = AbbVBR(6); + m_GlobalVarAbbrevDef[4] = AbbFixed(5); + m_GlobalVarAbbrevDef[5] = align; + m_GlobalVarAbbrevDef[6] = section; + + WriteAbbrevDefinition(m_GlobalVarAbbrevDef); +} + uint32_t BitcodeWriter::GetAbbrevID(uint32_t id) { // the id is a block-local index, starting from 0, of the abbrevs defined for that block. @@ -422,6 +470,13 @@ void BitcodeWriter::AutoRecord(uint32_t record, bool param, uint64_t val) case KnownBlock::VALUE_SYMTAB_BLOCK: RDCERR("Symbol table entry needs multiple parameters"); break; + case KnownBlock::MODULE_BLOCK: + switch(ModuleRecord(record)) + { + case ModuleRecord::GLOBALVAR: RDCERR("global var needs multiple parameters"); break; + default: break; + } + break; case KnownBlock::TYPE_BLOCK: switch(TypeRecord(record)) { @@ -458,6 +513,21 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray &vals) case KnownBlock::VALUE_SYMTAB_BLOCK: // the selection of abbrev here depends on the data break; + case KnownBlock::MODULE_BLOCK: + switch(ModuleRecord(record)) + { + case ModuleRecord::GLOBALVAR: + { + idx = m_GlobalVarAbbrev; + // if any of the later values are non-zero, can't use the global var abbrev + for(size_t i = 6; i < vals.size(); i++) + if(vals[i] != 0) + idx = ~0U; + break; + } + default: break; + } + break; case KnownBlock::TYPE_BLOCK: switch(TypeRecord(record)) { @@ -490,7 +560,14 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray &vals) } // if we got a valid abbrev, use it, otherwise emit unabbrev - if(idx < numAbbrevDefs) + if(idx == m_GlobalVarAbbrev && idx != ~0U) + { + // write the abbrev ID + b.fixed(abbrevSize, GetAbbrevID(m_GlobalVarAbbrev)); + + Abbrev(m_GlobalVarAbbrevDef, record, vals); + } + else if(idx < numAbbrevDefs) { // write the abbrev ID b.fixed(abbrevSize, GetAbbrevID(idx)); diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.h b/renderdoc/driver/shaders/dxil/llvm_encoder.h index cd8231802..e56dcb0f3 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.h +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.h @@ -37,11 +37,13 @@ public: BitcodeWriter(bytebuf &buf); ~BitcodeWriter(); - void BeginBlock(KnownBlock block); + void ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign, uint32_t maxGlobalType); + void BeginBlock(KnownBlock block); void EndBlock(); - void ModuleBlockInfo(uint32_t numTypes); + void ModuleBlockInfo(); + void EmitGlobalVarAbbrev(); void AutoRecord(uint32_t record, bool param, uint64_t val); void AutoRecord(uint32_t record, const rdcarray &vals); @@ -87,11 +89,17 @@ private: BitWriter b; uint32_t m_NumTypeBits; + uint32_t m_GlobalTypeBits; + uint32_t m_NumSectionBits; + uint32_t m_AlignBits; size_t abbrevSize; uint32_t numAbbrevs; KnownBlock curBlock; + uint32_t m_GlobalVarAbbrev; + AbbrevParam m_GlobalVarAbbrevDef[10] = {}; + struct BlockContext { KnownBlock block;