Index: lib/Transforms/InstCombine/InstCombinePHI.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombinePHI.cpp +++ lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -35,15 +35,6 @@ Type *LHSType = LHSVal->getType(); Type *RHSType = RHSVal->getType(); - bool isNUW = false, isNSW = false, isExact = false; - if (OverflowingBinaryOperator *BO = - dyn_cast(FirstInst)) { - isNUW = BO->hasNoUnsignedWrap(); - isNSW = BO->hasNoSignedWrap(); - } else if (PossiblyExactOperator *PEO = - dyn_cast(FirstInst)) - isExact = PEO->isExact(); - // Scan to see if all operands are the same opcode, and all have one use. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { Instruction *I = dyn_cast(PN.getIncomingValue(i)); @@ -59,13 +50,6 @@ if (CI->getPredicate() != cast(FirstInst)->getPredicate()) return nullptr; - if (isNUW) - isNUW = cast(I)->hasNoUnsignedWrap(); - if (isNSW) - isNSW = cast(I)->hasNoSignedWrap(); - if (isExact) - isExact = cast(I)->isExact(); - // Keep track of which operand needs a phi node. if (I->getOperand(0) != LHSVal) LHSVal = nullptr; if (I->getOperand(1) != RHSVal) RHSVal = nullptr; @@ -124,9 +108,12 @@ BinaryOperator *BinOp = cast(FirstInst); BinaryOperator *NewBinOp = BinaryOperator::Create(BinOp->getOpcode(), LHSVal, RHSVal); - if (isNUW) NewBinOp->setHasNoUnsignedWrap(); - if (isNSW) NewBinOp->setHasNoSignedWrap(); - if (isExact) NewBinOp->setIsExact(); + + NewBinOp->copyIRFlags(PN.getIncomingValue(0)); + + for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) + NewBinOp->andIRFlags(PN.getIncomingValue(i)); + NewBinOp->setDebugLoc(FirstInst->getDebugLoc()); return NewBinOp; } @@ -497,7 +484,6 @@ // code size and simplifying code. Constant *ConstantOp = nullptr; Type *CastSrcTy = nullptr; - bool isNUW = false, isNSW = false, isExact = false; if (isa(FirstInst)) { CastSrcTy = FirstInst->getOperand(0)->getType(); @@ -514,14 +500,6 @@ ConstantOp = dyn_cast(FirstInst->getOperand(1)); if (!ConstantOp) return FoldPHIArgBinOpIntoPHI(PN); - - if (OverflowingBinaryOperator *BO = - dyn_cast(FirstInst)) { - isNUW = BO->hasNoUnsignedWrap(); - isNSW = BO->hasNoSignedWrap(); - } else if (PossiblyExactOperator *PEO = - dyn_cast(FirstInst)) - isExact = PEO->isExact(); } else { return nullptr; // Cannot fold this operation. } @@ -537,13 +515,6 @@ } else if (I->getOperand(1) != ConstantOp) { return nullptr; } - - if (isNUW) - isNUW = cast(I)->hasNoUnsignedWrap(); - if (isNSW) - isNSW = cast(I)->hasNoSignedWrap(); - if (isExact) - isExact = cast(I)->isExact(); } // Okay, they are all the same operation. Create a new PHI node of the @@ -584,9 +555,11 @@ if (BinaryOperator *BinOp = dyn_cast(FirstInst)) { BinOp = BinaryOperator::Create(BinOp->getOpcode(), PhiVal, ConstantOp); - if (isNUW) BinOp->setHasNoUnsignedWrap(); - if (isNSW) BinOp->setHasNoSignedWrap(); - if (isExact) BinOp->setIsExact(); + BinOp->copyIRFlags(PN.getIncomingValue(0)); + + for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) + BinOp->andIRFlags(PN.getIncomingValue(i)); + BinOp->setDebugLoc(FirstInst->getDebugLoc()); return BinOp; } Index: test/Transforms/InstCombine/phi-preserve-ir-flags.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/phi-preserve-ir-flags.ll @@ -0,0 +1,89 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + +; CHECK-LABEL: f +define float @f(float %a, float %b, float %c, i1 %cond) { +entry: + br i1 %cond, label %cond.true, label %cond.false + +cond.true: + %sub0 = fsub fast float %a, %b + br label %cond.end + +cond.false: + %sub1 = fsub fast float %a, %c + br label %cond.end + +; The fast-math flags should always be transfered if possible. +; CHECK-LABEL: cond.end +; CHECK [[PHI:%[^ ]*]] = phi float [ %b, %cond.true ], [ %c, %cond.false ] +; CHECK fsub fast float %a, [[PHI]] +cond.end: + %e = phi float [ %sub0, %cond.true ], [ %sub1, %cond.false ] + ret float %e +} + +; CHECK-LABEL: g +define float @g(float %a, float %b, float %c, i1 %cond) { +entry: + br i1 %cond, label %cond.true, label %cond.false + +cond.true: + %sub0 = fsub fast float %a, %b + br label %cond.end + +cond.false: + %sub1 = fsub float %a, %c + br label %cond.end + +; The fast-math flags should always be transfered if possible. +; CHECK-LABEL: cond.end +; CHECK [[PHI:%[^ ]*]] = phi float [ %b, %cond.true ], [ %c, %cond.false ] +; CHECK fsub float %a, [[PHI]] +cond.end: + %e = phi float [ %sub0, %cond.true ], [ %sub1, %cond.false ] + ret float %e +} + +; CHECK-LABEL: h +define float @h(float %a, float %b, float %c, i1 %cond) { +entry: + br i1 %cond, label %cond.true, label %cond.false + +cond.true: + %sub0 = fsub fast float %a, 2.0 + br label %cond.end + +cond.false: + %sub1 = fsub fast float %b, 2.0 + br label %cond.end + +; CHECK-LABEL: cond.end +; CHECK [[PHI:%[^ ]*]] = phi float [ %a, %cond.true ], [ %b, %cond.false ] +; CHECK fadd fast float %a, [[PHI]] +cond.end: + %e = phi float [ %sub0, %cond.true ], [ %sub1, %cond.false ] + ret float %e +} + +; CHECK-LABEL: i +define float @i(float %a, float %b, float %c, i1 %cond) { +entry: + br i1 %cond, label %cond.true, label %cond.false + +cond.true: + %sub0 = fsub fast float %a, 2.0 + br label %cond.end + +cond.false: + %sub1 = fsub float %b, 2.0 + br label %cond.end + +; CHECK-LABEL: cond.end +; CHECK [[PHI:%[^ ]*]] = phi float [ %a, %cond.true ], [ %b, %cond.false ] +; CHECK fadd float %a, [[PHI]] +cond.end: + %e = phi float [ %sub0, %cond.true ], [ %sub1, %cond.false ] + ret float %e +}