Index: include/llvm/Analysis/ConstantFolding.h =================================================================== --- include/llvm/Analysis/ConstantFolding.h +++ include/llvm/Analysis/ConstantFolding.h @@ -46,8 +46,7 @@ /// result is returned, if not, null is returned. Constant * ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr, - FastMathFlags FMF = FastMathFlags()); + const TargetLibraryInfo *TLI = nullptr); /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the /// specified operands. If successful, the constant result is returned, if not, 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,8 @@ class FastMathFlags { private: friend class FPMathOperator; + friend class ConstantExpr; + friend class ConstantExprKeyType; unsigned Flags; FastMathFlags(unsigned F) : Flags(F) { } Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -894,11 +894,6 @@ /// and stores, which have no constant expression form. Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL, const TargetLibraryInfo *TLI) { - FastMathFlags FMF; - - if (isa(I)) - FMF = I->getFastMathFlags(); - // Handle PHI nodes quickly here... if (PHINode *PN = dyn_cast(I)) { Constant *CommonValue = nullptr; @@ -916,7 +911,7 @@ return nullptr; // Fold the PHI's operands. if (ConstantExpr *NewC = dyn_cast(C)) - C = ConstantFoldConstantExpression(NewC, DL, TLI, FMF); + C = ConstantFoldConstantExpression(NewC, DL, TLI); // If the incoming value is a different constant to // the one we saw previously, then give up. if (CommonValue && C != CommonValue) @@ -939,7 +934,7 @@ // Fold the Instruction's operands. if (ConstantExpr *NewCE = dyn_cast(Op)) - if (Constant *C = ConstantFoldConstantExpression(NewCE, DL, TLI, FMF)) + if (Constant *C = ConstantFoldConstantExpression(NewCE, DL, TLI)) Op = C; Ops.push_back(Op); @@ -965,6 +960,9 @@ EVI->getIndices()); } + FastMathFlags FMF; + if (isa(I)) + FMF = I->getFastMathFlags(); return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI, FMF); } @@ -1001,10 +999,10 @@ /// result is returned, if not, null is returned. Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, - const TargetLibraryInfo *TLI, - FastMathFlags FMF) { + const TargetLibraryInfo *TLI) { SmallPtrSet FoldedOps; - return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps, FMF); + return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps, + CE->getFastMathFlags()); } /// Attempt to constant fold an instruction with the 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, FMF.Flags, Flags); LLVMContextImpl *pImpl = C1->getContext().pImpl; return pImpl->ExprConstants.getOrCreate(C1->getType(), 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; @@ -435,13 +435,16 @@ 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() : CE->getFastMathFlags().Flags), + 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), + SubclassData(CE->isCompare() ? + CE->getPredicate() : CE->getFastMathFlags().Flags), Indexes(CE->hasIndices() ? CE->getIndices() : ArrayRef()) { assert(Storage.empty() && "Expected empty storage"); for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I) @@ -462,7 +465,8 @@ return false; if (Ops.size() != CE->getNumOperands()) return false; - if (SubclassData != (CE->isCompare() ? CE->getPredicate() : 0)) + if (SubclassData != (CE->isCompare() ? + CE->getPredicate() : CE->getFastMathFlags().Flags)) return false; for (unsigned I = 0, E = Ops.size(); I != E; ++I) if (Ops[I] != CE->getOperand(I)) @@ -487,7 +491,8 @@ if ((Opcode >= Instruction::BinaryOpsBegin && Opcode < Instruction::BinaryOpsEnd)) return new BinaryConstantExpr(Opcode, Ops[0], Ops[1], - SubclassOptionalData); + SubclassOptionalData, + FastMathFlags(SubclassData)); 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 +}