mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-23 23:16:31 +00:00
Handle attribute sets with per-function-parameter attributes in DXIL
* This also fixes the string (not enum) attribute decoding
This commit is contained in:
@@ -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<size_t>();
|
||||
if(attr > 0)
|
||||
inst.paramAttrs = &m_Attributes[attr - 1];
|
||||
inst.paramAttrs = &m_AttributeSets[attr - 1];
|
||||
|
||||
uint64_t callingFlags = op.get<uint64_t>();
|
||||
|
||||
|
||||
@@ -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<Instruction> &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<uint64_t> groups;
|
||||
uint32_t slotIndex = InvalidSlot;
|
||||
|
||||
Attribute params = Attribute::None;
|
||||
uint64_t align = 0, stackAlign = 0, derefBytes = 0, derefOrNullBytes = 0;
|
||||
rdcarray<rdcpair<rdcstr, rdcstr>> strs;
|
||||
|
||||
rdcstr toString() const;
|
||||
rdcstr toString(bool stringAttrs) const;
|
||||
};
|
||||
|
||||
struct AttributeSet
|
||||
{
|
||||
const AttributeGroup *functionSlot = NULL;
|
||||
rdcarray<const AttributeGroup *> groupSlots;
|
||||
|
||||
rdcarray<uint64_t> 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<Attributes> m_AttributeGroups;
|
||||
rdcarray<Attributes> m_Attributes;
|
||||
rdcarray<AttributeGroup> m_AttributeGroups;
|
||||
rdcarray<AttributeSet> m_AttributeSets;
|
||||
|
||||
rdcarray<Constant> m_Constants;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -522,11 +522,23 @@ void Program::MakeDisassemblyString()
|
||||
namedMeta += "}\n";
|
||||
}
|
||||
|
||||
rdcarray<const AttributeGroup *> 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<Instruction> &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<rdcstr, rdcstr> &str : strs)
|
||||
ret += " " + escapeString(str.first) + "=" + escapeString(str.second);
|
||||
if(stringAttrs)
|
||||
{
|
||||
ret.trim();
|
||||
|
||||
for(const rdcpair<rdcstr, rdcstr> &str : strs)
|
||||
{
|
||||
if(str.second.empty())
|
||||
ret += " " + escapeString(str.first);
|
||||
else
|
||||
ret += " " + escapeString(str.first) + "=" + escapeString(str.second);
|
||||
}
|
||||
}
|
||||
|
||||
return ret.trimmed();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user