//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#include "LeonPasses.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char &ID)
    : MachineFunctionPass(ID) {}

LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
    : MachineFunctionPass(ID) {}

int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
                                                   int OperandIndex) {
  if (MI.getNumOperands() > 0) {
    if (OperandIndex == LAST_OPERAND) {
      OperandIndex = MI.getNumOperands() - 1;
    }

    if (MI.getNumOperands() > (unsigned)OperandIndex &&
        MI.getOperand(OperandIndex).isReg()) {
      return (int)MI.getOperand(OperandIndex).getReg();
    }
  }

  static int NotFoundIndex = -10;
  // Return a different number each time to avoid any comparisons between the
  // values returned.
  NotFoundIndex -= 10;
  return NotFoundIndex;
}

// finds a new free FP register
// checks also the AllocatedRegisters vector
int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
  for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
    if (!MRI.isPhysRegUsed(RegisterIndex) &&
        !is_contained(UsedRegisters, RegisterIndex)) {
      return RegisterIndex;
    }
  }

  return -1;
}

//*****************************************************************************
//**** InsertNOPLoad pass
//*****************************************************************************
// This pass fixes the incorrectly working Load instructions that exists for
// some earlier versions of the LEON processor line. NOP instructions must
// be inserted after the load instruction to ensure that the Load instruction
// behaves as expected for these processors.
//
// This pass inserts a NOP after any LD or LDF instruction.
//
char InsertNOPLoad::ID = 0;

