[LLVMdev] More careful treatment of floating point exceptions

Sergey Dmitrouk sdmitrouk at accesssoftek.com
Thu Sep 25 02:47:52 PDT 2014


Hi again,

It's partially done.  My concern is that it won't be accepted as is
because of adding the flag parameter in a lot of places.  I'd like to show
what it looks like (here, not on llvm-commit yet),  maybe someone could
suggest a better way.

There are two sources of the flag: field of TargetOptions and function
attribute.  I had to add the later one for InstCombine pass.  Still it's
not enough for one place in Clang, where I can't get to code generation
attribute.

Please find the attached patches.  Is there a better way to implement patch
number 0006?  Would it make sense to mark IR instructions instead or
maybe create 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.

Basically, I'm looking for another way to communicate state of the option
to "target-independent" IR optimizations, which could replace adding
additional argument to a bunch of functions.

Thanks,
Sergey

On Fri, Sep 19, 2014 at 01:07:17PM -0700, Owen Anderson wrote:
> Both forms are useful.  There are some platforms (some GPUs and accelerators) that simply do not support floating point exceptions, and there are other platforms (most CPUs) that can suppose precise floating point exceptions, but where we generally don’t want to for performance reasons.
> 
> I suspect there’s a tripartite breakdown at play here:
> 	(1) Use cases where we don’t care about exceptions at all, e.g. compiling GLSL programs for a GPU.
> 	(2) Use cases where we want strict IEEE conformance.
> 	(3) Use cases where we want to support a reasonable degree of conformance (e.g., still getting a division by zero exception), but without all the performance constrains of (2).  This would be the default for normal clang invocations.
> 
> —Owen
> 
> > On Sep 19, 2014, at 12:59 PM, Sergey Dmitrouk <sdmitrouk at accesssoftek.com> wrote:
> > 
> > Hi Sanjay,
> > 
> > Thanks, I saw this flag and it's definitely should be considered, but
> > it appeared to me to be static characteristic of target platform.  I'm
> > not sure how appropriate it would be to change its value from a front-end.
> > It says "Has", while optional flag would rather say "Uses" meaning that
> > implementation cares about floating point exceptions.
> > 
> > Regards,
> > Sergey
> > 
> > On Fri, Sep 19, 2014 at 12:01:07PM -0700, Sanjay Patel wrote:
> >>   Hi Sergey -
> >> 
> >>   Does this solve part of the problem?
> >>   http://llvm.org/viewvc/llvm-project?view=revision&revision=215222
> >>   On Fri, Sep 19, 2014 at 9:12 AM, Sergey Dmitrouk
> >>   <sdmitrouk at accesssoftek.com> wrote:
> >> 
> >>     Hi,
> >> 
> >>     I'd like to make code emitted by LLVM that includes floating point
> >>     operations which raise FP exceptions behave closer to what is defined by
> >>     IEEE754 standard.A  I'm not going to "fix everything", just incorrect
> >>     behaviour I faced so far.
> >> 
> >>     Most of troubles regarding FP exceptions are caused by optimizations, so
> >>     there should be a flag to disable/block them if one wants to get better
> >>     code in a sense of its IEEE754 conformance.A  I couldn't find an
> >>     existing
> >>     flag for this and would like to introduce one.A  I guess it should be
> >>     added to llvm::TargetOptions (e.g. "IEEE754FPE"), then -std=c99 or
> >>     separate option could enable it from front-end (Clang in this case).
> >> 
> >>     I'm doing this for ARM platform and the flag should be reachable from
> >>     all these places in LLVM:
> >> 
> >>     A - lib/Analysis/ValueTracking.cpp
> >>     A - lib/CodeGen/SelectionDAG/SelectionDAG.cpp
> >>     A - lib/IR/ConstantFold.cpp
> >>     A - lib/Target/ARM/ARMFastISel.cpp
> >>     A - lib/Target/ARM/ARMISelLowering.cpp
> >>     A - lib/Target/ARM/ARMInstrVFP.td (through predicates)
> >>     A - lib/Target/ARM/ARMRegisterInfo.td (through predicates)
> >> 
> >>     and in Clang:
> >> 
> >>     A - lib/AST/ExprConstant.cpp
> >> 
> >>     Did I get it right and there is no such flag so far?A  Does what I'm
> >>     suggesting sounds reasonable?
> >> 
> >>     Thanks,
> >>     Sergey
-------------- next part --------------
Subject: [PATCH 1/7] Do not emit intermediate register for zero FP imm

