Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -596,27 +596,40 @@ if (BinaryOperator *BO = dyn_cast(SimplifiedInst)) { if (isa(SimplifiedInst)) { bool HasNSW = false; - if (isa(&I)) + bool HasNUW = false; + if (isa(&I)) { HasNSW = I.hasNoSignedWrap(); + HasNUW = I.hasNoUnsignedWrap(); + } - if (auto *LOBO = dyn_cast(LHS)) + if (auto *LOBO = dyn_cast(LHS)) { HasNSW &= LOBO->hasNoSignedWrap(); + HasNUW &= LOBO->hasNoUnsignedWrap(); + } - if (auto *ROBO = dyn_cast(RHS)) + if (auto *ROBO = dyn_cast(RHS)) { HasNSW &= ROBO->hasNoSignedWrap(); + HasNUW &= ROBO->hasNoUnsignedWrap(); + } - // We can propagate 'nsw' if we know that - // %Y = mul nsw i16 %X, C - // %Z = add nsw i16 %Y, %X - // => - // %Z = mul nsw i16 %X, C+1 - // - // iff C+1 isn't INT_MIN const APInt *CInt; if (TopLevelOpcode == Instruction::Add && - InnerOpcode == Instruction::Mul) - if (match(V, m_APInt(CInt)) && !CInt->isMinSignedValue()) - BO->setHasNoSignedWrap(HasNSW); + InnerOpcode == Instruction::Mul) { + // We can propagate 'nsw' if we know that + // %Y = mul nsw i16 %X, C + // %Z = add nsw i16 %Y, %X + // => + // %Z = mul nsw i16 %X, C+1 + // + // iff C+1 isn't INT_MIN + if (match(V, m_APInt(CInt))) { + if (!CInt->isMinSignedValue()) + BO->setHasNoSignedWrap(HasNSW); + } + + // nuw can be propagated with any constant or nuw value. + BO->setHasNoUnsignedWrap(HasNUW); + } } } } Index: test/Transforms/InstCombine/reassociate-nuw.ll =================================================================== --- test/Transforms/InstCombine/reassociate-nuw.ll +++ test/Transforms/InstCombine/reassociate-nuw.ll @@ -92,7 +92,7 @@ define i32 @tryFactorization_add_nuw_mul_nuw(i32 %x) { ; CHECK-LABEL: @tryFactorization_add_nuw_mul_nuw( -; CHECK-NEXT: [[ADD2:%.*]] = shl i32 [[X:%.*]], 2 +; CHECK-NEXT: [[ADD2:%.*]] = shl nuw i32 [[X:%.*]], 2 ; CHECK-NEXT: ret i32 [[ADD2]] ; %mul1 = mul nuw i32 %x, 3 @@ -102,7 +102,7 @@ define i32 @tryFactorization_add_nuw_mul_nuw_int_max(i32 %x) { ; CHECK-LABEL: @tryFactorization_add_nuw_mul_nuw_int_max( -; CHECK-NEXT: [[ADD2:%.*]] = shl i32 [[X:%.*]], 31 +; CHECK-NEXT: [[ADD2:%.*]] = shl nuw i32 [[X:%.*]], 31 ; CHECK-NEXT: ret i32 [[ADD2]] ; %mul1 = mul nuw i32 %x, 2147483647 @@ -129,3 +129,51 @@ %add2 = add i32 %mul1, %x ret i32 %add2 } + +define i32 @tryFactorization_add_nuw_mul_nuw_mul_nuw_var(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @tryFactorization_add_nuw_mul_nuw_mul_nuw_var( +; CHECK-NEXT: [[MUL21:%.*]] = add i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[ADD1:%.*]] = mul nuw i32 [[MUL21]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[ADD1]] +; + %mul1 = mul nuw i32 %x, %y + %mul2 = mul nuw i32 %x, %z + %add1 = add nuw i32 %mul1, %mul2 + ret i32 %add1 +} + +define i32 @tryFactorization_add_nuw_mul_mul_nuw_var(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @tryFactorization_add_nuw_mul_mul_nuw_var( +; CHECK-NEXT: [[MUL21:%.*]] = add i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[ADD1:%.*]] = mul i32 [[MUL21]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[ADD1]] +; + %mul1 = mul i32 %x, %y + %mul2 = mul nuw i32 %x, %z + %add1 = add nuw i32 %mul1, %mul2 + ret i32 %add1 +} + +define i32 @tryFactorization_add_nuw_mul_nuw_mul_var(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @tryFactorization_add_nuw_mul_nuw_mul_var( +; CHECK-NEXT: [[MUL21:%.*]] = add i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[ADD1:%.*]] = mul i32 [[MUL21]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[ADD1]] +; + %mul1 = mul nuw i32 %x, %y + %mul2 = mul i32 %x, %z + %add1 = add nuw i32 %mul1, %mul2 + ret i32 %add1 +} + +define i32 @tryFactorization_add_mul_nuw_mul_var(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: @tryFactorization_add_mul_nuw_mul_var( +; CHECK-NEXT: [[MUL21:%.*]] = add i32 [[Y:%.*]], [[Z:%.*]] +; CHECK-NEXT: [[ADD1:%.*]] = mul i32 [[MUL21]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[ADD1]] +; + %mul1 = mul nuw i32 %x, %y + %mul2 = mul nuw i32 %x, %z + %add1 = add i32 %mul1, %mul2 + ret i32 %add1 +}