1303231Sdim//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
2303231Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim//
9303231Sdim//
10303231Sdim//===----------------------------------------------------------------------===//
11303231Sdim
12303231Sdim#include "LeonPasses.h"
13303231Sdim#include "llvm/CodeGen/ISDOpcodes.h"
14303231Sdim#include "llvm/CodeGen/MachineFunction.h"
15303231Sdim#include "llvm/CodeGen/MachineInstr.h"
16303231Sdim#include "llvm/CodeGen/MachineInstrBuilder.h"
17303231Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
18314564Sdim#include "llvm/IR/DiagnosticInfo.h"
19303231Sdim#include "llvm/IR/LLVMContext.h"
20303231Sdim#include "llvm/Support/raw_ostream.h"
21303231Sdimusing namespace llvm;
22303231Sdim
23303231SdimLEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
24303231Sdim    : MachineFunctionPass(ID) {}
25303231Sdim
26303231Sdim//*****************************************************************************
27303231Sdim//**** InsertNOPLoad pass
28303231Sdim//*****************************************************************************
29303231Sdim// This pass fixes the incorrectly working Load instructions that exists for
30303231Sdim// some earlier versions of the LEON processor line. NOP instructions must
31303231Sdim// be inserted after the load instruction to ensure that the Load instruction
32303231Sdim// behaves as expected for these processors.
33303231Sdim//
34303231Sdim// This pass inserts a NOP after any LD or LDF instruction.
35303231Sdim//
36303231Sdimchar InsertNOPLoad::ID = 0;
37303231Sdim
38321369SdimInsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}
39303231Sdim
40303231Sdimbool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
41303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
42303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
43303231Sdim  DebugLoc DL = DebugLoc();
44303231Sdim
45303231Sdim  bool Modified = false;
46303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
47303231Sdim    MachineBasicBlock &MBB = *MFI;
48303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
49303231Sdim      MachineInstr &MI = *MBBI;
50303231Sdim      unsigned Opcode = MI.getOpcode();
51303231Sdim      if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
52303231Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
53303231Sdim        BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
54303231Sdim        Modified = true;
55303231Sdim      }
56303231Sdim    }
57303231Sdim  }
58303231Sdim
59303231Sdim  return Modified;
60303231Sdim}
61303231Sdim
62303231Sdim
63303231Sdim
64303231Sdim//*****************************************************************************
65314564Sdim//**** DetectRoundChange pass
66303231Sdim//*****************************************************************************
67314564Sdim// To prevent any explicit change of the default rounding mode, this pass
68314564Sdim// detects any call of the fesetround function.
69314564Sdim// A warning is generated to ensure the user knows this has happened.
70303231Sdim//
71314564Sdim// Detects an erratum in UT699 LEON 3 processor
72303231Sdim
73314564Sdimchar DetectRoundChange::ID = 0;
74303231Sdim
75321369SdimDetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}
76303231Sdim
77314564Sdimbool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) {
78303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
79303231Sdim
80303231Sdim  bool Modified = false;
81303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
82303231Sdim    MachineBasicBlock &MBB = *MFI;
83303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
84303231Sdim      MachineInstr &MI = *MBBI;
85303231Sdim      unsigned Opcode = MI.getOpcode();
86303231Sdim      if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
87303231Sdim        MachineOperand &MO = MI.getOperand(0);
88303231Sdim
89303231Sdim        if (MO.isGlobal()) {
90303231Sdim          StringRef FuncName = MO.getGlobal()->getName();
91303231Sdim          if (FuncName.compare_lower("fesetround") == 0) {
92314564Sdim            errs() << "Error: You are using the detectroundchange "
93314564Sdim                      "option to detect rounding changes that will "
94314564Sdim                      "cause LEON errata. The only way to fix this "
95314564Sdim                      "is to remove the call to fesetround from "
96314564Sdim                      "the source code.\n";
97303231Sdim          }
98303231Sdim        }
99303231Sdim      }
100303231Sdim    }
101303231Sdim  }
102303231Sdim
103303231Sdim  return Modified;
104303231Sdim}
105314564Sdim
106303231Sdim//*****************************************************************************
107314564Sdim//**** FixAllFDIVSQRT pass
108303231Sdim//*****************************************************************************
109314564Sdim// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
110314564Sdim// exist for some earlier versions of the LEON processor line. Five NOP
111314564Sdim// instructions need to be inserted after these instructions to ensure the
112314564Sdim// correct result is placed in the destination registers before they are used.
113303231Sdim//
114314564Sdim// This pass implements two fixes:
115314564Sdim//  1) fixing the FSQRTS and FSQRTD instructions.
116314564Sdim//  2) fixing the FDIVS and FDIVD instructions.
117314564Sdim//
118314564Sdim// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
119314564Sdim// the pipeline when this option is enabled, so this pass needs only to deal
120314564Sdim// with the changes that still need implementing for the "double" versions
121314564Sdim// of these instructions.
122314564Sdim//
123314564Sdimchar FixAllFDIVSQRT::ID = 0;
124303231Sdim
125321369SdimFixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}
126303231Sdim
127314564Sdimbool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
128303231Sdim  Subtarget = &MF.getSubtarget<SparcSubtarget>();
129303231Sdim  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
130303231Sdim  DebugLoc DL = DebugLoc();
131303231Sdim
132303231Sdim  bool Modified = false;
133303231Sdim  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
134303231Sdim    MachineBasicBlock &MBB = *MFI;
135303231Sdim    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
136303231Sdim      MachineInstr &MI = *MBBI;
137303231Sdim      unsigned Opcode = MI.getOpcode();
138303231Sdim
139314564Sdim      // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
140314564Sdim      // switched on so we don't need to check for them here. They will
141314564Sdim      // already have been converted to FSQRTD or FDIVD earlier in the
142314564Sdim      // pipeline.
143314564Sdim      if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
144314564Sdim        for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
145303231Sdim          BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
146303231Sdim
147314564Sdim        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
148314564Sdim        for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
149314564Sdim          BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
150303231Sdim
151314564Sdim        Modified = true;
152303231Sdim      }
153303231Sdim    }
154303231Sdim  }
155303231Sdim
156303231Sdim  return Modified;
157303231Sdim}
158