; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s ; https://bugs.llvm.org/show_bug.cgi?id=37603 ; Pattern: ; (1 << NBits) - 1 ; Should be transformed into: ; ~(-(1 << NBits)) ; The `not` may end up being folded into `and` ; ============================================================================ ; ; Most basic positive tests ; ============================================================================ ; ; No no-wrap tags on shl define i32 @shl_add(i32 %NBits) { ; CHECK-LABEL: @shl_add( ; 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 %ret = add i32 %setbit, -1 ret i32 %ret } define i32 @shl_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nsw( ; 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 %ret = add nsw i32 %setbit, -1 ret i32 %ret } define i32 @shl_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl i32 1, %NBits %ret = add nuw i32 %setbit, -1 ret i32 %ret } define i32 @shl_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_add_nsw_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl i32 1, %NBits %ret = add nuw nsw i32 %setbit, -1 ret i32 %ret } ; shl is nsw define i32 @shl_nsw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add( ; 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 %ret = add i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nsw( ; 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 %ret = add nsw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nsw i32 1, %NBits %ret = add nuw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_add_nsw_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nsw i32 1, %NBits %ret = add nuw nsw i32 %setbit, -1 ret i32 %ret } ; shl is nuw define i32 @shl_nuw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add( ; 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 %ret = add i32 %setbit, -1 ret i32 %ret } define i32 @shl_nuw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nsw( ; 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 %ret = add nsw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nuw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nuw i32 1, %NBits %ret = add nuw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nuw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nuw_add_nsw_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nuw i32 1, %NBits %ret = add nuw nsw i32 %setbit, -1 ret i32 %ret } ; shl is nuw nsw define i32 @shl_nsw_nuw_add(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add( ; 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 %ret = add i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_nuw_add_nsw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nsw( ; 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 %ret = add nsw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_nuw_add_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nuw nsw i32 1, %NBits %ret = add nuw i32 %setbit, -1 ret i32 %ret } define i32 @shl_nsw_nuw_add_nsw_nuw(i32 %NBits) { ; CHECK-LABEL: @shl_nsw_nuw_add_nsw_nuw( ; CHECK-NEXT: ret i32 -1 ; %setbit = shl nuw nsw i32 1, %NBits %ret = add nuw nsw i32 %setbit, -1 ret i32 %ret } ; ============================================================================ ; ; Vectors ; ============================================================================ ; define <2 x i32> @shl_add_vec(<2 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec( ; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <2 x i32> <i32 -1, i32 -1>, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = xor <2 x i32> [[NOTMASK]], <i32 -1, i32 -1> ; CHECK-NEXT: ret <2 x i32> [[RET]] ; %setbit = shl <2 x i32> <i32 1, i32 1>, %NBits %ret = add <2 x i32> %setbit, <i32 -1, i32 -1> ret <2 x i32> %ret } define <3 x i32> @shl_add_vec_undef0(<3 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec_undef0( ; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1> ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %setbit = shl <3 x i32> <i32 1, i32 undef, i32 1>, %NBits %ret = add <3 x i32> %setbit, <i32 -1, i32 -1, i32 -1> ret <3 x i32> %ret } define <3 x i32> @shl_add_vec_undef1(<3 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec_undef1( ; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1> ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %setbit = shl <3 x i32> <i32 1, i32 1, i32 1>, %NBits %ret = add <3 x i32> %setbit, <i32 -1, i32 undef, i32 -1> ret <3 x i32> %ret } define <3 x i32> @shl_add_vec_undef2(<3 x i32> %NBits) { ; CHECK-LABEL: @shl_add_vec_undef2( ; CHECK-NEXT: [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1> ; CHECK-NEXT: ret <3 x i32> [[RET]] ; %setbit = shl <3 x i32> <i32 1, i32 undef, i32 1>, %NBits %ret = add <3 x i32> %setbit, <i32 -1, i32 undef, i32 -1> ret <3 x i32> %ret } ; ============================================================================ ; ; Negative tests. Should not be folded. ; ============================================================================ ; declare void @use32(i32) ; One use only. define i32 @bad_oneuse0(i32 %NBits) { ; CHECK-LABEL: @bad_oneuse0( ; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] ; CHECK-NEXT: call void @use32(i32 [[SETBIT]]) ; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits call void @use32(i32 %setbit) %ret = add i32 %setbit, -1 ret i32 %ret } ; shift base is not `1` constant define i32 @bad_shl(i32 %base, i32 %NBits) { ; CHECK-LABEL: @bad_shl( ; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 [[BASE:%.*]], [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 %base, %NBits ; %base instead of 1 %ret = add i32 %setbit, -1 ret i32 %ret } ; Second `add` operand is not `-1` constant define i32 @bad_add0(i32 %NBits, i32 %addop2) { ; CHECK-LABEL: @bad_add0( ; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], [[ADDOP2:%.*]] ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits %ret = add i32 %setbit, %addop2 ret i32 %ret } ; Bad add constant define i32 @bad_add1(i32 %NBits) { ; CHECK-LABEL: @bad_add1( ; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], 1 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits %ret = add i32 %setbit, 1 ; not -1 ret i32 %ret } define i32 @bad_add2(i32 %NBits) { ; CHECK-LABEL: @bad_add2( ; CHECK-NEXT: [[SETBIT:%.*]] = shl i32 1, [[NBITS:%.*]] ; CHECK-NEXT: [[RET:%.*]] = add i32 [[SETBIT]], -2 ; CHECK-NEXT: ret i32 [[RET]] ; %setbit = shl i32 1, %NBits %ret = add i32 %setbit, -2 ; not -1 ret i32 %ret }