1 //===------- RISCVPushPopOptimizer.cpp - RISC-V Push/Pop opt. pass --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains a pass that replaces Zcmp POP instructions with
10 // POPRET[Z] where possible.
12 //===----------------------------------------------------------------------===//
14 #include "RISCVInstrInfo.h"
15 #include "RISCVMachineFunctionInfo.h"
19 #define RISCV_PUSH_POP_OPT_NAME "RISC-V Zcmp Push/Pop optimization pass"
22 struct RISCVPushPopOpt
: public MachineFunctionPass
{
25 RISCVPushPopOpt() : MachineFunctionPass(ID
) {
26 initializeRISCVPushPopOptPass(*PassRegistry::getPassRegistry());
29 const RISCVInstrInfo
*TII
;
30 const TargetRegisterInfo
*TRI
;
32 // Track which register units have been modified and used.
33 LiveRegUnits ModifiedRegUnits
, UsedRegUnits
;
35 bool usePopRet(MachineBasicBlock::iterator
&MBBI
,
36 MachineBasicBlock::iterator
&NextI
, bool IsReturnZero
);
37 bool adjustRetVal(MachineBasicBlock::iterator
&MBBI
);
38 bool runOnMachineFunction(MachineFunction
&Fn
) override
;
40 StringRef
getPassName() const override
{ return RISCV_PUSH_POP_OPT_NAME
; }
43 char RISCVPushPopOpt::ID
= 0;
45 } // end of anonymous namespace
47 INITIALIZE_PASS(RISCVPushPopOpt
, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME
,
50 // Check if POP instruction was inserted into the MBB and return iterator to it.
51 static MachineBasicBlock::iterator
containsPop(MachineBasicBlock
&MBB
) {
52 for (MachineBasicBlock::iterator MBBI
= MBB
.begin(); MBBI
!= MBB
.end();
53 MBBI
= next_nodbg(MBBI
, MBB
.end()))
54 if (MBBI
->getOpcode() == RISCV::CM_POP
)
60 bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator
&MBBI
,
61 MachineBasicBlock::iterator
&NextI
,
63 // Since Pseudo instruction lowering happen later in the pipeline,
64 // this will detect all ret instruction.
65 DebugLoc DL
= NextI
->getDebugLoc();
66 unsigned Opc
= IsReturnZero
? RISCV::CM_POPRETZ
: RISCV::CM_POPRET
;
67 BuildMI(*NextI
->getParent(), NextI
, DL
, TII
->get(Opc
))
68 .add(MBBI
->getOperand(0))
69 .add(MBBI
->getOperand(1));
71 MBBI
->eraseFromParent();
72 NextI
->eraseFromParent();
76 // Search for last assignment to a0 and if possible use ret_val slot of POP to
77 // store return value.
78 bool RISCVPushPopOpt::adjustRetVal(MachineBasicBlock::iterator
&MBBI
) {
79 MachineBasicBlock::reverse_iterator RE
= MBBI
->getParent()->rend();
80 // Track which register units have been modified and used between the POP
81 // insn and the last assignment to register a0.
82 ModifiedRegUnits
.clear();
84 // Since POP instruction is in Epilogue no normal instructions will follow
85 // after it. Therefore search only previous ones to find the return value.
86 for (MachineBasicBlock::reverse_iterator I
=
87 next_nodbg(MBBI
.getReverse(), RE
);
88 I
!= RE
; I
= next_nodbg(I
, RE
)) {
89 MachineInstr
&MI
= *I
;
90 if (auto OperandPair
= TII
->isCopyInstrImpl(MI
)) {
91 Register DestReg
= OperandPair
->Destination
->getReg();
92 Register Source
= OperandPair
->Source
->getReg();
93 if (DestReg
== RISCV::X10
&& Source
== RISCV::X0
) {
94 MI
.removeFromParent();
98 // Update modified / used register units.
99 LiveRegUnits::accumulateUsedDefed(MI
, ModifiedRegUnits
, UsedRegUnits
, TRI
);
100 // If a0 was modified or used, there is no possibility
101 // of using ret_val slot of POP instruction.
102 if (!ModifiedRegUnits
.available(RISCV::X10
) ||
103 !UsedRegUnits
.available(RISCV::X10
))
109 bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction
&Fn
) {
110 if (skipFunction(Fn
.getFunction()))
113 // If Zcmp extension is not supported, abort.
114 const RISCVSubtarget
*Subtarget
= &Fn
.getSubtarget
<RISCVSubtarget
>();
115 if (!Subtarget
->hasStdExtZcmp())
118 // If frame pointer elimination has been disabled, abort to avoid breaking the
120 if (Fn
.getTarget().Options
.DisableFramePointerElim(Fn
))
123 TII
= Subtarget
->getInstrInfo();
124 TRI
= Subtarget
->getRegisterInfo();
125 // Resize the modified and used register unit trackers. We do this once
126 // per function and then clear the register units each time we determine
127 // correct return value for the POP.
128 ModifiedRegUnits
.init(*TRI
);
129 UsedRegUnits
.init(*TRI
);
130 bool Modified
= false;
131 for (auto &MBB
: Fn
) {
132 MachineBasicBlock::iterator MBBI
= containsPop(MBB
);
133 MachineBasicBlock::iterator NextI
= next_nodbg(MBBI
, MBB
.end());
134 if (MBBI
!= MBB
.end() && NextI
!= MBB
.end() &&
135 NextI
->getOpcode() == RISCV::PseudoRET
)
136 Modified
|= usePopRet(MBBI
, NextI
, adjustRetVal(MBBI
));
141 /// createRISCVPushPopOptimizationPass - returns an instance of the
142 /// Push/Pop optimization pass.
143 FunctionPass
*llvm::createRISCVPushPopOptimizationPass() {
144 return new RISCVPushPopOpt();