| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt -S -passes=vector-combine -mtriple=aarch64 < %s | FileCheck %s |
| |
| define i1 @nn_zext_eq_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_zext_eq_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @np_sext_eq_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @np_sext_eq_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @np_sext_ne_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @np_sext_ne_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp ne i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @nn_ule_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_ule_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp ule i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @nn_ugt_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_ugt_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp ugt i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @nn_sle_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_sle_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp sle i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @np_sge_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @np_sge_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp sge i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @np_slt_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @np_slt_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp slt i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @nn_sgt_0(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_sgt_0( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <4 x i32> [[ADD]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp sgt i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Tautological predicates in the matching sign class: the fold must not |
| ; rewrite these (the surviving icmp would imply a different predicate). |
| define i1 @nn_sge_0_tautological(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @nn_sge_0_tautological( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[ZA:%.*]] = zext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nuw <4 x i32> [[ZA]], [[ZB]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[ADD]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %za = zext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add nuw <4 x i32> %za, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp sge i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| define i1 @np_sle_0_tautological(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @np_sle_0_tautological( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[ADD]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp sle i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; ashr X, BW-1 produces {0, -1} per lane. ComputeNumSignBits == BitWidth |
| ; recognizes this as non-positive even without a sext-of-i1 leaf. |
| define i1 @np_ashr_sign_bit_eq_0(<4 x i32> %x, <4 x i32> %y) { |
| ; CHECK-LABEL: define i1 @np_ashr_sign_bit_eq_0( |
| ; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) { |
| ; CHECK-NEXT: [[TMP1:%.*]] = or <4 x i32> [[Y]], [[X]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.vector.reduce.umax.v4i32(<4 x i32> [[TMP1]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP2]], -1 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sx = ashr <4 x i32> %x, splat (i32 31) |
| %sy = ashr <4 x i32> %y, splat (i32 31) |
| %add = add nsw <4 x i32> %sx, %sy |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Mixed sign classes: one operand is a sext (non-positive), one is a zext |
| ; (non-negative). Sum can cancel, so the fold must bail. |
| define i1 @mixed_sign_bail(<4 x i1> %a, <4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @mixed_sign_bail( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[ZB:%.*]] = zext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add <4 x i32> [[SA]], [[ZB]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[ADD]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %zb = zext <4 x i1> %b to <4 x i32> |
| %add = add <4 x i32> %sa, %zb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; reduce.add has another use, don't fold. |
| define i32 @multi_use_reduce_bail(<4 x i1> %a, <4 x i1> %b, ptr %p) { |
| ; CHECK-LABEL: define i32 @multi_use_reduce_bail( |
| ; CHECK-SAME: <4 x i1> [[A:%.*]], <4 x i1> [[B:%.*]], ptr [[P:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <4 x i1> [[A]] to <4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <4 x i1> [[B]] to <4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[ADD]]) |
| ; CHECK-NEXT: store i32 [[RED]], ptr [[P]], align 4 |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 0, i32 [[RED]] |
| ; CHECK-NEXT: ret i32 [[SEL]] |
| ; |
| %sa = sext <4 x i1> %a to <4 x i32> |
| %sb = sext <4 x i1> %b to <4 x i32> |
| %add = add nsw <4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %add) |
| store i32 %red, ptr %p |
| %cmp = icmp eq i32 %red, 0 |
| %sel = select i1 %cmp, i32 0, i32 %red |
| ret i32 %sel |
| } |
| |
| ; Element count too large relative to sign bits of leaves, summation could |
| ; overflow. |
| define i1 @overflow_bail(<16 x i32> %x) { |
| ; CHECK-LABEL: define i1 @overflow_bail( |
| ; CHECK-SAME: <16 x i32> [[X:%.*]]) { |
| ; CHECK-NEXT: [[ADD:%.*]] = add <16 x i32> [[X]], [[X]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v16i32(<16 x i32> [[ADD]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %add = add <16 x i32> %x, %x |
| %red = call i32 @llvm.vector.reduce.add.v16i32(<16 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Scalable vectors are not handled. |
| define i1 @scalable_bail(<vscale x 4 x i1> %a, <vscale x 4 x i1> %b) { |
| ; CHECK-LABEL: define i1 @scalable_bail( |
| ; CHECK-SAME: <vscale x 4 x i1> [[A:%.*]], <vscale x 4 x i1> [[B:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <vscale x 4 x i1> [[A]] to <vscale x 4 x i32> |
| ; CHECK-NEXT: [[SB:%.*]] = sext <vscale x 4 x i1> [[B]] to <vscale x 4 x i32> |
| ; CHECK-NEXT: [[ADD:%.*]] = add nsw <vscale x 4 x i32> [[SA]], [[SB]] |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> [[ADD]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <vscale x 4 x i1> %a to <vscale x 4 x i32> |
| %sb = sext <vscale x 4 x i1> %b to <vscale x 4 x i32> |
| %add = add nsw <vscale x 4 x i32> %sa, %sb |
| %red = call i32 @llvm.vector.reduce.add.nxv4i32(<vscale x 4 x i32> %add) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Single-lane vectors: reduce.add is trivial, don't bother. |
| define i1 @single_lane_bail(<1 x i1> %a) { |
| ; CHECK-LABEL: define i1 @single_lane_bail( |
| ; CHECK-SAME: <1 x i1> [[A:%.*]]) { |
| ; CHECK-NEXT: [[SA:%.*]] = sext <1 x i1> [[A]] to <1 x i32> |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v1i32(<1 x i32> [[SA]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %sa = sext <1 x i1> %a to <1 x i32> |
| %red = call i32 @llvm.vector.reduce.add.v1i32(<1 x i32> %sa) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Boundary: lanes with 3 sign bits are non-negative with magnitude < 2^29. |
| ; With 4 lanes: Log2_32(4)=2 < 3 sign bits -> fold applies. |
| define i1 @overflow_boundary_ok(<4 x i32> %x) { |
| ; CHECK-LABEL: define i1 @overflow_boundary_ok( |
| ; CHECK-SAME: <4 x i32> [[X:%.*]]) { |
| ; CHECK-NEXT: [[MASKED:%.*]] = and <4 x i32> [[X]], splat (i32 536870911) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[MASKED]], zeroinitializer |
| ; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.vector.reduce.and.v4i1(<4 x i1> [[TMP1]]) |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %masked = and <4 x i32> %x, splat (i32 536870911) |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %masked) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; With 8 lanes: Log2_32(8)=3 >= 3 sign bits -> must bail. |
| define i1 @overflow_boundary_bail(<8 x i32> %x) { |
| ; CHECK-LABEL: define i1 @overflow_boundary_bail( |
| ; CHECK-SAME: <8 x i32> [[X:%.*]]) { |
| ; CHECK-NEXT: [[MASKED:%.*]] = and <8 x i32> [[X]], splat (i32 536870911) |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> [[MASKED]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %masked = and <8 x i32> %x, splat (i32 536870911) |
| %red = call i32 @llvm.vector.reduce.add.v8i32(<8 x i32> %masked) |
| %cmp = icmp eq i32 %red, 0 |
| ret i1 %cmp |
| } |
| |
| ; Signed-inequality boundary: 3 sign bits on a non-negative tree with 4 lanes |
| ; gives Log2_32(4)=2 >= 3-1 sign bits -> the tighter signed margin bails, |
| ; even though the eq/ne margin (2 < 3) would allow the fold. |
| define i1 @signed_boundary_bail(<4 x i32> %x) { |
| ; CHECK-LABEL: define i1 @signed_boundary_bail( |
| ; CHECK-SAME: <4 x i32> [[X:%.*]]) { |
| ; CHECK-NEXT: [[MASKED:%.*]] = and <4 x i32> [[X]], splat (i32 536870911) |
| ; CHECK-NEXT: [[RED:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[MASKED]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[RED]], 0 |
| ; CHECK-NEXT: ret i1 [[CMP]] |
| ; |
| %masked = and <4 x i32> %x, splat (i32 536870911) |
| %red = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %masked) |
| %cmp = icmp sgt i32 %red, 0 |
| ret i1 %cmp |
| } |