DXIL Disassembly: Include GlobalVar in SSA Id generation

During SettleIDs() check that all instruction arguments that require an SSA Id have one set

Moved DXILDebug::Id, INVALID_ID, DXIL::GetSSAId() out of DXIL Debugger
This commit is contained in:
Jake Turner
2024-09-20 11:09:05 +01:00
parent d46b29a916
commit 9b1332077a
4 changed files with 44 additions and 21 deletions
@@ -45,6 +45,8 @@ namespace DXILDebug
{
class Debugger;
struct ThreadState;
const uint32_t INVALID_ID = ~0U;
typedef uint32_t Id;
};
namespace DXIL
@@ -1283,7 +1285,7 @@ struct Instruction : public ForwardReferencableValue<Instruction>
// For DXC Compatibility mode: slot contains a number assigned to instructions that don't have
// names and return a value, used for disassembly
// Otherwise a unique global ID used by the debugger and disassemvbly
// Otherwise a unique global ID used by the debugger and disassembly
uint32_t slot = ~0U;
InstructionFlags &opFlags() { return (InstructionFlags &)flags; }
InstructionFlags opFlags() const { return (InstructionFlags)flags; }
@@ -1724,6 +1726,7 @@ bool getival(const Value *v, T &out)
}
bool IsSSA(const Value *dxilValue);
DXILDebug::Id GetSSAId(const DXIL::Value *value);
bool IsDXCNop(const Instruction &inst);
bool IsLLVMDebugCall(const Instruction &inst);
+12 -17
View File
@@ -31,17 +31,6 @@
using namespace DXIL;
using namespace DXDebug;
const uint32_t DXIL_INVALID_ID = ~0U;
DXILDebug::Id GetSSAId(DXIL::Value *value)
{
if(const Instruction *inst = cast<Instruction>(value))
return inst->slot;
RDCERR("Unhandled DXIL::Value type");
return DXIL_INVALID_ID;
}
static bool OperationFlushing(const Operation op, DXOp dxOpCode)
{
if(dxOpCode != DXOp::NumOpCodes)
@@ -1283,7 +1272,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
}
else
{
resultId = DXIL_INVALID_ID;
resultId = DXILDebug::INVALID_ID;
result.name.clear();
}
break;
@@ -2379,14 +2368,14 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
const StackAllocPointer &ptr = itPtr->second;
Id baseMemoryId = ptr.baseMemoryId;
RDCASSERT(ptr.backingMemory);
RDCASSERTNOTEQUAL(baseMemoryId, DXIL_INVALID_ID);
RDCASSERTNOTEQUAL(baseMemoryId, DXILDebug::INVALID_ID);
auto itAlloc = m_StackAllocs.find(baseMemoryId);
RDCASSERT(itAlloc != m_StackAllocs.end());
StackAlloc &alloc = itAlloc->second;
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, arg));
RDCASSERTEQUAL(resultId, DXIL_INVALID_ID);
RDCASSERTEQUAL(resultId, DXILDebug::INVALID_ID);
// Memory copy from value to backing memory
VarType type = ConvertDXILTypeToVarType(inst.args[1]->type);
@@ -2895,8 +2884,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
}
// Update the result variable after the dormant variables have been brought back
RDCASSERT(!(result.name.empty() ^ (resultId == DXIL_INVALID_ID)));
if(!result.name.empty() && resultId != DXIL_INVALID_ID)
RDCASSERT(!(result.name.empty() ^ (resultId == DXILDebug::INVALID_ID)));
if(!result.name.empty() && resultId != DXILDebug::INVALID_ID)
{
if(recordChange)
SetResult(resultId, result, opCode, dxOpCode, eventFlags);
@@ -4639,7 +4628,7 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
const uint32_t maxInst = i + 1;
{
Id resultId = inst.slot;
if(resultId != DXIL_INVALID_ID)
if(resultId != DXILDebug::INVALID_ID)
{
// The result SSA should not have been referenced before
RDCASSERTEQUAL(ssaRefs.count(resultId), 0);
@@ -4670,6 +4659,12 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
if(DXIL::IsSSA(arg))
{
Id argId = GetSSAId(arg);
// Add GlobalVar args to the SSA refs (they won't be the result of an instruction)
if(cast<GlobalVar>(arg))
{
if(ssaRefs.count(argId) == 0)
ssaRefs.insert(argId);
}
if(!isPhiNode)
{
// For non phi-nodes the argument SSA should already exist as the result of a previous operation
@@ -43,7 +43,6 @@ typedef DXDebug::GatherChannel GatherChannel;
typedef DXBCBytecode::SamplerMode SamplerMode;
typedef DXBC::InterpolationMode InterpolationMode;
typedef uint32_t Id;
class Debugger;
struct GlobalState;
@@ -110,14 +110,14 @@ bool DXIL::IsSSA(const Value *dxilValue)
{
if(const Instruction *inst = cast<Instruction>(dxilValue))
return true;
if(const GlobalVar *gv = cast<GlobalVar>(dxilValue))
return true;
if(const Constant *c = cast<Constant>(dxilValue))
return false;
if(const Literal *lit = cast<Literal>(dxilValue))
return false;
if(const Block *block = cast<Block>(dxilValue))
return false;
if(const GlobalVar *gv = cast<GlobalVar>(dxilValue))
return false;
if(const Function *func = cast<Function>(dxilValue))
return false;
if(const Metadata *meta = cast<Metadata>(dxilValue))
@@ -127,6 +127,17 @@ bool DXIL::IsSSA(const Value *dxilValue)
return false;
}
DXILDebug::Id DXIL::GetSSAId(const DXIL::Value *value)
{
if(const Instruction *inst = cast<Instruction>(value))
return inst->slot;
if(const GlobalVar *gv = cast<GlobalVar>(value))
return gv->ssaId;
RDCERR("Unhandled DXIL::Value type");
return DXILDebug::INVALID_ID;
}
static const char *shaderNames[] = {
"Pixel", "Vertex", "Geometry", "Hull", "Domain",
"Compute", "Library", "RayGeneration", "Intersection", "AnyHit",
@@ -1060,6 +1071,13 @@ void Program::SettleIDs()
AssignMetaSlot(m_MetaSlots, m_NextMetaSlot, m.children[c]);
}
}
// assign SSA ID for global variables
for(GlobalVar *g : m_GlobalVars)
{
if(g->ssaId == ~0U)
g->ssaId = m_NextSSAId++;
}
rdcarray<Metadata *> &metaSlots = m_MetaSlots;
uint32_t &nextMetaSlot = m_NextMetaSlot;
for(size_t i = 0; i < m_Functions.size(); i++)
@@ -1093,6 +1111,14 @@ void Program::SettleIDs()
inst->slot = slot++;
#endif
}
#if DISABLED(DXC_COMPATIBLE_DISASM)
// Check all arguments have valid SSA IDs
for(const Value *arg : inst->args)
{
if(IsSSA(arg))
RDCASSERTNOTEQUAL(GetSSAId(arg), ~0U);
}
#endif
if(inst->op == Operation::Call)
{
Function *callFunc = (Function *)inst->getFuncCall();