1 //===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
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
7 //===----------------------------------------------------------------------===//
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"
22 char ErrataWorkaround::ID
= 0;
24 ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID
) {
25 initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry());
28 INITIALIZE_PASS(ErrataWorkaround
, "errata-workaround", "Errata workaround pass",
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();
41 while (I
== MBB
->end()) {
42 if (MBB
->getFallThrough() == nullptr)
44 MBB
= MBB
->getFallThrough();
47 } while (I
->isMetaInstruction() || I
->isInlineAsm());
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)
60 if (!I
->getOperand(0).isReg())
63 unsigned reg
= I
->getOperand(0).getReg();
65 if (!SP::FPRegsRegClass
.contains(reg
) && !SP::DFPRegsRegClass
.contains(reg
))
71 bool ErrataWorkaround::isDivSqrt(MachineBasicBlock::iterator I
) {
72 switch (I
->getOpcode()) {
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()) {
101 MachineBasicBlock::iterator MI
= I
;
105 if (MI
->mayStore() || MI
->mayLoad())
108 MachineBasicBlock::iterator PatchHere
= MI
;
116 insertNop(PatchHere
);
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()) {
136 MachineBasicBlock::iterator MI
= I
;
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
157 // Check for branch to atomic instruction with load in delay slot
159 MachineBasicBlock
*TargetMBB
= I
->getOperand(0).getMBB();
160 MachineBasicBlock::iterator MI
= TargetMBB
->begin();
162 while (MI
!= TargetMBB
->end() && MI
->isMetaInstruction())
165 if (MI
== TargetMBB
->end())
168 switch (MI
->getOpcode()) {
179 // Check for load followed by atomic instruction
180 MachineBasicBlock::iterator MI
= I
;
184 switch (MI
->getOpcode()) {
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())
201 switch (I
->getOpcode()) {
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
)
220 MachineBasicBlock
*TargetMBB
= I
->getOperand(0).getMBB();
221 MachineBasicBlock::iterator MI
= TargetMBB
->begin();
223 while (MI
!= TargetMBB
->end() && MI
->isMetaInstruction())
226 if (MI
== TargetMBB
->end())
229 if (!isFloat(MI
) && MI
->getOpcode() != SP::FBCOND
)
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
) {
250 unsigned dstReg
= I
->getOperand(0).getReg();
252 MachineBasicBlock::iterator MI
= I
;
256 if (MI
->isBranch()) {
261 MachineBasicBlock::iterator PatchHere
= MI
;
263 unsigned fpFound
= 0;
264 for (unsigned i
= 0; i
< 4; i
++) {
272 if (MI
->readsRegister(dstReg
, TRI
))
281 insertNop(PatchHere
);
283 insertNop(PatchHere
);
295 bool ErrataWorkaround::runOnMachineFunction(MachineFunction
&MF
) {
296 bool Changed
= false;
297 ST
= &MF
.getSubtarget
<SparcSubtarget
>();
299 if (!(ST
->fixTN0009() || ST
->fixTN0010() || ST
->fixTN0012() ||
303 TII
= ST
->getInstrInfo();
304 TRI
= ST
->getRegisterInfo();
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
);
316 Changed
|= checkSeqTN0010(I
);
318 Changed
|= checkSeqTN0012(I
);
320 Changed
|= checkSeqTN0013(I
);
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())
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
));
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())
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);
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";
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())
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
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
));