/* * Look for Jcc instructions in the main trace that * branch to "normal exits". We can optimize these into the * SideExitJcc* instructions that can be patched in place. */ void optimizeSideExitJccs(IRUnit& unit) { auto trace = unit.main(); FTRACE(5, "SideExitJcc:vvvvvvvvvvvvvvvvvvvvv\n"); SCOPE_EXIT { FTRACE(5, "SideExitJcc:^^^^^^^^^^^^^^^^^^^^^\n"); }; forEachInst(trace->blocks(), [&] (IRInstruction* inst) { if (!jccCanBeDirectExit(inst->op())) return; auto const exitBlock = inst->taken(); if (!isNormalExit(exitBlock)) return; auto it = exitBlock->backIter(); auto& reqBindJmp = *(it--); auto& syncABI = *it; assert(syncABI.op() == SyncABIRegs); FTRACE(5, "converting jcc ({}) to side exit\n", inst->id()); auto const newOpcode = jmpToSideExitJmp(inst->op()); SideExitJccData data; data.taken = reqBindJmp.extra<ReqBindJmp>()->offset; auto const block = inst->block(); block->insert(block->iteratorTo(inst), unit.cloneInstruction(&syncABI)); unit.replace( inst, newOpcode, data, std::make_pair(inst->numSrcs(), inst->srcs().begin()) ); }); }
/* * Look for CheckStk/CheckLoc instructions in the main trace that * branch to "normal exits". We can optimize these into the * SideExitGuard* instructions that can be patched in place. */ void optimizeSideExitChecks(IRUnit& unit) { auto trace = unit.main(); FTRACE(5, "SideExit:vvvvvvvvvvvvvvvvvvvvv\n"); SCOPE_EXIT { FTRACE(5, "SideExit:^^^^^^^^^^^^^^^^^^^^^\n"); }; forEachInst(trace->blocks(), [&] (IRInstruction* inst) { if (inst->op() != CheckStk && inst->op() != CheckLoc) return; auto const exitBlock = inst->taken(); if (!isNormalExit(exitBlock)) return; auto const syncABI = &*boost::prior(exitBlock->backIter()); assert(syncABI->op() == SyncABIRegs); FTRACE(5, "converting jump ({}) to side exit\n", inst->id()); auto const isStack = inst->op() == CheckStk; auto const fp = syncABI->src(0); auto const sp = syncABI->src(1); SideExitGuardData data; data.checkedSlot = isStack ? inst->extra<CheckStk>()->offset : inst->extra<CheckLoc>()->locId; data.taken = exitBlock->back()->extra<ReqBindJmp>()->offset; auto const block = inst->block(); block->insert(block->iteratorTo(inst), unit.cloneInstruction(syncABI)); unit.replace( inst, isStack ? SideExitGuardStk : SideExitGuardLoc, inst->typeParam(), data, isStack ? sp : fp ); }); }
// Return true if branch is a conditional branch to a normal exit. bool isSideExitJcc(IRInstruction* branch, Block* exit) { return jccCanBeDirectExit(branch->op()) && isNormalExit(exit); }