[PATCH] Flag to enable IEEE-754 friendly FP optimizations

Sergey Dmitrouk sdmitrouk at accesssoftek.com
Tue May 26 09:43:22 PDT 2015


Hi there,

Nope, I didn't forget about these changes :)  Ping!

Patches rebased onto ToT can be found in the attachment.

-- 
Sergey

On Fri, Mar 27, 2015 at 09:13:44AM -0700, Mehdi Amini wrote:
> Hi Sergey,
>
> I’m sorry that in 6 weeks nobody was able to approve your patches despite your pings.
>
> The code LGTM, but I don’t feel qualified enough to approve the global direction where this leads and I rather have someone else reviewing the “conceptual” part.
>
> Add CC Hal, who was involved at the beginning of the thread.
>
> Best,
>
>> Mehdi
>
> > On Mar 26, 2015, at 4:28 AM, Sergey Dmitrouk <sdmitrouk at accesssoftek.com> wrote:
> >
> > Ping.
> >
> > On Mon, Mar 16, 2015 at 09:55:45PM +0200, Sergey Dmitrouk wrote:
> >> Gentle ping.
> >>
> >> On Thu, Feb 26, 2015 at 01:33:19PM +0200, Sergey Dmitrouk wrote:
> >>> Ping.
> >>>
> >>> On Thu, Feb 19, 2015 at 05:34:26PM +0200, Sergey Dmitrouk wrote:
> >>>> Ping.
> >>>>
> >>>> On Tue, Feb 10, 2015 at 08:12:13PM +0200, Sergey Dmitrouk wrote:
> >>>>> Attached is alternative fix for InstCombine hanging, it disables only a
> >>>>> couple of conversions of "fadd" into "fsub" to break the loop.
> >>>>>
> >>>>> Modifying dyn_castFNegVal() directly causes some unit tests to fail, so
> >>>>> absence of checks seems to be intensional to enable more transformations.
> >>>>> As there exist "fsub" to "fadd" transformations and vice versa, making
> >>>>> some forms as canonical would disable at least one of them.  So the
> >>>>> patch disables replacements of "fadd" with "fsub" for "fadd"
> >>>>> instructions marked with floating-point environment access flags.
> >>>>>
> >>>>> Regards,
> >>>>> Sergey
> >>>>>
> >>>>> On Thu, Feb 05, 2015 at 07:56:56PM +0200, Sergey Dmitrouk wrote:
> >>>>>> Hello,
> >>>>>>
> >>>>>> Thanks for reviewing this.
> >>>>>>
> >>>>>> On Wed, Feb 04, 2015 at 10:42:35AM -0800, Mehdi Amini wrote:
> >>>>>>> Patch 1:
> >>>>>>>
> >>>>>>> The comment for:
> >>>>>>> +    unsigned AllowFPExceptAccess : 1;
> >>>>>>> mentions rounding and the comment for:
> >>>>>>> +    unsigned AllowFPRoundAccess : 1;
> >>>>>>> mentions exceptions, they are reversed.
> >>>>>>
> >>>>>> Updated.
> >>>>>>
> >>>>>>> Patch 2:
> >>>>>>>
> >>>>>>> Is kexc or kround flag allowed to be present at the same time as fast?
> >>>>>>
> >>>>>> Yes, currently they are.  There is no particular reason for this except
> >>>>>> for me not being able to decide whether "fast" should reset new flags or
> >>>>>> not.  Left it unrelated to each other as they are unlikely to be used at
> >>>>>> the same time, ready to change it if you have any suggestions.
> >>>>>>
> >>>>>>> Patch 3:
> >>>>>>>
> >>>>>>> isSafeToOptimizeFPOp() is not clear to me, especially how TLI->hasFloatingPointExceptions() disable any check, including rounding, while the description of this flag is "Whether the target supports or cares about preserving floating point exception behavior”, which seems orthogonal to getTarget().Options.AllowFPRoundAccess?
> >>>>>>> I assume it is done this way to keep existing behavior? Is it transitional?
> >>>>>>
> >>>>>> That's a mistake, it was fine until recent change for rounding when I
> >>>>>> reordered if statements incorrectly.  Thanks.
> >>>>>>
> >>>>>>> Patch 4:
> >>>>>>>
> >>>>>>> isSafeToSpeculativelyExecute(), comment might deserve to be updated , I don’t think it is true anymore with respect to rounding:
> >>>>>>> "Return true if the instruction does not have any effects besides calculating the result and does not have undefined behavior”.
> >>>>>>
> >>>>>> Updated.
> >>>>>>
> >>>>>>> canTrap(), again preserving the dynamic “rounding” is included in “trap”? Maybe the comment could be updated because it does not seem obvious to me.
> >>>>>>
> >>>>>> Actually, rounding flag wasn't even used and exceptions flag was
> >>>>>> unnecessary, so I just reverted that part.  It was required with flags
> >>>>>> being detached from instructions, but now that they are part of
> >>>>>> fast-math flags checking constant expressions should be no-operation
> >>>>>> (operations that go against flags must not be converted to constant
> >>>>>> expressions).
> >>>>>>
> >>>>>>> Patch 10: if you really want to test it, maybe the C++ unittests can do the job?
> >>>>>>
> >>>>>> Thanks, added a unit-test and a correction for "frem" instruction.
> >>>>>>
> >>>>>>> Patch 12: haven’t look into detail where the infinite loop occurs, but it seems like a hammer fix for the issue. The example mentioned in the test ((a + b) => (a - (-b)) => (a + b) => etc) makes me thinks that one of the two forms should be canonical and InstCombine should not make one of these two transforms. What do you think?
> >>>>>>
> >>>>>> I chose this way as it should guarantee to work for all cases, but you
> >>>>>> might be right in that something is wrong with pattern matching in
> >>>>>> InstCombine, see below.
> >>>>>>
> >>>>>> There is an implicit four step loop between InstCombiner::visitFAdd() and
> >>>>>> InstCombiner::visitFSub():
> >>>>>>
> >>>>>> 1. FAdd: Convert A to -A.
> >>>>>> 2. FSub: Convert -A to A; switch operands.
> >>>>>> 3. FAdd: Convert B to -B.
> >>>>>> 4. FSub: Convert -B to B; switch operands.
> >>>>>> 5. Go to step 1.
> >>>>>>
> >>>>>> Both functions try to do something about negative values, but they
> >>>>>> actually hang in case of positive arguments as well.  I couldn't find
> >>>>>> any checks whether operands are negative, it seems to be "assumed".
> >>>>>> Maybe dyn_castFNegVal() used to perform the check, but it doesn't anymore.
> >>>>>>
> >>>>>> If I add `C->isNegative()` check to dyn_castFNegVal(), the issue
> >>>>>> disappears, but I'm not sure if it's the right place.  Meaning of the
> >>>>>> comment there:
> >>>>>>
> >>>>>>  // Constants can be considered to be negated values if they can be
> >>>>>>  // folded.
> >>>>>>  if (ConstantFP *C = dyn_cast<ConstantFP>(V))
> >>>>>>    return ConstantExpr::getFNeg(C);
> >>>>>>
> >>>>>> is unclear to me.  Does it suggest that the function doesn't care about
> >>>>>> sign of the value?  In this case, checks for negative operands should be
> >>>>>> performed outside (in visitFAdd() and visitFSub() functions).
> >>>>>>
> >>>>>> Updated patches are attached (0000-recent-changes.diff contains latest
> >>>>>> changes only).  There is nothing for InstCombine yet and a small new
> >>>>>> change (not counting test file) for LICM pass.
> >>>>>>
> >>>>>> Thanks,
> >>>>>> Sergey
-------------- next part --------------
>From 4ec30372f25a9be5ec5b3be9866c8b3258ec00d9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 16:54:23 +0200
Subject: [PATCH 01/13] Add flags and command-line switches for FPEnv

* Two flags for TargetOptions.
* Three command-line switches to enable flags separately or at the same
  time.
---
 include/llvm/CodeGen/CommandFlags.h | 19 +++++++++++++++++++
 include/llvm/Target/TargetOptions.h | 17 ++++++++++++++++-
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h
index a58c2de..886f786 100644
--- a/include/llvm/CodeGen/CommandFlags.h
+++ b/include/llvm/CodeGen/CommandFlags.h
@@ -126,6 +126,21 @@ EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
       cl::desc("Force codegen to assume rounding mode can change dynamically"),
       cl::init(false));
 
+cl::opt<bool>
+EnableFPEnvAccessFPMath("enable-fpenv-access-fp-math",
+    cl::desc("Disable FP math optimizations that affect FP environment access"),
+    cl::init(false));
+
+cl::opt<bool>
+EnableExceptAccessFPMath("enable-except-access-fp-math",
+            cl::desc("Disable FP math optimizations that affect FP exceptions"),
+            cl::init(false));
+
+cl::opt<bool>
+EnableRoundAccessFPMath("enable-round-access-fp-math",
+              cl::desc("Disable FP math optimizations that affect FP rounding"),
+              cl::init(false));
+
 cl::opt<llvm::FloatABI::ABIType>
 FloatABIForCalls("float-abi",
                  cl::desc("Choose float ABI type"),
@@ -237,6 +252,10 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
   Options.NoNaNsFPMath = EnableNoNaNsFPMath;
   Options.HonorSignDependentRoundingFPMathOption =
       EnableHonorSignDependentRoundingFPMath;
+  Options.AllowFPExceptAccess = EnableExceptAccessFPMath |
+      EnableFPEnvAccessFPMath;
+  Options.AllowFPRoundAccess = EnableRoundAccessFPMath |
+      EnableFPEnvAccessFPMath;
   if (FloatABIForCalls != FloatABI::Default)
     Options.FloatABIType = FloatABIForCalls;
   Options.NoZerosInBSS = DontPlaceZerosInBSS;
diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h
index 435a0fd..21f19c5 100644
--- a/include/llvm/Target/TargetOptions.h
+++ b/include/llvm/Target/TargetOptions.h
@@ -63,7 +63,8 @@ namespace llvm {
         : PrintMachineCode(false), NoFramePointerElim(false),
           NoFramePointerElimOverride(false),
           LessPreciseFPMADOption(false), UnsafeFPMath(false),
-          NoInfsFPMath(false), NoNaNsFPMath(false),
+          NoInfsFPMath(false), NoNaNsFPMath(false), AllowFPExceptAccess(false),
+          AllowFPRoundAccess(false),
           HonorSignDependentRoundingFPMathOption(false),
           NoZerosInBSS(false),
           GuaranteedTailCallOpt(false),
@@ -121,6 +122,20 @@ namespace llvm {
     /// assume the FP arithmetic arguments and results are never NaNs.
     unsigned NoNaNsFPMath : 1;
 
+    /// AllowFPExceptAccess - This flag is enabled when the
+    /// -enable-except-access-fp-math or -enable-fpenv-access-fp-math flag is
+    /// specified on the command line.  When this flag is off (the default), the
+    /// code generator is allowed to assume exceptions part of floating-point
+    /// environment is not accessed by the program.
+    unsigned AllowFPExceptAccess : 1;
+
+    /// AllowFPRoundAccess - This flag is enabled when the
+    /// -enable-round-access-fp-math or -enable-fpenv-access-fp-math flag is
+    /// specified on the command line. When this flag is off (the default), the
+    /// code generator is allowed to assume rounding part of floating-point
+    /// environment is not accessed by the program.
+    unsigned AllowFPRoundAccess : 1;
+
     /// HonorSignDependentRoundingFPMath - This returns true when the
     /// -enable-sign-dependent-rounding-fp-math is specified.  If this returns
     /// false (the default), the code generator is allowed to assume that the
-- 
2.3.5

-------------- next part --------------
>From 808f76d25fe576a1a0f6766c18ba1ac63857fa37 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 16:06:06 +0200
Subject: [PATCH 02/13] Add FPEnv access flags to fast-math flags

Will be used to disable optimizations related to floating-point
operations which would affect runtime semantics (e.g. raising
floating-point exceptions).
---
 docs/LangRef.rst                     |  9 ++++++++-
 include/llvm/IR/Instruction.h        | 16 ++++++++++++++++
 include/llvm/IR/Operator.h           | 30 +++++++++++++++++++++++++++++-
 lib/AsmParser/LLLexer.cpp            |  2 ++
 lib/AsmParser/LLParser.h             | 12 +++++++-----
 lib/AsmParser/LLToken.h              |  2 ++
 lib/Bitcode/Reader/BitcodeReader.cpp |  4 ++++
 lib/Bitcode/Writer/BitcodeWriter.cpp |  4 ++++
 lib/IR/AsmWriter.cpp                 |  4 ++++
 lib/IR/Instruction.cpp               | 28 ++++++++++++++++++++++++++++
 test/Assembler/fast-math-flags.ll    |  8 ++++++++
 11 files changed, 112 insertions(+), 7 deletions(-)

diff --git a/docs/LangRef.rst b/docs/LangRef.rst
index 1ee16f8..2e5cb69 100644
--- a/docs/LangRef.rst
+++ b/docs/LangRef.rst
@@ -1825,10 +1825,17 @@ otherwise unsafe floating point operations
    Allow Reciprocal - Allow optimizations to use the reciprocal of an
    argument rather than perform division.
 
+``kexc``
+   Keep Exceptions - Forbid optimizations to affect floating point exceptions
+   that can be thrown at runtime.
+
+``kround``
+   Keep Rounding - Forbid optimizations to assume any predefined rounding mode.
+
 ``fast``
    Fast - Allow algebraically equivalent transformations that may
    dramatically change results in floating point (e.g. reassociate). This
-   flag implies all the others.
+   flag implies all the others except for the last two.
 
 .. _uselistorder:
 
diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h
index 2b9bc77..c44c58a 100644
--- a/include/llvm/IR/Instruction.h
+++ b/include/llvm/IR/Instruction.h
@@ -253,6 +253,16 @@ public:
   /// this flag.
   void setHasAllowReciprocal(bool B);
 
+  /// Set or clear the keep-exceptions flag on this instruction, which must be
+  /// an operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasKeepExceptions(bool B);
+
+  /// Set or clear the keep-rounding flag on this instruction, which must be an
+  /// operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasKeepRounding(bool B);
+
   /// Convenience function for setting multiple fast-math flags on this
   /// instruction, which must be an operator which supports these flags. See
   /// LangRef.html for the meaning of these flags.
@@ -278,6 +288,12 @@ public:
   /// Determine whether the allow-reciprocal flag is set.
   bool hasAllowReciprocal() const;
 
+  /// Determine whether the keep-exceptions flag is set.
+  bool hasKeepExceptions() const;
+
+  /// Determine whether the keep-rounding flag is set.
+  bool hasKeepRounding() const;
+
   /// Convenience function for getting all the fast-math flags, which must be an
   /// operator which supports these flags. See LangRef.html for the meaning of
   /// these flags.
diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h
index 1b9102e..dd5e689 100644
--- a/include/llvm/IR/Operator.h
+++ b/include/llvm/IR/Operator.h
@@ -173,7 +173,9 @@ public:
     NoNaNs          = (1 << 1),
     NoInfs          = (1 << 2),
     NoSignedZeros   = (1 << 3),
-    AllowReciprocal = (1 << 4)
+    AllowReciprocal = (1 << 4),
+    KeepExceptions  = (1 << 5),
+    KeepRounding    = (1 << 6)
   };
 
   FastMathFlags() : Flags(0)
@@ -191,6 +193,8 @@ public:
   bool noSignedZeros() const   { return 0 != (Flags & NoSignedZeros); }
   bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); }
   bool unsafeAlgebra() const   { return 0 != (Flags & UnsafeAlgebra); }
