Handle compare and select operations

This commit is contained in:
baldurk
2020-06-09 13:24:24 +01:00
parent d99a8536ca
commit a6c8949335
3 changed files with 234 additions and 0 deletions
@@ -1499,6 +1499,94 @@ Program::Program(const byte *bytes, size_t length)
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_CMP) ||
IS_KNOWN(op.id, FunctionRecord::INST_CMP2))
{
Instruction inst;
// a
inst.args.push_back(getSymbol(op.ops[0]));
// b
inst.args.push_back(getSymbol(op.ops[1]));
switch(op.ops[2])
{
case 0: inst.op = Instruction::FOrdFalse; break;
case 1: inst.op = Instruction::FOrdEqual; break;
case 2: inst.op = Instruction::FOrdGreater; break;
case 3: inst.op = Instruction::FOrdGreaterEqual; break;
case 4: inst.op = Instruction::FOrdLess; break;
case 5: inst.op = Instruction::FOrdLessEqual; break;
case 6: inst.op = Instruction::FOrdNotEqual; break;
case 7: inst.op = Instruction::FOrd; break;
case 8: inst.op = Instruction::FUnord; break;
case 9: inst.op = Instruction::FUnordEqual; break;
case 10: inst.op = Instruction::FUnordGreater; break;
case 11: inst.op = Instruction::FUnordGreaterEqual; break;
case 12: inst.op = Instruction::FUnordLess; break;
case 13: inst.op = Instruction::FUnordLessEqual; break;
case 14: inst.op = Instruction::FUnordNotEqual; break;
case 15: inst.op = Instruction::FOrdTrue; break;
case 32: inst.op = Instruction::IEqual; break;
case 33: inst.op = Instruction::INotEqual; break;
case 34: inst.op = Instruction::UGreater; break;
case 35: inst.op = Instruction::UGreaterEqual; break;
case 36: inst.op = Instruction::ULess; break;
case 37: inst.op = Instruction::ULessEqual; break;
case 38: inst.op = Instruction::SGreater; break;
case 39: inst.op = Instruction::SGreaterEqual; break;
case 40: inst.op = Instruction::SLess; break;
case 41: inst.op = Instruction::SLessEqual; break;
}
// fast math flags
if(op.ops.size() > 3)
inst.opFlags = InstructionFlags(op.ops[3]);
inst.type = GetBoolType();
// if we're comparing vectors, the return type is an equal sized bool vector
const Type *argType = GetSymbolType(f, inst.args[0]);
if(argType->type == Type::Vector)
{
for(const Type &t : m_Types)
{
if(t.type == Type::Vector && t.inner == inst.type &&
t.elemCount == argType->elemCount)
{
inst.type = &t;
break;
}
}
}
RDCASSERT(inst.type->type == argType->type);
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_SELECT) ||
IS_KNOWN(op.id, FunctionRecord::INST_VSELECT))
{
Instruction inst;
inst.op = Instruction::Select;
// if true
inst.args.push_back(getSymbol(op.ops[0]));
// if false
inst.args.push_back(getSymbol(op.ops[1]));
// selector
inst.args.push_back(getSymbol(op.ops[2]));
inst.type = GetSymbolType(f, inst.args[0]);
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
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) ||
@@ -1649,6 +1737,27 @@ const DXIL::Type *Program::GetVoidType()
return m_VoidType;
}
const DXIL::Type *Program::GetBoolType()
{
if(m_BoolType)
return m_BoolType;
for(size_t i = 0; i < m_Types.size(); i++)
{
if(m_Types[i].type == Type::Scalar && m_Types[i].scalarType == Type::Int &&
m_Types[i].bitWidth == 1)
{
m_BoolType = &m_Types[i];
break;
}
}
if(!m_BoolType)
RDCERR("Couldn't find void type");
return m_BoolType;
}
Metadata::~Metadata()
{
SAFE_DELETE(dwarf);
@@ -336,6 +336,33 @@ struct Instruction
GetElementPtr,
Load,
Store,
FOrdFalse,
FOrdEqual,
FOrdGreater,
FOrdGreaterEqual,
FOrdLess,
FOrdLessEqual,
FOrdNotEqual,
FOrd,
FUnord,
FUnordEqual,
FUnordGreater,
FUnordGreaterEqual,
FUnordLess,
FUnordLessEqual,
FUnordNotEqual,
FOrdTrue,
IEqual,
INotEqual,
UGreater,
UGreaterEqual,
ULess,
ULessEqual,
SGreater,
SGreaterEqual,
SLess,
SLessEqual,
Select,
} op = Unknown;
InstructionFlags opFlags = InstructionFlags::NoFlags;
@@ -412,6 +439,7 @@ private:
const Value *GetFunctionValue(const Function &f, uint64_t v);
const Metadata *GetFunctionMetadata(const Function &f, uint64_t v);
const Type *GetVoidType();
const Type *GetBoolType();
DXBC::ShaderType m_Type;
uint32_t m_Major, m_Minor;
@@ -425,6 +453,7 @@ private:
rdcarray<Type> m_Types;
const Type *m_VoidType = NULL;
const Type *m_BoolType = NULL;
rdcarray<Attributes> m_AttributeGroups;
rdcarray<Attributes> m_Attributes;
@@ -638,6 +638,102 @@ void Program::MakeDisassemblyString()
m_Disassembly += StringFormat::Fmt(", align %u", inst.align);
break;
}
case Instruction::FOrdFalse:
case Instruction::FOrdEqual:
case Instruction::FOrdGreater:
case Instruction::FOrdGreaterEqual:
case Instruction::FOrdLess:
case Instruction::FOrdLessEqual:
case Instruction::FOrdNotEqual:
case Instruction::FOrd:
case Instruction::FUnord:
case Instruction::FUnordEqual:
case Instruction::FUnordGreater:
case Instruction::FUnordGreaterEqual:
case Instruction::FUnordLess:
case Instruction::FUnordLessEqual:
case Instruction::FUnordNotEqual:
case Instruction::FOrdTrue:
{
m_Disassembly += "fcmp ";
rdcstr opFlagsStr = ToStr(inst.opFlags);
{
int offs = opFlagsStr.indexOf('|');
while(offs >= 0)
{
opFlagsStr.erase((size_t)offs, 2);
offs = opFlagsStr.indexOf('|');
}
}
m_Disassembly += opFlagsStr;
if(inst.opFlags != InstructionFlags::NoFlags)
m_Disassembly += " ";
switch(inst.op)
{
case Instruction::FOrdFalse: m_Disassembly += "false "; break;
case Instruction::FOrdEqual: m_Disassembly += "oeq "; break;
case Instruction::FOrdGreater: m_Disassembly += "ogt "; break;
case Instruction::FOrdGreaterEqual: m_Disassembly += "oge "; break;
case Instruction::FOrdLess: m_Disassembly += "olt "; break;
case Instruction::FOrdLessEqual: m_Disassembly += "ole "; break;
case Instruction::FOrdNotEqual: m_Disassembly += "one "; break;
case Instruction::FOrd: m_Disassembly += "ord "; break;
case Instruction::FUnord: m_Disassembly += "uno "; break;
case Instruction::FUnordEqual: m_Disassembly += "ueq "; break;
case Instruction::FUnordGreater: m_Disassembly += "ugt "; break;
case Instruction::FUnordGreaterEqual: m_Disassembly += "uge "; break;
case Instruction::FUnordLess: m_Disassembly += "ult "; break;
case Instruction::FUnordLessEqual: m_Disassembly += "ule "; break;
case Instruction::FUnordNotEqual: m_Disassembly += "une "; break;
case Instruction::FOrdTrue: m_Disassembly += "true "; break;
default: break;
}
m_Disassembly += argToString(inst.args[0], true);
m_Disassembly += ", ";
m_Disassembly += argToString(inst.args[1], false);
break;
}
case Instruction::IEqual:
case Instruction::INotEqual:
case Instruction::UGreater:
case Instruction::UGreaterEqual:
case Instruction::ULess:
case Instruction::ULessEqual:
case Instruction::SGreater:
case Instruction::SGreaterEqual:
case Instruction::SLess:
case Instruction::SLessEqual:
{
m_Disassembly += "icmp ";
switch(inst.op)
{
case Instruction::IEqual: m_Disassembly += "eq "; break;
case Instruction::INotEqual: m_Disassembly += "ne "; break;
case Instruction::UGreater: m_Disassembly += "ugt "; break;
case Instruction::UGreaterEqual: m_Disassembly += "uge "; break;
case Instruction::ULess: m_Disassembly += "ult "; break;
case Instruction::ULessEqual: m_Disassembly += "ule "; break;
case Instruction::SGreater: m_Disassembly += "sgt "; break;
case Instruction::SGreaterEqual: m_Disassembly += "sge "; break;
case Instruction::SLess: m_Disassembly += "slt "; break;
case Instruction::SLessEqual: m_Disassembly += "sle "; break;
default: break;
}
m_Disassembly += argToString(inst.args[0], true);
m_Disassembly += ", ";
m_Disassembly += argToString(inst.args[1], false);
break;
}
case Instruction::Select:
{
m_Disassembly += "select ";
m_Disassembly += argToString(inst.args[2], true);
m_Disassembly += ", ";
m_Disassembly += argToString(inst.args[0], true);
m_Disassembly += ", ";
m_Disassembly += argToString(inst.args[1], true);
break;
}
}
if(inst.debugLoc != ~0U)