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: 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)) @@ -2975,6 +2982,7 @@ if (EatIfPresent(lltok::kw_exact)) Exact = true; } + if (ParseToken(lltok::lparen, "expected '(' in binary constantexpr") || ParseGlobalTypeAndValue(Val0) || ParseToken(lltok::comma, "expected comma in binary constantexpr") || @@ -3018,7 +3026,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,10 +428,11 @@ 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()), @@ -487,7 +489,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 +}