+  bool keepExceptions() const  { return 0 != (Flags & KeepExceptions); }
+  bool keepRounding()const     { return 0 != (Flags & KeepRounding); }
 
   /// Flag setters
   void setNoNaNs()          { Flags |= NoNaNs; }
@@ -204,6 +208,8 @@ public:
     setNoSignedZeros();
     setAllowReciprocal();
   }
+  void setKeepExceptions() { Flags |= KeepExceptions; }
+  void setKeepRounding()   { Flags |= KeepRounding; }
 
   void operator&=(const FastMathFlags &OtherFlags) {
     Flags &= OtherFlags.Flags;
@@ -250,6 +256,16 @@ private:
       (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
       (B * FastMathFlags::AllowReciprocal);
   }
+  void setHasKeepExceptions(bool B) {
+    SubclassOptionalData =
+      (SubclassOptionalData & ~FastMathFlags::KeepExceptions) |
+      (B * FastMathFlags::KeepExceptions);
+  }
+  void setHasKeepRounding(bool B) {
+    SubclassOptionalData =
+      (SubclassOptionalData & ~FastMathFlags::KeepRounding) |
+      (B * FastMathFlags::KeepRounding);
+  }
 
   /// Convenience function for setting multiple fast-math flags.
   /// FMF is a mask of the bits to set.
@@ -294,6 +310,18 @@ public:
     return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
   }
 
+  /// Test whether this operation should not be optimized if its runtime
+  /// semantics regarding floating-point exceptions can't be preserved.
+  bool hasKeepExceptions() const {
+    return (SubclassOptionalData & FastMathFlags::KeepExceptions) != 0;
+  }
+
+  /// Test whether this operation should not be optimized if its runtime
+  /// semantics regarding floating-point rounding modes can't be preserved.
+  bool hasKeepRounding() const {
+    return (SubclassOptionalData & FastMathFlags::KeepRounding) != 0;
+  }
+
   /// Convenience function for getting all the fast-math flags
   FastMathFlags getFastMathFlags() const {
     return FastMathFlags(SubclassOptionalData);
diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp
index a72f713..d508243 100644
--- a/lib/AsmParser/LLLexer.cpp
+++ b/lib/AsmParser/LLLexer.cpp
@@ -545,6 +545,8 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(ninf);
   KEYWORD(nsz);
   KEYWORD(arcp);
+  KEYWORD(kexc);
+  KEYWORD(kround);
   KEYWORD(fast);
   KEYWORD(nuw);
   KEYWORD(nsw);
diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h
index a43a4b0..632d401 100644
--- a/lib/AsmParser/LLParser.h
+++ b/lib/AsmParser/LLParser.h
@@ -173,11 +173,13 @@ namespace llvm {
       FastMathFlags FMF;
       while (true)
         switch (Lex.getKind()) {
-        case lltok::kw_fast: FMF.setUnsafeAlgebra();   Lex.Lex(); continue;
-        case lltok::kw_nnan: FMF.setNoNaNs();          Lex.Lex(); continue;
-        case lltok::kw_ninf: FMF.setNoInfs();          Lex.Lex(); continue;
-        case lltok::kw_nsz:  FMF.setNoSignedZeros();   Lex.Lex(); continue;
-        case lltok::kw_arcp: FMF.setAllowReciprocal(); Lex.Lex(); continue;
+        case lltok::kw_fast:   FMF.setUnsafeAlgebra();   Lex.Lex(); continue;
+        case lltok::kw_nnan:   FMF.setNoNaNs();          Lex.Lex(); continue;
+        case lltok::kw_ninf:   FMF.setNoInfs();          Lex.Lex(); continue;
+        case lltok::kw_nsz:    FMF.setNoSignedZeros();   Lex.Lex(); continue;
+        case lltok::kw_arcp:   FMF.setAllowReciprocal(); Lex.Lex(); continue;
+        case lltok::kw_kexc:   FMF.setKeepExceptions();  Lex.Lex(); continue;
+        case lltok::kw_kround: FMF.setKeepRounding();    Lex.Lex(); continue;
         default: return FMF;
         }
       return FMF;
diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h
index 2bdc53b..122408d 100644
--- a/lib/AsmParser/LLToken.h
+++ b/lib/AsmParser/LLToken.h
@@ -66,6 +66,8 @@ namespace lltok {
     kw_ninf,
     kw_nsz,
     kw_arcp,
+    kw_kexc,
+    kw_kround,
     kw_fast,
     kw_nuw,
     kw_nsw,
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index 6eef594..ec404c5 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -3497,6 +3497,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) {
             FMF.setNoSignedZeros();
           if (0 != (Record[OpNum] & FastMathFlags::AllowReciprocal))
             FMF.setAllowReciprocal();
+          if (0 != (Record[OpNum] & FastMathFlags::KeepExceptions))
+            FMF.setKeepExceptions();
+          if (0 != (Record[OpNum] & FastMathFlags::KeepRounding))
+            FMF.setKeepRounding();
           if (FMF.any())
             I->setFastMathFlags(FMF);
         }
diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp
index 3a539e1..bd24c24 100644
--- a/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -752,6 +752,10 @@ static uint64_t GetOptimizationFlags(const Value *V) {
       Flags |= FastMathFlags::NoSignedZeros;
     if (FPMO->hasAllowReciprocal())
       Flags |= FastMathFlags::AllowReciprocal;
+    if (FPMO->hasKeepExceptions())
+      Flags |= FastMathFlags::KeepExceptions;
+    if (FPMO->hasKeepRounding())
+      Flags |= FastMathFlags::KeepRounding;
   }
 
   return Flags;
diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp
index 1089cb5..48ffd7b 100644
--- a/lib/IR/AsmWriter.cpp
+++ b/lib/IR/AsmWriter.cpp
@@ -1020,6 +1020,10 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
         Out << " nsz";
       if (FPO->hasAllowReciprocal())
         Out << " arcp";
+      if (FPO->hasKeepExceptions())
+        Out << " kexc";
+      if (FPO->hasKeepRounding())
+        Out << " kround";
     }
   }
 
diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp
index 57c143c..43fa285 100644
--- a/lib/IR/Instruction.cpp
+++ b/lib/IR/Instruction.cpp
@@ -124,6 +124,22 @@ void Instruction::setHasAllowReciprocal(bool B) {
   cast<FPMathOperator>(this)->setHasAllowReciprocal(B);
 }
 
+/// Set or clear the keep-exceptions flag on this instruction, which must be an
+/// operator which supports this flag. See LangRef.html for the meaning of this
+/// flag.
+void Instruction::setHasKeepExceptions(bool B) {
+  assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
+  cast<FPMathOperator>(this)->setHasKeepExceptions(B);
+}
+
+/// Set or clear the keep-rounding flag on this instruction, which must be an
+/// operator which supports this flag. See LangRef.html for the meaning of this
+/// flag.
+void Instruction::setHasKeepRounding(bool B) {
+  assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
+  cast<FPMathOperator>(this)->setHasKeepRounding(B);
+}
+
 /// Convenience function for setting all the fast-math flags on this
 /// instruction, which must be an operator which supports these flags. See
 /// LangRef.html for the meaning of these flats.
@@ -167,6 +183,18 @@ bool Instruction::hasAllowReciprocal() const {
   return cast<FPMathOperator>(this)->hasAllowReciprocal();
 }
 
+/// Determine whether the keep-exceptions flag is set.
+bool Instruction::hasKeepExceptions() const {
+  assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
+  return cast<FPMathOperator>(this)->hasKeepExceptions();
+}
+
+/// Determine whether the keep-rounding flag is set.
+bool Instruction::hasKeepRounding() const {
+  assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
+  return cast<FPMathOperator>(this)->hasKeepRounding();
+}
+
 /// Convenience function for getting all the fast-math flags, which must be an
 /// operator which supports these flags. See LangRef.html for the meaning of
 /// these flags.
diff --git a/test/Assembler/fast-math-flags.ll b/test/Assembler/fast-math-flags.ll
index f0d3ecc..4958c40 100644
--- a/test/Assembler/fast-math-flags.ll
+++ b/test/Assembler/fast-math-flags.ll
@@ -138,6 +138,14 @@ entry:
   %e = frem nnan nsz float %x, %y
 ; CHECK:  %e_vec = frem nnan <3 x float> %vec, %vec
   %e_vec = frem nnan <3 x float> %vec, %vec
+; CHECK:  %f = fmul fast float %x, %y
+  %f = fmul kexc kround fast float %x, %y
+; CHECK:  %f_vec = frem fast <3 x float> %vec, %vec
+  %f_vec = frem kexc kround fast <3 x float> %vec, %vec
+; CHECK:  %g = fmul kexc kround float %x, %y
+  %g = fmul kexc kround float %x, %y
+; CHECK:  %g_vec = frem kexc kround <3 x float> %vec, %vec
+  %g_vec = frem kexc kround <3 x float> %vec, %vec
 ; CHECK:  ret  float %e
   ret  float %e
 }
