xref: /llvm-project/llvm/lib/Target/Sparc/LeonPasses.cpp (revision 7faf1a0868cb6a6a05e454044239292c454e0a71)
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"
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"
19 
20 using namespace llvm;
21 
22 char ErrataWorkaround::ID = 0;
23 
24 ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID) {
25   initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry());
26 }
27 
28 INITIALIZE_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.
34 bool ErrataWorkaround::moveNext(MachineBasicBlock::iterator &I) {
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 
52 void ErrataWorkaround::insertNop(MachineBasicBlock::iterator I) {
53   BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP));
54 }
55 
56 bool ErrataWorkaround::isFloat(MachineBasicBlock::iterator I) {
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 
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;
78   }
79   return false;
80 }
81 
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;
99   }
100 
101   MachineBasicBlock::iterator MI = I;
102   if (!moveNext(MI))
103     return false;
104 
105   if (MI->mayStore() || MI->mayLoad())
106     return false;
107 
108   MachineBasicBlock::iterator PatchHere = MI;
109 
110   if (!moveNext(MI))
111     return false;
112 
113   if (!MI->mayStore())
114     return false;
115 
116   insertNop(PatchHere);
117   return true;
118 }
119 
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) {
125 
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;
134   }
135 
136   MachineBasicBlock::iterator MI = I;
137 
138   if (!moveNext(MI))
139     return false;
140 
141   if (!MI->mayStore())
142     return false;
143 
144   insertNop(MI);
145   return true;
146 }
147 
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) {
152 
153   // Check for load instruction or branch bundled with load instruction
154   if (!I->mayLoad())
155     return false;
156 
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();
161 
162     while (MI != TargetMBB->end() && MI->isMetaInstruction())
163       MI++;
164 
165     if (MI == TargetMBB->end())
166       return false;
167 
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;
176     }
177   }
178 
179   // Check for load followed by atomic instruction
180   MachineBasicBlock::iterator MI = I;
181   if (!moveNext(MI))
182     return false;
183 
184   switch (MI->getOpcode()) {
185   case SP::SWAPrr:
186   case SP::SWAPri:
187   case SP::CASArr:
188     break;
189   default:
190     return false;
191   }
192   insertNop(MI);
193   return true;
194 }
195 
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;
208   }
209   insertNop(I);
210   return true;
211 }
212 
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) {
216 
217   if (I->getOpcode() != SP::BCOND && I->getOpcode() != SP::BCONDA)
218     return false;
219 
220   MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB();
221   MachineBasicBlock::iterator MI = TargetMBB->begin();
222 
223   while (MI != TargetMBB->end() && MI->isMetaInstruction())
224     MI++;
225 
226   if (MI == TargetMBB->end())
227     return false;
228 
229   if (!isFloat(MI) && MI->getOpcode() != SP::FBCOND)
230     return false;
231 
232   insertNop(MI);
233   return true;
234 }
235 
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).
242 //
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) {
246 
247   if (!isDivSqrt(I))
248     return false;
249 
250   unsigned dstReg = I->getOperand(0).getReg();
251 
252   MachineBasicBlock::iterator MI = I;
253   if (!moveNext(MI))
254     return false;
255 
256   if (MI->isBranch()) {
257     insertNop(MI);
258     return true;
259   }
260 
261   MachineBasicBlock::iterator PatchHere = MI;
262 
263   unsigned fpFound = 0;
264   for (unsigned i = 0; i < 4; i++) {
265 
266     if (!isFloat(MI)) {
267       if (!moveNext(MI))
268         return false;
269       continue;
270     }
271 
272     if (MI->readsRegister(dstReg, TRI))
273       return false;
274 
275     if (isDivSqrt(MI)) {
276       if (i < 2)
277         return false;
278       if (fpFound < 2)
279         return false;
280 
281       insertNop(PatchHere);
282       if (i == 2)
283         insertNop(PatchHere);
284       return true;
285     }
286 
287     fpFound++;
288     if (!moveNext(MI))
289       return false;
290   }
291 
292   return false;
293 }
294 
295 bool ErrataWorkaround::runOnMachineFunction(MachineFunction &MF) {
296   bool Changed = false;
297   ST = &MF.getSubtarget<SparcSubtarget>();
298 
299   if (!(ST->fixTN0009() || ST->fixTN0010() || ST->fixTN0012() ||
300         ST->fixTN0013()))
301     return false;
302 
303   TII = ST->getInstrInfo();
304   TRI = ST->getRegisterInfo();
305 
306   if (ST->fixTN0010())
307     Changed |= checkSeqTN0010First(MF.front());
308 
309   for (auto &MBB : MF) {
310     for (auto &I : MBB) {
311       if (ST->fixTN0009()) {
312         Changed |= checkSeqTN0009A(I);
313         Changed |= checkSeqTN0009B(I);
314       }
315       if (ST->fixTN0010())
316         Changed |= checkSeqTN0010(I);
317       if (ST->fixTN0012())
318         Changed |= checkSeqTN0012(I);
319       if (ST->fixTN0013())
320         Changed |= checkSeqTN0013(I);
321     }
322   }
323   return Changed;
324 }
325 
326 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
327     : MachineFunctionPass(ID) {}
328 
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.
336 //
337 // This pass inserts a NOP after any LD or LDF instruction.
338 //
339 char InsertNOPLoad::ID = 0;
340 
341 InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}
342 
343 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
344   Subtarget = &MF.getSubtarget<SparcSubtarget>();
345   if (!Subtarget->insertNOPLoad())
346     return false;
347 
348   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
349   DebugLoc DL = DebugLoc();
350 
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;
360       }
361     }
362   }
363 
364   return Modified;
365 }
366 
367 
368 
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.
375 //
376 // Detects an erratum in UT699 LEON 3 processor
377 
378 char DetectRoundChange::ID = 0;
379 
380 DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}
381 
382 bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
383   Subtarget = &MF.getSubtarget<SparcSubtarget>();
384   if (!Subtarget->detectRoundChange())
385     return false;
386 
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);
393 
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";
402           }
403         }
404       }
405     }
406   }
407 
408   return Modified;
409 }
410 
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.
418 //
419 // This pass implements two fixes:
420 //  1) fixing the FSQRTS and FSQRTD instructions.
421 //  2) fixing the FDIVS and FDIVD instructions.
422 //
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.
427 //
428 char FixAllFDIVSQRT::ID = 0;
429 
430 FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}
431 
432 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
433   Subtarget = &MF.getSubtarget<SparcSubtarget>();
434   if (!Subtarget->fixAllFDIVSQRT())
435     return false;
436 
437   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
438   DebugLoc DL = DebugLoc();
439 
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();
445 
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));
453 
454         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
455         for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
456           BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
457 
458         Modified = true;
459       }
460     }
461   }
462 
463   return Modified;
464 }
465