Index: lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1096,6 +1096,30 @@ return nullptr; } +/// Fold +/// (1 << NBits) - 1 +/// Into: +/// ~(-(1 << NBits)) +/// Because a 'not' is better for bit-tracking analysis and other transforms +/// than an 'add'. The new shl is always nsw, and is nuw if old `and` was. +static Instruction *canonicalizeLowbitMask(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Value *NBits; + if (!match(&I, m_Add(m_OneUse(m_Shl(m_One(), m_Value(NBits))), m_AllOnes()))) + return nullptr; + + Constant *MinusOne = Constant::getAllOnesValue(NBits->getType()); + Value *NotMask = Builder.CreateShl(MinusOne, NBits, "notmask"); + // Be wary of constant folding. + if (auto *BOp = dyn_cast(NotMask)) { + // Always NSW. But NUW propagates from `add`. + BOp->setHasNoSignedWrap(); + BOp->setHasNoUnsignedWrap(I.hasNoUnsignedWrap()); + } + + return BinaryOperator::CreateNot(NotMask, I.getName()); +} + Instruction *InstCombiner::visitAdd(BinaryOperator &I) { bool Changed = SimplifyAssociativeOrCommutative(I); Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); @@ -1347,6 +1371,9 @@ I.setHasNoUnsignedWrap(true); } + if (Instruction *V = canonicalizeLowbitMask(I, Builder)) + return V; + return Changed ? &I : nullptr; } Index: test/Transforms/InstCombine/rem.ll =================================================================== --- test/Transforms/InstCombine/rem.ll +++ test/Transforms/InstCombine/rem.ll @@ -314,8 +314,8 @@ define i64 @test15(i32 %x, i32 %y) { ; CHECK-LABEL: @test15( -; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 1, [[Y:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[SHL]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X:%.*]] ; CHECK-NEXT: [[UREM:%.*]] = zext i32 [[TMP2]] to i64 ; CHECK-NEXT: ret i64 [[UREM]] Index: test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll =================================================================== --- test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll +++ test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll @@ -17,8 +17,8 @@ define i32 @shl_add(i32 %NBits) { ; CHECK-LABEL: @shl_add( -; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits @@ -28,8 +28,8 @@ define i32 @shl_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nsw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits @@ -39,8 +39,8 @@ define i32 @shl_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits @@ -50,8 +50,8 @@ define i32 @shl_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nsw_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits @@ -63,8 +63,8 @@ define i32 @shl_nsw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nsw i32 1, %NBits @@ -74,8 +74,8 @@ define i32 @shl_nsw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nsw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nsw i32 1, %NBits @@ -85,8 +85,8 @@ define i32 @shl_nsw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nsw i32 1, %NBits @@ -96,8 +96,8 @@ define i32 @shl_nsw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nsw_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nsw i32 1, %NBits @@ -109,8 +109,8 @@ define i32 @shl_nuw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw i32 1, %NBits @@ -120,8 +120,8 @@ define i32 @shl_nuw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nsw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw i32 1, %NBits @@ -131,8 +131,8 @@ define i32 @shl_nuw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw i32 1, %NBits @@ -142,8 +142,8 @@ define i32 @shl_nuw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nsw_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw i32 1, %NBits @@ -155,8 +155,8 @@ define i32 @shl_nsw_nuw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw nsw i32 1, %NBits @@ -166,8 +166,8 @@ define i32 @shl_nsw_nuw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nsw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw nsw i32 1, %NBits @@ -177,8 +177,8 @@ define i32 @shl_nsw_nuw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw nsw i32 1, %NBits @@ -188,8 +188,8 @@ define i32 @shl_nsw_nuw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nsw_nuw( -; CHECK-NEXT: [[SETBIT:%.*]] = shl nuw nsw i32 1, [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add nuw nsw i32 [[SETBIT]], -1 +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nuw nsw i32 -1, [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor i32 [[NOTMASK]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl nuw nsw i32 1, %NBits @@ -216,8 +216,8 @@ define <2 x i32> @shl_add_vec(<2 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec( -; CHECK-NEXT: [[SETBIT:%.*]] = shl <2 x i32> , [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add <2 x i32> [[SETBIT]], +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <2 x i32> , [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor <2 x i32> [[NOTMASK]], ; CHECK-NEXT: ret <2 x i32> [[RET]] ; %setbit = shl <2 x i32> , %NBits @@ -227,8 +227,8 @@ define <3 x i32> @shl_add_vec_undef(<3 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec_undef( -; CHECK-NEXT: [[SETBIT:%.*]] = shl <3 x i32> , [[NBITS:%.*]] -; CHECK-NEXT: [[RET:%.*]] = add <3 x i32> [[SETBIT]], +; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <3 x i32> , [[NBITS:%.*]] +; CHECK-NEXT: [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %setbit = shl <3 x i32> , %NBits