-- 
2.3.5

-------------- next part --------------
>From 1092a226e9722b40b6868c997c2c13c3b32dd5ae Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 13 Nov 2014 20:40:40 +0200
Subject: [PATCH 03/13] Consider FPEnv access in SelectionDAG

* Disable optimizations that erase floating-point exceptions at runtime
  if application is allowed to access exception mask.

* Disable optimizations if application is allowed to access rounding and
  result was rounded.
---
 include/llvm/CodeGen/SelectionDAG.h       |   5 ++
 lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  31 +++++--
 test/CodeGen/Generic/selectiondag-fenv.ll | 140 ++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+), 9 deletions(-)
 create mode 100644 test/CodeGen/Generic/selectiondag-fenv.ll

diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h
index 89f9005..2cd8768 100644
--- a/include/llvm/CodeGen/SelectionDAG.h
+++ b/include/llvm/CodeGen/SelectionDAG.h
@@ -1264,6 +1264,11 @@ private:
   SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, DebugLoc DL,
                               void *&InsertPos);
 
+  /// Checks whether it's safe to replace a floating-point operation with its
+  /// result.  UnsafeOps is bit mask of unacceptable exceptions.
+  bool isSafeToOptimizeFPOp(APFloat::opStatus s,
+                            APFloat::opStatus UnsafeOps) const;
+
   /// List of non-single value types.
   FoldingSet<SDVTListNode> VTListMap;
 
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index efd4bd9..95372ea 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3577,7 +3577,6 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
   }
 
   // Constant fold FP operations.
-  bool HasFPExceptions = TLI->hasFloatingPointExceptions();
   ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1.getNode());
   ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.getNode());
   if (N1CFP) {
@@ -3591,30 +3590,32 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
       switch (Opcode) {
       case ISD::FADD:
         s = V1.add(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || s != APFloat::opInvalidOp)
+        if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
           return getConstantFP(V1, DL, VT);
         break;
       case ISD::FSUB:
         s = V1.subtract(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+        if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
           return getConstantFP(V1, DL, VT);
         break;
       case ISD::FMUL:
         s = V1.multiply(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+        if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
           return getConstantFP(V1, DL, VT);
         break;
       case ISD::FDIV:
         s = V1.divide(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || (s!=APFloat::opInvalidOp &&
-                                 s!=APFloat::opDivByZero)) {
+        if (isSafeToOptimizeFPOp(s,
+                                 (APFloat::opStatus)(APFloat::opInvalidOp |
+                                                     APFloat::opDivByZero))) {
           return getConstantFP(V1, DL, VT);
         }
         break;
-      case ISD::FREM :
+      case ISD::FREM:
         s = V1.mod(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || (s!=APFloat::opInvalidOp &&
-                                 s!=APFloat::opDivByZero)) {
+        if (isSafeToOptimizeFPOp(s,
+                                 (APFloat::opStatus)(APFloat::opInvalidOp |
+                                                     APFloat::opDivByZero))) {
           return getConstantFP(V1, DL, VT);
         }
         break;
@@ -3736,6 +3737,18 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
   return SDValue(N, 0);
 }
 
+bool SelectionDAG::isSafeToOptimizeFPOp(APFloat::opStatus s,
+                                        APFloat::opStatus UnsafeOps) const {
+  if (getTarget().Options.AllowFPRoundAccess && (s & APFloat::opInexact))
+    return false;
+
+  if (!TLI->hasFloatingPointExceptions())
+    return true;
+  if (getTarget().Options.AllowFPExceptAccess)
+    return s == APFloat::opOK;
+  return (s & UnsafeOps) == APFloat::opOK;
+}
+
 SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT,
                               SDValue N1, SDValue N2, SDValue N3) {
   // Perform various simplifications.
diff --git a/test/CodeGen/Generic/selectiondag-fenv.ll b/test/CodeGen/Generic/selectiondag-fenv.ll
new file mode 100644
index 0000000..ed2e3f6
--- /dev/null
+++ b/test/CodeGen/Generic/selectiondag-fenv.ll
@@ -0,0 +1,140 @@
+; RUN: llc < %s -print-machineinstrs=expand-isel-pseudos -o /dev/null -enable-except-access-fp-math 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=EXCEPT
+; RUN: llc < %s -print-machineinstrs=expand-isel-pseudos -o /dev/null -enable-round-access-fp-math 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=ROUND
+
+; SelectionDAG should not fold floating-point operations that have constant
+; expression as their operands when FEnv access is enabled and such folding
+; leads to differences in observable effects at runtime.
+
+define double @do-not-fold-fadd-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fadd-that-can-trap:
+; CHECK: cp#0: 1.000000e+308
+entry:
+  %val = fadd double 1.000000e+308, 1.000000e+308
+  ret double %val
+}
+
+define double @do-not-fold-fsub-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fsub-that-can-trap:
+; CHECK: cp#0: 1.000000e-308
+; CHECK: cp#1: 1.000000e+308
+entry:
+  %val = fsub double 1.000000e-308, 1.000000e+308
+  ret double %val
+}
+
+define double @do-not-fold-fmul-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fmul-that-can-trap:
+; CHECK: cp#0: 1.000000e+300
+entry:
+  %val = fmul double 1.000000e+300, 1.000000e+300
+  ret double %val
+}
+
+define double @do-not-fold-fdiv-that-can-trap() {
+; CHECK-LABEL: do-not-fold-fdiv-that-can-trap:
+; CHECK: cp#0: 1.000000e+300
+; CHECK: cp#1: 1.000000e-300
+entry:
+  %val = fdiv double 1.000000e+300, 1.000000e-300
+  ret double %val
+}
+
+define double @do-not-fold-frem-that-can-trap() {
+; CHECK-LABEL: do-not-fold-frem-that-can-trap:
+; CHECK: cp#0: 1.0
+entry:
+  %val = frem double 1.0, 0.0
+  ret double %val
+}
+
+define double @do-not-fold-fadd-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fadd-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+  %val = fadd double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fsub-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fsub-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+  %val = fsub double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fmul-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fmul-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+  %val = fmul double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fdiv-because-of-rounding() {
+; CHECK-LABEL: do-not-fold-fdiv-because-of-rounding:
+; EXCEPT: cp#0: 1.010000e-01
+; EXCEPT: cp#1: 9.300000e-01
+; ROUND: cp#0: 1.010000e-01
+; ROUND: cp#1: 9.300000e-01
+entry:
+  %val = fdiv double 0.101, 0.93
+  ret double %val
+}
+
+; "frem" instruction falls into the same category, but none of tried test-cases
+; could raised inexact exception.
+
+define double @fold-fadd-without-rounding() {
+; CHECK-LABEL: fold-fadd-without-rounding:
+; EXCEPT: cp#0: 2.0
+; ROUND: cp#0: 2.0
+entry:
+  %val = fadd double 1.0, 1.0
+  ret double %val
+}
+
+define double @fold-fsub-without-rounding() {
+; CHECK-LABEL: fold-fsub-without-rounding:
+; EXCEPT: cp#0: 1.0
+; ROUND: cp#0: 1.0
+entry:
+  %val = fsub double 3.0, 2.0
+  ret double %val
+}
+
+define double @fold-fmul-without-rounding() {
+; CHECK-LABEL: fold-fmul-without-rounding:
+; EXCEPT: cp#0: 6.0
+; ROUND: cp#0: 6.0
+entry:
+  %val = fmul double 2.0, 3.0
+  ret double %val
+}
+
+define double @fold-fdiv-without-rounding() {
+; CHECK-LABEL: fold-fdiv-without-rounding:
+; EXCEPT: cp#0: 2.0
+; ROUND: cp#0: 2.0
+entry:
+  %val = fdiv double 6.0, 3.0
+  ret double %val
+}
+
+define double @fold-frem-without-rounding() {
+; CHECK-LABEL: fold-frem-without-rounding:
+; EXCEPT: cp#0: 1.0
+; ROUND: cp#0: 1.0
+entry:
+  %val = frem double 7.0, 3.0
+  ret double %val
+}
-- 
2.3.5

-------------- next part --------------
>From abb5d94ede37b81dd856cb6466324a5d03bd6d9d Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 17 Nov 2014 23:10:29 +0200
Subject: [PATCH 04/13] Skip constant folding to preserve FPEnv

Consider floating point environment flags when constant folding
expressions.
---
 include/llvm/Analysis/ValueTracking.h |  9 +++--
 include/llvm/IR/Constants.h           |  8 ++++-
 lib/Analysis/ValueTracking.cpp        | 25 +++++++++++++-
 lib/IR/ConstantFold.cpp               | 51 +++++++++++++++++++--------
 lib/IR/ConstantFold.h                 |  3 +-
 lib/IR/Constants.cpp                  | 65 +++++++++++++++++++++++++++++++++--
 6 files changed, 138 insertions(+), 23 deletions(-)

diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h
index 653821d..c395f43 100644
--- a/include/llvm/Analysis/ValueTracking.h
+++ b/include/llvm/Analysis/ValueTracking.h
@@ -229,8 +229,9 @@ namespace llvm {
                                 const TargetLibraryInfo *TLI = nullptr);
   
   /// isSafeToSpeculativelyExecute - Return true if the instruction does not
-  /// have any effects besides calculating the result and does not have
-  /// undefined behavior.
+  /// have any effects besides calculating the result (in a way that doesn't
+  /// lose floating-point exceptions or precision when requested via
+  /// corresponding flags) and does not have undefined behavior.
   ///
   /// This method never returns true for an instruction that returns true for
   /// mayHaveSideEffects; however, this method also does some other checks in
@@ -255,7 +256,9 @@ namespace llvm {
   bool isSafeToSpeculativelyExecute(const Value *V,
                                     const Instruction *CtxI = nullptr,
                                     const DominatorTree *DT = nullptr,
-                                    const TargetLibraryInfo *TLI = nullptr);
+                                    const TargetLibraryInfo *TLI = nullptr,
+                                    bool KeepExceptions = false,
+                                    bool KeepRounding = false);
 
   /// isKnownNonNull - Return true if this pointer couldn't possibly be null by
   /// its definition.  This returns true for allocas, non-extern-weak globals
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index e97bda5..352701f 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1038,7 +1038,9 @@ public:
   ///
   /// \param OnlyIfReducedTy see \a getWithOperands() docs.
   static Constant *get(unsigned Opcode, Constant *C1, Constant *C2,
-                       unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr);
+                       unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false);
 
   /// \brief Return an ICmp or FCmp comparison operator constant expression.
   ///
@@ -1164,6 +1166,10 @@ public:
     return V->getValueID() == ConstantExprVal;
   }
 
