From fccaee058ee79dc1221193837f191087ddc19379 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 8 Sep 2021 18:28:43 +0100 Subject: [PATCH] Handle attribute sets with per-function-parameter attributes in DXIL * This also fixes the string (not enum) attribute decoding --- .../driver/shaders/dxil/dxil_bytecode.cpp | 55 ++++++---- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 37 +++++-- .../shaders/dxil/dxil_bytecode_editor.cpp | 16 +-- .../driver/shaders/dxil/dxil_disassemble.cpp | 101 ++++++++++++++---- 4 files changed, 152 insertions(+), 57 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp index 8b7829b97..b6a45d416 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp @@ -463,8 +463,8 @@ Program::Program(const byte *bytes, size_t length) f.external = (rootchild.ops[2] != 0); // ignore linkage RDCASSERTMSG("Linkage is non-default", rootchild.ops[3] == 0); - if(rootchild.ops[4] > 0 && rootchild.ops[4] - 1 < m_Attributes.size()) - f.attrs = &m_Attributes[(size_t)rootchild.ops[4] - 1]; + if(rootchild.ops[4] > 0 && rootchild.ops[4] - 1 < m_AttributeSets.size()) + f.attrs = &m_AttributeSets[(size_t)rootchild.ops[4] - 1]; f.align = rootchild.ops[5]; @@ -531,11 +531,10 @@ Program::Program(const byte *bytes, size_t length) continue; } - Attributes group; + AttributeGroup group; size_t id = (size_t)attrgroup.ops[0]; - group.index = attrgroup.ops[1]; - group.valid = true; + group.slotIndex = (uint32_t)attrgroup.ops[1]; for(size_t i = 2; i < attrgroup.ops.size(); i++) { @@ -565,8 +564,22 @@ Program::Program(const byte *bytes, size_t length) } default: { - rdcstr a = attrgroup.getString(i + 1); - rdcstr b = attrgroup.getString(i + 1 + a.size() + 1); + rdcstr a, b; + + a = attrgroup.getString(i + 1); + a.resize(strlen(a.c_str())); + + if(attrgroup.ops[i] == 4) + { + b = attrgroup.getString(i + 1 + a.size() + 1); + b.resize(strlen(b.c_str())); + i += a.size() + b.size() + 2; + } + else + { + i += a.size() + 1; + } + group.strs.push_back({a, b}); break; } @@ -593,21 +606,25 @@ Program::Program(const byte *bytes, size_t length) continue; } - Attributes attrs; - attrs.index = m_Attributes.size(); - attrs.groups = paramattr.ops; + AttributeSet attrs; + + attrs.orderedGroups = paramattr.ops; for(uint64_t g : paramattr.ops) { if(g < m_AttributeGroups.size()) { - Attributes &other = m_AttributeGroups[(size_t)g]; - attrs.params |= other.params; - attrs.align = RDCMAX(attrs.align, other.align); - attrs.stackAlign = RDCMAX(attrs.stackAlign, other.stackAlign); - attrs.derefBytes = RDCMAX(attrs.derefBytes, other.derefBytes); - attrs.derefOrNullBytes = RDCMAX(attrs.derefOrNullBytes, other.derefOrNullBytes); - attrs.strs.append(other.strs); + const AttributeGroup &group = m_AttributeGroups[(size_t)g]; + if(group.slotIndex == AttributeGroup::FunctionSlot) + { + RDCASSERT(attrs.functionSlot == NULL); + attrs.functionSlot = &group; + } + else + { + attrs.groupSlots.resize_for_index(group.slotIndex); + attrs.groupSlots[group.slotIndex] = &m_AttributeGroups[(size_t)g]; + } } else { @@ -615,7 +632,7 @@ Program::Program(const byte *bytes, size_t length) } } - m_Attributes.push_back(attrs); + m_AttributeSets.push_back(attrs); } } else if(IS_KNOWN(rootchild.id, KnownBlock::TYPE_BLOCK)) @@ -1315,7 +1332,7 @@ Program::Program(const byte *bytes, size_t length) inst.op = Operation::Call; size_t attr = op.get(); if(attr > 0) - inst.paramAttrs = &m_Attributes[attr - 1]; + inst.paramAttrs = &m_AttributeSets[attr - 1]; uint64_t callingFlags = op.get(); diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 9c18dd9c6..c563d333a 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -49,6 +49,9 @@ struct ProgramHeader uint32_t BitcodeSize; // Size of LLVM bitcode. }; +struct Instruction; +struct AttributeSet; + struct Type { enum TypeKind @@ -85,7 +88,8 @@ struct Type bool isVoid() const { return type == Scalar && scalarType == Void; } rdcstr toString() const; - rdcstr declFunction(rdcstr funcName) const; + rdcstr declFunction(rdcstr funcName, const rdcarray &args, + const AttributeSet *attrs) const; // for scalars, arrays, vectors, pointers union @@ -261,18 +265,31 @@ enum class Attribute : uint64_t BITMASK_OPERATORS(Attribute); -struct Attributes +struct AttributeGroup { - bool valid = false; - uint64_t index = 0; + enum Slot : uint64_t + { + InvalidSlot = ~0U - 1, + FunctionSlot = ~0U, + ReturnSlot = 0U, + Param1Slot = 1U, + }; - rdcarray groups; + uint32_t slotIndex = InvalidSlot; Attribute params = Attribute::None; uint64_t align = 0, stackAlign = 0, derefBytes = 0, derefOrNullBytes = 0; rdcarray> strs; - rdcstr toString() const; + rdcstr toString(bool stringAttrs) const; +}; + +struct AttributeSet +{ + const AttributeGroup *functionSlot = NULL; + rdcarray groupSlots; + + rdcarray orderedGroups; }; enum class Operation : uint8_t @@ -568,7 +585,7 @@ struct Instruction AttachedMetadata attachedMeta; // function calls - const Attributes *paramAttrs = NULL; + const AttributeSet *paramAttrs = NULL; const Function *funcCall = NULL; }; @@ -592,7 +609,7 @@ struct Function const Type *funcType = NULL; bool external = false; - const Attributes *attrs = NULL; + const AttributeSet *attrs = NULL; uint64_t align = 0; @@ -686,8 +703,8 @@ protected: const Type *m_VoidType = NULL; const Type *m_BoolType = NULL; - rdcarray m_AttributeGroups; - rdcarray m_Attributes; + rdcarray m_AttributeGroups; + rdcarray m_AttributeSets; rdcarray m_Constants; diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp index a8dd6c880..65c5facd2 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode_editor.cpp @@ -41,7 +41,7 @@ DXIL::ProgramEditor::~ProgramEditor() DXBC::DXBCContainer::ReplaceDXILBytecode(m_OutBlob, EncodeProgram()); } -#define getAttribID(a) uint64_t(a - m_Attributes.begin()) +#define getAttribID(a) uint64_t(a - m_AttributeSets.begin()) #define getTypeID(t) uint64_t(t - m_Types.begin()) #define getMetaID(m) uint64_t(m - m_Metadata.begin()) #define getMetaIDOrNull(m) (m ? (getMetaID(m) + 1) : 0ULL) @@ -122,13 +122,13 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const for(size_t i = 0; i < m_AttributeGroups.size(); i++) { - if(m_AttributeGroups[i].valid) + if(m_AttributeGroups[i].slotIndex != AttributeGroup::InvalidSlot) { - const Attributes &group = m_AttributeGroups[i]; + const AttributeGroup &group = m_AttributeGroups[i]; vals.clear(); vals.push_back(i); - vals.push_back(group.index); + vals.push_back(group.slotIndex); // decompose params bitfield into bits if(group.params != Attribute::None) @@ -204,12 +204,12 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const writer.EndBlock(); } - if(!m_Attributes.empty()) + if(!m_AttributeSets.empty()) { writer.BeginBlock(LLVMBC::KnownBlock::PARAMATTR_BLOCK); - for(size_t i = 0; i < m_Attributes.size(); i++) - writer.Record(LLVMBC::ParamAttrRecord::ENTRY, m_Attributes[i].groups); + for(size_t i = 0; i < m_AttributeSets.size(); i++) + writer.Record(LLVMBC::ParamAttrRecord::ENTRY, m_AttributeSets[i].orderedGroups); writer.EndBlock(); } @@ -387,7 +387,7 @@ bytebuf DXIL::ProgramEditor::EncodeProgram() const // linkage 0U, // attributes - uint64_t(f.attrs ? 1U + (f.attrs - m_Attributes.begin()) : 0U), + uint64_t(f.attrs ? 1U + getAttribID(f.attrs) : 0U), // alignment f.align, // section diff --git a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp index 86691f79c..b5df0d860 100644 --- a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp @@ -522,11 +522,23 @@ void Program::MakeDisassemblyString() namedMeta += "}\n"; } + rdcarray funcAttrGroups; + for(size_t i = 0; i < m_AttributeGroups.size(); i++) + { + if(m_AttributeGroups[i].slotIndex != AttributeGroup::FunctionSlot) + continue; + + if(funcAttrGroups.contains(&m_AttributeGroups[i])) + continue; + + funcAttrGroups.push_back(&m_AttributeGroups[i]); + } + for(size_t i = 0; i < m_Functions.size(); i++) { Function &func = m_Functions[i]; - auto argToString = [this, &func](Value v, bool withTypes) { + auto argToString = [this, &func](Value v, bool withTypes, const rdcstr &attrString = "") { rdcstr ret; switch(v.type) { @@ -535,11 +547,13 @@ void Program::MakeDisassemblyString() case ValueType::Literal: if(withTypes) ret += "i32 "; + ret += attrString; ret += StringFormat::Fmt("%llu", v.literal); break; case ValueType::Metadata: if(withTypes) ret += "metadata "; + ret += attrString; if(m_Metadata.begin() <= v.meta && v.meta < m_Metadata.end()) { const Metadata &m = *v.meta; @@ -567,17 +581,25 @@ void Program::MakeDisassemblyString() ret += v.meta->refString(); } break; - case ValueType::Function: ret = "@" + escapeStringIfNeeded(v.function->name); break; + case ValueType::Function: + ret += attrString; + ret = "@" + escapeStringIfNeeded(v.function->name); + break; case ValueType::GlobalVar: if(withTypes) ret = v.global->type->toString() + " "; + ret += attrString; ret += "@" + escapeStringIfNeeded(v.global->name); break; - case ValueType::Constant: ret = v.constant->toString(withTypes); break; + case ValueType::Constant: + ret += attrString; + ret = v.constant->toString(withTypes); + break; case ValueType::Instruction: { if(withTypes) ret = v.instruction->type->toString() + " "; + ret += attrString; if(v.instruction->name.empty()) ret += StringFormat::Fmt("%%%u", v.instruction->resultID); else @@ -588,6 +610,7 @@ void Program::MakeDisassemblyString() { if(withTypes) ret = "label "; + ret += attrString; if(v.block->name.empty()) ret += StringFormat::Fmt("%%%u", v.block->resultID); else @@ -597,17 +620,19 @@ void Program::MakeDisassemblyString() return ret; }; - if(func.attrs) + if(func.attrs && func.attrs->functionSlot) { - m_Disassembly += StringFormat::Fmt("; Function Attrs: %s\n", func.attrs->toString().c_str()); + m_Disassembly += StringFormat::Fmt("; Function Attrs: %s\n", + func.attrs->functionSlot->toString(false).c_str()); instructionLine++; } m_Disassembly += (func.external ? "declare " : "define "); - m_Disassembly += func.funcType->inner->declFunction("@" + escapeStringIfNeeded(func.name)); + m_Disassembly += func.funcType->inner->declFunction("@" + escapeStringIfNeeded(func.name), + func.args, func.attrs); - if(func.attrs) - m_Disassembly += StringFormat::Fmt(" #%u", func.attrs->index); + if(func.attrs && func.attrs->functionSlot) + m_Disassembly += StringFormat::Fmt(" #%u", funcAttrGroups.indexOf(func.attrs->functionSlot)); if(!func.external) { @@ -646,18 +671,33 @@ void Program::MakeDisassemblyString() m_Disassembly += " @" + escapeStringIfNeeded(inst.funcCall->name); m_Disassembly += "("; bool first = true; + + // attribute args start from 1 + size_t argIdx = 1; for(Value &s : inst.args) { if(!first) m_Disassembly += ", "; first = false; - m_Disassembly += argToString(s, true); + // see if we have param attrs for this param + rdcstr attrString; + if(inst.paramAttrs && argIdx < inst.paramAttrs->groupSlots.size() && + inst.paramAttrs->groupSlots[argIdx]) + { + attrString = inst.paramAttrs->groupSlots[argIdx]->toString(true) + " "; + } + + m_Disassembly += argToString(s, true, attrString); + + argIdx++; } m_Disassembly += ")"; debugCall = inst.funcCall->name.beginsWith("llvm.dbg."); - if(inst.paramAttrs) - m_Disassembly += StringFormat::Fmt(" #%u", inst.paramAttrs - m_Attributes.begin()); + + if(inst.paramAttrs && inst.paramAttrs->functionSlot) + m_Disassembly += + StringFormat::Fmt(" #%u", funcAttrGroups.indexOf(inst.paramAttrs->functionSlot)); break; } case Operation::Trunc: @@ -1415,11 +1455,13 @@ void Program::MakeDisassemblyString() } } - for(size_t i = 0; i < m_Attributes.size(); i++) - m_Disassembly += - StringFormat::Fmt("attributes #%zu = { %s }\n", i, m_Attributes[i].toString().c_str()); + for(size_t i = 0; i < funcAttrGroups.size(); i++) + { + m_Disassembly += StringFormat::Fmt("attributes #%zu = { %s }\n", i, + funcAttrGroups[i]->toString(true).c_str()); + } - if(!m_Attributes.empty()) + if(!funcAttrGroups.empty()) m_Disassembly += "\n"; m_Disassembly += namedMeta + "\n"; @@ -1491,7 +1533,7 @@ rdcstr Type::toString() const else return StringFormat::Fmt("%s addrspace(%d)*", inner->toString().c_str(), addrSpace); case Array: return StringFormat::Fmt("[%u x %s]", elemCount, inner->toString().c_str()); - case Function: return declFunction(rdcstr()); + case Function: return declFunction(rdcstr(), {}, NULL); case Struct: { rdcstr ret; @@ -1518,7 +1560,8 @@ rdcstr Type::toString() const } } -rdcstr Type::declFunction(rdcstr funcName) const +rdcstr Type::declFunction(rdcstr funcName, const rdcarray &args, + const AttributeSet *attrs) const { rdcstr ret = inner->toString(); ret += " " + funcName + "("; @@ -1527,12 +1570,20 @@ rdcstr Type::declFunction(rdcstr funcName) const if(i > 0) ret += ", "; ret += members[i]->toString(); + + if(attrs && i + 1 < attrs->groupSlots.size() && attrs->groupSlots[i + 1]) + { + ret += " " + attrs->groupSlots[i + 1]->toString(true); + } + + if(i < args.size() && !args[i].name.empty()) + ret += " %" + escapeStringIfNeeded(args[i].name); } ret += ")"; return ret; } -rdcstr Attributes::toString() const +rdcstr AttributeGroup::toString(bool stringAttrs) const { rdcstr ret = ""; Attribute p = params; @@ -1569,8 +1620,18 @@ rdcstr Attributes::toString() const } } - for(const rdcpair &str : strs) - ret += " " + escapeString(str.first) + "=" + escapeString(str.second); + if(stringAttrs) + { + ret.trim(); + + for(const rdcpair &str : strs) + { + if(str.second.empty()) + ret += " " + escapeString(str.first); + else + ret += " " + escapeString(str.first) + "=" + escapeString(str.second); + } + } return ret.trimmed(); }