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().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 | }; |
77 | char Filler::ID = 0; |
78 | } // end of anonymous namespace |
79 | |
80 | // createLanaiDelaySlotFillerPass - Returns a pass that fills in delay |
81 | // slots in Lanai MachineFunctions |
82 | FunctionPass * |
83 | llvm::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. |
89 | bool 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 | |
142 | bool 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 | |
176 | bool 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. |
222 | void 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. |
252 | bool 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 | |