Index: include/llvm/Analysis/ConstantFolding.h =================================================================== --- include/llvm/Analysis/ConstantFolding.h +++ include/llvm/Analysis/ConstantFolding.h @@ -20,6 +20,8 @@ #ifndef LLVM_ANALYSIS_CONSTANTFOLDING_H #define LLVM_ANALYSIS_CONSTANTFOLDING_H +#include "llvm/IR/FastMathFlags.h" + namespace llvm { class Constant; class ConstantExpr; @@ -44,7 +46,8 @@ /// result is returned, if not, null is returned. Constant * ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); + const TargetLibraryInfo *TLI = nullptr, + FastMathFlags FMF = FastMathFlags()); /// ConstantFoldInstOperands - Attempt to constant fold an instruction with the /// specified operands. If successful, the constant result is returned, if not, @@ -55,7 +58,8 @@ Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy, ArrayRef Ops, const DataLayout &DL, - const TargetLibraryInfo *TLI = nullptr); + const TargetLibraryInfo *TLI = nullptr, + FastMathFlags FMF = FastMathFlags()); /// ConstantFoldCompareInstOperands - Attempt to constant fold a compare /// instruction (icmp/fcmp) with the specified operands. If it fails, it Index: include/llvm/Analysis/TargetFolder.h =================================================================== --- include/llvm/Analysis/TargetFolder.h +++ include/llvm/Analysis/TargetFolder.h @@ -22,6 +22,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/FastMathFlags.h" #include "llvm/IR/InstrTypes.h" namespace llvm { @@ -51,22 +52,25 @@ bool HasNUW = false, bool HasNSW = false) const { return Fold(ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW)); } - Constant *CreateFAdd(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getFAdd(LHS, RHS)); + Constant *CreateFAdd(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return Fold(ConstantExpr::getFAdd(LHS, RHS, FMF)); } Constant *CreateSub(Constant *LHS, Constant *RHS, bool HasNUW = false, bool HasNSW = false) const { return Fold(ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW)); } - Constant *CreateFSub(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getFSub(LHS, RHS)); + Constant *CreateFSub(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return Fold(ConstantExpr::getFSub(LHS, RHS, FMF)); } 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)); + Constant *CreateFMul(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return Fold(ConstantExpr::getFMul(LHS, RHS, FMF)); } Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{ return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact)); @@ -74,8 +78,9 @@ Constant *CreateSDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{ return Fold(ConstantExpr::getSDiv(LHS, RHS, isExact)); } - Constant *CreateFDiv(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getFDiv(LHS, RHS)); + Constant *CreateFDiv(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return Fold(ConstantExpr::getFDiv(LHS, RHS, FMF)); } Constant *CreateURem(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getURem(LHS, RHS)); @@ -83,8 +88,9 @@ Constant *CreateSRem(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getSRem(LHS, RHS)); } - Constant *CreateFRem(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getFRem(LHS, RHS)); + Constant *CreateFRem(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return Fold(ConstantExpr::getFRem(LHS, RHS, FMF)); } Constant *CreateShl(Constant *LHS, Constant *RHS, bool HasNUW = false, bool HasNSW = false) const { Index: include/llvm/IR/ConstantFolder.h =================================================================== --- include/llvm/IR/ConstantFolder.h +++ include/llvm/IR/ConstantFolder.h @@ -18,6 +18,7 @@ #define LLVM_IR_CONSTANTFOLDER_H #include "llvm/IR/Constants.h" +#include "llvm/IR/FastMathFlags.h" #include "llvm/IR/InstrTypes.h" namespace llvm { @@ -35,22 +36,25 @@ bool HasNUW = false, bool HasNSW = false) const { return ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW); } - Constant *CreateFAdd(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getFAdd(LHS, RHS); + Constant *CreateFAdd(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::getFAdd(LHS, RHS, FMF); } Constant *CreateSub(Constant *LHS, Constant *RHS, bool HasNUW = false, bool HasNSW = false) const { return ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW); } - Constant *CreateFSub(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getFSub(LHS, RHS); + Constant *CreateFSub(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::getFSub(LHS, RHS, FMF); } Constant *CreateMul(Constant *LHS, Constant *RHS, bool HasNUW = false, bool HasNSW = false) const { return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW); } - Constant *CreateFMul(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getFMul(LHS, RHS); + Constant *CreateFMul(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::getFMul(LHS, RHS, FMF); } Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false) const { @@ -60,8 +64,9 @@ bool isExact = false) const { return ConstantExpr::getSDiv(LHS, RHS, isExact); } - Constant *CreateFDiv(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getFDiv(LHS, RHS); + Constant *CreateFDiv(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::getFDiv(LHS, RHS, FMF); } Constant *CreateURem(Constant *LHS, Constant *RHS) const { return ConstantExpr::getURem(LHS, RHS); @@ -69,8 +74,9 @@ Constant *CreateSRem(Constant *LHS, Constant *RHS) const { return ConstantExpr::getSRem(LHS, RHS); } - Constant *CreateFRem(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getFRem(LHS, RHS); + Constant *CreateFRem(Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::getFRem(LHS, RHS, FMF); } Constant *CreateShl(Constant *LHS, Constant *RHS, bool HasNUW = false, bool HasNSW = false) const { @@ -95,8 +101,9 @@ } Constant *CreateBinOp(Instruction::BinaryOps Opc, - Constant *LHS, Constant *RHS) const { - return ConstantExpr::get(Opc, LHS, RHS); + Constant *LHS, Constant *RHS, + FastMathFlags FMF = FastMathFlags()) const { + return ConstantExpr::get(Opc, LHS, RHS, 0, nullptr, FMF); } //===--------------------------------------------------------------------===// Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -26,6 +26,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/IR/Constant.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/FastMathFlags.h" #include "llvm/IR/OperandTraits.h" namespace llvm { @@ -894,19 +895,24 @@ static Constant *getNot(Constant *C); static Constant *getAdd(Constant *C1, Constant *C2, bool HasNUW = false, bool HasNSW = false); - static Constant *getFAdd(Constant *C1, Constant *C2); + static Constant *getFAdd(Constant *C1, Constant *C2, + FastMathFlags FMF = FastMathFlags()); static Constant *getSub(Constant *C1, Constant *C2, bool HasNUW = false, bool HasNSW = false); - static Constant *getFSub(Constant *C1, Constant *C2); + static Constant *getFSub(Constant *C1, Constant *C2, + FastMathFlags FMF = FastMathFlags()); static Constant *getMul(Constant *C1, Constant *C2, bool HasNUW = false, bool HasNSW = false); - static Constant *getFMul(Constant *C1, Constant *C2); + static Constant *getFMul(Constant *C1, Constant *C2, + FastMathFlags FMF = FastMathFlags()); 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); + static Constant *getFDiv(Constant *C1, Constant *C2, + FastMathFlags FMF = FastMathFlags()); static Constant *getURem(Constant *C1, Constant *C2); static Constant *getSRem(Constant *C1, Constant *C2); - static Constant *getFRem(Constant *C1, Constant *C2); + static Constant *getFRem(Constant *C1, Constant *C2, + FastMathFlags FMF = FastMathFlags()); static Constant *getAnd(Constant *C1, Constant *C2); static Constant *getOr(Constant *C1, Constant *C2); static Constant *getXor(Constant *C1, Constant *C2); @@ -1070,8 +1076,7 @@ /// \param OnlyIfReducedTy see \a getWithOperands() docs. static Constant *get(unsigned Opcode, Constant *C1, Constant *C2, unsigned Flags = 0, Type *OnlyIfReducedTy = nullptr, - bool KeepExceptions = false, - bool KeepRounding = false); + FastMathFlags FMF = FastMathFlags()); /// \brief Return an ICmp or FCmp comparison operator constant expression. /// Index: include/llvm/IR/FastMathFlags.h =================================================================== --- /dev/null +++ include/llvm/IR/FastMathFlags.h @@ -0,0 +1,78 @@ +//===- FastMathFlags.h - Fast math flags structure definition ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides convenience struct for specifying and reasoning about +// fast-math flags. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_FASTMATHFLAGS_H +#define LLVM_IR_FASTMATHFLAGS_H + +namespace llvm { + +/// Convenience struct for specifying and reasoning about fast-math flags. +class FastMathFlags { +private: + friend class FPMathOperator; + unsigned Flags; + FastMathFlags(unsigned F) : Flags(F) { } + +public: + enum { + UnsafeAlgebra = (1 << 0), + NoNaNs = (1 << 1), + NoInfs = (1 << 2), + NoSignedZeros = (1 << 3), + AllowReciprocal = (1 << 4), + KeepExceptions = (1 << 5), + KeepRounding = (1 << 6) + }; + + FastMathFlags() : Flags(0) + { } + + /// Whether any flag is set + bool any() const { return Flags != 0; } + + /// Set all the flags to false + void clear() { Flags = 0; } + + /// Flag queries + bool noNaNs() const { return 0 != (Flags & NoNaNs); } + bool noInfs() const { return 0 != (Flags & NoInfs); } + bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } + bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } + bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); } + bool keepExceptions() const { return 0 != (Flags & KeepExceptions); } + bool keepRounding()const { return 0 != (Flags & KeepRounding); } + + /// Flag setters + void setNoNaNs() { Flags |= NoNaNs; } + void setNoInfs() { Flags |= NoInfs; } + void setNoSignedZeros() { Flags |= NoSignedZeros; } + void setAllowReciprocal() { Flags |= AllowReciprocal; } + void setUnsafeAlgebra() { + Flags |= UnsafeAlgebra; + setNoNaNs(); + setNoInfs(); + setNoSignedZeros(); + setAllowReciprocal(); + } + void setKeepExceptions() { Flags |= KeepExceptions; } + void setKeepRounding() { Flags |= KeepRounding; } + + void operator&=(const FastMathFlags &OtherFlags) { + Flags &= OtherFlags.Flags; + } +}; + +} // End llvm namespace + +#endif Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -778,7 +778,7 @@ MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Insert(Folder.CreateFAdd(LC, RC), Name); + return Insert(Folder.CreateFAdd(LC, RC, FMF), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFAdd(LHS, RHS), FPMathTag, FMF), Name); } @@ -800,7 +800,7 @@ MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Insert(Folder.CreateFSub(LC, RC), Name); + return Insert(Folder.CreateFSub(LC, RC, FMF), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFSub(LHS, RHS), FPMathTag, FMF), Name); } @@ -822,7 +822,7 @@ MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Insert(Folder.CreateFMul(LC, RC), Name); + return Insert(Folder.CreateFMul(LC, RC, FMF), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFMul(LHS, RHS), FPMathTag, FMF), Name); } @@ -854,7 +854,7 @@ MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Insert(Folder.CreateFDiv(LC, RC), Name); + return Insert(Folder.CreateFDiv(LC, RC, FMF), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFDiv(LHS, RHS), FPMathTag, FMF), Name); } @@ -874,7 +874,7 @@ MDNode *FPMathTag = nullptr) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Insert(Folder.CreateFRem(LC, RC), Name); + return Insert(Folder.CreateFRem(LC, RC, FMF), Name); return Insert(AddFPMathAttributes(BinaryOperator::CreateFRem(LHS, RHS), FPMathTag, FMF), Name); } Index: include/llvm/IR/Operator.h =================================================================== --- include/llvm/IR/Operator.h +++ include/llvm/IR/Operator.h @@ -18,6 +18,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/FastMathFlags.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Type.h" @@ -160,62 +161,6 @@ } }; -/// Convenience struct for specifying and reasoning about fast-math flags. -class FastMathFlags { -private: - friend class FPMathOperator; - unsigned Flags; - FastMathFlags(unsigned F) : Flags(F) { } - -public: - enum { - UnsafeAlgebra = (1 << 0), - NoNaNs = (1 << 1), - NoInfs = (1 << 2), - NoSignedZeros = (1 << 3), - AllowReciprocal = (1 << 4), - KeepExceptions = (1 << 5), - KeepRounding = (1 << 6) - }; - - FastMathFlags() : Flags(0) - { } - - /// Whether any flag is set - bool any() const { return Flags != 0; } - - /// Set all the flags to false - void clear() { Flags = 0; } - - /// Flag queries - bool noNaNs() const { return 0 != (Flags & NoNaNs); } - bool noInfs() const { return 0 != (Flags & NoInfs); } - bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } - bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } - bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); } - bool keepExceptions() const { return 0 != (Flags & KeepExceptions); } - bool keepRounding()const { return 0 != (Flags & KeepRounding); } - - /// Flag setters - void setNoNaNs() { Flags |= NoNaNs; } - void setNoInfs() { Flags |= NoInfs; } - void setNoSignedZeros() { Flags |= NoSignedZeros; } - void setAllowReciprocal() { Flags |= AllowReciprocal; } - void setUnsafeAlgebra() { - Flags |= UnsafeAlgebra; - setNoNaNs(); - setNoInfs(); - setNoSignedZeros(); - setAllowReciprocal(); - } - void setKeepExceptions() { Flags |= KeepExceptions; } - void setKeepRounding() { Flags |= KeepRounding; } - - void operator&=(const FastMathFlags &OtherFlags) { - Flags &= OtherFlags.Flags; - } -}; - /// Utility class for floating point operations which can have /// information about relaxed accuracy requirements attached to them. Index: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -894,6 +894,12 @@ /// 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; @@ -911,7 +917,7 @@ return nullptr; // Fold the PHI's operands. if (ConstantExpr *NewC = dyn_cast(C)) - C = ConstantFoldConstantExpression(NewC, DL, TLI); + C = ConstantFoldConstantExpression(NewC, DL, TLI, FMF); // If the incoming value is a different constant to // the one we saw previously, then give up. if (CommonValue && C != CommonValue) @@ -934,7 +940,7 @@ // Fold the Instruction's operands. if (ConstantExpr *NewCE = dyn_cast(Op)) - Op = ConstantFoldConstantExpression(NewCE, DL, TLI); + Op = ConstantFoldConstantExpression(NewCE, DL, TLI, FMF); Ops.push_back(Op); } @@ -959,13 +965,15 @@ EVI->getIndices()); } - return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI); + return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops, DL, TLI, + FMF); } static Constant * ConstantFoldConstantExpressionImpl(const ConstantExpr *CE, const DataLayout &DL, const TargetLibraryInfo *TLI, - SmallPtrSetImpl &FoldedOps) { + SmallPtrSetImpl &FoldedOps, + FastMathFlags FMF) { SmallVector Ops; for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); i != e; ++i) { @@ -974,7 +982,8 @@ // a ConstantExpr, we don't have to process it again. if (ConstantExpr *NewCE = dyn_cast(NewC)) { if (FoldedOps.insert(NewCE).second) - NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps); + NewC = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, FoldedOps, + FMF); } Ops.push_back(NewC); } @@ -982,7 +991,8 @@ if (CE->isCompare()) return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1], DL, TLI); - return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI); + return ConstantFoldInstOperands(CE->getOpcode(), CE->getType(), Ops, DL, TLI, + FMF); } /// Attempt to fold the constant expression @@ -990,9 +1000,10 @@ /// result is returned, if not, null is returned. Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL, - const TargetLibraryInfo *TLI) { + const TargetLibraryInfo *TLI, + FastMathFlags FMF) { SmallPtrSet FoldedOps; - return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps); + return ConstantFoldConstantExpressionImpl(CE, DL, TLI, FoldedOps, FMF); } /// Attempt to constant fold an instruction with the @@ -1008,7 +1019,8 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, Type *DestTy, ArrayRef Ops, const DataLayout &DL, - const TargetLibraryInfo *TLI) { + const TargetLibraryInfo *TLI, + FastMathFlags FMF) { // Handle easy binops first. if (Instruction::isBinaryOp(Opcode)) { if (isa(Ops[0]) || isa(Ops[1])) { @@ -1016,7 +1028,7 @@ return C; } - return ConstantExpr::get(Opcode, Ops[0], Ops[1]); + return ConstantExpr::get(Opcode, Ops[0], Ops[1], 0, nullptr, FMF); } switch (Opcode) { Index: lib/IR/ConstantFold.h =================================================================== --- lib/IR/ConstantFold.h +++ lib/IR/ConstantFold.h @@ -24,6 +24,7 @@ namespace llvm { class Value; class Constant; + class FastMathFlags; class Type; // Constant fold various types of instruction... @@ -44,8 +45,7 @@ Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val, ArrayRef Idxs); Constant *ConstantFoldBinaryInstruction(unsigned Opcode, Constant *V1, - Constant *V2, bool KeepFPExceptions, - bool KeepFPRounding); + Constant *V2, FastMathFlags FMF); 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 @@ -916,8 +916,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, Constant *C2, - bool KeepExceptions, - bool KeepRounding) { + FastMathFlags FMF) { // Handle UndefValue up front. if (isa(C1) || isa(C2)) { switch (Opcode) { @@ -1101,8 +1100,7 @@ } 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, 0, nullptr, KeepExceptions, - KeepRounding); + return ConstantExpr::get(Opcode, C2, C1, 0, nullptr, FMF); } // At this point we know neither constant is an UndefValue. @@ -1180,32 +1178,32 @@ break; case Instruction::FAdd: S = C3V.add(C2V, APFloat::rmNearestTiesToEven); - if ((KeepExceptions && S != APFloat::opOK) || - (KeepRounding && (S & APFloat::opInexact))) + if ((FMF.keepExceptions() && S != APFloat::opOK) || + (FMF.keepRounding() && (S & APFloat::opInexact))) break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FSub: S = C3V.subtract(C2V, APFloat::rmNearestTiesToEven); - if ((KeepExceptions && S != APFloat::opOK) || - (KeepRounding && (S & APFloat::opInexact))) + if ((FMF.keepExceptions() && S != APFloat::opOK) || + (FMF.keepRounding() && (S & APFloat::opInexact))) break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FMul: S = C3V.multiply(C2V, APFloat::rmNearestTiesToEven); - if ((KeepExceptions && S != APFloat::opOK) || - (KeepRounding && (S & APFloat::opInexact))) + if ((FMF.keepExceptions() && S != APFloat::opOK) || + (FMF.keepRounding() && (S & APFloat::opInexact))) break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FDiv: S = C3V.divide(C2V, APFloat::rmNearestTiesToEven); - if ((KeepExceptions && S != APFloat::opOK) || - (KeepRounding && (S & APFloat::opInexact))) + if ((FMF.keepExceptions() && S != APFloat::opOK) || + (FMF.keepRounding() && (S & APFloat::opInexact))) break; return ConstantFP::get(C1->getContext(), C3V); case Instruction::FRem: S = C3V.mod(C2V); - if ((KeepExceptions && S != APFloat::opOK) || - (KeepRounding && (S & APFloat::opInexact))) + if ((FMF.keepExceptions() && S != APFloat::opOK) || + (FMF.keepRounding() && (S & APFloat::opInexact))) break; return ConstantFP::get(C1->getContext(), C3V); } @@ -1220,8 +1218,7 @@ Constant *RHS = ConstantExpr::getExtractElement(C2, ConstantInt::get(Ty, i)); - Result.push_back(ConstantExpr::get(Opcode, LHS, RHS, 0, nullptr, - KeepExceptions, KeepRounding)); + Result.push_back(ConstantExpr::get(Opcode, LHS, RHS, 0, nullptr, FMF)); } return ConstantVector::get(Result); @@ -1236,17 +1233,16 @@ // (a + (b + c)). if (Instruction::isAssociative(Opcode) && CE1->getOpcode() == Opcode) { Constant *T = ConstantExpr::get(Opcode, CE1->getOperand(1), C2, 0, - nullptr, KeepExceptions, KeepRounding); + nullptr, FMF); if (!isa(T) || cast(T)->getOpcode() != Opcode) return ConstantExpr::get(Opcode, CE1->getOperand(0), T, 0, nullptr, - KeepExceptions, KeepRounding); + FMF); } } 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, KeepExceptions, - KeepRounding); + return ConstantFoldBinaryInstruction(Opcode, C2, C1, FMF); } // i1 can be simplified in many cases. Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -1871,7 +1871,7 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2, unsigned Flags, Type *OnlyIfReducedTy, - bool KeepExceptions, bool KeepRounding) { + FastMathFlags FMF) { // Check the operands for consistency first. assert(Opcode >= Instruction::BinaryOpsBegin && Opcode < Instruction::BinaryOpsEnd && @@ -1937,9 +1937,7 @@ } #endif - if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2, - KeepExceptions, - KeepRounding)) { + if (Constant *FC = ConstantFoldBinaryInstruction(Opcode, C1, C2, FMF)) { return FC; // Fold a few common cases. } @@ -2270,8 +2268,8 @@ return get(Instruction::Add, C1, C2, Flags); } -Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2) { - return get(Instruction::FAdd, C1, C2); +Constant *ConstantExpr::getFAdd(Constant *C1, Constant *C2, FastMathFlags FMF) { + return get(Instruction::FAdd, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getSub(Constant *C1, Constant *C2, @@ -2281,19 +2279,19 @@ return get(Instruction::Sub, C1, C2, Flags); } -Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2) { - return get(Instruction::FSub, C1, C2); +Constant *ConstantExpr::getFSub(Constant *C1, Constant *C2, FastMathFlags FMF) { + return get(Instruction::FSub, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getMul(Constant *C1, Constant *C2, bool HasNUW, bool HasNSW) { 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); } -Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2) { - return get(Instruction::FMul, C1, C2); +Constant *ConstantExpr::getFMul(Constant *C1, Constant *C2, FastMathFlags FMF) { + return get(Instruction::FMul, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getUDiv(Constant *C1, Constant *C2, bool isExact) { @@ -2306,8 +2304,8 @@ isExact ? PossiblyExactOperator::IsExact : 0); } -Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2) { - return get(Instruction::FDiv, C1, C2); +Constant *ConstantExpr::getFDiv(Constant *C1, Constant *C2, FastMathFlags FMF) { + return get(Instruction::FDiv, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getURem(Constant *C1, Constant *C2) { @@ -2318,8 +2316,8 @@ return get(Instruction::SRem, C1, C2); } -Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2) { - return get(Instruction::FRem, C1, C2); +Constant *ConstantExpr::getFRem(Constant *C1, Constant *C2, FastMathFlags FMF) { + return get(Instruction::FRem, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getAnd(Constant *C1, Constant *C2) { Index: test/Other/fpenv-constant-fold.ll =================================================================== --- /dev/null +++ test/Other/fpenv-constant-fold.ll @@ -0,0 +1,130 @@ +; InstCombine is used just for its calls to constant folder. +; RUN: opt -S -instcombine -o - < %s | FileCheck %s + +; Target independent constant folder should not fold floating-point operations +; that have constant expression as their operands when FEnv access is requested +; and such folding leads to differences in observable effects at runtime. + +define double @do-not-fold-fadd-that-can-trap() { +; CHECK-LABEL: @do-not-fold-fadd-that-can-trap +; CHECK: fadd +entry: + %val = fadd kexc double 1.000000e+308, 1.000000e+308 + ret double %val +} + +define double @do-not-fold-fsub-that-can-trap() { +; CHECK-LABEL: @do-not-fold-fsub-that-can-trap +; CHECK: fsub +entry: + %val = fsub kexc double 1.000000e-308, 1.000000e+308 + ret double %val +} + +define double @do-not-fold-fmul-that-can-trap() { +; CHECK-LABEL: @do-not-fold-fmul-that-can-trap +; CHECK: fmul +entry: + %val = fmul kexc double 1.000000e+300, 1.000000e+300 + ret double %val +} + +define double @do-not-fold-fdiv-that-can-trap() { +; CHECK-LABEL: @do-not-fold-fdiv-that-can-trap +; CHECK: fdiv +entry: + %val = fdiv kexc double 1.000000e+300, 1.000000e-300 + ret double %val +} + +define double @do-not-fold-frem-that-can-trap() { +; CHECK-LABEL: @do-not-fold-frem-that-can-trap +; CHECK: frem +entry: + %val = frem kexc double 1.000000e+300, 1.000000e-300 + ret double %val +} + +define double @do-not-fold-fadd-because-of-rounding() { +; CHECK-LABEL: @do-not-fold-fadd-because-of-rounding +; CHECK: fadd +entry: + %val = fadd kround double 0.101, 0.93 + ret double %val +} + +define double @do-not-fold-fsub-because-of-rounding() { +; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding +; CHECK: fsub +entry: + %val = fsub kround double 0.101, 0.93 + ret double %val +} + +define double @do-not-fold-fmul-because-of-rounding() { +; CHECK-LABEL: @do-not-fold-fmul-because-of-rounding +; CHECK: fmul +entry: + %val = fmul kround double 0.101, 0.93 + ret double %val +} + +define double @do-not-fold-fdiv-because-of-rounding() { +; CHECK-LABEL: @do-not-fold-fdiv-because-of-rounding +; CHECK: fdiv +entry: + %val = fdiv kround double 0.101, 0.93 + ret double %val +} + +; "frem" instruction falls into the same category, but none of tried test-cases +; could raised inexact exception. + +define double @fold-fadd-that-cant-trap() { +; CHECK-LABEL: @fold-fadd-that-cant-trap +; CHECK-NOT: fadd +entry: + %val = fadd kexc kround double 1.0, 1.0 + ret double %val +} + +define double @fold-fsub-that-cant-trap() { +; CHECK-LABEL: @fold-fsub-that-cant-trap +; CHECK-NOT: fsub +entry: + %val = fsub kexc kround double 1.0, 1.0 + ret double %val +} + +define double @fold-fmul-that-cant-trap() { +; CHECK-LABEL: @fold-fmul-that-cant-trap +; CHECK-NOT: fmul +entry: + %val = fmul kexc kround double 1.0, 1.0 + ret double %val +} + +define double @fold-fdiv-that-cant-trap() { +; CHECK-LABEL: @fold-fdiv-that-cant-trap +; CHECK-NOT: fdiv +entry: + %val = fdiv kexc kround double 1.0, 1.0 + ret double %val +} + +define double @fold-frem-that-cant-trap() { +; CHECK-LABEL: @fold-frem-that-cant-trap +; CHECK-NOT: frem +entry: + %val = frem kexc kround double 1.0, 1.0 + ret double %val +} + +define double @correcly-handle-nested-expressions() { +; CHECK-LABEL: @correcly-handle-nested-expressions +; CHECK: fmul +entry: + %val1 = fmul kexc double 1.000000e+300, 1.000000e+300 + %val2 = fdiv kexc double %val1, 1.000000e+300 + ret double %val2 +}