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