mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-26 16:36:31 +00:00
Decode alloca/gep/load/store
This commit is contained in:
@@ -1178,9 +1178,8 @@ Program::Program(const byte *bytes, size_t length)
|
||||
|
||||
uint64_t callingFlags = op.ops[n++];
|
||||
|
||||
uint64_t fastMathFlags = 0;
|
||||
if(callingFlags & (1ULL << 17))
|
||||
fastMathFlags = op.ops[n++];
|
||||
inst.opFlags = InstructionFlags(op.ops[n++]);
|
||||
|
||||
if(callingFlags & (1ULL << 15))
|
||||
n++; // funcCallType
|
||||
@@ -1318,21 +1317,21 @@ Program::Program(const byte *bytes, size_t length)
|
||||
inst.op == Instruction::Mul || inst.op == Instruction::ShiftLeft)
|
||||
{
|
||||
if(flags & 0x2)
|
||||
inst.opFlags |= MathFlags::NoSignedWrap;
|
||||
inst.opFlags |= InstructionFlags::NoSignedWrap;
|
||||
if(flags & 0x1)
|
||||
inst.opFlags |= MathFlags::NoUnsignedWrap;
|
||||
inst.opFlags |= InstructionFlags::NoUnsignedWrap;
|
||||
}
|
||||
else if(inst.op == Instruction::SDiv || inst.op == Instruction::UDiv ||
|
||||
inst.op == Instruction::LogicalShiftRight ||
|
||||
inst.op == Instruction::ArithShiftRight)
|
||||
{
|
||||
if(flags & 0x1)
|
||||
inst.opFlags |= MathFlags::Exact;
|
||||
inst.opFlags |= InstructionFlags::Exact;
|
||||
}
|
||||
else if(isFloatOp)
|
||||
{
|
||||
// fast math flags overlap
|
||||
inst.opFlags = MathFlags(flags);
|
||||
inst.opFlags = InstructionFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1340,6 +1339,166 @@ Program::Program(const byte *bytes, size_t length)
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_UNREACHABLE))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Unreachable;
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_ALLOCA))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Alloca;
|
||||
|
||||
uint64_t align = op.ops[3];
|
||||
|
||||
inst.type = &m_Types[op.ops[0]];
|
||||
|
||||
if(align & 0x20)
|
||||
{
|
||||
// argument alloca
|
||||
}
|
||||
if((align & 0x40) == 0)
|
||||
{
|
||||
RDCASSERT(inst.type->type == Type::Pointer);
|
||||
inst.type = inst.type->inner;
|
||||
}
|
||||
|
||||
// we now have the inner type, but this instruction returns a pointer to that type so
|
||||
// adjust
|
||||
for(const Type &t : m_Types)
|
||||
{
|
||||
if(t.type == Type::Pointer && t.inner == inst.type)
|
||||
{
|
||||
inst.type = &t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RDCASSERT(inst.type->type == Type::Pointer);
|
||||
|
||||
// size
|
||||
inst.args.push_back(m_Symbols[op.ops[2]]);
|
||||
// type of the size - ignored
|
||||
// m_Types[op.ops[1]]
|
||||
|
||||
align &= ~0xE0;
|
||||
|
||||
inst.align = (1U << align) >> 1;
|
||||
|
||||
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_INBOUNDS_GEP_OLD) ||
|
||||
IS_KNOWN(op.id, FunctionRecord::INST_GEP_OLD) ||
|
||||
IS_KNOWN(op.id, FunctionRecord::INST_GEP))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::GetElementPtr;
|
||||
|
||||
if(IS_KNOWN(op.id, FunctionRecord::INST_INBOUNDS_GEP_OLD))
|
||||
inst.opFlags |= InstructionFlags::InBounds;
|
||||
|
||||
size_t idx = 0;
|
||||
if(IS_KNOWN(op.id, FunctionRecord::INST_GEP))
|
||||
{
|
||||
if(op.ops[idx++])
|
||||
inst.opFlags |= InstructionFlags::InBounds;
|
||||
inst.type = &m_Types[op.ops[idx++]];
|
||||
}
|
||||
|
||||
for(; idx < op.ops.size(); idx++)
|
||||
inst.args.push_back(getSymbol(op.ops[idx]));
|
||||
|
||||
if(inst.type == NULL)
|
||||
inst.type = GetSymbolType(f, inst.args[0]);
|
||||
|
||||
// walk the type list to get the return type
|
||||
for(idx = 2; idx < inst.args.size(); idx++)
|
||||
{
|
||||
if(inst.type->type == Type::Vector || inst.type->type == Type::Array)
|
||||
{
|
||||
inst.type = inst.type->inner;
|
||||
}
|
||||
else if(inst.type->type == Type::Struct)
|
||||
{
|
||||
Symbol s = inst.args[idx];
|
||||
// if it's a struct the index must be constant
|
||||
RDCASSERT(s.type == SymbolType::Constant);
|
||||
inst.type = inst.type->members[GetFunctionValue(f, s.idx)->val.uv[0]];
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Unexpected type %d encountered in GEP", inst.type->type);
|
||||
}
|
||||
}
|
||||
|
||||
// get the pointer type
|
||||
for(const Type &t : m_Types)
|
||||
{
|
||||
if(t.type == Type::Pointer && t.inner == inst.type)
|
||||
{
|
||||
inst.type = &t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RDCASSERT(inst.type->type == Type::Pointer);
|
||||
|
||||
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_LOAD))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Load;
|
||||
|
||||
inst.args.push_back(getSymbol(op.ops[0]));
|
||||
|
||||
size_t idx = 1;
|
||||
|
||||
if(op.ops.size() == idx + 3)
|
||||
{
|
||||
inst.type = &m_Types[op.ops[idx++]];
|
||||
}
|
||||
else
|
||||
{
|
||||
inst.type = GetSymbolType(f, inst.args[0]);
|
||||
RDCASSERT(inst.type->type == Type::Pointer);
|
||||
inst.type = inst.type->inner;
|
||||
}
|
||||
|
||||
inst.align = (1U << op.ops[idx]) >> 1;
|
||||
inst.opFlags |=
|
||||
(op.ops[idx + 1] != 0) ? InstructionFlags::Volatile : InstructionFlags::NoFlags;
|
||||
|
||||
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_STORE_OLD) ||
|
||||
IS_KNOWN(op.id, FunctionRecord::INST_STORE))
|
||||
{
|
||||
Instruction inst;
|
||||
|
||||
inst.op = Instruction::Store;
|
||||
|
||||
inst.type = GetVoidType();
|
||||
|
||||
inst.args.push_back(getSymbol(op.ops[0]));
|
||||
inst.args.push_back(getSymbol(op.ops[1]));
|
||||
|
||||
inst.align = (1U << op.ops[2]) >> 1;
|
||||
inst.opFlags |=
|
||||
(op.ops[3] != 0) ? InstructionFlags::Volatile : InstructionFlags::NoFlags;
|
||||
|
||||
f.instructions.push_back(inst);
|
||||
}
|
||||
else if(IS_KNOWN(op.id, FunctionRecord::INST_LANDINGPAD) ||
|
||||
IS_KNOWN(op.id, FunctionRecord::INST_LANDINGPAD_OLD) ||
|
||||
IS_KNOWN(op.id, FunctionRecord::INST_VAARG) ||
|
||||
|
||||
@@ -265,7 +265,7 @@ struct DebugLocation
|
||||
|
||||
struct Function;
|
||||
|
||||
enum class MathFlags : uint32_t
|
||||
enum class InstructionFlags : uint32_t
|
||||
{
|
||||
NoFlags = 0,
|
||||
|
||||
@@ -282,9 +282,13 @@ enum class MathFlags : uint32_t
|
||||
|
||||
// shifts/divs
|
||||
Exact = (1 << 7),
|
||||
|
||||
// load/store
|
||||
InBounds = (1 << 8),
|
||||
Volatile = (1 << 9),
|
||||
};
|
||||
|
||||
BITMASK_OPERATORS(MathFlags);
|
||||
BITMASK_OPERATORS(InstructionFlags);
|
||||
|
||||
typedef rdcarray<rdcpair<uint64_t, Metadata *>> AttachedMetadata;
|
||||
|
||||
@@ -327,15 +331,21 @@ struct Instruction
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Unreachable,
|
||||
Alloca,
|
||||
GetElementPtr,
|
||||
Load,
|
||||
Store,
|
||||
} op = Unknown;
|
||||
|
||||
MathFlags opFlags = MathFlags::NoFlags;
|
||||
InstructionFlags opFlags = InstructionFlags::NoFlags;
|
||||
|
||||
// common to all instructions
|
||||
rdcstr name;
|
||||
uint32_t disassemblyLine = 0;
|
||||
uint32_t resultID = ~0U;
|
||||
uint32_t debugLoc = ~0U;
|
||||
uint32_t align = 0;
|
||||
const Type *type = NULL;
|
||||
rdcarray<Symbol> args;
|
||||
AttachedMetadata attachedMeta;
|
||||
@@ -440,4 +450,4 @@ rdcstr escapeStringIfNeeded(const rdcstr &name);
|
||||
}; // namespace DXIL
|
||||
|
||||
DECLARE_REFLECTION_ENUM(DXIL::Attribute);
|
||||
DECLARE_STRINGISE_TYPE(DXIL::MathFlags);
|
||||
DECLARE_STRINGISE_TYPE(DXIL::InstructionFlags);
|
||||
|
||||
@@ -570,7 +570,7 @@ void Program::MakeDisassemblyString()
|
||||
}
|
||||
}
|
||||
m_Disassembly += opFlagsStr;
|
||||
if(inst.opFlags != MathFlags::NoFlags)
|
||||
if(inst.opFlags != InstructionFlags::NoFlags)
|
||||
m_Disassembly += " ";
|
||||
|
||||
bool first = true;
|
||||
@@ -586,6 +586,58 @@ void Program::MakeDisassemblyString()
|
||||
break;
|
||||
}
|
||||
case Instruction::Ret: m_Disassembly += "ret " + inst.type->toString(); break;
|
||||
case Instruction::Unreachable: m_Disassembly += "unreachable"; break;
|
||||
case Instruction::Alloca:
|
||||
{
|
||||
m_Disassembly += "alloca ";
|
||||
m_Disassembly += inst.type->inner->toString();
|
||||
m_Disassembly += StringFormat::Fmt(", align %u", inst.align);
|
||||
break;
|
||||
}
|
||||
case Instruction::GetElementPtr:
|
||||
{
|
||||
m_Disassembly += "getelementptr ";
|
||||
if(inst.opFlags & InstructionFlags::InBounds)
|
||||
m_Disassembly += "inbounds ";
|
||||
m_Disassembly += GetSymbolType(func, inst.args[0])->inner->toString();
|
||||
m_Disassembly += ", ";
|
||||
bool first = true;
|
||||
for(Symbol &s : inst.args)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
|
||||
m_Disassembly += argToString(s, true);
|
||||
first = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Instruction::Load:
|
||||
{
|
||||
m_Disassembly += "load ";
|
||||
m_Disassembly += inst.type->toString();
|
||||
m_Disassembly += ", ";
|
||||
bool first = true;
|
||||
for(Symbol &s : inst.args)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
|
||||
m_Disassembly += argToString(s, true);
|
||||
first = false;
|
||||
}
|
||||
m_Disassembly += StringFormat::Fmt(", align %u", inst.align);
|
||||
break;
|
||||
}
|
||||
case Instruction::Store:
|
||||
{
|
||||
m_Disassembly += "store ";
|
||||
m_Disassembly += argToString(inst.args[1], true);
|
||||
m_Disassembly += ", ";
|
||||
m_Disassembly += argToString(inst.args[0], true);
|
||||
m_Disassembly += StringFormat::Fmt(", align %u", inst.align);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(inst.debugLoc != ~0U)
|
||||
@@ -998,14 +1050,14 @@ rdcstr Value::toString(bool withType) const
|
||||
}; // namespace DXIL
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const DXIL::MathFlags &el)
|
||||
rdcstr DoStringise(const DXIL::InstructionFlags &el)
|
||||
{
|
||||
BEGIN_BITFIELD_STRINGISE(DXIL::MathFlags);
|
||||
BEGIN_BITFIELD_STRINGISE(DXIL::InstructionFlags);
|
||||
{
|
||||
STRINGISE_BITFIELD_CLASS_VALUE_NAMED(NoFlags, "");
|
||||
|
||||
// llvm doesn't print all bits if fastmath is set
|
||||
if(el & DXIL::MathFlags::FastMath)
|
||||
if(el & DXIL::InstructionFlags::FastMath)
|
||||
return "fast";
|
||||
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoNaNs, "nnan");
|
||||
|
||||
Reference in New Issue
Block a user