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 BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc)) 66 .add(MBBI->getOperand(0)) 67 .add(MBBI->getOperand(1)); 68 69 MBBI->eraseFromParent(); 70 NextI->eraseFromParent(); 71 return true; 72 } 73 74 // Search for last assignment to a0 and if possible use ret_val slot of POP to 75 // store return value. 76 bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator &MBBI) { 77 MachineBasicBlock::reverse_iterator RE = MBBI->getParent()->rend(); 78 // Track which register units have been modified and used between the POP 79 // insn and the last assignment to register a0. 80 ModifiedRegUnits.clear(); 81 UsedRegUnits.clear(); 82 // Since POP instruction is in Epilogue no normal instructions will follow 83 // after it. Therefore search only previous ones to find the return value. 84 for (MachineBasicBlock::reverse_iterator I = 85 next_nodbg(MBBI.getReverse(), RE); 86 I != RE; I = next_nodbg(I, RE)) { 87 MachineInstr &MI = *I; 88 if (auto OperandPair = TII->isCopyInstrImpl(MI)) { 89 Register DestReg = OperandPair->Destination->getReg(); 90 Register Source = OperandPair->Source->getReg(); 91 if (DestReg == RISCV::X10 && Source == RISCV::X0) { 92 MI.removeFromParent(); 93 return true; 94 } 95 } 96 // Update modified / used register units. 97 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI); 98 // If a0 was modified or used, there is no possibility 99 // of using ret_val slot of POP instruction. 100 if (!ModifiedRegUnits.available(RISCV::X10) || 101 !UsedRegUnits.available(RISCV::X10)) 102 return false; 103 } 104 return false; 105 } 106 107 bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) { 108 if (skipFunction(Fn.getFunction())) 109 return false; 110 111 // If Zcmp extension is not supported, abort. 112 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>(); 113 if (!Subtarget->hasStdExtZcmp()) 114 return false; 115 116 // If frame pointer elimination has been disabled, abort to avoid breaking the 117 // ABI. 118 if (Fn.getTarget().Options.DisableFramePointerElim(Fn)) 119 return false; 120 121 TII = Subtarget->getInstrInfo(); 122 TRI = Subtarget->getRegisterInfo(); 123 // Resize the modified and used register unit trackers. We do this once 124 // per function and then clear the register units each time we determine 125 // correct return value for the POP. 126 ModifiedRegUnits.init(*TRI); 127 UsedRegUnits.init(*TRI); 128 bool Modified = false; 129 for (auto &MBB : Fn) { 130 MachineBasicBlock::iterator MBBI = containsPop(MBB); 131 MachineBasicBlock::iterator NextI = next_nodbg(MBBI, MBB.end()); 132 if (MBBI != MBB.end() && NextI != MBB.end() && 133 NextI->getOpcode() == RISCV::PseudoRET) 134 Modified |= usePopRet(MBBI, NextI, adjustRetVal(MBBI)); 135 } 136 return Modified; 137 } 138 139 /// createRISCVPushPopOptimizationPass - returns an instance of the 140 /// Push/Pop optimization pass. 141 FunctionPass *llvm::createRISCVPushPopOptimizationPass() { 142 return new RISCVPushPopOpt(); 143 } 144