From 2c3cdd66d27e046547315e9a1480c6ae32ad2bde Mon Sep 17 00:00:00 2001 From: Chris Dewhurst Date: Wed, 19 Oct 2016 14:01:06 +0000 Subject: [PATCH] [Sparc][LEON] Detects an erratum on UT699 LEON 3 processors involving rounding mode changes and issues an appropriate user error message. Differential Revision: https://reviews.llvm.org/D24665 llvm-svn: 284591 --- llvm/lib/Target/Sparc/LeonFeatures.td | 8 ++++ llvm/lib/Target/Sparc/LeonPasses.cpp | 45 +++++++++++++++++++ llvm/lib/Target/Sparc/LeonPasses.h | 14 ++++++ llvm/lib/Target/Sparc/SparcSubtarget.cpp | 1 + llvm/lib/Target/Sparc/SparcSubtarget.h | 2 + llvm/lib/Target/Sparc/SparcTargetMachine.cpp | 3 ++ .../SPARC/LeonDetectRoundChangePassUT.ll | 22 +++++++++ 7 files changed, 95 insertions(+) create mode 100644 llvm/test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll diff --git a/llvm/lib/Target/Sparc/LeonFeatures.td b/llvm/lib/Target/Sparc/LeonFeatures.td index 27d739b5a858..d06e734b5a7b 100755 --- a/llvm/lib/Target/Sparc/LeonFeatures.td +++ b/llvm/lib/Target/Sparc/LeonFeatures.td @@ -66,6 +66,14 @@ def ReplaceFMULS : SubtargetFeature< "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", diff --git a/llvm/lib/Target/Sparc/LeonPasses.cpp b/llvm/lib/Target/Sparc/LeonPasses.cpp index 46ae9ccc783f..0acc2875daa8 100644 --- a/llvm/lib/Target/Sparc/LeonPasses.cpp +++ b/llvm/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 @@ bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) { 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 //***************************************************************************** diff --git a/llvm/lib/Target/Sparc/LeonPasses.h b/llvm/lib/Target/Sparc/LeonPasses.h index c3ff86903292..2158cb636bfc 100755 --- a/llvm/lib/Target/Sparc/LeonPasses.h +++ b/llvm/lib/Target/Sparc/LeonPasses.h @@ -84,6 +84,20 @@ public: } }; +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; diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp index 75ea4c7c8f57..43ddef3cc96e 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -44,6 +44,7 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU, FixFSMULD = false; ReplaceFMULS = false; FixAllFDIVSQRT = false; + DetectRoundChange = false; // Determine default and user specified characteristics std::string CPUName = CPU; diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h index 25dc4291c44f..fa42da425ff2 100644 --- a/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -48,6 +48,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { bool FixFSMULD; bool ReplaceFMULS; bool FixAllFDIVSQRT; + bool DetectRoundChange; bool PerformSDIVReplace; SparcInstrInfo InstrInfo; @@ -93,6 +94,7 @@ public: 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. diff --git a/llvm/lib/Target/Sparc/SparcTargetMachine.cpp b/llvm/lib/Target/Sparc/SparcTargetMachine.cpp index 0669eb6cc6a9..4ae64062d9e2 100644 --- a/llvm/lib/Target/Sparc/SparcTargetMachine.cpp +++ b/llvm/lib/Target/Sparc/SparcTargetMachine.cpp @@ -157,6 +157,9 @@ void SparcPassConfig::addPreEmitPass(){ { addPass(new ReplaceFMULS(getSparcTargetMachine())); } + if (this->getSparcTargetMachine().getSubtargetImpl()->detectRoundChange()) { + addPass(new DetectRoundChange(getSparcTargetMachine())); + } if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT()) { addPass(new FixAllFDIVSQRT(getSparcTargetMachine())); diff --git a/llvm/test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll b/llvm/test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll new file mode 100644 index 000000000000..bcb350ebb004 --- /dev/null +++ b/llvm/test/CodeGen/SPARC/LeonDetectRoundChangePassUT.ll @@ -0,0 +1,22 @@ +; 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 +} +; 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 +}