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 #include "llvm/CodeGen/MachineInstr.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 28 const RISCVInstrInfo *TII; 29 const TargetRegisterInfo *TRI; 30 31 // Track which register units have been modified and used. 32 LiveRegUnits ModifiedRegUnits, UsedRegUnits; 33 34 bool usePopRet(MachineBasicBlock::iterator &MBBI, 35 MachineBasicBlock::iterator &NextI, bool IsReturnZero); 36 bool adjustRetVal(MachineBasicBlock::iterator &MBBI); 37 bool runOnMachineFunction(MachineFunction &Fn) override; 38 39 StringRef getPassName() const override { return RISCV_PUSH_POP_OPT_NAME; } 40 }; 41 42 char RISCVPushPopOpt::ID = 0; 43 44 } // end of anonymous namespace 45 46 INITIALIZE_PASS(RISCVPushPopOpt, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME, 47 false, false) 48 49 static bool isPop(unsigned Opcode) { 50 switch (Opcode) { 51 case RISCV::CM_POP: 52 case RISCV::QC_CM_POP: 53 return true; 54 default: 55 return false; 56 } 57 } 58 59 static unsigned getPopRetOpcode(unsigned PopOpcode, bool IsReturnZero) { 60 assert(isPop(PopOpcode) && "Unexpected Pop Opcode"); 61 62 switch (PopOpcode) { 63 case RISCV::CM_POP: 64 return IsReturnZero ? RISCV::CM_POPRETZ : RISCV::CM_POPRET; 65 case RISCV::QC_CM_POP: 66 return IsReturnZero ? RISCV::QC_CM_POPRETZ : RISCV::QC_CM_POPRET; 67 default: 68 llvm_unreachable("Unhandled Pop Opcode"); 69 } 70 } 71 72 bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator &MBBI, 73 MachineBasicBlock::iterator &NextI, 74 bool IsReturnZero) { 75 // Since Pseudo instruction lowering happen later in the pipeline, 76 // this will detect all ret instruction. 77 DebugLoc DL = NextI->getDebugLoc(); 78 unsigned Opc = getPopRetOpcode(MBBI->getOpcode(), IsReturnZero); 79 MachineInstrBuilder PopRetBuilder = 80 BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc)) 81 .add(MBBI->getOperand(0)) 82 .add(MBBI->getOperand(1)) 83 .setMIFlag(MachineInstr::FrameDestroy); 84 85 // Copy over the variable implicit uses and defs from the CM_POP. They depend 86 // on what register list has been picked during frame lowering. 87 const MCInstrDesc &PopDesc = MBBI->getDesc(); 88 unsigned FirstNonDeclaredOp = PopDesc.getNumOperands() + 89 PopDesc.NumImplicitUses + 90 PopDesc.NumImplicitDefs; 91 for (unsigned i = FirstNonDeclaredOp; i < MBBI->getNumOperands(); ++i) 92 PopRetBuilder.add(MBBI->getOperand(i)); 93 94 MBBI->eraseFromParent(); 95 NextI->eraseFromParent(); 96 return true; 97 } 98 99 // Search for last assignment to a0 and if possible use ret_val slot of POP to 100 // store return value. 101 bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator &MBBI) { 102 MachineBasicBlock::reverse_iterator RE = MBBI->getParent()->rend(); 103 // Track which register units have been modified and used between the POP 104 // insn and the last assignment to register a0. 105 ModifiedRegUnits.clear(); 106 UsedRegUnits.clear(); 107 // Since POP instruction is in Epilogue no normal instructions will follow 108 // after it. Therefore search only previous ones to find the return value. 109 for (MachineBasicBlock::reverse_iterator I = 110 next_nodbg(MBBI.getReverse(), RE); 111 I != RE; I = next_nodbg(I, RE)) { 112 MachineInstr &MI = *I; 113 if (auto OperandPair = TII->isCopyInstrImpl(MI)) { 114 Register DestReg = OperandPair->Destination->getReg(); 115 Register Source = OperandPair->Source->getReg(); 116 if (DestReg == RISCV::X10 && Source == RISCV::X0) { 117 MI.removeFromParent(); 118 return true; 119 } 120 } 121 // Update modified / used register units. 122 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI); 123 // If a0 was modified or used, there is no possibility 124 // of using ret_val slot of POP instruction. 125 if (!ModifiedRegUnits.available(RISCV::X10) || 126 !UsedRegUnits.available(RISCV::X10)) 127 return false; 128 } 129 return false; 130 } 131 132 bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) { 133 if (skipFunction(Fn.getFunction())) 134 return false; 135 136 // If Zcmp extension is not supported, abort. 137 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>(); 138 if (!Subtarget->hasStdExtZcmp() && !Subtarget->hasVendorXqccmp()) 139 return false; 140 141 TII = Subtarget->getInstrInfo(); 142 TRI = Subtarget->getRegisterInfo(); 143 144 // Resize the modified and used register unit trackers. We do this once 145 // per function and then clear the register units each time we determine 146 // correct return value for the POP. 147 ModifiedRegUnits.init(*TRI); 148 UsedRegUnits.init(*TRI); 149 150 bool Modified = false; 151 for (auto &MBB : Fn) { 152 // RET should be the only terminator. 153 auto RetMBBI = MBB.getFirstTerminator(); 154 if (RetMBBI == MBB.end() || RetMBBI->getOpcode() != RISCV::PseudoRET || 155 RetMBBI == MBB.begin()) 156 continue; 157 158 // The previous instruction should be a POP. 159 auto PopMBBI = prev_nodbg(RetMBBI, MBB.begin()); 160 if (isPop(PopMBBI->getOpcode()) && 161 PopMBBI->getFlag(MachineInstr::FrameDestroy)) 162 Modified |= usePopRet(PopMBBI, RetMBBI, adjustRetVal(PopMBBI)); 163 } 164 165 return Modified; 166 } 167 168 /// createRISCVPushPopOptimizationPass - returns an instance of the 169 /// Push/Pop optimization pass. 170 FunctionPass *llvm::createRISCVPushPopOptimizationPass() { 171 return new RISCVPushPopOpt(); 172 } 173