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(BB&: *I->getParent(), I, MIMD: I->getDebugLoc(), MCID: TII->get(Opcode: SP::NOP)); |
54 | } |
55 | |
56 | bool ErrataWorkaround::isFloat(MachineBasicBlock::iterator I) { |
57 | if (I->getNumOperands() == 0) |
58 | return false; |
59 | |
60 | if (!I->getOperand(i: 0).isReg()) |
61 | return false; |
62 | |
63 | unsigned reg = I->getOperand(i: 0).getReg(); |
64 | |
65 | if (!SP::FPRegsRegClass.contains(Reg: reg) && !SP::DFPRegsRegClass.contains(Reg: 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(I&: MI)) |
103 | return false; |
104 | |
105 | if (MI->mayStore() || MI->mayLoad()) |
106 | return false; |
107 | |
108 | MachineBasicBlock::iterator PatchHere = MI; |
109 | |
110 | if (!moveNext(I&: MI)) |
111 | return false; |
112 | |
113 | if (!MI->mayStore()) |
114 | return false; |
115 | |
116 | insertNop(I: 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(I&: MI)) |
139 | return false; |
140 | |
141 | if (!MI->mayStore()) |
142 | return false; |
143 | |
144 | insertNop(I: 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(i: 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(I: 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(I&: 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(I: 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(i: 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(I: MI) && MI->getOpcode() != SP::FBCOND) |
230 | return false; |
231 | |
232 | insertNop(I: 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(i: 0).getReg(); |
251 | |
252 | MachineBasicBlock::iterator MI = I; |
253 | if (!moveNext(I&: MI)) |
254 | return false; |
255 | |
256 | if (MI->isBranch()) { |
257 | insertNop(I: 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(I: MI)) { |
267 | if (!moveNext(I&: MI)) |
268 | return false; |
269 | continue; |
270 | } |
271 | |
272 | if (MI->readsRegister(Reg: dstReg, TRI)) |
273 | return false; |
274 | |
275 | if (isDivSqrt(I: MI)) { |
276 | if (i < 2) |
277 | return false; |
278 | if (fpFound < 2) |
279 | return false; |
280 | |
281 | insertNop(I: PatchHere); |
282 | if (i == 2) |
283 | insertNop(I: PatchHere); |
284 | return true; |
285 | } |
286 | |
287 | fpFound++; |
288 | if (!moveNext(I&: 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(MBB&: 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(x: MBBI); |
358 | BuildMI(BB&: MBB, I: NMBBI, MIMD: DL, MCID: TII.get(Opcode: 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(i: 0); |
393 | |
394 | if (MO.isGlobal()) { |
395 | StringRef FuncName = MO.getGlobal()->getName(); |
396 | if (FuncName.compare_insensitive(RHS: "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(BB&: MBB, I: MBBI, MIMD: DL, MCID: TII.get(Opcode: SP::NOP)); |
453 | |
454 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
455 | for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) |
456 | BuildMI(BB&: MBB, I: NMBBI, MIMD: DL, MCID: TII.get(Opcode: SP::NOP)); |
457 | |
458 | Modified = true; |
459 | } |
460 | } |
461 | } |
462 | |
463 | return Modified; |
464 | } |
465 | |