From 9e3385d18dc4836a1a57ca3cfd0936ae5b7b4273 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 31 Aug 2021 18:01:34 +0100 Subject: [PATCH] Emit root module block and blockinfo subblock * It looks like LLVM (at DXC's version anyway) hardcodes a series of abbreviations, so we do the same --- .../driver/shaders/dxil/dxil_bytecode.cpp | 31 +- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 179 ---------- .../shaders/dxil/dxil_bytecode_editor.cpp | 10 +- .../shaders/dxil/dxil_bytecode_editor.h | 2 +- .../driver/shaders/dxil/dxil_debuginfo.cpp | 33 +- renderdoc/driver/shaders/dxil/llvm_common.h | 198 ++++++++++- .../driver/shaders/dxil/llvm_decoder.cpp | 35 +- renderdoc/driver/shaders/dxil/llvm_decoder.h | 2 +- .../driver/shaders/dxil/llvm_encoder.cpp | 326 +++++++++++++++++- renderdoc/driver/shaders/dxil/llvm_encoder.h | 17 + 10 files changed, 596 insertions(+), 237 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp index 7308b705e..852971c18 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp @@ -29,12 +29,15 @@ #include "common/common.h" #include "common/formatting.h" #include "os/os_specific.h" +#include "llvm_common.h" #include "llvm_decoder.h" #define IS_KNOWN(val, KnownID) (decltype(KnownID)(val) == KnownID) namespace DXIL { +using namespace LLVMBC; + void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, std::function getType, std::function getPtrType, @@ -302,7 +305,7 @@ Program::Program(const byte *bytes, size_t length) LLVMBC::BlockOrRecord root = reader.ReadToplevelBlock(); // the top-level block should be MODULE_BLOCK - RDCASSERT(KnownBlocks(root.id) == KnownBlocks::MODULE_BLOCK); + RDCASSERT(KnownBlock(root.id) == KnownBlock::MODULE_BLOCK); // we should have consumed all bits, only one top-level block RDCASSERT(reader.AtEndOfStream()); @@ -497,11 +500,11 @@ Program::Program(const byte *bytes, size_t length) } else if(rootchild.IsBlock()) { - if(IS_KNOWN(rootchild.id, KnownBlocks::BLOCKINFO)) + if(IS_KNOWN(rootchild.id, KnownBlock::BLOCKINFO)) { // do nothing, this is internal parse data } - else if(IS_KNOWN(rootchild.id, KnownBlocks::PARAMATTR_GROUP_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::PARAMATTR_GROUP_BLOCK)) { for(const LLVMBC::BlockOrRecord &attrgroup : rootchild.children) { @@ -562,7 +565,7 @@ Program::Program(const byte *bytes, size_t length) m_AttributeGroups[id] = group; } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::PARAMATTR_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::PARAMATTR_BLOCK)) { for(const LLVMBC::BlockOrRecord ¶mattr : rootchild.children) { @@ -602,7 +605,7 @@ Program::Program(const byte *bytes, size_t length) m_Attributes.push_back(attrs); } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::TYPE_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::TYPE_BLOCK)) { rdcstr structname; @@ -763,7 +766,7 @@ Program::Program(const byte *bytes, size_t length) } } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::CONSTANTS_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::CONSTANTS_BLOCK)) { const Type *t = NULL; m_Constants.reserve(m_Constants.size() + rootchild.children.size()); @@ -820,7 +823,7 @@ Program::Program(const byte *bytes, size_t length) } } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::VALUE_SYMTAB_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::VALUE_SYMTAB_BLOCK)) { for(const LLVMBC::BlockOrRecord &symtab : rootchild.children) { @@ -868,7 +871,7 @@ Program::Program(const byte *bytes, size_t length) } } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::METADATA_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::METADATA_BLOCK)) { m_Metadata.reserve(rootchild.children.size()); for(size_t i = 0; i < rootchild.children.size(); i++) @@ -945,7 +948,7 @@ Program::Program(const byte *bytes, size_t length) } } } - else if(IS_KNOWN(rootchild.id, KnownBlocks::FUNCTION_BLOCK)) + else if(IS_KNOWN(rootchild.id, KnownBlock::FUNCTION_BLOCK)) { Function &f = m_Functions[functionDecls[0]]; functionDecls.erase(0); @@ -980,7 +983,7 @@ Program::Program(const byte *bytes, size_t length) { if(funcChild.IsBlock()) { - if(IS_KNOWN(funcChild.id, KnownBlocks::CONSTANTS_BLOCK)) + if(IS_KNOWN(funcChild.id, KnownBlock::CONSTANTS_BLOCK)) { f.constants.reserve(funcChild.children.size()); @@ -1030,7 +1033,7 @@ Program::Program(const byte *bytes, size_t length) instrSymbolStart = m_Symbols.size(); } - else if(IS_KNOWN(funcChild.id, KnownBlocks::METADATA_BLOCK)) + else if(IS_KNOWN(funcChild.id, KnownBlock::METADATA_BLOCK)) { f.metadata.resize(funcChild.children.size()); @@ -1080,7 +1083,7 @@ Program::Program(const byte *bytes, size_t length) m++; } } - else if(IS_KNOWN(funcChild.id, KnownBlocks::VALUE_SYMTAB_BLOCK)) + else if(IS_KNOWN(funcChild.id, KnownBlock::VALUE_SYMTAB_BLOCK)) { for(const LLVMBC::BlockOrRecord &symtab : funcChild.children) { @@ -1141,7 +1144,7 @@ Program::Program(const byte *bytes, size_t length) } } } - else if(IS_KNOWN(funcChild.id, KnownBlocks::METADATA_ATTACHMENT)) + else if(IS_KNOWN(funcChild.id, KnownBlock::METADATA_ATTACHMENT)) { for(const LLVMBC::BlockOrRecord &meta : funcChild.children) { @@ -1173,7 +1176,7 @@ Program::Program(const byte *bytes, size_t length) f.instructions[(size_t)meta.ops[0]].attachedMeta.swap(attach); } } - else if(IS_KNOWN(funcChild.id, KnownBlocks::USELIST_BLOCK)) + else if(IS_KNOWN(funcChild.id, KnownBlock::USELIST_BLOCK)) { RDCDEBUG("Ignoring uselist block"); } diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index b72293f90..141945f4b 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -31,12 +31,6 @@ #include "driver/dx/official/d3dcommon.h" #include "driver/shaders/dxbc/dxbc_common.h" -// undef some annoying defines that might come from OS headers -#undef VOID -#undef FLOAT -#undef LABEL -#undef OPAQUE - namespace LLVMBC { struct BlockOrRecord; @@ -55,179 +49,6 @@ struct ProgramHeader uint32_t BitcodeSize; // Size of LLVM bitcode. }; -enum class KnownBlocks : uint32_t -{ - BLOCKINFO = 0, - - // 1-7 reserved, - - MODULE_BLOCK = 8, - PARAMATTR_BLOCK = 9, - PARAMATTR_GROUP_BLOCK = 10, - CONSTANTS_BLOCK = 11, - FUNCTION_BLOCK = 12, - TYPE_SYMTAB_BLOCK = 13, - VALUE_SYMTAB_BLOCK = 14, - METADATA_BLOCK = 15, - METADATA_ATTACHMENT = 16, - TYPE_BLOCK = 17, - USELIST_BLOCK = 18, -}; - -enum class ModuleRecord : uint32_t -{ - VERSION = 1, - TRIPLE = 2, - DATALAYOUT = 3, - SECTIONNAME = 5, - GLOBALVAR = 7, - FUNCTION = 8, - ALIAS = 14, -}; - -enum class ConstantsRecord : uint32_t -{ - SETTYPE = 1, - CONST_NULL = 2, - UNDEF = 3, - INTEGER = 4, - FLOAT = 6, - AGGREGATE = 7, - STRING = 8, - CSTRING = 9, - EVAL_CAST = 11, - EVAL_GEP = 20, - DATA = 22, -}; - -enum class FunctionRecord : uint32_t -{ - DECLAREBLOCKS = 1, - INST_BINOP = 2, - INST_CAST = 3, - INST_GEP_OLD = 4, - INST_SELECT = 5, - INST_EXTRACTELT = 6, - INST_INSERTELT = 7, - INST_SHUFFLEVEC = 8, - INST_CMP = 9, - INST_RET = 10, - INST_BR = 11, - INST_SWITCH = 12, - INST_INVOKE = 13, - INST_UNREACHABLE = 15, - INST_PHI = 16, - INST_ALLOCA = 19, - INST_LOAD = 20, - INST_VAARG = 23, - INST_STORE_OLD = 24, - INST_EXTRACTVAL = 26, - INST_INSERTVAL = 27, - INST_CMP2 = 28, - INST_VSELECT = 29, - INST_INBOUNDS_GEP_OLD = 30, - INST_INDIRECTBR = 31, - DEBUG_LOC_AGAIN = 33, - INST_CALL = 34, - DEBUG_LOC = 35, - INST_FENCE = 36, - INST_CMPXCHG_OLD = 37, - INST_ATOMICRMW = 38, - INST_RESUME = 39, - INST_LANDINGPAD_OLD = 40, - INST_LOADATOMIC = 41, - INST_STOREATOMIC_OLD = 42, - INST_GEP = 43, - INST_STORE = 44, - INST_STOREATOMIC = 45, - INST_CMPXCHG = 46, - INST_LANDINGPAD = 47, -}; - -enum class ParamAttrRecord : uint32_t -{ - ENTRY = 2, -}; - -enum class ParamAttrGroupRecord : uint32_t -{ - ENTRY = 3, -}; - -enum class ValueSymtabRecord : uint32_t -{ - ENTRY = 1, - BBENTRY = 2, - FNENTRY = 3, - COMBINED_ENTRY = 5, -}; - -enum class MetaDataRecord : uint32_t -{ - STRING_OLD = 1, - VALUE = 2, - NODE = 3, - NAME = 4, - DISTINCT_NODE = 5, - KIND = 6, - LOCATION = 7, - OLD_NODE = 8, - OLD_FN_NODE = 9, - NAMED_NODE = 10, - ATTACHMENT = 11, - GENERIC_DEBUG = 12, - SUBRANGE = 13, - ENUMERATOR = 14, - BASIC_TYPE = 15, - FILE = 16, - DERIVED_TYPE = 17, - COMPOSITE_TYPE = 18, - SUBROUTINE_TYPE = 19, - COMPILE_UNIT = 20, - SUBPROGRAM = 21, - LEXICAL_BLOCK = 22, - LEXICAL_BLOCK_FILE = 23, - NAMESPACE = 24, - TEMPLATE_TYPE = 25, - TEMPLATE_VALUE = 26, - GLOBAL_VAR = 27, - LOCAL_VAR = 28, - EXPRESSION = 29, - OBJC_PROPERTY = 30, - IMPORTED_ENTITY = 31, - MODULE = 32, - MACRO = 33, - MACRO_FILE = 34, - STRINGS = 35, - GLOBAL_DECL_ATTACHMENT = 36, - GLOBAL_VAR_EXPR = 37, - INDEX_OFFSET = 38, - INDEX = 39, - LABEL = 40, - COMMON_BLOCK = 44, -}; - -enum class TypeRecord : uint32_t -{ - NUMENTRY = 1, - VOID = 2, - FLOAT = 3, - DOUBLE = 4, - LABEL = 5, - OPAQUE = 6, - INTEGER = 7, - POINTER = 8, - FUNCTION_OLD = 9, - HALF = 10, - ARRAY = 11, - VECTOR = 12, - METADATA = 16, - STRUCT_ANON = 18, - STRUCT_NAME = 19, - STRUCT_NAMED = 20, - FUNCTION = 21, -}; - struct Type { enum TypeKind diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp index 5c32cc259..5e87f5fee 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp @@ -40,12 +40,20 @@ DXIL::ProgramEditor::~ProgramEditor() DXBC::DXBCContainer::ReplaceDXILBytecode(m_OutBlob, EncodeProgram()); } -bytebuf DXIL::ProgramEditor::EncodeProgram() +bytebuf DXIL::ProgramEditor::EncodeProgram() const { bytebuf ret; LLVMBC::BitcodeWriter writer(ret); + writer.BeginBlock(LLVMBC::KnownBlock::MODULE_BLOCK); + + writer.Unabbrev((uint32_t)LLVMBC::ModuleRecord::VERSION, 1U); + + writer.ModuleBlockInfo((uint32_t)m_Types.size()); + + writer.EndBlock(); + ProgramHeader header; header.ProgramVersion = ((m_Major & 0xf) << 4) | (m_Minor & 0xf); diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.h b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.h index a35174ac0..641145c1d 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.h @@ -42,7 +42,7 @@ public: private: bytebuf &m_OutBlob; - bytebuf EncodeProgram(); + bytebuf EncodeProgram() const; }; }; // namespace DXIL diff --git a/renderdoc/driver/shaders/dxil/dxil_debuginfo.cpp b/renderdoc/driver/shaders/dxil/dxil_debuginfo.cpp index a19ff2368..db8772cff 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debuginfo.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debuginfo.cpp @@ -24,26 +24,27 @@ #include "dxil_debuginfo.h" #include "common/formatting.h" +#include "llvm_common.h" #include "llvm_decoder.h" namespace DXIL { bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Metadata &meta) { - MetaDataRecord id = (MetaDataRecord)metaRecord.id; + LLVMBC::MetaDataRecord id = (LLVMBC::MetaDataRecord)metaRecord.id; auto getNonNullMeta = [this](uint64_t id) { return &m_Metadata[size_t(id)]; }; auto getMeta = [this](uint64_t id) { return id ? &m_Metadata[size_t(id - 1)] : NULL; }; auto getMetaString = [this](uint64_t id) { return id ? &m_Metadata[size_t(id - 1)].str : NULL; }; - if(id == MetaDataRecord::FILE) + if(id == LLVMBC::MetaDataRecord::FILE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); meta.dwarf = new DIFile(getMeta(metaRecord.ops[1]), getMeta(metaRecord.ops[2])); meta.children = {getMeta(metaRecord.ops[1]), getMeta(metaRecord.ops[2])}; } - else if(id == MetaDataRecord::COMPILE_UNIT) + else if(id == LLVMBC::MetaDataRecord::COMPILE_UNIT) { // should be at least 14 parameters RDCASSERT(metaRecord.ops.size() >= 14); @@ -62,7 +63,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta getMeta(metaRecord.ops[10]), getMeta(metaRecord.ops[11]), getMeta(metaRecord.ops[12]), getMeta(metaRecord.ops[13])}; } - else if(id == MetaDataRecord::BASIC_TYPE) + else if(id == LLVMBC::MetaDataRecord::BASIC_TYPE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -70,7 +71,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta new DIBasicType(DW_TAG(metaRecord.ops[1]), getMetaString(metaRecord.ops[2]), metaRecord.ops[3], metaRecord.ops[4], DW_ENCODING(metaRecord.ops[5])); } - else if(id == MetaDataRecord::DERIVED_TYPE) + else if(id == LLVMBC::MetaDataRecord::DERIVED_TYPE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -83,7 +84,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[3]), getMeta(metaRecord.ops[5]), getMeta(metaRecord.ops[6]), getMeta(metaRecord.ops[11])}; } - else if(id == MetaDataRecord::COMPOSITE_TYPE) + else if(id == LLVMBC::MetaDataRecord::COMPOSITE_TYPE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -98,7 +99,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta getMeta(metaRecord.ops[6]), getMeta(metaRecord.ops[11]), getMeta(metaRecord.ops[14])}; } - else if(id == MetaDataRecord::TEMPLATE_TYPE) + else if(id == LLVMBC::MetaDataRecord::TEMPLATE_TYPE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -107,7 +108,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[2])}; } - else if(id == MetaDataRecord::TEMPLATE_VALUE) + else if(id == LLVMBC::MetaDataRecord::TEMPLATE_VALUE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -117,7 +118,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[3]), getMeta(metaRecord.ops[4])}; } - else if(id == MetaDataRecord::SUBPROGRAM) + else if(id == LLVMBC::MetaDataRecord::SUBPROGRAM) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -134,7 +135,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta getMeta(metaRecord.ops[14]), getMeta(metaRecord.ops[15]), getMeta(metaRecord.ops[16]), getMeta(metaRecord.ops[17])}; } - else if(id == MetaDataRecord::SUBROUTINE_TYPE) + else if(id == LLVMBC::MetaDataRecord::SUBROUTINE_TYPE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -142,7 +143,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[2])}; } - else if(id == MetaDataRecord::GLOBAL_VAR) + else if(id == LLVMBC::MetaDataRecord::GLOBAL_VAR) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -165,7 +166,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta RDCERR("Unsupported version of global variable metadata"); } } - else if(id == MetaDataRecord::LOCATION) + else if(id == LLVMBC::MetaDataRecord::LOCATION) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -177,7 +178,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getNonNullMeta(metaRecord.ops[3]), getMeta(metaRecord.ops[4])}; } - else if(id == MetaDataRecord::LOCAL_VAR) + else if(id == LLVMBC::MetaDataRecord::LOCAL_VAR) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -189,7 +190,7 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[2]), getMeta(metaRecord.ops[4]), getMeta(metaRecord.ops[6])}; } - else if(id == MetaDataRecord::LEXICAL_BLOCK) + else if(id == LLVMBC::MetaDataRecord::LEXICAL_BLOCK) { meta.isDistinct = (metaRecord.ops[0] & 0x1); @@ -198,13 +199,13 @@ bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Meta meta.children = {getMeta(metaRecord.ops[1]), getMeta(metaRecord.ops[2])}; } - else if(id == MetaDataRecord::SUBRANGE) + else if(id == LLVMBC::MetaDataRecord::SUBRANGE) { meta.isDistinct = (metaRecord.ops[0] & 0x1); meta.dwarf = new DISubrange(metaRecord.ops[1], LLVMBC::BitReader::svbr(metaRecord.ops[2])); } - else if(id == MetaDataRecord::EXPRESSION) + else if(id == LLVMBC::MetaDataRecord::EXPRESSION) { DIExpression *expr = new DIExpression; diff --git a/renderdoc/driver/shaders/dxil/llvm_common.h b/renderdoc/driver/shaders/dxil/llvm_common.h index 66a5a57a2..8474230af 100644 --- a/renderdoc/driver/shaders/dxil/llvm_common.h +++ b/renderdoc/driver/shaders/dxil/llvm_common.h @@ -24,10 +24,22 @@ #pragma once +#include "api/replay/rdcarray.h" +#include "common/common.h" + +// undef some annoying defines that might come from OS headers +#undef VOID +#undef FLOAT +#undef LABEL +#undef OPAQUE + namespace LLVMBC { +static const uint32_t BitcodeMagic = MAKE_FOURCC('B', 'C', 0xC0, 0xDE); + enum class AbbrevEncoding : uint8_t { + Unknown = 0, Fixed = 1, VBR = 2, Array = 3, @@ -54,5 +66,189 @@ enum class BlockInfoRecord SETRECORDNAME = 3, }; -static const uint32_t BitcodeMagic = MAKE_FOURCC('B', 'C', 0xC0, 0xDE); +enum class KnownBlock : uint32_t +{ + BLOCKINFO = 0, + + // 1-7 reserved, + + MODULE_BLOCK = 8, + PARAMATTR_BLOCK = 9, + PARAMATTR_GROUP_BLOCK = 10, + CONSTANTS_BLOCK = 11, + FUNCTION_BLOCK = 12, + // TYPE_SYMTAB_BLOCK deprecated? + VALUE_SYMTAB_BLOCK = 14, + METADATA_BLOCK = 15, + METADATA_ATTACHMENT = 16, + TYPE_BLOCK = 17, + USELIST_BLOCK = 18, + + Count, +}; + +enum class ModuleRecord : uint32_t +{ + VERSION = 1, + TRIPLE = 2, + DATALAYOUT = 3, + SECTIONNAME = 5, + GLOBALVAR = 7, + FUNCTION = 8, + ALIAS = 14, +}; + +enum class ConstantsRecord : uint32_t +{ + SETTYPE = 1, + CONST_NULL = 2, + UNDEF = 3, + INTEGER = 4, + FLOAT = 6, + AGGREGATE = 7, + STRING = 8, + CSTRING = 9, + EVAL_CAST = 11, + EVAL_GEP = 20, + DATA = 22, +}; + +enum class FunctionRecord : uint32_t +{ + DECLAREBLOCKS = 1, + INST_BINOP = 2, + INST_CAST = 3, + INST_GEP_OLD = 4, + INST_SELECT = 5, + INST_EXTRACTELT = 6, + INST_INSERTELT = 7, + INST_SHUFFLEVEC = 8, + INST_CMP = 9, + INST_RET = 10, + INST_BR = 11, + INST_SWITCH = 12, + INST_INVOKE = 13, + INST_UNREACHABLE = 15, + INST_PHI = 16, + INST_ALLOCA = 19, + INST_LOAD = 20, + INST_VAARG = 23, + INST_STORE_OLD = 24, + INST_EXTRACTVAL = 26, + INST_INSERTVAL = 27, + INST_CMP2 = 28, + INST_VSELECT = 29, + INST_INBOUNDS_GEP_OLD = 30, + INST_INDIRECTBR = 31, + DEBUG_LOC_AGAIN = 33, + INST_CALL = 34, + DEBUG_LOC = 35, + INST_FENCE = 36, + INST_CMPXCHG_OLD = 37, + INST_ATOMICRMW = 38, + INST_RESUME = 39, + INST_LANDINGPAD_OLD = 40, + INST_LOADATOMIC = 41, + INST_STOREATOMIC_OLD = 42, + INST_GEP = 43, + INST_STORE = 44, + INST_STOREATOMIC = 45, + INST_CMPXCHG = 46, + INST_LANDINGPAD = 47, +}; + +enum class ParamAttrRecord : uint32_t +{ + ENTRY = 2, +}; + +enum class ParamAttrGroupRecord : uint32_t +{ + ENTRY = 3, +}; + +enum class ValueSymtabRecord : uint32_t +{ + ENTRY = 1, + BBENTRY = 2, + FNENTRY = 3, + COMBINED_ENTRY = 5, +}; + +enum class MetaDataRecord : uint32_t +{ + STRING_OLD = 1, + VALUE = 2, + NODE = 3, + NAME = 4, + DISTINCT_NODE = 5, + KIND = 6, + LOCATION = 7, + OLD_NODE = 8, + OLD_FN_NODE = 9, + NAMED_NODE = 10, + ATTACHMENT = 11, + GENERIC_DEBUG = 12, + SUBRANGE = 13, + ENUMERATOR = 14, + BASIC_TYPE = 15, + FILE = 16, + DERIVED_TYPE = 17, + COMPOSITE_TYPE = 18, + SUBROUTINE_TYPE = 19, + COMPILE_UNIT = 20, + SUBPROGRAM = 21, + LEXICAL_BLOCK = 22, + LEXICAL_BLOCK_FILE = 23, + NAMESPACE = 24, + TEMPLATE_TYPE = 25, + TEMPLATE_VALUE = 26, + GLOBAL_VAR = 27, + LOCAL_VAR = 28, + EXPRESSION = 29, + OBJC_PROPERTY = 30, + IMPORTED_ENTITY = 31, + MODULE = 32, + MACRO = 33, + MACRO_FILE = 34, + STRINGS = 35, + GLOBAL_DECL_ATTACHMENT = 36, + GLOBAL_VAR_EXPR = 37, + INDEX_OFFSET = 38, + INDEX = 39, + LABEL = 40, + COMMON_BLOCK = 44, +}; + +enum class TypeRecord : uint32_t +{ + NUMENTRY = 1, + VOID = 2, + FLOAT = 3, + DOUBLE = 4, + LABEL = 5, + OPAQUE = 6, + INTEGER = 7, + POINTER = 8, + FUNCTION_OLD = 9, + HALF = 10, + ARRAY = 11, + VECTOR = 12, + METADATA = 16, + STRUCT_ANON = 18, + STRUCT_NAME = 19, + STRUCT_NAMED = 20, + FUNCTION = 21, +}; + +struct AbbrevParam +{ + AbbrevEncoding encoding; + uint64_t value; // this is also the bitwidth for Fixed/VBR +}; + +struct AbbrevDesc +{ + rdcarray params; +}; }; diff --git a/renderdoc/driver/shaders/dxil/llvm_decoder.cpp b/renderdoc/driver/shaders/dxil/llvm_decoder.cpp index df91cfaf4..874ce069a 100644 --- a/renderdoc/driver/shaders/dxil/llvm_decoder.cpp +++ b/renderdoc/driver/shaders/dxil/llvm_decoder.cpp @@ -28,22 +28,12 @@ namespace LLVMBC { -struct AbbrevParam -{ - AbbrevEncoding encoding; - uint64_t value; // this is also the bitwidth for Fixed/VBR -}; - -struct AbbrevDesc -{ - rdcarray params; -}; - // the temporary context while pushing/popping blocks struct BlockContext { - BlockContext(size_t size = 2) : abbrevSize(size) {} + BlockContext(size_t size, size_t offs = 0) : abbrevSize(size), lengthOffset(offs) {} size_t abbrevSize; + size_t lengthOffset; rdcarray abbrevs; }; @@ -62,6 +52,8 @@ bool BitcodeReader::Valid(const byte *bitcode, size_t length) BitcodeReader::BitcodeReader(const byte *bitcode, size_t length) : b(bitcode, length) { + abbrevSize = 2; + uint32_t magic = b.Read(); RDCASSERT(magic == BitcodeMagic); @@ -78,7 +70,7 @@ BlockOrRecord BitcodeReader::ReadToplevelBlock() BlockOrRecord ret; // should hit ENTER_SUBBLOCK first for top-level block - uint32_t abbrevID = b.fixed(abbrevSize()); + uint32_t abbrevID = b.fixed(abbrevSize); RDCASSERT(abbrevID == ENTER_SUBBLOCK); ReadBlockContents(ret); @@ -95,7 +87,8 @@ void BitcodeReader::ReadBlockContents(BlockOrRecord &block) { block.id = b.vbr(8); - blockStack.push_back(new BlockContext(b.vbr(4))); + abbrevSize = b.vbr(4); + blockStack.push_back(new BlockContext(abbrevSize)); b.align32bits(); block.blockDwordLength = b.Read(); @@ -106,7 +99,7 @@ void BitcodeReader::ReadBlockContents(BlockOrRecord &block) uint32_t abbrevID = ~0U; do { - abbrevID = b.fixed(abbrevSize()); + abbrevID = b.fixed(abbrevSize); if(abbrevID == END_BLOCK) { @@ -254,6 +247,8 @@ void BitcodeReader::ReadBlockContents(BlockOrRecord &block) delete blockStack.back(); blockStack.erase(blockStack.size() - 1); + + abbrevSize = blockStack.empty() ? 2 : blockStack.back()->abbrevSize; } uint64_t BitcodeReader::decodeAbbrevParam(const AbbrevParam ¶m) @@ -267,19 +262,13 @@ uint64_t BitcodeReader::decodeAbbrevParam(const AbbrevParam ¶m) case AbbrevEncoding::Char6: return b.c6(); case AbbrevEncoding::Literal: return param.value; case AbbrevEncoding::Array: - case AbbrevEncoding::Blob: RDCERR("Array and blob types must be decoded specially"); + case AbbrevEncoding::Blob: RDCERR("Array and blob types must be decoded specially"); break; + case AbbrevEncoding::Unknown: RDCERR("Unexpected abbrev encoding"); break; } return 0; } -size_t BitcodeReader::abbrevSize() const -{ - if(blockStack.empty()) - return 2; - return blockStack.back()->abbrevSize; -} - const AbbrevDesc &BitcodeReader::getAbbrev(uint32_t blockId, uint32_t abbrevID) { const BlockInfo *info = blockInfo[blockId]; diff --git a/renderdoc/driver/shaders/dxil/llvm_decoder.h b/renderdoc/driver/shaders/dxil/llvm_decoder.h index 88c934fe5..ded2f37aa 100644 --- a/renderdoc/driver/shaders/dxil/llvm_decoder.h +++ b/renderdoc/driver/shaders/dxil/llvm_decoder.h @@ -68,10 +68,10 @@ public: private: BitReader b; + size_t abbrevSize; void ReadBlockContents(BlockOrRecord &block); const AbbrevDesc &getAbbrev(uint32_t blockId, uint32_t abbrevID); - size_t abbrevSize() const; uint64_t decodeAbbrevParam(const AbbrevParam ¶m); rdcarray blockStack; diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp index 20c14d5b2..db5513d86 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp @@ -24,18 +24,342 @@ #include "llvm_encoder.h" #include "os/os_specific.h" -#include "llvm_common.h" namespace LLVMBC { +static uint32_t GetBlockAbbrevSize(KnownBlock block) +{ + uint32_t ret = 0; + + // the abbrev sizes seem to be hardcoded in llvm? At least this matches dxc's llvm + switch(block) + { + case KnownBlock::BLOCKINFO: ret = 2; break; + case KnownBlock::MODULE_BLOCK: ret = 3; break; + case KnownBlock::PARAMATTR_BLOCK: ret = 3; break; + case KnownBlock::PARAMATTR_GROUP_BLOCK: ret = 3; break; + case KnownBlock::CONSTANTS_BLOCK: ret = 4; break; + case KnownBlock::FUNCTION_BLOCK: ret = 4; break; + case KnownBlock::VALUE_SYMTAB_BLOCK: ret = 4; break; + case KnownBlock::METADATA_BLOCK: ret = 3; break; + case KnownBlock::METADATA_ATTACHMENT: ret = 3; break; + case KnownBlock::TYPE_BLOCK: ret = 4; break; + case KnownBlock::USELIST_BLOCK: ret = 3; break; + case KnownBlock::Count: break; + } + + return ret; +} + +#define MagicFixedSizeNumTypes 99 + +#define AbbFixed(n) \ + { \ + AbbrevEncoding::Fixed, n \ + } +#define AbbVBR(n) \ + { \ + AbbrevEncoding::VBR, n \ + } +#define AbbArray() \ + { \ + AbbrevEncoding::Array, 0 \ + } +#define AbbLiteral(lit) \ + { \ + AbbrevEncoding::Literal, uint64_t(lit) \ + } +#define AbbChar6() \ + { \ + AbbrevEncoding::Char6, 0 \ + } + +#define AbbFixedTypes() AbbFixed(MagicFixedSizeNumTypes) + +using AbbrevDefinition = AbbrevParam[8]; + +// known abbreviations. Encoded as an array of abbrevs, with each one being an array of params (the +// last param will have AbbrevEncoding::Unknown == 0) +enum class ValueSymtabAbbrev +{ + Entry8, + Entry7, + Entry6, + BBEntry6, +}; + +AbbrevDefinition ValueSymtabAbbrevDefs[] = { + // Entry8 + { + AbbFixed(3), AbbVBR(8), AbbArray(), AbbFixed(8), + }, + // Entry7 + { + AbbLiteral(ValueSymtabRecord::ENTRY), AbbVBR(8), AbbArray(), AbbFixed(7), + }, + // Entry6 + { + AbbLiteral(ValueSymtabRecord::ENTRY), AbbVBR(8), AbbArray(), AbbChar6(), + }, + // BBEntry6 + { + AbbLiteral(ValueSymtabRecord::BBENTRY), AbbVBR(8), AbbArray(), AbbChar6(), + }, +}; + +enum class ConstantsAbbrev +{ + SetType, + Integer, + EvalCast, + Null, +}; + +AbbrevDefinition ConstantsAbbrevDefs[] = { + // SetType + { + AbbLiteral(ConstantsRecord::SETTYPE), AbbFixedTypes(), + }, + // Integer + { + AbbLiteral(ConstantsRecord::INTEGER), AbbVBR(8), + }, + // EvalCast + { + AbbLiteral(ConstantsRecord::EVAL_CAST), AbbFixed(4), AbbFixedTypes(), AbbVBR(8), + }, + // Null + { + AbbLiteral(ConstantsRecord::CONST_NULL), + }, +}; + +enum class FunctionAbbrev +{ + Load, + BinOp, + BinOpFlags, + Cast, + RetVoid, + RetValue, + Unreachable, + GEP, +}; + +AbbrevDefinition FunctionAbbrevDefs[] = { + // Load + { + AbbLiteral(FunctionRecord::INST_LOAD), AbbVBR(6), AbbFixedTypes(), AbbVBR(4), AbbFixed(1), + }, + // BinOp + { + AbbLiteral(FunctionRecord::INST_BINOP), AbbVBR(6), AbbVBR(6), AbbFixed(4), + }, + // BinOpFlags + { + AbbLiteral(FunctionRecord::INST_BINOP), AbbVBR(6), AbbVBR(6), AbbFixed(4), AbbFixed(7), + }, + // Cast + { + AbbLiteral(FunctionRecord::INST_CAST), AbbVBR(6), AbbFixedTypes(), AbbFixed(4), + }, + // RetVoid + { + AbbLiteral(FunctionRecord::INST_RET), + }, + // RetValue + { + AbbLiteral(FunctionRecord::INST_RET), AbbVBR(6), + }, + // Unreachable + { + AbbLiteral(FunctionRecord::INST_UNREACHABLE), + }, + // GEP + { + AbbLiteral(FunctionRecord::INST_GEP), AbbFixed(1), AbbFixedTypes(), AbbArray(), AbbVBR(6), + }, +}; + +static AbbrevDefinition *GetAbbrevs(KnownBlock block) +{ + AbbrevDefinition *ret = NULL; + + switch(block) + { + case KnownBlock::VALUE_SYMTAB_BLOCK: ret = ValueSymtabAbbrevDefs; break; + case KnownBlock::CONSTANTS_BLOCK: ret = ConstantsAbbrevDefs; break; + case KnownBlock::FUNCTION_BLOCK: ret = FunctionAbbrevDefs; break; + default: break; + } + + return ret; +} + +static uint32_t GetNumAbbrevs(KnownBlock block) +{ + uint32_t ret = 0; + + switch(block) + { + case KnownBlock::VALUE_SYMTAB_BLOCK: ret = ARRAY_COUNT(ValueSymtabAbbrevDefs); break; + case KnownBlock::CONSTANTS_BLOCK: ret = ARRAY_COUNT(ConstantsAbbrevDefs); break; + case KnownBlock::FUNCTION_BLOCK: ret = ARRAY_COUNT(FunctionAbbrevDefs); break; + default: break; + } + + return ret; +} + BitcodeWriter::BitcodeWriter(bytebuf &buf) : b(buf) { b.Write(LLVMBC::BitcodeMagic); + + curBlock = KnownBlock::Count; + abbrevSize = 2; } BitcodeWriter::~BitcodeWriter() { } + +void BitcodeWriter::BeginBlock(KnownBlock block) +{ + uint32_t newAbbrevSize = GetBlockAbbrevSize(block); + + if(newAbbrevSize == 0) + { + RDCERR("Encoding error: unrecognised block %u", block); + return; + } + + b.fixed(abbrevSize, ENTER_SUBBLOCK); + b.vbr(8, block); + b.vbr(4, newAbbrevSize); + b.align32bits(); + + size_t offs = b.GetByteOffset(); + + // write a placeholder length + b.Write(0U); + + curBlock = block; + abbrevSize = newAbbrevSize; + blockStack.push_back({block, offs}); +} + +void BitcodeWriter::EndBlock() +{ + b.vbr(abbrevSize, END_BLOCK); + b.align32bits(); + + size_t offs = blockStack.back().second; + + // -4 because we don't include the word with the length itself + size_t lengthInBytes = b.GetByteOffset() - offs - 4; + + b.PatchLengthWord(offs, uint32_t(lengthInBytes / 4)); + + blockStack.pop_back(); + if(blockStack.empty()) + { + curBlock = KnownBlock::Count; + abbrevSize = 2; + } + else + { + curBlock = blockStack.back().first; + abbrevSize = GetBlockAbbrevSize(curBlock); + } +} + +void BitcodeWriter::ModuleBlockInfo(uint32_t numTypes) +{ + // these abbrevs are hardcoded in llvm, at least at dxc's version + BeginBlock(KnownBlock::BLOCKINFO); + + // the module-level blockinfo contains abbrevs for these block types that can be repeated + // subblocks + for(KnownBlock block : + {KnownBlock::VALUE_SYMTAB_BLOCK, KnownBlock::CONSTANTS_BLOCK, KnownBlock::FUNCTION_BLOCK}) + { + Unabbrev((uint32_t)BlockInfoRecord::SETBID, (uint32_t)block); + AbbrevDefinition *abbrevs = GetAbbrevs(block); + uint32_t numAbbrevs = GetNumAbbrevs(block); + + for(uint32_t i = 0; i < numAbbrevs; i++) + { + b.fixed(abbrevSize, DEFINE_ABBREV); + + AbbrevParam *abbrev = abbrevs[i]; + + uint32_t numParams = 0; + while(abbrev[numParams].encoding != AbbrevEncoding::Unknown) + numParams++; + + b.vbr(5, numParams); + + for(uint32_t p = 0; p < numParams; p++) + { + AbbrevParam param = abbrev[p]; + + if(param.value == MagicFixedSizeNumTypes) + { + param.value = 32 - Bits::CountLeadingZeroes(numTypes); + } + + const bool lit = param.encoding == AbbrevEncoding::Literal; + b.fixed(1, lit); + if(lit) + { + b.vbr(8, param.value); + } + else + { + b.fixed(3, param.encoding); + if(param.encoding == AbbrevEncoding::VBR || param.encoding == AbbrevEncoding::Fixed) + b.vbr(5, param.value); + } + } + } + } + + EndBlock(); +} + +void BitcodeWriter::Unabbrev(uint32_t record, uint32_t val) +{ + b.fixed(abbrevSize, UNABBREV_RECORD); + b.vbr(6, record); + b.vbr(6, 1U); // num parameters + b.vbr(6, val); +} + +void BitcodeWriter::Unabbrev(uint32_t record, uint64_t val) +{ + b.fixed(abbrevSize, UNABBREV_RECORD); + b.vbr(6, record); + b.vbr(6, 1U); // num parameters + b.vbr(6, val); +} + +void BitcodeWriter::Unabbrev(uint32_t record, const rdcarray &vals) +{ + b.fixed(abbrevSize, UNABBREV_RECORD); + b.vbr(6, record); + b.vbr(6, vals.size()); + for(uint32_t v : vals) + b.vbr(6, v); +} + +void BitcodeWriter::Unabbrev(uint32_t record, const rdcarray &vals) +{ + b.fixed(abbrevSize, UNABBREV_RECORD); + b.vbr(6, record); + b.vbr(6, vals.size()); + for(uint64_t v : vals) + b.vbr(6, v); +} }; #if ENABLED(ENABLE_UNIT_TESTS) diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.h b/renderdoc/driver/shaders/dxil/llvm_encoder.h index d58d3d40b..8c09716fa 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.h +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.h @@ -27,6 +27,7 @@ #include "api/replay/rdcarray.h" #include "api/replay/rdcstr.h" #include "llvm_bitwriter.h" +#include "llvm_common.h" namespace LLVMBC { @@ -36,8 +37,24 @@ public: BitcodeWriter(bytebuf &buf); ~BitcodeWriter(); + void BeginBlock(KnownBlock block); + + void EndBlock(); + + void ModuleBlockInfo(uint32_t numTypes); + + void Unabbrev(uint32_t record, uint32_t val); + void Unabbrev(uint32_t record, uint64_t val); + void Unabbrev(uint32_t record, const rdcarray &vals); + void Unabbrev(uint32_t record, const rdcarray &vals); + private: BitWriter b; + + size_t abbrevSize; + KnownBlock curBlock; + + rdcarray> blockStack; }; }; // namespace LLVMBC