InsertNOPLoad::InsertNOPLoad(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();
      if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
        BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
        Modified = true;
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** FixFSMULD pass
//*****************************************************************************
// This pass fixes the incorrectly working FSMULD instruction that exists for
// some earlier versions of the LEON processor line.
//
// The pass should convert the FSMULD operands to double precision in scratch
// registers, then calculate the result with the FMULD instruction. Therefore,
// the pass should replace operations of the form:
// fsmuld %f20,%f21,%f8
// with the sequence:
// fstod %f20,%f0
// fstod %f21,%f2
// fmuld %f0,%f2,%f8
//
char FixFSMULD::ID = 0;

FixFSMULD::FixFSMULD(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}

bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {

      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();

      const int UNASSIGNED_INDEX = -1;
      int Reg1Index = UNASSIGNED_INDEX;
      int Reg2Index = UNASSIGNED_INDEX;
      int Reg3Index = UNASSIGNED_INDEX;

      if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) {
        // take the registers from fsmuld %f20,%f21,%f8
        Reg1Index = MI.getOperand(0).getReg();
        Reg2Index = MI.getOperand(1).getReg();
        Reg3Index = MI.getOperand(2).getReg();
      }

      if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
          Reg3Index != UNASSIGNED_INDEX) {
        clearUsedRegisterList();
        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
        // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
        markRegisterUsed(Reg3Index);
        const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
        markRegisterUsed(ScratchReg1Index);
        const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
        markRegisterUsed(ScratchReg2Index);

        if (ScratchReg1Index == UNASSIGNED_INDEX ||
            ScratchReg2Index == UNASSIGNED_INDEX) {
          errs() << "Cannot allocate free scratch registers for the FixFSMULD "
                    "pass."
                 << "\n";
        } else {
          // create fstod %f20,%f0
          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
              .addReg(ScratchReg1Index)
              .addReg(Reg1Index);

          // create fstod %f21,%f2
          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
              .addReg(ScratchReg2Index)
              .addReg(Reg2Index);

          // create fmuld %f0,%f2,%f8
          BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
              .addReg(Reg3Index)
              .addReg(ScratchReg1Index)
              .addReg(ScratchReg2Index);

          MI.eraseFromParent();
          MBBI = NMBBI;

          Modified = true;
        }
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** ReplaceFMULS pass
//*****************************************************************************
// This pass fixes the incorrectly working FMULS instruction that exists for
// some earlier versions of the LEON processor line.
//
// This pass converts the FMULS operands to double precision in scratch
// registers, then calculates the result with the FMULD instruction.
// The pass should replace operations of the form:
// fmuls %f20,%f21,%f8
// with the sequence:
// fstod %f20,%f0
// fstod %f21,%f2
// fmuld %f0,%f2,%f8
//
char ReplaceFMULS::ID = 0;

ReplaceFMULS::ReplaceFMULS(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();

      const int UNASSIGNED_INDEX = -1;
      int Reg1Index = UNASSIGNED_INDEX;
      int Reg2Index = UNASSIGNED_INDEX;
      int Reg3Index = UNASSIGNED_INDEX;

      if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
        // take the registers from fmuls %f20,%f21,%f8
        Reg1Index = MI.getOperand(0).getReg();
        Reg2Index = MI.getOperand(1).getReg();
        Reg3Index = MI.getOperand(2).getReg();
      }

      if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
          Reg3Index != UNASSIGNED_INDEX) {
        clearUsedRegisterList();
        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
        // Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
        markRegisterUsed(Reg3Index);
        const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
        markRegisterUsed(ScratchReg1Index);
        const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
        markRegisterUsed(ScratchReg2Index);

        if (ScratchReg1Index == UNASSIGNED_INDEX ||
            ScratchReg2Index == UNASSIGNED_INDEX) {
          errs() << "Cannot allocate free scratch registers for the "
                    "ReplaceFMULS pass."
                 << "\n";
        } else {
          // create fstod %f20,%f0
          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
              .addReg(ScratchReg1Index)
              .addReg(Reg1Index);

          // create fstod %f21,%f2
          BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
              .addReg(ScratchReg2Index)
              .addReg(Reg2Index);

          // create fmuld %f0,%f2,%f8
          BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
              .addReg(Reg3Index)
              .addReg(ScratchReg1Index)
              .addReg(ScratchReg2Index);

          MI.eraseFromParent();
          MBBI = NMBBI;

          Modified = true;
        }
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** FixAllFDIVSQRT pass
//*****************************************************************************
// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
// exist for some earlier versions of the LEON processor line. Five NOP
// instructions need to be inserted after these instructions to ensure the
// correct result is placed in the destination registers before they are used.
//
// This pass implements two fixes:
//  1) fixing the FSQRTS and FSQRTD instructions.
//  2) fixing the FDIVS and FDIVD instructions.
//
// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
// the pipeline when this option is enabled, so this pass needs only to deal
// with the changes that still need implementing for the "double" versions
// of these instructions.
//
char FixAllFDIVSQRT::ID = 0;

FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();

      // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
      // switched on so we don't need to check for them here. They will
      // already have been converted to FSQRTD or FDIVD earlier in the
      // pipeline.
      if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
        // Insert 5 NOPs before FSQRTD,FDIVD.
        for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
          BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));

        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
        // ... and inserting 28 NOPs after FSQRTD,FDIVD.
        for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
          BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));

        Modified = true;
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** ReplaceSDIV pass
//*****************************************************************************
// This pass fixes the incorrectly working SDIV instruction that
// exist for some earlier versions of the LEON processor line. The instruction
// is replaced with an SDIVcc instruction instead, which is working.
//
char ReplaceSDIV::ID = 0;

ReplaceSDIV::ReplaceSDIV() : LEONMachineFunctionPass(ID) {}

ReplaceSDIV::ReplaceSDIV(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}

bool ReplaceSDIV::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();
      if (Opcode == SP::SDIVrr) {
        MI.setDesc(TII.get(SP::SDIVCCrr));
        Modified = true;
      } else if (Opcode == SP::SDIVri) {
        MI.setDesc(TII.get(SP::SDIVCCri));
        Modified = true;
      }
    }
  }

  return Modified;
}

static RegisterPass<ReplaceSDIV> X("replace-sdiv", "Replase SDIV Pass", false,
                                   false);

//*****************************************************************************
//**** FixCALL pass
//*****************************************************************************
// This pass restricts the size of the immediate operand of the CALL
// instruction, which can cause problems on some earlier versions of the LEON
// processor, which can interpret some of the call address bits incorrectly.
//
char FixCALL::ID = 0;

FixCALL::FixCALL(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}

