diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Sparc/LeonPasses.cpp')
-rwxr-xr-x | contrib/llvm/lib/Target/Sparc/LeonPasses.cpp | 933 |
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; +} |