Index: lib/Target/Sparc/LeonFeatures.td =================================================================== --- lib/Target/Sparc/LeonFeatures.td +++ lib/Target/Sparc/LeonFeatures.td @@ -44,6 +44,14 @@ "LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction" >; +def InsertNOPDoublePrecision : SubtargetFeature< + "insrtnopdblprcsn", + "InsertNOPDoublePrecision", + "true", + "LEON2 erratum fix: Insert a NOP before the double " + "precision floating point instruction" +>; + def FixFSMULD : SubtargetFeature< "fixfsmuld", "FixFSMULD", Index: lib/Target/Sparc/LeonPasses.h =================================================================== --- lib/Target/Sparc/LeonPasses.h +++ lib/Target/Sparc/LeonPasses.h @@ -58,6 +58,20 @@ } }; +class LLVM_LIBRARY_VISIBILITY InsertNOPDoublePrecision + : public LEONMachineFunctionPass { +public: + static char ID; + + InsertNOPDoublePrecision(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + const char *getPassName() const override { + return "InsertNOPDoublePrecision: Leon erratum fix: insert a NOP before " + "the double precision floating point instruction"; + } +}; + class LLVM_LIBRARY_VISIBILITY FixFSMULD : public LEONMachineFunctionPass { public: static char ID; Index: lib/Target/Sparc/LeonPasses.cpp =================================================================== --- lib/Target/Sparc/LeonPasses.cpp +++ lib/Target/Sparc/LeonPasses.cpp @@ -275,6 +275,88 @@ } //***************************************************************************** +//**** 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(); + 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; +} + + +//***************************************************************************** //**** FixAllFDIVSQRT pass //***************************************************************************** // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that Index: lib/Target/Sparc/Sparc.td =================================================================== --- lib/Target/Sparc/Sparc.td +++ lib/Target/Sparc/Sparc.td @@ -110,12 +110,12 @@ // LEON 2 FT (AT697E) // TO DO: Place-holder: Processor specific features will be added *very* soon here. def : Processor<"at697e", LEON2Itineraries, - [FeatureLeon, InsertNOPLoad]>; + [FeatureLeon, InsertNOPLoad, InsertNOPDoublePrecision]>; // LEON 2 FT (AT697F) // TO DO: Place-holder: Processor specific features will be added *very* soon here. def : Processor<"at697f", LEON2Itineraries, - [FeatureLeon, InsertNOPLoad]>; + [FeatureLeon, InsertNOPLoad, InsertNOPDoublePrecision]>; // LEON 3 FT generic Index: lib/Target/Sparc/SparcSubtarget.h =================================================================== --- lib/Target/Sparc/SparcSubtarget.h +++ lib/Target/Sparc/SparcSubtarget.h @@ -48,6 +48,7 @@ bool FixFSMULD; bool ReplaceFMULS; bool FixAllFDIVSQRT; + bool InsertNOPDoublePrecision; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; @@ -88,6 +89,7 @@ bool hasUmacSmac() const { return HasUmacSmac; } bool hasLeonCasa() const { return HasLeonCasa; } bool insertNOPLoad() const { return InsertNOPLoad; } + bool insertNOPDoublePrecision() const { return InsertNOPDoublePrecision; } bool fixFSMULD() const { return FixFSMULD; } bool replaceFMULS() const { return ReplaceFMULS; } bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; } Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -39,6 +39,7 @@ // Leon features HasLeonCasa = false; HasUmacSmac = false; + InsertNOPDoublePrecision = false; InsertNOPLoad = false; FixFSMULD = false; ReplaceFMULS = false; Index: lib/Target/Sparc/SparcTargetMachine.cpp =================================================================== --- lib/Target/Sparc/SparcTargetMachine.cpp +++ lib/Target/Sparc/SparcTargetMachine.cpp @@ -161,6 +161,10 @@ { addPass(new FixAllFDIVSQRT(getSparcTargetMachine())); } + if (this->getSparcTargetMachine() + .getSubtargetImpl()->insertNOPDoublePrecision()) { + addPass(new InsertNOPDoublePrecision(getSparcTargetMachine())); + } } void SparcV8TargetMachine::anchor() { } Index: test/CodeGen/SPARC/LeonInsertNOPsDoublePrecision.ll =================================================================== --- test/CodeGen/SPARC/LeonInsertNOPsDoublePrecision.ll +++ test/CodeGen/SPARC/LeonInsertNOPsDoublePrecision.ll @@ -0,0 +1,17 @@ +; RUN: llc %s -O0 -march=sparc -mcpu=at697f -o - | FileCheck %s + +; CHECK: ldd +; CHECK: ldd +; CHECK-NEXT: nop + +define double @mult() #0 { +entry: + %x = alloca double, align 8 + %y = alloca double, align 8 + store double 3.141590e+00, double* %x, align 8 + store double 1.234560e+00, double* %y, align 8 + %0 = load double, double* %x, align 8 + %1 = load double, double* %y, align 8 + %mul = fmul double %0, %1 + ret double %mul +}