Index: lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- lib/Transforms/Scalar/Reassociate.cpp +++ lib/Transforms/Scalar/Reassociate.cpp @@ -1016,6 +1016,17 @@ Sub->replaceAllUsesWith(New); New->setDebugLoc(Sub->getDebugLoc()); + // Preserve NSW/NUW flags. + if (Sub->getOpcode() == Instruction::Sub) { + bool NSW = cast(Sub)->hasNoSignedWrap(); + bool NUW = cast(Sub)->hasNoUnsignedWrap(); + New->setHasNoSignedWrap(NSW); + New->setHasNoUnsignedWrap(NUW); + if (BinaryOperator *NegBO = dyn_cast(NegVal)) { + NegBO->setHasNoSignedWrap(NSW); + NegBO->setHasNoUnsignedWrap(NUW); + } + } DEBUG(dbgs() << "Negated: " << *New << '\n'); return New; } @@ -1031,8 +1042,14 @@ BinaryOperator::CreateMul(Shl->getOperand(0), MulCst, "", Shl); Shl->setOperand(0, UndefValue::get(Shl->getType())); // Drop use of op. Mul->takeName(Shl); + + // Everyone now refers to the mul instruction. Shl->replaceAllUsesWith(Mul); Mul->setDebugLoc(Shl->getDebugLoc()); + + // Preserve NSW/NUW flags. + Mul->setHasNoSignedWrap(cast(Shl)->hasNoSignedWrap()); + Mul->setHasNoUnsignedWrap(cast(Shl)->hasNoUnsignedWrap()); return Mul; } Index: test/Transforms/Reassociate/wrap-flags.ll =================================================================== --- /dev/null +++ test/Transforms/Reassociate/wrap-flags.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -reassociate -dce -S | FileCheck %s +; PR12985 + +; Verify the nsw flag is preserved when converting shl to mul. +; CHECK-LABEL: @shl_to_mul( +; CHECK: %mul = mul nsw i32 %i, 4 +; CHECK: %mul2 = add nsw i32 %mul, 1 + +define i32 @shl_to_mul(i32 %i) { +entry: + %mul = shl nsw i32 %i, 2 + %mul2 = add nsw i32 %mul, 1 + ret i32 %mul2 +} + +; Verify the nsw flag is preserved when converting (X-Y)->(X+(0-Y)). +; CHECK-LABEL: @breakup_sub( +; CHECK: %y.neg = sub nsw i32 0, %y +; CHECK: %sub = add nsw i32 %y.neg, %x +; CHECK: %add = add nsw i32 %sub, %z + +define i32 @breakup_sub(i32 %x, i32 %y, i32 %z) { +entry: + %sub = sub nsw i32 %x, %y + %add = add nsw i32 %sub, %z + ret i32 %add +}