AMDGPU: Mark test as XFAIL in expensive_checks builds
[llvm-project.git] / llvm / lib / Target / Sparc / LeonPasses.cpp
blob018d8126f7a7e9aa4705a80c367e638621fc9e04
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 //===----------------------------------------------------------------------===//
12 #include "LeonPasses.h"
13 #include "SparcSubtarget.h"
14 #include "llvm/CodeGen/MachineBasicBlock.h"
15 #include "llvm/CodeGen/MachineFunction.h"
16 #include "llvm/CodeGen/MachineInstr.h"
17 #include "llvm/CodeGen/MachineInstrBuilder.h"
18 #include "llvm/Support/raw_ostream.h"
20 using namespace llvm;
22 char ErrataWorkaround::ID = 0;
24 ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID) {
25 initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry());
28 INITIALIZE_PASS(ErrataWorkaround, "errata-workaround", "Errata workaround pass",
29 false, false)
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.
34 bool ErrataWorkaround::moveNext(MachineBasicBlock::iterator &I) {
36 MachineBasicBlock *MBB = I->getParent();
38 do {
39 I++;
41 while (I == MBB->end()) {
42 if (MBB->getFallThrough() == nullptr)
43 return false;
44 MBB = MBB->getFallThrough();
45 I = MBB->begin();
47 } while (I->isMetaInstruction() || I->isInlineAsm());
49 return true;
52 void ErrataWorkaround::insertNop(MachineBasicBlock::iterator I) {
53 BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP));
56 bool ErrataWorkaround::isFloat(MachineBasicBlock::iterator I) {
57 if (I->getNumOperands() == 0)
58 return false;
60 if (!I->getOperand(0).isReg())
61 return false;
63 unsigned reg = I->getOperand(0).getReg();
65 if (!SP::FPRegsRegClass.contains(reg) && !SP::DFPRegsRegClass.contains(reg))
66 return false;
68 return true;
71 bool ErrataWorkaround::isDivSqrt(MachineBasicBlock::iterator I) {
72 switch (I->getOpcode()) {
73 case SP::FDIVS:
74 case SP::FDIVD:
75 case SP::FSQRTS:
76 case SP::FSQRTD:
77 return true;
79 return false;
82 // Prevents the following code sequence from being generated:
83 // (stb/sth/st/stf) -> (single non-store/load instruction) -> (any store)
84 // If the sequence is detected a NOP instruction is inserted after
85 // the first store instruction.
86 bool ErrataWorkaround::checkSeqTN0009A(MachineBasicBlock::iterator I) {
87 switch (I->getOpcode()) {
88 case SP::STrr:
89 case SP::STri:
90 case SP::STBrr:
91 case SP::STBri:
92 case SP::STHrr:
93 case SP::STHri:
94 case SP::STFrr:
95 case SP::STFri:
96 break;
97 default:
98 return false;
101 MachineBasicBlock::iterator MI = I;
102 if (!moveNext(MI))
103 return false;
105 if (MI->mayStore() || MI->mayLoad())
106 return false;
108 MachineBasicBlock::iterator PatchHere = MI;
110 if (!moveNext(MI))
111 return false;
113 if (!MI->mayStore())
114 return false;
116 insertNop(PatchHere);
117 return true;
120 // Prevents the following code sequence from being generated:
121 // (std/stdf) -> (any store)
122 // If the sequence is detected a NOP instruction is inserted after
123 // the first store instruction.
124 bool ErrataWorkaround::checkSeqTN0009B(MachineBasicBlock::iterator I) {
126 switch (I->getOpcode()) {
127 case SP::STDrr:
128 case SP::STDri:
129 case SP::STDFrr:
130 case SP::STDFri:
131 break;
132 default:
133 return false;
136 MachineBasicBlock::iterator MI = I;
138 if (!moveNext(MI))
139 return false;
141 if (!MI->mayStore())
142 return false;
144 insertNop(MI);
145 return true;
148 // Insert a NOP at branch target if load in delay slot and atomic
149 // instruction at branch target. Also insert a NOP between load
150 // instruction and atomic instruction (swap or casa).
151 bool ErrataWorkaround::checkSeqTN0010(MachineBasicBlock::iterator I) {
153 // Check for load instruction or branch bundled with load instruction
154 if (!I->mayLoad())
155 return false;
157 // Check for branch to atomic instruction with load in delay slot
158 if (I->isBranch()) {
159 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
160 MachineBasicBlock::iterator MI = TargetMBB->begin();
162 while (MI != TargetMBB->end() && MI->isMetaInstruction())
163 MI++;
165 if (MI == TargetMBB->end())
166 return false;
168 switch (MI->getOpcode()) {
169 case SP::SWAPrr:
170 case SP::SWAPri:
171 case SP::CASArr:
172 insertNop(MI);
173 break;
174 default:
175 break;
179 // Check for load followed by atomic instruction
180 MachineBasicBlock::iterator MI = I;
181 if (!moveNext(MI))
182 return false;
184 switch (MI->getOpcode()) {
185 case SP::SWAPrr:
186 case SP::SWAPri:
187 case SP::CASArr:
188 break;
189 default:
190 return false;
192 insertNop(MI);
193 return true;
196 // Do not allow functions to begin with an atomic instruction
197 bool ErrataWorkaround::checkSeqTN0010First(MachineBasicBlock &MBB) {
198 MachineBasicBlock::iterator I = MBB.begin();
199 while (I != MBB.end() && I->isMetaInstruction())
200 I++;
201 switch (I->getOpcode()) {
202 case SP::SWAPrr:
203 case SP::SWAPri:
204 case SP::CASArr:
205 break;
206 default:
207 return false;
209 insertNop(I);
210 return true;
213 // Inserts a NOP instruction at the target of an integer branch if the
214 // target is a floating-point instruction or floating-point branch.
215 bool ErrataWorkaround::checkSeqTN0012(MachineBasicBlock::iterator I) {
217 if (I->getOpcode() != SP::BCOND && I->getOpcode() != SP::BCONDA)
218 return false;
220 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
221 MachineBasicBlock::iterator MI = TargetMBB->begin();
223 while (MI != TargetMBB->end() && MI->isMetaInstruction())
224 MI++;
226 if (MI == TargetMBB->end())
227 return false;
229 if (!isFloat(MI) && MI->getOpcode() != SP::FBCOND)
230 return false;
232 insertNop(MI);
233 return true;
236 // Prevents the following code sequence from being generated:
237 // (div/sqrt) -> (2 to 3 floating-point operations or loads) -> (div/sqrt)
238 // If the sequence is detected one or two NOP instruction are inserted after
239 // the first div/sqrt instruction. No NOPs are inserted if one of the floating-
240 // point instructions in the middle of the sequence is a (div/sqrt), or if
241 // they have dependency on the destination register of the first (div/sqrt).
243 // The function also prevents the following code sequence from being generated,
244 // (div/sqrt) -> (branch), by inserting a NOP instruction after the (div/sqrt).
245 bool ErrataWorkaround::checkSeqTN0013(MachineBasicBlock::iterator I) {
247 if (!isDivSqrt(I))
248 return false;
250 unsigned dstReg = I->getOperand(0).getReg();
252 MachineBasicBlock::iterator MI = I;
253 if (!moveNext(MI))
254 return false;
256 if (MI->isBranch()) {
257 insertNop(MI);
258 return true;
261 MachineBasicBlock::iterator PatchHere = MI;
263 unsigned fpFound = 0;
264 for (unsigned i = 0; i < 4; i++) {
266 if (!isFloat(MI)) {
267 if (!moveNext(MI))
268 return false;
269 continue;
272 if (MI->readsRegister(dstReg, TRI))
273 return false;
275 if (isDivSqrt(MI)) {
276 if (i < 2)
277 return false;
278 if (fpFound < 2)
279 return false;
281 insertNop(PatchHere);
282 if (i == 2)
283 insertNop(PatchHere);
284 return true;
287 fpFound++;
288 if (!moveNext(MI))
289 return false;
292 return false;
295 bool ErrataWorkaround::runOnMachineFunction(MachineFunction &MF) {
296 bool Changed = false;
297 ST = &MF.getSubtarget<SparcSubtarget>();
299 if (!(ST->fixTN0009() || ST->fixTN0010() || ST->fixTN0012() ||
300 ST->fixTN0013()))
301 return false;
303 TII = ST->getInstrInfo();
304 TRI = ST->getRegisterInfo();
306 if (ST->fixTN0010())
307 Changed |= checkSeqTN0010First(MF.front());
309 for (auto &MBB : MF) {
310 for (auto &I : MBB) {
311 if (ST->fixTN0009()) {
312 Changed |= checkSeqTN0009A(I);
313 Changed |= checkSeqTN0009B(I);
315 if (ST->fixTN0010())
316 Changed |= checkSeqTN0010(I);
317 if (ST->fixTN0012())
318 Changed |= checkSeqTN0012(I);
319 if (ST->fixTN0013())
320 Changed |= checkSeqTN0013(I);
323 return Changed;
326 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
327 : MachineFunctionPass(ID) {}
329 //*****************************************************************************
330 //**** InsertNOPLoad pass
331 //*****************************************************************************
332 // This pass fixes the incorrectly working Load instructions that exists for
333 // some earlier versions of the LEON processor line. NOP instructions must
334 // be inserted after the load instruction to ensure that the Load instruction
335 // behaves as expected for these processors.
337 // This pass inserts a NOP after any LD or LDF instruction.
339 char InsertNOPLoad::ID = 0;
341 InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}
343 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
344 Subtarget = &MF.getSubtarget<SparcSubtarget>();
345 if (!Subtarget->insertNOPLoad())
346 return false;
348 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
349 DebugLoc DL = DebugLoc();
351 bool Modified = false;
352 for (MachineBasicBlock &MBB : MF) {
353 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
354 MachineInstr &MI = *MBBI;
355 unsigned Opcode = MI.getOpcode();
356 if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
357 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
358 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
359 Modified = true;
364 return Modified;
369 //*****************************************************************************
370 //**** DetectRoundChange pass
371 //*****************************************************************************
372 // To prevent any explicit change of the default rounding mode, this pass
373 // detects any call of the fesetround function.
374 // A warning is generated to ensure the user knows this has happened.
376 // Detects an erratum in UT699 LEON 3 processor
378 char DetectRoundChange::ID = 0;
380 DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}
382 bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
383 Subtarget = &MF.getSubtarget<SparcSubtarget>();
384 if (!Subtarget->detectRoundChange())
385 return false;
387 bool Modified = false;
388 for (MachineBasicBlock &MBB : MF) {
389 for (MachineInstr &MI : MBB) {
390 unsigned Opcode = MI.getOpcode();
391 if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
392 MachineOperand &MO = MI.getOperand(0);
394 if (MO.isGlobal()) {
395 StringRef FuncName = MO.getGlobal()->getName();
396 if (FuncName.compare_insensitive("fesetround") == 0) {
397 errs() << "Error: You are using the detectroundchange "
398 "option to detect rounding changes that will "
399 "cause LEON errata. The only way to fix this "
400 "is to remove the call to fesetround from "
401 "the source code.\n";
408 return Modified;
411 //*****************************************************************************
412 //**** FixAllFDIVSQRT pass
413 //*****************************************************************************
414 // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
415 // exist for some earlier versions of the LEON processor line. Five NOP
416 // instructions need to be inserted after these instructions to ensure the
417 // correct result is placed in the destination registers before they are used.
419 // This pass implements two fixes:
420 // 1) fixing the FSQRTS and FSQRTD instructions.
421 // 2) fixing the FDIVS and FDIVD instructions.
423 // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
424 // the pipeline when this option is enabled, so this pass needs only to deal
425 // with the changes that still need implementing for the "double" versions
426 // of these instructions.
428 char FixAllFDIVSQRT::ID = 0;
430 FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}
432 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
433 Subtarget = &MF.getSubtarget<SparcSubtarget>();
434 if (!Subtarget->fixAllFDIVSQRT())
435 return false;
437 const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
438 DebugLoc DL = DebugLoc();
440 bool Modified = false;
441 for (MachineBasicBlock &MBB : MF) {
442 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
443 MachineInstr &MI = *MBBI;
444 unsigned Opcode = MI.getOpcode();
446 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
447 // switched on so we don't need to check for them here. They will
448 // already have been converted to FSQRTD or FDIVD earlier in the
449 // pipeline.
450 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
451 for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
452 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
454 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
455 for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
456 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
458 Modified = true;
463 return Modified;