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

Sergey Dmitrouk sdmitrouk at accesssoftek.com
Fri Oct 31 09:19:40 PDT 2014


Ping.  Rebased patches with a fix for a typo (in code, not in comments) are
attached.

Hal, do I get it right that what you suggest can be implemented in
Instruction::mayReadFromMemory() and Instruction::mayWriteToMemory() to
get desired behaviour in wider range of usages?

Thanks,
Sergey

On Fri, Oct 24, 2014 at 09:24:48AM -0700, Stephen Canon wrote:
>      On Oct 24, 2014, at 12:23 PM, Hal Finkel <hfinkel at anl.gov> wrote:
> 
>      ----- Original Message -----
> 
>        From: "Stephen Canon" <scanon at apple.com>
>        To: "Hal Finkel" <hfinkel at anl.gov>
>        Cc: "Sergey Dmitrouk" <sdmitrouk at accesssoftek.com>, "llvm-commits"
>        <llvm-commits at cs.uiuc.edu>, "Owen Anderson"
>        <owen at apple.com>
>        Sent: Friday, October 24, 2014 11:13:10 AM
>        Subject: Re: [PATCH] Flag to enable IEEE-754 friendly FP optimizations
> 
>        As a necessary piece of building support for FENV_ACCESS, yes, I
>        think this is worth pursuing.  Note, however, that actually
>        providing full FENV_ACCESS support is likely to be a significant
>        undertaking, and I expect that the pieces that go into it are
>        basically useless until all of them are in place.  Thata**s not to say
>        that it isna**t worth doing, just that ita**s a big thankless job.
> 
>      Steve, so long as you're willing to serve as the expert reviewer here,
>      I'm happy to help move this forward as well. We should, however,
>      probably have a plan for the rest of it. Maybe this is as simple as:
>      when FP exceptions are enabled, we treat all FP operations as if they
>      might write to memory (except that AA confirms that they don't actually
>      alias with any address in particular, but we say nothing about function
>      calls). What do you think?
> 
>    From a numerical point of view, something along those lines could be
>    workable, yes.
>    a** Steve
-------------- next part --------------
>From 2caf27cfa48029dd315bcd51e95d53515992e9b4 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 25 Sep 2014 11:38:14 +0300
Subject: [PATCH 01/11] Add HonorFPExceptions flag to TargetOptions

---
 include/llvm/Target/TargetOptions.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/include/llvm/Target/TargetOptions.h b/include/llvm/Target/TargetOptions.h
index f7df921..e20fc36 100644
--- a/include/llvm/Target/TargetOptions.h
+++ b/include/llvm/Target/TargetOptions.h
@@ -62,7 +62,7 @@ namespace llvm {
     TargetOptions()
         : PrintMachineCode(false), NoFramePointerElim(false),
           LessPreciseFPMADOption(false), UnsafeFPMath(false),
-          NoInfsFPMath(false), NoNaNsFPMath(false),
+          NoInfsFPMath(false), NoNaNsFPMath(false), HonorFPExceptions(false),
           HonorSignDependentRoundingFPMathOption(false), UseSoftFloat(false),
           NoZerosInBSS(false), JITEmitDebugInfo(false),
           JITEmitDebugInfoToDisk(false), GuaranteedTailCallOpt(false),
@@ -117,6 +117,11 @@ namespace llvm {
     /// assume the FP arithmetic arguments and results are never NaNs.
     unsigned NoNaNsFPMath : 1;
 
+    /// HonorFPExceptions - This flag is enabled when code relies on
+    /// availability of floating point exceptions at run-time, thus such
+    /// operations should not be replaced with their results at compile-time.
+    unsigned HonorFPExceptions : 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
-- 
1.8.4

-------------- next part --------------
>From afec5b48cc94866ad4fe9315034c8e6e5d4fa6d0 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 25 Sep 2014 11:40:10 +0300
Subject: [PATCH 02/11] Consider HonorFPExceptions flag in SelectionDAG

---
 include/llvm/CodeGen/SelectionDAG.h       |  5 +++++
 lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 28 ++++++++++++++++++++--------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h
index ade7e56..008f90e 100644
--- a/include/llvm/CodeGen/SelectionDAG.h
+++ b/include/llvm/CodeGen/SelectionDAG.h
@@ -1248,6 +1248,11 @@ private:
                                 SDValue N1, SDValue N2, bool nuw, bool nsw,
                                 bool exact);
 
+  /// Checks whether it's safe to replace floating point operation with it's
+  /// result.  UnsafeOps is bit mask of unacceptable exceptions.
+  bool isSafeToOptimizeFPOp(APFloat::opStatus s,
+                            APFloat::opStatus UnsafeOps) const;
+
   /// VTList - List of non-single value types.
   FoldingSet<SDVTListNode> VTListMap;
 
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 7fb7aba..990f52c 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3381,7 +3381,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) {
@@ -3395,30 +3394,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, VT);
         break;
       case ISD::FSUB:
         s = V1.subtract(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+        if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
           return getConstantFP(V1, VT);
         break;
       case ISD::FMUL:
         s = V1.multiply(V2, APFloat::rmNearestTiesToEven);
-        if (!HasFPExceptions || s!=APFloat::opInvalidOp)
+        if (isSafeToOptimizeFPOp(s, APFloat::opInvalidOp))
           return getConstantFP(V1, 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, VT);
         }
         break;
       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, VT);
         }
         break;