bool FixCALL::runOnMachineFunction(MachineFunction &MF) {
  bool Modified = false;

  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;

      unsigned Opcode = MI.getOpcode();
      if (Opcode == SP::CALL || Opcode == SP::CALLrr) {
        unsigned NumOperands = MI.getNumOperands();
        for (unsigned OperandIndex = 0; OperandIndex < NumOperands;
             OperandIndex++) {
          MachineOperand &MO = MI.getOperand(OperandIndex);
          if (MO.isImm()) {
            int64_t Value = MO.getImm();
            MO.setImm(Value & 0x000fffffL);
            Modified = true;
            break;
          }
        }
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** IgnoreZeroFlag pass
//*****************************************************************************
// This erratum fix fixes the overflow behavior of SDIVCC and UDIVCC
// instructions that exists on some earlier LEON processors. Where these
// instructions are detected, they are replaced by a sequence that will
// explicitly write the overflow bit flag if this is required.
//
char IgnoreZeroFlag::ID = 0;

IgnoreZeroFlag::IgnoreZeroFlag(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool IgnoreZeroFlag::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();
      if (Opcode == SP::SDIVCCrr || Opcode == SP::SDIVCCri ||
          Opcode == SP::UDIVCCrr || Opcode == SP::UDIVCCri) {

        // split the current machine basic block - just after the sdivcc/udivcc
        // instruction
        // create a label that help us skip the zero flag update (of PSR -
        // Processor Status Register)
        // if conditions are not met
        const BasicBlock *LLVM_BB = MBB.getBasicBlock();
        MachineFunction::iterator It =
            std::next(MachineFunction::iterator(MBB));

        MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
        MF.insert(It, dneBB);

        // Transfer the remainder of MBB and its successor edges to dneBB.
        dneBB->splice(dneBB->begin(), &MBB,
                      std::next(MachineBasicBlock::iterator(MI)), MBB.end());
        dneBB->transferSuccessorsAndUpdatePHIs(&MBB);

        MBB.addSuccessor(dneBB);

        MachineBasicBlock::iterator NextMBBI = std::next(MBBI);

        // bvc - branch if overflow flag not set
        BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
            .addMBB(dneBB)
            .addImm(SPCC::ICC_VS);

        // bnz - branch if not zero
        BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
            .addMBB(dneBB)
            .addImm(SPCC::ICC_NE);

        // use the WRPSR (Write Processor State Register) instruction to set the
        // zeo flag to 1
        // create wr %g0, 1, %psr
        BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri))
            .addReg(SP::G0)
            .addImm(1);

        BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP));

        Modified = true;
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** InsertNOPDoublePrecision pass
//*****************************************************************************
// This erratum fix for some earlier LEON processors fixes a problem where a
// double precision load will not yield the correct result if used in FMUL,
// FDIV, FADD, FSUB or FSQRT instructions later. If this sequence is detected,
// inserting a NOP between the two instructions will fix the erratum.
// 1.scans the code after register allocation;
// 2.checks for the problem conditions as described in the AT697E erratum
// “Odd-Numbered FPU Register Dependency not Properly Checked in some
// Double-Precision FPU Operations”;
// 3.inserts NOPs if the problem exists.
//
char InsertNOPDoublePrecision::ID = 0;

