#include "config.h"
#include "AirDumpAsJS.h"
#if ENABLE(B3_JIT)
#include "AirCode.h"
#include "AirInstInlines.h"
namespace JSC { namespace B3 { namespace Air {
namespace {
CString varNameForBlockAtIndex(unsigned index)
{
return toCString("bb", index);
}
CString varName(BasicBlock* block)
{
return varNameForBlockAtIndex(block->index());
}
CString varNameForStackSlotAtIndex(unsigned index)
{
return toCString("slot", index);
}
CString varName(StackSlot* slot)
{
return varNameForStackSlotAtIndex(slot->index());
}
CString varName(Reg reg)
{
return toCString("Reg.", reg.debugName());
}
CString varNameForTmpWithTypeAndIndex(Arg::Type type, unsigned index)
{
return toCString(type == Arg::FP ? "f" : "", "tmp", index);
}
CString varName(Tmp tmp)
{
if (tmp.isReg())
return varName(tmp.reg());
return varNameForTmpWithTypeAndIndex(Arg(tmp).type(), tmp.tmpIndex());
}
}
void dumpAsJS(Code& code, PrintStream& out)
{
out.println("let code = new Code();");
for (unsigned i = 0; i < code.size(); ++i)
out.println("let ", varNameForBlockAtIndex(i), " = code.addBlock();");
out.println("let hash;");
for (unsigned i = 0; i < code.stackSlots().size(); ++i) {
StackSlot* slot = code.stackSlots()[i];
if (slot) {
out.println("let ", varName(slot), " = code.addStackSlot(", slot->byteSize(), ", ", slot->kind(), ");");
if (slot->offsetFromFP())
out.println(varName(slot), ".setOffsetFromFP(", slot->offsetFromFP(), ");");
out.println("hash = ", varName(slot), ".hash();");
out.println("if (hash != ", slot->jsHash(), ")");
out.println(" throw new Error(\"Bad hash: \" + hash);");
} else
out.println("code.addStackSlot(1, Spill);");
}
Arg::forEachType(
[&] (Arg::Type type) {
for (unsigned i = code.numTmps(type); i--;) {
out.println(
"let ", varNameForTmpWithTypeAndIndex(type, i), " = code.newTmp(", type, ");");
}
});
out.println("let inst;");
out.println("let arg;");
for (BasicBlock* block : code) {
for (FrequentedBlock successor : block->successors()) {
out.println(
varName(block), ".successors.push(new FrequentedBlock(",
varName(successor.block()), ", ", successor.frequency(), "));");
}
for (BasicBlock* predecessor : block->predecessors())
out.println(varName(block), ".predecessors.push(", varName(predecessor), ");");
for (Inst& inst : *block) {
out.println("inst = new Inst(", inst.opcode, ");");
inst.forEachArg(
[&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
switch (arg.kind()) {
case Arg::Invalid:
RELEASE_ASSERT_NOT_REACHED();
break;
case Arg::Tmp:
out.println("arg = Arg.createTmp(", varName(arg.tmp()), ");");
break;
case Arg::Imm:
out.println("arg = Arg.createImm(", arg.value(), ");");
break;
case Arg::BigImm:
out.println(
"arg = Arg.createBigImm(",
static_cast<int32_t>(arg.value()), ", ",
static_cast<int32_t>(arg.value() >> 32), ");");
break;
case Arg::BitImm:
out.println("arg = Arg.createBitImm(", arg.value(), ");");
break;
case Arg::BitImm64:
out.println(
"arg = Arg.createBitImm64(",
static_cast<int32_t>(arg.value()), ", ",
static_cast<int32_t>(arg.value() >> 32), ");");
break;
case Arg::Addr:
out.println(
"arg = Arg.createAddr(", varName(arg.base()), ", ", arg.offset(), ");");
break;
case Arg::Stack:
out.println(
"arg = Arg.createStack(", varName(arg.stackSlot()), ", ", arg.offset(), ");");
break;
case Arg::CallArg:
out.println("arg = Arg.createCallArg(", arg.offset(), ");");
break;
case Arg::Index:
out.println(
"arg = Arg.createIndex(", varName(arg.base()), ", ",
varName(arg.index()), ", ", arg.scale(), ", ", arg.offset(), ");");
break;
case Arg::RelCond:
out.println("arg = Arg.createRelCond(", arg.asRelationalCondition(), ");");
break;
case Arg::ResCond:
out.println("arg = Arg.createResCond(", arg.asResultCondition(), ");");
break;
case Arg::DoubleCond:
out.println("arg = Arg.createDoubleCond(", arg.asDoubleCondition(), ");");
break;
case Arg::Special:
out.println("arg = Arg.createSpecial();");
break;
case Arg::WidthArg:
out.println("arg = Arg.createWidthArg(", arg.width(), ");");
break;
}
out.println("inst.args.push(arg);");
});
if (inst.opcode == Patch) {
if (inst.hasNonArgEffects())
out.println("inst.patchHasNonArgEffects = true;");
out.println("inst.extraEarlyClobberedRegs = new Set();");
out.println("inst.extraClobberedRegs = new Set();");
inst.extraEarlyClobberedRegs().forEach(
[&] (Reg reg) {
out.println("inst.extraEarlyClobberedRegs.add(", varName(reg), ");");
});
inst.extraClobberedRegs().forEach(
[&] (Reg reg) {
out.println("inst.extraClobberedRegs.add(", varName(reg), ");");
});
out.println("inst.patchArgData = [];");
inst.forEachArg(
[&] (Arg&, Arg::Role role, Arg::Type type, Arg::Width width) {
out.println(
"inst.patchArgData.push({role: Arg.", role, ", type: ", type,
", width: ", width, "});");
});
}
if (inst.opcode == CCall || inst.opcode == ColdCCall) {
out.println("inst.cCallType = ", inst.origin->type());
out.println("inst.cCallArgTypes = [];");
for (unsigned i = 1; i < inst.origin->numChildren(); ++i)
out.println("inst.cCallArgTypes.push(", inst.origin->child(i)->type(), ");");
}
out.println("hash = inst.hash();");
out.println("if (hash != ", inst.jsHash(), ")");
out.println(" throw new Error(\"Bad hash: \" + hash);");
out.println(varName(block), ".append(inst);");
}
}
}
} } }
#endif // ENABLE(B3_JIT)