Decode alloca/gep/load/store

This commit is contained in:
baldurk
2020-06-18 17:22:41 +01:00
parent 591e02b565
commit d99a8536ca
3 changed files with 235 additions and 14 deletions
+165 -6
View File
@@ -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) ||
+14 -4
View File
@@ -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");