LLVM 23.0.0git
LeonPasses.cpp
Go to the documentation of this file.
1//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
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//
10//===----------------------------------------------------------------------===//
11
12#include "LeonPasses.h"
13#include "SparcSubtarget.h"
19
20using namespace llvm;
21
23
27
28INITIALIZE_PASS(ErrataWorkaround, "errata-workaround", "Errata workaround pass",
29 false, false)
30
31// Move iterator to the next instruction in the function, ignoring
32// meta instructions and inline assembly. Returns false when reaching
33// the end of the function.
35
36 MachineBasicBlock *MBB = I->getParent();
37
38 do {
39 I++;
40
41 while (I == MBB->end()) {
42 if (MBB->getFallThrough() == nullptr)
43 return false;
44 MBB = MBB->getFallThrough();
45 I = MBB->begin();
46 }
47 } while (I->isMetaInstruction() || I->isInlineAsm());
48
49 return true;
50}
51
53 BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP));
54}
55
57 if (I->getNumOperands() == 0)
58 return false;
59
60 if (!I->getOperand(0).isReg())
61 return false;
62
63 unsigned reg = I->getOperand(0).getReg();
64
65 if (!SP::FPRegsRegClass.contains(reg) && !SP::DFPRegsRegClass.contains(reg))
66 return false;
67
68 return true;
69}
70
72 switch (I->getOpcode()) {
73 case SP::FDIVS:
74 case SP::FDIVD:
75 case SP::FSQRTS:
76 case SP::FSQRTD:
77 return true;
78 }
79 return false;
80}
81
83 switch (I->getOpcode()) {
84 case SP::SWAPrr:
85 case SP::SWAPri:
86 case SP::CASArr:
87 case SP::LDSTUBrr:
88 case SP::LDSTUBri:
89 case SP::LDSTUBArr:
90 return true;
91 }
92 return false;
93}
94
95// Prevents the following code sequence from being generated:
96// (stb/sth/st/stf) -> (single non-store/load instruction) -> (any store)
97// If the sequence is detected a NOP instruction is inserted after
98// the first store instruction.
100 switch (I->getOpcode()) {
101 case SP::STrr:
102 case SP::STri:
103 case SP::STBrr:
104 case SP::STBri:
105 case SP::STHrr:
106 case SP::STHri:
107 case SP::STFrr:
108 case SP::STFri:
109 break;
110 default:
111 return false;
112 }
113
115 if (!moveNext(MI))
116 return false;
117
118 if (MI->mayStore() || MI->mayLoad())
119 return false;
120
122
123 if (!moveNext(MI))
124 return false;
125
126 if (!MI->mayStore())
127 return false;
128
129 insertNop(PatchHere);
130 return true;
131}
132
133// Prevents the following code sequence from being generated:
134// (std/stdf) -> (any store)
135// If the sequence is detected a NOP instruction is inserted after
136// the first store instruction.
138
139 switch (I->getOpcode()) {
140 case SP::STDrr:
141 case SP::STDri:
142 case SP::STDFrr:
143 case SP::STDFri:
144 break;
145 default:
146 return false;
147 }
148
150
151 if (!moveNext(MI))
152 return false;
153
154 if (!MI->mayStore())
155 return false;
156
157 insertNop(MI);
158 return true;
159}
160
161// Insert a NOP at branch target if load in delay slot and atomic
162// instruction at branch target. Also insert a NOP between load
163// instruction and atomic instruction (swap or casa).
165
166 // Check for load instruction or branch bundled with load instruction
167 if (!I->mayLoad())
168 return false;
169
170 // Check for branch to atomic instruction with load in delay slot
171 if (I->isBranch() && I->getOperand(0).isMBB()) {
172 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
173 MachineBasicBlock::iterator MI = TargetMBB->begin();
174
175 while (MI != TargetMBB->end() && MI->isMetaInstruction())
176 MI++;
177
178 if (MI == TargetMBB->end())
179 return false;
180
181 if (isAtomic(MI))
182 insertNop(MI);
183 }
184
185 // Check for load followed by atomic instruction
187 if (!moveNext(MI))
188 return false;
189
190 if (!isAtomic(MI))
191 return false;
192 insertNop(MI);
193 return true;
194}
195
196// Do not allow functions to begin with an atomic instruction
199 while (I != MBB.end() && I->isMetaInstruction())
200 I++;
201 if (I == MBB.end())
202 return false;
203 if (!isAtomic(I))
204 return false;
205 insertNop(I);
206 return true;
207}
208
209// Inserts a NOP instruction at the target of an integer branch if the
210// target is a floating-point instruction or floating-point branch.
212
213 if (I->getOpcode() != SP::BCOND && I->getOpcode() != SP::BCONDA)
214 return false;
215
216 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
217 MachineBasicBlock::iterator MI = TargetMBB->begin();
218
219 while (MI != TargetMBB->end() && MI->isMetaInstruction())
220 MI++;
221
222 if (MI == TargetMBB->end())
223 return false;
224
225 if (!isFloat(MI) && MI->getOpcode() != SP::FBCOND)
226 return false;
227
228 insertNop(MI);
229 return true;
230}
231
232// Prevents the following code sequence from being generated:
233// (div/sqrt) -> (2 to 3 floating-point operations or loads) -> (div/sqrt)
234// If the sequence is detected one or two NOP instruction are inserted after
235// the first div/sqrt instruction. No NOPs are inserted if one of the floating-
236// point instructions in the middle of the sequence is a (div/sqrt), or if
237// they have dependency on the destination register of the first (div/sqrt).
238//
239// The function also prevents the following code sequence from being generated,
240// (div/sqrt) -> (branch), by inserting a NOP instruction after the (div/sqrt).
242
243 if (!isDivSqrt(I))
244 return false;
245
246 unsigned dstReg = I->getOperand(0).getReg();
247
249 if (!moveNext(MI))
250 return false;
251
252 if (MI->isBranch()) {
253 insertNop(MI);
254 return true;
255 }
256
258
259 unsigned fpFound = 0;
260 for (unsigned i = 0; i < 4; i++) {
261
262 if (!isFloat(MI)) {
263 if (!moveNext(MI))
264 return false;
265 continue;
266 }
267
268 if (MI->readsRegister(dstReg, TRI))
269 return false;
270
271 if (isDivSqrt(MI)) {
272 if (i < 2)
273 return false;
274 if (fpFound < 2)
275 return false;
276
277 insertNop(PatchHere);
278 if (i == 2)
279 insertNop(PatchHere);
280 return true;
281 }
282
283 fpFound++;
284 if (!moveNext(MI))
285 return false;
286 }
287
288 return false;
289}
290
292 bool Changed = false;
294
295 if (!(ST->fixTN0009() || ST->fixTN0010() || ST->fixTN0012() ||
296 ST->fixTN0013()))
297 return false;
298
299 TII = ST->getInstrInfo();
300 TRI = ST->getRegisterInfo();
301
302 if (ST->fixTN0010())
304
305 for (auto &MBB : MF) {
306 for (auto &I : MBB) {
307 if (ST->fixTN0009()) {
310 }
311 if (ST->fixTN0010())
313 if (ST->fixTN0012())
315 if (ST->fixTN0013())
317 }
318 }
319 return Changed;
320}
321
324
325//*****************************************************************************
326//**** InsertNOPLoad pass
327//*****************************************************************************
328// This pass fixes the incorrectly working Load instructions that exists for
329// some earlier versions of the LEON processor line. NOP instructions must
330// be inserted after the load instruction to ensure that the Load instruction
331// behaves as expected for these processors.
332//
333// This pass inserts a NOP after any LD or LDF instruction.
334//
335char InsertNOPLoad::ID = 0;
336
338
341 if (!Subtarget->insertNOPLoad())
342 return false;
343
344 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
345 DebugLoc DL = DebugLoc();
346
347 bool Modified = false;
348 for (MachineBasicBlock &MBB : MF) {
349 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
350 MachineInstr &MI = *MBBI;
351 unsigned Opcode = MI.getOpcode();
352 if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
353 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
354 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
355 Modified = true;
356 }
357 }
358 }
359
360 return Modified;
361}
362
363
364
365//*****************************************************************************
366//**** DetectRoundChange pass
367//*****************************************************************************
368// To prevent any explicit change of the default rounding mode, this pass
369// detects any call of the fesetround function.
370// A warning is generated to ensure the user knows this has happened.
371//
372// Detects an erratum in UT699 LEON 3 processor
373
374char DetectRoundChange::ID = 0;
375
377
380 if (!Subtarget->detectRoundChange())
381 return false;
382
383 bool Modified = false;
384 for (MachineBasicBlock &MBB : MF) {
385 for (MachineInstr &MI : MBB) {
386 unsigned Opcode = MI.getOpcode();
387 if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
388 MachineOperand &MO = MI.getOperand(0);
389
390 if (MO.isGlobal()) {
391 StringRef FuncName = MO.getGlobal()->getName();
392 if (FuncName.compare_insensitive("fesetround") == 0) {
393 errs() << "Error: You are using the detectroundchange "
394 "option to detect rounding changes that will "
395 "cause LEON errata. The only way to fix this "
396 "is to remove the call to fesetround from "
397 "the source code.\n";
398 }
399 }
400 }
401 }
402 }
403
404 return Modified;
405}
406
407//*****************************************************************************
408//**** FixAllFDIVSQRT pass
409//*****************************************************************************
410// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
411// exist for some earlier versions of the LEON processor line. Five NOP
412// instructions need to be inserted after these instructions to ensure the
413// correct result is placed in the destination registers before they are used.
414//
415// This pass implements two fixes:
416// 1) fixing the FSQRTS and FSQRTD instructions.
417// 2) fixing the FDIVS and FDIVD instructions.
418//
419// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
420// the pipeline when this option is enabled, so this pass needs only to deal
421// with the changes that still need implementing for the "double" versions
422// of these instructions.
423//
424char FixAllFDIVSQRT::ID = 0;
425
427
430 if (!Subtarget->fixAllFDIVSQRT())
431 return false;
432
433 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
434 DebugLoc DL = DebugLoc();
435
436 bool Modified = false;
437 for (MachineBasicBlock &MBB : MF) {
438 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
439 MachineInstr &MI = *MBBI;
440 unsigned Opcode = MI.getOpcode();
441
442 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
443 // switched on so we don't need to check for them here. They will
444 // already have been converted to FSQRTD or FDIVD earlier in the
445 // pipeline.
446 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
447 for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
448 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
449
450 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
451 for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
452 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
453
454 Modified = true;
455 }
456 }
457 }
458
459 return Modified;
460}
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
A debug info location.
Definition DebugLoc.h:126
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
bool checkSeqTN0009A(MachineBasicBlock::iterator I)
bool checkSeqTN0013(MachineBasicBlock::iterator I)
bool isAtomic(MachineBasicBlock::iterator I)
bool checkSeqTN0010First(MachineBasicBlock &MBB)
bool moveNext(MachineBasicBlock::iterator &I)
const SparcSubtarget * ST
Definition LeonPasses.h:42
bool checkSeqTN0012(MachineBasicBlock::iterator I)
bool checkSeqTN0010(MachineBasicBlock::iterator I)
bool checkSeqTN0009B(MachineBasicBlock::iterator I)
const TargetInstrInfo * TII
Definition LeonPasses.h:43
bool isDivSqrt(MachineBasicBlock::iterator I)
bool isFloat(MachineBasicBlock::iterator I)
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetRegisterInfo * TRI
Definition LeonPasses.h:44
void insertNop(MachineBasicBlock::iterator I)
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const SparcSubtarget * Subtarget
Definition LeonPasses.h:23
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineBasicBlock & front() const
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM_ABI int compare_insensitive(StringRef RHS) const
Compare two strings, ignoring case.
Definition StringRef.cpp:32
TargetInstrInfo - Interface to description of machine instruction set.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeErrataWorkaroundPass(PassRegistry &)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.