@@ -3541,6 +3542,17 @@ 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 (!TLI->hasFloatingPointExceptions()) {
+      return true;
+  }
+  if (getTarget().Options.HonorFPExceptions) {
+      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.
-- 
1.8.4

-------------- next part --------------
>From 2b2200c97fe25600b542e6ab9ca6d3cccef70805 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 25 Sep 2014 11:44:51 +0300
Subject: [PATCH 03/11] Skip constant folding to preserve FP exceptions

---
 include/llvm/Analysis/ValueTracking.h |  3 +-
 include/llvm/IR/Constant.h            |  2 +-
 include/llvm/IR/Constants.h           |  4 ++
 lib/Analysis/ValueTracking.cpp        | 13 +++++-
 lib/IR/ConstantFold.cpp               | 44 ++++++++++++++------
 lib/IR/ConstantFold.h                 |  2 +-
 lib/IR/Constants.cpp                  | 78 ++++++++++++++++++++++++++++++++---
 7 files changed, 123 insertions(+), 23 deletions(-)

diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h
index 6bbf4f4..2afb912 100644
--- a/include/llvm/Analysis/ValueTracking.h
+++ b/include/llvm/Analysis/ValueTracking.h
@@ -203,7 +203,8 @@ namespace llvm {
   /// However, this method can return true for instructions that read memory;
   /// for such instructions, moving them may change the resulting value.
   bool isSafeToSpeculativelyExecute(const Value *V,
-                                    const DataLayout *TD = nullptr);
+                                    const DataLayout *TD = nullptr,
+                                    bool HonorFPExceptions = 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/Constant.h b/include/llvm/IR/Constant.h
index d26991e..fa7e4e5 100644
--- a/include/llvm/IR/Constant.h
+++ b/include/llvm/IR/Constant.h
@@ -77,7 +77,7 @@ public:
 
   /// canTrap - Return true if evaluation of this constant could trap.  This is
   /// true for things like constant expressions that could divide by zero.
-  bool canTrap() const;
+  bool canTrap(bool HonorFPExceptions = false) const;
 
   /// isThreadDependent - Return true if the value can vary between threads.
   bool isThreadDependent() const;
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index 4823be0..825998e 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1139,6 +1139,10 @@ public:
     return V->getValueID() == ConstantExprVal;
   }
 
+  /// Checks that floating point operation is safe with regard to exceptions.
+  /// Returns false for unsupported types of Value.
+  static bool isExceptionSafeFPOp(const Value *V);
+
 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 da5ba0b..e7911e3 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -2538,19 +2538,28 @@ bool llvm::onlyUsedByLifetimeMarkers(const Value *V) {
 }
 
 bool llvm::isSafeToSpeculativelyExecute(const Value *V,
-                                        const DataLayout *TD) {
+                                        const DataLayout *TD,
+                                        bool HonorFPExceptions) {
   const Operator *Inst = dyn_cast<Operator>(V);
   if (!Inst)
     return false;
 
   for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
     if (Constant *C = dyn_cast<Constant>(Inst->getOperand(i)))
-      if (C->canTrap())
+      if (C->canTrap(HonorFPExceptions))
         return false;
 
   switch (Inst->getOpcode()) {
   default:
     return true;
+  case Instruction::FMul:
+  case Instruction::FAdd:
+  case Instruction::FSub:
+  case Instruction::FDiv:
+    if (HonorFPExceptions) {
+      return ConstantExpr::isExceptionSafeFPOp(Inst);
+    }
+    return true;
   case Instruction::UDiv:
   case Instruction::URem:
     // x / y is undefined if y == 0, but calculations like x / 3 are safe.
diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp
index cdfb41f..542fe72 100644
--- a/lib/IR/ConstantFold.cpp
+++ b/lib/IR/ConstantFold.cpp
@@ -895,7 +895,8 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg,
 
 
 Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
-                                              Constant *C1, Constant *C2) {
+                                              Constant *C1, Constant *C2,
+                                              bool HonorFPExceptions) {
   // Handle UndefValue up front.
   if (isa<UndefValue>(C1) || isa<UndefValue>(C2)) {
     switch (Opcode) {
@@ -1058,7 +1059,7 @@ 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, HonorFPExceptions);
   }
 
   // At this point we know neither constant is an UndefValue.
@@ -1139,23 +1140,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 (HonorFPExceptions && s != APFloat::opOK) {
+          break;
+        }
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FSub:
-        (void)C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+        s = C3V.subtract(C2V, APFloat::rmNearestTiesToEven);
+        if (HonorFPExceptions && s != APFloat::opOK) {
+          break;
+        }
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FMul:
-        (void)C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+        s = C3V.multiply(C2V, APFloat::rmNearestTiesToEven);
+        if (HonorFPExceptions && s != APFloat::opOK) {
+          break;
+        }
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FDiv:
-        (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+        s = C3V.divide(C2V, APFloat::rmNearestTiesToEven);
+        if (HonorFPExceptions && s != APFloat::opOK) {
+          break;
+        }
         return ConstantFP::get(C1->getContext(), C3V);
       case Instruction::FRem:
-        (void)C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+        s = C3V.mod(C2V, APFloat::rmNearestTiesToEven);
+        if (HonorFPExceptions && s != APFloat::opOK) {
+          break;
+        }
         return ConstantFP::get(C1->getContext(), C3V);
       }
     }
@@ -1169,7 +1186,8 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode,
       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,
+                                         HonorFPExceptions));
     }
     
     return ConstantVector::get(Result);
