bool MachineBlockFrequencyInfo::runOnMachineFunction(MachineFunction &F) { MachineBranchProbabilityInfo &MBPI = getAnalysis<MachineBranchProbabilityInfo>(); MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>(); if (!MBFI) MBFI.reset(new ImplType); MBFI->calculate(F, MBPI, MLI); #ifndef NDEBUG if (ViewMachineBlockFreqPropagationDAG != GVDT_None && (ViewBlockFreqFuncName.empty() || F.getName().equals(ViewBlockFreqFuncName))) { view(); } #endif return false; }
bool CalculateSpillWeights::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Compute Spill Weights **********\n" << "********** Function: " << MF.getName() << '\n'); LiveIntervals &LIS = getAnalysis<LiveIntervals>(); MachineRegisterInfo &MRI = MF.getRegInfo(); VirtRegAuxInfo VRAI(MF, LIS, getAnalysis<MachineLoopInfo>()); for (unsigned i = 0, e = MRI.getNumVirtRegs(); i != e; ++i) { unsigned Reg = TargetRegisterInfo::index2VirtReg(i); if (MRI.reg_nodbg_empty(Reg)) continue; VRAI.CalculateWeightAndHint(LIS.getInterval(Reg)); } return false; }
/// Calculate the liveness information for the given machine function. bool StackMapLiveness::runOnMachineFunction(MachineFunction &MF) { if (!EnablePatchPointLiveness) return false; DEBUG(dbgs() << "********** COMPUTING STACKMAP LIVENESS: " << MF.getName() << " **********\n"); TRI = MF.getSubtarget().getRegisterInfo(); ++NumStackMapFuncVisited; // Skip this function if there are no patchpoints to process. if (!MF.getFrameInfo().hasPatchPoint()) { ++NumStackMapFuncSkipped; return false; } return calculateLiveness(MF); }
// Adjust local variables that are 4-bytes or larger to 4-byte boundary void ARCFrameLowering::processFunctionBeforeFrameFinalized( MachineFunction &MF, RegScavenger *RS) const { const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); LLVM_DEBUG(dbgs() << "Process function before frame finalized: " << MF.getName() << "\n"); MachineFrameInfo &MFI = MF.getFrameInfo(); LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n"); const TargetRegisterClass *RC = &ARC::GPR32RegClass; if (MFI.hasStackObjects()) { int RegScavFI = MFI.CreateStackObject( RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); RS->addScavengingFrameIndex(RegScavFI); LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI << "\n"); } }
bool LDVImpl::runOnMachineFunction(MachineFunction &mf) { clear(); MF = &mf; LIS = &pass.getAnalysis<LiveIntervals>(); MDT = &pass.getAnalysis<MachineDominatorTree>(); TRI = mf.getSubtarget().getRegisterInfo(); LS.initialize(mf); DEBUG(dbgs() << "********** COMPUTING LIVE DEBUG VARIABLES: " << mf.getName() << " **********\n"); bool Changed = collectDebugValues(mf); computeIntervals(); DEBUG(print(dbgs())); ModifiedMF = Changed; return Changed; }
void llvm::calculateSpillWeightsAndHints(LiveIntervals &LIS, MachineFunction &MF, const MachineLoopInfo &MLI, const MachineBlockFrequencyInfo &MBFI, VirtRegAuxInfo::NormalizingFn norm) { DEBUG(dbgs() << "********** Compute Spill Weights **********\n" << "********** Function: " << MF.getName() << '\n'); MachineRegisterInfo &MRI = MF.getRegInfo(); VirtRegAuxInfo VRAI(MF, LIS, MLI, MBFI, norm); for (unsigned i = 0, e = MRI.getNumVirtRegs(); i != e; ++i) { unsigned Reg = TargetRegisterInfo::index2VirtReg(i); if (MRI.reg_nodbg_empty(Reg)) continue; VRAI.calculateSpillWeightAndHint(LIS.getInterval(Reg)); } }
bool Combiner::combineMachineInstrs(MachineFunction &MF) { // If the ISel pipeline failed, do not bother running this pass. // FIXME: Should this be here or in individual combiner passes. if (MF.getProperties().hasProperty( MachineFunctionProperties::Property::FailedISel)) return false; MRI = &MF.getRegInfo(); Builder.setMF(MF); DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); bool MFChanged = false; bool Changed; do { // Collect all instructions. Do a post order traversal for basic blocks and // insert with list bottom up, so while we pop_back_val, we'll traverse top // down RPOT. Changed = false; GISelWorkList<512> WorkList; for (MachineBasicBlock *MBB : post_order(&MF)) { if (MBB->empty()) continue; for (auto MII = MBB->rbegin(), MIE = MBB->rend(); MII != MIE;) { MachineInstr *CurMI = &*MII; ++MII; // Erase dead insts before even adding to the list. if (isTriviallyDead(*CurMI, *MRI)) { DEBUG(dbgs() << *CurMI << "Is dead; erasing.\n"); CurMI->eraseFromParentAndMarkDBGValuesForRemoval(); continue; } WorkList.insert(CurMI); } } // Main Loop. Process the instructions here. while (!WorkList.empty()) { MachineInstr *CurrInst = WorkList.pop_back_val(); DEBUG(dbgs() << "Try combining " << *CurrInst << "\n";); Changed |= CInfo.combine(*CurrInst, Builder); } MFChanged |= Changed; } while (Changed);
bool RegUsageInfoPropagationPass::runOnMachineFunction(MachineFunction &MF) { const Module *M = MF.getFunction().getParent(); PhysicalRegisterUsageInfo *PRUI = &getAnalysis<PhysicalRegisterUsageInfo>(); DEBUG(dbgs() << " ++++++++++++++++++++ " << getPassName() << " ++++++++++++++++++++ \n"); DEBUG(dbgs() << "MachineFunction : " << MF.getName() << "\n"); const MachineFrameInfo &MFI = MF.getFrameInfo(); if (!MFI.hasCalls() && !MFI.hasTailCall()) return false; bool Changed = false; for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (!MI.isCall()) continue; DEBUG(dbgs() << "Call Instruction Before Register Usage Info Propagation : \n"); DEBUG(dbgs() << MI << "\n"); auto UpdateRegMask = [&](const Function *F) { const auto *RegMask = PRUI->getRegUsageInfo(F); if (!RegMask) return; setRegMask(MI, &(*RegMask)[0]); Changed = true; }; if (const Function *F = findCalledFunction(*M, MI)) { UpdateRegMask(F); } else { DEBUG(dbgs() << "Failed to find call target function\n"); } DEBUG(dbgs() << "Call Instruction After Register Usage Info Propagation : " << MI << '\n'); } } DEBUG(dbgs() << " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "++++++ \n"); return Changed; }
/// We need to override this function so we can avoid /// the call to EmitFunctionHeader(), which the MCPureStreamer can't handle. bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>(); if (STM.dumpCode()) { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) MF.dump(); #endif } SetupMachineFunction(MF); if (OutStreamer.hasRawTextSupport()) { OutStreamer.EmitRawText("@" + MF.getName() + ":"); } OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); if (STM.device()->getGeneration() > AMDGPUDeviceInfo::HD6XXX) { EmitProgramInfo(MF); } EmitFunctionBody(); return false; }
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** CFG Stackifying **********\n" "********** Function: " << MF.getName() << '\n'); const auto &MLI = getAnalysis<MachineLoopInfo>(); const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); // RPO sorting needs all loops to be single-entry. EliminateMultipleEntryLoops(MF, MLI); // Sort the blocks in RPO, with contiguous loops. SortBlocks(MF, MLI); // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. PlaceMarkers(MF, MLI, TII); return true; }
bool RABasic::runOnMachineFunction(MachineFunction &mf) { DEBUG(dbgs() << "********** BASIC REGISTER ALLOCATION **********\n" << "********** Function: " << mf.getName() << '\n'); MF = &mf; RegAllocBase::init(getAnalysis<VirtRegMap>(), getAnalysis<LiveIntervals>(), getAnalysis<LiveRegMatrix>()); SpillerInstance.reset(createInlineSpiller(*this, *MF, *VRM)); allocatePhysRegs(); // Diagnostic output before rewriting DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << *VRM << "\n"); releaseMemory(); return true; }
void MIRPrinter::print(const MachineFunction &MF) { initRegisterMaskIds(MF); yaml::MachineFunction YamlMF; YamlMF.Name = MF.getName(); YamlMF.Alignment = MF.getAlignment(); YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice(); YamlMF.HasWinCFI = MF.hasWinCFI(); YamlMF.Legalized = MF.getProperties().hasProperty( MachineFunctionProperties::Property::Legalized); YamlMF.RegBankSelected = MF.getProperties().hasProperty( MachineFunctionProperties::Property::RegBankSelected); YamlMF.Selected = MF.getProperties().hasProperty( MachineFunctionProperties::Property::Selected); YamlMF.FailedISel = MF.getProperties().hasProperty( MachineFunctionProperties::Property::FailedISel); convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo()); ModuleSlotTracker MST(MF.getFunction().getParent()); MST.incorporateFunction(MF.getFunction()); convert(MST, YamlMF.FrameInfo, MF.getFrameInfo()); convertStackObjects(YamlMF, MF, MST); if (const auto *ConstantPool = MF.getConstantPool()) convert(YamlMF, *ConstantPool); if (const auto *JumpTableInfo = MF.getJumpTableInfo()) convert(MST, YamlMF.JumpTableInfo, *JumpTableInfo); raw_string_ostream StrOS(YamlMF.Body.Value.Value); bool IsNewlineNeeded = false; for (const auto &MBB : MF) { if (IsNewlineNeeded) StrOS << "\n"; MIPrinter(StrOS, MST, RegisterMaskIds, StackObjectOperandMapping) .print(MBB); IsNewlineNeeded = true; } StrOS.flush(); yaml::Output Out(OS); if (!SimplifyMIR) Out.setWriteDefaultValues(true); Out << YamlMF; }
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** CFG Stackifying **********\n" "********** Function: " << MF.getName() << '\n'); const auto &MLI = getAnalysis<MachineLoopInfo>(); auto &MDT = getAnalysis<MachineDominatorTree>(); // Liveness is not tracked for EXPR_STACK physreg. const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); MF.getRegInfo().invalidateLiveness(); // Sort the blocks, with contiguous loops. SortBlocks(MF, MLI, MDT); // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. PlaceMarkers(MF, MLI, TII, MDT, MFI); return true; }
bool WebAssemblyOptimizeLiveIntervals::runOnMachineFunction(MachineFunction &MF) { LLVM_DEBUG(dbgs() << "********** Optimize LiveIntervals **********\n" "********** Function: " << MF.getName() << '\n'); MachineRegisterInfo &MRI = MF.getRegInfo(); LiveIntervals &LIS = getAnalysis<LiveIntervals>(); // We don't preserve SSA form. MRI.leaveSSA(); assert(MRI.tracksLiveness() && "OptimizeLiveIntervals expects liveness"); // Split multiple-VN LiveIntervals into multiple LiveIntervals. SmallVector<LiveInterval*, 4> SplitLIs; for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) { unsigned Reg = TargetRegisterInfo::index2VirtReg(i); if (MRI.reg_nodbg_empty(Reg)) continue; LIS.splitSeparateComponents(LIS.getInterval(Reg), SplitLIs); SplitLIs.clear(); } // In PrepareForLiveIntervals, we conservatively inserted IMPLICIT_DEF // instructions to satisfy LiveIntervals' requirement that all uses be // dominated by defs. Now that LiveIntervals has computed which of these // defs are actually needed and which are dead, remove the dead ones. for (auto MII = MF.begin()->begin(), MIE = MF.begin()->end(); MII != MIE; ) { MachineInstr *MI = &*MII++; if (MI->isImplicitDef() && MI->getOperand(0).isDead()) { LiveInterval &LI = LIS.getInterval(MI->getOperand(0).getReg()); LIS.removeVRegDefAt(LI, LIS.getInstructionIndex(*MI).getRegSlot()); LIS.RemoveMachineInstrFromMaps(*MI); MI->eraseFromParent(); } } return false; }
void NVPTXReplaceImageHandles:: replaceImageHandle(MachineOperand &Op, MachineFunction &MF) { const MachineRegisterInfo &MRI = MF.getRegInfo(); NVPTXMachineFunctionInfo *MFI = MF.getInfo<NVPTXMachineFunctionInfo>(); // Which instruction defines the handle? MachineInstr *MI = MRI.getVRegDef(Op.getReg()); assert(MI && "No def for image handle vreg?"); MachineInstr &TexHandleDef = *MI; switch (TexHandleDef.getOpcode()) { case NVPTX::LD_i64_avar: { // The handle is a parameter value being loaded, replace with the // parameter symbol assert(TexHandleDef.getOperand(6).isSymbol() && "Load is not a symbol!"); StringRef Sym = TexHandleDef.getOperand(6).getSymbolName(); std::string ParamBaseName = MF.getName(); ParamBaseName += "_param_"; assert(Sym.startswith(ParamBaseName) && "Invalid symbol reference"); unsigned Param = atoi(Sym.data()+ParamBaseName.size()); std::string NewSym; raw_string_ostream NewSymStr(NewSym); NewSymStr << MF.getFunction()->getName() << "_param_" << Param; Op.ChangeToImmediate( MFI->getImageHandleSymbolIndex(NewSymStr.str().c_str())); InstrsToRemove.insert(&TexHandleDef); break; } case NVPTX::texsurf_handles: { // The handle is a global variable, replace with the global variable name assert(TexHandleDef.getOperand(1).isGlobal() && "Load is not a global!"); const GlobalValue *GV = TexHandleDef.getOperand(1).getGlobal(); assert(GV->hasName() && "Global sampler must be named!"); Op.ChangeToImmediate(MFI->getImageHandleSymbolIndex(GV->getName().data())); InstrsToRemove.insert(&TexHandleDef); break; } default: llvm_unreachable("Unknown instruction operating on handle"); } }
void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{ if (Objects.empty()) return; const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering(); int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0); OS << "Frame Objects for " << MF.getName() << ":\n"; for (unsigned i = 0, e = Objects.size(); i != e; ++i) { const StackObject &SO = Objects[i]; OS << " fi#" << (int)(i-NumFixedObjects) << ": "; if (SO.Size == ~0ULL) { OS << "dead\n"; continue; } if (SO.Size == 0) OS << "variable sized"; else OS << "size=" << SO.Size; OS << ", align=" << SO.Alignment; if (i < NumFixedObjects) OS << ", fixed"; if (i < NumFixedObjects || SO.SPOffset != -1) { int64_t Off = SO.SPOffset - ValOffset; OS << ", at location [SP"; if (Off > 0) OS << "+" << format_hex(Off, 5); else if (Off < 0) OS << "-" << format_hex(-Off, 5); OS << "]"; } if (SO.isSpillSlot || SO.isStatepointSpillSlot) OS << ", spill_slot"; if (SO.Alloca) OS << ", has_alloca:" << SO.Alloca->getName(); OS << "\n"; } }
bool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Fixing up CALL_INDIRECTs **********\n" << MF.getName() << '\n'); bool Changed = false; const WebAssemblyInstrInfo *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (IsPseudoCallIndirect(MI)) { DEBUG(dbgs() << "Found call_indirect: " << MI << '\n'); // Rewrite pseudo to non-pseudo const MCInstrDesc &Desc = TII->get(GetNonPseudoCallIndirectOpcode(MI)); MI.setDesc(Desc); // Rewrite argument order auto Uses = MI.explicit_uses(); MachineInstr::mop_iterator it = Uses.begin(); const MachineOperand MO = *it; // Set up the flags immediate, which currently has no defined flags // so it's always zero. it->ChangeToImmediate(0); MI.addOperand(MF, MO); DEBUG(dbgs() << " After transform: " << MI); Changed = true; } } } DEBUG(dbgs() << "\nDone fixing up CALL_INDIRECTs\n\n"); return Changed; }
MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n"); const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); MachineInstr &Old = *I; DebugLoc dl = Old.getDebugLoc(); unsigned Amt = Old.getOperand(0).getImm(); auto *AFI = MF.getInfo<ARCFunctionInfo>(); if (!hasFP(MF)) { if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN) AFI->MaxCallStackReq = Amt; } else { if (Amt != 0) { assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN || Old.getOpcode() == ARC::ADJCALLSTACKUP) && "Unknown Frame Pseudo."); bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP); emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII); } } return MBB.erase(I); }
bool A15SDOptimizer::runOnMachineFunction(MachineFunction &Fn) { if (skipFunction(*Fn.getFunction())) return false; const ARMSubtarget &STI = Fn.getSubtarget<ARMSubtarget>(); // Since the A15SDOptimizer pass can insert VDUP instructions, it can only be // enabled when NEON is available. if (!(STI.isCortexA15() && STI.hasNEON())) return false; TII = STI.getInstrInfo(); TRI = STI.getRegisterInfo(); MRI = &Fn.getRegInfo(); bool Modified = false; DEBUG(dbgs() << "Running on function " << Fn.getName()<< "\n"); DeadInstr.clear(); Replacements.clear(); for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; ++MFI) { for (MachineBasicBlock::iterator MI = MFI->begin(), ME = MFI->end(); MI != ME;) { Modified |= runOnInstruction(MI++); } } for (std::set<MachineInstr *>::iterator I = DeadInstr.begin(), E = DeadInstr.end(); I != E; ++I) { (*I)->eraseFromParent(); } return Modified; }
bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { auto It = Functions.find(MF.getName()); if (It == Functions.end()) return error(Twine("no machine function information for function '") + MF.getName() + "' in the MIR file"); // TODO: Recreate the machine function. const yaml::MachineFunction &YamlMF = *It->getValue(); if (YamlMF.Alignment) MF.setAlignment(YamlMF.Alignment); MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasInlineAsm(YamlMF.HasInlineAsm); if (YamlMF.AllVRegsAllocated) MF.getProperties().set(MachineFunctionProperties::Property::AllVRegsAllocated); PerFunctionMIParsingState PFS(MF, SM, IRSlots); if (initializeRegisterInfo(PFS, YamlMF)) return true; if (!YamlMF.Constants.empty()) { auto *ConstantPool = MF.getConstantPool(); assert(ConstantPool && "Constant pool must be created"); if (initializeConstantPool(PFS, *ConstantPool, YamlMF)) return true; } StringRef BlockStr = YamlMF.Body.Value.Value; SMDiagnostic Error; SourceMgr BlockSM; BlockSM.AddNewSourceBuffer( MemoryBuffer::getMemBuffer(BlockStr, "",/*RequiresNullTerminator=*/false), SMLoc()); PFS.SM = &BlockSM; if (parseMachineBasicBlockDefinitions(PFS, BlockStr, Error)) { reportDiagnostic( diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange)); return true; } PFS.SM = &SM; if (MF.empty()) return error(Twine("machine function '") + Twine(MF.getName()) + "' requires at least one machine basic block in its body"); // Initialize the frame information after creating all the MBBs so that the // MBB references in the frame information can be resolved. if (initializeFrameInfo(PFS, YamlMF)) return true; // Initialize the jump table after creating all the MBBs so that the MBB // references can be resolved. if (!YamlMF.JumpTableInfo.Entries.empty() && initializeJumpTableInfo(PFS, YamlMF.JumpTableInfo)) return true; // Parse the machine instructions after creating all of the MBBs so that the // parser can resolve the MBB references. StringRef InsnStr = YamlMF.Body.Value.Value; SourceMgr InsnSM; InsnSM.AddNewSourceBuffer( MemoryBuffer::getMemBuffer(InsnStr, "", /*RequiresNullTerminator=*/false), SMLoc()); PFS.SM = &InsnSM; if (parseMachineInstructions(PFS, InsnStr, Error)) { reportDiagnostic( diagFromBlockStringDiag(Error, YamlMF.Body.Value.SourceRange)); return true; } PFS.SM = &SM; inferRegisterInfo(PFS, YamlMF); // FIXME: This is a temporary workaround until the reserved registers can be // serialized. MF.getRegInfo().freezeReservedRegs(MF); MF.verify(); return false; }
bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Hexagon New Value Jump **********\n" << "********** Function: " << MF.getName() << "\n"); if (skipFunction(*MF.getFunction())) return false; // If we move NewValueJump before register allocation we'll need live variable // analysis here too. QII = static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo()); QRI = static_cast<const HexagonRegisterInfo *>( MF.getSubtarget().getRegisterInfo()); MBPI = &getAnalysis<MachineBranchProbabilityInfo>(); if (DisableNewValueJumps) { return false; } int nvjCount = DbgNVJCount; int nvjGenerated = 0; // Loop through all the bb's of the function for (MachineFunction::iterator MBBb = MF.begin(), MBBe = MF.end(); MBBb != MBBe; ++MBBb) { MachineBasicBlock *MBB = &*MBBb; DEBUG(dbgs() << "** dumping bb ** " << MBB->getNumber() << "\n"); DEBUG(MBB->dump()); DEBUG(dbgs() << "\n" << "********** dumping instr bottom up **********\n"); bool foundJump = false; bool foundCompare = false; bool invertPredicate = false; unsigned predReg = 0; // predicate reg of the jump. unsigned cmpReg1 = 0; int cmpOp2 = 0; bool MO1IsKill = false; bool MO2IsKill = false; MachineBasicBlock::iterator jmpPos; MachineBasicBlock::iterator cmpPos; MachineInstr *cmpInstr = nullptr, *jmpInstr = nullptr; MachineBasicBlock *jmpTarget = nullptr; bool afterRA = false; bool isSecondOpReg = false; bool isSecondOpNewified = false; // Traverse the basic block - bottom up for (MachineBasicBlock::iterator MII = MBB->end(), E = MBB->begin(); MII != E;) { MachineInstr &MI = *--MII; if (MI.isDebugValue()) { continue; } if ((nvjCount == 0) || (nvjCount > -1 && nvjCount <= nvjGenerated)) break; DEBUG(dbgs() << "Instr: "; MI.dump(); dbgs() << "\n"); if (!foundJump && (MI.getOpcode() == Hexagon::J2_jumpt || MI.getOpcode() == Hexagon::J2_jumpf || MI.getOpcode() == Hexagon::J2_jumptnewpt || MI.getOpcode() == Hexagon::J2_jumptnew || MI.getOpcode() == Hexagon::J2_jumpfnewpt || MI.getOpcode() == Hexagon::J2_jumpfnew)) { // This is where you would insert your compare and // instr that feeds compare jmpPos = MII; jmpInstr = &MI; predReg = MI.getOperand(0).getReg(); afterRA = TargetRegisterInfo::isPhysicalRegister(predReg); // If ifconverter had not messed up with the kill flags of the // operands, the following check on the kill flag would suffice. // if(!jmpInstr->getOperand(0).isKill()) break; // This predicate register is live out out of BB // this would only work if we can actually use Live // variable analysis on phy regs - but LLVM does not // provide LV analysis on phys regs. //if(LVs.isLiveOut(predReg, *MBB)) break; // Get all the successors of this block - which will always // be 2. Check if the predicate register is live in in those // successor. If yes, we can not delete the predicate - // I am doing this only because LLVM does not provide LiveOut // at the BB level. bool predLive = false; for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(), SIE = MBB->succ_end(); SI != SIE; ++SI) { MachineBasicBlock* succMBB = *SI; if (succMBB->isLiveIn(predReg)) { predLive = true; } } if (predLive) break; if (!MI.getOperand(1).isMBB()) continue; jmpTarget = MI.getOperand(1).getMBB(); foundJump = true; if (MI.getOpcode() == Hexagon::J2_jumpf || MI.getOpcode() == Hexagon::J2_jumpfnewpt || MI.getOpcode() == Hexagon::J2_jumpfnew) { invertPredicate = true; } continue; } // No new value jump if there is a barrier. A barrier has to be in its // own packet. A barrier has zero operands. We conservatively bail out // here if we see any instruction with zero operands. if (foundJump && MI.getNumOperands() == 0) break; if (foundJump && !foundCompare && MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == predReg) { // Not all compares can be new value compare. Arch Spec: 7.6.1.1 if (isNewValueJumpCandidate(MI)) { assert( (MI.getDesc().isCompare()) && "Only compare instruction can be collapsed into New Value Jump"); isSecondOpReg = MI.getOperand(2).isReg(); if (!canCompareBeNewValueJump(QII, QRI, MII, predReg, isSecondOpReg, afterRA, jmpPos, MF)) break; cmpInstr = &MI; cmpPos = MII; foundCompare = true; // We need cmpReg1 and cmpOp2(imm or reg) while building // new value jump instruction. cmpReg1 = MI.getOperand(1).getReg(); if (MI.getOperand(1).isKill()) MO1IsKill = true; if (isSecondOpReg) { cmpOp2 = MI.getOperand(2).getReg(); if (MI.getOperand(2).isKill()) MO2IsKill = true; } else cmpOp2 = MI.getOperand(2).getImm(); continue; } } if (foundCompare && foundJump) { // If "common" checks fail, bail out on this BB. if (!commonChecksToProhibitNewValueJump(afterRA, MII)) break; bool foundFeeder = false; MachineBasicBlock::iterator feederPos = MII; if (MI.getOperand(0).isReg() && MI.getOperand(0).isDef() && (MI.getOperand(0).getReg() == cmpReg1 || (isSecondOpReg && MI.getOperand(0).getReg() == (unsigned)cmpOp2))) { unsigned feederReg = MI.getOperand(0).getReg(); // First try to see if we can get the feeder from the first operand // of the compare. If we can not, and if secondOpReg is true // (second operand of the compare is also register), try that one. // TODO: Try to come up with some heuristic to figure out which // feeder would benefit. if (feederReg == cmpReg1) { if (!canBeFeederToNewValueJump(QII, QRI, MII, jmpPos, cmpPos, MF)) { if (!isSecondOpReg) break; else continue; } else foundFeeder = true; } if (!foundFeeder && isSecondOpReg && feederReg == (unsigned) cmpOp2) if (!canBeFeederToNewValueJump(QII, QRI, MII, jmpPos, cmpPos, MF)) break; if (isSecondOpReg) { // In case of CMPLT, or CMPLTU, or EQ with the second register // to newify, swap the operands. if (cmpInstr->getOpcode() == Hexagon::C2_cmpeq && feederReg == (unsigned) cmpOp2) { unsigned tmp = cmpReg1; bool tmpIsKill = MO1IsKill; cmpReg1 = cmpOp2; MO1IsKill = MO2IsKill; cmpOp2 = tmp; MO2IsKill = tmpIsKill; } // Now we have swapped the operands, all we need to check is, // if the second operand (after swap) is the feeder. // And if it is, make a note. if (feederReg == (unsigned)cmpOp2) isSecondOpNewified = true; } // Now that we are moving feeder close the jump, // make sure we are respecting the kill values of // the operands of the feeder. bool updatedIsKill = false; for (unsigned i = 0; i < MI.getNumOperands(); i++) { MachineOperand &MO = MI.getOperand(i); if (MO.isReg() && MO.isUse()) { unsigned feederReg = MO.getReg(); for (MachineBasicBlock::iterator localII = feederPos, end = jmpPos; localII != end; localII++) { MachineInstr &localMI = *localII; for (unsigned j = 0; j < localMI.getNumOperands(); j++) { MachineOperand &localMO = localMI.getOperand(j); if (localMO.isReg() && localMO.isUse() && localMO.isKill() && feederReg == localMO.getReg()) { // We found that there is kill of a use register // Set up a kill flag on the register localMO.setIsKill(false); MO.setIsKill(); updatedIsKill = true; break; } } if (updatedIsKill) break; } } if (updatedIsKill) break; } MBB->splice(jmpPos, MI.getParent(), MI); MBB->splice(jmpPos, MI.getParent(), cmpInstr); DebugLoc dl = MI.getDebugLoc(); MachineInstr *NewMI; assert((isNewValueJumpCandidate(*cmpInstr)) && "This compare is not a New Value Jump candidate."); unsigned opc = getNewValueJumpOpcode(cmpInstr, cmpOp2, isSecondOpNewified, jmpTarget, MBPI); if (invertPredicate) opc = QII->getInvertedPredicatedOpcode(opc); if (isSecondOpReg) NewMI = BuildMI(*MBB, jmpPos, dl, QII->get(opc)) .addReg(cmpReg1, getKillRegState(MO1IsKill)) .addReg(cmpOp2, getKillRegState(MO2IsKill)) .addMBB(jmpTarget); else if ((cmpInstr->getOpcode() == Hexagon::C2_cmpeqi || cmpInstr->getOpcode() == Hexagon::C2_cmpgti) && cmpOp2 == -1 ) // Corresponding new-value compare jump instructions don't have the // operand for -1 immediate value. NewMI = BuildMI(*MBB, jmpPos, dl, QII->get(opc)) .addReg(cmpReg1, getKillRegState(MO1IsKill)) .addMBB(jmpTarget); else NewMI = BuildMI(*MBB, jmpPos, dl, QII->get(opc)) .addReg(cmpReg1, getKillRegState(MO1IsKill)) .addImm(cmpOp2) .addMBB(jmpTarget); assert(NewMI && "New Value Jump Instruction Not created!"); (void)NewMI; if (cmpInstr->getOperand(0).isReg() && cmpInstr->getOperand(0).isKill()) cmpInstr->getOperand(0).setIsKill(false); if (cmpInstr->getOperand(1).isReg() && cmpInstr->getOperand(1).isKill()) cmpInstr->getOperand(1).setIsKill(false); cmpInstr->eraseFromParent(); jmpInstr->eraseFromParent(); ++nvjGenerated; ++NumNVJGenerated; break; } } } } return true; }
bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Register Stackifying **********\n" "********** Function: " << MF.getName() << '\n'); bool Changed = false; MachineRegisterInfo &MRI = MF.getRegInfo(); WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); assert(MRI.isSSA() && "RegStackify depends on SSA form"); // Walk the instructions from the bottom up. Currently we don't look past // block boundaries, and the blocks aren't ordered so the block visitation // order isn't significant, but we may want to change this in the future. for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : reverse(MBB)) { MachineInstr *Insert = &MI; // Don't nest anything inside a phi. if (Insert->getOpcode() == TargetOpcode::PHI) break; // Don't nest anything inside an inline asm, because we don't have // constraints for $push inputs. if (Insert->getOpcode() == TargetOpcode::INLINEASM) break; // Iterate through the inputs in reverse order, since we'll be pulling // operands off the stack in LIFO order. bool AnyStackified = false; for (MachineOperand &Op : reverse(Insert->uses())) { // We're only interested in explicit virtual register operands. if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) continue; unsigned Reg = Op.getReg(); if (TargetRegisterInfo::isPhysicalRegister(Reg)) { // An instruction with a physical register. Conservatively mark it as // an expression stack input so that it isn't reordered with anything // in an expression stack which might use it (physical registers // aren't in SSA form so it's not trivial to determine this). // TODO: Be less conservative. ImposeStackInputOrdering(Insert); continue; } // Only consider registers with a single definition. // TODO: Eventually we may relax this, to stackify phi transfers. MachineInstr *Def = MRI.getVRegDef(Reg); if (!Def) continue; // There's no use in nesting implicit defs inside anything. if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) continue; // Don't nest an INLINE_ASM def into anything, because we don't have // constraints for $pop outputs. if (Def->getOpcode() == TargetOpcode::INLINEASM) continue; // Don't nest PHIs inside of anything. if (Def->getOpcode() == TargetOpcode::PHI) continue; // Argument instructions represent live-in registers and not real // instructions. if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || Def->getOpcode() == WebAssembly::ARGUMENT_I64 || Def->getOpcode() == WebAssembly::ARGUMENT_F32 || Def->getOpcode() == WebAssembly::ARGUMENT_F64) continue; // Single-use expression trees require defs that have one use. // TODO: Eventually we'll relax this, to take advantage of set_local // returning its result. if (!MRI.hasOneUse(Reg)) continue; // For now, be conservative and don't look across block boundaries. // TODO: Be more aggressive. if (Def->getParent() != &MBB) continue; // Don't move instructions that have side effects or memory dependencies // or other complications. if (!IsSafeToMove(Def, Insert, AA)) continue; Changed = true; AnyStackified = true; // Move the def down and nest it in the current instruction. MBB.insert(MachineBasicBlock::instr_iterator(Insert), Def->removeFromParent()); MFI.stackifyVReg(Reg); ImposeStackOrdering(Def, MRI); Insert = Def; } if (AnyStackified) ImposeStackOrdering(&MI, MRI); } } // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere // so that it never looks like a use-before-def. if (Changed) { MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); for (MachineBasicBlock &MBB : MF) MBB.addLiveIn(WebAssembly::EXPR_STACK); } #ifndef NDEBUG // Verify that pushes and pops are performed in FIFO order. SmallVector<unsigned, 0> Stack; for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { for (MachineOperand &MO : reverse(MI.explicit_operands())) { if (!MO.isReg()) continue; unsigned VReg = MO.getReg(); // Don't stackify physregs like SP or FP. if (!TargetRegisterInfo::isVirtualRegister(VReg)) continue; if (MFI.isVRegStackified(VReg)) { if (MO.isDef()) Stack.push_back(VReg); else assert(Stack.pop_back_val() == VReg); } } } // TODO: Generalize this code to support keeping values on the stack across // basic block boundaries. assert(Stack.empty()); } #endif return Changed; }
/// Insert epilog code into the function. /// For ARC, this inserts a call to a function that restores callee saved /// registers onto the stack, when enough callee saved registers are required. void ARCFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n"); auto *AFI = MF.getInfo<ARCFunctionInfo>(); const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); MachineFrameInfo &MFI = MF.getFrameInfo(); uint64_t StackSize = MF.getFrameInfo().getStackSize(); bool SavedBlink = false; unsigned AmountAboveFunclet = 0; // If we have variable sized frame objects, then we have to move // the stack pointer to a known spot (fp - StackSize). // Then, replace the frame pointer by (new) [sp,StackSize-4]. // Then, move the stack pointer the rest of the way (sp = sp + StackSize). if (hasFP(MF)) { BuildMI(MBB, MBBI, DebugLoc(), TII->get(ARC::SUB_rru6), ARC::SP) .addReg(ARC::FP) .addImm(StackSize); AmountAboveFunclet += 4; } // Now, move the stack pointer to the bottom of the save area for the funclet. const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); unsigned Last = determineLastCalleeSave(CSI); unsigned StackSlotsUsedByFunclet = 0; // Now, restore the callee save registers. if (UseSaveRestoreFunclet && Last > ARC::R14) { // BL to __ld_r13_to_<TRI->getRegAsmName()> StackSlotsUsedByFunclet = Last - ARC::R12; AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1); SavedBlink = true; } if (MFI.hasCalls() && !SavedBlink) { AmountAboveFunclet += 4; SavedBlink = true; } // Move the stack pointer up to the point of the funclet. if (StackSize - AmountAboveFunclet) { BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) .addReg(ARC::SP) .addReg(ARC::SP) .addImm(StackSize - AmountAboveFunclet); } if (StackSlotsUsedByFunclet) { BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL)) .addExternalSymbol(load_funclet_name[Last - ARC::R15]) .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) .addReg(ARC::SP) .addReg(ARC::SP) .addImm(4 * (StackSlotsUsedByFunclet)); } // Now, pop blink if necessary. if (SavedBlink) { BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK)); } // Now, pop fp if necessary. if (hasFP(MF)) { BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9)) .addReg(ARC::SP, RegState::Define) .addReg(ARC::FP, RegState::Define) .addReg(ARC::SP) .addImm(4); } // Relieve the varargs area if necessary. if (MF.getFunction().isVarArg()) { // Add in the varargs area here first. LLVM_DEBUG(dbgs() << "Varargs\n"); unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6)) .addReg(ARC::SP) .addReg(ARC::SP) .addImm(VarArgsBytes); } }
bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { auto It = Functions.find(MF.getName()); if (It == Functions.end()) return error(Twine("no machine function information for function '") + MF.getName() + "' in the MIR file"); // TODO: Recreate the machine function. const yaml::MachineFunction &YamlMF = *It->getValue(); if (YamlMF.Alignment) MF.setAlignment(YamlMF.Alignment); MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasInlineAsm(YamlMF.HasInlineAsm); PerFunctionMIParsingState PFS; if (initializeRegisterInfo(MF, YamlMF, PFS)) return true; if (!YamlMF.Constants.empty()) { auto *ConstantPool = MF.getConstantPool(); assert(ConstantPool && "Constant pool must be created"); if (initializeConstantPool(*ConstantPool, YamlMF, MF, PFS.ConstantPoolSlots)) return true; } const auto &F = *MF.getFunction(); for (const auto &YamlMBB : YamlMF.BasicBlocks) { const BasicBlock *BB = nullptr; const yaml::StringValue &Name = YamlMBB.Name; const yaml::StringValue &IRBlock = YamlMBB.IRBlock; if (!Name.Value.empty()) { BB = dyn_cast_or_null<BasicBlock>( F.getValueSymbolTable().lookup(Name.Value)); if (!BB) return error(Name.SourceRange.Start, Twine("basic block '") + Name.Value + "' is not defined in the function '" + MF.getName() + "'"); } if (!IRBlock.Value.empty()) { // TODO: Report an error when both name and ir block are specified. SMDiagnostic Error; if (parseIRBlockReference(BB, SM, MF, IRBlock.Value, PFS, IRSlots, Error)) return error(Error, IRBlock.SourceRange); } auto *MBB = MF.CreateMachineBasicBlock(BB); MF.insert(MF.end(), MBB); bool WasInserted = PFS.MBBSlots.insert(std::make_pair(YamlMBB.ID, MBB)).second; if (!WasInserted) return error(Twine("redefinition of machine basic block with id #") + Twine(YamlMBB.ID)); } if (YamlMF.BasicBlocks.empty()) return error(Twine("machine function '") + Twine(MF.getName()) + "' requires at least one machine basic block in its body"); // Initialize the frame information after creating all the MBBs so that the // MBB references in the frame information can be resolved. if (initializeFrameInfo(MF, YamlMF, PFS)) return true; // Initialize the jump table after creating all the MBBs so that the MBB // references can be resolved. if (!YamlMF.JumpTableInfo.Entries.empty() && initializeJumpTableInfo(MF, YamlMF.JumpTableInfo, PFS)) return true; // Initialize the machine basic blocks after creating them all so that the // machine instructions parser can resolve the MBB references. unsigned I = 0; for (const auto &YamlMBB : YamlMF.BasicBlocks) { if (initializeMachineBasicBlock(MF, *MF.getBlockNumbered(I++), YamlMBB, PFS)) return true; } // FIXME: This is a temporary workaround until the reserved registers can be // serialized. MF.getRegInfo().freezeReservedRegs(MF); MF.verify(); return false; }
bool RegAllocPBQP::runOnMachineFunction(MachineFunction &MF) { LiveIntervals &LIS = getAnalysis<LiveIntervals>(); MachineBlockFrequencyInfo &MBFI = getAnalysis<MachineBlockFrequencyInfo>(); calculateSpillWeightsAndHints(LIS, MF, getAnalysis<MachineLoopInfo>(), MBFI); VirtRegMap &VRM = getAnalysis<VirtRegMap>(); std::unique_ptr<Spiller> VRegSpiller(createInlineSpiller(*this, MF, VRM)); MF.getRegInfo().freezeReservedRegs(MF); DEBUG(dbgs() << "PBQP Register Allocating for " << MF.getName() << "\n"); // Allocator main loop: // // * Map current regalloc problem to a PBQP problem // * Solve the PBQP problem // * Map the solution back to a register allocation // * Spill if necessary // // This process is continued till no more spills are generated. // Find the vreg intervals in need of allocation. findVRegIntervalsToAlloc(MF, LIS); #ifndef NDEBUG const Function &F = *MF.getFunction(); std::string FullyQualifiedName = F.getParent()->getModuleIdentifier() + "." + F.getName().str(); #endif // If there are non-empty intervals allocate them using pbqp. if (!VRegsToAlloc.empty()) { const TargetSubtargetInfo &Subtarget = *MF.getTarget().getSubtargetImpl(); std::unique_ptr<PBQPRAConstraintList> ConstraintsRoot = llvm::make_unique<PBQPRAConstraintList>(); ConstraintsRoot->addConstraint(llvm::make_unique<SpillCosts>()); ConstraintsRoot->addConstraint(llvm::make_unique<Interference>()); if (PBQPCoalescing) ConstraintsRoot->addConstraint(llvm::make_unique<Coalescing>()); ConstraintsRoot->addConstraint(Subtarget.getCustomPBQPConstraints()); bool PBQPAllocComplete = false; unsigned Round = 0; while (!PBQPAllocComplete) { DEBUG(dbgs() << " PBQP Regalloc round " << Round << ":\n"); PBQPRAGraph G(PBQPRAGraph::GraphMetadata(MF, LIS, MBFI)); initializeGraph(G); ConstraintsRoot->apply(G); #ifndef NDEBUG if (PBQPDumpGraphs) { std::ostringstream RS; RS << Round; std::string GraphFileName = FullyQualifiedName + "." + RS.str() + ".pbqpgraph"; std::error_code EC; raw_fd_ostream OS(GraphFileName, EC, sys::fs::F_Text); DEBUG(dbgs() << "Dumping graph for round " << Round << " to \"" << GraphFileName << "\"\n"); G.dumpToStream(OS); } #endif PBQP::Solution Solution = PBQP::RegAlloc::solve(G); PBQPAllocComplete = mapPBQPToRegAlloc(G, Solution, VRM, *VRegSpiller); ++Round; } } // Finalise allocation, allocate empty ranges. finalizeAlloc(MF, LIS, VRM); VRegsToAlloc.clear(); EmptyIntervalVRegs.clear(); DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << VRM << "\n"); return true; }
bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** Lowering br_unless **********\n" "********** Function: " << MF.getName() << '\n'); auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); auto &MRI = MF.getRegInfo(); for (auto &MBB : MF) { for (auto MII = MBB.begin(); MII != MBB.end();) { MachineInstr *MI = &*MII++; if (MI->getOpcode() != WebAssembly::BR_UNLESS) continue; unsigned Cond = MI->getOperand(1).getReg(); bool Inverted = false; // Attempt to invert the condition in place. if (MFI.isVRegStackified(Cond)) { assert(MRI.hasOneDef(Cond)); MachineInstr *Def = MRI.getVRegDef(Cond); switch (Def->getOpcode()) { using namespace WebAssembly; case EQ_I32: Def->setDesc(TII.get(NE_I32)); Inverted = true; break; case NE_I32: Def->setDesc(TII.get(EQ_I32)); Inverted = true; break; case GT_S_I32: Def->setDesc(TII.get(LE_S_I32)); Inverted = true; break; case GE_S_I32: Def->setDesc(TII.get(LT_S_I32)); Inverted = true; break; case LT_S_I32: Def->setDesc(TII.get(GE_S_I32)); Inverted = true; break; case LE_S_I32: Def->setDesc(TII.get(GT_S_I32)); Inverted = true; break; case GT_U_I32: Def->setDesc(TII.get(LE_U_I32)); Inverted = true; break; case GE_U_I32: Def->setDesc(TII.get(LT_U_I32)); Inverted = true; break; case LT_U_I32: Def->setDesc(TII.get(GE_U_I32)); Inverted = true; break; case LE_U_I32: Def->setDesc(TII.get(GT_U_I32)); Inverted = true; break; case EQ_I64: Def->setDesc(TII.get(NE_I64)); Inverted = true; break; case NE_I64: Def->setDesc(TII.get(EQ_I64)); Inverted = true; break; case GT_S_I64: Def->setDesc(TII.get(LE_S_I64)); Inverted = true; break; case GE_S_I64: Def->setDesc(TII.get(LT_S_I64)); Inverted = true; break; case LT_S_I64: Def->setDesc(TII.get(GE_S_I64)); Inverted = true; break; case LE_S_I64: Def->setDesc(TII.get(GT_S_I64)); Inverted = true; break; case GT_U_I64: Def->setDesc(TII.get(LE_U_I64)); Inverted = true; break; case GE_U_I64: Def->setDesc(TII.get(LT_U_I64)); Inverted = true; break; case LT_U_I64: Def->setDesc(TII.get(GE_U_I64)); Inverted = true; break; case LE_U_I64: Def->setDesc(TII.get(GT_U_I64)); Inverted = true; break; case EQ_F32: Def->setDesc(TII.get(NE_F32)); Inverted = true; break; case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break; case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break; case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break; default: break; } } // If we weren't able to invert the condition in place. Insert an // expression to invert it. if (!Inverted) { unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); MFI.stackifyVReg(Tmp); BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp) .addReg(Cond); Cond = Tmp; Inverted = true; } // The br_unless condition has now been inverted. Insert a br_if and // delete the br_unless. assert(Inverted); BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF)) .addOperand(MI->getOperand(0)) .addReg(Cond); MBB.erase(MI); } } return true; }
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract /// frame indexes with appropriate references. /// bool PEI::runOnMachineFunction(MachineFunction &Fn) { const Function* F = Fn.getFunction(); const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering(); assert(!Fn.getRegInfo().getNumVirtRegs() && "Regalloc must assign all vregs"); RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : NULL; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn); // Calculate the MaxCallFrameSize and AdjustsStack variables for the // function's frame information. Also eliminates call frame pseudo // instructions. calculateCallsInformation(Fn); // Allow the target machine to make some adjustments to the function // e.g. UsedPhysRegs before calculateCalleeSavedRegisters. TFI->processFunctionBeforeCalleeSavedScan(Fn, RS); // Scan the function for modified callee saved registers and insert spill code // for any callee saved registers that are modified. calculateCalleeSavedRegisters(Fn); // Determine placement of CSR spill/restore code: // - With shrink wrapping, place spills and restores to tightly // enclose regions in the Machine CFG of the function where // they are used. // - Without shink wrapping (default), place all spills in the // entry block, all restores in return blocks. placeCSRSpillsAndRestores(Fn); // Add the code to save and restore the callee saved registers if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Attribute::Naked)) insertCSRSpillsAndRestores(Fn); // Allow the target machine to make final modifications to the function // before the frame layout is finalized. TFI->processFunctionBeforeFrameFinalized(Fn, RS); // Calculate actual frame offsets for all abstract stack objects... calculateFrameObjectOffsets(Fn); // Add prolog and epilog code to the function. This function is required // to align the stack frame as necessary for any stack variables or // called functions. Because of this, calculateCalleeSavedRegisters() // must be called before this function in order to set the AdjustsStack // and MaxCallFrameSize variables. if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex, Attribute::Naked)) insertPrologEpilogCode(Fn); // Replace all MO_FrameIndex operands with physical register references // and actual offsets. // replaceFrameIndices(Fn); // If register scavenging is needed, as we've enabled doing it as a // post-pass, scavenge the virtual registers that frame index elimiation // inserted. if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) scavengeFrameVirtualRegs(Fn); // Clear any vregs created by virtual scavenging. Fn.getRegInfo().clearVirtRegs(); // Warn on stack size when we exceeds the given limit. MachineFrameInfo *MFI = Fn.getFrameInfo(); if (WarnStackSize.getNumOccurrences() > 0 && WarnStackSize < MFI->getStackSize()) errs() << "warning: Stack size limit exceeded (" << MFI->getStackSize() << ") in " << Fn.getName() << ".\n"; delete RS; clearAllSets(); return true; }
bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction()) || MF.empty() || !isShrinkWrapEnabled(MF)) return false; LLVM_DEBUG(dbgs() << "**** Analysing " << MF.getName() << '\n'); init(MF); ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin()); if (containsIrreducibleCFG<MachineBasicBlock *>(RPOT, *MLI)) { // If MF is irreducible, a block may be in a loop without // MachineLoopInfo reporting it. I.e., we may use the // post-dominance property in loops, which lead to incorrect // results. Moreover, we may miss that the prologue and // epilogue are not in the same loop, leading to unbalanced // construction/deconstruction of the stack frame. LLVM_DEBUG(dbgs() << "Irreducible CFGs are not supported yet\n"); return false; } const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); std::unique_ptr<RegScavenger> RS( TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr); for (MachineBasicBlock &MBB : MF) { LLVM_DEBUG(dbgs() << "Look into: " << MBB.getNumber() << ' ' << MBB.getName() << '\n'); if (MBB.isEHFuncletEntry()) { LLVM_DEBUG(dbgs() << "EH Funclets are not supported yet.\n"); return false; } if (MBB.isEHPad()) { // Push the prologue and epilogue outside of // the region that may throw by making sure // that all the landing pads are at least at the // boundary of the save and restore points. // The problem with exceptions is that the throw // is not properly modeled and in particular, a // basic block can jump out from the middle. updateSaveRestorePoints(MBB, RS.get()); if (!ArePointsInteresting()) { LLVM_DEBUG(dbgs() << "EHPad prevents shrink-wrapping\n"); return false; } continue; } for (const MachineInstr &MI : MBB) { if (!useOrDefCSROrFI(MI, RS.get())) continue; // Save (resp. restore) point must dominate (resp. post dominate) // MI. Look for the proper basic block for those. updateSaveRestorePoints(MBB, RS.get()); // If we are at a point where we cannot improve the placement of // save/restore instructions, just give up. if (!ArePointsInteresting()) { LLVM_DEBUG(dbgs() << "No Shrink wrap candidate found\n"); return false; } // No need to look for other instructions, this basic block // will already be part of the handled region. break; } } if (!ArePointsInteresting()) { // If the points are not interesting at this point, then they must be null // because it means we did not encounter any frame/CSR related code. // Otherwise, we would have returned from the previous loop. assert(!Save && !Restore && "We miss a shrink-wrap opportunity?!"); LLVM_DEBUG(dbgs() << "Nothing to shrink-wrap\n"); return false; } LLVM_DEBUG(dbgs() << "\n ** Results **\nFrequency of the Entry: " << EntryFreq << '\n'); const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); do { LLVM_DEBUG(dbgs() << "Shrink wrap candidates (#, Name, Freq):\nSave: " << Save->getNumber() << ' ' << Save->getName() << ' ' << MBFI->getBlockFreq(Save).getFrequency() << "\nRestore: " << Restore->getNumber() << ' ' << Restore->getName() << ' ' << MBFI->getBlockFreq(Restore).getFrequency() << '\n'); bool IsSaveCheap, TargetCanUseSaveAsPrologue = false; if (((IsSaveCheap = EntryFreq >= MBFI->getBlockFreq(Save).getFrequency()) && EntryFreq >= MBFI->getBlockFreq(Restore).getFrequency()) && ((TargetCanUseSaveAsPrologue = TFI->canUseAsPrologue(*Save)) && TFI->canUseAsEpilogue(*Restore))) break; LLVM_DEBUG( dbgs() << "New points are too expensive or invalid for the target\n"); MachineBasicBlock *NewBB; if (!IsSaveCheap || !TargetCanUseSaveAsPrologue) { Save = FindIDom<>(*Save, Save->predecessors(), *MDT); if (!Save) break; NewBB = Save; } else { // Restore is expensive. Restore = FindIDom<>(*Restore, Restore->successors(), *MPDT); if (!Restore) break; NewBB = Restore; } updateSaveRestorePoints(*NewBB, RS.get()); } while (Save && Restore); if (!ArePointsInteresting()) { ++NumCandidatesDropped; return false; } LLVM_DEBUG(dbgs() << "Final shrink wrap candidates:\nSave: " << Save->getNumber() << ' ' << Save->getName() << "\nRestore: " << Restore->getNumber() << ' ' << Restore->getName() << '\n'); MachineFrameInfo &MFI = MF.getFrameInfo(); MFI.setSavePoint(Save); MFI.setRestorePoint(Restore); ++NumCandidates; return false; }
bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n" << "********** Function: " << MF.getName() << '\n'); TII = MF.getSubtarget().getInstrInfo(); DomTree = &getAnalysis<MachineDominatorTree>(); MRI = &MF.getRegInfo(); bool Changed = false; // Visit blocks in dominator tree pre-order. The pre-order enables multiple // cmp-conversions from the same head block. // Note that updateDomTree() modifies the children of the DomTree node // currently being visited. The df_iterator supports that; it doesn't look at // child_begin() / child_end() until after a node has been visited. for (MachineDomTreeNode *I : depth_first(DomTree)) { MachineBasicBlock *HBB = I->getBlock(); SmallVector<MachineOperand, 4> HeadCond; MachineBasicBlock *TBB = nullptr, *FBB = nullptr; if (TII->AnalyzeBranch(*HBB, TBB, FBB, HeadCond)) { continue; } // Equivalence check is to skip loops. if (!TBB || TBB == HBB) { continue; } SmallVector<MachineOperand, 4> TrueCond; MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr; if (TII->AnalyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) { continue; } MachineInstr *HeadCmpMI = findSuitableCompare(HBB); if (!HeadCmpMI) { continue; } MachineInstr *TrueCmpMI = findSuitableCompare(TBB); if (!TrueCmpMI) { continue; } AArch64CC::CondCode HeadCmp; if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) { continue; } AArch64CC::CondCode TrueCmp; if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) { continue; } const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm(); const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm(); DEBUG(dbgs() << "Head branch:\n"); DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp) << '\n'); DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n'); DEBUG(dbgs() << "True branch:\n"); DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp) << '\n'); DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n'); if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::LT) || (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::GT)) && std::abs(TrueImm - HeadImm) == 2) { // This branch transforms machine instructions that correspond to // // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...) // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...) // // into // // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...) // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...) CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp); CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp); if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) && std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) { modifyCmp(HeadCmpMI, HeadCmpInfo); modifyCmp(TrueCmpMI, TrueCmpInfo); Changed = true; } } else if (((HeadCmp == AArch64CC::GT && TrueCmp == AArch64CC::GT) || (HeadCmp == AArch64CC::LT && TrueCmp == AArch64CC::LT)) && std::abs(TrueImm - HeadImm) == 1) { // This branch transforms machine instructions that correspond to // // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...) // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...) // // into // // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...) // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...) // GT -> GE transformation increases immediate value, so picking the // smaller one; LT -> LE decreases immediate value so invert the choice. bool adjustHeadCond = (HeadImm < TrueImm); if (HeadCmp == AArch64CC::LT) { adjustHeadCond = !adjustHeadCond; } if (adjustHeadCond) { Changed |= adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm); } else { Changed |= adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm); } } // Other transformation cases almost never occur due to generation of < or > // comparisons instead of <= and >=. } return Changed; }
/// Insert prolog code into the function. /// For ARC, this inserts a call to a function that puts required callee saved /// registers onto the stack, when enough callee saved registers are required. void ARCFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n"); auto *AFI = MF.getInfo<ARCFunctionInfo>(); MachineModuleInfo &MMI = MF.getMMI(); MCContext &Context = MMI.getContext(); const MCRegisterInfo *MRI = Context.getRegisterInfo(); const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc dl; MachineFrameInfo &MFI = MF.getFrameInfo(); const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); unsigned Last = determineLastCalleeSave(CSI); unsigned StackSlotsUsedByFunclet = 0; bool SavedBlink = false; unsigned AlreadyAdjusted = 0; if (MF.getFunction().isVarArg()) { // Add in the varargs area here first. LLVM_DEBUG(dbgs() << "Varargs\n"); unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex()); BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6)) .addReg(ARC::SP) .addReg(ARC::SP) .addImm(VarArgsBytes); } if (hasFP(MF)) { LLVM_DEBUG(dbgs() << "Saving FP\n"); BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9)) .addReg(ARC::SP, RegState::Define) .addReg(ARC::FP) .addReg(ARC::SP) .addImm(-4); AlreadyAdjusted += 4; } if (UseSaveRestoreFunclet && Last > ARC::R14) { LLVM_DEBUG(dbgs() << "Creating store funclet.\n"); // BL to __save_r13_to_<TRI->getRegAsmName()> StackSlotsUsedByFunclet = Last - ARC::R12; BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6)) .addReg(ARC::SP) .addReg(ARC::SP) .addImm(4 * StackSlotsUsedByFunclet); BuildMI(MBB, MBBI, dl, TII->get(ARC::BL)) .addExternalSymbol(store_funclet_name[Last - ARC::R15]) .addReg(ARC::BLINK, RegState::Implicit | RegState::Kill); AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1); SavedBlink = true; } // If we haven't saved BLINK, but we need to...do that now. if (MFI.hasCalls() && !SavedBlink) { LLVM_DEBUG(dbgs() << "Creating save blink.\n"); BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK)); AlreadyAdjusted += 4; } if (AFI->MaxCallStackReq > 0) MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq); // We have already saved some of the stack... LLVM_DEBUG(dbgs() << "Adjusting stack by: " << (MFI.getStackSize() - AlreadyAdjusted) << "\n"); generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl, -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP); if (hasFP(MF)) { LLVM_DEBUG(dbgs() << "Setting FP from SP.\n"); BuildMI(MBB, MBBI, dl, TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6 : ARC::ADD_rrlimm), ARC::FP) .addReg(ARC::SP) .addImm(MFI.getStackSize()); } // Emit CFI records: // .cfi_def_cfa_offset StackSize // .cfi_offset fp, -StackSize // .cfi_offset blink, -StackSize+4 unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); int CurOffset = -4; if (hasFP(MF)) { CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset)); BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); CurOffset -= 4; } if (MFI.hasCalls()) { CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset)); BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } // CFI for the rest of the registers. for (const auto &Entry : CSI) { unsigned Reg = Entry.getReg(); int FI = Entry.getFrameIdx(); // Skip BLINK and FP. if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK)) continue; CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI))); BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } }