[llvm] [InstCombine] Infer sub nuw from dominating conditions (PR #100164)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 23 10:01:28 PDT 2024


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/100164

Alive2: https://alive2.llvm.org/ce/z/g3xxnM


>From f7cd7bb7e8c2204d815940591e19ec95be48d775 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 24 Jul 2024 00:53:22 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 llvm/test/Transforms/InstCombine/sub.ll | 144 ++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 49770e8d9e43f..72bcaf6619a26 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -2661,3 +2661,147 @@ define i8 @sub_of_adds_2xc(i8 %x, i8 %y) {
   %r = sub i8 %xc, %yc
   ret i8 %r
 }
+
+define i32 @sub_infer_nuw_from_domcond(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond(
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i32 0
+;
+  %cond = icmp uge i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %sub = sub i32 %x, %y
+  ret i32 %sub
+
+if.else:
+  ret i32 0
+}
+
+define i1 @sub_infer_nuw_from_domcond_fold1(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond_fold1(
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[EXT0:%.*]] = zext i32 [[Y]] to i64
+; CHECK-NEXT:    [[EXT1:%.*]] = zext i32 [[X]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[EXT2:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i64 [[EXT2]], [[EXT0]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[ADD]], [[EXT1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i1 false
+;
+  %cond = icmp uge i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %ext0 = zext i32 %y to i64
+  %ext1 = zext i32 %x to i64
+  %sub = sub i32 %x, %y
+  %ext2 = zext i32 %sub to i64
+  %add = add nuw nsw i64 %ext2, %ext0
+  %cmp = icmp ugt i64 %add, %ext1
+  ret i1 %cmp
+
+if.else:
+  ret i1 false
+}
+
+define i64 @sub_infer_nuw_from_domcond_fold2(i32 range(i32 0, 2147483648) %x, i32 range(i32 0, 2147483648) %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond_fold2(
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i64 0
+;
+  %cond = icmp uge i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %sub = sub i32 %x, %y
+  %ext = zext i32 %sub to i64
+  ret i64 %ext
+
+if.else:
+  ret i64 0
+}
+
+define i1 @sub_infer_nuw_from_domcond_fold3(i16 %xx, i32 range(i32 0, 12) %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond_fold3(
+; CHECK-NEXT:    [[X:%.*]] = zext i16 [[XX:%.*]] to i32
+; CHECK-NEXT:    [[COND:%.*]] = icmp ult i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SUB]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i1 false
+;
+  %x = zext i16 %xx to i32
+  %cond = icmp ult i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %sub = sub nsw i32 %y, %x
+  %cmp = icmp eq i32 %sub, -1
+  ret i1 %cmp
+
+if.else:
+  ret i1 false
+}
+
+; negative tests
+
+define i32 @sub_infer_nuw_from_domcond_wrong_pred(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond_wrong_pred(
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i32 0
+;
+  %cond = icmp sge i32 %x, %y
+  br i1 %cond, label %if.then, label %if.else
+
+if.then:
+  %sub = sub i32 %x, %y
+  ret i32 %sub
+
+if.else:
+  ret i32 0
+}
+
+define i32 @sub_infer_nuw_from_domcond_lhs_is_false(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_infer_nuw_from_domcond_lhs_is_false(
+; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    ret i32 [[SUB]]
+; CHECK:       if.else:
+; CHECK-NEXT:    ret i32 0
+;
+  %cond = icmp uge i32 %x, %y
+  br i1 %cond, label %if.else, label %if.then
+
+if.then:
+  %sub = sub i32 %x, %y
+  ret i32 %sub
+
+if.else:
+  ret i32 0
+}

>From db7728f2acac24a2d919287971b6b91fef93b001 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 24 Jul 2024 00:58:50 +0800
Subject: [PATCH 2/2] [InstCombine] Infer sub nuw from dominating conditions

---
 .../InstCombine/InstCombineAddSub.cpp          |  5 ++++-
 .../Transforms/InstCombine/abs-intrinsic.ll    |  2 +-
 llvm/test/Transforms/InstCombine/sub.ll        | 18 +++++-------------
 3 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 0a55f4762fdf0..6285091a33d46 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2175,7 +2175,10 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
       Changed = true;
       I.setHasNoSignedWrap(true);
     }
-    if (!I.hasNoUnsignedWrap() && willNotOverflowUnsignedSub(Op0, Op1, I)) {
+    if (!I.hasNoUnsignedWrap() &&
+        (willNotOverflowUnsignedSub(Op0, Op1, I) ||
+         isImpliedByDomCondition(ICmpInst::ICMP_UGE, Op0, Op1, &I, DL)
+             .value_or(false))) {
       Changed = true;
       I.setHasNoUnsignedWrap(true);
     }
diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index b6740374c0791..f7c639f1d8e6b 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -800,7 +800,7 @@ define i32 @sub_abs_wrong_pred(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
 ; CHECK:       cond.true:
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 true)
 ; CHECK-NEXT:    br label [[COND_END]]
 ; CHECK:       cond.end:
diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 72bcaf6619a26..cb308ab66b093 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -2667,7 +2667,7 @@ define i32 @sub_infer_nuw_from_domcond(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub nuw i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i32 [[SUB]]
 ; CHECK:       if.else:
 ; CHECK-NEXT:    ret i32 0
@@ -2688,13 +2688,7 @@ define i1 @sub_infer_nuw_from_domcond_fold1(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    [[EXT0:%.*]] = zext i32 [[Y]] to i64
-; CHECK-NEXT:    [[EXT1:%.*]] = zext i32 [[X]] to i64
-; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[EXT2:%.*]] = zext i32 [[SUB]] to i64
-; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i64 [[EXT2]], [[EXT0]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[ADD]], [[EXT1]]
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       if.else:
 ; CHECK-NEXT:    ret i1 false
 ;
@@ -2719,8 +2713,8 @@ define i64 @sub_infer_nuw_from_domcond_fold2(i32 range(i32 0, 2147483648) %x, i3
 ; CHECK-NEXT:    [[COND_NOT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[COND_NOT]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nuw nsw i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SUB]] to i64
 ; CHECK-NEXT:    ret i64 [[EXT]]
 ; CHECK:       if.else:
 ; CHECK-NEXT:    ret i64 0
@@ -2743,9 +2737,7 @@ define i1 @sub_infer_nuw_from_domcond_fold3(i16 %xx, i32 range(i32 0, 12) %y) {
 ; CHECK-NEXT:    [[COND:%.*]] = icmp ult i32 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       if.then:
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SUB]], -1
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       if.else:
 ; CHECK-NEXT:    ret i1 false
 ;



More information about the llvm-commits mailing list