@@ -1183,15 +1201,17 @@ 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, HonorFPExceptions);
       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,
+                                 HonorFPExceptions);
     }
   } 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, HonorFPExceptions);
   }
 
   // i1 can be simplified in many cases.
diff --git a/lib/IR/ConstantFold.h b/lib/IR/ConstantFold.h
index a516abe..1a6d82e 100644
--- a/lib/IR/ConstantFold.h
+++ b/lib/IR/ConstantFold.h
@@ -44,7 +44,7 @@ namespace llvm {
   Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
                                                ArrayRef<unsigned> Idxs);
   Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1,
-                                          Constant *V2);
+                                          Constant *V2, bool HonorFPExceptions);
   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 21dbacc..779c02f 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -306,7 +306,8 @@ void Constant::destroyConstantImpl() {
 }
 
 static bool canTrapImpl(const Constant *C,
-                        SmallPtrSetImpl<const ConstantExpr *> &NonTrappingOps) {
+                        SmallPtrSetImpl<const ConstantExpr *> &NonTrappingOps,
+                        bool HonorFPExceptions) {
   assert(C->getType()->isFirstClassType() && "Cannot evaluate aggregate vals!");
   // The only thing that could possibly trap are constant exprs.
   const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
@@ -316,13 +317,27 @@ 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) && canTrapImpl(Op, NonTrappingOps))
+      if (NonTrappingOps.insert(Op) && canTrapImpl(Op, NonTrappingOps,
+                                                   HonorFPExceptions)) {
         return true;
+      }
     }
   }
 
   // Otherwise, only specific operations can trap.
-  switch (CE->getOpcode()) {
+  unsigned Opcode = CE->getOpcode();
+  if (HonorFPExceptions) {
+    switch (Opcode) {
+    default:
+      break;
+    case Instruction::FMul:
+    case Instruction::FAdd:
+    case Instruction::FSub:
+    case Instruction::FDiv:
+      return !ConstantExpr::isExceptionSafeFPOp(CE);
+    }
+  }
+  switch (Opcode) {
   default:
     return false;
   case Instruction::UDiv:
@@ -340,9 +355,9 @@ static bool canTrapImpl(const Constant *C,
 
 /// canTrap - Return true if evaluation of this constant could trap.  This is
 /// true for things like constant expressions that could divide by zero.
-bool Constant::canTrap() const {
+bool Constant::canTrap(bool HonorFPExceptions) const {
   SmallPtrSet<const ConstantExpr *, 4> NonTrappingOps;
-  return canTrapImpl(this, NonTrappingOps);
+  return canTrapImpl(this, NonTrappingOps, HonorFPExceptions);
 }
 
 /// Check if C contains a GlobalValue for which Predicate is true.
@@ -1892,7 +1907,7 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
   }
 #endif
 
-  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2))
+  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2, false))
     return FC;          // Fold a few common cases.
 
   if (OnlyIfReducedTy == C1->getType())
@@ -2965,3 +2980,54 @@ Instruction *ConstantExpr::getAsInstruction() {
     return BO;
   }
 }
+
+bool ConstantExpr::isExceptionSafeFPOp(const Value *V) {
+  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: {
+    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();
+    APFloat::opStatus status;
+
+    switch (Opcode) {
+    case Instruction::FMul:
+      status = LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FAdd:
+      status = LHS.add(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FSub:
+      status = LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    case Instruction::FDiv:
+      status = LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+      break;
+    }
+
+    return (status == APFloat::opOK);
+  }
+  }
+}
-- 
1.8.4

-------------- next part --------------
>From 342de27ad5e8173a84b8618fb21fc0e701d2db09 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 25 Sep 2014 11:46:24 +0300
Subject: [PATCH 04/11] Pass HonorFPExceptions flag around

