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, FMF); } //===--------------------------------------------------------------------===// Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -785,7 +785,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); } @@ -807,7 +807,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); } @@ -829,7 +829,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); } @@ -861,7 +861,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); } @@ -881,7 +881,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: lib/Analysis/ConstantFolding.cpp =================================================================== --- lib/Analysis/ConstantFolding.cpp +++ lib/Analysis/ConstantFolding.cpp @@ -894,6 +894,11 @@ /// 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 +916,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 +939,8 @@ // Fold the Instruction's operands. if (ConstantExpr *NewCE = dyn_cast(Op)) - Op = ConstantFoldConstantExpression(NewCE, DL, TLI); + if (Constant *C = ConstantFoldConstantExpression(NewCE, DL, TLI, FMF)) + Op = C; 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,9 @@ // 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); + if (Constant *C = ConstantFoldConstantExpressionImpl(NewCE, DL, TLI, + FoldedOps, FMF)) + NewC = C; } Ops.push_back(NewC); } @@ -982,7 +992,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 +1001,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 +1020,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 +1029,7 @@ return C; } - return ConstantExpr::get(Opcode, Ops[0], Ops[1]); + return ConstantExpr::get(Opcode, Ops[0], Ops[1], FMF); } switch (Opcode) { Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -1895,7 +1895,7 @@ Constant *ConstantExpr::get(unsigned Opcode, Constant *C1, Constant *C2, FastMathFlags FMF) { - return get(Opcode, C1, C2, FMF); + return get(Opcode, C1, C2, 0, nullptr, FMF); } Constant *ConstantExpr::getSizeOf(Type* Ty) { 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 nrnd double 1.000000e+308, 1.000000e+308 +entry: + %val = fadd nrnd 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 nrnd double 1.000000e-308, 1.000000e+308 +entry: + %val = fsub nrnd 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 nrnd double 1.000000e+300, 1.000000e+300 +entry: + %val = fmul nrnd 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 nrnd double 1.000000e+300, 1.000000e-300 +entry: + %val = fdiv nrnd 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 nrnd double 1.000000e+300, 1.000000e-300 +entry: + %val = frem nrnd 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 nexc double 0.101, 0.93 +entry: + %val = fadd nexc 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 nexc double 0.101, 0.93 +entry: + %val = fsub nexc 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 nexc double 0.101, 0.93 +entry: + %val = fmul nexc 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 nexc double 0.101, 0.93 +entry: + %val = fdiv nexc 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 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 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 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 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 double 1.0, 1.0 + ret double %val +} + +define double @correcly-handle-nested-expressions() { +; CHECK-LABEL: @correcly-handle-nested-expressions +; CHECK: fmul nrnd double 1.000000e+300, 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 +}