Handle switch opcode

This commit is contained in:
baldurk
2020-06-09 17:25:07 +01:00
parent 26d4244d25
commit e29502ddcb
3 changed files with 87 additions and 6 deletions
@@ -1616,14 +1616,12 @@ Program::Program(const byte *bytes, size_t length)
// 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
@@ -1634,6 +1632,62 @@ Program::Program(const byte *bytes, size_t length)
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_SWITCH))
{
Instruction inst;
inst.op = Instruction::Switch;
inst.type = GetVoidType();
uint64_t typeIdx = op.ops[0];
static const uint64_t SWITCH_INST_MAGIC = 0x4B5;
if((typeIdx >> 16) == SWITCH_INST_MAGIC)
{
// type of condition
const Type *condType = &m_Types[op.ops[1]];
RDCASSERT(condType->bitWidth <= 64);
// condition
inst.args.push_back(getSymbol(op.ops[2]));
// default block
inst.args.push_back(Symbol(SymbolType::BasicBlock, op.ops[3]));
f.blocks[op.ops[3]].preds.insert(0, &f.blocks[curBlock]);
RDCERR("Unsupported switch instruction version");
}
else
{
// type of condition, ignored
// op.ops[0]
// condition
inst.args.push_back(getSymbol(op.ops[1]));
// default block
inst.args.push_back(Symbol(SymbolType::BasicBlock, op.ops[2]));
f.blocks[op.ops[2]].preds.insert(0, &f.blocks[curBlock]);
uint64_t numCases = (op.ops.size() - 3) / 2;
for(uint64_t c = 0; c < numCases; c++)
{
// case value, absolute not relative
inst.args.push_back(m_Symbols[op.ops[3 + c * 2 + 0]]);
// case block
inst.args.push_back(Symbol(SymbolType::BasicBlock, op.ops[3 + c * 2 + 1]));
f.blocks[op.ops[3 + c * 2 + 1]].preds.insert(0, &f.blocks[curBlock]);
}
}
curBlock++;
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_PHI))
{
Instruction inst;
@@ -1802,7 +1856,8 @@ Program::Program(const byte *bytes, size_t length)
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)
f.instructions[i].op == Instruction::Unreachable ||
f.instructions[i].op == Instruction::Switch)
{
curBlock++;
if(f.blocks[curBlock].name.empty())
@@ -388,6 +388,7 @@ struct Instruction
InsertValue,
Branch,
Phi,
Switch,
} op = Unknown;
InstructionFlags opFlags = InstructionFlags::NoFlags;
@@ -395,8 +395,12 @@ void Program::MakeDisassemblyString()
switch(s.type)
{
case SymbolType::Unknown:
case SymbolType::Alias:
case SymbolType::Literal: ret = "???"; break;
case SymbolType::Alias: ret = "???"; break;
case SymbolType::Literal:
if(withTypes)
ret += "i32 ";
ret += StringFormat::Fmt("%lld", s.idx);
break;
case SymbolType::Metadata:
if(withTypes)
ret += "metadata ";
@@ -835,6 +839,25 @@ void Program::MakeDisassemblyString()
}
break;
}
case Instruction::Switch:
{
m_Disassembly += "switch ";
m_Disassembly += argToString(inst.args[0], true);
m_Disassembly += ", ";
m_Disassembly += argToString(inst.args[1], true);
m_Disassembly += " [";
m_Disassembly += "\n";
instructionLine++;
for(size_t a = 2; a < inst.args.size(); a += 2)
{
m_Disassembly +=
StringFormat::Fmt(" %s, %s\n", argToString(inst.args[a], true).c_str(),
argToString(inst.args[a + 1], true).c_str());
instructionLine++;
}
m_Disassembly += " ]";
break;
}
}
if(inst.debugLoc != ~0U)
@@ -905,7 +928,8 @@ void Program::MakeDisassemblyString()
m_Disassembly += "\n";
instructionLine++;
if(inst.op == Instruction::Branch || inst.op == Instruction::Unreachable)
if(inst.op == Instruction::Branch || inst.op == Instruction::Unreachable ||
inst.op == Instruction::Switch)
{
m_Disassembly += "\n";
instructionLine++;
@@ -939,6 +963,7 @@ void Program::MakeDisassemblyString()
m_Disassembly += labelName;
m_Disassembly += "\n";
instructionLine++;
}
}
m_Disassembly += "}\n\n";