mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Add handling for branching and phi nodes
This commit is contained in:
@@ -855,6 +855,7 @@ Program::Program(const byte *bytes, size_t length)
|
||||
case SymbolType::Instruction:
|
||||
case SymbolType::Metadata:
|
||||
case SymbolType::Literal:
|
||||
case SymbolType::BasicBlock:
|
||||
RDCERR("Unexpected global symbol referring to %d", m_Symbols[s].type);
|
||||
break;
|
||||
case SymbolType::GlobalVar:
|
||||
@@ -970,6 +971,8 @@ Program::Program(const byte *bytes, size_t length)
|
||||
size_t prevNumSymbols = m_Symbols.size();
|
||||
size_t instrSymbolStart = 0;
|
||||
|
||||
rdcarray<size_t> forwardRefInstructions;
|
||||
|
||||
for(size_t i = 0; i < f.funcType->members.size(); i++)
|
||||
{
|
||||
Instruction arg;
|
||||
@@ -984,7 +987,7 @@ Program::Program(const byte *bytes, size_t length)
|
||||
return id < m_Symbols.size() ? m_Symbols[id] : Symbol(SymbolType::Unknown, id);
|
||||
};
|
||||
|
||||
Block *curBlock = NULL;
|
||||
size_t curBlock = 0;
|
||||
int32_t debugLocIndex = -1;
|
||||
|
||||
for(const LLVMBC::BlockOrRecord &funcChild : rootchild.children)
|
||||
@@ -1104,6 +1107,7 @@ Program::Program(const byte *bytes, size_t length)
|
||||
case SymbolType::Instruction:
|
||||
f.instructions[s.idx].name = symtab.getString(1);
|
||||
break;
|
||||
case SymbolType::BasicBlock: f.blocks[s.idx].name = symtab.getString(1); break;
|
||||
case SymbolType::GlobalVar:
|
||||
case SymbolType::Function:
|
||||
case SymbolType::Alias:
|
||||
@@ -1159,7 +1163,7 @@ Program::Program(const byte *bytes, size_t length)
|
||||
{
|
||||
f.blocks.resize(op.ops[0]);
|
||||
|
||||
curBlock = &f.blocks[0];
|
||||
curBlock = 0;
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::DEBUG_LOC))
|
||||
{
|
||||
@@ -1602,6 +1606,70 @@ Program::Program(const byte *bytes, size_t length)
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_BR))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Branch;
|
||||
|
||||
inst.type = GetVoidType();
|
||||
|
||||
// true destination
|
||||
inst.args.push_back(Symbol(SymbolType::BasicBlock, op.ops[0]));
|
||||
|
||||
f.blocks[op.ops[0]].preds.insert(0, &f.blocks[curBlock]);
|
||||
|
||||
if(op.ops.size() > 1)
|
||||
{
|
||||
// false destination
|
||||
inst.args.push_back(Symbol(SymbolType::BasicBlock, op.ops[1]));
|
||||
|
||||
f.blocks[op.ops[1]].preds.insert(0, &f.blocks[curBlock]);
|
||||
|
||||
// predicate
|
||||
inst.args.push_back(getSymbol(op.ops[2]));
|
||||
}
|
||||
|
||||
curBlock++;
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_PHI))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Phi;
|
||||
|
||||
inst.type = &m_Types[op.ops[0]];
|
||||
|
||||
bool fwdRef = false;
|
||||
|
||||
for(size_t idx = 1; idx < op.ops.size(); idx += 2)
|
||||
{
|
||||
int64_t valSrc = LLVMBC::BitReader::svbr(op.ops[idx]);
|
||||
uint64_t blockSrc = op.ops[idx + 1];
|
||||
|
||||
if(valSrc < 0)
|
||||
{
|
||||
inst.args.push_back(Symbol(SymbolType::Unknown, m_Symbols.size() - valSrc));
|
||||
fwdRef = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst.args.push_back(getSymbol((uint64_t)valSrc));
|
||||
}
|
||||
inst.args.push_back(Symbol(SymbolType::BasicBlock, blockSrc));
|
||||
}
|
||||
|
||||
// forward references can't be resolved until we know the symbols lookup (because void
|
||||
// instructions are skipped)
|
||||
if(fwdRef)
|
||||
forwardRefInstructions.push_back(f.instructions.size());
|
||||
|
||||
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_EXTRACTELT))
|
||||
{
|
||||
// DXIL claims to be scalarised so should this appear?
|
||||
@@ -1728,8 +1796,20 @@ Program::Program(const byte *bytes, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
f.blocks[0].resultID = 0;
|
||||
|
||||
curBlock = 0;
|
||||
for(size_t i = 0, resultID = 1; i < f.instructions.size(); i++)
|
||||
{
|
||||
if(f.instructions[i].op == Instruction::Branch ||
|
||||
f.instructions[i].op == Instruction::Unreachable)
|
||||
{
|
||||
curBlock++;
|
||||
if(f.blocks[curBlock].name.empty())
|
||||
f.blocks[curBlock].resultID = (uint32_t)resultID++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(f.instructions[i].type->isVoid())
|
||||
continue;
|
||||
|
||||
@@ -1745,6 +1825,18 @@ Program::Program(const byte *bytes, size_t length)
|
||||
if(m.func)
|
||||
m.instruction = m_Symbols[instrSymbolStart + m.instruction].idx;
|
||||
|
||||
for(size_t fwdRefInst : forwardRefInstructions)
|
||||
{
|
||||
for(Symbol &s : f.instructions[fwdRefInst].args)
|
||||
{
|
||||
if(s.type == SymbolType::Unknown)
|
||||
{
|
||||
s = m_Symbols[s.idx];
|
||||
RDCASSERT(s.type == SymbolType::Instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Symbols.resize(prevNumSymbols);
|
||||
}
|
||||
else
|
||||
@@ -1830,6 +1922,7 @@ const Type *Program::GetSymbolType(const Function &f, Symbol s)
|
||||
case SymbolType::Unknown:
|
||||
case SymbolType::Alias:
|
||||
case SymbolType::Metadata:
|
||||
case SymbolType::BasicBlock:
|
||||
case SymbolType::Literal: RDCERR("Unexpected symbol to get type for %d", s.type); break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -89,6 +89,7 @@ enum class SymbolType
|
||||
Instruction,
|
||||
Metadata,
|
||||
Literal,
|
||||
BasicBlock,
|
||||
};
|
||||
|
||||
struct Symbol
|
||||
@@ -308,6 +309,8 @@ BITMASK_OPERATORS(InstructionFlags);
|
||||
|
||||
typedef rdcarray<rdcpair<uint64_t, Metadata *>> AttachedMetadata;
|
||||
|
||||
struct Block;
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
enum
|
||||
@@ -383,6 +386,8 @@ struct Instruction
|
||||
InsertElement,
|
||||
ShuffleVector,
|
||||
InsertValue,
|
||||
Branch,
|
||||
Phi,
|
||||
} op = Unknown;
|
||||
|
||||
InstructionFlags opFlags = InstructionFlags::NoFlags;
|
||||
@@ -404,6 +409,9 @@ struct Instruction
|
||||
|
||||
struct Block
|
||||
{
|
||||
uint32_t resultID = ~0U;
|
||||
rdcstr name;
|
||||
rdcarray<const Block *> preds;
|
||||
};
|
||||
|
||||
struct Function
|
||||
|
||||
@@ -438,6 +438,16 @@ void Program::MakeDisassemblyString()
|
||||
ret += StringFormat::Fmt("%%%s", escapeStringIfNeeded(refinst.name).c_str());
|
||||
break;
|
||||
}
|
||||
case SymbolType::BasicBlock:
|
||||
{
|
||||
const Block &block = func.blocks[s.idx];
|
||||
if(withTypes)
|
||||
ret = "label ";
|
||||
if(block.name.empty())
|
||||
ret += StringFormat::Fmt("%%%u", block.resultID);
|
||||
else
|
||||
ret += StringFormat::Fmt("%%%s", escapeStringIfNeeded(block.name).c_str());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
@@ -459,6 +469,8 @@ void Program::MakeDisassemblyString()
|
||||
m_Disassembly += " {\n";
|
||||
instructionLine++;
|
||||
|
||||
size_t curBlock = 0;
|
||||
|
||||
for(Instruction &inst : func.instructions)
|
||||
{
|
||||
inst.disassemblyLine = instructionLine;
|
||||
@@ -792,6 +804,37 @@ void Program::MakeDisassemblyString()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::Branch:
|
||||
{
|
||||
m_Disassembly += "br ";
|
||||
if(inst.args.size() > 1)
|
||||
{
|
||||
m_Disassembly += argToString(inst.args[2], true);
|
||||
m_Disassembly += StringFormat::Fmt(", %s", argToString(inst.args[0], true).c_str());
|
||||
m_Disassembly += StringFormat::Fmt(", %s", argToString(inst.args[1], true).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Disassembly += argToString(inst.args[0], true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::Phi:
|
||||
{
|
||||
m_Disassembly += "phi ";
|
||||
m_Disassembly += inst.type->toString();
|
||||
for(size_t a = 0; a < inst.args.size(); a += 2)
|
||||
{
|
||||
if(a == 0)
|
||||
m_Disassembly += " ";
|
||||
else
|
||||
m_Disassembly += ", ";
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt("[ %s, %s ]", argToString(inst.args[a], false).c_str(),
|
||||
argToString(inst.args[a + 1], false).c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inst.debugLoc != ~0U)
|
||||
@@ -861,6 +904,42 @@ void Program::MakeDisassemblyString()
|
||||
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
|
||||
if(inst.op == Instruction::Branch || inst.op == Instruction::Unreachable)
|
||||
{
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
|
||||
curBlock++;
|
||||
|
||||
rdcstr labelName;
|
||||
|
||||
if(func.blocks[curBlock].name.empty())
|
||||
labelName = StringFormat::Fmt("; <label>:%u", func.blocks[curBlock].resultID);
|
||||
else
|
||||
labelName =
|
||||
StringFormat::Fmt("%s: ", escapeStringIfNeeded(func.blocks[curBlock].name).c_str());
|
||||
|
||||
labelName.reserve(50);
|
||||
while(labelName.size() < 50)
|
||||
labelName.push_back(' ');
|
||||
|
||||
labelName += "; preds = ";
|
||||
bool first = true;
|
||||
for(const Block *pred : func.blocks[curBlock].preds)
|
||||
{
|
||||
if(!first)
|
||||
labelName += ", ";
|
||||
first = false;
|
||||
if(pred->name.empty())
|
||||
labelName += StringFormat::Fmt("%%%u", pred->resultID);
|
||||
else
|
||||
labelName += "%" + escapeStringIfNeeded(pred->name);
|
||||
}
|
||||
|
||||
m_Disassembly += labelName;
|
||||
m_Disassembly += "\n";
|
||||
}
|
||||
}
|
||||
m_Disassembly += "}\n\n";
|
||||
instructionLine += 2;
|
||||
|
||||
Reference in New Issue
Block a user