| ; 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=36950 |
| |
| ; These all should be just and+icmp, there should be no select. |
| |
| define i32 @and_lshr_and(i32 %arg) { |
| ; CHECK-LABEL: @and_lshr_and( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[ARG:%.*]], 3 |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = zext i1 [[TMP2]] to i32 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 1 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = lshr i32 %arg, 1 |
| %t3 = and i32 %t2, 1 |
| %t4 = select i1 %t1, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| define <2 x i32> @and_lshr_and_splatvec(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_lshr_and_splatvec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 3, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T4]] |
| ; |
| %t = and <2 x i32> %arg, <i32 1, i32 1> |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = lshr <2 x i32> %arg, <i32 1, i32 1> |
| %t3 = and <2 x i32> %t2, <i32 1, i32 1> |
| %t4 = select <2 x i1> %t1, <2 x i32> %t3, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t4 |
| } |
| |
| define <2 x i32> @and_lshr_and_vec_v0(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_lshr_and_vec_v0( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 3, i32 6> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T4]] |
| ; |
| %t = and <2 x i32> %arg, <i32 1, i32 4> ; mask is not splat |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = lshr <2 x i32> %arg, <i32 1, i32 1> |
| %t3 = and <2 x i32> %t2, <i32 1, i32 1> |
| %t4 = select <2 x i1> %t1, <2 x i32> %t3, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t4 |
| } |
| |
| define <2 x i32> @and_lshr_and_vec_v1(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_lshr_and_vec_v1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 3, i32 5> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T4]] |
| ; |
| %t = and <2 x i32> %arg, <i32 1, i32 1> |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = lshr <2 x i32> %arg, <i32 1, i32 2> ; shift is not splat |
| %t3 = and <2 x i32> %t2, <i32 1, i32 1> |
| %t4 = select <2 x i1> %t1, <2 x i32> %t3, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t4 |
| } |
| |
| define <2 x i32> @and_lshr_and_vec_v2(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_lshr_and_vec_v2( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 12, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T4]] |
| ; |
| %t = and <2 x i32> %arg, <i32 8, i32 1> ; mask is not splat |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = lshr <2 x i32> %arg, <i32 2, i32 1> ; shift is not splat |
| %t3 = and <2 x i32> %t2, <i32 1, i32 1> |
| %t4 = select <2 x i1> %t1, <2 x i32> %t3, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t4 |
| } |
| |
| define <3 x i32> @and_lshr_and_vec_undef(<3 x i32> %arg) { |
| ; CHECK-LABEL: @and_lshr_and_vec_undef( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i32> [[ARG:%.*]], <i32 3, i32 poison, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <3 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <3 x i1> [[TMP2]] to <3 x i32> |
| ; CHECK-NEXT: ret <3 x i32> [[T4]] |
| ; |
| %t = and <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t1 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t2 = lshr <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t3 = and <3 x i32> %t2, <i32 1, i32 undef, i32 1> |
| ; The second element of %t4 is poison because it is (undef ? poison : undef). |
| %t4 = select <3 x i1> %t1, <3 x i32> %t3, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t4 |
| } |
| |
| define i32 @and_and(i32 %arg) { |
| ; CHECK-LABEL: @and_and( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[ARG:%.*]], 3 |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0 |
| ; CHECK-NEXT: [[T3:%.*]] = zext i1 [[TMP2]] to i32 |
| ; CHECK-NEXT: ret i32 [[T3]] |
| ; |
| %t = and i32 %arg, 2 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = and i32 %arg, 1 |
| %t3 = select i1 %t1, i32 %t2, i32 1 |
| ret i32 %t3 |
| } |
| |
| define <2 x i32> @and_and_splatvec(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_and_splatvec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 3, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T3:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T3]] |
| ; |
| %t = and <2 x i32> %arg, <i32 2, i32 2> |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = and <2 x i32> %arg, <i32 1, i32 1> |
| %t3 = select <2 x i1> %t1, <2 x i32> %t2, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t3 |
| } |
| |
| define <2 x i32> @and_and_vec(<2 x i32> %arg) { |
| ; CHECK-LABEL: @and_and_vec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 7, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T3:%.*]] = zext <2 x i1> [[TMP2]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T3]] |
| ; |
| %t = and <2 x i32> %arg, <i32 6, i32 2> ; mask is not splat |
| %t1 = icmp eq <2 x i32> %t, zeroinitializer |
| %t2 = and <2 x i32> %arg, <i32 1, i32 1> |
| %t3 = select <2 x i1> %t1, <2 x i32> %t2, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t3 |
| } |
| |
| define <3 x i32> @and_and_vec_undef(<3 x i32> %arg) { |
| ; CHECK-LABEL: @and_and_vec_undef( |
| ; CHECK-NEXT: [[TMP1:%.*]] = and <3 x i32> [[ARG:%.*]], <i32 3, i32 -1, i32 3> |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <3 x i32> [[TMP1]], zeroinitializer |
| ; CHECK-NEXT: [[T3:%.*]] = zext <3 x i1> [[TMP2]] to <3 x i32> |
| ; CHECK-NEXT: ret <3 x i32> [[T3]] |
| ; |
| %t = and <3 x i32> %arg, <i32 2, i32 undef, i32 2> |
| %t1 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t2 = and <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t3 = select <3 x i1> %t1, <3 x i32> %t2, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t3 |
| } |
| |
| ; ============================================================================ ; |
| ; Mask can be a variable, too. |
| ; ============================================================================ ; |
| |
| define i32 @f_var0(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @f_var0( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 2 |
| ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 |
| ; CHECK-NEXT: [[T5:%.*]] = zext i1 [[TMP3]] to i32 |
| ; CHECK-NEXT: ret i32 [[T5]] |
| ; |
| %t = and i32 %arg, %arg1 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = lshr i32 %arg, 1 |
| %t4 = and i32 %t3, 1 |
| %t5 = select i1 %t2, i32 %t4, i32 1 |
| ret i32 %t5 |
| } |
| |
| ; Should be exactly as the previous one |
| define i32 @f_var0_commutative_and(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @f_var0_commutative_and( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 2 |
| ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 |
| ; CHECK-NEXT: [[T5:%.*]] = zext i1 [[TMP3]] to i32 |
| ; CHECK-NEXT: ret i32 [[T5]] |
| ; |
| %t = and i32 %arg1, %arg ; in different order |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = lshr i32 %arg, 1 |
| %t4 = and i32 %t3, 1 |
| %t5 = select i1 %t2, i32 %t4, i32 1 |
| ret i32 %t5 |
| } |
| |
| define <2 x i32> @f_var0_splatvec(<2 x i32> %arg, <2 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var0_splatvec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[ARG1:%.*]], <i32 2, i32 2> |
| ; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne <2 x i32> [[TMP2]], zeroinitializer |
| ; CHECK-NEXT: [[T5:%.*]] = zext <2 x i1> [[TMP3]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T5]] |
| ; |
| %t = and <2 x i32> %arg, %arg1 |
| %t2 = icmp eq <2 x i32> %t, zeroinitializer |
| %t3 = lshr <2 x i32> %arg, <i32 1, i32 1> |
| %t4 = and <2 x i32> %t3, <i32 1, i32 1> |
| %t5 = select <2 x i1> %t2, <2 x i32> %t4, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t5 |
| } |
| |
| define <2 x i32> @f_var0_vec(<2 x i32> %arg, <2 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var0_vec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[ARG1:%.*]], <i32 2, i32 4> |
| ; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne <2 x i32> [[TMP2]], zeroinitializer |
| ; CHECK-NEXT: [[T5:%.*]] = zext <2 x i1> [[TMP3]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T5]] |
| ; |
| %t = and <2 x i32> %arg, %arg1 |
| %t2 = icmp eq <2 x i32> %t, zeroinitializer |
| %t3 = lshr <2 x i32> %arg, <i32 1, i32 2> ; shift is not splat |
| %t4 = and <2 x i32> %t3, <i32 1, i32 1> |
| %t5 = select <2 x i1> %t2, <2 x i32> %t4, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t5 |
| } |
| |
| define <3 x i32> @f_var0_vec_undef(<3 x i32> %arg, <3 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var0_vec_undef( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <3 x i32> [[ARG1:%.*]], <i32 2, i32 poison, i32 2> |
| ; CHECK-NEXT: [[TMP2:%.*]] = and <3 x i32> [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne <3 x i32> [[TMP2]], zeroinitializer |
| ; CHECK-NEXT: [[T5:%.*]] = zext <3 x i1> [[TMP3]] to <3 x i32> |
| ; CHECK-NEXT: ret <3 x i32> [[T5]] |
| ; |
| %t = and <3 x i32> %arg, %arg1 |
| %t2 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t3 = lshr <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t4 = and <3 x i32> %t3, <i32 1, i32 undef, i32 1> |
| ; The second element of %t5 is poison because it is (undef ? poison : undef). |
| %t5 = select <3 x i1> %t2, <3 x i32> %t4, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t5 |
| } |
| |
| define i32 @f_var1(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @f_var1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = zext i1 [[TMP3]] to i32 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, %arg1 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = and i32 %arg, 1 |
| %t4 = select i1 %t2, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| ; Should be exactly as the previous one |
| define i32 @f_var1_commutative_and(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @f_var1_commutative_and( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = zext i1 [[TMP3]] to i32 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg1, %arg ; in different order |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = and i32 %arg, 1 |
| %t4 = select i1 %t2, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| define <2 x i32> @f_var1_vec(<2 x i32> %arg, <2 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var1_vec( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[ARG1:%.*]], <i32 1, i32 1> |
| ; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne <2 x i32> [[TMP2]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <2 x i1> [[TMP3]] to <2 x i32> |
| ; CHECK-NEXT: ret <2 x i32> [[T4]] |
| ; |
| %t = and <2 x i32> %arg, %arg1 |
| %t2 = icmp eq <2 x i32> %t, zeroinitializer |
| %t3 = and <2 x i32> %arg, <i32 1, i32 1> |
| %t4 = select <2 x i1> %t2, <2 x i32> %t3, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t4 |
| } |
| |
| define <3 x i32> @f_var1_vec_undef(<3 x i32> %arg, <3 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var1_vec_undef( |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <3 x i32> [[ARG1:%.*]], <i32 1, i32 1, i32 1> |
| ; CHECK-NEXT: [[TMP2:%.*]] = and <3 x i32> [[TMP1]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne <3 x i32> [[TMP2]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = zext <3 x i1> [[TMP3]] to <3 x i32> |
| ; CHECK-NEXT: ret <3 x i32> [[T4]] |
| ; |
| %t = and <3 x i32> %arg, %arg1 |
| %t2 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t3 = and <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t4 = select <3 x i1> %t2, <3 x i32> %t3, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t4 |
| } |
| |
| ; ============================================================================ ; |
| ; Shift can't be a variable in general. |
| ; ============================================================================ ; |
| |
| define i32 @f_var2(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @f_var2( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[ARG]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 1 |
| ; CHECK-NEXT: [[T5:%.*]] = select i1 [[T2]], i32 [[T4]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T5]] |
| ; |
| %t = and i32 %arg, 1 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = lshr i32 %arg, %arg1 |
| %t4 = and i32 %t3, 1 |
| %t5 = select i1 %t2, i32 %t4, i32 1 |
| ret i32 %t5 |
| } |
| |
| define <2 x i32> @f_var2_splatvec(<2 x i32> %arg, <2 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var2_splatvec( |
| ; CHECK-NEXT: [[T:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 1, i32 1> |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq <2 x i32> [[T]], zeroinitializer |
| ; CHECK-NEXT: [[T3:%.*]] = lshr <2 x i32> [[ARG]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T4:%.*]] = and <2 x i32> [[T3]], <i32 1, i32 1> |
| ; CHECK-NEXT: [[T5:%.*]] = select <2 x i1> [[T2]], <2 x i32> [[T4]], <2 x i32> <i32 1, i32 1> |
| ; CHECK-NEXT: ret <2 x i32> [[T5]] |
| ; |
| %t = and <2 x i32> %arg, <i32 1, i32 1> |
| %t2 = icmp eq <2 x i32> %t, zeroinitializer |
| %t3 = lshr <2 x i32> %arg, %arg1 |
| %t4 = and <2 x i32> %t3, <i32 1, i32 1> |
| %t5 = select <2 x i1> %t2, <2 x i32> %t4, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t5 |
| } |
| |
| define <2 x i32> @f_var2_vec(<2 x i32> %arg, <2 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var2_vec( |
| ; CHECK-NEXT: [[T:%.*]] = and <2 x i32> [[ARG:%.*]], <i32 2, i32 1> |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq <2 x i32> [[T]], zeroinitializer |
| ; CHECK-NEXT: [[T3:%.*]] = lshr <2 x i32> [[ARG]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T4:%.*]] = and <2 x i32> [[T3]], <i32 1, i32 1> |
| ; CHECK-NEXT: [[T5:%.*]] = select <2 x i1> [[T2]], <2 x i32> [[T4]], <2 x i32> <i32 1, i32 1> |
| ; CHECK-NEXT: ret <2 x i32> [[T5]] |
| ; |
| %t = and <2 x i32> %arg, <i32 2, i32 1>; mask is not splat |
| %t2 = icmp eq <2 x i32> %t, zeroinitializer |
| %t3 = lshr <2 x i32> %arg, %arg1 |
| %t4 = and <2 x i32> %t3, <i32 1, i32 1> |
| %t5 = select <2 x i1> %t2, <2 x i32> %t4, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t5 |
| } |
| |
| define <3 x i32> @f_var2_vec_undef(<3 x i32> %arg, <3 x i32> %arg1) { |
| ; CHECK-LABEL: @f_var2_vec_undef( |
| ; CHECK-NEXT: [[T:%.*]] = and <3 x i32> [[ARG:%.*]], <i32 1, i32 undef, i32 1> |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq <3 x i32> [[T]], <i32 0, i32 undef, i32 0> |
| ; CHECK-NEXT: [[T3:%.*]] = lshr <3 x i32> [[ARG]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T4:%.*]] = and <3 x i32> [[T3]], <i32 1, i32 undef, i32 1> |
| ; CHECK-NEXT: [[T5:%.*]] = select <3 x i1> [[T2]], <3 x i32> [[T4]], <3 x i32> <i32 1, i32 undef, i32 1> |
| ; CHECK-NEXT: ret <3 x i32> [[T5]] |
| ; |
| %t = and <3 x i32> %arg, <i32 1, i32 undef, i32 1> |
| %t2 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t3 = lshr <3 x i32> %arg, %arg1 |
| %t4 = and <3 x i32> %t3, <i32 1, i32 undef, i32 1> |
| %t5 = select <3 x i1> %t2, <3 x i32> %t4, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t5 |
| } |
| |
| ; ============================================================================ ; |
| ; The worst case: both Mask and Shift are variables |
| ; ============================================================================ ; |
| |
| define i32 @f_var3(i32 %arg, i32 %arg1, i32 %arg2) { |
| ; CHECK-LABEL: @f_var3( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T3:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]] |
| ; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], 1 |
| ; CHECK-NEXT: [[T6:%.*]] = select i1 [[T3]], i32 [[T5]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T6]] |
| ; |
| %t = and i32 %arg, %arg1 |
| %t3 = icmp eq i32 %t, 0 |
| %t4 = lshr i32 %arg, %arg2 |
| %t5 = and i32 %t4, 1 |
| %t6 = select i1 %t3, i32 %t5, i32 1 |
| ret i32 %t6 |
| } |
| |
| ; Should be exactly as the previous one |
| define i32 @f_var3_commutative_and(i32 %arg, i32 %arg1, i32 %arg2) { |
| ; CHECK-LABEL: @f_var3_commutative_and( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]] |
| ; CHECK-NEXT: [[T3:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]] |
| ; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], 1 |
| ; CHECK-NEXT: [[T6:%.*]] = select i1 [[T3]], i32 [[T5]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T6]] |
| ; |
| %t = and i32 %arg1, %arg ; in different order |
| %t3 = icmp eq i32 %t, 0 |
| %t4 = lshr i32 %arg, %arg2 |
| %t5 = and i32 %t4, 1 |
| %t6 = select i1 %t3, i32 %t5, i32 1 |
| ret i32 %t6 |
| } |
| |
| define <2 x i32> @f_var3_splatvec(<2 x i32> %arg, <2 x i32> %arg1, <2 x i32> %arg2) { |
| ; CHECK-LABEL: @f_var3_splatvec( |
| ; CHECK-NEXT: [[T:%.*]] = and <2 x i32> [[ARG:%.*]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T3:%.*]] = icmp eq <2 x i32> [[T]], zeroinitializer |
| ; CHECK-NEXT: [[T4:%.*]] = lshr <2 x i32> [[ARG]], [[ARG2:%.*]] |
| ; CHECK-NEXT: [[T5:%.*]] = and <2 x i32> [[T4]], <i32 1, i32 1> |
| ; CHECK-NEXT: [[T6:%.*]] = select <2 x i1> [[T3]], <2 x i32> [[T5]], <2 x i32> <i32 1, i32 1> |
| ; CHECK-NEXT: ret <2 x i32> [[T6]] |
| ; |
| %t = and <2 x i32> %arg, %arg1 |
| %t3 = icmp eq <2 x i32> %t, zeroinitializer |
| %t4 = lshr <2 x i32> %arg, %arg2 |
| %t5 = and <2 x i32> %t4, <i32 1, i32 1> |
| %t6 = select <2 x i1> %t3, <2 x i32> %t5, <2 x i32> <i32 1, i32 1> |
| ret <2 x i32> %t6 |
| } |
| |
| define <3 x i32> @f_var3_vec_undef(<3 x i32> %arg, <3 x i32> %arg1, <3 x i32> %arg2) { |
| ; CHECK-LABEL: @f_var3_vec_undef( |
| ; CHECK-NEXT: [[T:%.*]] = and <3 x i32> [[ARG:%.*]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T3:%.*]] = icmp eq <3 x i32> [[T]], <i32 0, i32 undef, i32 0> |
| ; CHECK-NEXT: [[T4:%.*]] = lshr <3 x i32> [[ARG]], [[ARG2:%.*]] |
| ; CHECK-NEXT: [[T5:%.*]] = and <3 x i32> [[T4]], <i32 1, i32 undef, i32 1> |
| ; CHECK-NEXT: [[T6:%.*]] = select <3 x i1> [[T3]], <3 x i32> [[T5]], <3 x i32> <i32 1, i32 undef, i32 1> |
| ; CHECK-NEXT: ret <3 x i32> [[T6]] |
| ; |
| %t = and <3 x i32> %arg, %arg1 |
| %t3 = icmp eq <3 x i32> %t, <i32 0, i32 undef, i32 0> |
| %t4 = lshr <3 x i32> %arg, %arg2 |
| %t5 = and <3 x i32> %t4, <i32 1, i32 undef, i32 1> |
| %t6 = select <3 x i1> %t3, <3 x i32> %t5, <3 x i32> <i32 1, i32 undef, i32 1> |
| ret <3 x i32> %t6 |
| } |
| |
| ; ============================================================================ ; |
| ; Negative tests. Should not be folded. |
| ; ============================================================================ ; |
| |
| ; One use only. |
| |
| declare void @use32(i32) |
| |
| declare void @use1(i1) |
| |
| define i32 @n_var0_oneuse(i32 %arg, i32 %arg1, i32 %arg2) { |
| ; CHECK-LABEL: @n_var0_oneuse( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T3:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]] |
| ; CHECK-NEXT: [[T5:%.*]] = and i32 [[T4]], 1 |
| ; CHECK-NEXT: [[T6:%.*]] = select i1 [[T3]], i32 [[T5]], i32 1 |
| ; CHECK-NEXT: call void @use32(i32 [[T]]) |
| ; CHECK-NEXT: call void @use1(i1 [[T3]]) |
| ; CHECK-NEXT: call void @use32(i32 [[T4]]) |
| ; CHECK-NEXT: call void @use32(i32 [[T5]]) |
| ; CHECK-NEXT: ret i32 [[T6]] |
| ; |
| %t = and i32 %arg, %arg1 |
| %t3 = icmp eq i32 %t, 0 |
| %t4 = lshr i32 %arg, %arg2 |
| %t5 = and i32 %t4, 1 |
| %t6 = select i1 %t3, i32 %t5, i32 1 |
| call void @use32(i32 %t) |
| call void @use1(i1 %t3) |
| call void @use32(i32 %t4) |
| call void @use32(i32 %t5) |
| ret i32 %t6 |
| } |
| |
| define i32 @n_var1_oneuse(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @n_var1_oneuse( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], [[ARG1:%.*]] |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[ARG]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T2]], i32 [[T3]], i32 1 |
| ; CHECK-NEXT: call void @use32(i32 [[T]]) |
| ; CHECK-NEXT: call void @use1(i1 [[T2]]) |
| ; CHECK-NEXT: call void @use32(i32 [[T3]]) |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, %arg1 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = and i32 %arg, 1 |
| %t4 = select i1 %t2, i32 %t3, i32 1 |
| call void @use32(i32 %t) |
| call void @use1(i1 %t2) |
| call void @use32(i32 %t3) |
| ret i32 %t4 |
| } |
| |
| ; Different variables are used |
| |
| define i32 @n0(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @n0( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T3:%.*]] = lshr i32 [[ARG1:%.*]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = and i32 [[T3]], 1 |
| ; CHECK-NEXT: [[T5:%.*]] = select i1 [[T2]], i32 [[T4]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T5]] |
| ; |
| %t = and i32 %arg, 1 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = lshr i32 %arg1, 1 ; works on %arg1 instead of %arg |
| %t4 = and i32 %t3, 1 |
| %t5 = select i1 %t2, i32 %t4, i32 1 |
| ret i32 %t5 |
| } |
| |
| define i32 @n1(i32 %arg, i32 %arg1) { |
| ; CHECK-LABEL: @n1( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 2 |
| ; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[ARG1:%.*]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T2]], i32 [[T3]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 2 |
| %t2 = icmp eq i32 %t, 0 |
| %t3 = and i32 %arg1, 1 ; works on %arg1 instead of %arg |
| %t4 = select i1 %t2, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| ; False-value is not 1 |
| |
| define i32 @n2(i32 %arg) { |
| ; CHECK-LABEL: @n2( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[ARG]], 2 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[T2]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 [[T3]], i32 0 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 1 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = lshr i32 %arg, 2 |
| %t3 = and i32 %t2, 1 |
| %t4 = select i1 %t1, i32 %t3, i32 0 ; 0 instead of 1 |
| ret i32 %t4 |
| } |
| |
| define i32 @n3(i32 %arg) { |
| ; CHECK-LABEL: @n3( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 2 |
| ; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = and i32 [[ARG]], 1 |
| ; CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 [[T2]], i32 0 |
| ; CHECK-NEXT: ret i32 [[T3]] |
| ; |
| %t = and i32 %arg, 2 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = and i32 %arg, 1 |
| %t3 = select i1 %t1, i32 %t2, i32 0 ; 0 instead of 1 |
| ret i32 %t3 |
| } |
| |
| ; Mask of second and is not one |
| |
| define i32 @n4(i32 %arg) { |
| ; CHECK-LABEL: @n4( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[ARG]], 2 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[T2]], 2 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 [[T3]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 1 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = lshr i32 %arg, 2 |
| %t3 = and i32 %t2, 2 ; 2 instead of 1 |
| %t4 = select i1 %t1, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| define i32 @n5(i32 %arg) { |
| ; CHECK-LABEL: @n5( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 2 |
| ; CHECK-NEXT: [[T1:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = and i32 [[ARG]], 2 |
| ; CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 [[T2]], i32 1 |
| ; CHECK-NEXT: ret i32 [[T3]] |
| ; |
| %t = and i32 %arg, 2 |
| %t1 = icmp eq i32 %t, 0 |
| %t2 = and i32 %arg, 2 ; 2 instead of 1 |
| %t3 = select i1 %t1, i32 %t2, i32 1 |
| ret i32 %t3 |
| } |
| |
| ; Wrong icmp pred |
| |
| define i32 @n6(i32 %arg) { |
| ; CHECK-LABEL: @n6( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T1_NOT:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[ARG]], 2 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[T2]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T1_NOT]], i32 1, i32 [[T3]] |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 1 |
| %t1 = icmp ne i32 %t, 0 ; ne, not eq |
| %t2 = lshr i32 %arg, 2 |
| %t3 = and i32 %t2, 1 |
| %t4 = select i1 %t1, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |
| |
| define i32 @n7(i32 %arg) { |
| ; CHECK-LABEL: @n7( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 2 |
| ; CHECK-NEXT: [[T1_NOT:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = and i32 [[ARG]], 1 |
| ; CHECK-NEXT: [[T3:%.*]] = select i1 [[T1_NOT]], i32 1, i32 [[T2]] |
| ; CHECK-NEXT: ret i32 [[T3]] |
| ; |
| %t = and i32 %arg, 2 |
| %t1 = icmp ne i32 %t, 0 ; ne, not eq |
| %t2 = and i32 %arg, 1 |
| %t3 = select i1 %t1, i32 %t2, i32 1 |
| ret i32 %t3 |
| } |
| |
| ; icmp second operand is not zero |
| |
| define i32 @n8(i32 %arg) { |
| ; CHECK-LABEL: @n8( |
| ; CHECK-NEXT: [[T:%.*]] = and i32 [[ARG:%.*]], 1 |
| ; CHECK-NEXT: [[T1_NOT:%.*]] = icmp eq i32 [[T]], 0 |
| ; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[ARG]], 2 |
| ; CHECK-NEXT: [[T3:%.*]] = and i32 [[T2]], 1 |
| ; CHECK-NEXT: [[T4:%.*]] = select i1 [[T1_NOT]], i32 1, i32 [[T3]] |
| ; CHECK-NEXT: ret i32 [[T4]] |
| ; |
| %t = and i32 %arg, 1 |
| %t1 = icmp eq i32 %t, 1 |
| %t2 = lshr i32 %arg, 2 |
| %t3 = and i32 %t2, 1 |
| %t4 = select i1 %t1, i32 %t3, i32 1 |
| ret i32 %t4 |
| } |