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 | LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) |
23 | : MachineFunctionPass(ID) {} |
24 | |
25 | //***************************************************************************** |
26 | //**** InsertNOPLoad pass |
27 | //***************************************************************************** |
28 | // This pass fixes the incorrectly working Load instructions that exists for |
29 | // some earlier versions of the LEON processor line. NOP instructions must |
30 | // be inserted after the load instruction to ensure that the Load instruction |
31 | // behaves as expected for these processors. |
32 | // |
33 | // This pass inserts a NOP after any LD or LDF instruction. |
34 | // |
35 | char InsertNOPLoad::ID = 0; |
36 | |
37 | InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {} |
38 | |
39 | bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { |
40 | Subtarget = &MF.getSubtarget<SparcSubtarget>(); |
41 | if (!Subtarget->insertNOPLoad()) |
42 | return false; |
43 | |
44 | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); |
45 | DebugLoc DL = DebugLoc(); |
46 | |
47 | bool Modified = false; |
48 | for (MachineBasicBlock &MBB : MF) { |
49 | for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { |
50 | MachineInstr &MI = *MBBI; |
51 | unsigned Opcode = MI.getOpcode(); |
52 | if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { |
53 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
54 | BuildMI(BB&: MBB, I: NMBBI, MIMD: DL, MCID: TII.get(Opcode: SP::NOP)); |
55 | Modified = true; |
56 | } |
57 | } |
58 | } |
59 | |
60 | return Modified; |
61 | } |
62 | |
63 | |
64 | |
65 | //***************************************************************************** |
66 | //**** DetectRoundChange pass |
67 | //***************************************************************************** |
68 | // To prevent any explicit change of the default rounding mode, this pass |
69 | // detects any call of the fesetround function. |
70 | // A warning is generated to ensure the user knows this has happened. |
71 | // |
72 | // Detects an erratum in UT699 LEON 3 processor |
73 | |
74 | char DetectRoundChange::ID = 0; |
75 | |
76 | DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {} |
77 | |
78 | bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) { |
79 | Subtarget = &MF.getSubtarget<SparcSubtarget>(); |
80 | if (!Subtarget->detectRoundChange()) |
81 | return false; |
82 | |
83 | bool Modified = false; |
84 | for (MachineBasicBlock &MBB : MF) { |
85 | for (MachineInstr &MI : MBB) { |
86 | unsigned Opcode = MI.getOpcode(); |
87 | if (Opcode == SP::CALL && MI.getNumOperands() > 0) { |
88 | MachineOperand &MO = MI.getOperand(i: 0); |
89 | |
90 | if (MO.isGlobal()) { |
91 | StringRef FuncName = MO.getGlobal()->getName(); |
92 | if (FuncName.compare_insensitive(RHS: "fesetround" ) == 0) { |
93 | errs() << "Error: You are using the detectroundchange " |
94 | "option to detect rounding changes that will " |
95 | "cause LEON errata. The only way to fix this " |
96 | "is to remove the call to fesetround from " |
97 | "the source code.\n" ; |
98 | } |
99 | } |
100 | } |
101 | } |
102 | } |
103 | |
104 | return Modified; |
105 | } |
106 | |
107 | //***************************************************************************** |
108 | //**** FixAllFDIVSQRT pass |
109 | //***************************************************************************** |
110 | // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that |
111 | // exist for some earlier versions of the LEON processor line. Five NOP |
112 | // instructions need to be inserted after these instructions to ensure the |
113 | // correct result is placed in the destination registers before they are used. |
114 | // |
115 | // This pass implements two fixes: |
116 | // 1) fixing the FSQRTS and FSQRTD instructions. |
117 | // 2) fixing the FDIVS and FDIVD instructions. |
118 | // |
119 | // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in |
120 | // the pipeline when this option is enabled, so this pass needs only to deal |
121 | // with the changes that still need implementing for the "double" versions |
122 | // of these instructions. |
123 | // |
124 | char FixAllFDIVSQRT::ID = 0; |
125 | |
126 | FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {} |
127 | |
128 | bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { |
129 | Subtarget = &MF.getSubtarget<SparcSubtarget>(); |
130 | if (!Subtarget->fixAllFDIVSQRT()) |
131 | return false; |
132 | |
133 | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); |
134 | DebugLoc DL = DebugLoc(); |
135 | |
136 | bool Modified = false; |
137 | for (MachineBasicBlock &MBB : MF) { |
138 | for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { |
139 | MachineInstr &MI = *MBBI; |
140 | unsigned Opcode = MI.getOpcode(); |
141 | |
142 | // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is |
143 | // switched on so we don't need to check for them here. They will |
144 | // already have been converted to FSQRTD or FDIVD earlier in the |
145 | // pipeline. |
146 | if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { |
147 | for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) |
148 | BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII.get(Opcode: SP::NOP)); |
149 | |
150 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
151 | for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) |
152 | BuildMI(BB&: MBB, I: NMBBI, MIMD: DL, MCID: TII.get(Opcode: SP::NOP)); |
153 | |
154 | Modified = true; |
155 | } |
156 | } |
157 | } |
158 | |
159 | return Modified; |
160 | } |
161 | |