+  /// Evaluates floating point operation to examine it, does nothing for non-FP
+  /// operations.  Returns false for unsupported values.
+  static bool getFPOpExceptions(const Value *V, APFloat::opStatus &S);
+
 private:
   // Shadow Value::setValueSubclassData with a private forwarding method so that
   // subclasses cannot accidentally use it.
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index a55712c..0fa0b42 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -3044,11 +3044,18 @@ bool llvm::isDereferenceablePointer(const Value *V, const DataLayout &DL,
 bool llvm::isSafeToSpeculativelyExecute(const Value *V,
                                         const Instruction *CtxI,
                                         const DominatorTree *DT,
-                                        const TargetLibraryInfo *TLI) {
+                                        const TargetLibraryInfo *TLI,
+                                        bool KeepExceptions,
+                                        bool KeepRounding) {
   const Operator *Inst = dyn_cast<Operator>(V);
   if (!Inst)
     return false;
 
+  if (const FPMathOperator *MathOp = dyn_cast<FPMathOperator>(Inst)) {
+      KeepExceptions |= MathOp->hasKeepExceptions();
+      KeepRounding |= MathOp->hasKeepRounding();
+  }
+
   for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
     if (Constant *C = dyn_cast<Constant>(Inst->getOperand(i)))
       if (C->canTrap())
@@ -3057,6 +3064,22 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
   switch (Inst->getOpcode()) {
   default:
     return true;
+  case Instruction::FMul:
+  case Instruction::FAdd:
+  case Instruction::FSub:
+  case Instruction::FDiv:
+  case Instruction::FRem:
+    if (KeepExceptions || KeepRounding) {
+      APFloat::opStatus S;
+      if (!ConstantExpr::getFPOpExceptions(Inst, S))
+        return false;
+
+      if (KeepExceptions && S != APFloat::opOK)
+        return false;
+      if (KeepRounding && (S & APFloat::opInexact))
+        return false;
+    }
+    return true;
   case Instruction::UDiv:
   case Instruction::URem: {
     // x / y is undefined if y == 0.
diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp
index 3f64c43..495b894 100644
--- a/lib/IR/ConstantFold.cpp
+++ b/lib/IR/ConstantFold.cpp
@@ -915,7 +915,9 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg,
 
 
 Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
-                                              Constant *C1, Constant *C2) {
+                                              Constant *C1, Constant *C2,
+                                              bool KeepExceptions,
+                                              bool KeepRounding) {
   // Handle UndefValue up front.
   if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) {
     switch (Opcode) {
@@ -1099,7 +1101,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
   } else if (isa<ConstantInt>(C1)) {
     // If C1 is a ConstantInt and C2 is not, swap the operands.
     if (Instruction::isCommutative(Opcode))
-      return ConstantExpr::get(Opcode, C2, C1);
+      return ConstantExpr::get(Opcode, C2, C1, 0, nullptr, KeepExceptions,
+                               KeepRounding);
   }
 
   // At this point we know neither constant is an UndefValue.
@@ -1171,23 +1174,39 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
       APFloat C1V = CFP1->getValueAPF();
       APFloat C2V = CFP2->getValueAPF();
       APFloat C3V = C1V;  // copy for modification
+      APFloat::opStatus S;
       switch (Opcode) {
-      default:                   
+      default:
         break;
       case Instruction::FAdd:
-        (void)C3V.add(C2V, APFloat::rmNearestTiesToEven);
+        S = C3V.add(C2V, APFloat::rmNearestTiesToEven);
+        if ((KeepExceptions && S != APFloat::opOK) ||
+            (KeepRounding && (S & APFloat::opInexact)))
+          break;
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FSub:
-        (void)C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+        S = C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+        if ((KeepExceptions && S != APFloat::opOK) ||
+            (KeepRounding && (S & APFloat::opInexact)))
+          break;
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FMul:
-        (void)C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+        S = C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+        if ((KeepExceptions && S != APFloat::opOK) ||
+            (KeepRounding && (S & APFloat::opInexact)))
+          break;
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FDiv:
-        (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+        S = C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+        if ((KeepExceptions && S != APFloat::opOK) ||
+            (KeepRounding && (S & APFloat::opInexact)))
+          break;
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FRem:
-        (void)C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+        S = C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+        if ((KeepExceptions && S != APFloat::opOK) ||
+            (KeepRounding && (S & APFloat::opInexact)))
+          break;
         return ConstantFP::get(C1->getContext(), C3V);
       }
     }
@@ -1200,10 +1219,11 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
         ConstantExpr::getExtractElement(C1, ConstantInt::get(Ty, i));
       Constant *RHS =
         ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, i));
-      
-      Result.push_back(ConstantExpr::get(Opcode, LHS, RHS));
+
+      Result.push_back(ConstantExpr::get(Opcode, LHS, RHS, 0, nullptr,
+                                         KeepExceptions, KeepRounding));
     }
-    
+
     return ConstantVector::get(Result);
   }
 
@@ -1215,15 +1235,18 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
     // Given ((a + b) + c), if (b + c) folds to something interesting, return
     // (a + (b + c)).
     if (Instruction::isAssociative(Opcode) && CE1->getOpcode() == Opcode) {
-      Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2);
+      Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2, 0,
+                                      nullptr, KeepExceptions, KeepRounding);
       if (!isa<ConstantExpr>(T) || cast<ConstantExpr>(T)->getOpcode() != Opcode)
-        return ConstantExpr::get(Opcode, CE1->getOperand(0), T);
+        return ConstantExpr::get(Opcode, CE1->getOperand(0), T, 0, nullptr,
+                                 KeepExceptions, KeepRounding);
     }
   } else if (isa<ConstantExpr>(C2)) {
     // If C2 is a constant expr and C1 isn't, flop them around and fold the
     // other way if possible.
     if (Instruction::isCommutative(Opcode))
-      return ConstantFoldBinaryInstruction(Opcode, C2, C1);
+      return ConstantFoldBinaryInstruction(Opcode, C2, C1, KeepExceptions,
+                                           KeepRounding);
   }
 
   // i1 can be simplified in many cases.
diff --git a/lib/IR/ConstantFold.h b/lib/IR/ConstantFold.h
index 42a9c6b..8e35aa0 100644
--- a/lib/IR/ConstantFold.h
+++ b/lib/IR/ConstantFold.h
@@ -44,7 +44,8 @@ namespace llvm {
   Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
                                                ArrayRef<unsigned> Idxs);
   Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1,
-                                          Constant *V2);
+                                          Constant *V2, bool KeepFPExceptions,
+                                          bool KeepFPRounding);
   Constant *ConstantFoldCompareInstruction(unsigned short predicate, 
                                            Constant *C1, Constant *C2);
   Constant *ConstantFoldGetElementPtr(Constant *C, bool inBounds,
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index fb83ebb..1003ef3 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -316,8 +316,9 @@ static bool canTrapImpl(const Constant *C,
   // ConstantExpr traps if any operands can trap.
   for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) {
     if (ConstantExpr *Op = dyn_cast<ConstantExpr>(CE->getOperand(i))) {
-      if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps))
+      if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps)) {
         return true;
+      }
     }
   }
 
@@ -1852,7 +1853,8 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
 }
 
 Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
-                            unsigned Flags, Type *OnlyIfReducedTy) {
+                            unsigned Flags, Type *OnlyIfReducedTy,
+                            bool KeepExceptions, bool KeepRounding) {
   // Check the operands for consistency first.
   assert(Opcode >= Instruction::BinaryOpsBegin &&
          Opcode <  Instruction::BinaryOpsEnd   &&
@@ -1918,8 +1920,11 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
   }
 #endif
 
-  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2))
+  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2,
+                                                   KeepExceptions,
+                                                   KeepRounding)) {
     return FC;          // Fold a few common cases.
+  }
 
   if (OnlyIfReducedTy == C1->getType())
     return nullptr;
@@ -3050,3 +3055,57 @@ Instruction *ConstantExpr::getAsInstruction() {
     return BO;
   }
 }
+
+bool ConstantExpr::getFPOpExceptions(const Value *V, APFloat::opStatus &S) {
+  unsigned Opcode;
+  const User *U;
+  if (const Operator *Op = dyn_cast<Operator>(V)) {
+    U = Op;
+    Opcode = Op->getOpcode();
+  } if (const ConstantExpr *C = dyn_cast<ConstantExpr>(V)) {
+    U = C;
+    Opcode = C->getOpcode();
+  } else {
+    return false;
+  }
+
+  switch (Opcode) {
+  default:
+    return true;
+  case Instruction::FMul:
+  case Instruction::FAdd:
+  case Instruction::FSub:
+  case Instruction::FDiv:
+  case Instruction::FRem: {
+    ConstantFP *LHSC = dyn_cast<ConstantFP>(U->getOperand(0));
+    ConstantFP *RHSC = dyn_cast<ConstantFP>(U->getOperand(1));
+
+    if (!LHSC || !RHSC) {
+      return false;
+    }
+
+    APFloat LHS = LHSC->getValueAPF();
+    APFloat RHS = LHSC->getValueAPF();
+
+    switch (Opcode) {
+    case Instruction::FMul:
+      S = LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FAdd:
+      S = LHS.add(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FSub:
+      S = LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FDiv:
+      S = LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FRem:
+      S = LHS.mod(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    }
+
+    return true;
+  }
+  }
+}
-- 
2.3.5

-------------- next part --------------
>From 13bc6d0b5970ca1e14c348070ad5bd9df8d167a2 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Wed, 26 Nov 2014 15:22:55 +0200
Subject: [PATCH 05/13] Teach IR builder and folders about new flags

---
 include/llvm/Analysis/ConstantFolding.h |   8 +-
 include/llvm/Analysis/TargetFolder.h    |  37 ++++++---
 include/llvm/IR/ConstantFolder.h        |  44 +++++++----
 include/llvm/IR/Constants.h             |  24 ++++--
 include/llvm/IR/IRBuilder.h             |  30 +++++---
 lib/Analysis/ConstantFolding.cpp        |  40 +++++++---
 lib/IR/ConstantFold.h                   |   4 +-
 lib/IR/Constants.cpp                    |  36 ++++++---
 test/Other/fpenv-constant-fold.ll       | 130 ++++++++++++++++++++++++++++++++
 9 files changed, 285 insertions(+), 68 deletions(-)
 create mode 100644 test/Other/fpenv-constant-fold.ll

diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h
index 541a210..b97e54f 100644
--- a/include/llvm/Analysis/ConstantFolding.h
+++ b/include/llvm/Analysis/ConstantFolding.h
@@ -44,7 +44,9 @@ namespace llvm {
 /// result is returned, if not, null is returned.
   Constant *
   ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL,
-                                 const TargetLibraryInfo *TLI = nullptr);
+                                 const TargetLibraryInfo *TLI = nullptr,
+                                 bool KeepExceptions = false,
+                                 bool KeepRounding = false);
 
 /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
 /// specified operands.  If successful, the constant result is returned, if not,
@@ -55,7 +57,9 @@ namespace llvm {
   Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
                                      ArrayRef<Constant *> Ops,
                                      const DataLayout &DL,
-                                     const TargetLibraryInfo *TLI = nullptr);
+                                     const TargetLibraryInfo *TLI = nullptr,
+                                     bool KeepExceptions = false,
+                                     bool KeepRounding = false);
 
 /// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
 /// instruction (icmp/fcmp) with the specified operands.  If it fails, it
diff --git a/include/llvm/Analysis/TargetFolder.h b/include/llvm/Analysis/TargetFolder.h
index 12bf9fe..44f7edb 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -51,22 +51,31 @@ public:
                       bool HasNUW = false, bool HasNSW = false) const {
     return Fold(ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW));
   }
-  Constant *CreateFAdd(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFAdd(LHS, RHS));
+  Constant *CreateFAdd(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding));
   }
   Constant *CreateSub(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
     return Fold(ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW));
   }
-  Constant *CreateFSub(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFSub(LHS, RHS));
+  Constant *CreateFSub(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding));
   }
   Constant *CreateMul(Constant *LHS, Constant *RHS,
-                      bool HasNUW = false, bool HasNSW = false) const {
-    return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW));
+                      bool HasNUW = false, bool HasNSW = false,
+                      bool KeepExceptions = false,
+                      bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW,
+                                     KeepExceptions, KeepRounding));
   }
-  Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFMul(LHS, RHS));
+  Constant *CreateFMul(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding));
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
     return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
@@ -74,8 +83,10 @@ public:
   Constant *CreateSDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
     return Fold(ConstantExpr::getSDiv(LHS, RHS, isExact));
   }
-  Constant *CreateFDiv(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFDiv(LHS, RHS));
+  Constant *CreateFDiv(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding));
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return Fold(ConstantExpr::getURem(LHS, RHS));
@@ -83,8 +94,10 @@ public:
   Constant *CreateSRem(Constant *LHS, Constant *RHS) const {
     return Fold(ConstantExpr::getSRem(LHS, RHS));
   }
-  Constant *CreateFRem(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFRem(LHS, RHS));
+  Constant *CreateFRem(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding));
   }
   Constant *CreateShl(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index fb6ca3b..d7f8e01 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -35,22 +35,31 @@ public:
                       bool HasNUW = false, bool HasNSW = false) const {
     return ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW);
   }
-  Constant *CreateFAdd(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFAdd(LHS, RHS);
+  Constant *CreateFAdd(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding);
   }
   Constant *CreateSub(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
     return ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW);
   }
-  Constant *CreateFSub(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFSub(LHS, RHS);
+  Constant *CreateFSub(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding);
   }
   Constant *CreateMul(Constant *LHS, Constant *RHS,
-                      bool HasNUW = false, bool HasNSW = false) const {
-    return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW);
+                      bool HasNUW = false, bool HasNSW = false,
+                      bool KeepExceptions = false,
+                      bool KeepRounding = false) const {
+    return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW, KeepExceptions,
+                                KeepRounding);
   }
