From a2a5d8ec8aa4bd7e7d132cc952a08d3c1beb51dc Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 1 Sep 2021 18:22:29 +0100 Subject: [PATCH] Emit the global constants block in DXIL --- .../driver/shaders/dxil/dxil_bytecode.cpp | 96 +++++---- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 58 +++++- .../shaders/dxil/dxil_bytecode_editor.cpp | 155 +++++++++++++-- .../driver/shaders/dxil/dxil_disassemble.cpp | 12 +- renderdoc/driver/shaders/dxil/llvm_common.h | 2 +- .../driver/shaders/dxil/llvm_encoder.cpp | 188 ++++++++++++++---- renderdoc/driver/shaders/dxil/llvm_encoder.h | 10 +- 7 files changed, 417 insertions(+), 104 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp index 1f615e689..affe5ead6 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp @@ -84,8 +84,8 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, Constant v; v.op = DecodeCast(constant.ops[0]); v.type = curType; - // getType(constant.ops[1]); type of the constant, which we ignore v.inner = getConstant(constant.ops[2]); + RDCASSERT(getType(constant.ops[1]) == v.inner->type); addConstant(v); } else if(IS_KNOWN(constant.id, ConstantsRecord::EVAL_GEP)) @@ -104,26 +104,28 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, const Constant *a = getConstant(constant.ops[idx + 1]); RDCASSERT(t == a->type); - v.members.push_back(*a); + v.members.push_back(a); } if(!v.type) - v.type = v.members[0].type; - - // walk the type list to get the return type - for(idx = 2; idx < v.members.size(); idx++) { - if(v.type->type == Type::Vector || v.type->type == Type::Array) + v.type = v.members[0]->type; + + // walk the type list to get the return type + for(idx = 2; idx < v.members.size(); idx++) { - v.type = v.type->inner; - } - else if(v.type->type == Type::Struct) - { - v.type = v.type->members[v.members[idx].val.u32v[0]]; - } - else - { - RDCERR("Unexpected type %d encountered in GEP", v.type->type); + if(v.type->type == Type::Vector || v.type->type == Type::Array) + { + v.type = v.type->inner; + } + else if(v.type->type == Type::Struct) + { + v.type = v.type->members[v.members[idx]->val.u32v[0]]; + } + else + { + RDCERR("Unexpected type %d encountered in GEP", v.type->type); + } } } @@ -145,6 +147,8 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, if(member) { + v.members.push_back(member); + if(v.type->bitWidth <= 32) v.val.u32v[m] = member->val.u32v[m]; else @@ -164,13 +168,13 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, if(member && member->type) { - v.members.push_back(*member); + v.members.push_back(member); } else { - Constant c; - c.type = NULL; - c.val.u64v[0] = m; + Constant *c = new Constant(); + c->type = NULL; + c->val.u64v[0] = m; v.members.push_back(c); RDCWARN("Index %llu out of bounds for constants array, possible forward reference", m); } @@ -182,6 +186,7 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, { Constant v; v.type = curType; + v.data = true; if(v.type->type == Type::Vector) { for(size_t m = 0; m < constant.ops.size(); m++) @@ -196,12 +201,12 @@ void ParseConstant(const LLVMBC::BlockOrRecord &constant, const Type *&curType, { for(size_t m = 0; m < constant.ops.size(); m++) { - Constant el; - el.type = v.type->inner; - if(el.type->bitWidth <= 32) - el.val.u32v[0] = constant.ops[m] & ((1ULL << el.type->bitWidth) - 1); + Constant *el = new Constant(); + el->type = v.type->inner; + if(el->type->bitWidth <= 32) + el->val.u32v[0] = constant.ops[m] & ((1ULL << el->type->bitWidth) - 1); else - el.val.u64v[m] = constant.ops[m]; + el->val.u64v[0] = constant.ops[m]; v.members.push_back(el); } } @@ -474,16 +479,23 @@ Program::Program(const byte *bytes, size_t length) } else if(IS_KNOWN(rootchild.id, ModuleRecord::ALIAS)) { - // [alias value type, addrspace, aliasee val#, linkage, visibility] + // [alias type, aliasee val#, linkage, visibility] Alias a; + a.type = &m_Types[(size_t)rootchild.ops[0]]; + a.valID = rootchild.ops[1]; + + // ignore rest of properties, assert that if present they are 0 + for(size_t p = 2; p < rootchild.ops.size(); p++) + RDCASSERT(rootchild.ops[p] == 0, p, rootchild.ops[p]); + // symbols refer into any of N types in declaration order m_Symbols.push_back({SymbolType::Alias, m_Aliases.size()}); // all global symbols are 'values' in LLVM, we don't need this but need to keep indexing the // same Constant v; - v.type = &m_Types[(size_t)rootchild.ops[0]]; + v.type = a.type; v.symbol = true; m_Constants.push_back(v); @@ -800,25 +812,30 @@ Program::Program(const byte *bytes, size_t length) if(c.members.empty()) continue; - for(Constant &m : c.members) + for(size_t m = 0; m < c.members.size(); m++) { - if(m.type == NULL) + const Constant *mem = c.members[m]; + if(mem->type == NULL) { - if(m.val.u64v[0] > 0) + size_t idx = (size_t)mem->val.u64v[0]; + + delete mem; + + if(idx > 0) { - size_t idx = (size_t)m.val.u64v[0]; if(idx < m_Constants.size()) { - m = m_Constants[idx]; + c.members[m] = &m_Constants[idx]; } else { - m = Constant(); + c.members[m] = &m_Constants[0]; RDCERR("Couldn't resolve constant %zu", idx); } } else { + c.members[m] = &m_Constants[0]; RDCERR("Unexpected member with no type but no forward-index constant value"); } } @@ -1017,16 +1034,21 @@ Program::Program(const byte *bytes, size_t length) if(c.members.empty()) continue; - for(Constant &m : c.members) + for(size_t m = 0; m < c.members.size(); m++) { - if(m.type == NULL) + const Constant *mem = c.members[m]; + if(mem->type == NULL) { - if(m.val.u64v[0] > 0) + uint64_t idx = mem->val.u64v[0]; + delete mem; + + if(idx > 0) { - m = *getConstant(m.val.u64v[0]); + c.members[m] = getConstant(idx); } else { + c.members[m] = getConstant(0); RDCERR("Unexpected member with no type but no forward-index constant value"); } } diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 000a0b610..d0b22eb6b 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -355,14 +355,68 @@ inline Operation DecodeCast(uint64_t opcode) } } +inline uint64_t EncodeCast(Operation op) +{ + switch(op) + { + case Operation::Trunc: return 0; break; + case Operation::ZExt: return 1; break; + case Operation::SExt: return 2; break; + case Operation::FToU: return 3; break; + case Operation::FToS: return 4; break; + case Operation::UToF: return 5; break; + case Operation::SToF: return 6; break; + case Operation::FPTrunc: return 7; break; + case Operation::FPExt: return 8; break; + case Operation::PtrToI: return 9; break; + case Operation::IToPtr: return 10; break; + case Operation::Bitcast: return 11; break; + case Operation::AddrSpaceCast: return 12; break; + default: return ~0U; + } +} + struct Constant { + Constant() = default; + Constant &operator=(const Constant &o) = delete; + Constant(const Constant &o) + { + type = o.type; + val = o.val; + inner = o.inner; + str = o.str; + undef = o.undef; + nullconst = o.nullconst; + symbol = o.symbol; + data = o.data; + op = o.op; + if(data) + { + members.resize(o.members.size()); + for(size_t i = 0; i < members.size(); i++) + members[i] = new Constant(*o.members[i]); + } + else + { + members = o.members; + } + } + ~Constant() + { + // data constants own their members, they aren't pointers to other constants + if(data) + { + for(size_t i = 0; i < members.size(); i++) + delete members[i]; + } + } const Type *type = NULL; ShaderValue val = {}; - rdcarray members; + rdcarray members; const Constant *inner = NULL; rdcstr str; - bool undef = false, nullconst = false, symbol = false; + bool undef = false, nullconst = false, symbol = false, data = false; Operation op = Operation::NoOp; rdcstr toString(bool withType = false) const; diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp index 38d25d6ce..89c9a672d 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp @@ -24,6 +24,7 @@ #include "dxil_bytecode_editor.h" #include "driver/shaders/dxbc/dxbc_container.h" +#include "maths/half_convert.h" #include "dxil_bytecode.h" #include "llvm_encoder.h" @@ -51,18 +52,31 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const uint64_t maxAlign = 0; uint32_t maxGlobalType = 0; + auto getTypeID = [this](const Type *t) { return uint64_t(t - m_Types.begin()); }; + 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()); + uint32_t typeIndex = uint32_t(getTypeID(m_GlobalVars[i].type->inner)); 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); + size_t numGlobalConsts = 0; + + for(size_t i = m_GlobalVars.size() + m_Functions.size(); i < m_Symbols.size(); i++) + { + // stop once we pass constants + if(m_Symbols[i].type != SymbolType::Constant) + break; + + numGlobalConsts++; + } + + writer.ConfigureSizes(m_Types.size(), numGlobalConsts, m_Sections.size(), maxAlign, maxGlobalType); writer.BeginBlock(LLVMBC::KnownBlock::MODULE_BLOCK); @@ -206,18 +220,17 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const } else if(m_Types[i].type == Type::Vector) { - size_t innerTypeIndex = m_Types[i].inner - m_Types.begin(); - writer.Record(LLVMBC::TypeRecord::VECTOR, {m_Types[i].elemCount, innerTypeIndex}); + writer.Record(LLVMBC::TypeRecord::VECTOR, + {m_Types[i].elemCount, getTypeID(m_Types[i].inner)}); } else if(m_Types[i].type == Type::Array) { - size_t innerTypeIndex = m_Types[i].inner - m_Types.begin(); - writer.Record(LLVMBC::TypeRecord::ARRAY, {m_Types[i].elemCount, innerTypeIndex}); + writer.Record(LLVMBC::TypeRecord::ARRAY, {m_Types[i].elemCount, getTypeID(m_Types[i].inner)}); } else if(m_Types[i].type == Type::Pointer) { - size_t innerTypeIndex = m_Types[i].inner - m_Types.begin(); - writer.Record(LLVMBC::TypeRecord::POINTER, {innerTypeIndex, (uint64_t)m_Types[i].addrSpace}); + writer.Record(LLVMBC::TypeRecord::POINTER, + {getTypeID(m_Types[i].inner), (uint64_t)m_Types[i].addrSpace}); } else if(m_Types[i].type == Type::Struct) { @@ -240,7 +253,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const vals.push_back(m_Types[i].packedStruct ? 1 : 0); for(const Type *t : m_Types[i].members) - vals.push_back(t - m_Types.begin()); + vals.push_back(getTypeID(t)); writer.Record(type, vals); } @@ -251,10 +264,10 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const vals.push_back(m_Types[i].vararg ? 1 : 0); - vals.push_back(m_Types[i].inner - m_Types.begin()); + vals.push_back(getTypeID(m_Types[i].inner)); for(const Type *t : m_Types[i].members) - vals.push_back(t - m_Types.begin()); + vals.push_back(getTypeID(t)); writer.Record(LLVMBC::TypeRecord::FUNCTION, vals); } @@ -285,7 +298,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const 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 typeIndex = getTypeID(g.type->inner); uint64_t linkageValue = 0; @@ -334,7 +347,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const for(size_t i = 0; i < m_Functions.size(); i++) { const Function &f = m_Functions[i]; - size_t typeIndex = f.funcType - m_Types.begin(); + uint64_t typeIndex = getTypeID(f.funcType); writer.Record(LLVMBC::ModuleRecord::FUNCTION, { @@ -373,7 +386,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const for(size_t i = 0; i < m_Aliases.size(); i++) { const Alias &a = m_Aliases[i]; - size_t typeIndex = a.type - m_Types.begin(); + uint64_t typeIndex = getTypeID(a.type); writer.Record(LLVMBC::ModuleRecord::ALIAS, { typeIndex, a.valID, @@ -384,6 +397,120 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const }); } + // the symbols for constants start after the global variables and functions which we just + // outputted + { + bool inblock = false; + + const Type *curType = NULL; + + for(size_t i = m_GlobalVars.size() + m_Functions.size(); i < m_Symbols.size(); i++) + { + // stop once we pass constants + if(m_Symbols[i].type != SymbolType::Constant) + break; + + if(!inblock) + { + inblock = true; + writer.BeginBlock(LLVMBC::KnownBlock::CONSTANTS_BLOCK); + } + + const Constant &c = m_Constants[i]; + if(c.type != curType) + { + writer.Record(LLVMBC::ConstantsRecord::SETTYPE, getTypeID(c.type)); + curType = c.type; + } + + if(c.nullconst) + { + writer.Record(LLVMBC::ConstantsRecord::CONST_NULL); + } + else if(c.undef) + { + writer.Record(LLVMBC::ConstantsRecord::UNDEF); + } + else if(c.op == Operation::GetElementPtr) + { + rdcarray vals; + vals.reserve(c.members.size() * 2 + 1); + + // DXC's version of llvm always writes the explicit type here + vals.push_back(getTypeID(c.type)); + + for(size_t m = 0; m < c.members.size(); m++) + { + vals.push_back(getTypeID(c.members[m]->type)); + vals.push_back(c.members[m] - m_Constants.begin()); + } + + writer.Record(LLVMBC::ConstantsRecord::EVAL_GEP, vals); + } + else if(c.op != Operation::NoOp) + { + uint64_t cast = EncodeCast(c.op); + RDCASSERT(cast != ~0U); + + writer.Record(LLVMBC::ConstantsRecord::EVAL_CAST, + {EncodeCast(c.op), getTypeID(c.type), getTypeID(c.inner->type), + uint64_t(c.inner - m_Constants.begin())}); + } + else if(c.type->scalarType == Type::Int) + { + writer.Record(LLVMBC::ConstantsRecord::INTEGER, LLVMBC::BitWriter::svbr(c.val.s64v[0])); + } + else if(c.type->scalarType == Type::Float) + { + writer.Record(LLVMBC::ConstantsRecord::FLOAT, c.val.u64v[0]); + } + else if(!c.str.empty()) + { + if(c.str.indexOf('\0') < 0) + { + writer.Record(LLVMBC::ConstantsRecord::CSTRING, c.str); + } + else + { + writer.Record(LLVMBC::ConstantsRecord::STRING, c.str); + } + } + else if(c.data) + { + rdcarray vals; + vals.reserve(c.members.size()); + + if(c.type->type == Type::Vector) + { + for(uint32_t m = 0; m < c.type->elemCount; m++) + vals.push_back(c.type->bitWidth <= 32 ? c.val.u32v[m] : c.val.u64v[m]); + } + else + { + for(size_t m = 0; m < c.members.size(); m++) + vals.push_back(c.type->inner->bitWidth <= 32 ? c.members[m]->val.u32v[0] + : c.members[m]->val.u64v[0]); + } + + writer.Record(LLVMBC::ConstantsRecord::DATA, vals); + } + else if(c.type->type == Type::Vector || c.type->type == Type::Array || + c.type->type == Type::Struct) + { + rdcarray vals; + vals.reserve(c.members.size()); + + for(size_t m = 0; m < c.members.size(); m++) + vals.push_back(c.members[m] - m_Constants.begin()); + + writer.Record(LLVMBC::ConstantsRecord::AGGREGATE, vals); + } + } + + if(inblock) + writer.EndBlock(); + } + writer.EndBlock(); ProgramHeader header; diff --git a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp index c6028da37..cbe387776 100644 --- a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp @@ -1265,8 +1265,8 @@ void Program::MakeDisassemblyString() if(props && !props->nullconst) { - packedProps[0] = props->members[0].val.u32v[0]; - packedProps[1] = props->members[1].val.u32v[0]; + packedProps[0] = props->members[0]->val.u32v[0]; + packedProps[1] = props->members[1]->val.u32v[0]; } ComponentType compType = ComponentType(packedProps[0] & 0x1f); @@ -1742,14 +1742,14 @@ rdcstr Constant::toString(bool withType) const { ret += "getelementptr inbounds ("; - const Type *baseType = members[0].type; + const Type *baseType = members[0]->type; RDCASSERT(baseType->type == Type::Pointer); ret += baseType->inner->toString(); for(size_t i = 0; i < members.size(); i++) { ret += ", "; - ret += members[i].toString(withType); + ret += members[i]->toString(withType); } ret += ")"; break; @@ -1849,7 +1849,7 @@ rdcstr Constant::toString(bool withType) const if(i > 0) ret += ", "; - ret += members[i].toString(withType); + ret += members[i]->toString(withType); } ret += "]"; } @@ -1861,7 +1861,7 @@ rdcstr Constant::toString(bool withType) const if(i > 0) ret += ", "; - ret += members[i].toString(withType); + ret += members[i]->toString(withType); } ret += " }"; } diff --git a/renderdoc/driver/shaders/dxil/llvm_common.h b/renderdoc/driver/shaders/dxil/llvm_common.h index 8474230af..c5ce00fcd 100644 --- a/renderdoc/driver/shaders/dxil/llvm_common.h +++ b/renderdoc/driver/shaders/dxil/llvm_common.h @@ -95,7 +95,7 @@ enum class ModuleRecord : uint32_t SECTIONNAME = 5, GLOBALVAR = 7, FUNCTION = 8, - ALIAS = 14, + ALIAS = 9, }; enum class ConstantsRecord : uint32_t diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp index 7548bf277..a757c1b55 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.cpp +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.cpp @@ -57,8 +57,6 @@ static uint32_t GetBlockAbbrevSize(KnownBlock block) return ret; } -#define MagicFixedSizeNumTypes 99 - #define AbbFixed(n) \ { \ AbbrevEncoding::Fixed, n \ @@ -80,7 +78,11 @@ static uint32_t GetBlockAbbrevSize(KnownBlock block) AbbrevEncoding::Char6, 0 \ } +#define MagicFixedSizeNumTypes 99 +#define MagicFixedSizeNumConstants 999 + #define AbbFixedTypes() AbbFixed(MagicFixedSizeNumTypes) +#define AbbFixedConstants() AbbFixed(MagicFixedSizeNumConstants) using AbbrevDefinition = AbbrevParam[8]; @@ -119,6 +121,11 @@ enum class ConstantsAbbrev Integer, EvalCast, Null, + // the ones below are only used in the global constants block + Aggregate, + String, + CString7, + CString6, }; AbbrevDefinition ConstantsAbbrevDefs[] = { @@ -140,6 +147,25 @@ AbbrevDefinition ConstantsAbbrevDefs[] = { }, }; +AbbrevDefinition ConstantsGlobalAbbrevDefs[] = { + // Aggregate + { + AbbLiteral(ConstantsRecord::AGGREGATE), AbbArray(), AbbFixedConstants(), + }, + // String + { + AbbLiteral(ConstantsRecord::STRING), AbbArray(), AbbFixed(8), + }, + // CString7 + { + AbbLiteral(ConstantsRecord::CSTRING), AbbArray(), AbbFixed(7), + }, + // CString6 + { + AbbLiteral(ConstantsRecord::CSTRING), AbbArray(), AbbChar6(), + }, +}; + enum class FunctionAbbrev { Load, @@ -263,8 +289,6 @@ BitcodeWriter::BitcodeWriter(bytebuf &buf) : b(buf) curBlock = KnownBlock::Count; abbrevSize = 2; - numAbbrevs = 0; - m_GlobalVarAbbrev = ~0U; } @@ -294,16 +318,32 @@ void BitcodeWriter::BeginBlock(KnownBlock block) curBlock = block; abbrevSize = newAbbrevSize; - blockStack.push_back({block, offs, numAbbrevs}); + blockStack.push_back({block, offs}); + + curAbbrevs.swap(blockStack.back().abbrevs); // emit known abbrevs here that aren't in blockinfo switch(block) { - case KnownBlock::VALUE_SYMTAB_BLOCK: case KnownBlock::CONSTANTS_BLOCK: + case KnownBlock::VALUE_SYMTAB_BLOCK: case KnownBlock::FUNCTION_BLOCK: { - // these blocks have abbrevs but we shouldn't emit them as they're handled in blockinfo + // these blocks have abbrevs from the blockinfo. Don't write them, but add them to our abbrev + // dictionary + uint32_t numAbbrevDefs = GetNumAbbrevDefs(block); + AbbrevDefinition *abbrevs = GetAbbrevDefs(block); + for(uint32_t i = 0; i < numAbbrevDefs; i++) + curAbbrevs.push_back(abbrevs[i]); + + // the global constants block has some extra abbrevs + // blockStack[0] is always the module block + if(block == KnownBlock::CONSTANTS_BLOCK && blockStack.size() == 2) + { + for(size_t i = 0; i < ARRAY_COUNT(ConstantsGlobalAbbrevDefs); i++) + WriteAbbrevDefinition(ConstantsGlobalAbbrevDefs[i]); + } + break; } default: @@ -338,14 +378,14 @@ void BitcodeWriter::EndBlock() else { curBlock = blockStack.back().block; - numAbbrevs = blockStack.back().numAbbrevs; + curAbbrevs = blockStack.back().abbrevs; abbrevSize = GetBlockAbbrevSize(curBlock); } } void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev) { - numAbbrevs++; + curAbbrevs.push_back(abbrev); b.fixed(abbrevSize, DEFINE_ABBREV); @@ -361,6 +401,8 @@ void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev) if(param.value == MagicFixedSizeNumTypes) param.value = m_NumTypeBits; + if(param.value == MagicFixedSizeNumConstants) + param.value = m_NumConstantBits; const bool lit = param.encoding == AbbrevEncoding::Literal; b.fixed(1, lit); @@ -377,10 +419,11 @@ void BitcodeWriter::WriteAbbrevDefinition(AbbrevParam *abbrev) } } -void BitcodeWriter::ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign, - uint32_t maxGlobalType) +void BitcodeWriter::ConfigureSizes(size_t numTypes, size_t numGlobalConsts, size_t numSections, + uint64_t maxAlign, uint32_t maxGlobalType) { m_NumTypeBits = 32 - Bits::CountLeadingZeroes((uint32_t)numTypes); + m_NumConstantBits = 32 - Bits::CountLeadingZeroes((uint32_t)numGlobalConsts); m_GlobalTypeBits = 32 - Bits::CountLeadingZeroes(maxGlobalType); @@ -410,7 +453,7 @@ void BitcodeWriter::ModuleBlockInfo() for(KnownBlock block : {KnownBlock::VALUE_SYMTAB_BLOCK, KnownBlock::CONSTANTS_BLOCK, KnownBlock::FUNCTION_BLOCK}) { - Unabbrev((uint32_t)BlockInfoRecord::SETBID, (uint32_t)block); + Unabbrev((uint32_t)BlockInfoRecord::SETBID, true, (uint32_t)block); AbbrevDefinition *abbrevs = GetAbbrevDefs(block); uint32_t numAbbrevDefs = GetNumAbbrevDefs(block); @@ -423,7 +466,7 @@ void BitcodeWriter::ModuleBlockInfo() void BitcodeWriter::EmitGlobalVarAbbrev() { - m_GlobalVarAbbrev = numAbbrevs; + m_GlobalVarAbbrev = (uint32_t)curAbbrevs.size(); AbbrevParam align = AbbFixed(m_AlignBits); if(m_AlignBits == 0) @@ -447,21 +490,13 @@ void BitcodeWriter::EmitGlobalVarAbbrev() uint32_t BitcodeWriter::GetAbbrevID(uint32_t id) { // the id is a block-local index, starting from 0, of the abbrevs defined for that block. - - // when we begin a block, we store the number of previously defined abbrevs from earlier blocks so - // we add that on - id += blockStack.back().numAbbrevs; - // the ID we need to encode starts at APPLICATION_ABBREV for the first one, so add that return APPLICATION_ABBREV + id; } void BitcodeWriter::AutoRecord(uint32_t record, bool param, uint64_t val) { - AbbrevDefinition *abbrevs = GetAbbrevDefs(curBlock); - uint32_t numAbbrevDefs = GetNumAbbrevDefs(curBlock); - - uint32_t idx = numAbbrevDefs; + uint32_t idx = ~0U; // the records with abbrevs are hardcoded, so just determine if this record in this block has an // abbrev and select it here @@ -477,6 +512,33 @@ void BitcodeWriter::AutoRecord(uint32_t record, bool param, uint64_t val) default: break; } break; + case KnownBlock::CONSTANTS_BLOCK: + { + // blockStack[0] is always the module block + const bool globalConsts = blockStack.size() == 2; + switch(ConstantsRecord(record)) + { + // global only abbrevs + case ConstantsRecord::AGGREGATE: + if(globalConsts) + idx = (uint32_t)ConstantsAbbrev::Aggregate; + break; + case ConstantsRecord::STRING: + if(globalConsts) + idx = (uint32_t)ConstantsAbbrev::String; + break; + // these abbrevs are available in all constants blocks + case ConstantsRecord::SETTYPE: idx = (uint32_t)ConstantsAbbrev::SetType; break; + case ConstantsRecord::INTEGER: idx = (uint32_t)ConstantsAbbrev::Integer; break; + case ConstantsRecord::EVAL_CAST: + idx = (uint32_t)ConstantsAbbrev::EvalCast; + break; + // LLVM doesn't seem to use this abbrev? + // case ConstantsRecord::CONST_NULL: idx = (uint32_t)ConstantsAbbrev::Null; break; + default: break; + } + break; + } case KnownBlock::TYPE_BLOCK: switch(TypeRecord(record)) { @@ -493,17 +555,21 @@ void BitcodeWriter::AutoRecord(uint32_t record, bool param, uint64_t val) } // if we got a valid abbrev, use it, otherwise emit unabbrev - if(idx < numAbbrevDefs) - Abbrev(abbrevs[idx], GetAbbrevID(record), val); + if(idx < curAbbrevs.size()) + { + // write the abbrev ID + b.fixed(abbrevSize, GetAbbrevID(idx)); + + Abbrev(curAbbrevs[idx], record, val); + } else + { Unabbrev(record, param, val); + } } void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray &vals) { - AbbrevDefinition *abbrevs = GetAbbrevDefs(curBlock); - uint32_t numAbbrevDefs = GetNumAbbrevDefs(curBlock); - uint32_t idx = ~0U; // the records with abbrevs are hardcoded, so just determine if this record in this block has an @@ -528,6 +594,48 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray &vals) default: break; } break; + case KnownBlock::CONSTANTS_BLOCK: + { + // blockStack[0] is always the module block + const bool globalConsts = blockStack.size() == 2; + switch(ConstantsRecord(record)) + { + // global only abbrevs + case ConstantsRecord::AGGREGATE: + if(globalConsts) + idx = (uint32_t)ConstantsAbbrev::Aggregate; + break; + case ConstantsRecord::STRING: + if(globalConsts) + idx = (uint32_t)ConstantsAbbrev::String; + break; + case ConstantsRecord::CSTRING: + if(globalConsts) + { + bool c6 = true, c7 = true; + for(size_t i = 0; (c6 || c7) && i < vals.size(); i++) + { + if(!isChar6(char(vals[i]))) + c6 = false; + if(vals[i] >= 128) + c7 = false; + } + + if(c6) + idx = (uint32_t)ConstantsAbbrev::CString6; + else if(c7) + idx = (uint32_t)ConstantsAbbrev::CString7; + } + break; + // these abbrevs are available in all constants blocks + case ConstantsRecord::SETTYPE: idx = (uint32_t)ConstantsAbbrev::SetType; break; + case ConstantsRecord::INTEGER: idx = (uint32_t)ConstantsAbbrev::Integer; break; + case ConstantsRecord::EVAL_CAST: idx = (uint32_t)ConstantsAbbrev::EvalCast; break; + case ConstantsRecord::CONST_NULL: idx = (uint32_t)ConstantsAbbrev::Null; break; + default: break; + } + break; + } case KnownBlock::TYPE_BLOCK: switch(TypeRecord(record)) { @@ -560,23 +668,16 @@ void BitcodeWriter::AutoRecord(uint32_t record, const rdcarray &vals) } // if we got a valid abbrev, use it, otherwise emit unabbrev - 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) + if(idx < curAbbrevs.size()) { // write the abbrev ID b.fixed(abbrevSize, GetAbbrevID(idx)); - Abbrev(abbrevs[idx], record, vals); + Abbrev(curAbbrevs[idx], record, vals); } else { - Unabbrev(record, vals); + Unabbrev(record, false, vals); } } @@ -634,9 +735,16 @@ void BitcodeWriter::WriteAbbrevParam(const AbbrevParam &abbrev, uint64_t val) return; if(abbrev.encoding == AbbrevEncoding::Fixed) - b.fixed(abbrev.value == MagicFixedSizeNumTypes ? m_NumTypeBits : abbrev.value, val); + { + uint64_t width = abbrev.value; + if(abbrev.value == MagicFixedSizeNumTypes) + width = m_NumTypeBits; + else if(abbrev.value == MagicFixedSizeNumConstants) + width = m_NumConstantBits; + b.fixed((size_t)width, val); + } else if(abbrev.encoding == AbbrevEncoding::VBR) - b.vbr(abbrev.value, val); + b.vbr((size_t)abbrev.value, val); else if(abbrev.encoding == AbbrevEncoding::Char6) b.c6(char(val)); else @@ -652,7 +760,7 @@ void BitcodeWriter::Unabbrev(uint32_t record, bool param, uint64_t val) b.vbr(6, val); } -void BitcodeWriter::Unabbrev(uint32_t record, const rdcarray &vals) +void BitcodeWriter::Unabbrev(uint32_t record, bool, const rdcarray &vals) { b.fixed(abbrevSize, UNABBREV_RECORD); b.vbr(6, record); diff --git a/renderdoc/driver/shaders/dxil/llvm_encoder.h b/renderdoc/driver/shaders/dxil/llvm_encoder.h index e56dcb0f3..070a0aa7d 100644 --- a/renderdoc/driver/shaders/dxil/llvm_encoder.h +++ b/renderdoc/driver/shaders/dxil/llvm_encoder.h @@ -37,7 +37,8 @@ public: BitcodeWriter(bytebuf &buf); ~BitcodeWriter(); - void ConfigureSizes(size_t numTypes, size_t numSections, uint64_t maxAlign, uint32_t maxGlobalType); + void ConfigureSizes(size_t numTypes, size_t numGlobalConsts, size_t numSections, + uint64_t maxAlign, uint32_t maxGlobalType); void BeginBlock(KnownBlock block); void EndBlock(); @@ -77,7 +78,7 @@ private: void WriteAbbrevDefinition(AbbrevParam *abbrev); void Unabbrev(uint32_t record, bool param, uint64_t val); - void Unabbrev(uint32_t record, const rdcarray &vals); + void Unabbrev(uint32_t record, bool, const rdcarray &vals); void Abbrev(AbbrevParam *abbrev, uint32_t record, uint64_t val); void Abbrev(AbbrevParam *abbrev, uint32_t record, const rdcarray &vals); @@ -89,12 +90,13 @@ private: BitWriter b; uint32_t m_NumTypeBits; + uint32_t m_NumConstantBits; uint32_t m_GlobalTypeBits; uint32_t m_NumSectionBits; uint32_t m_AlignBits; size_t abbrevSize; - uint32_t numAbbrevs; + rdcarray curAbbrevs; KnownBlock curBlock; uint32_t m_GlobalVarAbbrev; @@ -104,7 +106,7 @@ private: { KnownBlock block; size_t offset; - uint32_t numAbbrevs; + rdcarray abbrevs; }; rdcarray blockStack;