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