-  Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFMul(LHS, RHS);
+  Constant *CreateFMul(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding);
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS,
                        bool isExact = false) const {
@@ -60,8 +69,10 @@ public:
                        bool isExact = false) const {
     return ConstantExpr::getSDiv(LHS, RHS, isExact);
   }
-  Constant *CreateFDiv(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFDiv(LHS, RHS);
+  Constant *CreateFDiv(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding);
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return ConstantExpr::getURem(LHS, RHS);
@@ -69,8 +80,10 @@ public:
   Constant *CreateSRem(Constant *LHS, Constant *RHS) const {
     return ConstantExpr::getSRem(LHS, RHS);
   }
-  Constant *CreateFRem(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFRem(LHS, RHS);
+  Constant *CreateFRem(Constant *LHS, Constant *RHS,
+                       bool KeepExceptions = false,
+                       bool KeepRounding = false) const {
+    return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding);
   }
   Constant *CreateShl(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
@@ -95,8 +108,11 @@ public:
   }
 
   Constant *CreateBinOp(Instruction::BinaryOps Opc,
-                        Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::get(Opc, LHS, RHS);
+                        Constant *LHS, Constant *RHS,
+                        bool KeepExceptions = false,
+                        bool KeepRounding = false) const {
+    return ConstantExpr::get(Opc, LHS, RHS, 0, nullptr, KeepExceptions,
+                             KeepRounding);
   }
 
   //===--------------------------------------------------------------------===//
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index 352701f..f97a23d 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -863,19 +863,31 @@ public:
   static Constant *getNot(Constant *C);
   static Constant *getAdd(Constant *C1, Constant *C2,
                           bool HasNUW = false, bool HasNSW = false);
-  static Constant *getFAdd(Constant *C1, Constant *C2);
+  static Constant *getFAdd(Constant *C1, Constant *C2,
+                           bool KeepExceptions = false,
+                           bool KeepRounding = false);
   static Constant *getSub(Constant *C1, Constant *C2,
                           bool HasNUW = false, bool HasNSW = false);
-  static Constant *getFSub(Constant *C1, Constant *C2);
+  static Constant *getFSub(Constant *C1, Constant *C2,
+                           bool KeepExceptions = false,
+                           bool KeepRounding = false);
   static Constant *getMul(Constant *C1, Constant *C2,
-                          bool HasNUW = false, bool HasNSW = false);
-  static Constant *getFMul(Constant *C1, Constant *C2);
+                          bool HasNUW = false, bool HasNSW = false,
+                          bool KeepExceptions = false,
+                          bool KeepRounding = false);
+  static Constant *getFMul(Constant *C1, Constant *C2,
+                           bool KeepExceptions = false,
+                           bool KeepRounding = false);
   static Constant *getUDiv(Constant *C1, Constant *C2, bool isExact = false);
   static Constant *getSDiv(Constant *C1, Constant *C2, bool isExact = false);
-  static Constant *getFDiv(Constant *C1, Constant *C2);
+  static Constant *getFDiv(Constant *C1, Constant *C2,
+                           bool KeepExceptions = false,
+                           bool KeepRounding = false);
   static Constant *getURem(Constant *C1, Constant *C2);
   static Constant *getSRem(Constant *C1, Constant *C2);
-  static Constant *getFRem(Constant *C1, Constant *C2);
+  static Constant *getFRem(Constant *C1, Constant *C2,
+                           bool KeepExceptions = false,
+                           bool KeepRounding = false);
   static Constant *getAnd(Constant *C1, Constant *C2);
   static Constant *getOr(Constant *C1, Constant *C2);
   static Constant *getXor(Constant *C1, Constant *C2);
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index adf6924..43089d4 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -733,10 +733,12 @@ public:
     return CreateAdd(LHS, RHS, Name, true, false);
   }
   Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFAdd(LC, RC), Name);
+        return Insert(Folder.CreateFAdd(LC, RC, KeepExceptions, KeepRounding),
+                      Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -755,10 +757,12 @@ public:
     return CreateSub(LHS, RHS, Name, true, false);
   }
   Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFSub(LC, RC), Name);
+        return Insert(Folder.CreateFSub(LC, RC, KeepExceptions, KeepRounding),
+                      Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -777,10 +781,12 @@ public:
     return CreateMul(LHS, RHS, Name, true, false);
   }
   Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFMul(LC, RC), Name);
+        return Insert(Folder.CreateFMul(LC, RC, KeepExceptions, KeepRounding),
+                      Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -809,10 +815,12 @@ public:
     return CreateSDiv(LHS, RHS, Name, true);
   }
   Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFDiv(LC, RC), Name);
+        return Insert(Folder.CreateFDiv(LC, RC, KeepExceptions, KeepRounding),
+                      Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -829,10 +837,12 @@ public:
     return Insert(BinaryOperator::CreateSRem(LHS, RHS), Name);
   }
   Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFRem(LC, RC), Name);
+        return Insert(Folder.CreateFRem(LC, RC, KeepExceptions, KeepRounding),
+                      Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp
index 2f4c6a9..197cffd 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -891,6 +891,14 @@ static Constant *SymbolicallyEvaluateGEP(Type *SrcTy, ArrayRef<Constant *> Ops,
 /// and stores, which have no constant expression form.
 Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
                                         const TargetLibraryInfo *TLI) {
+  bool KeepExceptions = false;
+  bool KeepRounding = false;
+
+  if (isa<FPMathOperator>(I)) {
+    KeepExceptions = I->hasKeepExceptions();
+    KeepRounding = I->hasKeepRounding();
+  }
+
   // Handle PHI nodes quickly here...
   if (PHINode *PN = dyn_cast<PHINode>(I)) {
     Constant *CommonValue = nullptr;
@@ -908,7 +916,8 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
         return nullptr;
       // Fold the PHI's operands.
       if (ConstantExpr *NewC = dyn_cast<ConstantExpr>(C))
-        C = ConstantFoldConstantExpression(NewC, DL, TLI);
+        C = ConstantFoldConstantExpression(NewC, DL, TLI,
+                                           KeepExceptions, KeepRounding);
       // If the incoming value is a different constant to
       // the one we saw previously, then give up.
       if (CommonValue && C != CommonValue)
@@ -931,7 +940,8 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
 
     // Fold the Instruction's operands.
     if (ConstantExpr *NewCE = dyn_cast<ConstantExpr>(Op))
-      Op = ConstantFoldConstantExpression(NewCE, DL, TLI);
+      Op = ConstantFoldConstantExpression(NewCE, DL, TLI,
+                                          KeepExceptions, KeepRounding);
 
     Ops.push_back(Op);
   }
@@ -956,13 +966,15 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
                                     EVI->getIndices());
   }
 
-  return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI);
+  return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI,
+                                  KeepExceptions, KeepRounding);
 }
 
 static Constant *
 ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
                                    const TargetLibraryInfo *TLI,
-                                   SmallPtrSetImpl<ConstantExpr *> &FoldedOps) {
+                                   SmallPtrSetImpl<ConstantExpr *> &FoldedOps,
+                                   bool KeepExceptions, bool KeepRounding) {
   SmallVector<Constant *, 8> Ops;
   for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); i != e;
        ++i) {
@@ -971,7 +983,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
     // a ConstantExpr, we don't have to process it again.
     if (ConstantExpr *NewCE = dyn_cast<ConstantExpr>(NewC)) {
       if (FoldedOps.insert(NewCE).second)
-        NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps);
+        NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps,
+                                                  KeepExceptions, KeepRounding);
     }
     Ops.push_back(NewC);
   }
@@ -979,7 +992,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
   if (CE->isCompare())
     return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1],
                                            DL, TLI);
-  return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI);
+  return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI,
+                                  KeepExceptions, KeepRounding);
 }
 
 /// Attempt to fold the constant expression
@@ -987,9 +1001,12 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL,
 /// result is returned, if not, null is returned.
 Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
                                                const DataLayout &DL,
-                                               const TargetLibraryInfo *TLI) {
+                                               const TargetLibraryInfo *TLI,
+                                               bool KeepExceptions,
+                                               bool KeepRounding) {
   SmallPtrSet<ConstantExpr *, 4> FoldedOps;
-  return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps);
+  return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps,
+                                            KeepExceptions, KeepRounding);
 }
 
 /// Attempt to constant fold an instruction with the
@@ -1005,7 +1022,9 @@ Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
 Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
                                          ArrayRef<Constant *> Ops,
                                          const DataLayout &DL,
