From d99a8536cad2c95976de6c37164a0f0fdc9bd03b Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 9 Jun 2020 12:57:48 +0100 Subject: [PATCH] Decode alloca/gep/load/store --- .../driver/shaders/dxil/dxil_bytecode.cpp | 171 +++++++++++++++++- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 18 +- .../driver/shaders/dxil/dxil_disassemble.cpp | 60 +++++- 3 files changed, 235 insertions(+), 14 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp index d78c3870e..60e26a590 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.cpp @@ -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) || diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 2e89eaad4..575c942a6 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -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> 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 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); diff --git a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp index 8de15e9bf..d6585288c 100644 --- a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp @@ -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");