LeonPasses.cpp revision 321369
1303231Sdim//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
2303231Sdim//
3303231Sdim//                     The LLVM Compiler Infrastructure
4303231Sdim//
5303231Sdim// This file is distributed under the University of Illinois Open Source
6303231Sdim// License. See LICENSE.TXT for details.
7303231Sdim//
8303231Sdim//===----------------------------------------------------------------------===//
9303231Sdim//
10303231Sdim//
11303231Sdim//===----------------------------------------------------------------------===//
12303231Sdim
13303231Sdim#include "LeonPasses.h"
14303231Sdim#include "llvm/CodeGen/ISDOpcodes.h"
15303231Sdim#include "llvm/CodeGen/MachineFunction.h"
16303231Sdim#include "llvm/CodeGen/MachineInstr.h"
17303231Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
18303231Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
19314564Sdim#include "llvm/IR/DiagnosticInfo.h"
20303231Sdim#include "llvm/IR/LLVMContext.h"
21303231Sdim#include "llvm/Support/raw_ostream.h"
22303231Sdimusing namespace llvm;
23303231Sdim
24303231SdimLEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
25303231Sdim    : MachineFunctionPass(ID) {}
26303231Sdim
27303231Sdimint LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
28303231Sdim                                                   int OperandIndex) {
29303231Sdim  if (MI.getNumOperands() > 0) {
30303231Sdim    if (OperandIndex == LAST_OPERAND) {
31303231Sdim      OperandIndex = MI.getNumOperands() - 1;
32303231Sdim    }
33303231Sdim
34303231Sdim    if (MI.getNumOperands() > (unsigned)OperandIndex &&
35303231Sdim        MI.getOperand(OperandIndex).isReg()) {
36303231Sdim      return (int)MI.getOperand(OperandIndex).getReg();
37303231Sdim    }
38303231Sdim  }
39303231Sdim
40303231Sdim  static int NotFoundIndex = -10;
41303231Sdim  // Return a different number each time to avoid any comparisons between the
42303231Sdim  // values returned.
43303231Sdim  NotFoundIndex -= 10;
44303231Sdim  return NotFoundIndex;
45303231Sdim}
46303231Sdim
47303231Sdim// finds a new free FP register
48303231Sdim// checks also the AllocatedRegisters vector
49303231Sdimint LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
50303231Sdim  for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
51303231Sdim    if (!MRI.isPhysRegUsed(RegisterIndex) &&
52314564Sdim        !is_contained(UsedRegisters, RegisterIndex)) {
53303231Sdim      return RegisterIndex;
54303231Sdim    }
55303231Sdim  }
56303231Sdim
57303231Sdim  return -1;
58303231Sdim}
59303231Sdim
60303231Sdim//*****************************************************************************
61303231Sdim//**** InsertNOPLoad pass
62303231Sdim//*****************************************************************************
63303231Sdim// This pass fixes the incorrectly working Load instructions that exists for
64303231Sdim// some earlier versions of the LEON processor line. NOP instructions must
65303231Sdim// be inserted after the load instruction to ensure that the Load instruction
66303231Sdim// behaves as expected for these processors.
67303231Sdim//
68303231Sdim// This pass inserts a NOP after any LD or LDF instruction.
69303231Sdim//
70303231Sdimchar InsertNOPLoad::ID = 0;
71303231Sdim
72321369SdimInsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}
73303231Sdim
74303231Sdimbool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
75303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
76303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
77303231Sdim  DebugLoc DL = DebugLoc();
78303231Sdim
79303231Sdim  bool Modified = false;
80303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
81303231Sdim    MachineBasicBlock &MBB = *MFI;
82303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
83303231Sdim      MachineInstr &MI = *MBBI;
84303231Sdim      unsigned Opcode = MI.getOpcode();
85303231Sdim      if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
86303231Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
87303231Sdim        BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
88303231Sdim        Modified = true;
89303231Sdim      }
90303231Sdim    }
91303231Sdim  }
92303231Sdim
93303231Sdim  return Modified;
94303231Sdim}
95303231Sdim
96303231Sdim//*****************************************************************************
97303231Sdim//**** FixFSMULD pass
98303231Sdim//*****************************************************************************
99303231Sdim// This pass fixes the incorrectly working FSMULD instruction that exists for
100303231Sdim// some earlier versions of the LEON processor line.
101303231Sdim//
102303231Sdim// The pass should convert the FSMULD operands to double precision in scratch
103303231Sdim// registers, then calculate the result with the FMULD instruction. Therefore,
104303231Sdim// the pass should replace operations of the form:
105303231Sdim// fsmuld %f20,%f21,%f8
106303231Sdim// with the sequence:
107303231Sdim// fstod %f20,%f0
108303231Sdim// fstod %f21,%f2
109303231Sdim// fmuld %f0,%f2,%f8
110303231Sdim//
111303231Sdimchar FixFSMULD::ID = 0;
112303231Sdim
113321369SdimFixFSMULD::FixFSMULD() : LEONMachineFunctionPass(ID) {}
114303231Sdim
115303231Sdimbool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
116303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
117303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
118303231Sdim  DebugLoc DL = DebugLoc();
119303231Sdim
120303231Sdim  bool Modified = false;
121303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
122303231Sdim    MachineBasicBlock &MBB = *MFI;
123303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
124303231Sdim
125303231Sdim      MachineInstr &MI = *MBBI;
126303231Sdim      unsigned Opcode = MI.getOpcode();
127303231Sdim
128303231Sdim      const int UNASSIGNED_INDEX = -1;
129303231Sdim      int Reg1Index = UNASSIGNED_INDEX;
130303231Sdim      int Reg2Index = UNASSIGNED_INDEX;
131303231Sdim      int Reg3Index = UNASSIGNED_INDEX;
132303231Sdim
133303231Sdim      if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) {
134303231Sdim        // take the registers from fsmuld %f20,%f21,%f8
135303231Sdim        Reg1Index = MI.getOperand(0).getReg();
136303231Sdim        Reg2Index = MI.getOperand(1).getReg();
137303231Sdim        Reg3Index = MI.getOperand(2).getReg();
138303231Sdim      }
139303231Sdim
140303231Sdim      if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
141303231Sdim          Reg3Index != UNASSIGNED_INDEX) {
142303231Sdim        clearUsedRegisterList();
143303231Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
144303231Sdim        // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
145303231Sdim        markRegisterUsed(Reg3Index);
146303231Sdim        const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
147303231Sdim        markRegisterUsed(ScratchReg1Index);
148303231Sdim        const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
149303231Sdim        markRegisterUsed(ScratchReg2Index);
150303231Sdim
151303231Sdim        if (ScratchReg1Index == UNASSIGNED_INDEX ||
152303231Sdim            ScratchReg2Index == UNASSIGNED_INDEX) {
153303231Sdim          errs() << "Cannot allocate free scratch registers for the FixFSMULD "
154303231Sdim                    "pass."
155303231Sdim                 << "\n";
156303231Sdim        } else {
157303231Sdim          // create fstod %f20,%f0
158303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
159303231Sdim              .addReg(ScratchReg1Index)
160303231Sdim              .addReg(Reg1Index);
161303231Sdim
162303231Sdim          // create fstod %f21,%f2
163303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
164303231Sdim              .addReg(ScratchReg2Index)
165303231Sdim              .addReg(Reg2Index);
166303231Sdim
167303231Sdim          // create fmuld %f0,%f2,%f8
168303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
169303231Sdim              .addReg(Reg3Index)
170303231Sdim              .addReg(ScratchReg1Index)
171303231Sdim              .addReg(ScratchReg2Index);
172303231Sdim
173303231Sdim          MI.eraseFromParent();
174303231Sdim          MBBI = NMBBI;
175303231Sdim
176303231Sdim          Modified = true;
177303231Sdim        }
178303231Sdim      }
179303231Sdim    }
180303231Sdim  }
181303231Sdim
182303231Sdim  return Modified;
183303231Sdim}
184303231Sdim
185303231Sdim//*****************************************************************************
186303231Sdim//**** ReplaceFMULS pass
187303231Sdim//*****************************************************************************
188303231Sdim// This pass fixes the incorrectly working FMULS instruction that exists for
189303231Sdim// some earlier versions of the LEON processor line.
190303231Sdim//
191303231Sdim// This pass converts the FMULS operands to double precision in scratch
192303231Sdim// registers, then calculates the result with the FMULD instruction.
193303231Sdim// The pass should replace operations of the form:
194303231Sdim// fmuls %f20,%f21,%f8
195303231Sdim// with the sequence:
196303231Sdim// fstod %f20,%f0
197303231Sdim// fstod %f21,%f2
198303231Sdim// fmuld %f0,%f2,%f8
199303231Sdim//
200303231Sdimchar ReplaceFMULS::ID = 0;
201303231Sdim
202321369SdimReplaceFMULS::ReplaceFMULS() : LEONMachineFunctionPass(ID) {}
203303231Sdim
204303231Sdimbool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
205303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
206303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
207303231Sdim  DebugLoc DL = DebugLoc();
208303231Sdim
209303231Sdim  bool Modified = false;
210303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
211303231Sdim    MachineBasicBlock &MBB = *MFI;
212303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
213303231Sdim      MachineInstr &MI = *MBBI;
214303231Sdim      unsigned Opcode = MI.getOpcode();
215303231Sdim
216303231Sdim      const int UNASSIGNED_INDEX = -1;
217303231Sdim      int Reg1Index = UNASSIGNED_INDEX;
218303231Sdim      int Reg2Index = UNASSIGNED_INDEX;
219303231Sdim      int Reg3Index = UNASSIGNED_INDEX;
220303231Sdim
221303231Sdim      if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
222303231Sdim        // take the registers from fmuls %f20,%f21,%f8
223303231Sdim        Reg1Index = MI.getOperand(0).getReg();
224303231Sdim        Reg2Index = MI.getOperand(1).getReg();
225303231Sdim        Reg3Index = MI.getOperand(2).getReg();
226303231Sdim      }
227303231Sdim
228303231Sdim      if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
229303231Sdim          Reg3Index != UNASSIGNED_INDEX) {
230303231Sdim        clearUsedRegisterList();
231303231Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
232303231Sdim        // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
233303231Sdim        markRegisterUsed(Reg3Index);
234303231Sdim        const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
235303231Sdim        markRegisterUsed(ScratchReg1Index);
236303231Sdim        const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
237303231Sdim        markRegisterUsed(ScratchReg2Index);
238303231Sdim
239303231Sdim        if (ScratchReg1Index == UNASSIGNED_INDEX ||
240303231Sdim            ScratchReg2Index == UNASSIGNED_INDEX) {
241303231Sdim          errs() << "Cannot allocate free scratch registers for the "
242303231Sdim                    "ReplaceFMULS pass."
243303231Sdim                 << "\n";
244303231Sdim        } else {
245303231Sdim          // create fstod %f20,%f0
246303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
247303231Sdim              .addReg(ScratchReg1Index)
248303231Sdim              .addReg(Reg1Index);
249303231Sdim
250303231Sdim          // create fstod %f21,%f2
251303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
252303231Sdim              .addReg(ScratchReg2Index)
253303231Sdim              .addReg(Reg2Index);
254303231Sdim
255303231Sdim          // create fmuld %f0,%f2,%f8
256303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
257303231Sdim              .addReg(Reg3Index)
258303231Sdim              .addReg(ScratchReg1Index)
259303231Sdim              .addReg(ScratchReg2Index);
260303231Sdim
261303231Sdim          MI.eraseFromParent();
262303231Sdim          MBBI = NMBBI;
263303231Sdim
264303231Sdim          Modified = true;
265303231Sdim        }
266303231Sdim      }
267303231Sdim    }
268303231Sdim  }
269303231Sdim
270303231Sdim  return Modified;
271303231Sdim}
272303231Sdim
273303231Sdim
274303231Sdim//*****************************************************************************
275314564Sdim//**** DetectRoundChange pass
276303231Sdim//*****************************************************************************
277314564Sdim// To prevent any explicit change of the default rounding mode, this pass
278314564Sdim// detects any call of the fesetround function.
279314564Sdim// A warning is generated to ensure the user knows this has happened.
280303231Sdim//
281314564Sdim// Detects an erratum in UT699 LEON 3 processor
282303231Sdim
283314564Sdimchar DetectRoundChange::ID = 0;
284303231Sdim
285321369SdimDetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}
286303231Sdim
287314564Sdimbool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
288303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
289303231Sdim
290303231Sdim  bool Modified = false;
291303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
292303231Sdim    MachineBasicBlock &MBB = *MFI;
293303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
294303231Sdim      MachineInstr &MI = *MBBI;
295303231Sdim      unsigned Opcode = MI.getOpcode();
296303231Sdim      if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
297303231Sdim        MachineOperand &MO = MI.getOperand(0);
298303231Sdim
299303231Sdim        if (MO.isGlobal()) {
300303231Sdim          StringRef FuncName = MO.getGlobal()->getName();
301303231Sdim          if (FuncName.compare_lower("fesetround") == 0) {
302314564Sdim            errs() << "Error: You are using the detectroundchange "
303314564Sdim                      "option to detect rounding changes that will "
304314564Sdim                      "cause LEON errata. The only way to fix this "
305314564Sdim                      "is to remove the call to fesetround from "
306314564Sdim                      "the source code.\n";
307303231Sdim          }
308303231Sdim        }
309303231Sdim      }
310303231Sdim    }
311303231Sdim  }
312303231Sdim
313303231Sdim  return Modified;
314303231Sdim}
315314564Sdim
316303231Sdim//*****************************************************************************
317314564Sdim//**** FixAllFDIVSQRT pass
318303231Sdim//*****************************************************************************
319314564Sdim// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
320314564Sdim// exist for some earlier versions of the LEON processor line. Five NOP
321314564Sdim// instructions need to be inserted after these instructions to ensure the
322314564Sdim// correct result is placed in the destination registers before they are used.
323303231Sdim//
324314564Sdim// This pass implements two fixes:
325314564Sdim//  1) fixing the FSQRTS and FSQRTD instructions.
326314564Sdim//  2) fixing the FDIVS and FDIVD instructions.
327314564Sdim//
328314564Sdim// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
329314564Sdim// the pipeline when this option is enabled, so this pass needs only to deal
330314564Sdim// with the changes that still need implementing for the "double" versions
331314564Sdim// of these instructions.
332314564Sdim//
333314564Sdimchar FixAllFDIVSQRT::ID = 0;
334303231Sdim
335321369SdimFixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}
336303231Sdim
337314564Sdimbool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
338303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
339303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
340303231Sdim  DebugLoc DL = DebugLoc();
341303231Sdim
342303231Sdim  bool Modified = false;
343303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
344303231Sdim    MachineBasicBlock &MBB = *MFI;
345303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
346303231Sdim      MachineInstr &MI = *MBBI;
347303231Sdim      unsigned Opcode = MI.getOpcode();
348303231Sdim
349314564Sdim      // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
350314564Sdim      // switched on so we don't need to check for them here. They will
351314564Sdim      // already have been converted to FSQRTD or FDIVD earlier in the
352314564Sdim      // pipeline.
353314564Sdim      if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
354314564Sdim        for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
355303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
356303231Sdim
357314564Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
358314564Sdim        for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
359314564Sdim          BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
360303231Sdim
361314564Sdim        Modified = true;
362303231Sdim      }
363303231Sdim    }
364303231Sdim  }
365303231Sdim
366303231Sdim  return Modified;
367303231Sdim}
368