void generateToAir(Procedure& procedure, Air::Code& code) { TimingScope timingScope("generateToAir"); // We don't require the incoming IR to have predecessors computed. procedure.resetReachability(); if (shouldValidateIR()) validate(procedure); // If we're doing super verbose dumping, the phase scope of any phase will already do a dump. if (shouldDumpIR() && !shouldDumpIRAtEachPhase()) { dataLog("Initial B3:\n"); dataLog(procedure); } reduceStrength(procedure); // FIXME: Add more optimizations here. // https://bugs.webkit.org/show_bug.cgi?id=150507 moveConstants(procedure); if (shouldValidateIR()) validate(procedure); // If we're doing super verbose dumping, the phase scope of any phase will already do a dump. // Note that lowerToAir() acts like a phase in this regard. if (shouldDumpIR() && !shouldDumpIRAtEachPhase()) { dataLog("B3 after ", procedure.lastPhaseName(), ", before generation:\n"); dataLog(procedure); } lowerToAir(procedure, code); }
void generateToAir(Procedure& procedure, unsigned optLevel) { TimingScope timingScope("generateToAir"); if (shouldDumpIR(B3Mode) && !shouldDumpIRAtEachPhase(B3Mode)) { dataLog("Initial B3:\n"); dataLog(procedure); } // We don't require the incoming IR to have predecessors computed. procedure.resetReachability(); if (shouldValidateIR()) validate(procedure); if (optLevel >= 1) { reduceDoubleToFloat(procedure); reduceStrength(procedure); eliminateCommonSubexpressions(procedure); inferSwitches(procedure); duplicateTails(procedure); fixSSA(procedure); foldPathConstants(procedure); // FIXME: Add more optimizations here. // https://bugs.webkit.org/show_bug.cgi?id=150507 } lowerMacros(procedure); if (optLevel >= 1) { reduceStrength(procedure); // FIXME: Add more optimizations here. // https://bugs.webkit.org/show_bug.cgi?id=150507 } lowerMacrosAfterOptimizations(procedure); legalizeMemoryOffsets(procedure); moveConstants(procedure); // FIXME: We should run pureCSE here to clean up some platform specific changes from the previous phases. // https://bugs.webkit.org/show_bug.cgi?id=164873 if (shouldValidateIR()) validate(procedure); // If we're doing super verbose dumping, the phase scope of any phase will already do a dump. // Note that lowerToAir() acts like a phase in this regard. if (shouldDumpIR(B3Mode) && !shouldDumpIRAtEachPhase(B3Mode)) { dataLog("B3 after ", procedure.lastPhaseName(), ", before generation:\n"); dataLog(procedure); } lowerToAir(procedure); }
void generate(Code& code, CCallHelpers& jit) { TimingScope timingScope("Air::generate"); // We don't expect the incoming code to have predecessors computed. code.resetReachability(); if (shouldValidateIR()) validate(code); // If we're doing super verbose dumping, the phase scope of any phase will already do a dump. if (shouldDumpIR() && !shouldDumpIRAtEachPhase()) { dataLog("Initial air:\n"); dataLog(code); } // This is where we run our optimizations and transformations. // FIXME: Add Air optimizations. // https://bugs.webkit.org/show_bug.cgi?id=150456 eliminateDeadCode(code); // This is where we would have a real register allocator. Then, we could use spillEverything() // in place of the register allocator only for testing. // FIXME: https://bugs.webkit.org/show_bug.cgi?id=150457 spillEverything(code); // Prior to this point the prologue and epilogue is implicit. This makes it explicit. It also // does things like identify which callee-saves we're using and saves them. handleCalleeSaves(code); // This turns all Stack and CallArg Args into Addr args that use the frame pointer. It does // this by first-fit allocating stack slots. It should be pretty darn close to optimal, so we // shouldn't have to worry about this very much. allocateStack(code); // If we coalesced moves then we can unbreak critical edges. This is the main reason for this // phase. simplifyCFG(code); // FIXME: We should really have a code layout optimization here. // https://bugs.webkit.org/show_bug.cgi?id=150478 reportUsedRegisters(code); if (shouldValidateIR()) validate(code); // Do a final dump of Air. Note that we have to do this even if we are doing per-phase dumping, // since the final generation is not a phase. if (shouldDumpIR()) { dataLog("Air after ", code.lastPhaseName(), ", before generation:\n"); dataLog(code); } TimingScope codeGenTimingScope("Air::generate backend"); // And now, we generate code. jit.emitFunctionPrologue(); jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister); 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); }; for (BasicBlock* block : code) { blockJumps[block].link(&jit); ASSERT(block->size() >= 1); for (unsigned i = 0; i < block->size() - 1; ++i) { CCallHelpers::Jump jump = block->at(i).generate(jit, context); ASSERT_UNUSED(jump, !jump.isSet()); } if (block->last().opcode == Jump && block->successorBlock(0) == code.findNextBlock(block)) continue; if (block->last().opcode == Ret) { // We currently don't represent the full prologue/epilogue in Air, so we need to // have this override. jit.emitFunctionEpilogue(); jit.ret(); continue; } CCallHelpers::Jump jump = block->last().generate(jit, context); for (Inst& inst : *block) jump = inst.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; } } for (auto& latePath : context.latePaths) latePath->run(jit, context); }
void prepareForGeneration(Code& code) { TimingScope timingScope("Air::prepareForGeneration"); // We don't expect the incoming code to have predecessors computed. code.resetReachability(); if (shouldValidateIR()) validate(code); // If we're doing super verbose dumping, the phase scope of any phase will already do a dump. if (shouldDumpIR() && !shouldDumpIRAtEachPhase()) { dataLog("Initial air:\n"); dataLog(code); } // This is where we run our optimizations and transformations. // FIXME: Add Air optimizations. // https://bugs.webkit.org/show_bug.cgi?id=150456 eliminateDeadCode(code); // Register allocation for all the Tmps that do not have a corresponding machine register. // After this phase, every Tmp has a reg. // // For debugging, you can use spillEverything() to put everything to the stack between each Inst. if (Options::airSpillsEverything()) spillEverything(code); else iteratedRegisterCoalescing(code); // Prior to this point the prologue and epilogue is implicit. This makes it explicit. It also // does things like identify which callee-saves we're using and saves them. handleCalleeSaves(code); // This turns all Stack and CallArg Args into Addr args that use the frame pointer. It does // this by first-fit allocating stack slots. It should be pretty darn close to optimal, so we // shouldn't have to worry about this very much. allocateStack(code); // If we coalesced moves then we can unbreak critical edges. This is the main reason for this // phase. simplifyCFG(code); // This sorts the basic blocks in Code to achieve an ordering that maximizes the likelihood that a high // frequency successor is also the fall-through target. optimizeBlockOrder(code); // Attempt to remove false dependencies between instructions created by partial register changes. // This must be executed as late as possible as it depends on the instructions order and register use. fixPartialRegisterStalls(code); // This is needed to satisfy a requirement of B3::StackmapValue. reportUsedRegisters(code); if (shouldValidateIR()) validate(code); // Do a final dump of Air. Note that we have to do this even if we are doing per-phase dumping, // since the final generation is not a phase. if (shouldDumpIR()) { dataLog("Air after ", code.lastPhaseName(), ", before generation:\n"); dataLog(code); } }