const Vector<GPRReg>& gprsInPriorityOrder() { static Vector<GPRReg>* result; static std::once_flag once; std::call_once( once, [] { result = new Vector<GPRReg>(); RegisterSet all = RegisterSet::allGPRs(); all.exclude(RegisterSet::stackRegisters()); all.exclude(RegisterSet::reservedHardwareRegisters()); RegisterSet calleeSave = RegisterSet::calleeSaveRegisters(); all.forEach( [&] (Reg reg) { if (!calleeSave.get(reg)) result->append(reg.gpr()); }); all.forEach( [&] (Reg reg) { if (calleeSave.get(reg)) result->append(reg.gpr()); }); }); return *result; }
const Vector<FPRReg>& fprsInPriorityOrder() { static Vector<FPRReg>* result; static std::once_flag once; std::call_once( once, [] { result = new Vector<FPRReg>(); RegisterSet all = RegisterSet::allFPRs(); RegisterSet calleeSave = RegisterSet::calleeSaveRegisters(); all.forEach( [&] (Reg reg) { if (!calleeSave.get(reg)) result->append(reg.fpr()); }); all.forEach( [&] (Reg reg) { if (calleeSave.get(reg)) result->append(reg.fpr()); }); }); return *result; }
void fixPartialRegisterStalls(Code& code) { if (!isX86()) return; PhaseScope phaseScope(code, "fixPartialRegisterStalls"); Vector<BasicBlock*> candidates; for (BasicBlock* block : code) { for (const Inst& inst : *block) { if (hasPartialXmmRegUpdate(inst)) { candidates.append(block); break; } } } // Fortunately, Partial Stalls are rarely used. Return early if no block // cares about them. if (candidates.isEmpty()) return; // For each block, this provides the distance to the last instruction setting each register // on block *entry*. IndexMap<BasicBlock, FPDefDistance> lastDefDistance(code.size()); // Blocks with dirty distance at head. IndexSet<BasicBlock> dirty; // First, we compute the local distance for each block and push it to the successors. for (BasicBlock* block : code) { FPDefDistance localDistance; unsigned distanceToBlockEnd = block->size(); for (Inst& inst : *block) updateDistances(inst, localDistance, distanceToBlockEnd); for (BasicBlock* successor : block->successorBlocks()) { if (lastDefDistance[successor].updateFromPrecessor(localDistance)) dirty.add(successor); } } // Now we propagate the minimums accross blocks. bool changed; do { changed = false; for (BasicBlock* block : code) { if (!dirty.remove(block)) continue; // Little shortcut: if the block is big enough, propagating it won't add any information. if (block->size() >= minimumSafeDistance) continue; unsigned blockSize = block->size(); FPDefDistance& blockDistance = lastDefDistance[block]; for (BasicBlock* successor : block->successorBlocks()) { if (lastDefDistance[successor].updateFromPrecessor(blockDistance, blockSize)) { dirty.add(successor); changed = true; } } } } while (changed); // Finally, update each block as needed. InsertionSet insertionSet(code); for (BasicBlock* block : candidates) { unsigned distanceToBlockEnd = block->size(); FPDefDistance& localDistance = lastDefDistance[block]; for (unsigned i = 0; i < block->size(); ++i) { Inst& inst = block->at(i); if (hasPartialXmmRegUpdate(inst)) { RegisterSet defs; RegisterSet uses; inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type) { if (tmp.isFPR()) { if (Arg::isDef(role)) defs.set(tmp.fpr()); if (Arg::isAnyUse(role)) uses.set(tmp.fpr()); } }); // We only care about values we define but not use. Otherwise we have to wait // for the value to be resolved anyway. defs.exclude(uses); defs.forEach([&] (Reg reg) { if (localDistance.distance[MacroAssembler::fpRegisterIndex(reg.fpr())] < minimumSafeDistance) insertionSet.insert(i, MoveZeroToDouble, inst.origin, Tmp(reg)); }); } updateDistances(inst, localDistance, distanceToBlockEnd); } insertionSet.execute(block); } }
void logRegisterPressure(Code& code) { const unsigned totalColumns = 200; const unsigned registerColumns = 100; RegLiveness liveness(code); for (BasicBlock* block : code) { RegLiveness::LocalCalc localCalc(liveness, block); block->dumpHeader(WTF::dataFile()); Vector<CString> instDumps; for (unsigned instIndex = block->size(); instIndex--;) { Inst& inst = block->at(instIndex); Inst* prevInst = block->get(instIndex - 1); localCalc.execute(instIndex); RegisterSet set; set.setAll(localCalc.live()); Inst::forEachDefWithExtraClobberedRegs<Reg>( prevInst, &inst, [&] (Reg reg, Arg::Role, Arg::Type, Arg::Width) { set.set(reg); }); StringPrintStream instOut; StringPrintStream lineOut; lineOut.print(" "); if (set.numberOfSetRegisters()) { set.forEach( [&] (Reg reg) { CString text = toCString(" ", reg); if (text.length() + lineOut.length() > totalColumns) { instOut.print(lineOut.toCString(), "\n"); lineOut.reset(); lineOut.print(" "); } lineOut.print(text); }); lineOut.print(":"); } if (lineOut.length() > registerColumns) { instOut.print(lineOut.toCString(), "\n"); lineOut.reset(); } while (lineOut.length() < registerColumns) lineOut.print(" "); lineOut.print(" "); lineOut.print(inst); instOut.print(lineOut.toCString(), "\n"); instDumps.append(instOut.toCString()); } for (unsigned i = instDumps.size(); i--;) dataLog(instDumps[i]); block->dumpFooter(WTF::dataFile()); } }