Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -882,9 +882,13 @@ void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + // Flags to control and limit possible optimizations. + FastMathFlags FMF; + protected: - ConstantExpr(Type *ty, unsigned Opcode, Use *Ops, unsigned NumOps) - : Constant(ty, ConstantExprVal, Ops, NumOps) { + ConstantExpr(Type *ty, unsigned Opcode, Use *Ops, unsigned NumOps, + FastMathFlags FMF = FastMathFlags()) + : Constant(ty, ConstantExprVal, Ops, NumOps), FMF(FMF) { // Operation type (an Instruction opcode) is stored as the SubclassData. setValueSubclassData(Opcode); } @@ -1231,6 +1235,9 @@ /// would make it harder to remove ConstantExprs altogether. Instruction *getAsInstruction(); + /// Returns fast math flags for this constant expression. + FastMathFlags getFastMathFlags() const { return FMF; } + /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { return V->getValueID() == ConstantExprVal; Index: include/llvm/IR/FastMathFlags.h =================================================================== --- include/llvm/IR/FastMathFlags.h +++ include/llvm/IR/FastMathFlags.h @@ -21,6 +21,7 @@ class FastMathFlags { private: friend class FPMathOperator; + friend class ConstantExprKeyType; unsigned Flags; FastMathFlags(unsigned F) : Flags(F) { } Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -1004,6 +1004,8 @@ const TargetLibraryInfo *TLI, FastMathFlags FMF) { SmallPtrSet FoldedOps; + if (!FMF.any()) + FMF = CE->getFastMathFlags(); return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps, FMF); } Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -2961,6 +2961,13 @@ Constant *Val0, *Val1; Lex.Lex(); LocTy ModifierLoc = Lex.getLoc(); + + FastMathFlags FMF; + if (Opc == Instruction::FAdd || Opc == Instruction::FSub || + Opc == Instruction::FMul || Opc == Instruction::FDiv || + Opc == Instruction::FRem) + FMF = EatFastMathFlagsIfPresent(); + if (Opc == Instruction::Add || Opc == Instruction::Sub || Opc == Instruction::Mul || Opc == Instruction::Shl) { if (EatIfPresent(lltok::kw_nuw)) @@ -3018,7 +3025,7 @@ 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, FMF); ID.ConstantVal = C; ID.Kind = ValID::t_Constant; return false; Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1056,22 +1056,29 @@ } static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { - if (const FPMathOperator *FPO = dyn_cast(U)) { + FastMathFlags FMF; + + if (const FPMathOperator *FPO = dyn_cast(U)) + FMF = FPO->getFastMathFlags(); + else if (const ConstantExpr *CE = dyn_cast(U)) + FMF = CE->getFastMathFlags(); + + if (FMF.any()) { // Unsafe algebra implies all the others, no need to write them all out - if (FPO->hasUnsafeAlgebra()) + if (FMF.unsafeAlgebra()) Out << " fast"; else { - if (FPO->hasNoNaNs()) + if (FMF.noNaNs()) Out << " nnan"; - if (FPO->hasNoInfs()) + if (FMF.noInfs()) Out << " ninf"; - if (FPO->hasNoSignedZeros()) + if (FMF.noSignedZeros()) Out << " nsz"; - if (FPO->hasAllowReciprocal()) + if (FMF.allowReciprocal()) Out << " arcp"; - if (FPO->hasNoExceptions()) + if (FMF.noExceptions()) Out << " nexc"; - if (FPO->hasNoRounding()) + if (FMF.noRounding()) Out << " nrnd"; } } Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -1887,7 +1887,7 @@ return nullptr; Constant *ArgVec[] = { C1, C2 }; - ConstantExprKeyType Key(Opcode, ArgVec, 0, Flags); + ConstantExprKeyType Key(Opcode, ArgVec, 0, Flags, FMF); LLVMContextImpl *pImpl = C1->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(C1->getType(), Key); @@ -2017,8 +2017,8 @@ ArgVec.push_back(cast(Idxs[i])); } const ConstantExprKeyType Key(Instruction::GetElementPtr, ArgVec, 0, - InBounds ? GEPOperator::IsInBounds : 0, None, - Ty); + InBounds ? GEPOperator::IsInBounds : 0, + FastMathFlags(), None, Ty); LLVMContextImpl *pImpl = C->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(ReqTy, Key); @@ -2159,7 +2159,8 @@ return nullptr; Constant *ArgVec[] = { Agg, Val }; - const ConstantExprKeyType Key(Instruction::InsertValue, ArgVec, 0, 0, Idxs); + const ConstantExprKeyType Key(Instruction::InsertValue, ArgVec, 0, 0, + FastMathFlags(), Idxs); LLVMContextImpl *pImpl = Agg->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(ReqTy, Key); @@ -2183,7 +2184,8 @@ return nullptr; Constant *ArgVec[] = { Agg }; - const ConstantExprKeyType Key(Instruction::ExtractValue, ArgVec, 0, 0, Idxs); + const ConstantExprKeyType Key(Instruction::ExtractValue, ArgVec, 0, 0, + FastMathFlags(), Idxs); LLVMContextImpl *pImpl = Agg->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(ReqTy, Key); Index: lib/IR/ConstantsContext.h =================================================================== --- lib/IR/ConstantsContext.h +++ lib/IR/ConstantsContext.h @@ -58,8 +58,8 @@ return User::operator new(s, 2); } BinaryConstantExpr(unsigned Opcode, Constant *C1, Constant *C2, - unsigned Flags) - : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2) { + unsigned Flags, FastMathFlags FMF) + : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2, FMF) { Op<0>() = C1; Op<1>() = C2; SubclassOptionalData = Flags; @@ -420,6 +420,7 @@ uint8_t Opcode; uint8_t SubclassOptionalData; uint16_t SubclassData; + FastMathFlags FMF; ArrayRef Ops; ArrayRef Indexes; Type *ExplicitTy; @@ -427,21 +428,24 @@ ConstantExprKeyType(unsigned Opcode, ArrayRef Ops, unsigned short SubclassData = 0, unsigned short SubclassOptionalData = 0, + FastMathFlags FMF = FastMathFlags(), ArrayRef Indexes = None, Type *ExplicitTy = nullptr) : Opcode(Opcode), SubclassOptionalData(SubclassOptionalData), - SubclassData(SubclassData), Ops(Ops), Indexes(Indexes), + SubclassData(SubclassData), FMF(FMF), Ops(Ops), Indexes(Indexes), ExplicitTy(ExplicitTy) {} ConstantExprKeyType(ArrayRef Operands, const ConstantExpr *CE) : Opcode(CE->getOpcode()), SubclassOptionalData(CE->getRawSubclassOptionalData()), - SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Ops(Operands), + SubclassData(CE->isCompare() ? CE->getPredicate() : 0), + FMF(CE->getFastMathFlags()), Ops(Operands), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()) {} ConstantExprKeyType(const ConstantExpr *CE, SmallVectorImpl &Storage) : Opcode(CE->getOpcode()), SubclassOptionalData(CE->getRawSubclassOptionalData()), SubclassData(CE->isCompare() ? CE->getPredicate() : 0), + FMF(CE->getFastMathFlags()), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()) { assert(Storage.empty() && "Expected empty storage"); for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I) @@ -451,8 +455,8 @@ bool operator==(const ConstantExprKeyType &X) const { return Opcode == X.Opcode && SubclassData == X.SubclassData && - SubclassOptionalData == X.SubclassOptionalData && Ops == X.Ops && - Indexes == X.Indexes; + SubclassOptionalData == X.SubclassOptionalData && + FMF.Flags == X.FMF.Flags && Ops == X.Ops && Indexes == X.Indexes; } bool operator==(const ConstantExpr *CE) const { @@ -460,6 +464,8 @@ return false; if (SubclassOptionalData != CE->getRawSubclassOptionalData()) return false; + if (FMF.Flags != CE->getFastMathFlags().Flags) + return false; if (Ops.size() != CE->getNumOperands()) return false; if (SubclassData != (CE->isCompare() ? CE->getPredicate() : 0)) @@ -473,7 +479,7 @@ } unsigned getHash() const { - return hash_combine(Opcode, SubclassOptionalData, SubclassData, + return hash_combine(Opcode, SubclassOptionalData, SubclassData, FMF.Flags, hash_combine_range(Ops.begin(), Ops.end()), hash_combine_range(Indexes.begin(), Indexes.end())); } @@ -487,7 +493,7 @@ if ((Opcode >= Instruction::BinaryOpsBegin && Opcode < Instruction::BinaryOpsEnd)) return new BinaryConstantExpr(Opcode, Ops[0], Ops[1], - SubclassOptionalData); + SubclassOptionalData, FMF); llvm_unreachable("Invalid ConstantExpr!"); case Instruction::Select: return new SelectConstantExpr(Ops[0], Ops[1], Ops[2]); Index: test/Other/fpenv-constant-fold.ll =================================================================== --- test/Other/fpenv-constant-fold.ll +++ test/Other/fpenv-constant-fold.ll @@ -7,74 +7,65 @@ define double @do-not-fold-fadd-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fadd-that-can-trap -; CHECK: fadd nrnd double 1.000000e+308, 1.000000e+308 +; CHECK: ret double fadd nrnd (double 1.000000e+308, double 1.000000e+308) entry: - %val = fadd nrnd double 1.000000e+308, 1.000000e+308 - ret double %val + ret double fadd nrnd (double 1.000000e+308, double 1.000000e+308) } define double @do-not-fold-fsub-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fsub-that-can-trap -; CHECK: fsub nrnd double 1.000000e-308, 1.000000e+308 +; CHECK: ret double fsub nrnd (double 1.000000e-308, double 1.000000e+308) entry: - %val = fsub nrnd double 1.000000e-308, 1.000000e+308 - ret double %val + ret double fsub nrnd (double 1.000000e-308, double 1.000000e+308) } define double @do-not-fold-fmul-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fmul-that-can-trap -; CHECK: fmul nrnd double 1.000000e+300, 1.000000e+300 +; CHECK: ret double fmul nrnd (double 1.000000e+300, double 1.000000e+300) entry: - %val = fmul nrnd double 1.000000e+300, 1.000000e+300 - ret double %val + ret double fmul nrnd (double 1.000000e+300, double 1.000000e+300) } define double @do-not-fold-fdiv-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fdiv-that-can-trap -; CHECK: fdiv nrnd double 1.000000e+300, 1.000000e-300 +; CHECK: ret double fdiv nrnd (double 1.000000e+300, double 1.000000e-300) entry: - %val = fdiv nrnd double 1.000000e+300, 1.000000e-300 - ret double %val + ret double fdiv nrnd (double 1.000000e+300, double 1.000000e-300) } define double @do-not-fold-frem-that-can-trap() { ; CHECK-LABEL: @do-not-fold-frem-that-can-trap -; CHECK: frem nrnd double 1.000000e+300, 1.000000e-300 +; CHECK: ret double frem nrnd (double 1.000000e+300, double 1.000000e-300) entry: - %val = frem nrnd double 1.000000e+300, 1.000000e-300 - ret double %val + ret double frem nrnd (double 1.000000e+300, double 1.000000e-300) } define double @do-not-fold-fadd-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fadd-because-of-rounding -; CHECK: fadd nexc double 0.101, 0.93 +; CHECK: ret double fadd nexc (double 1.010000e-01, double 9.300000e-01) entry: - %val = fadd nexc double 0.101, 0.93 - ret double %val + ret double fadd nexc (double 0.101, double 0.93) } define double @do-not-fold-fsub-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding -; CHECK: fsub nexc double 0.101, 0.93 +; CHECK: ret double fsub nexc (double 1.010000e-01, double 9.300000e-01) entry: - %val = fsub nexc double 0.101, 0.93 - ret double %val + ret double fsub nexc (double 0.101, double 0.93) } define double @do-not-fold-fmul-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fmul-because-of-rounding -; CHECK: fmul nexc double 0.101, 0.93 +; CHECK: ret double fmul nexc (double 1.010000e-01, double 9.300000e-01) entry: - %val = fmul nexc double 0.101, 0.93 - ret double %val + ret double fmul nexc (double 0.101, double 0.93) } define double @do-not-fold-fdiv-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fdiv-because-of-rounding -; CHECK: fdiv nexc double 0.101, 0.93 +; CHECK: ret double fdiv nexc (double 1.010000e-01, double 9.300000e-01) entry: - %val = fdiv nexc double 0.101, 0.93 - ret double %val + ret double fdiv nexc (double 0.101, double 0.93) } ; "frem" instruction falls into the same category, but none of tried test-cases @@ -84,47 +75,40 @@ ; CHECK-LABEL: @fold-fadd-that-cant-trap ; CHECK-NOT: fadd entry: - %val = fadd double 1.0, 1.0 - ret double %val + ret double fadd (double 1.0, double 1.0) } define double @fold-fsub-that-cant-trap() { ; CHECK-LABEL: @fold-fsub-that-cant-trap ; CHECK-NOT: fsub entry: - %val = fsub double 1.0, 1.0 - ret double %val + ret double fsub (double 1.0, double 1.0) } define double @fold-fmul-that-cant-trap() { ; CHECK-LABEL: @fold-fmul-that-cant-trap ; CHECK-NOT: fmul entry: - %val = fmul double 1.0, 1.0 - ret double %val + ret double fmul (double 1.0, double 1.0) } define double @fold-fdiv-that-cant-trap() { ; CHECK-LABEL: @fold-fdiv-that-cant-trap ; CHECK-NOT: fdiv entry: - %val = fdiv double 1.0, 1.0 - ret double %val + ret double fdiv (double 1.0, double 1.0) } define double @fold-frem-that-cant-trap() { ; CHECK-LABEL: @fold-frem-that-cant-trap ; CHECK-NOT: frem entry: - %val = frem double 1.0, 1.0 - ret double %val + ret double frem (double 1.0, double 1.0) } define double @correcly-handle-nested-expressions() { ; CHECK-LABEL: @correcly-handle-nested-expressions -; CHECK: fmul nrnd double 1.000000e+300, 1.000000e+300 +; CHECK: ret double fdiv nrnd (double fmul nrnd (double 1.000000e+300, double 1.000000e+300), double 1.000000e+300) entry: - %val1 = fmul nrnd double 1.000000e+300, 1.000000e+300 - %val2 = fdiv nrnd double %val1, 1.000000e+300 - ret double %val2 + ret double fdiv nrnd (double fmul nrnd (double 1.000000e+300, double 1.000000e+300), double 1.000000e+300) } Index: test/Transforms/EarlyCSE/fpenv.ll =================================================================== --- /dev/null +++ test/Transforms/EarlyCSE/fpenv.ll @@ -0,0 +1,23 @@ +; %val.true and %val.false should not be moved inside phi-node as constant +; expressions as such transformation looses fast-math flags. +; RUN: opt < %s -S -early-cse | FileCheck %s + +define double @do-not-fold-on-turning-into-constexpr(double %x) { +; CHECK-LABEL: @do-not-fold-on-turning-into-constexpr( +; CHECK: fmul +entry: + %cmp = fcmp oeq double %x, 0.000000e+00 + br i1 %cmp, label %cond.true, label %cond.false + +cond.true: ; preds = %entry + %val.true = fmul nrnd double 1.000000e+300, 1.000000e+300 + br label %cond.end + +cond.false: ; preds = %entry + %val.false = fmul nrnd double 1.000000e-300, 1.000000e-300 + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi double [ %val.true, %cond.true ], [ %val.false, %cond.false ] + ret double %cond +}