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