xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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