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         std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
173         std::string FMULSOpCoode ("fsmuld");
174         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
175         if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FSMULD instruction
176           //errs() << "Detected InlineAsm FSMULD\n";
177 
178           unsigned StartOp = InlineAsm::MIOp_FirstOperand;
179 
180           //extracts the registers from the inline assembly instruction
181           for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
182             const MachineOperand &MO = MI.getOperand(i);
183             if (MO.isReg()) {
184               if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg();
185               else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg();
186               else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg();
187             }
188             if (Reg3Index != UNASSIGNED_INDEX)
189               break;
190           }
191         }
192       }
193 
194       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) {
195         clearUsedRegisterList();
196         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
197         //Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
198         markRegisterUsed(Reg3Index);
199         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
200         markRegisterUsed(ScratchReg1Index);
201         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
202         markRegisterUsed(ScratchReg2Index);
203 
204         if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) {
205           //errs() << "Cannot allocate free scratch registers for the FixFSMULD pass." << "\n";
206         }
207         else {
208           //create fstod %f20,%f0
209           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
210           .addReg(ScratchReg1Index)
211           .addReg(Reg1Index);
212 
213           //create fstod %f21,%f2
214           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
215           .addReg(ScratchReg2Index)
216           .addReg(Reg2Index);
217 
218           //create fmuld %f0,%f2,%f8
219           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
220           .addReg(Reg3Index)
221           .addReg(ScratchReg1Index)
222           .addReg(ScratchReg2Index);
223 
224           MI.eraseFromParent();
225           MBBI = NMBBI;
226 
227           Modified = true;
228         }
229       }
230     }
231   }
232 
233   return Modified;
234 }
235 
236 
237 //*****************************************************************************
238 //**** ReplaceFMULS pass
239 //*****************************************************************************
240 //This pass converts the FMULS operands to double precision in scratch registers,
241 //then calculates the result with the FMULD instruction.
242 //The pass should replace operations of the form:
243 //fmuls %f20,%f21,%f8
244 //with the sequence:
245 //fstod %f20,%f0
246 //fstod %f21,%f2
247 //fmuld %f0,%f2,%f8
248 //
249 char ReplaceFMULS::ID = 0;
250 
251 ReplaceFMULS::ReplaceFMULS(TargetMachine &tm) :
252                     LEONMachineFunctionPass(tm, ID)
253 {
254 }
255 
256 bool ReplaceFMULS::runOnMachineFunction(MachineFunction& MF)
257 {
258   Subtarget = &MF.getSubtarget<SparcSubtarget>();
259   const TargetInstrInfo& TII = *Subtarget->getInstrInfo();
260   DebugLoc DL = DebugLoc();
261 
262   //errs() << "ReplaceFMULS on function " << MF.getName() << "\n";
263 
264   bool Modified = false;
265   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
266     MachineBasicBlock &MBB = *MFI;
267     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) {
268       MachineInstr &MI = *MBBI;
269       unsigned Opcode = MI.getOpcode();
270 
271       const int UNASSIGNED_INDEX = -1;
272       int Reg1Index = UNASSIGNED_INDEX;
273       int Reg2Index = UNASSIGNED_INDEX;
274       int Reg3Index = UNASSIGNED_INDEX;
275 
276       if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
277         //errs() << "Detected FMULS\n";
278         //take the registers from fmuls %f20,%f21,%f8
279         Reg1Index = MI.getOperand(0).getReg();
280         Reg2Index = MI.getOperand(1).getReg();
281         Reg3Index = MI.getOperand(2).getReg();
282       }
283       else if (MI.isInlineAsm()) {
284         std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
285         std::string FMULSOpCoode ("fmuls");
286         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
287         if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FMULS instruction
288           //errs() << "Detected InlineAsm FMULS\n";
289 
290           unsigned StartOp = InlineAsm::MIOp_FirstOperand;
291 
292           //extracts the registers from the inline assembly instruction
293           for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
294             const MachineOperand &MO = MI.getOperand(i);
295             if (MO.isReg()) {
296               if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg();
297               else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg();
298               else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg();
299             }
300             if (Reg3Index != UNASSIGNED_INDEX)
301               break;
302           }
303         }
304       }
305 
306       if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) {
307         clearUsedRegisterList();
308         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
309         //Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
310         markRegisterUsed(Reg3Index);
311         const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
312         markRegisterUsed(ScratchReg1Index);
313         const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
314         markRegisterUsed(ScratchReg2Index);
315 
316         if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) {
317           //errs() << "Cannot allocate free scratch registers for the ReplaceFMULS pass." << "\n";
318         }
319         else {
320           //create fstod %f20,%f0
321           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
322           .addReg(ScratchReg1Index)
323           .addReg(Reg1Index);
324 
325           //create fstod %f21,%f2
326           BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
327           .addReg(ScratchReg2Index)
328           .addReg(Reg2Index);
329 
330           //create fmuld %f0,%f2,%f8
331           BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
332           .addReg(Reg3Index)
333           .addReg(ScratchReg1Index)
334           .addReg(ScratchReg2Index);
335 
336           MI.eraseFromParent();
337           MBBI = NMBBI;
338 
339           Modified = true;
340         }
341       }
342     }
343   }
344 
345   return Modified;
346 }
347 
348 //*****************************************************************************
349 //**** FixAllFDIVSQRT pass
350 //*****************************************************************************
351 //This pass implements two fixes:
352 // 1) fixing the FSQRTS and FSQRTD instructions;
353 // 2) fixing the FDIVS and FDIVD instructions.
354 //
355 char FixAllFDIVSQRT::ID = 0;
356 
357 FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm) :
358                     LEONMachineFunctionPass(tm, ID)
359 {
360 }
361 
362 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction& MF)
363 {
364   Subtarget = &MF.getSubtarget<SparcSubtarget>();
365   const TargetInstrInfo& TII = *Subtarget->getInstrInfo();
366   DebugLoc DL = DebugLoc();
367 
368   //errs() << "FixAllFDIVSQRT on function " << MF.getName() << "\n";
369 
370   bool Modified = false;
371   for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
372     MachineBasicBlock &MBB = *MFI;
373     //MBB.print(errs());
374     for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) {
375       MachineInstr &MI = *MBBI;
376       //MI.print(errs());
377       unsigned Opcode = MI.getOpcode();
378 
379       if (MI.isInlineAsm()) {
380         std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
381         std::string FSQRTDOpCode ("fsqrtd");
382         std::string FDIVDOpCode ("fdivd");
383         std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
384         if (AsmString.find(FSQRTDOpCode) == 0) { // this is an inline fsqrts instruction
385           //errs() << "Detected InlineAsm FSQRTD\n";
386           Opcode = SP::FSQRTD;
387         }
388         else if (AsmString.find(FDIVDOpCode) == 0) { // this is an inline fsqrts instruction
389           //errs() << "Detected InlineAsm FDIVD\n";
390           Opcode = SP::FDIVD;
391         }
392       }
393 
394       // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is switched on
395       // so we don't need to check for them here. They will already have been converted
396       // to FSQRTD or FDIVD earlier in the pipeline.
397       if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
398         //errs() << "Inserting 5 NOPs before FSQRTD,FDIVD.\n";
399         for (int InsertedCount=0; InsertedCount<5; InsertedCount++)
400           BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
401 
402         MachineBasicBlock::iterator NMBBI = std::next(MBBI);
403         //errs() << "Inserting 28 NOPs after FSQRTD,FDIVD.\n";
404         for (int InsertedCount=0; InsertedCount<28; InsertedCount++)
405           BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
406 
407         Modified = true;
408       }
409     }
410   }
411 
412   return Modified;
413 }
414