---
 include/llvm/Analysis/ConstantFolding.h |  9 ++++++---
 include/llvm/Analysis/TargetFolder.h    | 26 ++++++++++++++----------
 include/llvm/IR/ConstantFolder.h        | 30 +++++++++++++++++-----------
 include/llvm/IR/Constants.h             | 18 +++++++++++------
 include/llvm/IR/IRBuilder.h             | 20 +++++++++++--------
 lib/Analysis/ConstantFolding.cpp        | 35 ++++++++++++++++++++++-----------
 lib/IR/Constants.cpp                    | 32 +++++++++++++++++++-----------
 7 files changed, 107 insertions(+), 63 deletions(-)

diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h
index 09d45ca..8f013ec 100644
--- a/include/llvm/Analysis/ConstantFolding.h
+++ b/include/llvm/Analysis/ConstantFolding.h
@@ -38,14 +38,16 @@ namespace llvm {
 /// and stores, which have no constant expression form.
 Constant *ConstantFoldInstruction(Instruction *I,
                                   const DataLayout *TD = nullptr,
-                                  const TargetLibraryInfo *TLI = nullptr);
+                                  const TargetLibraryInfo *TLI = nullptr,
+                                  bool HonorFPExceptions = false);
 
 /// ConstantFoldConstantExpression - Attempt to fold the constant expression
 /// using the specified DataLayout.  If successful, the constant result is
 /// result is returned, if not, null is returned.
 Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
                                          const DataLayout *TD = nullptr,
-                                         const TargetLibraryInfo *TLI =nullptr);
+                                         const TargetLibraryInfo *TLI = nullptr,
+                                         bool HonorFPExceptions = false);
 
 /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
 /// specified operands.  If successful, the constant result is returned, if not,
@@ -56,7 +58,8 @@ Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
 Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
                                    ArrayRef<Constant *> Ops,
                                    const DataLayout *TD = nullptr,
-                                   const TargetLibraryInfo *TLI = nullptr);
+                                   const TargetLibraryInfo *TLI = nullptr,
+                                   bool HonorFPExceptions = 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 587a7ef..a04a186 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -51,22 +51,27 @@ 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 HonorFPExceptions = false) const {
+    return Fold(ConstantExpr::getFAdd(LHS, RHS, HonorFPExceptions));
   }
   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 HonorFPExceptions = false) const {
+    return Fold(ConstantExpr::getFSub(LHS, RHS, HonorFPExceptions));
   }
   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 HonorFPExceptions = false) const {
+    return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW,
+                                     HonorFPExceptions));
   }
-  Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFMul(LHS, RHS));
+  Constant *CreateFMul(Constant *LHS, Constant *RHS,
+                       bool HonorFPExceptions = false) const {
+    return Fold(ConstantExpr::getFMul(LHS, RHS, HonorFPExceptions));
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{
     return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
@@ -74,8 +79,9 @@ 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 HonorFPExceptions = false) const {
+    return Fold(ConstantExpr::getFDiv(LHS, RHS, HonorFPExceptions));
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return Fold(ConstantExpr::getURem(LHS, RHS));
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index e271a14..fd753ad 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -35,22 +35,26 @@ 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 HonorFPExceptions = false) const {
+    return ConstantExpr::getFAdd(LHS, RHS, HonorFPExceptions);
   }
   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 HonorFPExceptions = false) const {
+    return ConstantExpr::getFSub(LHS, RHS, HonorFPExceptions);
   }
   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 HonorFPExceptions = false) const {
+    return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW, HonorFPExceptions);
   }
-  Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::getFMul(LHS, RHS);
+  Constant *CreateFMul(Constant *LHS, Constant *RHS,
+                       bool HonorFPExceptions = false) const {
+    return ConstantExpr::getFMul(LHS, RHS, HonorFPExceptions);
   }
   Constant *CreateUDiv(Constant *LHS, Constant *RHS,
                        bool isExact = false) const {
@@ -60,8 +64,9 @@ 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 HonorFPExceptions = false) const {
+    return ConstantExpr::getFDiv(LHS, RHS, HonorFPExceptions);
   }
   Constant *CreateURem(Constant *LHS, Constant *RHS) const {
     return ConstantExpr::getURem(LHS, RHS);
@@ -95,8 +100,9 @@ public:
   }
 
   Constant *CreateBinOp(Instruction::BinaryOps Opc,
-                        Constant *LHS, Constant *RHS) const {
-    return ConstantExpr::get(Opc, LHS, RHS);
+                        Constant *LHS, Constant *RHS,
+                        bool HonorFPExceptions = false) const {
+    return ConstantExpr::get(Opc, LHS, RHS, 0, nullptr, HonorFPExceptions);
   }
 
   //===--------------------------------------------------------------------===//
diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h
index 825998e..cc12bbf 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -841,16 +841,21 @@ 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 HonorFPExceptions = 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 HonorFPExceptions = 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 HonorFPExceptions = false);
+  static Constant *getFMul(Constant *C1, Constant *C2,
+                           bool HonorFPExceptions = 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 HonorFPExceptions = false);
   static Constant *getURem(Constant *C1, Constant *C2);
   static Constant *getSRem(Constant *C1, Constant *C2);
   static Constant *getFRem(Constant *C1, Constant *C2);
@@ -1016,7 +1021,8 @@ 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 HonorFPExceptions = false);
 
   /// \brief Return an ICmp or FCmp comparison operator constant expression.
   ///
diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h
index d803bf4..8908c0e 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -664,10 +664,11 @@ public:
     return CreateAdd(LHS, RHS, Name, true, false);
   }
   Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool HonorFPExceptions = 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, HonorFPExceptions), Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -686,10 +687,11 @@ public:
     return CreateSub(LHS, RHS, Name, true, false);
   }
   Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool HonorFPExceptions = 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, HonorFPExceptions), Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -708,10 +710,11 @@ public:
     return CreateMul(LHS, RHS, Name, true, false);
   }
   Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool HonorFPExceptions = 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, HonorFPExceptions), Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
@@ -740,10 +743,11 @@ public:
     return CreateSDiv(LHS, RHS, Name, true);
   }
   Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "",
-                    MDNode *FPMathTag = nullptr) {
+                    MDNode *FPMathTag = nullptr,
+                    bool HonorFPExceptions = 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, HonorFPExceptions), Name);
     return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS),
                                       FPMathTag, FMF), Name);
   }
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp
index cd25acb..0fb5bb0 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -623,7 +623,8 @@ static Constant *ConstantFoldLoadInst(const LoadInst *LI, const DataLayout *TD){
 /// these together.  If target data info is available, it is provided as DL,
 /// otherwise DL is null.
 static Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0,
-                                           Constant *Op1, const DataLayout *DL){
+                                           Constant *Op1, const DataLayout *DL,
+                                           bool HonorFPExceptions) {
   // SROA
 
   // Fold (and 0xffffffff00000000, (shl x, 32)) -> shl.
@@ -900,7 +901,8 @@ static Constant *SymbolicallyEvaluateGEP(ArrayRef<Constant *> Ops,
 /// and stores, which have no constant expression form.
 Constant *llvm::ConstantFoldInstruction(Instruction *I,
                                         const DataLayout *TD,
-                                        const TargetLibraryInfo *TLI) {
+                                        const TargetLibraryInfo *TLI,
+                                        bool HonorFPExceptions) {
   // Handle PHI nodes quickly here...
   if (PHINode *PN = dyn_cast<PHINode>(I)) {
     Constant *CommonValue = nullptr;
@@ -919,7 +921,7 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I,
         return nullptr;
       // Fold the PHI's operands.
       if (ConstantExpr *NewC = dyn_cast<ConstantExpr>(C))
-        C = ConstantFoldConstantExpression(NewC, TD, TLI);
+        C = ConstantFoldConstantExpression(NewC, TD, TLI, HonorFPExceptions);
       // If the incoming value is a different constant to
       // the one we saw previously, then give up.
       if (CommonValue && C != CommonValue)
@@ -967,13 +969,15 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I,
                                     EVI->getIndices());
   }
 
-  return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, TD, TLI);
+  return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, TD, TLI,
+                                  HonorFPExceptions);
 }
 
 static Constant *
 ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout *TD,
                                    const TargetLibraryInfo *TLI,
-                                   SmallPtrSetImpl<ConstantExpr *> &FoldedOps) {
+                                   SmallPtrSetImpl<ConstantExpr *> &FoldedOps,
+                                   bool HonorFPExceptions) {
   SmallVector<Constant *, 8> Ops;
   for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); i != e;
        ++i) {
@@ -982,7 +986,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout *TD,
     // a ConstantExpr, we don't have to process it again.
     if (ConstantExpr *NewCE = dyn_cast<ConstantExpr>(NewC)) {
       if (FoldedOps.insert(NewCE))
-        NewC = ConstantFoldConstantExpressionImpl(NewCE, TD, TLI, FoldedOps);
+        NewC = ConstantFoldConstantExpressionImpl(NewCE, TD, TLI, FoldedOps,
+                                                  HonorFPExceptions);
     }
     Ops.push_back(NewC);
   }
@@ -990,7 +995,8 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout *TD,
   if (CE->isCompare())
     return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1],
                                            TD, TLI);
-  return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, TD, TLI);
+  return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, TD, TLI,
+                                  HonorFPExceptions);
 }
 
 /// Attempt to fold the constant expression
@@ -998,9 +1004,11 @@ ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout *TD,
 /// result is returned, if not, null is returned.
 Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
                                                const DataLayout *TD,
