Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -255,8 +255,9 @@ const TargetLibraryInfo *TLI = nullptr); /// isSafeToSpeculativelyExecute - Return true if the instruction does not - /// have any effects besides calculating the result and does not have - /// undefined behavior. + /// have any effects besides calculating the result (in a way that doesn't + /// lose floating-point exceptions or precision when requested via + /// corresponding flags) and does not have undefined behavior. /// /// This method never returns true for an instruction that returns true for /// mayHaveSideEffects; however, this method also does some other checks in @@ -281,7 +282,9 @@ bool isSafeToSpeculativelyExecute(const Value *V, const Instruction *CtxI = nullptr, const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const TargetLibraryInfo *TLI = nullptr, + bool KeepExceptions = false, + bool KeepRounding = false); /// Returns true if the result or effects of the given instructions \p I /// depend on or influence global memory. Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -1069,7 +1069,9 @@ /// /// \param OnlyIfReducedTy see \a getWithOperands() docs. static Constant *get(unsigned Opcode, Constant *C1, Constant *C2, - unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr); + unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr, + bool KeepExceptions = false, + bool KeepRounding = false); /// \brief Return an ICmp or FCmp comparison operator constant expression. /// @@ -1193,6 +1195,12 @@ return V->getValueID() == ConstantExprVal; } + /// Evaluates floating point operation to examine how it could affect + /// floating-environment at run-time if it's not folded, does nothing for + /// non-FP operations. Returns false for unsupported values, otherwise true + /// is returned and S is assigned status of the operation. + static bool getFPOpExceptions(const Value *V, APFloat::opStatus &S); + private: // Shadow Value::setValueSubclassData with a private forwarding method so that // subclasses cannot accidentally use it. Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3280,11 +3280,18 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V, const Instruction *CtxI, const DominatorTree *DT, - const TargetLibraryInfo *TLI) { + const TargetLibraryInfo *TLI, + bool KeepExceptions, + bool KeepRounding) { const Operator *Inst = dyn_cast(V); if (!Inst) return false; + if (const FPMathOperator *MathOp = dyn_cast(Inst)) { + KeepExceptions |= MathOp->hasKeepExceptions(); + KeepRounding |= MathOp->hasKeepRounding(); + } + for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i) if (Constant *C = dyn_cast(Inst->getOperand(i))) if (C->canTrap()) @@ -3293,6 +3300,22 @@ switch (Inst->getOpcode()) { default: return true; + case Instruction::FMul: + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FDiv: + case Instruction::FRem: + if (KeepExceptions || KeepRounding) { + APFloat::opStatus S; + if (!ConstantExpr::getFPOpExceptions(Inst, S)) + return false; + + if (KeepExceptions && S != APFloat::opOK) + return false; + if (KeepRounding && (S & APFloat::opInexact)) + return false; + } + return true; case Instruction::UDiv: case Instruction::URem: { // x / y is undefined if y == 0. Index: lib/IR/ConstantFold.h =================================================================== --- lib/IR/ConstantFold.h +++ lib/IR/ConstantFold.h @@ -44,7 +44,8 @@ Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef Idxs); Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1, - Constant *V2); + Constant *V2, bool KeepFPExceptions, + bool KeepFPRounding); Constant *ConstantFoldCompareInstruction(unsigned short predicate, Constant *C1, Constant *C2); Constant *ConstantFoldGetElementPtr(Constant *C, bool inBounds, Index: lib/IR/ConstantFold.cpp =================================================================== --- lib/IR/ConstantFold.cpp +++ lib/IR/ConstantFold.cpp @@ -915,7 +915,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, - Constant *C1, Constant *C2) { + Constant *C1, Constant *C2, + bool KeepExceptions, + bool KeepRounding) { // Handle UndefValue up front. if (isa(C1) || isa(C2)) { switch (Opcode) { @@ -1099,7 +1101,8 @@ } else if (isa(C1)) { // If C1 is a ConstantInt and C2 is not, swap the operands. if (Instruction::isCommutative(Opcode)) - return ConstantExpr::get(Opcode, C2, C1); + return ConstantExpr::get(Opcode, C2, C1, 0, nullptr, KeepExceptions, + KeepRounding); } // At this point we know neither constant is an UndefValue. @@ -1171,23 +1174,39 @@ APFloat C1V = CFP1->getValueAPF(); APFloat C2V = CFP2->getValueAPF(); APFloat C3V = C1V; // copy for modification + APFloat::opStatus S; switch (Opcode) { - default: + default: break; case Instruction::FAdd: - (void)C3V.add(C2V, APFloat::rmNearestTiesToEven); + S = C3V.add(C2V, APFloat::rmNearestTiesToEven); + if ((KeepExceptions && S != APFloat::opOK) || + (KeepRounding && (S & APFloat::opInexact))) + break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FSub: - (void)C3V.subtract(C2V, APFloat::rmNearestTiesToEven); + S = C3V.subtract(C2V, APFloat::rmNearestTiesToEven); + if ((KeepExceptions && S != APFloat::opOK) || + (KeepRounding && (S & APFloat::opInexact))) + break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FMul: - (void)C3V.multiply(C2V, APFloat::rmNearestTiesToEven); + S = C3V.multiply(C2V, APFloat::rmNearestTiesToEven); + if ((KeepExceptions && S != APFloat::opOK) || + (KeepRounding && (S & APFloat::opInexact))) + break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FDiv: - (void)C3V.divide(C2V, APFloat::rmNearestTiesToEven); + S = C3V.divide(C2V, APFloat::rmNearestTiesToEven); + if ((KeepExceptions && S != APFloat::opOK) || + (KeepRounding && (S & APFloat::opInexact))) + break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FRem: - (void)C3V.mod(C2V); + S = C3V.mod(C2V); + if ((KeepExceptions && S != APFloat::opOK) || + (KeepRounding && (S & APFloat::opInexact))) + break; return ConstantFP::get(C1->getContext(), C3V); } } @@ -1200,10 +1219,11 @@ ConstantExpr::getExtractElement(C1, ConstantInt::get(Ty, i)); Constant *RHS = ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, i)); - - Result.push_back(ConstantExpr::get(Opcode, LHS, RHS)); + + Result.push_back(ConstantExpr::get(Opcode, LHS, RHS, 0, nullptr, + KeepExceptions, KeepRounding)); } - + return ConstantVector::get(Result); } @@ -1215,15 +1235,18 @@ // Given ((a + b) + c), if (b + c) folds to something interesting, return // (a + (b + c)). if (Instruction::isAssociative(Opcode) && CE1->getOpcode() == Opcode) { - Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2); + Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2, 0, + nullptr, KeepExceptions, KeepRounding); if (!isa(T) || cast(T)->getOpcode() != Opcode) - return ConstantExpr::get(Opcode, CE1->getOperand(0), T); + return ConstantExpr::get(Opcode, CE1->getOperand(0), T, 0, nullptr, + KeepExceptions, KeepRounding); } } else if (isa(C2)) { // If C2 is a constant expr and C1 isn't, flop them around and fold the // other way if possible. if (Instruction::isCommutative(Opcode)) - return ConstantFoldBinaryInstruction(Opcode, C2, C1); + return ConstantFoldBinaryInstruction(Opcode, C2, C1, KeepExceptions, + KeepRounding); } // i1 can be simplified in many cases. Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -327,8 +327,9 @@ // ConstantExpr traps if any operands can trap. for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) { if (ConstantExpr *Op = dyn_cast(CE->getOperand(i))) { - if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps)) + if (NonTrappingOps.insert(Op).second && canTrapImpl(Op, NonTrappingOps)) { return true; + } } } @@ -1869,7 +1870,8 @@ } Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2, - unsigned Flags, Type *OnlyIfReducedTy) { + unsigned Flags, Type *OnlyIfReducedTy, + bool KeepExceptions, bool KeepRounding) { // Check the operands for consistency first. assert(Opcode >= Instruction::BinaryOpsBegin && Opcode < Instruction::BinaryOpsEnd && @@ -1935,8 +1937,11 @@ } #endif - if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2)) + if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2, + KeepExceptions, + KeepRounding)) { return FC; // Fold a few common cases. + } if (OnlyIfReducedTy == C1->getType()) return nullptr; @@ -3091,3 +3096,57 @@ return BO; } } + +bool ConstantExpr::getFPOpExceptions(const Value *V, APFloat::opStatus &S) { + unsigned Opcode; + const User *U; + if (const Operator *Op = dyn_cast(V)) { + U = Op; + Opcode = Op->getOpcode(); + } if (const ConstantExpr *C = dyn_cast(V)) { + U = C; + Opcode = C->getOpcode(); + } else { + return false; + } + + switch (Opcode) { + default: + return true; + case Instruction::FMul: + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FDiv: + case Instruction::FRem: { + ConstantFP *LHSC = dyn_cast(U->getOperand(0)); + ConstantFP *RHSC = dyn_cast(U->getOperand(1)); + + if (!LHSC || !RHSC) { + return false; + } + + APFloat LHS = LHSC->getValueAPF(); + APFloat RHS = LHSC->getValueAPF(); + + switch (Opcode) { + case Instruction::FMul: + S = LHS.multiply(RHS, APFloat::rmNearestTiesToEven); + break; + case Instruction::FAdd: + S = LHS.add(RHS, APFloat::rmNearestTiesToEven); + break; + case Instruction::FSub: + S = LHS.subtract(RHS, APFloat::rmNearestTiesToEven); + break; + case Instruction::FDiv: + S = LHS.divide(RHS, APFloat::rmNearestTiesToEven); + break; + case Instruction::FRem: + S = LHS.mod(RHS); + break; + } + + return true; + } + } +}