[llvm] [ValueTracking] isNonZero sub of ptr2int's with recursive GEP (PR #68680)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 24 03:06:48 PDT 2023


https://github.com/bipmis updated https://github.com/llvm/llvm-project/pull/68680

>From a1369af8df901b4cefd2e13f5e5cd8cec4f04042 Mon Sep 17 00:00:00 2001
From: bipmis <biplob.mishra at arm.com>
Date: Mon, 9 Oct 2023 15:07:19 +0100
Subject: [PATCH 1/3] Precommit tests for ValueTracking isKnownNonZero with
 recursive GEP

---
 .../Analysis/ValueTracking/phi-known-bits.ll  | 337 ++++++++++++++++++
 1 file changed, 337 insertions(+)

diff --git a/llvm/test/Analysis/ValueTracking/phi-known-bits.ll b/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
index 5227661c837347e..228b80129512443 100644
--- a/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
+++ b/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
@@ -424,3 +424,340 @@ T:
 F:
   br label %T
 }
+
+define i1 @phi_sub_recursiveGEP_knownNonZero1(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_knownNonZero1_PhiOperandsCommuted(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero1_PhiOperandsCommuted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[VAL1]], [[ENTRY:%.*]] ], [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %val1, %entry ], [ %test.0.i, %while.cond.i ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_knownNonZero1_SubOperandsCommuted(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero1_SubOperandsCommuted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.rhs.cast.i, %sub.ptr.lhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_knownNonZero2(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 -1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 -1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_knownNonZero3(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_ADD:%.*]], [[WHILE_COND_I]] ], [ 7, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[A_PN_I_ADD]] = add nuw nsw i64 [[A_PN_I_IDX]], 1
+; CHECK-NEXT:    [[TEST_0_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1]], i64 [[A_PN_I_ADD]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I_PTR]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[A_PN_I_ADD]], 5
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %test.val1 = getelementptr inbounds i8, ptr %val1, i64 7
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %test.val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %1 = getelementptr inbounds i8, ptr %val1, i64 5
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_notknownNonZero1(ptr noundef %val1, i64 %val2) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_notknownNonZero1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[VAL1]], i64 [[VAL2:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq ptr [[TEST_0_I]], [[TMP1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP2]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %1 = getelementptr inbounds i8, ptr %val1, i64 %val2
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_notknownNonZero2(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_notknownNonZero2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TEST_VAL1:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 -1
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[TEST_VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %test.val1 = getelementptr inbounds i8, ptr %val1, i64 -1
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %test.val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}
+
+define i1 @phi_sub_recursiveGEP_notknownNonZero3(ptr noundef %val1) {
+; CHECK-LABEL: @phi_sub_recursiveGEP_notknownNonZero3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TEST_VAL1:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 5
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1]], null
+; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
+; CHECK:       while.cond.i:
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[TEST_VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 -1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
+; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
+; CHECK:       while.end.i:
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
+; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
+; CHECK:       _Z9stringlenPKs.exit:
+; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+;
+entry:
+  %test.val1 = getelementptr inbounds i8, ptr %val1, i64 5
+  %cmp.i = icmp eq ptr %val1, null
+  br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
+
+while.cond.i:
+  %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %test.val1, %entry ]
+  %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 -1
+  %0 = load i8, ptr %test.0.i, align 2
+  %cmp3.not.i = icmp eq i8 %0, 0
+  br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
+
+while.end.i:
+  %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64
+  %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64
+  %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i
+  br label %_Z9stringlenPKs.exit
+
+_Z9stringlenPKs.exit:
+  %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %entry ]
+  %bool = icmp eq i64 %retval.0.i, 0
+  ret i1 %bool
+}

>From c053b902e375a0efd31d902261001f1e74dbdecb Mon Sep 17 00:00:00 2001
From: bipmis <biplob.mishra at arm.com>
Date: Mon, 9 Oct 2023 15:19:49 +0100
Subject: [PATCH 2/3] isNonZeroSub for ptr2int with one of them being a
 Recursive GEP

---
 llvm/lib/Analysis/ValueTracking.cpp           | 67 +++++++++++++++++++
 .../Analysis/ValueTracking/phi-known-bits.ll  | 30 +++------
 2 files changed, 77 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index f510f6a42f08c12..c367c8edc750869 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2410,9 +2410,76 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
       .isNonZero();
 }
 
