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