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
) {}
27 const RISCVInstrInfo
*TII
;
28 const TargetRegisterInfo
*TRI
;
30 // Track which register units have been modified and used.
31 LiveRegUnits ModifiedRegUnits
, UsedRegUnits
;
33 bool usePopRet(MachineBasicBlock::iterator
&MBBI
,
34 MachineBasicBlock::iterator
&NextI
, bool IsReturnZero
);
35 bool adjustRetVal(MachineBasicBlock::iterator
&MBBI
);
36 bool runOnMachineFunction(MachineFunction
&Fn
) override
;
38 StringRef
getPassName() const override
{ return RISCV_PUSH_POP_OPT_NAME
; }
41 char RISCVPushPopOpt::ID
= 0;
43 } // end of anonymous namespace
45 INITIALIZE_PASS(RISCVPushPopOpt
, "riscv-push-pop-opt", RISCV_PUSH_POP_OPT_NAME
,
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
)
58 bool RISCVPushPopOpt::usePopRet(MachineBasicBlock::iterator
&MBBI
,
59 MachineBasicBlock::iterator
&NextI
,
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));
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
));
79 MBBI
->eraseFromParent();
80 NextI
->eraseFromParent();
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();
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();
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
))
117 bool RISCVPushPopOpt::runOnMachineFunction(MachineFunction
&Fn
) {
118 if (skipFunction(Fn
.getFunction()))
121 // If Zcmp extension is not supported, abort.
122 const RISCVSubtarget
*Subtarget
= &Fn
.getSubtarget
<RISCVSubtarget
>();
123 if (!Subtarget
->hasStdExtZcmp())
126 // If frame pointer elimination has been disabled, abort to avoid breaking the
128 if (Fn
.getTarget().Options
.DisableFramePointerElim(Fn
))
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
));
149 /// createRISCVPushPopOptimizationPass - returns an instance of the
150 /// Push/Pop optimization pass.
151 FunctionPass
*llvm::createRISCVPushPopOptimizationPass() {
152 return new RISCVPushPopOpt();