---
 lib/Target/ARM/ARMISelLowering.cpp     | 12 ++++++++++++
 test/CodeGen/ARM/fpcmp-f64-neon-opt.ll | 12 ++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 test/CodeGen/ARM/fpcmp-f64-neon-opt.ll

diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index ca6b614..48e038f 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -3240,6 +3240,18 @@ static bool isFloatingPointZero(SDValue Op) {
         if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
           return CFP->getValueAPF().isPosZero();
     }
+  } else if (Op->getOpcode() == ISD::BITCAST &&
+             Op->getValueType(0) == MVT::f64) {
+    // Handle (ISD::BITCAST (ARMISD::VMOVIMM (ISD::TargetConstant 0)) MVT::f64)
+    // created by LowerConstantFP().
+    SDValue BitcastOp = Op->getOperand(0);
+    if (BitcastOp->getOpcode() == ARMISD::VMOVIMM) {
+      SDValue MoveOp = BitcastOp->getOperand(0);
+      if (MoveOp->getOpcode() == ISD::TargetConstant &&
+          cast<ConstantSDNode>(MoveOp)->getZExtValue() == 0) {
+        return true;
+      }
+    }
   }
   return false;
 }
diff --git a/test/CodeGen/ARM/fpcmp-f64-neon-opt.ll b/test/CodeGen/ARM/fpcmp-f64-neon-opt.ll
new file mode 100644
index 0000000..7444a68
--- /dev/null
+++ b/test/CodeGen/ARM/fpcmp-f64-neon-opt.ll
@@ -0,0 +1,12 @@
+; RUN: llc -mtriple=linux-arm-gnueabihf -mattr=+neon %s -o - | FileCheck %s
+
+; Check that no intermediate integer register is used.
+define i32 @no-intermediate-register-for-zero-imm(double %x) #0 {
+entry:
+; CHECK-LABEL: no-intermediate-register-for-zero-imm
+; CHECK-NOT: vmov
+; CHECK: vcmp
+  %cmp = fcmp une double %x, 0.000000e+00
+  %conv = zext i1 %cmp to i32
+  ret i32 %conv
+}
-- 
1.8.4

-------------- next part --------------
Subject: [PATCH 2/7] Double check for constant expression domination

---
 lib/Transforms/Utils/SimplifyCFG.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index a01f9b0..c5205ce 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -267,7 +267,7 @@ static bool DominatesMergePoint(Value *V, BasicBlock *BB,
     // Non-instructions all dominate instructions, but not all constantexprs
     // can be executed unconditionally.
     if (ConstantExpr *C = dyn_cast<ConstantExpr>(V))
-      if (C->canTrap())
+      if (C->canTrap() || !isSafeToSpeculativelyExecute(V, DL))
         return false;
     return true;
   }
-- 
1.8.4

-------------- next part --------------
Subject: [PATCH 3/7] 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 --------------
Subject: [PATCH 4/7] 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 --------------
Subject: [PATCH 5/7] Skip constant folding to preserve FP exceptions

---
 include/llvm/Analysis/ValueTracking.h |  3 ++-
 lib/Analysis/ValueTracking.cpp        | 42 ++++++++++++++++++++++++++++++++-
 lib/IR/ConstantFold.cpp               | 44 +++++++++++++++++++++++++----------
 lib/IR/ConstantFold.h                 |  2 +-
 lib/IR/Constants.cpp                  |  2 +-
 5 files changed, 77 insertions(+), 16 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/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp
