Index: lib/Target/Sparc/LeonFeatures.td =================================================================== --- lib/Target/Sparc/LeonFeatures.td +++ lib/Target/Sparc/LeonFeatures.td @@ -58,6 +58,14 @@ "LEON erratum fix: Replace FMULS instruction with FMULD and relevant conversion instructions" >; +def PreventRoundChange : SubtargetFeature< + "prvntroundchange", + "PreventRoundChange", + "true", + "LEON3 erratum fix: Prevent any rounding mode change " + "request: use only the round-to-nearest rounding mode" +>; + def FixAllFDIVSQRT : SubtargetFeature< "fixallfdivsqrt", "FixAllFDIVSQRT", Index: lib/Target/Sparc/LeonPasses.h =================================================================== --- lib/Target/Sparc/LeonPasses.h +++ lib/Target/Sparc/LeonPasses.h @@ -84,6 +84,20 @@ } }; +class LLVM_LIBRARY_VISIBILITY PreventRoundChange + : public LEONMachineFunctionPass { +public: + static char ID; + + PreventRoundChange(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + const char *getPassName() const override { + return "PreventRoundChange: Leon erratum fix: prevent any rounding mode " + "change request: use only the round-to-nearest rounding mode"; + } +}; + class LLVM_LIBRARY_VISIBILITY FixAllFDIVSQRT : public LEONMachineFunctionPass { public: static char ID; Index: lib/Target/Sparc/LeonPasses.cpp =================================================================== --- lib/Target/Sparc/LeonPasses.cpp +++ lib/Target/Sparc/LeonPasses.cpp @@ -16,6 +16,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -327,3 +328,52 @@ 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. A warning is generated to ensure the user +// knows this has happened. +// +// Fixes erratum in UT699 LEON 3 processor + +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); + emitOptimizationRemark( + MF.getFunction()->getContext(), getPassName(), *MF.getFunction(), + MI.getDebugLoc(), "Warning: You are using the prvntroundchange " + "option to prevent rounding changes caused " + "by LEON errata. A call to fesetround to be " + "removed from the output."); + MI.eraseFromParent(); + MBBI = NMBBI; + Modified = true; + } + } + } + } + } + + return Modified; +} 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 PreventRoundChange; SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; @@ -90,6 +91,7 @@ bool insertNOPLoad() const { return InsertNOPLoad; } bool fixFSMULD() const { return FixFSMULD; } bool replaceFMULS() const { return ReplaceFMULS; } + bool preventRoundChange() const { return PreventRoundChange; } bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; } /// ParseSubtargetFeatures - Parses features string setting specified Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -42,6 +42,7 @@ InsertNOPLoad = false; FixFSMULD = false; ReplaceFMULS = false; + PreventRoundChange = false; FixAllFDIVSQRT = false; // Determine default and user specified characteristics Index: lib/Target/Sparc/SparcTargetMachine.cpp =================================================================== --- lib/Target/Sparc/SparcTargetMachine.cpp +++ lib/Target/Sparc/SparcTargetMachine.cpp @@ -157,6 +157,9 @@ { addPass(new ReplaceFMULS(getSparcTargetMachine())); } + if (this->getSparcTargetMachine().getSubtargetImpl()->preventRoundChange()) { + addPass(new PreventRoundChange(getSparcTargetMachine())); + } if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT()) { addPass(new FixAllFDIVSQRT(getSparcTargetMachine())); Index: test/CodeGen/SPARC/LeonPreventRoundChangePassUT.ll =================================================================== --- test/CodeGen/SPARC/LeonPreventRoundChangePassUT.ll +++ test/CodeGen/SPARC/LeonPreventRoundChangePassUT.ll @@ -0,0 +1,65 @@ +; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s -check-prefix=NO_ROUND_FUNC +; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -mattr=+prvntroundchange -o - | FileCheck %s -check-prefix=NO_ROUND_FUNC + +; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -mattr=-prvntroundchange -o - | FileCheck %s -check-prefix=ROUND_FUNC +; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -o - | FileCheck %s -check-prefix=ROUND_FUNC + + +; NO_ROUND_FUNC-LABEL: test_round_change +; NO_ROUND_FUNC-NOT: fesetround + +; ROUND_FUNC-LABEL: test_round_change +; ROUND_FUNC: fesetround + +; ModuleID = '' +target datalayout = "E-m:e-p:32:32-i64:64-f128:64-n32-S64" +target triple = "sparc-unknown--eabi" + +@.str = private unnamed_addr constant [17 x i8] c"-((-a)*b) != a*b\00", align 1 +@.str.1 = private unnamed_addr constant [7 x i8] c"test.c\00", align 1 +@__PRETTY_FUNCTION__.mult = private unnamed_addr constant [12 x i8] c"void mult()\00", align 1 + +; Function Attrs: nounwind +define void @test_round_change() #0 { +entry: + %a = alloca double, align 8 + %b = alloca double, align 8 + %x = alloca float, align 4 + store double 1.100000e+00, double* %a, align 8 + store double 1.010000e+01, double* %b, align 8 + store float 0x400921FA00000000, float* %x, align 4 + %call = call i32 @fesetround(i32 2048) #2 + %0 = load double, double* %a, align 8 + %sub = fsub double -0.000000e+00, %0 + %1 = load double, double* %b, align 8 + %mul = fmul double %sub, %1 + %sub1 = fsub double -0.000000e+00, %mul + %2 = load double, double* %a, align 8 + %3 = load double, double* %b, align 8 + %mul2 = fmul double %2, %3 + %cmp = fcmp une double %sub1, %mul2 + br i1 %cmp, label %cond.true, label %cond.false + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + call void @__assert_fail(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i32 10, i8* getelementptr inbounds ([12 x i8], [12 x i8]* @__PRETTY_FUNCTION__.mult, i32 0, i32 0)) #3 + unreachable + ; No predecessors! + br label %cond.end + +cond.end: ; preds = %4, %cond.true + ret void +} + +; Function Attrs: nounwind +declare i32 @fesetround(i32) #0 + +; Function Attrs: noreturn nounwind +declare void @__assert_fail(i8*, i8*, i32, i8*) #1 + +attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noreturn nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } +attributes #3 = { noreturn nounwind } \ No newline at end of file