-                                         const TargetLibraryInfo *TLI) {
+                                         const TargetLibraryInfo *TLI,
+                                         bool KeepExceptions,
+                                         bool KeepRounding) {
   // Handle easy binops first.
   if (Instruction::isBinaryOp(Opcode)) {
     if (isa<ConstantExpr>(Ops[0]) || isa<ConstantExpr>(Ops[1])) {
@@ -1013,7 +1032,8 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
         return C;
     }
 
-    return ConstantExpr::get(Opcode, Ops[0], Ops[1]);
+    return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr,
+                             KeepExceptions, KeepRounding);
   }
 
   switch (Opcode) {
diff --git a/lib/IR/ConstantFold.h b/lib/IR/ConstantFold.h
index 8e35aa0..f635ce1 100644
--- a/lib/IR/ConstantFold.h
+++ b/lib/IR/ConstantFold.h
@@ -44,8 +44,8 @@ namespace llvm {
   Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
                                                ArrayRef<unsigned> Idxs);
   Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1,
-                                          Constant *V2, bool KeepFPExceptions,
-                                          bool KeepFPRounding);
+                                          Constant *V2, bool KeepExceptions,
+                                          bool KeepRounding);
   Constant *ConstantFoldCompareInstruction(unsigned short predicate, 
                                            Constant *C1, Constant *C2);
   Constant *ConstantFoldGetElementPtr(Constant *C, bool inBounds,
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 1003ef3..3d18cfd 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -2253,8 +2253,10 @@ Constant *ConstantExpr::getAdd(Constant *C1, Constant *C2,
   return get(Instruction::Add, C1, C2, Flags);
 }
 
-Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2) {
-  return get(Instruction::FAdd, C1, C2);
+Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2,
+                                bool KeepExceptions, bool KeepRounding) {
+  return get(Instruction::FAdd, C1, C2, 0, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
 Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
@@ -2264,19 +2266,25 @@ Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
   return get(Instruction::Sub, C1, C2, Flags);
 }
 
-Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2) {
-  return get(Instruction::FSub, C1, C2);
+Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2,
+                                bool KeepExceptions, bool KeepRounding) {
+  return get(Instruction::FSub, C1, C2, 0, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
 Constant *ConstantExpr::getMul(Constant *C1, Constant *C2,
-                               bool HasNUW, bool HasNSW) {
+                               bool HasNUW, bool HasNSW,
+                               bool KeepExceptions, bool KeepRounding) {
   unsigned Flags = (HasNUW ? OverflowingBinaryOperator::NoUnsignedWrap : 0) |
                    (HasNSW ? OverflowingBinaryOperator::NoSignedWrap   : 0);
-  return get(Instruction::Mul, C1, C2, Flags);
+  return get(Instruction::Mul, C1, C2, Flags, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
-Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2) {
-  return get(Instruction::FMul, C1, C2);
+Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2,
+                                bool KeepExceptions, bool KeepRounding) {
+  return get(Instruction::FMul, C1, C2, 0, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
 Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) {
@@ -2289,8 +2297,10 @@ Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2, bool isExact) {
              isExact ? PossiblyExactOperator::IsExact : 0);
 }
 
-Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2) {
-  return get(Instruction::FDiv, C1, C2);
+Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2,
+                                bool KeepExceptions, bool KeepRounding) {
+  return get(Instruction::FDiv, C1, C2, 0, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
 Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
@@ -2301,8 +2311,10 @@ Constant *ConstantExpr::getSRem(Constant *C1, Constant *C2) {
   return get(Instruction::SRem, C1, C2);
 }
 
-Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2) {
-  return get(Instruction::FRem, C1, C2);
+Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2,
+                                bool KeepExceptions, bool KeepRounding) {
+  return get(Instruction::FRem, C1, C2, 0, nullptr, KeepExceptions,
+             KeepRounding);
 }
 
 Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) {
diff --git a/test/Other/fpenv-constant-fold.ll b/test/Other/fpenv-constant-fold.ll
new file mode 100644
index 0000000..01dbfa0
--- /dev/null
+++ b/test/Other/fpenv-constant-fold.ll
@@ -0,0 +1,130 @@
+; InstCombine is used just for its calls to constant folder.
+; RUN: opt -S -instcombine -o - < %s | FileCheck %s
+
+; Target independent constant folder should not fold floating-point operations
+; that have constant expression as their operands when FEnv access is requested
+; and such folding leads to differences in observable effects at runtime.
+
+define double @do-not-fold-fadd-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fadd-that-can-trap
+; CHECK: fadd
+entry:
+  %val = fadd kexc double 1.000000e+308, 1.000000e+308
+  ret double %val
+}
+
+define double @do-not-fold-fsub-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fsub-that-can-trap
+; CHECK: fsub
+entry:
+  %val = fsub kexc double 1.000000e-308, 1.000000e+308
+  ret double %val
+}
+
+define double @do-not-fold-fmul-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fmul-that-can-trap
+; CHECK: fmul
+entry:
+  %val = fmul kexc double 1.000000e+300, 1.000000e+300
+  ret double %val
+}
+
+define double @do-not-fold-fdiv-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-fdiv-that-can-trap
+; CHECK: fdiv
+entry:
+  %val = fdiv kexc double 1.000000e+300, 1.000000e-300
+  ret double %val
+}
+
+define double @do-not-fold-frem-that-can-trap() {
+; CHECK-LABEL: @do-not-fold-frem-that-can-trap
+; CHECK: frem
+entry:
+  %val = frem kexc double 1.000000e+300, 1.000000e-300
+  ret double %val
+}
+
+define double @do-not-fold-fadd-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fadd-because-of-rounding
+; CHECK: fadd
+entry:
+  %val = fadd kround double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fsub-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding
+; CHECK: fsub
+entry:
+  %val = fsub kround double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fmul-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fmul-because-of-rounding
+; CHECK: fmul
+entry:
+  %val = fmul kround double 0.101, 0.93
+  ret double %val
+}
+
+define double @do-not-fold-fdiv-because-of-rounding() {
+; CHECK-LABEL: @do-not-fold-fdiv-because-of-rounding
+; CHECK: fdiv
+entry:
+  %val = fdiv kround double 0.101, 0.93
+  ret double %val
+}
+
+; "frem" instruction falls into the same category, but none of tried test-cases
+; could raised inexact exception.
+
+define double @fold-fadd-that-cant-trap() {
+; CHECK-LABEL: @fold-fadd-that-cant-trap
+; CHECK-NOT: fadd
+entry:
+  %val = fadd kexc kround double 1.0, 1.0
+  ret double %val
+}
+
+define double @fold-fsub-that-cant-trap() {
+; CHECK-LABEL: @fold-fsub-that-cant-trap
+; CHECK-NOT: fsub
+entry:
+  %val = fsub kexc kround double 1.0, 1.0
+  ret double %val
+}
+
+define double @fold-fmul-that-cant-trap() {
+; CHECK-LABEL: @fold-fmul-that-cant-trap
+; CHECK-NOT: fmul
+entry:
+  %val = fmul kexc kround double 1.0, 1.0
+  ret double %val
+}
+
+define double @fold-fdiv-that-cant-trap() {
+; CHECK-LABEL: @fold-fdiv-that-cant-trap
+; CHECK-NOT: fdiv
+entry:
+  %val = fdiv kexc kround double 1.0, 1.0
+  ret double %val
+}
+
+define double @fold-frem-that-cant-trap() {
+; CHECK-LABEL: @fold-frem-that-cant-trap
+; CHECK-NOT: frem
+entry:
+  %val = frem kexc kround double 1.0, 1.0
+  ret double %val
+}
+
+define double @correcly-handle-nested-expressions() {
+; CHECK-LABEL: @correcly-handle-nested-expressions
+; CHECK: fmul
+entry:
+  %val1 = fmul kexc double 1.000000e+300, 1.000000e+300
+  %val2 = fdiv kexc double %val1, 1.000000e+300
+  ret double %val2
+}
-- 
2.3.5

-------------- next part --------------
>From e489145cf4dfc40f761cdc466cd801b6fe7879cd Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Wed, 26 Nov 2014 19:50:50 +0200
Subject: [PATCH 06/13] Do not fold constants on reading in IR asm/bitcode

---
 lib/AsmParser/LLParser.cpp              |  3 ++-
 lib/Bitcode/Reader/BitcodeReader.cpp    |  2 +-
 test/Assembler/do-not-fold-fp-consts.ll | 36 +++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+), 2 deletions(-)
 create mode 100644 test/Assembler/do-not-fold-fp-consts.ll

diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index d3c8ffd..de1a1bc 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -2783,7 +2783,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) {
     if (NUW)   Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
     if (NSW)   Flags |= OverflowingBinaryOperator::NoSignedWrap;
     if (Exact) Flags |= PossiblyExactOperator::IsExact;
-    Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags);
+    Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags, nullptr, true,
+                                    true);
     ID.ConstantVal = C;
     ID.Kind = ValID::t_Constant;
     return false;
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp
index ec404c5..77c01c3 100644
--- a/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2316,7 +2316,7 @@ std::error_code BitcodeReader::ParseConstants() {
               Flags |= SDivOperator::IsExact;
           }
         }
-        V = ConstantExpr::get(Opc, LHS, RHS, Flags);
+        V = ConstantExpr::get(Opc, LHS, RHS, Flags, nullptr, true, true);
       }
       break;
     }
diff --git a/test/Assembler/do-not-fold-fp-consts.ll b/test/Assembler/do-not-fold-fp-consts.ll
new file mode 100644
index 0000000..6b2ddcb
--- /dev/null
+++ b/test/Assembler/do-not-fold-fp-consts.ll
@@ -0,0 +1,36 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+define double @do-not-fold-fadd() {
+; CHECK-LABEL: @do-not-fold-fadd
+; CHECK: fadd
+entry:
+  ret double fadd (double 1.000000e+308, double 1.000000e+308)
+}
+
+define double @do-not-fold-fsub() {
+; CHECK-LABEL: @do-not-fold-fsub
+; CHECK: fsub
+entry:
+  ret double fsub (double 1.000000e-308, double 1.000000e+308)
+}
+
+define double @do-not-fold-fmul() {
+; CHECK-LABEL: @do-not-fold-fmul
+; CHECK: fmul
+entry:
+  ret double fmul (double 1.000000e+300, double 1.000000e+300)
+}
+
+define double @do-not-fold-fdiv() {
+; CHECK-LABEL: @do-not-fold-fdiv
+; CHECK: fdiv
+entry:
+  ret double fdiv (double 1.000000e+300, double 1.000000e-300)
+}
+
+define double @do-not-fold-frem() {
+; CHECK-LABEL: @do-not-fold-frem
+; CHECK: frem
+entry:
+  ret double frem (double 1.000000e+300, double 1.000000e-300)
+}
-- 
2.3.5

-------------- next part --------------
>From db43c926abc925cfbf322817239320654ed245b4 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 28 Nov 2014 12:58:45 +0200
Subject: [PATCH 07/13] Prevent undesired folding by InstSimplify

---
 lib/Analysis/InstructionSimplify.cpp      |  9 ++++--
 test/Transforms/InstSimplify/fast-math.ll | 48 +++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp
index 097b99e..d754caa 100644
--- a/lib/Analysis/InstructionSimplify.cpp
+++ b/lib/Analysis/InstructionSimplify.cpp
@@ -790,7 +790,8 @@ static Value *SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF,
     if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
       Constant *Ops[] = { CLHS, CRHS };
       return ConstantFoldInstOperands(Instruction::FAdd, CLHS->getType(),
-                                      Ops, Q.DL, Q.TLI);
+                                      Ops, Q.DL, Q.TLI,
+                                      FMF.keepExceptions(), FMF.keepRounding());
     }
 
     // Canonicalize the constant to the RHS.
@@ -832,7 +833,8 @@ static Value *SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF,
     if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
       Constant *Ops[] = { CLHS, CRHS };
       return ConstantFoldInstOperands(Instruction::FSub, CLHS->getType(),
-                                      Ops, Q.DL, Q.TLI);
+                                      Ops, Q.DL, Q.TLI,
+                                      FMF.keepExceptions(), FMF.keepRounding());
     }
   }
 
@@ -870,7 +872,8 @@ static Value *SimplifyFMulInst(Value *Op0, Value *Op1,
     if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
       Constant *Ops[] = { CLHS, CRHS };
       return ConstantFoldInstOperands(Instruction::FMul, CLHS->getType(),
-                                      Ops, Q.DL, Q.TLI);
+                                      Ops, Q.DL, Q.TLI,
+                                      FMF.keepExceptions(), FMF.keepRounding());
     }
 
     // Canonicalize the constant to the RHS.
diff --git a/test/Transforms/InstSimplify/fast-math.ll b/test/Transforms/InstSimplify/fast-math.ll
index e7fb14d..e7bbb49 100644
--- a/test/Transforms/InstSimplify/fast-math.ll
+++ b/test/Transforms/InstSimplify/fast-math.ll
@@ -114,3 +114,51 @@ define double @fdiv_zero_by_x(double %X) {
   ret double %r
 ; CHECK: ret double 0
 }
