Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
35271 views
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 (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(std::next(I), &MBB, FI, I);
120
FilledSlots += 2;
121
} else {
122
if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {
123
MBB.splice(std::next(I), &MBB, J);
124
} else {
125
BuildMI(MBB, std::next(I), DebugLoc(), TII->get(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(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(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(FI, SawLoad, SawStore, RegDefs, RegUses)) {
168
insertDefsUses(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(RegDefs, Reg) || isRegInSet(RegUses, Reg))
211
return true;
212
}
213
if (MO.isUse()) {
214
// check whether Reg is defined before delay slot.
215
if (isRegInSet(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);
232
unsigned Reg;
233
234
if (!MO.isReg() || !(Reg = MO.getReg()))
235
continue;
236
237
if (MO.isDef())
238
RegDefs.insert(Reg);
239
else if (MO.isUse())
240
RegUses.insert(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(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(*AI))
257
return true;
258
return false;
259
}
260
261