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