+
+; CHECK-LABEL: @nofold_fadd_kexc(
+define double @nofold_fadd_kexc() {
+; CHECK: fadd
+entry:
+  %val = fadd kexc double 1.000000e+308, 1.000000e+308
+  ret double %val
+}
+
+; CHECK-LABEL: @nofold_fsub_kexc(
+define double @nofold_fsub_kexc() {
+; CHECK: fsub
+entry:
+  %val = fsub kexc double 1.000000e-308, 1.000000e+308
+  ret double %val
+}
+
+; CHECK-LABEL: @nofold_fmul_kexc(
+define double @nofold_fmul_kexc() {
+; CHECK: fmul
+entry:
+  %val = fmul kexc double 1.000000e+300, 1.000000e+300
+  ret double %val
+}
+
+; CHECK-LABEL: @nofold_fadd_kround(
+define double @nofold_fadd_kround() {
+; CHECK: fadd
+entry:
+  %val = fadd kround double 1.000000e+308, 1.000000e+308
+  ret double %val
+}
+
+; CHECK-LABEL: @nofold_fsub_kround(
+define double @nofold_fsub_kround() {
+; CHECK: fsub
+entry:
+  %val = fsub kround double 1.000000e-308, 1.000000e+308
+  ret double %val
+}
+
+; CHECK-LABEL: @nofold_fmul_kround(
+define double @nofold_fmul_kround() {
+; CHECK: fmul
+entry:
+  %val = fmul kround double 1.000000e+300, 1.000000e+300
+  ret double %val
+}
-- 
2.3.5

-------------- next part --------------
>From 59b81b17eeac60e021c70ff5bc66b271c1d467e3 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 28 Nov 2014 15:53:44 +0200
Subject: [PATCH 08/13] Do not simplify expressions with FPEnv access

ConstantExpression can't store these flags, which can lead to
going against them.
---
 include/llvm/IR/Constants.h       |  4 ++--
 lib/Analysis/ConstantFolding.cpp  |  2 +-
 lib/IR/Constants.cpp              |  8 +++++++-
 test/Transforms/EarlyCSE/fpenv.ll | 24 ++++++++++++++++++++++++
 4 files changed, 34 insertions(+), 4 deletions(-)
 create mode 100644 test/Transforms/EarlyCSE/fpenv.ll

diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index f97a23d..db487d2 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1051,8 +1051,8 @@ public:
   /// \param OnlyIfReducedTy see \a getWithOperands() docs.
   static Constant *get(unsigned Opcode, Constant *C1, Constant *C2,
                        unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr,
-                       bool KeepExceptions = false,
-                       bool KeepRounding = false);
+                       bool KeepExceptions = false, bool KeepRounding = false,
+                       bool Strict = false);
 
   /// \brief Return an ICmp or FCmp comparison operator constant expression.
   ///
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp
index 197cffd..7063553 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -1033,7 +1033,7 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
     }
 
     return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr,
-                             KeepExceptions, KeepRounding);
+                             KeepExceptions, KeepRounding, /* Strict = */ true);
   }
 
   switch (Opcode) {
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 3d18cfd..4277f7d 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -1854,7 +1854,8 @@ Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
 
 Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
                             unsigned Flags, Type *OnlyIfReducedTy,
-                            bool KeepExceptions, bool KeepRounding) {
+                            bool KeepExceptions, bool KeepRounding,
+                            bool Strict) {
   // Check the operands for consistency first.
   assert(Opcode >= Instruction::BinaryOpsBegin &&
          Opcode <  Instruction::BinaryOpsEnd   &&
@@ -1929,6 +1930,11 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
   if (OnlyIfReducedTy == C1->getType())
     return nullptr;
 
+  // ConstantExpression can't store these flags, which can lead to going against
+  // them.
+  if (Strict && (KeepExceptions || KeepRounding))
+    return nullptr;
+
   Constant *ArgVec[] = { C1, C2 };
   ConstantExprKeyType Key(Opcode, ArgVec, 0, Flags);
 
diff --git a/test/Transforms/EarlyCSE/fpenv.ll b/test/Transforms/EarlyCSE/fpenv.ll
new file mode 100644
index 0000000..aba632c
--- /dev/null
+++ b/test/Transforms/EarlyCSE/fpenv.ll
@@ -0,0 +1,24 @@
+; %val.true and %val.false should not be moved inside phi-node as constant
+; expressions as such transformation looses fast-math flags.
+; RUN: opt < %s -S -early-cse | FileCheck %s
+
+define double @do-not-turn-into-constexpr(double %x) {
+; CHECK-LABEL: @do-not-turn-into-constexpr(
+; CHECK: %val.true = fmul
+; CHECK: %val.false = fmul
+entry:
+  %cmp = fcmp oeq double %x, 0.000000e+00
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  %val.true = fmul kexc double 1.000000e+300, 1.000000e+300
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  %val.false = fmul kexc double 1.000000e-300, 1.000000e-300
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi double [ %val.true, %cond.true ], [ %val.false, %cond.false ]
+  ret double %cond
+}
-- 
2.3.5

-------------- next part --------------
>From 51a8815d3b8e3bbdd9402e6736f6fbb34a169aac Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 12 Dec 2014 16:35:01 +0200
Subject: [PATCH 09/13] Make Strict flag available for more clients

---
 include/llvm/Analysis/TargetFolder.h | 35 +++++++++++++++++++++++------------
 include/llvm/IR/ConstantFolder.h     | 35 +++++++++++++++++++++++------------
 include/llvm/IR/Constants.h          | 18 ++++++++++++------
 lib/IR/Constants.cpp                 | 30 ++++++++++++++++++------------
 4 files changed, 76 insertions(+), 42 deletions(-)

diff --git a/include/llvm/Analysis/TargetFolder.h b/include/llvm/Analysis/TargetFolder.h
index 44f7edb..f2188f3 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -53,8 +53,10 @@ public:
   }
   Constant *CreateFAdd(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding));
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return Fold(ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding,
+                                      Strict));
   }
   Constant *CreateSub(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
@@ -62,20 +64,25 @@ public:
   }
   Constant *CreateFSub(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding));
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return Fold(ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding,
+                                      Strict));
   }
   Constant *CreateMul(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false,
                       bool KeepExceptions = false,
-                      bool KeepRounding = false) const {
+                      bool KeepRounding = false,
+                      bool Strict = false) const {
     return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW,
-                                     KeepExceptions, KeepRounding));
+                                     KeepExceptions, KeepRounding, Strict));
   }
   Constant *CreateFMul(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding));
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return Fold(ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding,
+                                      Strict));
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
     return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
@@ -85,8 +92,10 @@ public:
   }
   Constant *CreateFDiv(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding));
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return Fold(ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding,
+                                      Strict));
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return Fold(ConstantExpr::getURem(LHS, RHS));
@@ -96,8 +105,10 @@ public:
   }
   Constant *CreateFRem(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding));
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return Fold(ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding,
+                                      Strict));
   }
   Constant *CreateShl(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index d7f8e01..3f9ec66 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -37,8 +37,10 @@ public:
   }
   Constant *CreateFAdd(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding);
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return ConstantExpr::getFAdd(LHS, RHS, KeepExceptions, KeepRounding,
+                                 Strict);
   }
   Constant *CreateSub(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
@@ -46,20 +48,25 @@ public:
   }
   Constant *CreateFSub(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding);
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return ConstantExpr::getFSub(LHS, RHS, KeepExceptions, KeepRounding,
+                                 Strict);
   }
   Constant *CreateMul(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false,
                       bool KeepExceptions = false,
-                      bool KeepRounding = false) const {
+                      bool KeepRounding = false,
+                      bool Strict = false) const {
     return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW, KeepExceptions,
-                                KeepRounding);
+                                KeepRounding, Strict);
   }
   Constant *CreateFMul(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding);
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return ConstantExpr::getFMul(LHS, RHS, KeepExceptions, KeepRounding,
+                                 Strict);
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS,
                        bool isExact = false) const {
@@ -71,8 +78,10 @@ public:
   }
   Constant *CreateFDiv(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding);
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return ConstantExpr::getFDiv(LHS, RHS, KeepExceptions, KeepRounding,
+                                 Strict);
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return ConstantExpr::getURem(LHS, RHS);
@@ -82,8 +91,10 @@ public:
   }
   Constant *CreateFRem(Constant *LHS, Constant *RHS,
                        bool KeepExceptions = false,
-                       bool KeepRounding = false) const {
-    return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding);
+                       bool KeepRounding = false,
+                       bool Strict = false) const {
+    return ConstantExpr::getFRem(LHS, RHS, KeepExceptions, KeepRounding,
+                                 Strict);
   }
   Constant *CreateShl(Constant *LHS, Constant *RHS,
                       bool HasNUW = false, bool HasNSW = false) const {
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index db487d2..f5ae2c9 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -865,29 +865,35 @@ public:
                           bool HasNUW = false, bool HasNSW = false);
   static Constant *getFAdd(Constant *C1, Constant *C2,
                            bool KeepExceptions = false,
-                           bool KeepRounding = false);
+                           bool KeepRounding = false,
+                           bool Strict = false);
   static Constant *getSub(Constant *C1, Constant *C2,
                           bool HasNUW = false, bool HasNSW = false);
   static Constant *getFSub(Constant *C1, Constant *C2,
                            bool KeepExceptions = false,
-                           bool KeepRounding = false);
+                           bool KeepRounding = false,
+                           bool Strict = false);
   static Constant *getMul(Constant *C1, Constant *C2,
                           bool HasNUW = false, bool HasNSW = false,
                           bool KeepExceptions = false,
-                          bool KeepRounding = false);
+                          bool KeepRounding = false,
+                          bool Strict = false);
   static Constant *getFMul(Constant *C1, Constant *C2,
                            bool KeepExceptions = false,
-                           bool KeepRounding = false);
+                           bool KeepRounding = false,
+                           bool Strict = false);
   static Constant *getUDiv(Constant *C1, Constant *C2, bool isExact = false);
   static Constant *getSDiv(Constant *C1, Constant *C2, bool isExact = false);
   static Constant *getFDiv(Constant *C1, Constant *C2,
                            bool KeepExceptions = false,
-                           bool KeepRounding = false);
+                           bool KeepRounding = false,
+                           bool Strict = false);
   static Constant *getURem(Constant *C1, Constant *C2);
   static Constant *getSRem(Constant *C1, Constant *C2);
   static Constant *getFRem(Constant *C1, Constant *C2,
                            bool KeepExceptions = false,
-                           bool KeepRounding = false);
+                           bool KeepRounding = false,
+                           bool Strict = false);
   static Constant *getAnd(Constant *C1, Constant *C2);
   static Constant *getOr(Constant *C1, Constant *C2);
   static Constant *getXor(Constant *C1, Constant *C2);
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 4277f7d..b8dc0e1 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -2260,9 +2260,10 @@ Constant *ConstantExpr::getAdd(Constant *C1, Constant *C2,
 }
 
 Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2,
