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(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 (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};
79char Filler::ID = 0;
80} // end of anonymous namespace
81
82// createLanaiDelaySlotFillerPass - Returns a pass that fills in delay
83// slots in Lanai MachineFunctions
84FunctionPass *
85llvm::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.
91bool 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
144bool 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
178bool 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.
225void 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.
255bool 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