index f208bb7..9a67a82 100644
--- a/lib/Analysis/ValueTracking.cpp
+++ b/lib/Analysis/ValueTracking.cpp
@@ -2508,7 +2508,8 @@ 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;
@@ -2521,6 +2522,45 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
   switch (Inst->getOpcode()) {
   default:
     return true;
+  case Instruction::FMul:
+  case Instruction::FAdd:
+  case Instruction::FSub:
+  case Instruction::FDiv: {
+    if (!HonorFPExceptions) {
+      return true;
+    }
+
+    ConstantFP *LHSC = dyn_cast<ConstantFP>(Inst->getOperand(0));
+    ConstantFP *RHSC = dyn_cast<ConstantFP>(Inst->getOperand(1));
+
+    if (!LHSC || !RHSC) {
+      return true;
+    }
+
+    APFloat LHS = dyn_cast<ConstantFP>(Inst->getOperand(0))->getValueAPF();
+    APFloat RHS = dyn_cast<ConstantFP>(Inst->getOperand(1))->getValueAPF();
+    APFloat::opStatus status;
+
+    switch (Inst->getOpcode()) {
+      default:
+        status = APFloat::opOK;
+        break;
+      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);
+  }
   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..69682a4 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -1892,7 +1892,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())
-- 
1.8.4

-------------- next part --------------
Subject: [PATCH 6/7] Pass HonorFPExceptions flag around

---
 include/llvm/Analysis/ConstantFolding.h |  9 ++++++---
 include/llvm/Analysis/TargetFolder.h    | 13 +++++++-----
 include/llvm/IR/ConstantFolder.h        | 15 ++++++++------
 include/llvm/IR/Constants.h             |  9 ++++++---
 include/llvm/IR/IRBuilder.h             |  5 +++--
 lib/Analysis/ConstantFolding.cpp        | 35 ++++++++++++++++++++++-----------
 lib/IR/Constants.cpp                    | 17 ++++++++++------
 7 files changed, 66 insertions(+), 37 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..e9b2ba17 100644
--- a/include/llvm/Analysis/TargetFolder.h
+++ b/include/llvm/Analysis/TargetFolder.h
@@ -62,11 +62,14 @@ public:
     return Fold(ConstantExpr::getFSub(LHS, RHS));
   }
   Constant *CreateMul(Constant *LHS, Constant *RHS,
-                      bool HasNUW = false, bool HasNSW = false) const {
-    return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW));
-  }
-  Constant *CreateFMul(Constant *LHS, Constant *RHS) const {
-    return Fold(ConstantExpr::getFMul(LHS, RHS));
+                      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,
+                       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));
diff --git a/include/llvm/IR/ConstantFolder.h b/include/llvm/IR/ConstantFolder.h
index e271a14..554db21 100644
--- a/include/llvm/IR/ConstantFolder.h
+++ b/include/llvm/IR/ConstantFolder.h
@@ -46,11 +46,13 @@ public:
     return ConstantExpr::getFSub(LHS, RHS);
   }
   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 {
@@ -95,8 +97,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 122dda2..6eee47c 100644
--- a/include/llvm/IR/Constants.h
+++ b/include/llvm/IR/Constants.h
@@ -843,8 +843,10 @@ public:
                           bool HasNUW = false, bool HasNSW = false);
   static Constant *getFSub(Constant *C1, Constant *C2);
   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);
@@ -1013,7 +1015,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..1024990 100644
--- a/include/llvm/IR/IRBuilder.h
+++ b/include/llvm/IR/IRBuilder.h
@@ -704,10 +704,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);
   }
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 69682a4..de827c1 100644
--- a/lib/IR/Constants.cpp
+++ b/lib/IR/Constants.cpp
@@ -1826,7 +1826,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   &&
@@ -1892,8 +1893,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;
@@ -2232,14 +2235,16 @@ Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2) {
 }
 
 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) {
-- 
1.8.4

-------------- next part --------------
Subject: [PATCH 7/7] 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 c5205ce..d341afd 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



More information about the llvm-dev mailing list