#include "config.h"
#include "AirGenerate.h"
#if ENABLE(B3_JIT)
#include "AirAllocateStack.h"
#include "AirCode.h"
#include "AirDumpAsJS.h"
#include "AirEliminateDeadCode.h"
#include "AirFixObviousSpills.h"
#include "AirFixPartialRegisterStalls.h"
#include "AirGenerationContext.h"
#include "AirHandleCalleeSaves.h"
#include "AirIteratedRegisterCoalescing.h"
#include "AirLogRegisterPressure.h"
#include "AirLowerAfterRegAlloc.h"
#include "AirLowerMacros.h"
#include "AirOpcodeUtils.h"
#include "AirOptimizeBlockOrder.h"
#include "AirReportUsedRegisters.h"
#include "AirSimplifyCFG.h"
#include "AirSpillEverything.h"
#include "AirValidate.h"
#include "B3Common.h"
#include "B3IndexMap.h"
#include "B3Procedure.h"
#include "B3TimingScope.h"
#include "CCallHelpers.h"
#include "DisallowMacroScratchRegisterUsage.h"
namespace JSC { namespace B3 { namespace Air {
void prepareForGeneration(Code& code)
{
TimingScope timingScope("Air::prepareForGeneration");
code.resetReachability();
if (shouldValidateIR())
validate(code);
if (shouldDumpIR(AirMode) && !shouldDumpIRAtEachPhase(AirMode)) {
dataLog("Initial air:\n");
dataLog(code);
}
lowerMacros(code);
eliminateDeadCode(code);
if (Options::airSpillsEverything())
spillEverything(code);
else
iteratedRegisterCoalescing(code);
if (Options::logAirRegisterPressure()) {
dataLog("Register pressure after register allocation:\n");
logRegisterPressure(code);
}
fixObviousSpills(code);
lowerAfterRegAlloc(code);
handleCalleeSaves(code);
if (Options::dumpAirAsJSBeforeAllocateStack()) {
dataLog("Dumping Air as JS before allocateStack:\n");
dumpAsJS(code, WTF::dataFile());
dataLog("Air hash: ", code.jsHash(), "\n");
}
allocateStack(code);
if (Options::dumpAirAfterAllocateStack()) {
dataLog("Dumping Air after allocateStack:\n");
dataLog(code);
dataLog("Air hash: ", code.jsHash(), "\n");
}
simplifyCFG(code);
optimizeBlockOrder(code);
reportUsedRegisters(code);
fixPartialRegisterStalls(code);
if (shouldValidateIR())
validate(code);
if (shouldDumpIR(AirMode)) {
dataLog("Air after ", code.lastPhaseName(), ", before generation:\n");
dataLog(code);
}
}
void generate(Code& code, CCallHelpers& jit)
{
TimingScope timingScope("Air::generate");
DisallowMacroScratchRegisterUsage disallowScratch(jit);
jit.emitFunctionPrologue();
if (code.frameSize())
jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
auto argFor = [&] (const RegisterAtOffset& entry) -> CCallHelpers::Address {
return CCallHelpers::Address(GPRInfo::callFrameRegister, entry.offset());
};
for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
if (entry.reg().isGPR())
jit.storePtr(entry.reg().gpr(), argFor(entry));
else
jit.storeDouble(entry.reg().fpr(), argFor(entry));
}
GenerationContext context;
context.code = &code;
IndexMap<BasicBlock, CCallHelpers::Label> blockLabels(code.size());
IndexMap<BasicBlock, CCallHelpers::JumpList> blockJumps(code.size());
auto link = [&] (CCallHelpers::Jump jump, BasicBlock* target) {
if (blockLabels[target].isSet()) {
jump.linkTo(blockLabels[target], &jit);
return;
}
blockJumps[target].append(jump);
};
PCToOriginMap& pcToOriginMap = code.proc().pcToOriginMap();
auto addItem = [&] (Inst& inst) {
if (!inst.origin) {
pcToOriginMap.appendItem(jit.label(), Origin());
return;
}
pcToOriginMap.appendItem(jit.label(), inst.origin->origin());
};
for (BasicBlock* block : code) {
blockJumps[block].link(&jit);
blockLabels[block] = jit.label();
ASSERT(block->size() >= 1);
for (unsigned i = 0; i < block->size() - 1; ++i) {
Inst& inst = block->at(i);
addItem(inst);
CCallHelpers::Jump jump = inst.generate(jit, context);
ASSERT_UNUSED(jump, !jump.isSet());
}
if (block->last().opcode == Jump
&& block->successorBlock(0) == code.findNextBlock(block))
continue;
addItem(block->last());
if (isReturn(block->last().opcode)) {
if (code.frameSize()) {
for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
if (entry.reg().isGPR())
jit.loadPtr(argFor(entry), entry.reg().gpr());
else
jit.loadDouble(argFor(entry), entry.reg().fpr());
}
jit.emitFunctionEpilogue();
} else
jit.emitFunctionEpilogueWithEmptyFrame();
jit.ret();
addItem(block->last());
continue;
}
CCallHelpers::Jump jump = block->last().generate(jit, context);
switch (block->numSuccessors()) {
case 0:
ASSERT(!jump.isSet());
break;
case 1:
link(jump, block->successorBlock(0));
break;
case 2:
link(jump, block->successorBlock(0));
if (block->successorBlock(1) != code.findNextBlock(block))
link(jit.jump(), block->successorBlock(1));
break;
default:
RELEASE_ASSERT_NOT_REACHED();
break;
}
addItem(block->last());
}
pcToOriginMap.appendItem(jit.label(), Origin());
for (auto& latePath : context.latePaths)
latePath->run(jit, context);
pcToOriginMap.appendItem(jit.label(), Origin());
}
} } }
#endif // ENABLE(B3_JIT)