11d0244aeSSameer Sahasrabuddhe //===- MachineCycleAnalysis.cpp - Compute CycleInfo for Machine IR --------===//
21d0244aeSSameer Sahasrabuddhe //
31d0244aeSSameer Sahasrabuddhe // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41d0244aeSSameer Sahasrabuddhe // See https://llvm.org/LICENSE.txt for license information.
51d0244aeSSameer Sahasrabuddhe // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61d0244aeSSameer Sahasrabuddhe //
71d0244aeSSameer Sahasrabuddhe //===----------------------------------------------------------------------===//
81d0244aeSSameer Sahasrabuddhe 
91d0244aeSSameer Sahasrabuddhe #include "llvm/CodeGen/MachineCycleAnalysis.h"
101d0244aeSSameer Sahasrabuddhe #include "llvm/ADT/GenericCycleImpl.h"
11*d7927523SChen Zheng #include "llvm/CodeGen/MachineRegisterInfo.h"
12*d7927523SChen Zheng #include "llvm/CodeGen/TargetInstrInfo.h"
13*d7927523SChen Zheng #include "llvm/CodeGen/TargetSubtargetInfo.h"
141d0244aeSSameer Sahasrabuddhe 
151d0244aeSSameer Sahasrabuddhe using namespace llvm;
161d0244aeSSameer Sahasrabuddhe 
171d0244aeSSameer Sahasrabuddhe template class llvm::GenericCycleInfo<llvm::MachineSSAContext>;
181d0244aeSSameer Sahasrabuddhe template class llvm::GenericCycle<llvm::MachineSSAContext>;
191d0244aeSSameer Sahasrabuddhe 
201d0244aeSSameer Sahasrabuddhe char MachineCycleInfoWrapperPass::ID = 0;
211d0244aeSSameer Sahasrabuddhe 
MachineCycleInfoWrapperPass()221d0244aeSSameer Sahasrabuddhe MachineCycleInfoWrapperPass::MachineCycleInfoWrapperPass()
231d0244aeSSameer Sahasrabuddhe     : MachineFunctionPass(ID) {
241d0244aeSSameer Sahasrabuddhe   initializeMachineCycleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
251d0244aeSSameer Sahasrabuddhe }
261d0244aeSSameer Sahasrabuddhe 
271d0244aeSSameer Sahasrabuddhe INITIALIZE_PASS_BEGIN(MachineCycleInfoWrapperPass, "machine-cycles",
281d0244aeSSameer Sahasrabuddhe                       "Machine Cycle Info Analysis", true, true)
291d0244aeSSameer Sahasrabuddhe INITIALIZE_PASS_END(MachineCycleInfoWrapperPass, "machine-cycles",
301d0244aeSSameer Sahasrabuddhe                     "Machine Cycle Info Analysis", true, true)
311d0244aeSSameer Sahasrabuddhe 
getAnalysisUsage(AnalysisUsage & AU) const321d0244aeSSameer Sahasrabuddhe void MachineCycleInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
331d0244aeSSameer Sahasrabuddhe   AU.setPreservesAll();
341d0244aeSSameer Sahasrabuddhe   MachineFunctionPass::getAnalysisUsage(AU);
351d0244aeSSameer Sahasrabuddhe }
361d0244aeSSameer Sahasrabuddhe 
runOnMachineFunction(MachineFunction & Func)371d0244aeSSameer Sahasrabuddhe bool MachineCycleInfoWrapperPass::runOnMachineFunction(MachineFunction &Func) {
381d0244aeSSameer Sahasrabuddhe   CI.clear();
391d0244aeSSameer Sahasrabuddhe 
401d0244aeSSameer Sahasrabuddhe   F = &Func;
411d0244aeSSameer Sahasrabuddhe   CI.compute(Func);
421d0244aeSSameer Sahasrabuddhe   return false;
431d0244aeSSameer Sahasrabuddhe }
441d0244aeSSameer Sahasrabuddhe 
print(raw_ostream & OS,const Module *) const451d0244aeSSameer Sahasrabuddhe void MachineCycleInfoWrapperPass::print(raw_ostream &OS, const Module *) const {
461d0244aeSSameer Sahasrabuddhe   OS << "MachineCycleInfo for function: " << F->getName() << "\n";
471d0244aeSSameer Sahasrabuddhe   CI.print(OS);
481d0244aeSSameer Sahasrabuddhe }
491d0244aeSSameer Sahasrabuddhe 
releaseMemory()501d0244aeSSameer Sahasrabuddhe void MachineCycleInfoWrapperPass::releaseMemory() {
511d0244aeSSameer Sahasrabuddhe   CI.clear();
521d0244aeSSameer Sahasrabuddhe   F = nullptr;
531d0244aeSSameer Sahasrabuddhe }
541d0244aeSSameer Sahasrabuddhe 
55*d7927523SChen Zheng class MachineCycleInfoPrinterPass : public MachineFunctionPass {
56*d7927523SChen Zheng public:
57*d7927523SChen Zheng   static char ID;
58*d7927523SChen Zheng 
59*d7927523SChen Zheng   MachineCycleInfoPrinterPass();
60*d7927523SChen Zheng 
61*d7927523SChen Zheng   bool runOnMachineFunction(MachineFunction &F) override;
62*d7927523SChen Zheng   void getAnalysisUsage(AnalysisUsage &AU) const override;
63*d7927523SChen Zheng };
64*d7927523SChen Zheng 
651d0244aeSSameer Sahasrabuddhe char MachineCycleInfoPrinterPass::ID = 0;
661d0244aeSSameer Sahasrabuddhe 
MachineCycleInfoPrinterPass()671d0244aeSSameer Sahasrabuddhe MachineCycleInfoPrinterPass::MachineCycleInfoPrinterPass()
681d0244aeSSameer Sahasrabuddhe     : MachineFunctionPass(ID) {
691d0244aeSSameer Sahasrabuddhe   initializeMachineCycleInfoPrinterPassPass(*PassRegistry::getPassRegistry());
701d0244aeSSameer Sahasrabuddhe }
711d0244aeSSameer Sahasrabuddhe 
721d0244aeSSameer Sahasrabuddhe INITIALIZE_PASS_BEGIN(MachineCycleInfoPrinterPass, "print-machine-cycles",
731d0244aeSSameer Sahasrabuddhe                       "Print Machine Cycle Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)741d0244aeSSameer Sahasrabuddhe INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
751d0244aeSSameer Sahasrabuddhe INITIALIZE_PASS_END(MachineCycleInfoPrinterPass, "print-machine-cycles",
761d0244aeSSameer Sahasrabuddhe                     "Print Machine Cycle Info Analysis", true, true)
771d0244aeSSameer Sahasrabuddhe 
781d0244aeSSameer Sahasrabuddhe void MachineCycleInfoPrinterPass::getAnalysisUsage(AnalysisUsage &AU) const {
791d0244aeSSameer Sahasrabuddhe   AU.setPreservesAll();
801d0244aeSSameer Sahasrabuddhe   AU.addRequired<MachineCycleInfoWrapperPass>();
811d0244aeSSameer Sahasrabuddhe   MachineFunctionPass::getAnalysisUsage(AU);
821d0244aeSSameer Sahasrabuddhe }
831d0244aeSSameer Sahasrabuddhe 
runOnMachineFunction(MachineFunction & F)841d0244aeSSameer Sahasrabuddhe bool MachineCycleInfoPrinterPass::runOnMachineFunction(MachineFunction &F) {
851d0244aeSSameer Sahasrabuddhe   auto &CI = getAnalysis<MachineCycleInfoWrapperPass>();
861d0244aeSSameer Sahasrabuddhe   CI.print(errs());
871d0244aeSSameer Sahasrabuddhe   return false;
881d0244aeSSameer Sahasrabuddhe }
89*d7927523SChen Zheng 
isCycleInvariant(const MachineCycle * Cycle,MachineInstr & I)90*d7927523SChen Zheng bool llvm::isCycleInvariant(const MachineCycle *Cycle, MachineInstr &I) {
91*d7927523SChen Zheng   MachineFunction *MF = I.getParent()->getParent();
92*d7927523SChen Zheng   MachineRegisterInfo *MRI = &MF->getRegInfo();
93*d7927523SChen Zheng   const TargetSubtargetInfo &ST = MF->getSubtarget();
94*d7927523SChen Zheng   const TargetRegisterInfo *TRI = ST.getRegisterInfo();
95*d7927523SChen Zheng   const TargetInstrInfo *TII = ST.getInstrInfo();
96*d7927523SChen Zheng 
97*d7927523SChen Zheng   // The instruction is cycle invariant if all of its operands are.
98*d7927523SChen Zheng   for (const MachineOperand &MO : I.operands()) {
99*d7927523SChen Zheng     if (!MO.isReg())
100*d7927523SChen Zheng       continue;
101*d7927523SChen Zheng 
102*d7927523SChen Zheng     Register Reg = MO.getReg();
103*d7927523SChen Zheng     if (Reg == 0)
104*d7927523SChen Zheng       continue;
105*d7927523SChen Zheng 
106*d7927523SChen Zheng     // An instruction that uses or defines a physical register can't e.g. be
107*d7927523SChen Zheng     // hoisted, so mark this as not invariant.
108*d7927523SChen Zheng     if (Register::isPhysicalRegister(Reg)) {
109*d7927523SChen Zheng       if (MO.isUse()) {
110*d7927523SChen Zheng         // If the physreg has no defs anywhere, it's just an ambient register
111*d7927523SChen Zheng         // and we can freely move its uses. Alternatively, if it's allocatable,
112*d7927523SChen Zheng         // it could get allocated to something with a def during allocation.
113*d7927523SChen Zheng         // However, if the physreg is known to always be caller saved/restored
114*d7927523SChen Zheng         // then this use is safe to hoist.
115*d7927523SChen Zheng         if (!MRI->isConstantPhysReg(Reg) &&
116*d7927523SChen Zheng             !(TRI->isCallerPreservedPhysReg(Reg.asMCReg(), *I.getMF())) &&
117*d7927523SChen Zheng             !TII->isIgnorableUse(MO))
118*d7927523SChen Zheng           return false;
119*d7927523SChen Zheng         // Otherwise it's safe to move.
120*d7927523SChen Zheng         continue;
121*d7927523SChen Zheng       } else if (!MO.isDead()) {
122*d7927523SChen Zheng         // A def that isn't dead can't be moved.
123*d7927523SChen Zheng         return false;
124*d7927523SChen Zheng       } else if (any_of(Cycle->getEntries(),
125*d7927523SChen Zheng                         [&](const MachineBasicBlock *Block) {
126*d7927523SChen Zheng                           return Block->isLiveIn(Reg);
127*d7927523SChen Zheng                         })) {
128*d7927523SChen Zheng         // If the reg is live into any header of the cycle we can't hoist an
129*d7927523SChen Zheng         // instruction which would clobber it.
130*d7927523SChen Zheng         return false;
131*d7927523SChen Zheng       }
132*d7927523SChen Zheng     }
133*d7927523SChen Zheng 
134*d7927523SChen Zheng     if (!MO.isUse())
135*d7927523SChen Zheng       continue;
136*d7927523SChen Zheng 
137*d7927523SChen Zheng     assert(MRI->getVRegDef(Reg) && "Machine instr not mapped for this vreg?!");
138*d7927523SChen Zheng 
139*d7927523SChen Zheng     // If the cycle contains the definition of an operand, then the instruction
140*d7927523SChen Zheng     // isn't cycle invariant.
141*d7927523SChen Zheng     if (Cycle->contains(MRI->getVRegDef(Reg)->getParent()))
142*d7927523SChen Zheng       return false;
143*d7927523SChen Zheng   }
144*d7927523SChen Zheng 
145*d7927523SChen Zheng   // If we got this far, the instruction is cycle invariant!
146*d7927523SChen Zheng   return true;
147*d7927523SChen Zheng }
148