]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
MFV r321673:
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / Sparc / LeonPasses.cpp
1 //===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "LeonPasses.h"
14 #include "llvm/CodeGen/ISDOpcodes.h"
15 #include "llvm/CodeGen/MachineFunction.h"
16 #include "llvm/CodeGen/MachineInstr.h"
17 #include "llvm/CodeGen/MachineInstrBuilder.h"
18 #include "llvm/CodeGen/MachineRegisterInfo.h"
19 #include "llvm/IR/DiagnosticInfo.h"
20 #include "llvm/IR/LLVMContext.h"
21 #include "llvm/Support/raw_ostream.h"
22 using namespace llvm;
23
24 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
25     : MachineFunctionPass(ID) {}
26
27 int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
28                                                    int OperandIndex) {
29   if (MI.getNumOperands() > 0) {
30     if (OperandIndex == LAST_OPERAND) {
31       OperandIndex = MI.getNumOperands() - 1;
32     }
33
34     if (MI.getNumOperands() > (unsigned)OperandIndex &&
35         MI.getOperand(OperandIndex).isReg()) {
36       return (int)MI.getOperand(OperandIndex).getReg();
37     }
38   }
39
40   static int NotFoundIndex = -10;
41   // Return a different number each time to avoid any comparisons between the
42   // values returned.
43   NotFoundIndex -= 10;
44   return NotFoundIndex;
45 }
46
47 // finds a new free FP register
48 // checks also the AllocatedRegisters vector
49 int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
50   for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
51     if (!MRI.isPhysRegUsed(RegisterIndex) &&
52         !is_contained(UsedRegisters, RegisterIndex)) {
53       return RegisterIndex;
54     }
55   }
56
57   return -1;
58 }
59
60 //*****************************************************************************
61 //**** InsertNOPLoad pass
62 //*****************************************************************************
63 // This pass fixes the incorrectly working Load instructions that exists for
64 // some earlier versions of the LEON processor line. NOP instructions must
65 // be inserted after the load instruction to ensure that the Load instruction
66 // behaves as expected for these processors.
67 //
68 // This pass inserts a NOP after any LD or LDF instruction.
69 //
70 char InsertNOPLoad::ID = 0;
71
72 InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}
73
74 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
75   Subtarget = &MF.getSubtarget<SparcSubtarget>();
76   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
77   DebugLoc DL = DebugLoc();
78
79   bool Modified = false;
80   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
81     MachineBasicBlock &MBB = *MFI;
82     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
83       MachineInstr &MI = *MBBI;
84       unsigned Opcode = MI.getOpcode();
85       if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
86         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
87         BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
88         Modified = true;
89       }
90     }
91   }
92
93   return Modified;
94 }
95
96 //*****************************************************************************
97 //**** FixFSMULD pass
98 //*****************************************************************************
99 // This pass fixes the incorrectly working FSMULD instruction that exists for
100 // some earlier versions of the LEON processor line.
101 //
102 // The pass should convert the FSMULD operands to double precision in scratch
103 // registers, then calculate the result with the FMULD instruction. Therefore,
104 // the pass should replace operations of the form:
105 // fsmuld %f20,%f21,%f8
106 // with the sequence:
107 // fstod %f20,%f0
108 // fstod %f21,%f2
109 // fmuld %f0,%f2,%f8
110 //
111 char FixFSMULD::ID = 0;
112
113 FixFSMULD::FixFSMULD() : LEONMachineFunctionPass(ID) {}
114
115 bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
116   Subtarget = &MF.getSubtarget<SparcSubtarget>();
117   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
118   DebugLoc DL = DebugLoc();
119
120   bool Modified = false;
121   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
122     MachineBasicBlock &MBB = *MFI;
123     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
124
125       MachineInstr &MI = *MBBI;
126       unsigned Opcode = MI.getOpcode();
127
128       const int UNASSIGNED_INDEX = -1;
129       int Reg1Index = UNASSIGNED_INDEX;
130       int Reg2Index = UNASSIGNED_INDEX;
131       int Reg3Index = UNASSIGNED_INDEX;
132
133       if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) {
134         // take the registers from fsmuld %f20,%f21,%f8
135         Reg1Index = MI.getOperand(0).getReg();
136         Reg2Index = MI.getOperand(1).getReg();
137         Reg3Index = MI.getOperand(2).getReg();
138       }
139
140       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
141           Reg3Index != UNASSIGNED_INDEX) {
142         clearUsedRegisterList();
143         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
144         // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
145         markRegisterUsed(Reg3Index);
146         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
147         markRegisterUsed(ScratchReg1Index);
148         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
149         markRegisterUsed(ScratchReg2Index);
150
151         if (ScratchReg1Index == UNASSIGNED_INDEX ||
152             ScratchReg2Index == UNASSIGNED_INDEX) {
153           errs() << "Cannot allocate free scratch registers for the FixFSMULD "
154                     "pass."
155                  << "\n";
156         } else {
157           // create fstod %f20,%f0
158           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
159               .addReg(ScratchReg1Index)
160               .addReg(Reg1Index);
161
162           // create fstod %f21,%f2
163           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
164               .addReg(ScratchReg2Index)
165               .addReg(Reg2Index);
166
167           // create fmuld %f0,%f2,%f8
168           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
169               .addReg(Reg3Index)
170               .addReg(ScratchReg1Index)
171               .addReg(ScratchReg2Index);
172
173           MI.eraseFromParent();
174           MBBI = NMBBI;
175
176           Modified = true;
177         }
178       }
179     }
180   }
181
182   return Modified;
183 }
184
185 //*****************************************************************************
186 //**** ReplaceFMULS pass
187 //*****************************************************************************
188 // This pass fixes the incorrectly working FMULS instruction that exists for
189 // some earlier versions of the LEON processor line.
190 //
191 // This pass converts the FMULS operands to double precision in scratch
192 // registers, then calculates the result with the FMULD instruction.
193 // The pass should replace operations of the form:
194 // fmuls %f20,%f21,%f8
195 // with the sequence:
196 // fstod %f20,%f0
197 // fstod %f21,%f2
198 // fmuld %f0,%f2,%f8
199 //
200 char ReplaceFMULS::ID = 0;
201
202 ReplaceFMULS::ReplaceFMULS() : LEONMachineFunctionPass(ID) {}
203
204 bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
205   Subtarget = &MF.getSubtarget<SparcSubtarget>();
206   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
207   DebugLoc DL = DebugLoc();
208
209   bool Modified = false;
210   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
211     MachineBasicBlock &MBB = *MFI;
212     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
213       MachineInstr &MI = *MBBI;
214       unsigned Opcode = MI.getOpcode();
215
216       const int UNASSIGNED_INDEX = -1;
217       int Reg1Index = UNASSIGNED_INDEX;
218       int Reg2Index = UNASSIGNED_INDEX;
219       int Reg3Index = UNASSIGNED_INDEX;
220
221       if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
222         // take the registers from fmuls %f20,%f21,%f8
223         Reg1Index = MI.getOperand(0).getReg();
224         Reg2Index = MI.getOperand(1).getReg();
225         Reg3Index = MI.getOperand(2).getReg();
226       }
227
228       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
229           Reg3Index != UNASSIGNED_INDEX) {
230         clearUsedRegisterList();
231         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
232         // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
233         markRegisterUsed(Reg3Index);
234         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
235         markRegisterUsed(ScratchReg1Index);
236         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
237         markRegisterUsed(ScratchReg2Index);
238
239         if (ScratchReg1Index == UNASSIGNED_INDEX ||
240             ScratchReg2Index == UNASSIGNED_INDEX) {
241           errs() << "Cannot allocate free scratch registers for the "
242                     "ReplaceFMULS pass."
243                  << "\n";
244         } else {
245           // create fstod %f20,%f0
246           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
247               .addReg(ScratchReg1Index)
248               .addReg(Reg1Index);
249
250           // create fstod %f21,%f2
251           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
252               .addReg(ScratchReg2Index)
253               .addReg(Reg2Index);
254
255           // create fmuld %f0,%f2,%f8
256           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
257               .addReg(Reg3Index)
258               .addReg(ScratchReg1Index)
259               .addReg(ScratchReg2Index);
260
261           MI.eraseFromParent();
262           MBBI = NMBBI;
263
264           Modified = true;
265         }
266       }
267     }
268   }
269
270   return Modified;
271 }
272
273
274 //*****************************************************************************
275 //**** DetectRoundChange pass
276 //*****************************************************************************
277 // To prevent any explicit change of the default rounding mode, this pass
278 // detects any call of the fesetround function.
279 // A warning is generated to ensure the user knows this has happened.
280 //
281 // Detects an erratum in UT699 LEON 3 processor
282
283 char DetectRoundChange::ID = 0;
284
285 DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}
286
287 bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
288   Subtarget = &MF.getSubtarget<SparcSubtarget>();
289
290   bool Modified = false;
291   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
292     MachineBasicBlock &MBB = *MFI;
293     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
294       MachineInstr &MI = *MBBI;
295       unsigned Opcode = MI.getOpcode();
296       if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
297         MachineOperand &MO = MI.getOperand(0);
298
299         if (MO.isGlobal()) {
300           StringRef FuncName = MO.getGlobal()->getName();
301           if (FuncName.compare_lower("fesetround") == 0) {
302             errs() << "Error: You are using the detectroundchange "
303                       "option to detect rounding changes that will "
304                       "cause LEON errata. The only way to fix this "
305                       "is to remove the call to fesetround from "
306                       "the source code.\n";
307           }
308         }
309       }
310     }
311   }
312
313   return Modified;
314 }
315
316 //*****************************************************************************
317 //**** FixAllFDIVSQRT pass
318 //*****************************************************************************
319 // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
320 // exist for some earlier versions of the LEON processor line. Five NOP
321 // instructions need to be inserted after these instructions to ensure the
322 // correct result is placed in the destination registers before they are used.
323 //
324 // This pass implements two fixes:
325 //  1) fixing the FSQRTS and FSQRTD instructions.
326 //  2) fixing the FDIVS and FDIVD instructions.
327 //
328 // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
329 // the pipeline when this option is enabled, so this pass needs only to deal
330 // with the changes that still need implementing for the "double" versions
331 // of these instructions.
332 //
333 char FixAllFDIVSQRT::ID = 0;
334
335 FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}
336
337 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
338   Subtarget = &MF.getSubtarget<SparcSubtarget>();
339   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
340   DebugLoc DL = DebugLoc();
341
342   bool Modified = false;
343   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
344     MachineBasicBlock &MBB = *MFI;
345     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
346       MachineInstr &MI = *MBBI;
347       unsigned Opcode = MI.getOpcode();
348
349       // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
350       // switched on so we don't need to check for them here. They will
351       // already have been converted to FSQRTD or FDIVD earlier in the
352       // pipeline.
353       if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
354         for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
355           BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
356
357         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
358         for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
359           BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
360
361         Modified = true;
362       }
363     }
364   }
365
366   return Modified;
367 }