//===------ 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(); 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(); 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(); 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(); 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(); 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 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(); 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(); 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(); 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(); 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(); 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; }