InsertNOPDoublePrecision::InsertNOPDoublePrecision(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool InsertNOPDoublePrecision::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();
      if (Opcode == SP::LDDFri || Opcode == SP::LDDFrr) {
        MachineBasicBlock::iterator NMBBI = std::next(MBBI);
        MachineInstr &NMI = *NMBBI;

        unsigned NextOpcode = NMI.getOpcode();
        if (NextOpcode == SP::FADDD || NextOpcode == SP::FSUBD ||
            NextOpcode == SP::FMULD || NextOpcode == SP::FDIVD) {
          int RegAIndex = GetRegIndexForOperand(MI, 0);
          int RegBIndex = GetRegIndexForOperand(NMI, 0);
          int RegCIndex =
              GetRegIndexForOperand(NMI, 2); // Second source operand is index 2
          int RegDIndex =
              GetRegIndexForOperand(NMI, 1); // Destination operand is index 1

          if ((RegAIndex == RegBIndex + 1 && RegBIndex == RegDIndex) ||
              (RegAIndex == RegCIndex + 1 && RegCIndex == RegDIndex) ||
              (RegAIndex == RegBIndex + 1 && RegCIndex == RegDIndex) ||
              (RegAIndex == RegCIndex + 1 && RegBIndex == RegDIndex)) {
            // Insert NOP between the two instructions.
            BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
            Modified = true;
          }

          // Check the errata patterns that only happen for FADDD and FMULD
          if (Modified == false &&
              (NextOpcode == SP::FADDD || NextOpcode == SP::FMULD)) {
            RegAIndex = GetRegIndexForOperand(MI, 1);
            if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex &&
                RegBIndex == RegDIndex) {
              // Insert NOP between the two instructions.
              BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
              Modified = true;
            }
          }
        } else if (NextOpcode == SP::FSQRTD) {
          int RegAIndex = GetRegIndexForOperand(MI, 1);
          int RegBIndex = GetRegIndexForOperand(NMI, 0);
          int RegCIndex = GetRegIndexForOperand(NMI, 1);

          if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex) {
            // Insert NOP between the two instructions.
            BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
            Modified = true;
          }
        }
      }
    }
  }

  return Modified;
}

//*****************************************************************************
//**** PreventRoundChange pass
//*****************************************************************************
// To prevent any explicit change of the default rounding mode, this pass
// detects any call of the fesetround function and removes this call from the
// list of generated operations.
//
char PreventRoundChange::ID = 0;

PreventRoundChange::PreventRoundChange(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;
      unsigned Opcode = MI.getOpcode();
      if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
        MachineOperand &MO = MI.getOperand(0);

        if (MO.isGlobal()) {
          StringRef FuncName = MO.getGlobal()->getName();
          if (FuncName.compare_lower("fesetround") == 0) {
            MachineBasicBlock::iterator NMBBI = std::next(MBBI);
            emitOptimizationRemark(
                MF.getFunction()->getContext(), getPassName(), *MF.getFunction(),
                MI.getDebugLoc(), "Warning: You are using the prvntroundchange "
                                  "option to prevent rounding changes caused "
                                  "by LEON errata. A call to fesetround to be "
                                  "removed from the output.");
            MI.eraseFromParent();
            MBBI = NMBBI;
            Modified = true;
          }
        }
      }
    }
  }

  return Modified;
}
//*****************************************************************************
//**** InsertNOPsLoadStore pass
//*****************************************************************************
// This pass shall insert NOPs between floating point loads and stores when the
// following circumstances are present [5]:
// Pattern 1:
// 1. single-precision load or single-precision FPOP to register %fX, where X is
// the same register as the store being checked;
// 2. single-precision load or single-precision FPOP to register %fY , where Y
// is the opposite register in the same double-precision pair;
// 3. 0-3 instructions of any kind, except stores from %fX or %fY or operations
// with %fX as destination;
// 4. the store (from register %fX) being considered.
// Pattern 2:
// 1. double-precision FPOP;
// 2. any number of operations on any kind, except no double-precision FPOP and
// at most one (less than two) single-precision or single-to-double FPOPs;
// 3. the store (from register %fX) being considered.
//
char InsertNOPsLoadStore::ID = 0;

