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

Sergey Dmitrouk sdmitrouk at accesssoftek.com
Fri Oct 3 10:33:25 PDT 2014


Hello,

this is continuation of LLVM-dev's thread "More careful treatment of
floating point exceptions".  There wasn't much discussion there, so I
just repeat updated version of the main part of text below.

Currently, LLVM optimizes some floating point operations by replacing
them with result evaluated at compile-time even if their execution at
run-time would cause floating point exceptions.  I'm trying to introduce
a flag (off by default) that would disable such optimizations.  This
isn't trivial as related code is located in different parts of LLVM, so
don't expect attached patches to be ready to be applied, they are rather
something that works and require review from people that have much more
experience with LLVM codebase than me.

There are two sources of the flag (well three, if command-line option is
counted): field of TargetOptions and function attribute.  The later one
is for InstCombine and similar passes, which do not have references to
code generation option.

Please find the attached patches.  Is there a better way to implement patch
number 0004?  Would it make sense to mark IR instructions instead or
maybe creating some special forms for them?  The issue here is caused by an
assumption that floating point operations are target independent, which
doesn't hold if one wants an option to switch between optimized floating
point operations and IEEE conformance.  If there is another way to
communicate state of the option to "target-independent" IR optimizations,
which could replace adding additional argument to a bunch of functions, I
would rather switched to it.

Thanks,
Sergey

P.S. Also thinking about "PreserveFPExceptions" as an alternative name.
-------------- next part --------------
>From 02cc1ae07bfe6e07686ffd345c86b73aaad96765 Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Thu, 25 Sep 2014 11:38:14 +0300
Subject: [PATCH 1/9] 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 f0143afa7544fe08f7b3a09fb0d8a699c6a5ae41 Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Thu, 25 Sep 2014 11:40:10 +0300
Subject: [PATCH 2/9] 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 eaec6dc..89d6bc9 100644
--- a/include/llvm/CodeGen/SelectionDAG.h
+++ b/include/llvm/CodeGen/SelectionDAG.h
@@ -1242,6 +1242,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 e2ead47..d5dd0eb 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -3402,7 +3402,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) {
@@ -3416,30 +3415,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;
@@ -3562,6 +3563,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 6adb48a2785a0feb0e3469a367a47269152eabba Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Thu, 25 Sep 2014 11:44:51 +0300
Subject: [PATCH 3/9] 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 122dda2..365dded 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -1136,6 +1136,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 f208bb7..9a2ec82 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -2508,19 +2508,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 b96d154..18820a5 100644
--- a/lib/IR/ConstantFold.cpp
+++ b/lib/IR/ConstantFold.cpp
@@ -886,7 +886,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) {
@@ -1049,7 +1050,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.
@@ -1130,23 +1131,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);
       }
     }
@@ -1160,7 +1177,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);
@@ -1174,15 +1192,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..4a8b979 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 b314a0cb75c75a4e8e7deecca450d58e6247404b Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Thu, 25 Sep 2014 11:46:24 +0300
Subject: [PATCH 4/9] 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 365dded..53dc813 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -838,16 +838,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);
@@ -1013,7 +1018,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 c074be8..735ed3f 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -660,10 +660,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);
   }
@@ -682,10 +683,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);
   }
@@ -704,10 +706,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);
   }
@@ -736,10 +739,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 88e2558..4d7c366 100644
--- a/lib/Analysis/ConstantFolding.cpp
+++ b/lib/Analysis/ConstantFolding.cpp
@@ -615,7 +615,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.
@@ -894,7 +895,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;
@@ -913,7 +915,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)
@@ -961,13 +963,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) {
@@ -976,7 +980,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);
   }
@@ -984,7 +989,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);
 }
 
 /// ConstantFoldConstantExpression - Attempt to fold the constant expression
@@ -992,9 +998,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);
 }
 
 /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
@@ -1010,15 +1018,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 4a8b979..c3eb4b6 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 54d04dbbb4da1b875a991a4f4e7b508730d16d1b Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Thu, 25 Sep 2014 11:47:00 +0300
Subject: [PATCH 5/9] 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 dcb8338..44fb521 100644
--- a/lib/Target/TargetMachine.cpp
+++ b/lib/Target/TargetMachine.cpp
@@ -68,6 +68,7 @@ void TargetMachine::resetTargetOptions(const MachineFunction *MF) 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");
 
   TO.MCOptions.SanitizeAddress = F->hasFnAttribute(Attribute::SanitizeAddress);
 }
diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h
index 6c0d4e7..d18309d 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 ac0c01e..270e086 100644
--- a/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2635,7 +2635,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);
@@ -2662,7 +2663,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);
@@ -2679,10 +2681,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;
@@ -2748,7 +2753,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
@@ -2943,6 +2948,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 a01f9b0..ba5694b 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -1073,6 +1073,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();
@@ -1082,10 +1087,14 @@ HoistTerminator:
       if (BB1V == BB2V)
         continue;
 
-      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 f084ca27c31f678acc1bc178fd826b66e2e3c0d1 Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Fri, 26 Sep 2014 15:33:02 +0300
Subject: [PATCH 6/9] 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 b58d94ac9350a2d1c997ece5f25e74aacdb1a3f7 Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Fri, 26 Sep 2014 15:33:25 +0300
Subject: [PATCH 7/9] 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 cfdb1d4..aef0def 100644
--- a/lib/AsmParser/LLParser.cpp
+++ b/lib/AsmParser/LLParser.cpp
@@ -2774,7 +2774,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 433246857a17c18676f2c691cc4224970aaebbae Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Fri, 26 Sep 2014 18:41:17 +0300
Subject: [PATCH 8/9] 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 ba5694b..33a1c57 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -266,9 +266,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 7b7aaddd7dd4503948cafe45a10445a59bc1b643 Mon Sep 17 00:00:00 2001
From: xaizek <xaizek at openmailbox.org>
Date: Fri, 3 Oct 2014 17:30:13 +0300
Subject: [PATCH 9/9] 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