+static bool isNonZeroSubWithRecursiveGEP(const SimplifyQuery &Q, Value *X,
+                                         Value *Y) {
+  // Handle sub(PtrtoInt(LHS), PtrtoInt(RHS))
+  // Where LHS is a recursive GEP for an incoming value of PHI indicating a
+  // loop. RHS can be a ptr/GEP.
+  // If the PHI has 2 incoming values, one of it being the recursive GEP
+  // and other a ptr at same base and at an same/higher offset than RHS we are
+  // only incrementing the pointer further in loop if offset of recursive GEP is
+  // greater than 0.
+  Value *LHS, *RHS;
+  // sub(PtrtoInt(LHS), PtrtoInt(RHS))
+  if (match(X, m_PtrToInt(m_Value(LHS))) &&
+      match(Y, m_PtrToInt(m_Value(RHS)))) {
+    GEPOperator *LHSGEP = dyn_cast<GEPOperator>(LHS);
+    // Make sure LHS GEP pointer operand is a PHI. If sub(A,B) is non zero, so
+    // is sub(B,A)
+    if (!LHSGEP || !isa<PHINode>(LHSGEP->getPointerOperand())) {
+      LHSGEP = dyn_cast<GEPOperator>(RHS);
+      std::swap(LHS, RHS);
+    }
+    if (LHSGEP && isa<PHINode>(LHSGEP->getPointerOperand())) {
+      // Handle 2 incoming values with one being a recursive GEP.
+      auto *PN = dyn_cast<PHINode>(LHSGEP->getPointerOperand());
+      if (PN->getNumIncomingValues() == 2) {
+        // Recursive GEP in second incoming value. Always keep Recursive GEP as
+        // FirstInst
+        Value *FirstInst = nullptr, *SecondInst = nullptr;
+        for (unsigned i = 0; i != 2; ++i) {
+          // Check if LHS is a Recursive GEP in one of the incoming values.
+          if (PN->getIncomingValue(i) == LHS && LHSGEP->getNumIndices() == 1 &&
+              isa<Constant>(LHSGEP->idx_begin())) {
+            FirstInst = PN->getIncomingValue(i);
+            SecondInst = PN->getIncomingValue(!i);
+            continue;
+          }
+        }
+
+        if (FirstInst && SecondInst) {
+          // Other incoming node base should match the RHS base.
+          // SecondInstOffset >= RHSOffset && FirstInstOffset > 0?
+          // SecondInstOffset <= RHSOffset && FirstInstOffset < 0?
+          // Is non-zero if above are true.
+          APInt FirstInstOffset(
+              Q.DL.getIndexTypeSizeInBits(FirstInst->getType()), 0);
+          FirstInst = FirstInst->stripAndAccumulateConstantOffsets(
+              Q.DL, FirstInstOffset, /* AllowNonInbounds */ true);
+          APInt SecondInstOffset(
+              Q.DL.getIndexTypeSizeInBits(SecondInst->getType()), 0);
+          SecondInst = SecondInst->stripAndAccumulateConstantOffsets(
+              Q.DL, SecondInstOffset, /* AllowNonInbounds */ true);
+          APInt RHSOffset(Q.DL.getIndexTypeSizeInBits(RHS->getType()), 0);
+          RHS = RHS->stripAndAccumulateConstantOffsets(
+              Q.DL, RHSOffset, /* AllowNonInbounds */ true);
+          if (SecondInst == RHS &&
+              ((SecondInstOffset.sge(RHSOffset) && FirstInstOffset.sgt(0)) ||
+               (SecondInstOffset.sle(RHSOffset) && FirstInstOffset.slt(0))))
+            return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
                          const SimplifyQuery &Q, unsigned BitWidth, Value *X,
                          Value *Y) {
+  if(isNonZeroSubWithRecursiveGEP(Q, X, Y))
+    return true;
+
   if (auto *C = dyn_cast<Constant>(X))
     if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Depth, Q))
       return true;
diff --git a/llvm/test/Analysis/ValueTracking/phi-known-bits.ll b/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
index 228b80129512443..6b01c9d3da09f11 100644
--- a/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
+++ b/llvm/test/Analysis/ValueTracking/phi-known-bits.ll
@@ -437,11 +437,9 @@ define i1 @phi_sub_recursiveGEP_knownNonZero1(ptr noundef %val1) {
 ; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
 ; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
 ; CHECK:       while.end.i:
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
 ; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
 ; CHECK:       _Z9stringlenPKs.exit:
-; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+; CHECK-NEXT:    ret i1 [[CMP_I]]
 ;
 entry:
   %cmp.i = icmp eq ptr %val1, null
@@ -478,11 +476,9 @@ define i1 @phi_sub_recursiveGEP_knownNonZero1_PhiOperandsCommuted(ptr noundef %v
 ; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
 ; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
 ; CHECK:       while.end.i:
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
 ; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
 ; CHECK:       _Z9stringlenPKs.exit:
-; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+; CHECK-NEXT:    ret i1 [[CMP_I]]
 ;
 entry:
   %cmp.i = icmp eq ptr %val1, null
@@ -519,11 +515,9 @@ define i1 @phi_sub_recursiveGEP_knownNonZero1_SubOperandsCommuted(ptr noundef %v
 ; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
 ; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
 ; CHECK:       while.end.i:
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
 ; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
 ; CHECK:       _Z9stringlenPKs.exit:
-; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+; CHECK-NEXT:    ret i1 [[CMP_I]]
 ;
 entry:
   %cmp.i = icmp eq ptr %val1, null
@@ -560,11 +554,9 @@ define i1 @phi_sub_recursiveGEP_knownNonZero2(ptr noundef %val1) {
 ; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
 ; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
 ; CHECK:       while.end.i:
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[TEST_0_I]], [[VAL1]]
 ; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
 ; CHECK:       _Z9stringlenPKs.exit:
-; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+; CHECK-NEXT:    ret i1 [[CMP_I]]
 ;
 entry:
   %cmp.i = icmp eq ptr %val1, null
@@ -592,21 +584,19 @@ _Z9stringlenPKs.exit:
 define i1 @phi_sub_recursiveGEP_knownNonZero3(ptr noundef %val1) {
 ; CHECK-LABEL: @phi_sub_recursiveGEP_knownNonZero3(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
+; CHECK-NEXT:    [[TEST_VAL1:%.*]] = getelementptr inbounds i8, ptr [[VAL1:%.*]], i64 7
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq ptr [[VAL1]], null
 ; CHECK-NEXT:    br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
 ; CHECK:       while.cond.i:
-; CHECK-NEXT:    [[A_PN_I_IDX:%.*]] = phi i64 [ [[A_PN_I_ADD:%.*]], [[WHILE_COND_I]] ], [ 7, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[A_PN_I_ADD]] = add nuw nsw i64 [[A_PN_I_IDX]], 1
-; CHECK-NEXT:    [[TEST_0_I_PTR:%.*]] = getelementptr inbounds i8, ptr [[VAL1]], i64 [[A_PN_I_ADD]]
-; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I_PTR]], align 2
+; CHECK-NEXT:    [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[TEST_VAL1]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
 ; CHECK-NEXT:    [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
 ; CHECK-NEXT:    br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
 ; CHECK:       while.end.i:
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[A_PN_I_ADD]], 5
 ; CHECK-NEXT:    br label [[_Z9STRINGLENPKS_EXIT]]
 ; CHECK:       _Z9stringlenPKs.exit:
-; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi i1 [ [[TMP1]], [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    ret i1 [[RETVAL_0_I]]
+; CHECK-NEXT:    ret i1 [[CMP_I]]
 ;
 entry:
   %test.val1 = getelementptr inbounds i8, ptr %val1, i64 7

>From 66864d8066b50215f3d8731ef4b1d7919ed91f69 Mon Sep 17 00:00:00 2001
From: bipmis <biplob.mishra at arm.com>
Date: Tue, 17 Oct 2023 17:28:40 +0100
Subject: [PATCH 3/3] Correct code formatting

---
 llvm/lib/Analysis/ValueTracking.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c367c8edc750869..b017a191c88f034 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2477,7 +2477,7 @@ static bool isNonZeroSubWithRecursiveGEP(const SimplifyQuery &Q, Value *X,
 static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
                          const SimplifyQuery &Q, unsigned BitWidth, Value *X,
                          Value *Y) {
-  if(isNonZeroSubWithRecursiveGEP(Q, X, Y))
+  if (isNonZeroSubWithRecursiveGEP(Q, X, Y))
     return true;
 
   if (auto *C = dyn_cast<Constant>(X))



More information about the llvm-commits mailing list