1 //===------- RISCVPushPopOptimizer.cpp - RISC-V Push/Pop opt. pass --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a pass that replaces Zcmp POP instructions with 10 // POPRET[Z] where possible. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "RISCVInstrInfo.h" 15 #include "RISCVMachineFunctionInfo.h" 16 17 using namespace llvm; 18 19 #define RISCV_PUSH_POP_OPT_NAME "RISC-V Zcmp Push/Pop optimization pass" 20 21 namespace { 22 struct RISCVPushPopOpt : public MachineFunctionPass { 23 static char ID; 24 25 RISCVPushPopOpt() : MachineFunctionPass(ID) {} 26 27 const RISCVInstrInfo *TII; 28 const TargetRegisterInfo *TRI; 29 30 // Track which register units have been modified and used. 31 LiveRegUnits ModifiedRegUnits, UsedRegUnits; 32 33 bool usePopRet(MachineBasicBlock::iterator &MBBI, 34 MachineBasicBlock::iterator &NextI, bool IsReturnZero); 35 bool adjustRetVal(MachineBasicBlock::iterator &MBBI); 36 bool runOnMachineFunction(MachineFunction &Fn) override; 37 38 StringRef getPassName() const override { return RISCV_PUSH_POP_OPT_NAME; } 39 }; 40 41 char RISCVPushPopOpt::ID = 0; 42 43 } // end of anonymous namespace 44 45 INITIALIZE_PASS(RISCVPushPopOpt, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME, 46 false, false) 47 48 // Check if POP instruction was inserted into the MBB and return iterator to it. 49 static MachineBasicBlock::iterator containsPop(MachineBasicBlock &MBB) { 50 for (MachineBasicBlock::iterator MBBI = MBB.begin(); MBBI != MBB.end(); 51 MBBI = next_nodbg(MBBI, MBB.end())) 52 if (MBBI->getOpcode() == RISCV::CM_POP) 53 return MBBI; 54 55 return MBB.end(); 56 } 57 58 bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator &MBBI, 59 MachineBasicBlock::iterator &NextI, 60 bool IsReturnZero) { 61 // Since Pseudo instruction lowering happen later in the pipeline, 62 // this will detect all ret instruction. 63 DebugLoc DL = NextI->getDebugLoc(); 64 unsigned Opc = IsReturnZero ? RISCV::CM_POPRETZ : RISCV::CM_POPRET; 65 MachineInstrBuilder PopRetBuilder = 66 BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc)) 67 .add(MBBI->getOperand(0)) 68 .add(MBBI->getOperand(1)); 69 70 // Copy over the variable implicit uses and defs from the CM_POP. They depend 71 // on what register list has been picked during frame lowering. 72 const MCInstrDesc &PopDesc = MBBI->getDesc(); 73 unsigned FirstNonDeclaredOp = PopDesc.getNumOperands() + 74 PopDesc.NumImplicitUses + 75 PopDesc.NumImplicitDefs; 76 for (unsigned i = FirstNonDeclaredOp; i < MBBI->getNumOperands(); ++i) 77 PopRetBuilder.add(MBBI->getOperand(i)); 78 79 MBBI->eraseFromParent(); 80 NextI->eraseFromParent(); 81 return true; 82 } 83 84 // Search for last assignment to a0 and if possible use ret_val slot of POP to 85 // store return value. 86 bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator &MBBI) { 87 MachineBasicBlock::reverse_iterator RE = MBBI->getParent()->rend(); 88 // Track which register units have been modified and used between the POP 89 // insn and the last assignment to register a0. 90 ModifiedRegUnits.clear(); 91 UsedRegUnits.clear(); 92 // Since POP instruction is in Epilogue no normal instructions will follow 93 // after it. Therefore search only previous ones to find the return value. 94 for (MachineBasicBlock::reverse_iterator I = 95 next_nodbg(MBBI.getReverse(), RE); 96 I != RE; I = next_nodbg(I, RE)) { 97 MachineInstr &MI = *I; 98 if (auto OperandPair = TII->isCopyInstrImpl(MI)) { 99 Register DestReg = OperandPair->Destination->getReg(); 100 Register Source = OperandPair->Source->getReg(); 101 if (DestReg == RISCV::X10 && Source == RISCV::X0) { 102 MI.removeFromParent(); 103 return true; 104 } 105 } 106 // Update modified / used register units. 107 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI); 108 // If a0 was modified or used, there is no possibility 109 // of using ret_val slot of POP instruction. 110 if (!ModifiedRegUnits.available(RISCV::X10) || 111 !UsedRegUnits.available(RISCV::X10)) 112 return false; 113 } 114 return false; 115 } 116 117 bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) { 118 if (skipFunction(Fn.getFunction())) 119 return false; 120 121 // If Zcmp extension is not supported, abort. 122 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>(); 123 if (!Subtarget->hasStdExtZcmp()) 124 return false; 125 126 // If frame pointer elimination has been disabled, abort to avoid breaking the 127 // ABI. 128 if (Fn.getTarget().Options.DisableFramePointerElim(Fn)) 129 return false; 130 131 TII = Subtarget->getInstrInfo(); 132 TRI = Subtarget->getRegisterInfo(); 133 // Resize the modified and used register unit trackers. We do this once 134 // per function and then clear the register units each time we determine 135 // correct return value for the POP. 136 ModifiedRegUnits.init(*TRI); 137 UsedRegUnits.init(*TRI); 138 bool Modified = false; 139 for (auto &MBB : Fn) { 140 MachineBasicBlock::iterator MBBI = containsPop(MBB); 141 MachineBasicBlock::iterator NextI = next_nodbg(MBBI, MBB.end()); 142 if (MBBI != MBB.end() && NextI != MBB.end() && 143 NextI->getOpcode() == RISCV::PseudoRET) 144 Modified |= usePopRet(MBBI, NextI, adjustRetVal(MBBI)); 145 } 146 return Modified; 147 } 148 149 /// createRISCVPushPopOptimizationPass - returns an instance of the 150 /// Push/Pop optimization pass. 151 FunctionPass *llvm::createRISCVPushPopOptimizationPass() { 152 return new RISCVPushPopOpt(); 153 } 154