[llvm] [InstCombine] Fold (X / C) < X and (X >> C) < X into X > 0 (PR #85555)

via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 19 12:39:16 PDT 2024


================
@@ -375,3 +375,115 @@ define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
   %r = icmp eq i32 %d, -2147483648
   ret i1 %r
 }
+
+; Fold (X / C) cmp X into X ~cmp 0 (~cmp is the inverse predicate of cmp), for some C != 1
+; Alternative form of this fold is when division is replaced with logic right shift
+
+define i1 @sdiv_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @sdiv_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %v = udiv i32 %x, 13
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+define i1 @udiv_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @udiv_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %1 = udiv i32 %x, 123
+  %2 = icmp slt i32 %1, %x
+  ret i1 %2
+}
+
+; Same as above but with right shift instead of division (C != 0)
+
+define i1 @lshr_x_by_const_cmp_x(i32 %x) {
+; CHECK-LABEL: @lshr_x_by_const_cmp_x(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %v = lshr i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+define <4 x i1> @lshr_by_const_cmp_sle_value(<4 x i32> %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_sle_value(
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt <4 x i32> [[X:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <4 x i1> [[R]]
+;
+  %v = lshr <4 x i32> %x, <i32 3, i32 3, i32 3, i32 3>
+  %r = icmp sle <4 x i32> %v, %x
+  ret <4 x i1> %r
+}
+
+define i1 @lshr_by_const_cmp_uge_value(i32 %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_uge_value(
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i32 [[X:%.*]], 0
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = lshr i32 %x, 3
+  %r = icmp sle i32 %v, %x
+  ret i1 %r
+}
+
+; Negative test - constant is 1
+
+define i1 @udiv_by_const_cmp_eq_value_neg(i32 %x) {
+; CHECK-LABEL: @udiv_by_const_cmp_eq_value_neg(
+; CHECK-NEXT:    ret i1 true
+;
+  %v = udiv i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+define i1 @sdiv_by_const_cmp_eq_value_neg(i32 %x) {
+; CHECK-LABEL: @sdiv_by_const_cmp_eq_value_neg(
+; CHECK-NEXT:    ret i1 true
+;
+  %v = sdiv i32 %x, 1
+  %r = icmp eq i32 %v, %x
+  ret i1 %r
+}
+
+; Negative test - constant is 0
+
+define i1 @lshr_by_const_cmp_slt_value_neg(i32 %x) {
+; CHECK-LABEL: @lshr_by_const_cmp_slt_value_neg(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = lshr i32 %x, 0
+  %r = icmp slt i32 %v, %x
+  ret i1 %r
----------------
goldsteinn wrote:

to make any of these tests meaningful, they really need to be in the form of a non-splat vector constant where one element is the identity, and another is some interesting constant.

https://github.com/llvm/llvm-project/pull/85555


More information about the llvm-commits mailing list