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
RISCVPushPopOpt__anon4591693d0111::RISCVPushPopOpt25 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
getPassName__anon4591693d0111::RISCVPushPopOpt38 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.
containsPop(MachineBasicBlock & MBB)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
usePopRet(MachineBasicBlock::iterator & MBBI,MachineBasicBlock::iterator & NextI,bool IsReturnZero)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.
adjustRetVal(MachineBasicBlock::iterator & MBBI)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
runOnMachineFunction(MachineFunction & Fn)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.
createRISCVPushPopOptimizationPass()141 FunctionPass *llvm::createRISCVPushPopOptimizationPass() {
142 return new RISCVPushPopOpt();
143 }
144