LLVM 24.0.0git
RISCVPushPopOptimizer.cpp
Go to the documentation of this file.
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 "RISCV.h"
15#include "RISCVInstrInfo.h"
21#include "llvm/IR/Analysis.h"
22#include "llvm/Pass.h"
23
24using namespace llvm;
25
26#define RISCV_PUSH_POP_OPT_NAME "RISC-V Zcmp Push/Pop optimization pass"
27
28namespace {
29class RISCVPushPopOptLegacy : public MachineFunctionPass {
30public:
31 static char ID;
32
33 RISCVPushPopOptLegacy() : MachineFunctionPass(ID) {}
34 bool runOnMachineFunction(MachineFunction &MF) override;
35
36 StringRef getPassName() const override { return RISCV_PUSH_POP_OPT_NAME; }
37
38 void getAnalysisUsage(AnalysisUsage &AU) const override {
39 AU.setPreservesCFG();
41 }
42};
43
44class RISCVPushPopOptImpl {
45 const RISCVInstrInfo *TII;
47
48 // Track which register units have been modified and used.
49 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
50
51 bool usePopRet(MachineBasicBlock::iterator &MBBI,
52 MachineBasicBlock::iterator &NextI, bool IsReturnZero);
53 bool adjustRetVal(MachineBasicBlock::iterator &MBBI);
54
55public:
56 bool runOnMachineFunction(MachineFunction &MF);
57};
58
59char RISCVPushPopOptLegacy::ID = 0;
60
61} // end of anonymous namespace
62
63INITIALIZE_PASS(RISCVPushPopOptLegacy, "riscv-push-pop-opt",
64 RISCV_PUSH_POP_OPT_NAME, false, false)
65
66static bool isPop(unsigned Opcode) {
67 switch (Opcode) {
68 case RISCV::CM_POP:
69 case RISCV::QC_CM_POP:
70 return true;
71 default:
72 return false;
73 }
74}
75
76static unsigned getPopRetOpcode(unsigned PopOpcode, bool IsReturnZero) {
77 assert(isPop(PopOpcode) && "Unexpected Pop Opcode");
78
79 switch (PopOpcode) {
80 case RISCV::CM_POP:
81 return IsReturnZero ? RISCV::CM_POPRETZ : RISCV::CM_POPRET;
82 case RISCV::QC_CM_POP:
83 return IsReturnZero ? RISCV::QC_CM_POPRETZ : RISCV::QC_CM_POPRET;
84 default:
85 llvm_unreachable("Unhandled Pop Opcode");
86 }
87}
88
89bool RISCVPushPopOptImpl::usePopRet(MachineBasicBlock::iterator &MBBI,
91 bool IsReturnZero) {
92 // Since Pseudo instruction lowering happen later in the pipeline,
93 // this will detect all ret instruction.
94 DebugLoc DL = NextI->getDebugLoc();
95 unsigned Opc = getPopRetOpcode(MBBI->getOpcode(), IsReturnZero);
96 MachineInstrBuilder PopRetBuilder =
97 BuildMI(*NextI->getParent(), NextI, DL, TII->get(Opc))
98 .add(MBBI->getOperand(0))
99 .add(MBBI->getOperand(1))
101
102 // Copy over the variable implicit uses and defs from the CM_POP. They depend
103 // on what register list has been picked during frame lowering.
104 const MCInstrDesc &PopDesc = MBBI->getDesc();
105 unsigned FirstNonDeclaredOp = PopDesc.getNumOperands() +
106 PopDesc.NumImplicitUses +
107 PopDesc.NumImplicitDefs;
108 for (unsigned i = FirstNonDeclaredOp; i < MBBI->getNumOperands(); ++i)
109 PopRetBuilder.add(MBBI->getOperand(i));
110
112 NextI->eraseFromParent();
113 return true;
114}
115
116// Search for last assignment to a0 and if possible use ret_val slot of POP to
117// store return value.
118bool RISCVPushPopOptImpl::adjustRetVal(MachineBasicBlock::iterator &MBBI) {
120 // Track which register units have been modified and used between the POP
121 // insn and the last assignment to register a0.
122 ModifiedRegUnits.clear();
123 UsedRegUnits.clear();
124 // Since POP instruction is in Epilogue no normal instructions will follow
125 // after it. Therefore search only previous ones to find the return value.
127 next_nodbg(MBBI.getReverse(), RE);
128 I != RE; I = next_nodbg(I, RE)) {
129 MachineInstr &MI = *I;
130 if (auto OperandPair = TII->isCopyInstrImpl(MI)) {
131 Register DestReg = OperandPair->Destination->getReg();
132 Register Source = OperandPair->Source->getReg();
133 if (DestReg == RISCV::X10 && Source == RISCV::X0) {
134 MI.removeFromParent();
135 return true;
136 }
137 }
138 // Update modified / used register units.
139 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
140 // If a0 was modified or used, there is no possibility
141 // of using ret_val slot of POP instruction.
142 if (!ModifiedRegUnits.available(RISCV::X10) ||
143 !UsedRegUnits.available(RISCV::X10))
144 return false;
145 }
146 return false;
147}
148
149bool RISCVPushPopOptImpl::runOnMachineFunction(MachineFunction &MF) {
150 // If Zcmp extension is not supported, abort.
151 const RISCVSubtarget *Subtarget = &MF.getSubtarget<RISCVSubtarget>();
152 if (!Subtarget->hasStdExtZcmp() && !Subtarget->hasVendorXqccmp())
153 return false;
154
155 // We don't want any popret[z] instructions when emitting code with shadow
156 // stack protection. Note that this pass would actually fail to insert any
157 // popret[z] instructions in this case since the cm.pop and ret will not be
158 // adjacent. But there's no point in running a pass that won't do anything.
159 if ((MF.getFunction().hasFnAttribute("hw-shadow-stack") &&
160 Subtarget->hasStdExtZimop()) ||
161 MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))
162 return false;
163
164 TII = Subtarget->getInstrInfo();
165 TRI = Subtarget->getRegisterInfo();
166
167 // Resize the modified and used register unit trackers. We do this once
168 // per function and then clear the register units each time we determine
169 // correct return value for the POP.
170 ModifiedRegUnits.init(*TRI);
171 UsedRegUnits.init(*TRI);
172
173 bool Modified = false;
174 for (auto &MBB : MF) {
175 // RET should be the only terminator.
176 auto RetMBBI = MBB.getFirstTerminator();
177 if (RetMBBI == MBB.end() || RetMBBI->getOpcode() != RISCV::PseudoRET ||
178 RetMBBI == MBB.begin())
179 continue;
180
181 // The previous instruction should be a POP.
182 auto PopMBBI = prev_nodbg(RetMBBI, MBB.begin());
183 if (isPop(PopMBBI->getOpcode()) &&
184 PopMBBI->getFlag(MachineInstr::FrameDestroy))
185 Modified |= usePopRet(PopMBBI, RetMBBI, adjustRetVal(PopMBBI));
186 }
187
188 return Modified;
189}
190
191/// createRISCVPushPopOptimizationPass - returns an instance of the
192/// Push/Pop optimization pass.
194 return new RISCVPushPopOptLegacy();
195}
196
197bool RISCVPushPopOptLegacy::runOnMachineFunction(MachineFunction &MF) {
198 if (skipFunction(MF.getFunction()))
199 return false;
200 RISCVPushPopOptImpl Impl;
201 return Impl.runOnMachineFunction(MF);
202}
203
204PreservedAnalyses
207 RISCVPushPopOptImpl Impl;
208 return Impl.runOnMachineFunction(MF)
212}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool isPop(unsigned Opcode)
#define RISCV_PUSH_POP_OPT_NAME
static unsigned getPopRetOpcode(unsigned PopOpcode, bool IsReturnZero)
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:731
A set of register units used to track register liveness.
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void init(const TargetRegisterInfo &TRI)
Initialize and clear the set.
void clear()
Clears the set.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
uint8_t NumImplicitUses
uint8_t NumImplicitDefs
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
reverse_iterator rend()
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const RISCVRegisterInfo * getRegisterInfo() const override
const RISCVInstrInfo * getInstrInfo() const override
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createRISCVPushPopOptLegacyPass()
createRISCVPushPopOptimizationPass - returns an instance of the Push/Pop optimization pass.
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.