| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; This test makes sure that these instructions are properly eliminated. |
| ; |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| declare void @use(i8) |
| |
| define i32 @shl_C1_add_A_C2_i32(i16 %A) { |
| ; CHECK-LABEL: @shl_C1_add_A_C2_i32( |
| ; CHECK-NEXT: [[B:%.*]] = zext i16 [[A:%.*]] to i32 |
| ; CHECK-NEXT: [[D:%.*]] = shl i32 192, [[B]] |
| ; CHECK-NEXT: ret i32 [[D]] |
| ; |
| %B = zext i16 %A to i32 |
| %C = add i32 %B, 5 |
| %D = shl i32 6, %C |
| ret i32 %D |
| } |
| |
| define i32 @ashr_C1_add_A_C2_i32(i32 %A) { |
| ; CHECK-LABEL: @ashr_C1_add_A_C2_i32( |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| %B = and i32 %A, 65535 |
| %C = add i32 %B, 5 |
| %D = ashr i32 6, %C |
| ret i32 %D |
| } |
| |
| define i32 @lshr_C1_add_A_C2_i32(i32 %A) { |
| ; CHECK-LABEL: @lshr_C1_add_A_C2_i32( |
| ; CHECK-NEXT: [[B:%.*]] = and i32 [[A:%.*]], 65535 |
| ; CHECK-NEXT: [[D:%.*]] = shl i32 192, [[B]] |
| ; CHECK-NEXT: ret i32 [[D]] |
| ; |
| %B = and i32 %A, 65535 |
| %C = add i32 %B, 5 |
| %D = shl i32 6, %C |
| ret i32 %D |
| } |
| |
| define <4 x i32> @shl_C1_add_A_C2_v4i32(<4 x i16> %A) { |
| ; CHECK-LABEL: @shl_C1_add_A_C2_v4i32( |
| ; CHECK-NEXT: [[B:%.*]] = zext <4 x i16> [[A:%.*]] to <4 x i32> |
| ; CHECK-NEXT: [[D:%.*]] = shl <4 x i32> <i32 6, i32 4, i32 poison, i32 -458752>, [[B]] |
| ; CHECK-NEXT: ret <4 x i32> [[D]] |
| ; |
| %B = zext <4 x i16> %A to <4 x i32> |
| %C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16> |
| %D = shl <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C |
| ret <4 x i32> %D |
| } |
| |
| define <4 x i32> @ashr_C1_add_A_C2_v4i32(<4 x i32> %A) { |
| ; CHECK-LABEL: @ashr_C1_add_A_C2_v4i32( |
| ; CHECK-NEXT: [[B:%.*]] = and <4 x i32> [[A:%.*]], <i32 0, i32 15, i32 255, i32 65535> |
| ; CHECK-NEXT: [[D:%.*]] = ashr <4 x i32> <i32 6, i32 1, i32 poison, i32 -1>, [[B]] |
| ; CHECK-NEXT: ret <4 x i32> [[D]] |
| ; |
| %B = and <4 x i32> %A, <i32 0, i32 15, i32 255, i32 65535> |
| %C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16> |
| %D = ashr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C |
| ret <4 x i32> %D |
| } |
| |
| define <4 x i32> @lshr_C1_add_A_C2_v4i32(<4 x i32> %A) { |
| ; CHECK-LABEL: @lshr_C1_add_A_C2_v4i32( |
| ; CHECK-NEXT: [[B:%.*]] = and <4 x i32> [[A:%.*]], <i32 0, i32 15, i32 255, i32 65535> |
| ; CHECK-NEXT: [[D:%.*]] = lshr <4 x i32> <i32 6, i32 1, i32 poison, i32 65535>, [[B]] |
| ; CHECK-NEXT: ret <4 x i32> [[D]] |
| ; |
| %B = and <4 x i32> %A, <i32 0, i32 15, i32 255, i32 65535> |
| %C = add <4 x i32> %B, <i32 0, i32 1, i32 50, i32 16> |
| %D = lshr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %C |
| ret <4 x i32> %D |
| } |
| |
| define <4 x i32> @shl_C1_add_A_C2_v4i32_splat(i16 %I) { |
| ; CHECK-LABEL: @shl_C1_add_A_C2_v4i32_splat( |
| ; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32 |
| ; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> undef, i32 [[A]], i64 0 |
| ; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> undef, <4 x i32> zeroinitializer |
| ; CHECK-NEXT: [[E:%.*]] = shl <4 x i32> <i32 6, i32 4, i32 poison, i32 -458752>, [[C]] |
| ; CHECK-NEXT: ret <4 x i32> [[E]] |
| ; |
| %A = zext i16 %I to i32 |
| %B = insertelement <4 x i32> undef, i32 %A, i32 0 |
| %C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer |
| %D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16> |
| %E = shl <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D |
| ret <4 x i32> %E |
| } |
| |
| define <4 x i32> @ashr_C1_add_A_C2_v4i32_splat(i16 %I) { |
| ; CHECK-LABEL: @ashr_C1_add_A_C2_v4i32_splat( |
| ; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32 |
| ; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> undef, i32 [[A]], i64 0 |
| ; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> undef, <4 x i32> zeroinitializer |
| ; CHECK-NEXT: [[E:%.*]] = ashr <4 x i32> <i32 6, i32 1, i32 poison, i32 -1>, [[C]] |
| ; CHECK-NEXT: ret <4 x i32> [[E]] |
| ; |
| %A = zext i16 %I to i32 |
| %B = insertelement <4 x i32> undef, i32 %A, i32 0 |
| %C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer |
| %D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16> |
| %E = ashr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D |
| ret <4 x i32> %E |
| } |
| |
| define <4 x i32> @lshr_C1_add_A_C2_v4i32_splat(i16 %I) { |
| ; CHECK-LABEL: @lshr_C1_add_A_C2_v4i32_splat( |
| ; CHECK-NEXT: [[A:%.*]] = zext i16 [[I:%.*]] to i32 |
| ; CHECK-NEXT: [[B:%.*]] = insertelement <4 x i32> undef, i32 [[A]], i64 0 |
| ; CHECK-NEXT: [[C:%.*]] = shufflevector <4 x i32> [[B]], <4 x i32> undef, <4 x i32> zeroinitializer |
| ; CHECK-NEXT: [[E:%.*]] = lshr <4 x i32> <i32 6, i32 1, i32 poison, i32 65535>, [[C]] |
| ; CHECK-NEXT: ret <4 x i32> [[E]] |
| ; |
| %A = zext i16 %I to i32 |
| %B = insertelement <4 x i32> undef, i32 %A, i32 0 |
| %C = shufflevector <4 x i32> %B, <4 x i32> undef, <4 x i32> zeroinitializer |
| %D = add <4 x i32> %C, <i32 0, i32 1, i32 50, i32 16> |
| %E = lshr <4 x i32> <i32 6, i32 2, i32 1, i32 -7>, %D |
| ret <4 x i32> %E |
| } |
| |
| define i32 @shl_add_nuw(i32 %x) { |
| ; CHECK-LABEL: @shl_add_nuw( |
| ; CHECK-NEXT: [[R:%.*]] = shl i32 192, [[X:%.*]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add nuw i32 %x, 5 |
| %r = shl i32 6, %a |
| ret i32 %r |
| } |
| |
| ; vectors with arbitrary constants work too |
| |
| define <2 x i12> @lshr_add_nuw(<2 x i12> %x) { |
| ; CHECK-LABEL: @lshr_add_nuw( |
| ; CHECK-NEXT: [[R:%.*]] = lshr <2 x i12> <i12 0, i12 21>, [[X:%.*]] |
| ; CHECK-NEXT: ret <2 x i12> [[R]] |
| ; |
| %a = add nuw <2 x i12> %x, <i12 5, i12 1> |
| %r = lshr <2 x i12> <i12 6, i12 42>, %a |
| ret <2 x i12> %r |
| } |
| |
| ; extra use is ok and in this case the result can be simplified to a constant |
| |
| define i32 @ashr_add_nuw(i32 %x, ptr %p) { |
| ; CHECK-LABEL: @ashr_add_nuw( |
| ; CHECK-NEXT: [[A:%.*]] = add nuw i32 [[X:%.*]], 5 |
| ; CHECK-NEXT: store i32 [[A]], ptr [[P:%.*]], align 4 |
| ; CHECK-NEXT: ret i32 -1 |
| ; |
| %a = add nuw i32 %x, 5 |
| store i32 %a, ptr %p |
| %r = ashr i32 -6, %a |
| ret i32 %r |
| } |
| |
| ; negative test - must have 'nuw' |
| |
| define i32 @shl_add_nsw(i32 %x) { |
| ; CHECK-LABEL: @shl_add_nsw( |
| ; CHECK-NEXT: [[A:%.*]] = add nsw i32 [[X:%.*]], 5 |
| ; CHECK-NEXT: [[R:%.*]] = shl i32 6, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add nsw i32 %x, 5 |
| %r = shl i32 6, %a |
| ret i32 %r |
| } |
| |
| ; offset precondition check (must be negative constant) for lshr_exact_add_negative_shift_positive |
| |
| define i32 @lshr_exact_add_positive_shift_positive(i32 %x) { |
| ; CHECK-LABEL: @lshr_exact_add_positive_shift_positive( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 1 |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, 1 |
| %r = lshr exact i32 2, %a |
| ret i32 %r |
| } |
| |
| define i32 @lshr_exact_add_big_negative_offset(i32 %x) { |
| ; CHECK-LABEL: @lshr_exact_add_big_negative_offset( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33 |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact i32 2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -33 |
| %r = lshr exact i32 2, %a |
| ret i32 %r |
| } |
| |
| ; leading zeros for shifted constant precondition check for lshr_exact_add_negative_shift_positive |
| |
| define i32 @lshr_exact_add_negative_shift_negative(i32 %x) { |
| ; CHECK-LABEL: @lshr_exact_add_negative_shift_negative( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1 |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact i32 -2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = lshr exact i32 -2, %a |
| ret i32 %r |
| } |
| |
| ; exact precondition check for lshr_exact_add_negative_shift_positive |
| |
| define i32 @lshr_add_negative_shift_no_exact(i32 %x) { |
| ; CHECK-LABEL: @lshr_add_negative_shift_no_exact( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1 |
| ; CHECK-NEXT: [[R:%.*]] = lshr i32 2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = lshr i32 2, %a |
| ret i32 %r |
| } |
| |
| define i32 @lshr_exact_add_negative_shift_positive(i32 %x) { |
| ; CHECK-LABEL: @lshr_exact_add_negative_shift_positive( |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact i32 4, [[X:%.*]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = lshr exact i32 2, %a |
| ret i32 %r |
| } |
| |
| define i8 @lshr_exact_add_negative_shift_positive_extra_use(i8 %x) { |
| ; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_extra_use( |
| ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -1 |
| ; CHECK-NEXT: call void @use(i8 [[A]]) |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact i8 -128, [[X]] |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %a = add i8 %x, -1 |
| call void @use(i8 %a) |
| %r = lshr exact i8 64, %a |
| ret i8 %r |
| } |
| |
| define <2 x i9> @lshr_exact_add_negative_shift_positive_vec(<2 x i9> %x) { |
| ; CHECK-LABEL: @lshr_exact_add_negative_shift_positive_vec( |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 -256, i9 -256>, [[X:%.*]] |
| ; CHECK-NEXT: ret <2 x i9> [[R]] |
| ; |
| %a = add <2 x i9> %x, <i9 -7, i9 -7> |
| %r = lshr exact <2 x i9> <i9 2, i9 2>, %a |
| ret <2 x i9> %r |
| } |
| |
| ; not enough leading zeros in shift constant |
| |
| define <2 x i9> @lshr_exact_add_negative_shift_lzcnt(<2 x i9> %x) { |
| ; CHECK-LABEL: @lshr_exact_add_negative_shift_lzcnt( |
| ; CHECK-NEXT: [[A:%.*]] = add <2 x i9> [[X:%.*]], <i9 -7, i9 -7> |
| ; CHECK-NEXT: [[R:%.*]] = lshr exact <2 x i9> <i9 4, i9 4>, [[A]] |
| ; CHECK-NEXT: ret <2 x i9> [[R]] |
| ; |
| %a = add <2 x i9> %x, <i9 -7, i9 -7> |
| %r = lshr exact <2 x i9> <i9 4, i9 4>, %a |
| ret <2 x i9> %r |
| } |
| |
| ; leading ones precondition check for ashr_exact_add_negative_shift_[positive,negative] |
| |
| define i8 @ashr_exact_add_negative_shift_no_trailing_zeros(i8 %x) { |
| ; CHECK-LABEL: @ashr_exact_add_negative_shift_no_trailing_zeros( |
| ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -4 |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -112, [[A]] |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %a = add i8 %x, -4 |
| %r = ashr exact i8 -112, %a ; 0b1001_0000 |
| ret i8 %r |
| } |
| |
| define i32 @ashr_exact_add_big_negative_offset(i32 %x) { |
| ; CHECK-LABEL: @ashr_exact_add_big_negative_offset( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33 |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -33 |
| %r = ashr exact i32 -2, %a |
| ret i32 %r |
| } |
| |
| ; exact precondition check for ashr_exact_add_negative_shift_[positive,negative] |
| |
| define i32 @ashr_add_negative_shift_no_exact(i32 %x) { |
| ; CHECK-LABEL: @ashr_add_negative_shift_no_exact( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -1 |
| ; CHECK-NEXT: [[R:%.*]] = ashr i32 -2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = ashr i32 -2, %a |
| ret i32 %r |
| } |
| |
| define i32 @ashr_exact_add_negative_shift_negative(i32 %x) { |
| ; CHECK-LABEL: @ashr_exact_add_negative_shift_negative( |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact i32 -4, [[X:%.*]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = ashr exact i32 -2, %a |
| ret i32 %r |
| } |
| |
| define i8 @ashr_exact_add_negative_shift_negative_extra_use(i8 %x) { |
| ; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_extra_use( |
| ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], -2 |
| ; CHECK-NEXT: call void @use(i8 [[A]]) |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact i8 -128, [[X]] |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %a = add i8 %x, -2 |
| call void @use(i8 %a) |
| %r = ashr exact i8 -32, %a |
| ret i8 %r |
| } |
| |
| define <2 x i7> @ashr_exact_add_negative_shift_negative_vec(<2 x i7> %x) { |
| ; CHECK-LABEL: @ashr_exact_add_negative_shift_negative_vec( |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -64, i7 -64>, [[X:%.*]] |
| ; CHECK-NEXT: ret <2 x i7> [[R]] |
| ; |
| %a = add <2 x i7> %x, <i7 -5, i7 -5> |
| %r = ashr exact <2 x i7> <i7 -2, i7 -2>, %a |
| ret <2 x i7> %r |
| } |
| |
| ; not enough leading ones in shift constant |
| |
| define <2 x i7> @ashr_exact_add_negative_leading_ones_vec(<2 x i7> %x) { |
| ; CHECK-LABEL: @ashr_exact_add_negative_leading_ones_vec( |
| ; CHECK-NEXT: [[A:%.*]] = add <2 x i7> [[X:%.*]], <i7 -5, i7 -5> |
| ; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i7> <i7 -4, i7 -4>, [[A]] |
| ; CHECK-NEXT: ret <2 x i7> [[R]] |
| ; |
| %a = add <2 x i7> %x, <i7 -5, i7 -5> |
| %r = ashr exact <2 x i7> <i7 -4, i7 -4>, %a |
| ret <2 x i7> %r |
| } |
| |
| ; PR54890 |
| |
| define i32 @shl_nsw_add_negative(i32 %x) { |
| ; CHECK-LABEL: @shl_nsw_add_negative( |
| ; CHECK-NEXT: [[R:%.*]] = shl nuw i32 1, [[X:%.*]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -1 |
| %r = shl nsw i32 2, %a |
| ret i32 %r |
| } |
| |
| ; vectors and extra uses are allowed |
| ; nuw propagates to the new shift |
| |
| define <2 x i8> @shl_nuw_add_negative_splat_uses(<2 x i8> %x, ptr %p) { |
| ; CHECK-LABEL: @shl_nuw_add_negative_splat_uses( |
| ; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], <i8 -2, i8 -2> |
| ; CHECK-NEXT: store <2 x i8> [[A]], ptr [[P:%.*]], align 2 |
| ; CHECK-NEXT: [[R:%.*]] = shl nuw <2 x i8> <i8 3, i8 3>, [[X]] |
| ; CHECK-NEXT: ret <2 x i8> [[R]] |
| ; |
| %a = add <2 x i8> %x, <i8 -2, i8 -2> |
| store <2 x i8> %a, ptr %p |
| %r = shl nuw <2 x i8> <i8 12, i8 12>, %a |
| ret <2 x i8> %r |
| } |
| |
| ; negative test - shift constant must have enough trailing zeros to allow the pre-shift |
| |
| define i32 @shl_nsw_add_negative_invalid_constant(i32 %x) { |
| ; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2 |
| ; CHECK-NEXT: [[R:%.*]] = shl nsw i32 2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -2 |
| %r = shl nsw i32 2, %a |
| ret i32 %r |
| } |
| |
| ; negative test - the offset constant must be negative |
| |
| define i32 @shl_nsw_add_positive_invalid_constant(i32 %x) { |
| ; CHECK-LABEL: @shl_nsw_add_positive_invalid_constant( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], 2 |
| ; CHECK-NEXT: [[R:%.*]] = shl nsw i32 4, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, 2 |
| %r = shl nsw i32 4, %a |
| ret i32 %r |
| } |
| |
| ; negative test - a large shift must be detected without crashing |
| |
| define i32 @shl_nsw_add_negative_invalid_constant2(i32 %x) { |
| ; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant2( |
| ; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -33 |
| ; CHECK-NEXT: [[R:%.*]] = shl nsw i32 2, [[A]] |
| ; CHECK-NEXT: ret i32 [[R]] |
| ; |
| %a = add i32 %x, -33 |
| %r = shl nsw i32 2, %a |
| ret i32 %r |
| } |
| |
| ; negative test - currently transformed to 'xor' before we see it, |
| ; but INT_MIN should be handled too |
| |
| define i4 @shl_nsw_add_negative_invalid_constant3(i4 %x) { |
| ; CHECK-LABEL: @shl_nsw_add_negative_invalid_constant3( |
| ; CHECK-NEXT: [[A:%.*]] = xor i4 [[X:%.*]], -8 |
| ; CHECK-NEXT: [[R:%.*]] = shl nsw i4 2, [[A]] |
| ; CHECK-NEXT: ret i4 [[R]] |
| ; |
| %a = add i4 %x, 8 |
| %r = shl nsw i4 2, %a |
| ret i4 %r |
| } |
| |
| define i2 @lshr_2_add_zext_basic(i1 %a, i1 %b) { |
| ; CHECK-LABEL: @lshr_2_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[TMP1]] to i2 |
| ; CHECK-NEXT: ret i2 [[LSHR]] |
| ; |
| %zext.a = zext i1 %a to i2 |
| %zext.b = zext i1 %b to i2 |
| %add = add i2 %zext.a, %zext.b |
| %lshr = lshr i2 %add, 1 |
| ret i2 %lshr |
| } |
| |
| define i2 @ashr_2_add_zext_basic(i1 %a, i1 %b) { |
| ; CHECK-LABEL: @ashr_2_add_zext_basic( |
| ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i1 [[A:%.*]] to i2 |
| ; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i1 [[B:%.*]] to i2 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw i2 [[ZEXT_A]], [[ZEXT_B]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = ashr i2 [[ADD]], 1 |
| ; CHECK-NEXT: ret i2 [[LSHR]] |
| ; |
| %zext.a = zext i1 %a to i2 |
| %zext.b = zext i1 %b to i2 |
| %add = add i2 %zext.a, %zext.b |
| %lshr = ashr i2 %add, 1 |
| ret i2 %lshr |
| } |
| |
| define i32 @lshr_16_add_zext_basic(i16 %a, i16 %b) { |
| ; CHECK-LABEL: @lshr_16_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 |
| ; CHECK-NEXT: ret i32 [[LSHR]] |
| ; |
| %zext.a = zext i16 %a to i32 |
| %zext.b = zext i16 %b to i32 |
| %add = add i32 %zext.a, %zext.b |
| %lshr = lshr i32 %add, 16 |
| ret i32 %lshr |
| } |
| |
| define i32 @lshr_16_add_zext_basic_multiuse(i16 %a, i16 %b) { |
| ; CHECK-LABEL: @lshr_16_add_zext_basic_multiuse( |
| ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i16 [[A:%.*]] to i32 |
| ; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i16 [[B:%.*]] to i32 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[ZEXT_A]], [[ZEXT_B]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16 |
| ; CHECK-NEXT: [[OTHERUSE:%.*]] = or i32 [[LSHR]], [[ZEXT_A]] |
| ; CHECK-NEXT: ret i32 [[OTHERUSE]] |
| ; |
| %zext.a = zext i16 %a to i32 |
| %zext.b = zext i16 %b to i32 |
| %add = add i32 %zext.a, %zext.b |
| %lshr = lshr i32 %add, 16 |
| %otheruse = or i32 %lshr, %zext.a |
| ret i32 %otheruse |
| } |
| |
| define i32 @lshr_16_add_known_16_leading_zeroes(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_16_add_known_16_leading_zeroes( |
| ; CHECK-NEXT: [[A16:%.*]] = and i32 [[A:%.*]], 65535 |
| ; CHECK-NEXT: [[B16:%.*]] = and i32 [[B:%.*]], 65535 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A16]], [[B16]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16 |
| ; CHECK-NEXT: ret i32 [[LSHR]] |
| ; |
| %a16 = and i32 %a, 65535 ; 0x65535 |
| %b16 = and i32 %b, 65535 ; 0x65535 |
| %add = add i32 %a16, %b16 |
| %lshr = lshr i32 %add, 16 |
| ret i32 %lshr |
| } |
| |
| define i32 @lshr_16_add_not_known_16_leading_zeroes(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_16_add_not_known_16_leading_zeroes( |
| ; CHECK-NEXT: [[A16:%.*]] = and i32 [[A:%.*]], 131071 |
| ; CHECK-NEXT: [[B16:%.*]] = and i32 [[B:%.*]], 65535 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A16]], [[B16]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], 16 |
| ; CHECK-NEXT: ret i32 [[LSHR]] |
| ; |
| %a16 = and i32 %a, 131071 ; 0x1FFFF |
| %b16 = and i32 %b, 65535 ; 0x65535 |
| %add = add i32 %a16, %b16 |
| %lshr = lshr i32 %add, 16 |
| ret i32 %lshr |
| } |
| |
| define i64 @lshr_32_add_zext_basic(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_32_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = lshr i64 %add, 32 |
| ret i64 %lshr |
| } |
| |
| define i64 @lshr_32_add_zext_basic_multiuse(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_32_add_zext_basic_multiuse( |
| ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64 |
| ; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32 |
| ; CHECK-NEXT: [[OTHERUSE:%.*]] = or i64 [[LSHR]], [[ZEXT_B]] |
| ; CHECK-NEXT: ret i64 [[OTHERUSE]] |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = lshr i64 %add, 32 |
| %otheruse = or i64 %lshr, %zext.b |
| ret i64 %otheruse |
| } |
| |
| define i64 @lshr_31_i32_add_zext_basic(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_31_i32_add_zext_basic( |
| ; CHECK-NEXT: [[ZEXT_A:%.*]] = zext i32 [[A:%.*]] to i64 |
| ; CHECK-NEXT: [[ZEXT_B:%.*]] = zext i32 [[B:%.*]] to i64 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[ZEXT_A]], [[ZEXT_B]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 31 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = lshr i64 %add, 31 |
| ret i64 %lshr |
| } |
| |
| define i64 @lshr_33_i32_add_zext_basic(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_33_i32_add_zext_basic( |
| ; CHECK-NEXT: ret i64 0 |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = lshr i64 %add, 33 |
| ret i64 %lshr |
| } |
| |
| define i64 @lshr_16_to_64_add_zext_basic(i16 %a, i16 %b) { |
| ; CHECK-LABEL: @lshr_16_to_64_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %zext.a = zext i16 %a to i64 |
| %zext.b = zext i16 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = lshr i64 %add, 16 |
| ret i64 %lshr |
| } |
| |
| define i64 @lshr_32_add_known_32_leading_zeroes(i64 %a, i64 %b) { |
| ; CHECK-LABEL: @lshr_32_add_known_32_leading_zeroes( |
| ; CHECK-NEXT: [[A32:%.*]] = and i64 [[A:%.*]], 4294967295 |
| ; CHECK-NEXT: [[B32:%.*]] = and i64 [[B:%.*]], 4294967295 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[A32]], [[B32]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %a32 = and i64 %a, 4294967295 ; 0xFFFFFFFF |
| %b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF |
| %add = add i64 %a32, %b32 |
| %lshr = lshr i64 %add, 32 |
| ret i64 %lshr |
| } |
| |
| define i64 @lshr_32_add_not_known_32_leading_zeroes(i64 %a, i64 %b) { |
| ; |
| ; CHECK-LABEL: @lshr_32_add_not_known_32_leading_zeroes( |
| ; CHECK-NEXT: [[A32:%.*]] = and i64 [[A:%.*]], 8589934591 |
| ; CHECK-NEXT: [[B32:%.*]] = and i64 [[B:%.*]], 4294967295 |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[A32]], [[B32]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = lshr i64 [[ADD]], 32 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %a32 = and i64 %a, 8589934591 ; 0x1FFFFFFFF |
| %b32 = and i64 %b, 4294967295 ; 0xFFFFFFFF |
| %add = add i64 %a32, %b32 |
| %lshr = lshr i64 %add, 32 |
| ret i64 %lshr |
| } |
| |
| define i32 @ashr_16_add_zext_basic(i16 %a, i16 %b) { |
| ; CHECK-LABEL: @ashr_16_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 |
| ; CHECK-NEXT: ret i32 [[LSHR]] |
| ; |
| %zext.a = zext i16 %a to i32 |
| %zext.b = zext i16 %b to i32 |
| %add = add i32 %zext.a, %zext.b |
| %lshr = lshr i32 %add, 16 |
| ret i32 %lshr |
| } |
| |
| define i64 @ashr_32_add_zext_basic(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @ashr_32_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = ashr i64 %add, 32 |
| ret i64 %lshr |
| } |
| |
| define i64 @ashr_16_to_64_add_zext_basic(i16 %a, i16 %b) { |
| ; CHECK-LABEL: @ashr_16_to_64_add_zext_basic( |
| ; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[A:%.*]], -1 |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i16 [[TMP1]], [[B:%.*]] |
| ; CHECK-NEXT: [[LSHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 |
| ; CHECK-NEXT: ret i64 [[LSHR]] |
| ; |
| %zext.a = zext i16 %a to i64 |
| %zext.b = zext i16 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %lshr = ashr i64 %add, 16 |
| ret i64 %lshr |
| } |
| |
| define i32 @lshr_32_add_zext_trunc(i32 %a, i32 %b) { |
| ; CHECK-LABEL: @lshr_32_add_zext_trunc( |
| ; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[A:%.*]], [[B:%.*]] |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[A]] |
| ; CHECK-NEXT: [[TRUNC_SHR:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i32 |
| ; CHECK-NEXT: [[RET:%.*]] = add i32 [[ADD_NARROWED]], [[TRUNC_SHR]] |
| ; CHECK-NEXT: ret i32 [[RET]] |
| ; |
| %zext.a = zext i32 %a to i64 |
| %zext.b = zext i32 %b to i64 |
| %add = add i64 %zext.a, %zext.b |
| %trunc.add = trunc i64 %add to i32 |
| %shr = lshr i64 %add, 32 |
| %trunc.shr = trunc i64 %shr to i32 |
| %ret = add i32 %trunc.add, %trunc.shr |
| ret i32 %ret |
| } |
| |
| define <3 x i32> @add3_i96(<3 x i32> %0, <3 x i32> %1) { |
| ; CHECK-LABEL: @add3_i96( |
| ; CHECK-NEXT: [[TMP3:%.*]] = extractelement <3 x i32> [[TMP0:%.*]], i64 0 |
| ; CHECK-NEXT: [[TMP4:%.*]] = extractelement <3 x i32> [[TMP1:%.*]], i64 0 |
| ; CHECK-NEXT: [[ADD_NARROWED:%.*]] = add i32 [[TMP4]], [[TMP3]] |
| ; CHECK-NEXT: [[ADD_NARROWED_OVERFLOW:%.*]] = icmp ult i32 [[ADD_NARROWED]], [[TMP4]] |
| ; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP0]], i64 1 |
| ; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[TMP5]] to i64 |
| ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <3 x i32> [[TMP1]], i64 1 |
| ; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64 |
| ; CHECK-NEXT: [[TMP9:%.*]] = add nuw nsw i64 [[TMP8]], [[TMP6]] |
| ; CHECK-NEXT: [[TMP10:%.*]] = zext i1 [[ADD_NARROWED_OVERFLOW]] to i64 |
| ; CHECK-NEXT: [[TMP11:%.*]] = add nuw nsw i64 [[TMP9]], [[TMP10]] |
| ; CHECK-NEXT: [[TMP12:%.*]] = extractelement <3 x i32> [[TMP0]], i64 2 |
| ; CHECK-NEXT: [[TMP13:%.*]] = extractelement <3 x i32> [[TMP1]], i64 2 |
| ; CHECK-NEXT: [[TMP14:%.*]] = add i32 [[TMP13]], [[TMP12]] |
| ; CHECK-NEXT: [[TMP15:%.*]] = lshr i64 [[TMP11]], 32 |
| ; CHECK-NEXT: [[TMP16:%.*]] = trunc i64 [[TMP15]] to i32 |
| ; CHECK-NEXT: [[TMP17:%.*]] = add i32 [[TMP14]], [[TMP16]] |
| ; CHECK-NEXT: [[TMP18:%.*]] = insertelement <3 x i32> undef, i32 [[ADD_NARROWED]], i64 0 |
| ; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP11]] to i32 |
| ; CHECK-NEXT: [[TMP20:%.*]] = insertelement <3 x i32> [[TMP18]], i32 [[TMP19]], i64 1 |
| ; CHECK-NEXT: [[TMP21:%.*]] = insertelement <3 x i32> [[TMP20]], i32 [[TMP17]], i64 2 |
| ; CHECK-NEXT: ret <3 x i32> [[TMP21]] |
| ; |
| %3 = extractelement <3 x i32> %0, i64 0 |
| %4 = zext i32 %3 to i64 |
| %5 = extractelement <3 x i32> %1, i64 0 |
| %6 = zext i32 %5 to i64 |
| %7 = add nuw nsw i64 %6, %4 |
| %8 = extractelement <3 x i32> %0, i64 1 |
| %9 = zext i32 %8 to i64 |
| %10 = extractelement <3 x i32> %1, i64 1 |
| %11 = zext i32 %10 to i64 |
| %12 = add nuw nsw i64 %11, %9 |
| %13 = lshr i64 %7, 32 |
| %14 = add nuw nsw i64 %12, %13 |
| %15 = extractelement <3 x i32> %0, i64 2 |
| %16 = extractelement <3 x i32> %1, i64 2 |
| %17 = add i32 %16, %15 |
| %18 = lshr i64 %14, 32 |
| %19 = trunc i64 %18 to i32 |
| %20 = add i32 %17, %19 |
| %21 = trunc i64 %7 to i32 |
| %22 = insertelement <3 x i32> undef, i32 %21, i32 0 |
| %23 = trunc i64 %14 to i32 |
| %24 = insertelement <3 x i32> %22, i32 %23, i32 1 |
| %25 = insertelement <3 x i32> %24, i32 %20, i32 2 |
| ret <3 x i32> %25 |
| } |