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/LLVMContext.h"
20 #include "llvm/Support/raw_ostream.h"
21 using namespace llvm;
22 
23 LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char &ID)
24     : MachineFunctionPass(ID) {}
25 
26 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
27     : MachineFunctionPass(ID) {}
28 
29 int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
30                                                    int OperandIndex) {
31   if (MI.getNumOperands() > 0) {
32     if (OperandIndex == LAST_OPERAND) {
33       OperandIndex = MI.getNumOperands() - 1;
34     }
35 
36     if (MI.getNumOperands() > (unsigned)OperandIndex &&
37         MI.getOperand(OperandIndex).isReg()) {
38       return (int)MI.getOperand(OperandIndex).getReg();
39     }
40   }
41 
42   static int NotFoundIndex = -10;
43   // Return a different number each time to avoid any comparisons between the
44   // values returned.
45   NotFoundIndex -= 10;
46   return NotFoundIndex;
47 }
48 
49 // finds a new free FP register
50 // checks also the AllocatedRegisters vector
51 int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
52   for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
53     if (!MRI.isPhysRegUsed(RegisterIndex) &&
54         !(std::find(UsedRegisters.begin(), UsedRegisters.end(),
55                     RegisterIndex) != UsedRegisters.end())) {
56       return RegisterIndex;
57     }
58   }
59 
60   return -1;
61 }
62 
63 //*****************************************************************************
64 //**** InsertNOPLoad pass
65 //*****************************************************************************
66 // This pass fixes the incorrectly working Load instructions that exists for
67 // some earlier versions of the LEON processor line. NOP instructions must
68 // be inserted after the load instruction to ensure that the Load instruction
69 // behaves as expected for these processors.
70 //
71 // This pass inserts a NOP after any LD or LDF instruction.
72 //
73 char InsertNOPLoad::ID = 0;
74 
75 InsertNOPLoad::InsertNOPLoad(TargetMachine &tm)
76     : LEONMachineFunctionPass(tm, ID) {}
77 
78 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
79   Subtarget = &MF.getSubtarget<SparcSubtarget>();
80   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
81   DebugLoc DL = DebugLoc();
82 
83   bool Modified = false;
84   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
85     MachineBasicBlock &MBB = *MFI;
86     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
87       MachineInstr &MI = *MBBI;
88       unsigned Opcode = MI.getOpcode();
89       if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
90         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
91         BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
92         Modified = true;
93       } else if (MI.isInlineAsm()) {
94         // Look for an inline ld or ldf instruction.
95         StringRef AsmString =
96             MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
97         if (AsmString.startswith_lower("ld")) {
98           MachineBasicBlock::iterator NMBBI = std::next(MBBI);
99           BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
100           Modified = true;
101         }
102       }
103     }
104   }
105 
106   return Modified;
107 }
108 
109 //*****************************************************************************
110 //**** FixFSMULD pass
111 //*****************************************************************************
112 // This pass fixes the incorrectly working FSMULD instruction that exists for
113 // some earlier versions of the LEON processor line.
114 //
115 // The pass should convert the FSMULD operands to double precision in scratch
116 // registers, then calculate the result with the FMULD instruction. Therefore,
117 // the pass should replace operations of the form:
118 // fsmuld %f20,%f21,%f8
119 // with the sequence:
120 // fstod %f20,%f0
121 // fstod %f21,%f2
122 // fmuld %f0,%f2,%f8
123 //
124 char FixFSMULD::ID = 0;
125 
126 FixFSMULD::FixFSMULD(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
127 
128 bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
129   Subtarget = &MF.getSubtarget<SparcSubtarget>();
130   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
131   DebugLoc DL = DebugLoc();
132 
133   bool Modified = false;
134   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
135     MachineBasicBlock &MBB = *MFI;
136     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
137 
138       MachineInstr &MI = *MBBI;
139       unsigned Opcode = MI.getOpcode();
140 
141       const int UNASSIGNED_INDEX = -1;
142       int Reg1Index = UNASSIGNED_INDEX;
143       int Reg2Index = UNASSIGNED_INDEX;
144       int Reg3Index = UNASSIGNED_INDEX;
145 
146       if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) {
147         // take the registers from fsmuld %f20,%f21,%f8
148         Reg1Index = MI.getOperand(0).getReg();
149         Reg2Index = MI.getOperand(1).getReg();
150         Reg3Index = MI.getOperand(2).getReg();
151       } else if (MI.isInlineAsm()) {
152         std::string AsmString(
153             MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
154         std::string FMULSOpCoode("fsmuld");
155         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(),
156                        ::tolower);
157         if (AsmString.find(FMULSOpCoode) ==
158             0) { // this is an inline FSMULD instruction
159 
160           unsigned StartOp = InlineAsm::MIOp_FirstOperand;
161 
162           // extracts the registers from the inline assembly instruction
163           for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
164             const MachineOperand &MO = MI.getOperand(i);
165             if (MO.isReg()) {
166               if (Reg1Index == UNASSIGNED_INDEX)
167                 Reg1Index = MO.getReg();
168               else if (Reg2Index == UNASSIGNED_INDEX)
169                 Reg2Index = MO.getReg();
170               else if (Reg3Index == UNASSIGNED_INDEX)
171                 Reg3Index = MO.getReg();
172             }
173             if (Reg3Index != UNASSIGNED_INDEX)
174               break;
175           }
176         }
177       }
178 
179       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
180           Reg3Index != UNASSIGNED_INDEX) {
181         clearUsedRegisterList();
182         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
183         // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
184         markRegisterUsed(Reg3Index);
185         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
186         markRegisterUsed(ScratchReg1Index);
187         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
188         markRegisterUsed(ScratchReg2Index);
189 
190         if (ScratchReg1Index == UNASSIGNED_INDEX ||
191             ScratchReg2Index == UNASSIGNED_INDEX) {
192           errs() << "Cannot allocate free scratch registers for the FixFSMULD "
193                     "pass."
194                  << "\n";
195         } else {
196           // create fstod %f20,%f0
197           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
198               .addReg(ScratchReg1Index)
199               .addReg(Reg1Index);
200 
201           // create fstod %f21,%f2
202           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
203               .addReg(ScratchReg2Index)
204               .addReg(Reg2Index);
205 
206           // create fmuld %f0,%f2,%f8
207           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
208               .addReg(Reg3Index)
209               .addReg(ScratchReg1Index)
210               .addReg(ScratchReg2Index);
211 
212           MI.eraseFromParent();
213           MBBI = NMBBI;
214 
215           Modified = true;
216         }
217       }
218     }
219   }
220 
221   return Modified;
222 }
223 
224 //*****************************************************************************
225 //**** ReplaceFMULS pass
226 //*****************************************************************************
227 // This pass fixes the incorrectly working FMULS instruction that exists for
228 // some earlier versions of the LEON processor line.
229 //
230 // This pass converts the FMULS operands to double precision in scratch
231 // registers, then calculates the result with the FMULD instruction.
232 // The pass should replace operations of the form:
233 // fmuls %f20,%f21,%f8
234 // with the sequence:
235 // fstod %f20,%f0
236 // fstod %f21,%f2
237 // fmuld %f0,%f2,%f8
238 //
239 char ReplaceFMULS::ID = 0;
240 
241 ReplaceFMULS::ReplaceFMULS(TargetMachine &tm)
242     : LEONMachineFunctionPass(tm, ID) {}
243 
244 bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
245   Subtarget = &MF.getSubtarget<SparcSubtarget>();
246   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
247   DebugLoc DL = DebugLoc();
248 
249   bool Modified = false;
250   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
251     MachineBasicBlock &MBB = *MFI;
252     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
253       MachineInstr &MI = *MBBI;
254       unsigned Opcode = MI.getOpcode();
255 
256       const int UNASSIGNED_INDEX = -1;
257       int Reg1Index = UNASSIGNED_INDEX;
258       int Reg2Index = UNASSIGNED_INDEX;
259       int Reg3Index = UNASSIGNED_INDEX;
260 
261       if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
262         // take the registers from fmuls %f20,%f21,%f8
263         Reg1Index = MI.getOperand(0).getReg();
264         Reg2Index = MI.getOperand(1).getReg();
265         Reg3Index = MI.getOperand(2).getReg();
266       } else if (MI.isInlineAsm()) {
267         std::string AsmString(
268             MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
269         std::string FMULSOpCoode("fmuls");
270         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(),
271                        ::tolower);
272         if (AsmString.find(FMULSOpCoode) ==
273             0) { // this is an inline FMULS instruction
274           unsigned StartOp = InlineAsm::MIOp_FirstOperand;
275 
276           // extracts the registers from the inline assembly instruction
277           for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
278             const MachineOperand &MO = MI.getOperand(i);
279             if (MO.isReg()) {
280               if (Reg1Index == UNASSIGNED_INDEX)
281                 Reg1Index = MO.getReg();
282               else if (Reg2Index == UNASSIGNED_INDEX)
283                 Reg2Index = MO.getReg();
284               else if (Reg3Index == UNASSIGNED_INDEX)
285                 Reg3Index = MO.getReg();
286             }
287             if (Reg3Index != UNASSIGNED_INDEX)
288               break;
289           }
290         }
291       }
292 
293       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
294           Reg3Index != UNASSIGNED_INDEX) {
295         clearUsedRegisterList();
296         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
297         // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
298         markRegisterUsed(Reg3Index);
299         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
300         markRegisterUsed(ScratchReg1Index);
301         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
302         markRegisterUsed(ScratchReg2Index);
303 
304         if (ScratchReg1Index == UNASSIGNED_INDEX ||
305             ScratchReg2Index == UNASSIGNED_INDEX) {
306           errs() << "Cannot allocate free scratch registers for the "
307                     "ReplaceFMULS pass."
308                  << "\n";
309         } else {
310           // create fstod %f20,%f0
311           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
312               .addReg(ScratchReg1Index)
313               .addReg(Reg1Index);
314 
315           // create fstod %f21,%f2
316           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
317               .addReg(ScratchReg2Index)
318               .addReg(Reg2Index);
319 
320           // create fmuld %f0,%f2,%f8
321           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
322               .addReg(Reg3Index)
323               .addReg(ScratchReg1Index)
324               .addReg(ScratchReg2Index);
325 
326           MI.eraseFromParent();
327           MBBI = NMBBI;
328 
329           Modified = true;
330         }
331       }
332     }
333   }
334 
335   return Modified;
336 }
337 
338 //*****************************************************************************
339 //**** FixAllFDIVSQRT pass
340 //*****************************************************************************
341 // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
342 // exist for some earlier versions of the LEON processor line. Five NOP
343 // instructions need to be inserted after these instructions to ensure the
344 // correct result is placed in the destination registers before they are used.
345 //
346 // This pass implements two fixes:
347 //  1) fixing the FSQRTS and FSQRTD instructions.
348 //  2) fixing the FDIVS and FDIVD instructions.
349 //
350 // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
351 // the pipeline when this option is enabled, so this pass needs only to deal
352 // with the changes that still need implementing for the "double" versions
353 // of these instructions.
354 //
355 char FixAllFDIVSQRT::ID = 0;
356 
357 FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm)
358     : LEONMachineFunctionPass(tm, ID) {}
359 
360 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
361   Subtarget = &MF.getSubtarget<SparcSubtarget>();
362   const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
363   DebugLoc DL = DebugLoc();
364 
365   bool Modified = false;
366   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
367     MachineBasicBlock &MBB = *MFI;
368     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
369       MachineInstr &MI = *MBBI;
370       unsigned Opcode = MI.getOpcode();
371 
372       if (MI.isInlineAsm()) {
373         std::string AsmString(
374             MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
375         std::string FSQRTDOpCode("fsqrtd");
376         std::string FDIVDOpCode("fdivd");
377         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(),
378                        ::tolower);
379         if (AsmString.find(FSQRTDOpCode) ==
380             0) { // this is an inline fsqrts instruction
381           Opcode = SP::FSQRTD;
382         } else if (AsmString.find(FDIVDOpCode) ==
383                    0) { // this is an inline fsqrts instruction
384           Opcode = SP::FDIVD;
385         }
386       }
387 
388       // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
389       // switched on so we don't need to check for them here. They will
390       // already have been converted to FSQRTD or FDIVD earlier in the
391       // pipeline.
392       if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
393         for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
394           BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
395 
396         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
397         for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
398           BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
399 
400         Modified = true;
401       }
402     }
403   }
404 
405   return Modified;
406 }
407