InsertNOPsLoadStore::InsertNOPsLoadStore(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool InsertNOPsLoadStore::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  MachineInstr *Pattern1FirstInstruction = NULL;
  MachineInstr *Pattern2FirstInstruction = NULL;
  unsigned int StoreInstructionsToCheck = 0;
  int FxRegIndex, FyRegIndex;

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
      MachineInstr &MI = *MBBI;

      if (StoreInstructionsToCheck > 0) {
        if (((MI.getOpcode() == SP::STFrr || MI.getOpcode() == SP::STFri) &&
             (GetRegIndexForOperand(MI, LAST_OPERAND) == FxRegIndex ||
              GetRegIndexForOperand(MI, LAST_OPERAND) == FyRegIndex)) ||
            GetRegIndexForOperand(MI, 0) == FxRegIndex) {
          // Insert four NOPs
          for (unsigned InsertedCount = 0; InsertedCount < 4; InsertedCount++) {
            BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
          }
          Modified = true;
        }
        StoreInstructionsToCheck--;
      }

      switch (MI.getOpcode()) {
      // Watch for Pattern 1 FPop instructions
      case SP::LDrr:
      case SP::LDri:
      case SP::LDFrr:
      case SP::LDFri:
      case SP::FADDS:
      case SP::FSUBS:
      case SP::FMULS:
      case SP::FDIVS:
      case SP::FSQRTS:
      case SP::FCMPS:
      case SP::FMOVS:
      case SP::FNEGS:
      case SP::FABSS:
      case SP::FITOS:
      case SP::FSTOI:
      case SP::FITOD:
      case SP::FDTOI:
      case SP::FDTOS:
        if (Pattern1FirstInstruction != NULL) {
          FxRegIndex = GetRegIndexForOperand(*Pattern1FirstInstruction, 0);
          FyRegIndex = GetRegIndexForOperand(MI, 0);

          // Check to see if these registers are part of the same double
          // precision
          // register pair.
          int DoublePrecRegIndexForX = (FxRegIndex - SP::F0) / 2;
          int DoublePrecRegIndexForY = (FyRegIndex - SP::F0) / 2;

          if (DoublePrecRegIndexForX == DoublePrecRegIndexForY)
            StoreInstructionsToCheck = 4;
        }

        Pattern1FirstInstruction = &MI;
        break;
      // End of Pattern 1

      // Search for Pattern 2
      case SP::FADDD:
      case SP::FSUBD:
      case SP::FMULD:
      case SP::FDIVD:
      case SP::FSQRTD:
      case SP::FCMPD:
        Pattern2FirstInstruction = &MI;
        Pattern1FirstInstruction = NULL;
        break;

      case SP::STFrr:
      case SP::STFri:
      case SP::STDFrr:
      case SP::STDFri:
        if (Pattern2FirstInstruction != NULL) {
          if (GetRegIndexForOperand(MI, LAST_OPERAND) ==
              GetRegIndexForOperand(*Pattern2FirstInstruction, 0)) {
            // Insert four NOPs
            for (unsigned InsertedCount = 0; InsertedCount < 4;
                 InsertedCount++) {
              BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
            }

            Pattern2FirstInstruction = NULL;
          }
        }
        Pattern1FirstInstruction = NULL;
        break;
      // End of Pattern 2

      default:
        // Ensure we don't count debug-only values while we're testing for the
        // patterns.
        if (!MI.isDebugValue())
          Pattern1FirstInstruction = NULL;
        break;
      }
    }
  }

  return Modified;
}


//****************************************************************************************************************
//**** FillDataCache pass
//****************************************************************************************************************
// This erratum fix inserts after the first operand a loop performing 4096 NOP
// instructions.
//
// mov 0, %l0
// mov 4096, %l1
// loop1:
// inc %l0
// cmp %l0, %l1
// ble loop1

char FillDataCache::ID = 0;
bool FillDataCache::CacheFilled = false;

FillDataCache::FillDataCache(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool FillDataCache::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  unsigned int CountInstr = 0;

  bool Modified = false;
  if (!CacheFilled) {
    for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {

      if (CacheFilled)
        break;

      MachineBasicBlock &MBB = *MFI;

      for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
        MachineInstr &MI = *MBBI;

        CountInstr++;
        MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
        MBBI = NextMBBI;

        // insert the following sequence right after the first instruction
        // initializing the stack pointer (sp register)
        // or %g0, 1, %g1
        // loop1:
        // nop
        // add %g1, 1, %g1
        // cmp %g1, 4096
        // ble  .LBB0_1
        if (CountInstr == 1) {
          BuildMI(MBB, NextMBBI, DL, TII.get(SP::ORrr))
              .addReg(SP::G1)
              .addReg(SP::G0)
              .addImm(1);
        } else {
          const BasicBlock *LLVM_BB = MBB.getBasicBlock();
          MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);

          MachineFunction::iterator It =
              std::next(MachineFunction::iterator(MBB));

          MF.insert(It, dneBB);

          BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));

          BuildMI(MBB, MBBI, DL, TII.get(SP::ADDri))
              .addReg(SP::G1)
              .addReg(SP::G1)
              .addImm(1);

          BuildMI(MBB, MBBI, DL, TII.get(SP::CMPri))
              .addReg(SP::G1)
              .addImm(4096);

          BuildMI(MBB, MBBI, DL, TII.get(SP::BCOND))
              .addMBB(dneBB)
              .addImm(SPCC::ICC_LE);

          dneBB->splice(dneBB->begin(), &MBB,
                        std::next(MachineBasicBlock::iterator(MI)), MBB.end());
          dneBB->transferSuccessorsAndUpdatePHIs(&MBB);

          MBB.addSuccessor(dneBB);

          CacheFilled = true;
          Modified = true;
          break;
        }
      }
    }
  }

  return Modified;
}