-                                bool KeepExceptions, bool KeepRounding) {
+                                bool KeepExceptions, bool KeepRounding,
+                                bool Strict) {
   return get(Instruction::FAdd, C1, C2, 0, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
@@ -2273,24 +2274,27 @@ Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
 }
 
 Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2,
-                                bool KeepExceptions, bool KeepRounding) {
+                                bool KeepExceptions, bool KeepRounding,
+                                bool Strict) {
   return get(Instruction::FSub, C1, C2, 0, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getMul(Constant *C1, Constant *C2,
                                bool HasNUW, bool HasNSW,
-                               bool KeepExceptions, bool KeepRounding) {
+                               bool KeepExceptions, bool KeepRounding,
+                               bool Strict) {
   unsigned Flags = (HasNUW ? OverflowingBinaryOperator::NoUnsignedWrap : 0) |
                    (HasNSW ? OverflowingBinaryOperator::NoSignedWrap   : 0);
   return get(Instruction::Mul, C1, C2, Flags, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2,
-                                bool KeepExceptions, bool KeepRounding) {
+                                bool KeepExceptions, bool KeepRounding,
+                                bool Strict) {
   return get(Instruction::FMul, C1, C2, 0, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) {
@@ -2304,9 +2308,10 @@ Constant *ConstantExpr::getSDiv(Constant *C1, Constant *C2, bool isExact) {
 }
 
 Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2,
-                                bool KeepExceptions, bool KeepRounding) {
+                                bool KeepExceptions, bool KeepRounding,
+                                bool Strict) {
   return get(Instruction::FDiv, C1, C2, 0, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
@@ -2318,9 +2323,10 @@ Constant *ConstantExpr::getSRem(Constant *C1, Constant *C2) {
 }
 
 Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2,
-                                bool KeepExceptions, bool KeepRounding) {
+                                bool KeepExceptions, bool KeepRounding,
+                                bool Strict) {
   return get(Instruction::FRem, C1, C2, 0, nullptr, KeepExceptions,
-             KeepRounding);
+             KeepRounding, Strict);
 }
 
 Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) {
-- 
2.3.5

-------------- next part --------------
>From 803a078e1891cf556eba7d8733706ff122d95da9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 12 Dec 2014 16:40:08 +0200
Subject: [PATCH 10/13] Use Strict in IRBuilder

Try to create constant expression, but skip it in case of conflicts
with FPEnv access flags.
---
 include/llvm/IR/IRBuilder.h    | 25 +++++++++++++++----------
 unittests/IR/IRBuilderTest.cpp | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index 43089d4..2be4686 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -737,8 +737,9 @@ public:
                     bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFAdd(LC, RC, KeepExceptions, KeepRounding),
-                      Name);
+        if (Constant *C = Folder.CreateFAdd(LC, RC, KeepExceptions,
+                                            KeepRounding, true))
+          return Insert(C, Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -761,8 +762,9 @@ public:
                     bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFSub(LC, RC, KeepExceptions, KeepRounding),
-                      Name);
+        if (Constant *C = Folder.CreateFSub(LC, RC, KeepExceptions,
+                                            KeepRounding, true))
+          return Insert(C, Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -785,8 +787,9 @@ public:
                     bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFMul(LC, RC, KeepExceptions, KeepRounding),
-                      Name);
+        if (Constant *C = Folder.CreateFMul(LC, RC, KeepExceptions,
+                                            KeepRounding, true))
+          return Insert(C, Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -819,8 +822,9 @@ public:
                     bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFDiv(LC, RC, KeepExceptions, KeepRounding),
-                      Name);
+        if (Constant *C = Folder.CreateFDiv(LC, RC, KeepExceptions,
+                                            KeepRounding, true))
+          return Insert(C, Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -841,8 +845,9 @@ public:
                     bool KeepExceptions = false, bool KeepRounding = false) {
     if (Constant *LC = dyn_cast<Constant>(LHS))
       if (Constant *RC = dyn_cast<Constant>(RHS))
-        return Insert(Folder.CreateFRem(LC, RC, KeepExceptions, KeepRounding),
-                      Name);
+        if (Constant *C = Folder.CreateFRem(LC, RC, KeepExceptions,
+                                            KeepRounding, true))
+            return Insert(C, Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp
index e8aaaea..ea3d081 100644
--- a/unittests/IR/IRBuilderTest.cpp
+++ b/unittests/IR/IRBuilderTest.cpp
@@ -204,6 +204,47 @@ TEST_F(IRBuilderTest, FastMathFlags) {
 
 }
 
+TEST_F(IRBuilderTest, FPEnvFlags) {
+  IRBuilder<> Builder(BB);
+  Value *F;
+
+  Constant *Huge = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e+308);
+  Constant *Big = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e+300);
+  Constant *Small = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e-300);
+  Constant *Tiny = ConstantFP::get(Type::getDoubleTy(Ctx), 1.000000e-308);
+  Constant *Zero = ConstantFP::get(Type::getDoubleTy(Ctx), 0.0);
+
+  F = Builder.CreateFAdd(Huge, Huge, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFSub(Tiny, Huge, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFMul(Big, Big, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFDiv(Big, Small, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFDiv(Big, Zero, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFRem(Big, Zero, "", nullptr, /* KeepExceptions */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFAdd(Huge, Huge, "", nullptr, /* KeepExceptions */ false,
+                         /* KeepRounding */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFSub(Tiny, Huge, "", nullptr, /* KeepExceptions */ false,
+                         /* KeepRounding */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+
+  F = Builder.CreateFMul(Huge, Huge, "", nullptr, /* KeepExceptions */ false,
+                         /* KeepRounding */ true);
+  EXPECT_FALSE(isa<Constant>(F));
+}
+
 TEST_F(IRBuilderTest, WrapFlags) {
   IRBuilder<true, NoFolder> Builder(BB);
 
-- 
2.3.5

-------------- next part --------------
>From 16d8d4f54d70dcbd3071073e4a78665f9f5b8bc9 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 15 Dec 2014 14:18:03 +0200
Subject: [PATCH 11/13] Don't convert fpops to constexprs in SCCP

---
 lib/Transforms/Scalar/SCCP.cpp                     | 18 ++++++++++++----
 .../SCCP/do-not-convert-fpop-to-constexpr.ll       | 24 ++++++++++++++++++++++
 2 files changed, 38 insertions(+), 4 deletions(-)
 create mode 100644 test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll

diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp
index bc068f7..a1f3cae 100644
--- a/lib/Transforms/Scalar/SCCP.cpp
+++ b/lib/Transforms/Scalar/SCCP.cpp
@@ -851,10 +851,20 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
   LatticeVal &IV = ValueState[&I];
   if (IV.isOverdefined()) return;
 
-  if (V1State.isConstant() && V2State.isConstant())
-    return markConstant(IV, &I,
-                        ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
-                                          V2State.getConstant()));
+  if (V1State.isConstant() && V2State.isConstant()) {
+    bool KeepExceptions = false;
+    bool KeepRounding = false;
+
+    if (isa<FPMathOperator>(&I)) {
+      KeepExceptions = I.hasKeepExceptions();
+      KeepRounding = I.hasKeepRounding();
+    }
+
+    if (Constant *C = ConstantExpr::get(I.getOpcode(), V1State.getConstant(),
+                                        V2State.getConstant(), 0, nullptr,
+                                        KeepExceptions, KeepRounding, true))
+      return markConstant(IV, &I, C);
+  }
 
   // If something is undef, wait for it to resolve.
   if (!V1State.isOverdefined() && !V2State.isOverdefined())
diff --git a/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll b/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll
new file mode 100644
index 0000000..df3275a
--- /dev/null
+++ b/test/Transforms/SCCP/do-not-convert-fpop-to-constexpr.ll
@@ -0,0 +1,24 @@
+; fmuls shouldn't be converted to constant expressions.
+; RUN: opt < %s -sccp -S -enable-except-access-fp-math | FileCheck %s
+
+define double @do-not-convert-fpop-to-constexpr(double %x) {
+; CHECK-LABEL: @do-not-convert-fpop-to-constexpr(
+; CHECK: fmul
+; CHECK: fmul
+; CHECK-NOT: select
+entry:
+  %cmp = fcmp oeq double %x, 0.000000e+00
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:
+  %val.true = fmul kexc double 1.000000e+300, 1.000000e+300
+  br label %cond.end
+
+cond.false:
+  %val.false = fmul kexc double 1.000000e-300, 1.000000e-300
+  br label %cond.end
+
+cond.end:
+  %cond = phi double [ %val.true, %cond.true ], [ %val.false, %cond.false ]
+  ret double %cond
+}
-- 
2.3.5

-------------- next part --------------
>From 27e9d885d176bb1800ab24e775050ef6eb7921d2 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 19 Dec 2014 15:08:59 +0200
Subject: [PATCH 12/13] Prevent InstCombine from hanging

InstCombine shouldn't hang in non-terminating sequence of conversions like:
    (a + b) => (a - (-b)) => (a + b) => etc.
---
 lib/Transforms/InstCombine/InstCombineAddSub.cpp   | 27 +++++++-------
 test/Other/fpenv-constant-fold.ll                  |  9 ++---
 .../do-not-hand-on-fpops-with-fpenv-access.ll      | 42 ++++++++++++++++++++++
 3 files changed, 62 insertions(+), 16 deletions(-)
 create mode 100644 test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll

diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index a8d0172..0faa56c 100644
--- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1333,22 +1333,25 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
         return NV;
   }
 
-  // -A + B  -->  B - A
-  // -A + -B  -->  -(A + B)
-  if (Value *LHSV = dyn_castFNegVal(LHS)) {
-    Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV);
-    RI->copyFastMathFlags(&I);
-    return RI;
-  }
-
-  // A + -B  -->  A - B
-  if (!isa<Constant>(RHS))
-    if (Value *V = dyn_castFNegVal(RHS)) {
-      Instruction *RI = BinaryOperator::CreateFSub(LHS, V);
+  // Skip this to break implicit infinite loop with "fsub" transformations.
+  if (!I.hasKeepExceptions() && !I.hasKeepRounding()) {
+    // -A + B  -->  B - A
+    // -A + -B  -->  -(A + B)
+    if (Value *LHSV = dyn_castFNegVal(LHS)) {
+      Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV);
       RI->copyFastMathFlags(&I);
       return RI;
     }
 
+    // A + -B  -->  A - B
+    if (!isa<Constant>(RHS))
+      if (Value *V = dyn_castFNegVal(RHS)) {
+        Instruction *RI = BinaryOperator::CreateFSub(LHS, V);
+        RI->copyFastMathFlags(&I);
+        return RI;
+      }
+  }
+
   // Check for (fadd double (sitofp x), y), see if we can merge this into an
   // integer add followed by a promotion.
   if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
diff --git a/test/Other/fpenv-constant-fold.ll b/test/Other/fpenv-constant-fold.ll
index 01dbfa0..68b94ca 100644
--- a/test/Other/fpenv-constant-fold.ll
+++ b/test/Other/fpenv-constant-fold.ll
@@ -1,4 +1,5 @@
-; InstCombine is used just for its calls to constant folder.
+; InstCombine is used just for its calls to constant folder, it is the cause of
+; fsub -> fadd transformation.
 ; RUN: opt -S -instcombine -o - < %s | FileCheck %s
 
 ; Target independent constant folder should not fold floating-point operations
@@ -15,7 +16,7 @@ entry:
 
 define double @do-not-fold-fsub-that-can-trap() {
 ; CHECK-LABEL: @do-not-fold-fsub-that-can-trap
-; CHECK: fsub
+; CHECK: fadd
 entry:
   %val = fsub kexc double 1.000000e-308, 1.000000e+308
   ret double %val
@@ -55,7 +56,7 @@ entry:
 
 define double @do-not-fold-fsub-because-of-rounding() {
 ; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding
-; CHECK: fsub
+; CHECK: fadd
 entry:
   %val = fsub kround double 0.101, 0.93
   ret double %val
@@ -92,7 +93,7 @@ define double @fold-fsub-that-cant-trap() {
 ; CHECK-LABEL: @fold-fsub-that-cant-trap
 ; CHECK-NOT: fsub
 entry:
-  %val = fsub kexc kround double 1.0, 1.0
+  %val = fadd kexc kround double 1.0, 1.0
   ret double %val
 }
 
diff --git a/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll b/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll
new file mode 100644
index 0000000..8ea33f0
--- /dev/null
+++ b/test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll
@@ -0,0 +1,42 @@
+; RUN: opt < %s -instcombine -S
+
+; InstCombine shouldn't hang in non-terminating sequence of conversions like:
+;    (a + b) => (a - (-b)) => (a + b) => etc.
+
+define double @test1() {
+entry:
+  %add = fadd kexc double 0x3FF921FB54442D18, 0x3870000000000000
+  ret double %add
+}
+
+define double @test2(double %x) {
+entry:
+  %sub = fsub kexc kround double -0.000000e+00, 1.000000e+00
+  %div = fdiv kexc kround double %sub, %x
+  ret double %div
+}
+
+define double @test3() {
+entry:
+  %sub = fsub kexc kround double -0.000000e+00, 0x400921FB54442D18
+  ret double %sub
+}
+
+define double @test4(i32 %y) {
+entry:
+  %tobool = icmp ne i32 %y, 0
+  br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true:
+  %sub = fsub kexc kround double -0.000000e+00, 0x400921FB54442D18
+  %div = fdiv kexc kround double %sub, 2.000000e+00
+  br label %cond.end
+
+cond.false:
+  %div1 = fdiv kexc kround double 0x400921FB54442D18, 2.000000e+00
+  br label %cond.end
+
+cond.end:
+  %cond = phi double [ %div, %cond.true ], [ %div1, %cond.false ]
+  ret double %cond
+}
-- 
2.3.5

-------------- next part --------------
>From 874ec7e6913e5e310b9608e0f880456b6765a6f0 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Mon, 2 Feb 2015 18:53:43 +0200
Subject: [PATCH 13/13] Don't hoist FP-ops with side-effects in LICM

---
 lib/Transforms/Scalar/LICM.cpp |  4 ++++
 test/Transforms/LICM/fpenv.ll  | 30 ++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)
 create mode 100644 test/Transforms/LICM/fpenv.ll

diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp
index f0e6d64..af13591 100644
--- a/lib/Transforms/Scalar/LICM.cpp
+++ b/lib/Transforms/Scalar/LICM.cpp
@@ -489,6 +489,10 @@ bool canSinkOrHoistInst(Instruction &I, AliasAnalysis *AA, DominatorTree *DT,
       !isa<InsertValueInst>(I))
     return false;
 
+  if (const FPMathOperator *MathOp = dyn_cast<FPMathOperator>(&I))
+    if (MathOp->hasKeepExceptions() || MathOp->hasKeepRounding())
+      return false;
+
   // TODO: Plumb the context instruction through to make hoisting and sinking
   // more powerful. Hoisting of loads already works due to the special casing
   // above. 
diff --git a/test/Transforms/LICM/fpenv.ll b/test/Transforms/LICM/fpenv.ll
new file mode 100644
index 0000000..6fb459c
--- /dev/null
+++ b/test/Transforms/LICM/fpenv.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -O3 -S | FileCheck %s
+
+define void @fdiv-is-not-hoisted-out-of-loop(i32 %n) {
+; CHECK-LABEL: @fdiv-is-not-hoisted-out-of-loop(
+; CHECK: for.body:
+; CHECK: fdiv
+entry:
+  %cmp2 = icmp sgt i32 %n, 0
+  br i1 %cmp2, label %for.body.lr.ph, label %for.end
+
+for.body.lr.ph:
+  %0 = add i32 %n, -1
+  br label %for.body
+
+for.body:
+  %i.03 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
+  %div = fdiv kexc kround double 0.000000e+00, 0.000000e+00
+  tail call void @process(double %div)
+  %inc = add nuw nsw i32 %i.03, 1
+  %exitcond = icmp eq i32 %i.03, %0
+  br i1 %exitcond, label %for.end.loopexit, label %for.body
+
+for.end.loopexit:
+  br label %for.end
+
+for.end:
+  ret void
+}
+
+declare void @process(double) nounwind
-- 
2.3.5



More information about the llvm-commits mailing list