1//===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===//
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// Simple pass to fill delay slots with useful instructions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Lanai.h"
14#include "LanaiTargetMachine.h"
15#include "llvm/ADT/SmallSet.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/CodeGen/MachineFunctionPass.h"
18#include "llvm/CodeGen/MachineInstrBuilder.h"
19#include "llvm/CodeGen/TargetInstrInfo.h"
20#include "llvm/Support/CommandLine.h"
21
22using namespace llvm;
23
24#define DEBUG_TYPE "delay-slot-filler"
25
26STATISTIC(FilledSlots, "Number of delay slots filled");
27
28static cl::opt<bool>
29 NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(Val: false),
30 cl::desc("Fill Lanai delay slots with NOPs."),
31 cl::Hidden);
32
33namespace {
34struct Filler : public MachineFunctionPass {
35 // Target machine description which we query for reg. names, data
36 // layout, etc.
37 const TargetInstrInfo *TII;
38 const TargetRegisterInfo *TRI;
39 MachineBasicBlock::instr_iterator LastFiller;
40
41 static char ID;
42 explicit Filler() : MachineFunctionPass(ID) {}
43
44 StringRef getPassName() const override { return "Lanai Delay Slot Filler"; }
45
46 bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
47
48 bool runOnMachineFunction(MachineFunction &MF) override {
49 const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();
50 TII = Subtarget.getInstrInfo();
51 TRI = Subtarget.getRegisterInfo();
52
53 bool Changed = false;
54 for (MachineBasicBlock &MBB : MF)
55 Changed |= runOnMachineBasicBlock(MBB);
56 return Changed;
57 }
58
59 MachineFunctionProperties getRequiredProperties() const override {
60 return MachineFunctionProperties().setNoVRegs();
61 }
62
63 void insertDefsUses(MachineBasicBlock::instr_iterator MI,
64 SmallSet<unsigned, 32> &RegDefs,
65 SmallSet<unsigned, 32> &RegUses);
66
67 bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);
68
69 bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
70 bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
71 SmallSet<unsigned, 32> &RegUses);
72
73 bool findDelayInstr(MachineBasicBlock &MBB,
74 MachineBasicBlock::instr_iterator Slot,
75 MachineBasicBlock::instr_iterator &Filler);
76};
77char Filler::ID = 0;
78} // end of anonymous namespace
79
80// createLanaiDelaySlotFillerPass - Returns a pass that fills in delay
81// slots in Lanai MachineFunctions
82FunctionPass *
83llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine & /*tm*/) {
84 return new Filler();
85}
86
87// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
88// There is one or two delay slot per delayed instruction.
89bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
90 bool Changed = false;
91 LastFiller = MBB.instr_end();
92
93 for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();
94 I != MBB.instr_end(); ++I) {
95 if (I->getDesc().hasDelaySlot()) {
96 MachineBasicBlock::instr_iterator InstrWithSlot = I;
97 MachineBasicBlock::instr_iterator J = I;
98
99 // Treat RET specially as it is only instruction with 2 delay slots
100 // generated while all others generated have 1 delay slot.
101 if (I->getOpcode() == Lanai::RET) {
102 // RET is generated as part of epilogue generation and hence we know
103 // what the two instructions preceding it are and that it is safe to
104 // insert RET above them.
105 MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();
106 assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
107 RI->getOperand(0).getReg() == Lanai::FP &&
108 RI->getOperand(1).isReg() &&
109 RI->getOperand(1).getReg() == Lanai::FP &&
110 RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);
111 ++RI;
112 assert(RI->getOpcode() == Lanai::ADD_I_LO &&
113 RI->getOperand(0).isReg() &&
114 RI->getOperand(0).getReg() == Lanai::SP &&
115 RI->getOperand(1).isReg() &&
116 RI->getOperand(1).getReg() == Lanai::FP);
117 MachineBasicBlock::instr_iterator FI = RI.getReverse();
118 MBB.splice(Where: std::next(x: I), Other: &MBB, From: FI, To: I);
119 FilledSlots += 2;
120 } else {
121 if (!NopDelaySlotFiller && findDelayInstr(MBB, Slot: I, Filler&: J)) {
122 MBB.splice(Where: std::next(x: I), Other: &MBB, From: J);
123 } else {
124 BuildMI(BB&: MBB, I: std::next(x: I), MIMD: DebugLoc(), MCID: TII->get(Opcode: Lanai::NOP));
125 }
126 ++FilledSlots;
127 }
128
129 Changed = true;
130 // Record the filler instruction that filled the delay slot.
131 // The instruction after it will be visited in the next iteration.
132 LastFiller = ++I;
133
134 // Bundle the delay slot filler to InstrWithSlot so that the machine
135 // verifier doesn't expect this instruction to be a terminator.
136 MIBundleBuilder(MBB, InstrWithSlot, std::next(x: LastFiller));
137 }
138 }
139 return Changed;
140}
141
142bool Filler::findDelayInstr(MachineBasicBlock &MBB,
143 MachineBasicBlock::instr_iterator Slot,
144 MachineBasicBlock::instr_iterator &Filler) {
145 SmallSet<unsigned, 32> RegDefs;
146 SmallSet<unsigned, 32> RegUses;
147
148 insertDefsUses(MI: Slot, RegDefs, RegUses);
149
150 bool SawLoad = false;
151 bool SawStore = false;
152
153 for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();
154 I != MBB.instr_rend(); ++I) {
155 // skip debug value
156 if (I->isDebugInstr())
157 continue;
158
159 // Convert to forward iterator.
160 MachineBasicBlock::instr_iterator FI = I.getReverse();
161
162 if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
163 FI == LastFiller || I->isPseudo())
164 break;
165
166 if (delayHasHazard(MI: FI, SawLoad, SawStore, RegDefs, RegUses)) {
167 insertDefsUses(MI: FI, RegDefs, RegUses);
168 continue;
169 }
170 Filler = FI;
171 return true;
172 }
173 return false;
174}
175
176bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
177 bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
178 SmallSet<unsigned, 32> &RegUses) {
179 if (MI->isImplicitDef() || MI->isKill())
180 return true;
181
182 // Loads or stores cannot be moved past a store to the delay slot
183 // and stores cannot be moved past a load.
184 if (MI->mayLoad()) {
185 if (SawStore)
186 return true;
187 SawLoad = true;
188 }
189
190 if (MI->mayStore()) {
191 if (SawStore)
192 return true;
193 SawStore = true;
194 if (SawLoad)
195 return true;
196 }
197
198 assert((!MI->isCall() && !MI->isReturn()) &&
199 "Cannot put calls or returns in delay slot.");
200
201 for (const MachineOperand &MO : MI->operands()) {
202 unsigned Reg;
203
204 if (!MO.isReg() || !(Reg = MO.getReg()))
205 continue; // skip
206
207 if (MO.isDef()) {
208 // check whether Reg is defined or used before delay slot.
209 if (isRegInSet(RegSet&: RegDefs, Reg) || isRegInSet(RegSet&: RegUses, Reg))
210 return true;
211 }
212 if (MO.isUse()) {
213 // check whether Reg is defined before delay slot.
214 if (isRegInSet(RegSet&: RegDefs, Reg))
215 return true;
216 }
217 }
218 return false;
219}
220
221// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
222void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,
223 SmallSet<unsigned, 32> &RegDefs,
224 SmallSet<unsigned, 32> &RegUses) {
225 // If MI is a call or return, just examine the explicit non-variadic operands.
226 const MCInstrDesc &MCID = MI->getDesc();
227 unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()
228 : MI->getNumOperands();
229 for (unsigned I = 0; I != E; ++I) {
230 const MachineOperand &MO = MI->getOperand(i: I);
231 unsigned Reg;
232
233 if (!MO.isReg() || !(Reg = MO.getReg()))
234 continue;
235
236 if (MO.isDef())
237 RegDefs.insert(V: Reg);
238 else if (MO.isUse())
239 RegUses.insert(V: Reg);
240 }
241
242 // Call & return instructions defines SP implicitly. Implicit defines are not
243 // included in the RegDefs set of calls but instructions modifying SP cannot
244 // be inserted in the delay slot of a call/return as these instructions are
245 // expanded to multiple instructions with SP modified before the branch that
246 // has the delay slot.
247 if (MI->isCall() || MI->isReturn())
248 RegDefs.insert(V: Lanai::SP);
249}
250
251// Returns true if the Reg or its alias is in the RegSet.
252bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {
253 // Check Reg and all aliased Registers.
254 for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
255 if (RegSet.count(V: *AI))
256 return true;
257 return false;
258}
259