diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -277,6 +277,10 @@ ConstantInt::getAllOnesValue(Ty) : ConstantFP::get(Ty, -1.0); BinaryOperator *Res = CreateMul(Neg->getOperand(OpNo), NegOne, "", Neg, Neg); + if (OverflowingBinaryOperator *OBON = dyn_cast(Neg)) { + Res->setHasNoSignedWrap(OBON->hasNoSignedWrap()); + Res->setHasNoUnsignedWrap(OBON->hasNoUnsignedWrap()); + } Neg->setOperand(OpNo, Constant::getNullValue(Ty)); // Drop use of op. Res->takeName(Neg); Neg->replaceAllUsesWith(Res); @@ -787,8 +791,17 @@ FastMathFlags Flags = I->getFastMathFlags(); ExpressionChanged->clearSubclassOptionalData(); ExpressionChanged->setFastMathFlags(Flags); - } else + } else { + // Preserve nsw/nuw flags. + OverflowingBinaryOperator *OBOI = dyn_cast(I); + bool NSW = OBOI ? OBOI->hasNoSignedWrap() : false; + bool NUW = OBOI ? OBOI->hasNoUnsignedWrap() : false; ExpressionChanged->clearSubclassOptionalData(); + if (isa(ExpressionChanged)) { + ExpressionChanged->setHasNoSignedWrap(NSW); + ExpressionChanged->setHasNoUnsignedWrap(NUW); + } + } if (ExpressionChanged == I) break; @@ -1062,6 +1075,10 @@ // Everyone now refers to the add instruction. Sub->replaceAllUsesWith(New); New->setDebugLoc(Sub->getDebugLoc()); + if (OverflowingBinaryOperator *OBOS = dyn_cast(Sub)) { + New->setHasNoSignedWrap(OBOS->hasNoSignedWrap()); + New->setHasNoUnsignedWrap(OBOS->hasNoUnsignedWrap()); + } LLVM_DEBUG(dbgs() << "Negated: " << *New << '\n'); return New; @@ -1953,6 +1970,10 @@ if (Ops.size() == 1) return Ops[0].Op; + OverflowingBinaryOperator *OBOI = dyn_cast(I); + bool NSW = OBOI ? OBOI->hasNoSignedWrap() : false; + bool NUW = OBOI ? OBOI->hasNoUnsignedWrap() : false; + // Handle destructive annihilation due to identities between elements in the // argument list here. unsigned NumOps = Ops.size(); @@ -1971,14 +1992,26 @@ case Instruction::Add: case Instruction::FAdd: - if (Value *Result = OptimizeAdd(I, Ops)) + if (Value *Result = OptimizeAdd(I, Ops)) { + BinaryOperator *BO = dyn_cast(Result); + if (isa_and_nonnull(BO)) { + BO->setHasNoSignedWrap(NSW); + BO->setHasNoUnsignedWrap(NUW); + } return Result; + } break; case Instruction::Mul: case Instruction::FMul: - if (Value *Result = OptimizeMul(I, Ops)) + if (Value *Result = OptimizeMul(I, Ops)) { + BinaryOperator *BO = dyn_cast(Result); + if (isa_and_nonnull(BO)) { + BO->setHasNoSignedWrap(NSW); + BO->setHasNoUnsignedWrap(NUW); + } return Result; + } break; } diff --git a/llvm/test/Transforms/Reassociate/cse-pairs.ll b/llvm/test/Transforms/Reassociate/cse-pairs.ll --- a/llvm/test/Transforms/Reassociate/cse-pairs.ll +++ b/llvm/test/Transforms/Reassociate/cse-pairs.ll @@ -32,9 +32,9 @@ define signext i32 @twoPairsAllOpInPairs(i32 signext %0, i32 signext %1, i32 signext %2, i32 signext %3) { ; CHECK-LABEL: @twoPairsAllOpInPairs( -; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP2:%.*]], [[TMP1:%.*]] -; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP0:%.*]] -; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], [[TMP3:%.*]] +; CHECK-NEXT: [[TMP5:%.*]] = add nsw i32 [[TMP2:%.*]], [[TMP1:%.*]] +; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP5]], [[TMP0:%.*]] +; CHECK-NEXT: [[TMP7:%.*]] = add nsw i32 [[TMP6]], [[TMP3:%.*]] ; CHECK-NEXT: store i32 [[TMP7]], i32* @num1, align 4 ; CHECK-NEXT: store i32 [[TMP5]], i32* @num2, align 4 ; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP3]], [[TMP0]] @@ -54,11 +54,11 @@ define signext i32 @threePairsAllOpInPairs(i32 signext %0, i32 signext %1, i32 signext %2, i32 signext %3, i32 signext %4, i32 signext %5) { ; CHECK-LABEL: @threePairsAllOpInPairs( -; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP3:%.*]], [[TMP2:%.*]] -; CHECK-NEXT: [[TMP8:%.*]] = add i32 [[TMP7]], [[TMP0:%.*]] -; CHECK-NEXT: [[TMP9:%.*]] = add i32 [[TMP8]], [[TMP1:%.*]] -; CHECK-NEXT: [[TMP10:%.*]] = add i32 [[TMP9]], [[TMP4:%.*]] -; CHECK-NEXT: [[TMP11:%.*]] = add i32 [[TMP10]], [[TMP5:%.*]] +; CHECK-NEXT: [[TMP7:%.*]] = add nsw i32 [[TMP3:%.*]], [[TMP2:%.*]] +; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP7]], [[TMP0:%.*]] +; CHECK-NEXT: [[TMP9:%.*]] = add nsw i32 [[TMP8]], [[TMP1:%.*]] +; CHECK-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], [[TMP4:%.*]] +; CHECK-NEXT: [[TMP11:%.*]] = add nsw i32 [[TMP10]], [[TMP5:%.*]] ; CHECK-NEXT: store i32 [[TMP11]], i32* @num1, align 4 ; CHECK-NEXT: [[TMP12:%.*]] = add nsw i32 [[TMP5]], [[TMP0]] ; CHECK-NEXT: store i32 [[TMP12]], i32* @num2, align 4 diff --git a/llvm/test/Transforms/Reassociate/no-op.ll b/llvm/test/Transforms/Reassociate/no-op.ll --- a/llvm/test/Transforms/Reassociate/no-op.ll +++ b/llvm/test/Transforms/Reassociate/no-op.ll @@ -31,8 +31,8 @@ ; The initial add doesn't change so should not lose the nsw flag. ; CHECK-LABEL: @test2( ; CHECK-NEXT: [[A0:%.*]] = add nsw i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[A1:%.*]] = add i32 [[A0]], [[C:%.*]] -; CHECK-NEXT: [[A2:%.*]] = add i32 [[A1]], [[D:%.*]] +; CHECK-NEXT: [[A1:%.*]] = add nsw i32 [[A0]], [[C:%.*]] +; CHECK-NEXT: [[A2:%.*]] = add nsw i32 [[A1]], [[D:%.*]] ; CHECK-NEXT: call void @use(i32 [[A2]]) ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/Reassociate/optional-flags.ll b/llvm/test/Transforms/Reassociate/optional-flags.ll --- a/llvm/test/Transforms/Reassociate/optional-flags.ll +++ b/llvm/test/Transforms/Reassociate/optional-flags.ll @@ -19,8 +19,8 @@ define i64 @test1(i64 %a, i64 %b, i64 %c) { ; ; CHECK-LABEL: @test1( -; CHECK-NEXT: [[Y:%.*]] = add i64 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[Z:%.*]] = add i64 [[Y]], [[C:%.*]] +; CHECK-NEXT: [[Y:%.*]] = add nsw i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[Z:%.*]] = add nsw i64 [[Y]], [[C:%.*]] ; CHECK-NEXT: ret i64 [[Z]] ; %y = add i64 %c, %b diff --git a/llvm/test/Transforms/Reassociate/vaarg_movable.ll b/llvm/test/Transforms/Reassociate/vaarg_movable.ll --- a/llvm/test/Transforms/Reassociate/vaarg_movable.ll +++ b/llvm/test/Transforms/Reassociate/vaarg_movable.ll @@ -15,8 +15,8 @@ ; CHECK-NEXT: [[V0:%.*]] = va_arg i8** [[VARARGS]], i32 ; CHECK-NEXT: [[V1:%.*]] = va_arg i8** [[VARARGS]], i32 ; CHECK-NEXT: [[V0_NEG:%.*]] = sub i32 0, [[V0]] -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[V0_NEG]], 1 -; CHECK-NEXT: [[ADD:%.*]] = add i32 [[SUB]], [[V1]] +; CHECK-NEXT: [[SUB:%.*]] = add nsw i32 [[V0_NEG]], 1 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], [[V1]] ; CHECK-NEXT: call void @llvm.va_end(i8* [[VARARGS1]]) ; CHECK-NEXT: ret i32 [[ADD]] ; diff --git a/llvm/test/Transforms/Reassociate/wrap-flags.ll b/llvm/test/Transforms/Reassociate/wrap-flags.ll --- a/llvm/test/Transforms/Reassociate/wrap-flags.ll +++ b/llvm/test/Transforms/Reassociate/wrap-flags.ll @@ -79,7 +79,7 @@ ; CHECK-LABEL: @pr23926( ; CHECK-NEXT: [[X1_NEG:%.*]] = sub i2 0, [[X1:%.*]] ; CHECK-NEXT: [[ADD_NEG:%.*]] = add i2 [[X1_NEG]], -1 -; CHECK-NEXT: [[SUB:%.*]] = add i2 [[ADD_NEG]], [[X2:%.*]] +; CHECK-NEXT: [[SUB:%.*]] = add nuw nsw i2 [[ADD_NEG]], [[X2:%.*]] ; CHECK-NEXT: ret i2 [[SUB]] ; %add = add nuw i2 %X1, 1