14275eb13SSerguei Katkov //===-- FixupStatepointCallerSaved.cpp - Fixup caller saved registers  ----===//
24275eb13SSerguei Katkov //
34275eb13SSerguei Katkov //                     The LLVM Compiler Infrastructure
44275eb13SSerguei Katkov //
54275eb13SSerguei Katkov // This file is distributed under the University of Illinois Open Source
64275eb13SSerguei Katkov // License. See LICENSE.TXT for details.
74275eb13SSerguei Katkov //
84275eb13SSerguei Katkov //===----------------------------------------------------------------------===//
94275eb13SSerguei Katkov ///
104275eb13SSerguei Katkov /// \file
114275eb13SSerguei Katkov /// Statepoint instruction in deopt parameters contains values which are
124275eb13SSerguei Katkov /// meaningful to the runtime and should be able to be read at the moment the
134275eb13SSerguei Katkov /// call returns. So we can say that we need to encode the fact that these
144275eb13SSerguei Katkov /// values are "late read" by runtime. If we could express this notion for
154275eb13SSerguei Katkov /// register allocator it would produce the right form for us.
164275eb13SSerguei Katkov /// The need to fixup (i.e this pass) is specifically handling the fact that
174275eb13SSerguei Katkov /// we cannot describe such a late read for the register allocator.
184275eb13SSerguei Katkov /// Register allocator may put the value on a register clobbered by the call.
194275eb13SSerguei Katkov /// This pass forces the spill of such registers and replaces corresponding
204275eb13SSerguei Katkov /// statepoint operands to added spill slots.
214275eb13SSerguei Katkov ///
224275eb13SSerguei Katkov //===----------------------------------------------------------------------===//
234275eb13SSerguei Katkov 
244275eb13SSerguei Katkov #include "llvm/ADT/SmallSet.h"
254275eb13SSerguei Katkov #include "llvm/ADT/Statistic.h"
264275eb13SSerguei Katkov #include "llvm/CodeGen/MachineFrameInfo.h"
274275eb13SSerguei Katkov #include "llvm/CodeGen/MachineFunctionPass.h"
284275eb13SSerguei Katkov #include "llvm/CodeGen/MachineRegisterInfo.h"
294275eb13SSerguei Katkov #include "llvm/CodeGen/Passes.h"
304275eb13SSerguei Katkov #include "llvm/CodeGen/StackMaps.h"
314275eb13SSerguei Katkov #include "llvm/CodeGen/TargetFrameLowering.h"
324275eb13SSerguei Katkov #include "llvm/CodeGen/TargetInstrInfo.h"
334275eb13SSerguei Katkov #include "llvm/IR/Statepoint.h"
344275eb13SSerguei Katkov #include "llvm/InitializePasses.h"
354275eb13SSerguei Katkov #include "llvm/Support/Debug.h"
364275eb13SSerguei Katkov 
374275eb13SSerguei Katkov using namespace llvm;
384275eb13SSerguei Katkov 
394275eb13SSerguei Katkov #define DEBUG_TYPE "fixup-statepoint-caller-saved"
404275eb13SSerguei Katkov STATISTIC(NumSpilledRegisters, "Number of spilled register");
414275eb13SSerguei Katkov STATISTIC(NumSpillSlotsAllocated, "Number of spill slots allocated");
424275eb13SSerguei Katkov STATISTIC(NumSpillSlotsExtended, "Number of spill slots extended");
434275eb13SSerguei Katkov 
444275eb13SSerguei Katkov static cl::opt<bool> FixupSCSExtendSlotSize(
454275eb13SSerguei Katkov     "fixup-scs-extend-slot-size", cl::Hidden, cl::init(false),
464275eb13SSerguei Katkov     cl::desc("Allow spill in spill slot of greater size than register size"),
474275eb13SSerguei Katkov     cl::Hidden);
484275eb13SSerguei Katkov 
494275eb13SSerguei Katkov namespace {
504275eb13SSerguei Katkov 
514275eb13SSerguei Katkov class FixupStatepointCallerSaved : public MachineFunctionPass {
524275eb13SSerguei Katkov public:
534275eb13SSerguei Katkov   static char ID;
544275eb13SSerguei Katkov 
554275eb13SSerguei Katkov   FixupStatepointCallerSaved() : MachineFunctionPass(ID) {
564275eb13SSerguei Katkov     initializeFixupStatepointCallerSavedPass(*PassRegistry::getPassRegistry());
574275eb13SSerguei Katkov   }
584275eb13SSerguei Katkov 
594275eb13SSerguei Katkov   void getAnalysisUsage(AnalysisUsage &AU) const override {
604275eb13SSerguei Katkov     MachineFunctionPass::getAnalysisUsage(AU);
614275eb13SSerguei Katkov   }
624275eb13SSerguei Katkov 
634275eb13SSerguei Katkov   StringRef getPassName() const override {
644275eb13SSerguei Katkov     return "Fixup Statepoint Caller Saved";
654275eb13SSerguei Katkov   }
664275eb13SSerguei Katkov 
674275eb13SSerguei Katkov   bool runOnMachineFunction(MachineFunction &MF) override;
684275eb13SSerguei Katkov };
694275eb13SSerguei Katkov } // End anonymous namespace.
704275eb13SSerguei Katkov 
714275eb13SSerguei Katkov char FixupStatepointCallerSaved::ID = 0;
724275eb13SSerguei Katkov char &llvm::FixupStatepointCallerSavedID = FixupStatepointCallerSaved::ID;
734275eb13SSerguei Katkov 
744275eb13SSerguei Katkov INITIALIZE_PASS_BEGIN(FixupStatepointCallerSaved, DEBUG_TYPE,
754275eb13SSerguei Katkov                       "Fixup Statepoint Caller Saved", false, false)
764275eb13SSerguei Katkov INITIALIZE_PASS_END(FixupStatepointCallerSaved, DEBUG_TYPE,
774275eb13SSerguei Katkov                     "Fixup Statepoint Caller Saved", false, false)
784275eb13SSerguei Katkov 
794275eb13SSerguei Katkov // Utility function to get size of the register.
804275eb13SSerguei Katkov static unsigned getRegisterSize(const TargetRegisterInfo &TRI, Register Reg) {
814275eb13SSerguei Katkov   const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
824275eb13SSerguei Katkov   return TRI.getSpillSize(*RC);
834275eb13SSerguei Katkov }
844275eb13SSerguei Katkov 
854275eb13SSerguei Katkov // Cache used frame indexes during statepoint re-write to re-use them in
864275eb13SSerguei Katkov // processing next statepoint instruction.
874275eb13SSerguei Katkov // Two strategies. One is to preserve the size of spill slot while another one
884275eb13SSerguei Katkov // extends the size of spill slots to reduce the number of them, causing
894275eb13SSerguei Katkov // the less total frame size. But unspill will have "implicit" any extend.
904275eb13SSerguei Katkov class FrameIndexesCache {
914275eb13SSerguei Katkov private:
924275eb13SSerguei Katkov   struct FrameIndexesPerSize {
934275eb13SSerguei Katkov     // List of used frame indexes during processing previous statepoints.
944275eb13SSerguei Katkov     SmallVector<int, 8> Slots;
954275eb13SSerguei Katkov     // Current index of un-used yet frame index.
964275eb13SSerguei Katkov     unsigned Index = 0;
974275eb13SSerguei Katkov   };
984275eb13SSerguei Katkov   MachineFrameInfo &MFI;
994275eb13SSerguei Katkov   const TargetRegisterInfo &TRI;
1004275eb13SSerguei Katkov   // Map size to list of frame indexes of this size. If the mode is
1014275eb13SSerguei Katkov   // FixupSCSExtendSlotSize then the key 0 is used to keep all frame indexes.
1024275eb13SSerguei Katkov   // If the size of required spill slot is greater than in a cache then the
1034275eb13SSerguei Katkov   // size will be increased.
1044275eb13SSerguei Katkov   DenseMap<unsigned, FrameIndexesPerSize> Cache;
1054275eb13SSerguei Katkov 
1064275eb13SSerguei Katkov public:
1074275eb13SSerguei Katkov   FrameIndexesCache(MachineFrameInfo &MFI, const TargetRegisterInfo &TRI)
1084275eb13SSerguei Katkov       : MFI(MFI), TRI(TRI) {}
1094275eb13SSerguei Katkov   // Reset the current state of used frame indexes. After invocation of
1104275eb13SSerguei Katkov   // this function all frame indexes are available for allocation.
1114275eb13SSerguei Katkov   void reset() {
1124275eb13SSerguei Katkov     for (auto &It : Cache)
1134275eb13SSerguei Katkov       It.second.Index = 0;
1144275eb13SSerguei Katkov   }
1154275eb13SSerguei Katkov   // Get frame index to spill the register.
1164275eb13SSerguei Katkov   int getFrameIndex(Register Reg) {
1174275eb13SSerguei Katkov     unsigned Size = getRegisterSize(TRI, Reg);
1184275eb13SSerguei Katkov     // In FixupSCSExtendSlotSize mode the bucket with 0 index is used
1194275eb13SSerguei Katkov     // for all sizes.
1204275eb13SSerguei Katkov     unsigned Bucket = FixupSCSExtendSlotSize ? 0 : Size;
1214275eb13SSerguei Katkov     FrameIndexesPerSize &Line = Cache[Bucket];
1224275eb13SSerguei Katkov     if (Line.Index < Line.Slots.size()) {
1234275eb13SSerguei Katkov       int FI = Line.Slots[Line.Index++];
1244275eb13SSerguei Katkov       // If all sizes are kept together we probably need to extend the
1254275eb13SSerguei Katkov       // spill slot size.
1264275eb13SSerguei Katkov       if (MFI.getObjectSize(FI) < Size) {
1274275eb13SSerguei Katkov         MFI.setObjectSize(FI, Size);
1284275eb13SSerguei Katkov         MFI.setObjectAlignment(FI, Align(Size));
1294275eb13SSerguei Katkov         NumSpillSlotsExtended++;
1304275eb13SSerguei Katkov       }
1314275eb13SSerguei Katkov       return FI;
1324275eb13SSerguei Katkov     }
1334275eb13SSerguei Katkov     int FI = MFI.CreateSpillStackObject(Size, Size);
1344275eb13SSerguei Katkov     NumSpillSlotsAllocated++;
1354275eb13SSerguei Katkov     Line.Slots.push_back(FI);
1364275eb13SSerguei Katkov     ++Line.Index;
1374275eb13SSerguei Katkov     return FI;
1384275eb13SSerguei Katkov   }
1394275eb13SSerguei Katkov   // Sort all registers to spill in descendent order. In the
1404275eb13SSerguei Katkov   // FixupSCSExtendSlotSize mode it will minimize the total frame size.
1414275eb13SSerguei Katkov   // In non FixupSCSExtendSlotSize mode we can skip this step.
1424275eb13SSerguei Katkov   void sortRegisters(SmallVectorImpl<Register> &Regs) {
1434275eb13SSerguei Katkov     if (!FixupSCSExtendSlotSize)
1444275eb13SSerguei Katkov       return;
1454275eb13SSerguei Katkov     llvm::sort(Regs.begin(), Regs.end(), [&](Register &A, Register &B) {
1464275eb13SSerguei Katkov       return getRegisterSize(TRI, A) > getRegisterSize(TRI, B);
1474275eb13SSerguei Katkov     });
1484275eb13SSerguei Katkov   }
1494275eb13SSerguei Katkov };
1504275eb13SSerguei Katkov 
1514275eb13SSerguei Katkov // Describes the state of the current processing statepoint instruction.
1524275eb13SSerguei Katkov class StatepointState {
1534275eb13SSerguei Katkov private:
1544275eb13SSerguei Katkov   // statepoint instruction.
1554275eb13SSerguei Katkov   MachineInstr &MI;
1564275eb13SSerguei Katkov   MachineFunction &MF;
1574275eb13SSerguei Katkov   const TargetRegisterInfo &TRI;
1584275eb13SSerguei Katkov   const TargetInstrInfo &TII;
1594275eb13SSerguei Katkov   MachineFrameInfo &MFI;
1604275eb13SSerguei Katkov   // Mask with callee saved registers.
1614275eb13SSerguei Katkov   const uint32_t *Mask;
1624275eb13SSerguei Katkov   // Cache of frame indexes used on previous instruction processing.
1634275eb13SSerguei Katkov   FrameIndexesCache &CacheFI;
1644275eb13SSerguei Katkov   // Operands with physical registers requiring spilling.
1654275eb13SSerguei Katkov   SmallVector<unsigned, 8> OpsToSpill;
1664275eb13SSerguei Katkov   // Set of register to spill.
1674275eb13SSerguei Katkov   SmallVector<Register, 8> RegsToSpill;
1684275eb13SSerguei Katkov   // Map Register to Frame Slot index.
1694275eb13SSerguei Katkov   DenseMap<Register, int> RegToSlotIdx;
1704275eb13SSerguei Katkov 
1714275eb13SSerguei Katkov public:
1724275eb13SSerguei Katkov   StatepointState(MachineInstr &MI, const uint32_t *Mask,
1734275eb13SSerguei Katkov                   FrameIndexesCache &CacheFI)
1744275eb13SSerguei Katkov       : MI(MI), MF(*MI.getMF()), TRI(*MF.getSubtarget().getRegisterInfo()),
1754275eb13SSerguei Katkov         TII(*MF.getSubtarget().getInstrInfo()), MFI(MF.getFrameInfo()),
1764275eb13SSerguei Katkov         Mask(Mask), CacheFI(CacheFI) {}
1774275eb13SSerguei Katkov   // Return true if register is callee saved.
1784275eb13SSerguei Katkov   bool isCalleeSaved(Register Reg) { return (Mask[Reg / 32] >> Reg % 32) & 1; }
1794275eb13SSerguei Katkov   // Iterates over statepoint meta args to find caller saver registers.
1804275eb13SSerguei Katkov   // Also cache the size of found registers.
1814275eb13SSerguei Katkov   // Returns true if caller save registers found.
1824275eb13SSerguei Katkov   bool findRegistersToSpill() {
1834275eb13SSerguei Katkov     SmallSet<Register, 8> VisitedRegs;
1844275eb13SSerguei Katkov     for (unsigned Idx = StatepointOpers(&MI).getVarIdx(),
1854275eb13SSerguei Katkov                   EndIdx = MI.getNumOperands();
1864275eb13SSerguei Katkov          Idx < EndIdx; ++Idx) {
1874275eb13SSerguei Katkov       MachineOperand &MO = MI.getOperand(Idx);
1884275eb13SSerguei Katkov       if (!MO.isReg() || MO.isImplicit())
1894275eb13SSerguei Katkov         continue;
1904275eb13SSerguei Katkov       Register Reg = MO.getReg();
1914275eb13SSerguei Katkov       assert(Reg.isPhysical() && "Only physical regs are expected");
1924275eb13SSerguei Katkov       if (isCalleeSaved(Reg))
1934275eb13SSerguei Katkov         continue;
1944275eb13SSerguei Katkov       if (VisitedRegs.insert(Reg).second)
1954275eb13SSerguei Katkov         RegsToSpill.push_back(Reg);
1964275eb13SSerguei Katkov       OpsToSpill.push_back(Idx);
1974275eb13SSerguei Katkov     }
1984275eb13SSerguei Katkov     CacheFI.sortRegisters(RegsToSpill);
1994275eb13SSerguei Katkov     return !RegsToSpill.empty();
2004275eb13SSerguei Katkov   }
2014275eb13SSerguei Katkov   // Spill all caller saved registers right before statepoint instruction.
2024275eb13SSerguei Katkov   // Remember frame index where register is spilled.
2034275eb13SSerguei Katkov   void spillRegisters() {
2044275eb13SSerguei Katkov     for (Register Reg : RegsToSpill) {
2054275eb13SSerguei Katkov       int FI = CacheFI.getFrameIndex(Reg);
2064275eb13SSerguei Katkov       const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
2074275eb13SSerguei Katkov       TII.storeRegToStackSlot(*MI.getParent(), MI, Reg, true /*is_Kill*/, FI,
2084275eb13SSerguei Katkov                               RC, &TRI);
2094275eb13SSerguei Katkov       NumSpilledRegisters++;
2104275eb13SSerguei Katkov       RegToSlotIdx[Reg] = FI;
2114275eb13SSerguei Katkov     }
2124275eb13SSerguei Katkov   }
2134275eb13SSerguei Katkov   // Re-write statepoint machine instruction to replace caller saved operands
2144275eb13SSerguei Katkov   // with indirect memory location (frame index).
2154275eb13SSerguei Katkov   void rewriteStatepoint() {
2164275eb13SSerguei Katkov     MachineInstr *NewMI =
2174275eb13SSerguei Katkov         MF.CreateMachineInstr(TII.get(MI.getOpcode()), MI.getDebugLoc(), true);
2184275eb13SSerguei Katkov     MachineInstrBuilder MIB(MF, NewMI);
2194275eb13SSerguei Katkov 
2204275eb13SSerguei Katkov     // Add End marker.
2214275eb13SSerguei Katkov     OpsToSpill.push_back(MI.getNumOperands());
2224275eb13SSerguei Katkov     unsigned CurOpIdx = 0;
2234275eb13SSerguei Katkov 
2244275eb13SSerguei Katkov     for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
2254275eb13SSerguei Katkov       MachineOperand &MO = MI.getOperand(I);
2264275eb13SSerguei Katkov       if (I == OpsToSpill[CurOpIdx]) {
2274275eb13SSerguei Katkov         int FI = RegToSlotIdx[MO.getReg()];
2284275eb13SSerguei Katkov         MIB.addImm(StackMaps::IndirectMemRefOp);
2294275eb13SSerguei Katkov         MIB.addImm(getRegisterSize(TRI, MO.getReg()));
2304275eb13SSerguei Katkov         assert(MO.isReg() && "Should be register");
2314275eb13SSerguei Katkov         assert(MO.getReg().isPhysical() && "Should be physical register");
2324275eb13SSerguei Katkov         MIB.addFrameIndex(FI);
2334275eb13SSerguei Katkov         MIB.addImm(0);
2344275eb13SSerguei Katkov         ++CurOpIdx;
2354275eb13SSerguei Katkov       } else
2364275eb13SSerguei Katkov         MIB.add(MO);
2374275eb13SSerguei Katkov     }
2384275eb13SSerguei Katkov     assert(CurOpIdx == (OpsToSpill.size() - 1) && "Not all operands processed");
2394275eb13SSerguei Katkov     // Add mem operands.
2404275eb13SSerguei Katkov     NewMI->setMemRefs(MF, MI.memoperands());
2414275eb13SSerguei Katkov     for (auto It : RegToSlotIdx) {
2424275eb13SSerguei Katkov       int FrameIndex = It.second;
2434275eb13SSerguei Katkov       auto PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex);
2444275eb13SSerguei Katkov       auto *MMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
2454275eb13SSerguei Katkov                                           getRegisterSize(TRI, It.first),
2464275eb13SSerguei Katkov                                           MFI.getObjectAlign(FrameIndex));
2474275eb13SSerguei Katkov       NewMI->addMemOperand(MF, MMO);
2484275eb13SSerguei Katkov     }
2494275eb13SSerguei Katkov     // Insert new statepoint and erase old one.
2504275eb13SSerguei Katkov     MI.getParent()->insert(MI, NewMI);
2514275eb13SSerguei Katkov     MI.eraseFromParent();
2524275eb13SSerguei Katkov   }
2534275eb13SSerguei Katkov };
2544275eb13SSerguei Katkov 
2554275eb13SSerguei Katkov class StatepointProcessor {
2564275eb13SSerguei Katkov private:
2574275eb13SSerguei Katkov   MachineFunction &MF;
2584275eb13SSerguei Katkov   const TargetRegisterInfo &TRI;
2594275eb13SSerguei Katkov   FrameIndexesCache CacheFI;
2604275eb13SSerguei Katkov 
2614275eb13SSerguei Katkov public:
2624275eb13SSerguei Katkov   StatepointProcessor(MachineFunction &MF)
2634275eb13SSerguei Katkov       : MF(MF), TRI(*MF.getSubtarget().getRegisterInfo()),
2644275eb13SSerguei Katkov         CacheFI(MF.getFrameInfo(), TRI) {}
2654275eb13SSerguei Katkov 
2664275eb13SSerguei Katkov   bool process(MachineInstr &MI) {
267*edbb27ccSDenis Antrushin     StatepointOpers SO(&MI);
268*edbb27ccSDenis Antrushin     uint64_t Flags = SO.getFlags();
2694275eb13SSerguei Katkov     // Do nothing for LiveIn, it supports all registers.
2704275eb13SSerguei Katkov     if (Flags & (uint64_t)StatepointFlags::DeoptLiveIn)
2714275eb13SSerguei Katkov       return false;
272*edbb27ccSDenis Antrushin     CallingConv::ID CC = SO.getCallingConv();
2734275eb13SSerguei Katkov     const uint32_t *Mask = TRI.getCallPreservedMask(MF, CC);
2744275eb13SSerguei Katkov     CacheFI.reset();
2754275eb13SSerguei Katkov     StatepointState SS(MI, Mask, CacheFI);
2764275eb13SSerguei Katkov 
2774275eb13SSerguei Katkov     if (!SS.findRegistersToSpill())
2784275eb13SSerguei Katkov       return false;
2794275eb13SSerguei Katkov 
2804275eb13SSerguei Katkov     SS.spillRegisters();
2814275eb13SSerguei Katkov     SS.rewriteStatepoint();
2824275eb13SSerguei Katkov     return true;
2834275eb13SSerguei Katkov   }
2844275eb13SSerguei Katkov };
2854275eb13SSerguei Katkov 
2864275eb13SSerguei Katkov bool FixupStatepointCallerSaved::runOnMachineFunction(MachineFunction &MF) {
2874275eb13SSerguei Katkov   if (skipFunction(MF.getFunction()))
2884275eb13SSerguei Katkov     return false;
2894275eb13SSerguei Katkov 
2904275eb13SSerguei Katkov   const Function &F = MF.getFunction();
2914275eb13SSerguei Katkov   if (!F.hasGC())
2924275eb13SSerguei Katkov     return false;
2934275eb13SSerguei Katkov 
2944275eb13SSerguei Katkov   SmallVector<MachineInstr *, 16> Statepoints;
2954275eb13SSerguei Katkov   for (MachineBasicBlock &BB : MF)
2964275eb13SSerguei Katkov     for (MachineInstr &I : BB)
2974275eb13SSerguei Katkov       if (I.getOpcode() == TargetOpcode::STATEPOINT)
2984275eb13SSerguei Katkov         Statepoints.push_back(&I);
2994275eb13SSerguei Katkov 
3004275eb13SSerguei Katkov   if (Statepoints.empty())
3014275eb13SSerguei Katkov     return false;
3024275eb13SSerguei Katkov 
3034275eb13SSerguei Katkov   bool Changed = false;
3044275eb13SSerguei Katkov   StatepointProcessor SPP(MF);
3054275eb13SSerguei Katkov   for (MachineInstr *I : Statepoints)
3064275eb13SSerguei Katkov     Changed |= SPP.process(*I);
3074275eb13SSerguei Katkov   return Changed;
3084275eb13SSerguei Katkov }
309