aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/Sparc/LeonPasses.cpp')
-rwxr-xr-xcontrib/llvm/lib/Target/Sparc/LeonPasses.cpp933
1 files changed, 933 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp b/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
new file mode 100755
index 000000000000..5d0920892ff0
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/LeonPasses.cpp
@@ -0,0 +1,933 @@
+//===------ 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/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) &&
+ !(std::find(UsedRegisters.begin(), UsedRegisters.end(),
+ RegisterIndex) != UsedRegisters.end())) {
+ 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;
+ } else if (MI.isInlineAsm()) {
+ // Look for an inline ld or ldf instruction.
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("ld")) {
+ 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();
+ } else if (MI.isInlineAsm()) {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("fsmuld")) {
+ // this is an inline FSMULD instruction
+
+ unsigned StartOp = InlineAsm::MIOp_FirstOperand;
+
+ // extracts the registers from the inline assembly instruction
+ for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
+ if (MO.isReg()) {
+ if (Reg1Index == UNASSIGNED_INDEX)
+ Reg1Index = MO.getReg();
+ else if (Reg2Index == UNASSIGNED_INDEX)
+ Reg2Index = MO.getReg();
+ else if (Reg3Index == UNASSIGNED_INDEX)
+ Reg3Index = MO.getReg();
+ }
+ if (Reg3Index != UNASSIGNED_INDEX)
+ break;
+ }
+ }
+ }
+
+ 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();
+ } else if (MI.isInlineAsm()) {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("fmuls")) {
+ // this is an inline FMULS instruction
+ unsigned StartOp = InlineAsm::MIOp_FirstOperand;
+
+ // extracts the registers from the inline assembly instruction
+ for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
+ if (MO.isReg()) {
+ if (Reg1Index == UNASSIGNED_INDEX)
+ Reg1Index = MO.getReg();
+ else if (Reg2Index == UNASSIGNED_INDEX)
+ Reg2Index = MO.getReg();
+ else if (Reg3Index == UNASSIGNED_INDEX)
+ Reg3Index = MO.getReg();
+ }
+ if (Reg3Index != UNASSIGNED_INDEX)
+ break;
+ }
+ }
+ }
+
+ 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();
+
+ if (MI.isInlineAsm()) {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("fsqrtd")) {
+ // this is an inline fsqrts instruction
+ Opcode = SP::FSQRTD;
+ } else if (AsmString.startswith_lower("fdivd")) {
+ // this is an inline fsqrts instruction
+ Opcode = SP::FDIVD;
+ }
+ }
+
+ // 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;
+ MI.print(errs());
+ errs() << "\n";
+
+ 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;
+ }
+ }
+ } else if (MI.isInlineAsm()) // inline assembly immediate call
+ {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("call")) {
+ // this is an inline call instruction
+ unsigned StartOp = InlineAsm::MIOp_FirstOperand;
+
+ // extracts the registers from the inline assembly instruction
+ for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
+ MachineOperand &MO = MI.getOperand(i);
+ if (MO.isImm()) {
+ int64_t Value = MO.getImm();
+ MO.setImm(Value & 0x000fffffL);
+ Modified = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ 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;
+ } else if (MI.isInlineAsm()) {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("sdivcc") ||
+ AsmString.startswith_lower("udivcc")) {
+ // this is an inline SDIVCC or UDIVCC instruction
+
+ // 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();
+ // NMI.print(errs());
+ 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);
+ MI.eraseFromParent();
+ MBBI = NMBBI;
+ Modified = true;
+ }
+ }
+ }
+ }
+ }
+
+ return Modified;
+}
+//*****************************************************************************
+//**** FlushCacheLineSWAP pass
+//*****************************************************************************
+// This pass inserts FLUSHW just before any SWAP atomic instruction.
+//
+char FlushCacheLineSWAP::ID = 0;
+
+FlushCacheLineSWAP::FlushCacheLineSWAP(TargetMachine &tm)
+ : LEONMachineFunctionPass(tm, ID) {}
+
+bool FlushCacheLineSWAP::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::SWAPrr || Opcode == SP::SWAPri ||
+ Opcode == SP::LDSTUBrr || Opcode == SP::LDSTUBri) {
+ // insert flush and 5 NOPs before the swap/ldstub instruction
+ BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+
+ Modified = true;
+ } else if (MI.isInlineAsm()) {
+ StringRef AsmString =
+ MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
+ if (AsmString.startswith_lower("swap") ||
+ AsmString.startswith_lower("ldstub")) {
+ // this is an inline swap or ldstub instruction
+
+ // insert flush and 5 NOPs before the swap/ldstub instruction
+ BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+
+ 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;
+}