-                                               const TargetLibraryInfo *TLI) {
+                                               const TargetLibraryInfo *TLI,
+                                               bool HonorFPExceptions) {
   SmallPtrSet<ConstantExpr *, 4> FoldedOps;
-  return ConstantFoldConstantExpressionImpl(CE, TD, TLI, FoldedOps);
+  return ConstantFoldConstantExpressionImpl(CE, TD, TLI, FoldedOps,
+                                            HonorFPExceptions);
 }
 
 /// Attempt to constant fold an instruction with the
@@ -1016,15 +1024,18 @@ Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE,
 Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
                                          ArrayRef<Constant *> Ops,
                                          const DataLayout *TD,
-                                         const TargetLibraryInfo *TLI) {
+                                         const TargetLibraryInfo *TLI,
+                                         bool HonorFPExceptions) {
   // Handle easy binops first.
   if (Instruction::isBinaryOp(Opcode)) {
     if (isa<ConstantExpr>(Ops[0]) || isa<ConstantExpr>(Ops[1])) {
-      if (Constant *C = SymbolicallyEvaluateBinop(Opcode, Ops[0], Ops[1], TD))
+      if (Constant *C = SymbolicallyEvaluateBinop(Opcode, Ops[0], Ops[1], TD,
+                                                  HonorFPExceptions))
         return C;
     }
 
-    return ConstantExpr::get(Opcode, Ops[0], Ops[1]);
+    return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr,
+                             HonorFPExceptions);
   }
 
   switch (Opcode) {
diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp
index 779c02f..5ce91b1 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -1841,7 +1841,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 HonorFPExceptions) {
   // Check the operands for consistency first.
   assert(Opcode >= Instruction::BinaryOpsBegin &&
          Opcode <  Instruction::BinaryOpsEnd   &&
@@ -1907,8 +1908,10 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2,
   }
 #endif
 
-  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2, false))
+  if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2,
+                                                   HonorFPExceptions)) {
     return FC;          // Fold a few common cases.
+  }
 
   if (OnlyIfReducedTy == C1->getType())
     return nullptr;
@@ -2231,8 +2234,9 @@ 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 HonorFPExceptions) {
+  return get(Instruction::FAdd, C1, C2, 0, nullptr, HonorFPExceptions);
 }
 
 Constant *ConstantExpr::getSub(Constant *C1, Constant *C2,
@@ -2242,19 +2246,22 @@ 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 HonorFPExceptions) {
+  return get(Instruction::FSub, C1, C2, 0, nullptr, HonorFPExceptions);
 }
 
 Constant *ConstantExpr::getMul(Constant *C1, Constant *C2,
-                               bool HasNUW, bool HasNSW) {
+                               bool HasNUW, bool HasNSW,
+                               bool HonorFPExceptions) {
   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, HonorFPExceptions);
 }
 
-Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2) {
-  return get(Instruction::FMul, C1, C2);
+Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2,
+                                bool HonorFPExceptions) {
+  return get(Instruction::FMul, C1, C2, 0, nullptr, HonorFPExceptions);
 }
 
 Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) {
@@ -2267,8 +2274,9 @@ 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 HonorFPExceptions) {
+  return get(Instruction::FDiv, C1, C2, 0, nullptr, HonorFPExceptions);
 }
 
 Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) {
-- 
1.8.4

-------------- next part --------------
>From b849aaa0c13b64e5a5ffc1874c1f47a8a468a233 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Thu, 25 Sep 2014 11:47:00 +0300
Subject: [PATCH 05/11] Use "honor-fp-exceptions" function attribute

---
 lib/Target/TargetMachine.cpp                       |  1 +
 lib/Transforms/InstCombine/InstCombine.h           |  2 ++
 .../InstCombine/InstructionCombining.cpp           | 22 ++++++++++++++++------
 lib/Transforms/Utils/SimplifyCFG.cpp               | 13 +++++++++++--
 4 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp
index 309e1bf..0250552 100644
--- a/lib/Target/TargetMachine.cpp
+++ b/lib/Target/TargetMachine.cpp
@@ -64,6 +64,7 @@ void TargetMachine::resetTargetOptions(const Function &F) const {
   RESET_OPTION(NoNaNsFPMath, "no-nans-fp-math");
   RESET_OPTION(UseSoftFloat, "use-soft-float");
   RESET_OPTION(DisableTailCalls, "disable-tail-calls");
+  RESET_OPTION(HonorFPExceptions, "honor-fp-exceptions");
 
   Options.MCOptions.SanitizeAddress = F.hasFnAttribute(Attribute::SanitizeAddress);
 }
diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h
index d4b252b..d7b604c 100644
--- a/lib/Transforms/InstCombine/InstCombine.h
+++ b/lib/Transforms/InstCombine/InstCombine.h
@@ -102,6 +102,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
   bool MadeIRChange;
   LibCallSimplifier *Simplifier;
   bool MinimizeSize;
+  bool HonorFPExceptions;
 
 public:
   /// Worklist - All of the instructions that need to be simplified.
@@ -115,6 +116,7 @@ public:
   static char ID; // Pass identification, replacement for typeid
   InstCombiner() : FunctionPass(ID), DL(nullptr), Builder(nullptr) {
     MinimizeSize = false;
+    HonorFPExceptions = false;
     initializeInstCombinerPass(*PassRegistry::getPassRegistry());
   }
 
diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp
index c32294f..7ad2bb3 100644
--- a/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2660,7 +2660,8 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB,
                                        SmallPtrSetImpl<BasicBlock*> &Visited,
                                        InstCombiner &IC,
                                        const DataLayout *DL,
-                                       const TargetLibraryInfo *TLI) {
+                                       const TargetLibraryInfo *TLI,
+                                       bool HonorFPExceptions) {
   bool MadeIRChange = false;
   SmallVector<BasicBlock*, 256> Worklist;
   Worklist.push_back(BB);
@@ -2687,7 +2688,8 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB,
 
       // ConstantProp instruction if trivially constant.
       if (!Inst->use_empty() && isa<Constant>(Inst->getOperand(0)))
-        if (Constant *C = ConstantFoldInstruction(Inst, DL, TLI)) {
+        if (Constant *C = ConstantFoldInstruction(Inst, DL, TLI,
+                                                  HonorFPExceptions)) {
           DEBUG(dbgs() << "IC: ConstFold to: " << *C << " from: "
                        << *Inst << '\n');
           Inst->replaceAllUsesWith(C);
@@ -2704,10 +2706,13 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB,
           if (CE == nullptr) continue;
 
           Constant*& FoldRes = FoldedConstants[CE];
-          if (!FoldRes)
-            FoldRes = ConstantFoldConstantExpression(CE, DL, TLI);
-          if (!FoldRes)
+          if (!FoldRes) {
+            FoldRes = ConstantFoldConstantExpression(CE, DL, TLI,
+                                                     HonorFPExceptions);
+          }
+          if (!FoldRes) {
             FoldRes = CE;
+          }
 
           if (FoldRes != CE) {
             *i = FoldRes;
@@ -2773,7 +2778,7 @@ bool InstCombiner::DoOneIteration(Function &F, unsigned Iteration) {
     // track of which blocks we visit.
     SmallPtrSet<BasicBlock*, 64> Visited;
     MadeIRChange |= AddReachableCodeToWorklist(F.begin(), Visited, *this, DL,
-                                               TLI);
+                                               TLI, HonorFPExceptions);
 
     // Do a quick scan over the function.  If we find any blocks that are
     // unreachable, remove any instructions inside of them.  This prevents
@@ -2968,6 +2973,11 @@ bool InstCombiner::runOnFunction(Function &F) {
   MinimizeSize = F.getAttributes().hasAttribute(AttributeSet::FunctionIndex,
                                                 Attribute::MinSize);
 
+  // Target cares about IEEE754 conformant FP exceptions at run-time?
+  HonorFPExceptions = F.hasFnAttribute("honor-fp-exceptions") &&
+                      (F.getFnAttribute("honor-fp-exceptions")
+                        .getValueAsString() == "true");
+
   /// Builder - This is an IRBuilder that automatically inserts new
   /// instructions into the worklist when they are created.
   IRBuilder<true, TargetFolder, InstCombineIRInserter>
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index 0e4d779..9009241 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -1088,6 +1088,11 @@ HoistTerminator:
   if (isa<InvokeInst>(I1) && !isSafeToHoistInvoke(BB1, BB2, I1, I2))
     return Changed;
 
+  Function *F = BIParent->getParent();
+  bool HonorFPExceptions = F->hasFnAttribute("honor-fp-exceptions") &&
+                           (F->getFnAttribute("honor-fp-exceptions")
+                              .getValueAsString() == "true");
+
   for (succ_iterator SI = succ_begin(BB1), E = succ_end(BB1); SI != E; ++SI) {
     PHINode *PN;
     for (BasicBlock::iterator BBI = SI->begin();
@@ -1103,10 +1108,14 @@ HoistTerminator:
           passingValueIsAlwaysUndefined(BB2V, PN))
        return Changed;
 
-      if (isa<ConstantExpr>(BB1V) && !isSafeToSpeculativelyExecute(BB1V, DL))
+      if (isa<ConstantExpr>(BB1V) &&
+          !isSafeToSpeculativelyExecute(BB1V, DL, HonorFPExceptions)) {
         return Changed;
-      if (isa<ConstantExpr>(BB2V) && !isSafeToSpeculativelyExecute(BB2V, DL))
+      }
+      if (isa<ConstantExpr>(BB2V) &&
+          !isSafeToSpeculativelyExecute(BB2V, DL, HonorFPExceptions)) {
         return Changed;
+      }
     }
   }
 
-- 
1.8.4

-------------- next part --------------
>From e3bb752a4bca84e6f4711f24fe5cf70574f0443b Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 26 Sep 2014 15:33:02 +0300
Subject: [PATCH 06/11] Add -honor-fp-exceptions option to LLVM

---
 include/llvm/CodeGen/CommandFlags.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h
index 95579f8..60baf67 100644
--- a/include/llvm/CodeGen/CommandFlags.h
+++ b/include/llvm/CodeGen/CommandFlags.h
@@ -133,6 +133,11 @@ GenerateSoftFloatCalls("soft-float",
                     cl::desc("Generate software floating point library calls"),
                     cl::init(false));
 
+cl::opt<bool>
+HonorFPExceptions("honor-fp-exceptions",
+                  cl::desc("Preserve exceptions raising floating operations"),
+                  cl::init(false));
+
 cl::opt<llvm::FloatABI::ABIType>
 FloatABIForCalls("float-abi",
                  cl::desc("Choose float ABI type"),
@@ -237,6 +242,7 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
   Options.UnsafeFPMath = EnableUnsafeFPMath;
   Options.NoInfsFPMath = EnableNoInfsFPMath;
   Options.NoNaNsFPMath = EnableNoNaNsFPMath;
+  Options.HonorFPExceptions = HonorFPExceptions;
   Options.HonorSignDependentRoundingFPMathOption =
       EnableHonorSignDependentRoundingFPMath;
   Options.UseSoftFloat = GenerateSoftFloatCalls;
-- 
1.8.4

-------------- next part --------------
>From 74029ba361eba8ef237a975a5a6dfd5ed7193ad8 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 26 Sep 2014 15:33:25 +0300
Subject: [PATCH 07/11] Do not fold constants on reading in IR assembly

---
 lib/AsmParser/LLParser.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp
index b7818bb..0aea438 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -2776,7 +2776,7 @@ 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);
     ID.ConstantVal = C;
     ID.Kind = ValID::t_Constant;
     return false;
-- 
1.8.4

-------------- next part --------------
>From 723d7cff2ea0a4c8cf13dc3ada0bad3b437df3c5 Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 26 Sep 2014 18:41:17 +0300
Subject: [PATCH 08/11] Consider HonorFPExceptions flag in SimplifyCFG

---
 lib/Transforms/Utils/SimplifyCFG.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index 9009241..593056d 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -278,9 +278,15 @@ static bool DominatesMergePoint(Value *V, BasicBlock *BB,
   if (!I) {
     // Non-instructions all dominate instructions, but not all constantexprs
     // can be executed unconditionally.
-    if (ConstantExpr *C = dyn_cast<ConstantExpr>(V))
-      if (C->canTrap())
+    if (ConstantExpr *C = dyn_cast<ConstantExpr>(V)) {
+      Function *F = BB->getParent();
+      bool HonorFPExceptions = F->hasFnAttribute("honor-fp-exceptions") &&
+                               (F->getFnAttribute("honor-fp-exceptions")
+                                  .getValueAsString() == "true");
+
+      if (C->canTrap(HonorFPExceptions))
         return false;
+    }
     return true;
   }
   BasicBlock *PBB = I->getParent();
-- 
1.8.4

-------------- next part --------------
>From 578cc30b79bdafa864cb3481e425783fa951a1cb Mon Sep 17 00:00:00 2001
From: Sergey Dmitrouk <sdmitrouk at accesssoftek.com>
Date: Fri, 3 Oct 2014 17:30:13 +0300
Subject: [PATCH 09/11] Add LLVM test for HonorFPExceptions

---
 .../SimplifyCFG/do-not-hoist-fp-that-can-trap.ll   | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 test/Transforms/SimplifyCFG/do-not-hoist-fp-that-can-trap.ll

diff --git a/test/Transforms/SimplifyCFG/do-not-hoist-fp-that-can-trap.ll b/test/Transforms/SimplifyCFG/do-not-hoist-fp-that-can-trap.ll
new file mode 100644
index 0000000..351c6d7
--- /dev/null
+++ b/test/Transforms/SimplifyCFG/do-not-hoist-fp-that-can-trap.ll
@@ -0,0 +1,28 @@
+; The phi should not be replaced with select because operation raises exception.
+; RUN: opt < %s -simplifycfg -S | FileCheck %s
+
+define double @do-not-hoist-fp-that-can-trap(double %x, double %y) #0 {
+; CHECK-NOT: select
+; CHECK-NOT: double 0x7FF0000000000000
+; CHECK-NOT: double 0.000000e+00
+entry:
+  %x.addr = alloca double, align 8
+  %y.addr = alloca double, align 8
+  store double %x, double* %x.addr, align 8
+  store double %y, double* %y.addr, align 8
+  %0 = load double* %x.addr, align 8
+  %cmp = fcmp oeq double %0, 0.000000e+00
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi double [ fmul (double 1.000000e+300, double 1.000000e+300), %cond.true ], [ fmul (double 1.000000e-300, double 1.000000e-300), %cond.false ]
+  ret double %cond
+}
+
+attributes #0 = { "honor-fp-exceptions"="true" }
-- 
1.8.4



More information about the llvm-commits mailing list