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