Index: lib/Target/Sparc/LeonFeatures.td =================================================================== --- lib/Target/Sparc/LeonFeatures.td +++ lib/Target/Sparc/LeonFeatures.td @@ -66,6 +66,14 @@ "LEON erratum fix: Replace FMULS instruction with FMULD and relevant conversion instructions" >; +def DetectRoundChange : SubtargetFeature< + "detectroundchange", + "DetectRoundChange", + "true", + "LEON3 erratum detection: Detects 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 DetectRoundChange + : public LEONMachineFunctionPass { +public: + static char ID; + + DetectRoundChange(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + StringRef getPassName() const override { + return "DetectRoundChange: Leon erratum detection: detect 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; @@ -274,6 +275,50 @@ return Modified; } + +//***************************************************************************** +//**** DetectRoundChange pass +//***************************************************************************** +// To prevent any explicit change of the default rounding mode, this pass +// detects any call of the fesetround function. +// A warning is generated to ensure the user knows this has happened. +// +// Detects an erratum in UT699 LEON 3 processor + +char DetectRoundChange::ID = 0; + +DetectRoundChange::DetectRoundChange(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool DetectRoundChange::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) { + errs() << "Error: You are using the detectroundchange " + "option to detect rounding changes that will " + "cause LEON errata. The only way to fix this " + "is to remove the call to fesetround from " + "the source code.\n"; + } + } + } + } + } + + return Modified; +} + //***************************************************************************** //**** FixAllFDIVSQRT pass //***************************************************************************** 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 DetectRoundChange; bool PerformSDIVReplace; SparcInstrInfo InstrInfo; @@ -93,6 +94,7 @@ bool fixFSMULD() const { return FixFSMULD; } bool replaceFMULS() const { return ReplaceFMULS; } bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; } + bool detectRoundChange() const { return DetectRoundChange; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -44,6 +44,7 @@ FixFSMULD = false; ReplaceFMULS = false; FixAllFDIVSQRT = false; + DetectRoundChange = false; // Determine default and user specified characteristics std::string CPUName = CPU; 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()->detectRoundChange()) { + addPass(new DetectRoundChange(getSparcTargetMachine())); + } if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT()) { addPass(new FixAllFDIVSQRT(getSparcTargetMachine())); Index: test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll =================================================================== --- test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll +++ test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll @@ -0,0 +1,11 @@ +; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -mattr=+detectroundchange -o - |& grep "detect rounding changes" + +; Function Attrs: nounwind +declare i32 @fesetround(i32) + +define void @test_round_change() { +entry: + %call = call i32 @fesetround(i32 2048) + + ret void +}