//****************************************************************************************************************
//**** RestoreExecAddress pass
//****************************************************************************************************************
// This erratum fix should handle user traps of FPU exceptions and restore the
// execution address by skipping the trapped FPU instruction.
// The algorithm:
// find rett - return from trap
// insert code before rett to:
// 1. load the FSR register
// 2. check if there is an FPU exception
// 3. branch to old rett if there is no exception
// 4. rett to a restored exec address
char RestoreExecAddress::ID = 0;

RestoreExecAddress::RestoreExecAddress(TargetMachine &tm)
    : LEONMachineFunctionPass(tm, ID) {}

bool RestoreExecAddress::runOnMachineFunction(MachineFunction &MF) {
  Subtarget = &MF.getSubtarget<SparcSubtarget>();
  const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
  DebugLoc DL = DebugLoc();

  bool Modified = false;
  for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
    MachineBasicBlock &MBB = *MFI;
    bool ExecAddressRestored = false;
    for (auto NMBBI = MBB.begin(), E = MBB.end(); NMBBI != E; ++NMBBI) {

      if (NMBBI != E && !ExecAddressRestored) {
        MachineBasicBlock::iterator MBBI = std::next(NMBBI);
        MachineInstr &MI = *MBBI;
        unsigned Opcode = MI.getOpcode();

        if (Opcode == SP::RETTrr || Opcode == SP::RETTri) {

          const BasicBlock *LLVM_BB = MBB.getBasicBlock();

          MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);

          // gets the FSR - floating point status register;
          // the firts 4 bits are *cexc* - current exception flags
          BuildMI(MBB, MBBI, DL, TII.get(SP::STFSRrr)).addReg(SP::L7).addImm(0);

          BuildMI(MBB, MBBI, DL, TII.get(SP::LDrr))
              .addReg(SP::L7)
              .addReg(SP::L7)
              .addImm(0);

          // performs a bitwise AND with b1111 to check the first 4 bits of FSR
          // (cexc)
          // if cexc is not zero, then it is an FPU exception
          BuildMI(MBB, MBBI, DL, TII.get(SP::ANDri))
              .addReg(SP::L7)
              .addReg(SP::L7)
              .addImm(15);

          BuildMI(MBB, MBBI, DL, TII.get(SP::CMPri)).addReg(SP::L7).addImm(0);

          BuildMI(MBB, MBBI, DL, TII.get(SP::BCOND))
              .addMBB(dneBB)
              .addImm(SPCC::ICC_E);
          // BuildMI(&MBB, DL,
          // TII.get(SP::BCOND)).addMBB(dneBB).addImm(SPCC::ICC_E);

          BuildMI(MBB, MBBI, DL, TII.get(SP::RETTri)).addReg(SP::L2).addImm(4);

          MachineFunction::iterator It =
              std::next(MachineFunction::iterator(MBB));
          MF.insert(It, dneBB);

          // Transfer the remainder of MBB and its successor edges to dneBB.
          dneBB->splice(dneBB->begin(), &MBB, MachineBasicBlock::iterator(MI),
                        MBB.end());
          dneBB->transferSuccessorsAndUpdatePHIs(&MBB);

          MBB.addSuccessor(dneBB);

          ExecAddressRestored = true;
          Modified = true;
        }
      }
    }
  }

  return Modified;
}

