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