xref: /llvm-project/llvm/lib/Target/RISCV/RISCVPushPopOptimizer.cpp (revision 514686acfda66401869f9599954d731619c12c99)
144d4f975SCraig Topper //===------- RISCVPushPopOptimizer.cpp - RISC-V Push/Pop opt. pass --------===//
2c0221e00SWuXinlong //
3c0221e00SWuXinlong // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c0221e00SWuXinlong // See https://llvm.org/LICENSE.txt for license information.
5c0221e00SWuXinlong // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c0221e00SWuXinlong //
7c0221e00SWuXinlong //===----------------------------------------------------------------------===//
8c0221e00SWuXinlong //
9fc654b4fSAlex Bradbury // This file contains a pass that replaces Zcmp POP instructions with
10fc654b4fSAlex Bradbury // POPRET[Z] where possible.
11c0221e00SWuXinlong //
12c0221e00SWuXinlong //===----------------------------------------------------------------------===//
13c0221e00SWuXinlong 
14c0221e00SWuXinlong #include "RISCVInstrInfo.h"
15c0221e00SWuXinlong #include "RISCVMachineFunctionInfo.h"
16c0221e00SWuXinlong 
17c0221e00SWuXinlong using namespace llvm;
18c0221e00SWuXinlong 
19c0221e00SWuXinlong #define RISCV_PUSH_POP_OPT_NAME "RISC-V Zcmp Push/Pop optimization pass"
20c0221e00SWuXinlong 
21c0221e00SWuXinlong namespace {
22c0221e00SWuXinlong struct RISCVPushPopOpt : public MachineFunctionPass {
23c0221e00SWuXinlong   static char ID;
24c0221e00SWuXinlong 
RISCVPushPopOpt__anon43491f680111::RISCVPushPopOpt254162a9bcSCraig Topper   RISCVPushPopOpt() : MachineFunctionPass(ID) {}
26c0221e00SWuXinlong 
27c0221e00SWuXinlong   const RISCVInstrInfo *TII;
28c0221e00SWuXinlong   const TargetRegisterInfo *TRI;
29c0221e00SWuXinlong 
30c0221e00SWuXinlong   // Track which register units have been modified and used.
31c0221e00SWuXinlong   LiveRegUnits ModifiedRegUnits, UsedRegUnits;
32c0221e00SWuXinlong 
33c0221e00SWuXinlong   bool usePopRet(MachineBasicBlock::iterator &MBBI,
34c0221e00SWuXinlong                  MachineBasicBlock::iterator &NextI, bool IsReturnZero);
35c0221e00SWuXinlong   bool adjustRetVal(MachineBasicBlock::iterator &MBBI);
36c0221e00SWuXinlong   bool runOnMachineFunction(MachineFunction &Fn) override;
37c0221e00SWuXinlong 
getPassName__anon43491f680111::RISCVPushPopOpt38c0221e00SWuXinlong   StringRef getPassName() const override { return RISCV_PUSH_POP_OPT_NAME; }
39c0221e00SWuXinlong };
40c0221e00SWuXinlong 
41c0221e00SWuXinlong char RISCVPushPopOpt::ID = 0;
42c0221e00SWuXinlong 
43c0221e00SWuXinlong } // end of anonymous namespace
44c0221e00SWuXinlong 
45c0221e00SWuXinlong INITIALIZE_PASS(RISCVPushPopOpt, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME,
46c0221e00SWuXinlong                 false, false)
47c0221e00SWuXinlong 
48c0221e00SWuXinlong // Check if POP instruction was inserted into the MBB and return iterator to it.
containsPop(MachineBasicBlock & MBB)49c0221e00SWuXinlong static MachineBasicBlock::iterator containsPop(MachineBasicBlock &MBB) {
50c0221e00SWuXinlong   for (MachineBasicBlock::iterator MBBI = MBB.begin(); MBBI != MBB.end();
51c0221e00SWuXinlong        MBBI = next_nodbg(MBBI, MBB.end()))
52c0221e00SWuXinlong     if (MBBI->getOpcode() == RISCV::CM_POP)
53c0221e00SWuXinlong       return MBBI;
54c0221e00SWuXinlong 
55c0221e00SWuXinlong   return MBB.end();
56c0221e00SWuXinlong }
57c0221e00SWuXinlong 
usePopRet(MachineBasicBlock::iterator & MBBI,MachineBasicBlock::iterator & NextI,bool IsReturnZero)58c0221e00SWuXinlong bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator &MBBI,
59c0221e00SWuXinlong                                 MachineBasicBlock::iterator &NextI,
60c0221e00SWuXinlong                                 bool IsReturnZero) {
61c0221e00SWuXinlong   // Since Pseudo instruction lowering happen later in the pipeline,
62c0221e00SWuXinlong   // this will detect all ret instruction.
63c0221e00SWuXinlong   DebugLoc DL = NextI->getDebugLoc();
64c0221e00SWuXinlong   unsigned Opc = IsReturnZero ? RISCV::CM_POPRETZ : RISCV::CM_POPRET;
65*514686acSVisoiu Mistrih Francis   MachineInstrBuilder PopRetBuilder =
66c0221e00SWuXinlong       BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc))
67c0221e00SWuXinlong           .add(MBBI->getOperand(0))
68c0221e00SWuXinlong           .add(MBBI->getOperand(1));
69c0221e00SWuXinlong 
70*514686acSVisoiu Mistrih Francis   // Copy over the variable implicit uses and defs from the CM_POP. They depend
71*514686acSVisoiu Mistrih Francis   // on what register list has been picked during frame lowering.
72*514686acSVisoiu Mistrih Francis   const MCInstrDesc &PopDesc = MBBI->getDesc();
73*514686acSVisoiu Mistrih Francis   unsigned FirstNonDeclaredOp = PopDesc.getNumOperands() +
74*514686acSVisoiu Mistrih Francis                                 PopDesc.NumImplicitUses +
75*514686acSVisoiu Mistrih Francis                                 PopDesc.NumImplicitDefs;
76*514686acSVisoiu Mistrih Francis   for (unsigned i = FirstNonDeclaredOp; i < MBBI->getNumOperands(); ++i)
77*514686acSVisoiu Mistrih Francis     PopRetBuilder.add(MBBI->getOperand(i));
78*514686acSVisoiu Mistrih Francis 
79c0221e00SWuXinlong   MBBI->eraseFromParent();
80c0221e00SWuXinlong   NextI->eraseFromParent();
81c0221e00SWuXinlong   return true;
82c0221e00SWuXinlong }
83c0221e00SWuXinlong 
84c0221e00SWuXinlong // Search for last assignment to a0 and if possible use ret_val slot of POP to
85c0221e00SWuXinlong // store return value.
adjustRetVal(MachineBasicBlock::iterator & MBBI)86c0221e00SWuXinlong bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator &MBBI) {
87c0221e00SWuXinlong   MachineBasicBlock::reverse_iterator RE = MBBI->getParent()->rend();
88c0221e00SWuXinlong   // Track which register units have been modified and used between the POP
89c0221e00SWuXinlong   // insn and the last assignment to register a0.
90c0221e00SWuXinlong   ModifiedRegUnits.clear();
91c0221e00SWuXinlong   UsedRegUnits.clear();
92c0221e00SWuXinlong   // Since POP instruction is in Epilogue no normal instructions will follow
93c0221e00SWuXinlong   // after it. Therefore search only previous ones to find the return value.
94c0221e00SWuXinlong   for (MachineBasicBlock::reverse_iterator I =
95c0221e00SWuXinlong            next_nodbg(MBBI.getReverse(), RE);
96c0221e00SWuXinlong        I != RE; I = next_nodbg(I, RE)) {
97c0221e00SWuXinlong     MachineInstr &MI = *I;
98c0221e00SWuXinlong     if (auto OperandPair = TII->isCopyInstrImpl(MI)) {
99c0221e00SWuXinlong       Register DestReg = OperandPair->Destination->getReg();
100c0221e00SWuXinlong       Register Source = OperandPair->Source->getReg();
101c0221e00SWuXinlong       if (DestReg == RISCV::X10 && Source == RISCV::X0) {
102c0221e00SWuXinlong         MI.removeFromParent();
103c0221e00SWuXinlong         return true;
104c0221e00SWuXinlong       }
105c0221e00SWuXinlong     }
106c0221e00SWuXinlong     // Update modified / used register units.
107c0221e00SWuXinlong     LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
108c0221e00SWuXinlong     // If a0 was modified or used, there is no possibility
109c0221e00SWuXinlong     // of using ret_val slot of POP instruction.
110c0221e00SWuXinlong     if (!ModifiedRegUnits.available(RISCV::X10) ||
111c0221e00SWuXinlong         !UsedRegUnits.available(RISCV::X10))
112c0221e00SWuXinlong       return false;
113c0221e00SWuXinlong   }
114c0221e00SWuXinlong   return false;
115c0221e00SWuXinlong }
116c0221e00SWuXinlong 
runOnMachineFunction(MachineFunction & Fn)117c0221e00SWuXinlong bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction &Fn) {
118c0221e00SWuXinlong   if (skipFunction(Fn.getFunction()))
119c0221e00SWuXinlong     return false;
120c0221e00SWuXinlong 
121c0221e00SWuXinlong   // If Zcmp extension is not supported, abort.
122c0221e00SWuXinlong   const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
123c0221e00SWuXinlong   if (!Subtarget->hasStdExtZcmp())
124c0221e00SWuXinlong     return false;
125c0221e00SWuXinlong 
126c0221e00SWuXinlong   // If frame pointer elimination has been disabled, abort to avoid breaking the
127c0221e00SWuXinlong   // ABI.
128c0221e00SWuXinlong   if (Fn.getTarget().Options.DisableFramePointerElim(Fn))
129c0221e00SWuXinlong     return false;
130c0221e00SWuXinlong 
131cde5e428SAlex Bradbury   TII = Subtarget->getInstrInfo();
132c0221e00SWuXinlong   TRI = Subtarget->getRegisterInfo();
133c0221e00SWuXinlong   // Resize the modified and used register unit trackers.  We do this once
134c0221e00SWuXinlong   // per function and then clear the register units each time we determine
135c0221e00SWuXinlong   // correct return value for the POP.
136c0221e00SWuXinlong   ModifiedRegUnits.init(*TRI);
137c0221e00SWuXinlong   UsedRegUnits.init(*TRI);
138c0221e00SWuXinlong   bool Modified = false;
139c0221e00SWuXinlong   for (auto &MBB : Fn) {
140c0221e00SWuXinlong     MachineBasicBlock::iterator MBBI = containsPop(MBB);
141c0221e00SWuXinlong     MachineBasicBlock::iterator NextI = next_nodbg(MBBI, MBB.end());
14253e89f5eSAnmol P. Paralkar     if (MBBI != MBB.end() && NextI != MBB.end() &&
14353e89f5eSAnmol P. Paralkar         NextI->getOpcode() == RISCV::PseudoRET)
144c0221e00SWuXinlong       Modified |= usePopRet(MBBI, NextI, adjustRetVal(MBBI));
145c0221e00SWuXinlong   }
146c0221e00SWuXinlong   return Modified;
147c0221e00SWuXinlong }
148c0221e00SWuXinlong 
149c0221e00SWuXinlong /// createRISCVPushPopOptimizationPass - returns an instance of the
150c0221e00SWuXinlong /// Push/Pop optimization pass.
createRISCVPushPopOptimizationPass()151c0221e00SWuXinlong FunctionPass *llvm::createRISCVPushPopOptimizationPass() {
152c0221e00SWuXinlong   return new RISCVPushPopOpt();
153c0221e00SWuXinlong }
154