Add handling for branching and phi nodes

This commit is contained in:
baldurk
2020-06-09 16:47:32 +01:00
parent 08cd7ae0e0
commit 340bf9f805
3 changed files with 182 additions and 2 deletions
@@ -855,6 +855,7 @@ Program::Program(const byte *bytes, size_t length)
case SymbolType::Instruction:
case SymbolType::Metadata:
case SymbolType::Literal:
case SymbolType::BasicBlock:
RDCERR("Unexpected global symbol referring to %d", m_Symbols[s].type);
break;
case SymbolType::GlobalVar:
@@ -970,6 +971,8 @@ Program::Program(const byte *bytes, size_t length)
size_t prevNumSymbols = m_Symbols.size();
size_t instrSymbolStart = 0;
rdcarray<size_t> forwardRefInstructions;
for(size_t i = 0; i < f.funcType->members.size(); i++)
{
Instruction arg;
@@ -984,7 +987,7 @@ Program::Program(const byte *bytes, size_t length)
return id < m_Symbols.size() ? m_Symbols[id] : Symbol(SymbolType::Unknown, id);
};
Block *curBlock = NULL;
size_t curBlock = 0;
int32_t debugLocIndex = -1;
for(const LLVMBC::BlockOrRecord &funcChild : rootchild.children)
@@ -1104,6 +1107,7 @@ Program::Program(const byte *bytes, size_t length)
case SymbolType::Instruction:
f.instructions[s.idx].name = symtab.getString(1);
break;
case SymbolType::BasicBlock: f.blocks[s.idx].name = symtab.getString(1); break;
case SymbolType::GlobalVar:
case SymbolType::Function:
case SymbolType::Alias:
@@ -1159,7 +1163,7 @@ Program::Program(const byte *bytes, size_t length)
{
f.blocks.resize(op.ops[0]);
curBlock = &f.blocks[0];
curBlock = 0;
}
else if(IS_KNOWN(op.id, FunctionRecord::DEBUG_LOC))
{
@@ -1602,6 +1606,70 @@ Program::Program(const byte *bytes, size_t length)
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_BR))
{
Instruction inst;
inst.op = Instruction::Branch;
inst.type = GetVoidType();
// 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
inst.args.push_back(getSymbol(op.ops[2]));
}
curBlock++;
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_PHI))
{
Instruction inst;
inst.op = Instruction::Phi;
inst.type = &m_Types[op.ops[0]];
bool fwdRef = false;
for(size_t idx = 1; idx < op.ops.size(); idx += 2)
{
int64_t valSrc = LLVMBC::BitReader::svbr(op.ops[idx]);
uint64_t blockSrc = op.ops[idx + 1];
if(valSrc < 0)
{
inst.args.push_back(Symbol(SymbolType::Unknown, m_Symbols.size() - valSrc));
fwdRef = true;
}
else
{
inst.args.push_back(getSymbol((uint64_t)valSrc));
}
inst.args.push_back(Symbol(SymbolType::BasicBlock, blockSrc));
}
// forward references can't be resolved until we know the symbols lookup (because void
// instructions are skipped)
if(fwdRef)
forwardRefInstructions.push_back(f.instructions.size());
m_Symbols.push_back({SymbolType::Instruction, f.instructions.size()});
f.instructions.push_back(inst);
}
else if(IS_KNOWN(op.id, FunctionRecord::INST_EXTRACTELT))
{
// DXIL claims to be scalarised so should this appear?
@@ -1728,8 +1796,20 @@ Program::Program(const byte *bytes, size_t length)
}
}
f.blocks[0].resultID = 0;
curBlock = 0;
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)
{
curBlock++;
if(f.blocks[curBlock].name.empty())
f.blocks[curBlock].resultID = (uint32_t)resultID++;
continue;
}
if(f.instructions[i].type->isVoid())
continue;
@@ -1745,6 +1825,18 @@ Program::Program(const byte *bytes, size_t length)
if(m.func)
m.instruction = m_Symbols[instrSymbolStart + m.instruction].idx;
for(size_t fwdRefInst : forwardRefInstructions)
{
for(Symbol &s : f.instructions[fwdRefInst].args)
{
if(s.type == SymbolType::Unknown)
{
s = m_Symbols[s.idx];
RDCASSERT(s.type == SymbolType::Instruction);
}
}
}
m_Symbols.resize(prevNumSymbols);
}
else
@@ -1830,6 +1922,7 @@ const Type *Program::GetSymbolType(const Function &f, Symbol s)
case SymbolType::Unknown:
case SymbolType::Alias:
case SymbolType::Metadata:
case SymbolType::BasicBlock:
case SymbolType::Literal: RDCERR("Unexpected symbol to get type for %d", s.type); break;
}
return ret;
@@ -89,6 +89,7 @@ enum class SymbolType
Instruction,
Metadata,
Literal,
BasicBlock,
};
struct Symbol
@@ -308,6 +309,8 @@ BITMASK_OPERATORS(InstructionFlags);
typedef rdcarray<rdcpair<uint64_t, Metadata *>> AttachedMetadata;
struct Block;
struct Instruction
{
enum
@@ -383,6 +386,8 @@ struct Instruction
InsertElement,
ShuffleVector,
InsertValue,
Branch,
Phi,
} op = Unknown;
InstructionFlags opFlags = InstructionFlags::NoFlags;
@@ -404,6 +409,9 @@ struct Instruction
struct Block
{
uint32_t resultID = ~0U;
rdcstr name;
rdcarray<const Block *> preds;
};
struct Function
@@ -438,6 +438,16 @@ void Program::MakeDisassemblyString()
ret += StringFormat::Fmt("%%%s", escapeStringIfNeeded(refinst.name).c_str());
break;
}
case SymbolType::BasicBlock:
{
const Block &block = func.blocks[s.idx];
if(withTypes)
ret = "label ";
if(block.name.empty())
ret += StringFormat::Fmt("%%%u", block.resultID);
else
ret += StringFormat::Fmt("%%%s", escapeStringIfNeeded(block.name).c_str());
}
}
return ret;
};
@@ -459,6 +469,8 @@ void Program::MakeDisassemblyString()
m_Disassembly += " {\n";
instructionLine++;
size_t curBlock = 0;
for(Instruction &inst : func.instructions)
{
inst.disassemblyLine = instructionLine;
@@ -792,6 +804,37 @@ void Program::MakeDisassemblyString()
}
break;
}
case Instruction::Branch:
{
m_Disassembly += "br ";
if(inst.args.size() > 1)
{
m_Disassembly += argToString(inst.args[2], true);
m_Disassembly += StringFormat::Fmt(", %s", argToString(inst.args[0], true).c_str());
m_Disassembly += StringFormat::Fmt(", %s", argToString(inst.args[1], true).c_str());
}
else
{
m_Disassembly += argToString(inst.args[0], true);
}
break;
}
case Instruction::Phi:
{
m_Disassembly += "phi ";
m_Disassembly += inst.type->toString();
for(size_t a = 0; a < inst.args.size(); a += 2)
{
if(a == 0)
m_Disassembly += " ";
else
m_Disassembly += ", ";
m_Disassembly +=
StringFormat::Fmt("[ %s, %s ]", argToString(inst.args[a], false).c_str(),
argToString(inst.args[a + 1], false).c_str());
}
break;
}
}
if(inst.debugLoc != ~0U)
@@ -861,6 +904,42 @@ void Program::MakeDisassemblyString()
m_Disassembly += "\n";
instructionLine++;
if(inst.op == Instruction::Branch || inst.op == Instruction::Unreachable)
{
m_Disassembly += "\n";
instructionLine++;
curBlock++;
rdcstr labelName;
if(func.blocks[curBlock].name.empty())
labelName = StringFormat::Fmt("; <label>:%u", func.blocks[curBlock].resultID);
else
labelName =
StringFormat::Fmt("%s: ", escapeStringIfNeeded(func.blocks[curBlock].name).c_str());
labelName.reserve(50);
while(labelName.size() < 50)
labelName.push_back(' ');
labelName += "; preds = ";
bool first = true;
for(const Block *pred : func.blocks[curBlock].preds)
{
if(!first)
labelName += ", ";
first = false;
if(pred->name.empty())
labelName += StringFormat::Fmt("%%%u", pred->resultID);
else
labelName += "%" + escapeStringIfNeeded(pred->name);
}
m_Disassembly += labelName;
m_Disassembly += "\n";
}
}
m_Disassembly += "}\n\n";
instructionLine += 2;