| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instcombine -S | FileCheck %s |
| |
| define i32 @foo(i32 %x, i32 %y) { |
| ; CHECK-LABEL: @foo( |
| ; CHECK-NEXT: [[A:%.*]] = and i32 [[X:%.*]], 7 |
| ; CHECK-NEXT: [[B:%.*]] = and i32 [[Y:%.*]], 7 |
| ; CHECK-NEXT: [[C:%.*]] = mul nuw nsw i32 [[A]], [[B]] |
| ; CHECK-NEXT: [[D:%.*]] = shl nuw i32 [[C]], 26 |
| ; CHECK-NEXT: [[E:%.*]] = ashr exact i32 [[D]], 26 |
| ; CHECK-NEXT: ret i32 [[E]] |
| ; |
| %a = and i32 %x, 7 |
| %b = and i32 %y, 7 |
| %c = mul i32 %a, %b |
| %d = shl i32 %c, 26 |
| %e = ashr i32 %d, 26 |
| ret i32 %e |
| } |
| |
| ; PR48683 'Quadratic Reciprocity' - and(mul(x,x),2) -> 0 |
| |
| define i1 @PR48683(i32 %x) { |
| ; CHECK-LABEL: @PR48683( |
| ; CHECK-NEXT: ret i1 false |
| ; |
| %a = mul i32 %x, %x |
| %b = and i32 %a, 2 |
| %c = icmp ne i32 %b, 0 |
| ret i1 %c |
| } |
| |
| define <4 x i1> @PR48683_vec(<4 x i32> %x) { |
| ; CHECK-LABEL: @PR48683_vec( |
| ; CHECK-NEXT: ret <4 x i1> zeroinitializer |
| ; |
| %a = mul <4 x i32> %x, %x |
| %b = and <4 x i32> %a, <i32 2, i32 2, i32 2, i32 2> |
| %c = icmp ne <4 x i32> %b, zeroinitializer |
| ret <4 x i1> %c |
| } |
| |
| define <4 x i1> @PR48683_vec_undef(<4 x i32> %x) { |
| ; CHECK-LABEL: @PR48683_vec_undef( |
| ; CHECK-NEXT: [[A:%.*]] = mul <4 x i32> [[X:%.*]], [[X]] |
| ; CHECK-NEXT: [[B:%.*]] = and <4 x i32> [[A]], <i32 2, i32 2, i32 2, i32 undef> |
| ; CHECK-NEXT: [[C:%.*]] = icmp ne <4 x i32> [[B]], zeroinitializer |
| ; CHECK-NEXT: ret <4 x i1> [[C]] |
| ; |
| %a = mul <4 x i32> %x, %x |
| %b = and <4 x i32> %a, <i32 2, i32 2, i32 2, i32 undef> |
| %c = icmp ne <4 x i32> %b, zeroinitializer |
| ret <4 x i1> %c |
| } |
| |
| ; mul(x,x) - bit[1] is 0, but if demanding the other bits the source must not be undef |
| |
| define i64 @combine_mul_self_demandedbits(i64 %x) { |
| ; CHECK-LABEL: @combine_mul_self_demandedbits( |
| ; CHECK-NEXT: [[TMP1:%.*]] = mul i64 [[X:%.*]], [[X]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], -3 |
| ; CHECK-NEXT: ret i64 [[TMP2]] |
| ; |
| %1 = mul i64 %x, %x |
| %2 = and i64 %1, -3 |
| ret i64 %2 |
| } |
| |
| define <4 x i32> @combine_mul_self_demandedbits_vector(<4 x i32> %x) { |
| ; CHECK-LABEL: @combine_mul_self_demandedbits_vector( |
| ; CHECK-NEXT: [[TMP1:%.*]] = freeze <4 x i32> [[X:%.*]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = mul <4 x i32> [[TMP1]], [[TMP1]] |
| ; CHECK-NEXT: ret <4 x i32> [[TMP2]] |
| ; |
| %1 = freeze <4 x i32> %x |
| %2 = mul <4 x i32> %1, %1 |
| %3 = and <4 x i32> %2, <i32 -3, i32 -3, i32 -3, i32 -3> |
| ret <4 x i32> %3 |
| } |
| |
| define <vscale x 2 x i32> @combine_mul_self_demandedbits_vector2(<vscale x 2 x i32> %x) { |
| ; CHECK-LABEL: @combine_mul_self_demandedbits_vector2( |
| ; CHECK-NEXT: [[TMP1:%.*]] = freeze <vscale x 2 x i32> [[X:%.*]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = mul <vscale x 2 x i32> [[TMP1]], [[TMP1]] |
| ; CHECK-NEXT: ret <vscale x 2 x i32> [[TMP2]] |
| ; |
| %1 = freeze <vscale x 2 x i32> %x |
| %2 = mul <vscale x 2 x i32> %1, %1 |
| %3 = and <vscale x 2 x i32> %2, shufflevector (<vscale x 2 x i32> insertelement (<vscale x 2 x i32> poison, i32 -3, i32 0), <vscale x 2 x i32> poison, <vscale x 2 x i32> zeroinitializer) |
| ret <vscale x 2 x i32> %3 |
| } |
| |
| define i8 @one_demanded_bit(i8 %x) { |
| ; CHECK-LABEL: @one_demanded_bit( |
| ; CHECK-NEXT: [[M:%.*]] = shl i8 [[X:%.*]], 6 |
| ; CHECK-NEXT: [[R:%.*]] = or i8 [[M]], -65 |
| ; CHECK-NEXT: ret i8 [[R]] |
| ; |
| %m = mul i8 %x, 192 ; 0b1100_0000 |
| %r = or i8 %m, 191 ; 0b1011_1111 |
| ret i8 %r |
| } |
| |
| define <2 x i8> @one_demanded_bit_splat(<2 x i8> %x) { |
| ; CHECK-LABEL: @one_demanded_bit_splat( |
| ; CHECK-NEXT: [[M:%.*]] = shl <2 x i8> [[X:%.*]], <i8 5, i8 5> |
| ; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[M]], <i8 32, i8 32> |
| ; CHECK-NEXT: ret <2 x i8> [[R]] |
| ; |
| %m = mul <2 x i8> %x, <i8 160, i8 160> ; 0b1010_0000 |
| %r = and <2 x i8> %m, <i8 32, i8 32> ; 0b0010_0000 |
| ret <2 x i8> %r |
| } |
| |
| define i67 @one_demanded_low_bit(i67 %x) { |
| ; CHECK-LABEL: @one_demanded_low_bit( |
| ; CHECK-NEXT: [[R:%.*]] = and i67 [[X:%.*]], 1 |
| ; CHECK-NEXT: ret i67 [[R]] |
| ; |
| %m = mul i67 %x, -63 ; any odd number will do |
| %r = and i67 %m, 1 |
| ret i67 %r |
| } |
| |
| define i33 @squared_one_demanded_low_bit(i33 %x) { |
| ; CHECK-LABEL: @squared_one_demanded_low_bit( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i33 [[X:%.*]], 1 |
| ; CHECK-NEXT: ret i33 [[TMP1]] |
| ; |
| %mul = mul i33 %x, %x |
| %and = and i33 %mul, 1 |
| ret i33 %and |
| } |
| |
| define <2 x i8> @squared_one_demanded_low_bit_splat(<2 x i8> %x) { |
| ; CHECK-LABEL: @squared_one_demanded_low_bit_splat( |
| ; CHECK-NEXT: [[AND:%.*]] = or <2 x i8> [[X:%.*]], <i8 -2, i8 -2> |
| ; CHECK-NEXT: ret <2 x i8> [[AND]] |
| ; |
| %mul = mul <2 x i8> %x, %x |
| %and = or <2 x i8> %mul, <i8 254, i8 254> |
| ret <2 x i8> %and |
| } |
| |
| define i33 @squared_demanded_2_low_bits(i33 %x) { |
| ; CHECK-LABEL: @squared_demanded_2_low_bits( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i33 [[X:%.*]], 1 |
| ; CHECK-NEXT: ret i33 [[TMP1]] |
| ; |
| %mul = mul i33 %x, %x |
| %and = and i33 %mul, 3 |
| ret i33 %and |
| } |
| |
| define <2 x i8> @squared_demanded_2_low_bits_splat(<2 x i8> %x) { |
| ; CHECK-LABEL: @squared_demanded_2_low_bits_splat( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 1, i8 1> |
| ; CHECK-NEXT: [[AND:%.*]] = or <2 x i8> [[TMP1]], <i8 -4, i8 -4> |
| ; CHECK-NEXT: ret <2 x i8> [[AND]] |
| ; |
| %mul = mul <2 x i8> %x, %x |
| %and = or <2 x i8> %mul, <i8 252, i8 252> |
| ret <2 x i8> %and |
| } |
| |
| ; negative test |
| |
| define i33 @squared_demanded_3_low_bits(i33 %x) { |
| ; CHECK-LABEL: @squared_demanded_3_low_bits( |
| ; CHECK-NEXT: [[MUL:%.*]] = mul i33 [[X:%.*]], [[X]] |
| ; CHECK-NEXT: [[AND:%.*]] = and i33 [[MUL]], 7 |
| ; CHECK-NEXT: ret i33 [[AND]] |
| ; |
| %mul = mul i33 %x, %x |
| %and = and i33 %mul, 7 |
| ret i33 %and |
| } |
| |
| ; Instcombine should be able to simplify mul operator. |
| |
| ; Scalar tests |
| define i64 @scalar_mul_bit_x0_y0(i64 %x, i64 %y) { |
| ; CHECK-LABEL: @scalar_mul_bit_x0_y0( |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 1 |
| ; CHECK-NEXT: [[MUL:%.*]] = and i64 [[AND2]], [[X:%.*]] |
| ; CHECK-NEXT: ret i64 [[MUL]] |
| ; |
| %and1 = and i64 %x, 1 |
| %and2 = and i64 %y, 1 |
| %mul = mul i64 %and1, %and2 |
| ret i64 %mul |
| } |
| |
| declare void @use(i64) |
| |
| define i64 @scalar_mul_bit_x0_y0_uses(i64 %x, i64 %y) { |
| ; CHECK-LABEL: @scalar_mul_bit_x0_y0_uses( |
| ; CHECK-NEXT: [[AND1:%.*]] = and i64 [[X:%.*]], 1 |
| ; CHECK-NEXT: call void @use(i64 [[AND1]]) |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 1 |
| ; CHECK-NEXT: call void @use(i64 [[AND2]]) |
| ; CHECK-NEXT: [[MUL:%.*]] = and i64 [[AND2]], [[X]] |
| ; CHECK-NEXT: ret i64 [[MUL]] |
| ; |
| %and1 = and i64 %x, 1 |
| call void @use(i64 %and1) |
| %and2 = and i64 %y, 1 |
| call void @use(i64 %and2) |
| %mul = mul i64 %and1, %and2 |
| ret i64 %mul |
| } |
| |
| ; Negative test |
| define i64 @scalar_mul_bit_x0_y1(i64 %x, i64 %y) { |
| ; CHECK-LABEL: @scalar_mul_bit_x0_y1( |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[X:%.*]], 1 |
| ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i64 [[TMP1]], 0 |
| ; CHECK-NEXT: [[MUL:%.*]] = select i1 [[DOTNOT]], i64 0, i64 [[AND2]] |
| ; CHECK-NEXT: ret i64 [[MUL]] |
| ; |
| %and1 = and i64 %x, 1 |
| %and2 = and i64 %y, 2 |
| %mul = mul i64 %and1, %and2 |
| ret i64 %mul |
| } |
| |
| define i64 @scalar_mul_bit_x0_yC(i64 %x, i64 %y, i64 %c) { |
| ; CHECK-LABEL: @scalar_mul_bit_x0_yC( |
| ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], [[C:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[X:%.*]], 1 |
| ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i64 [[TMP1]], 0 |
| ; CHECK-NEXT: [[MUL:%.*]] = select i1 [[DOTNOT]], i64 0, i64 [[AND2]] |
| ; CHECK-NEXT: ret i64 [[MUL]] |
| ; |
| %and1 = and i64 %x, 1 |
| %and2 = and i64 %y, %c |
| %mul = mul i64 %and1, %and2 |
| ret i64 %mul |
| } |
| |
| ; Vector tests |
| define <2 x i64> @vector_mul_bit_x0_y0(<2 x i64> %x, <2 x i64> %y) { |
| ; CHECK-LABEL: @vector_mul_bit_x0_y0( |
| ; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[Y:%.*]], <i64 1, i64 1> |
| ; CHECK-NEXT: [[MUL:%.*]] = and <2 x i64> [[AND2]], [[X:%.*]] |
| ; CHECK-NEXT: ret <2 x i64> [[MUL]] |
| ; |
| %and1 = and <2 x i64> %x, <i64 1, i64 1> |
| %and2 = and <2 x i64> %y, <i64 1, i64 1> |
| %mul = mul <2 x i64> %and1, %and2 |
| ret <2 x i64> %mul |
| } |