| ; 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 nuw 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 nuw 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 nuw i32 1, [[NBITS:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = add nuw 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 nuw 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 |
| } |