[llvm] [InstSimplify] Simplify `uadd.sat(X, Y) u>= X + Y` and `usub.sat(X, Y) u<= X, Y` (PR #104698)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 18 04:09:08 PDT 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/104698
These patterns are found in harfbuzz/typst.
Alive2: https://alive2.llvm.org/ce/z/cxyjYV
>From b659f185aa1b0a986d5b6bdfafeac551ea5d434b Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 18 Aug 2024 18:53:38 +0800
Subject: [PATCH 1/2] [InstSimplify] Add pre-commit tests. NFC.
---
.../InstSimplify/saturating-add-sub.ll | 136 ++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
index 40b22c619f7686..947585b76708e6 100644
--- a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
@@ -932,3 +932,139 @@ define i1 @usub_uge_fail(i8 %x, i8 %y) {
%cmp = icmp uge i8 %sat, %x
ret i1 %cmp
}
+
+define i1 @icmp_ult_uaddsat_add(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ult_uaddsat_add(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
+ %add = add i32 %x, %y
+ %cmp = icmp ult i32 %uaddsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_uge_uaddsat_add(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_uge_uaddsat_add(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[UADDSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
+ %add = add i32 %x, %y
+ %cmp = icmp uge i32 %uaddsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_ugt_uaddsat_add_commuted1(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ugt_uaddsat_add_commuted1(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[ADD]], [[UADDSAT]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
+ %add = add i32 %x, %y
+ %cmp = icmp ugt i32 %add, %uaddsat
+ ret i1 %cmp
+}
+
+define i1 @icmp_ult_uaddsat_add_commuted2(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ult_uaddsat_add_commuted2(
+; CHECK-NEXT: [[XX:%.*]] = mul i32 [[X:%.*]], 998244353
+; CHECK-NEXT: [[YY:%.*]] = mul i32 [[Y:%.*]], 998244353
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[XX]], i32 [[YY]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[YY]], [[XX]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %xx = mul i32 %x, 998244353
+ %yy = mul i32 %y, 998244353
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %xx, i32 %yy)
+ %add = add i32 %yy, %xx ; thwart complexity-based canonicalization
+ %cmp = icmp ult i32 %uaddsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_ule_usubsat_sub(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ule_usubsat_sub(
+; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[USUBSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
+ %add = sub i32 %x, %y
+ %cmp = icmp ule i32 %usubsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_ugt_usubsat_sub(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ugt_usubsat_sub(
+; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[USUBSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
+ %add = sub i32 %x, %y
+ %cmp = icmp ugt i32 %usubsat, %add
+ ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @icmp_ult_uaddsat_add_mismatch(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @icmp_ult_uaddsat_add_mismatch(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Z:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %z)
+ %add = add i32 %x, %y
+ %cmp = icmp ult i32 %uaddsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_ult_uaddsat_add_wrong_pred(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ult_uaddsat_add_wrong_pred(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[UADDSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
+ %add = add i32 %x, %y
+ %cmp = icmp ule i32 %uaddsat, %add
+ ret i1 %cmp
+}
+
+define i1 @icmp_ult_uaddsat_add_wrong_op(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ult_uaddsat_add_wrong_op(
+; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[SUB]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
+ %sub = sub i32 %x, %y
+ %cmp = icmp ult i32 %uaddsat, %sub
+ ret i1 %cmp
+}
+
+define i1 @icmp_ule_usubsat_sub_commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: @icmp_ule_usubsat_sub_commuted(
+; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[USUBSAT]], [[ADD]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
+ %add = sub i32 %y, %x
+ %cmp = icmp ule i32 %usubsat, %add
+ ret i1 %cmp
+}
>From 8151c01b6d378edab481dff1726e0a0406d4f14b Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 18 Aug 2024 18:54:53 +0800
Subject: [PATCH 2/2] [InstSimplify] Simplify `uadd.sat(X, Y) uge X + Y` and
`usub.sat(X, Y) ule X - Y`
---
llvm/lib/Analysis/InstructionSimplify.cpp | 16 ++++++++++
.../InstSimplify/saturating-add-sub.ll | 32 ++++---------------
2 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index eff8a7cfc8ce6c..32a9f1ab34fb3f 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3718,6 +3718,14 @@ static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred,
if (Pred == ICmpInst::ICMP_ULT)
return ConstantInt::getFalse(getCompareTy(II));
}
+ // uadd.sat(X, Y) uge X + Y
+ if (match(RHS, m_c_Add(m_Specific(II->getArgOperand(0)),
+ m_Specific(II->getArgOperand(1))))) {
+ if (Pred == ICmpInst::ICMP_UGE)
+ return ConstantInt::getTrue(getCompareTy(II));
+ if (Pred == ICmpInst::ICMP_ULT)
+ return ConstantInt::getFalse(getCompareTy(II));
+ }
return nullptr;
case Intrinsic::usub_sat:
// usub.sat(X, Y) ule X
@@ -3727,6 +3735,14 @@ static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred,
if (Pred == ICmpInst::ICMP_UGT)
return ConstantInt::getFalse(getCompareTy(II));
}
+ // usub.sat(X, Y) ule X - Y
+ if (match(RHS, m_Sub(m_Specific(II->getArgOperand(0)),
+ m_Specific(II->getArgOperand(1))))) {
+ if (Pred == ICmpInst::ICMP_ULE)
+ return ConstantInt::getTrue(getCompareTy(II));
+ if (Pred == ICmpInst::ICMP_UGT)
+ return ConstantInt::getFalse(getCompareTy(II));
+ }
return nullptr;
default:
return nullptr;
diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
index 947585b76708e6..ea139f2411cc3d 100644
--- a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
+++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll
@@ -935,10 +935,7 @@ define i1 @usub_uge_fail(i8 %x, i8 %y) {
define i1 @icmp_ult_uaddsat_add(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_ult_uaddsat_add(
-; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
%add = add i32 %x, %y
@@ -948,10 +945,7 @@ define i1 @icmp_ult_uaddsat_add(i32 %x, i32 %y) {
define i1 @icmp_uge_uaddsat_add(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_uge_uaddsat_add(
-; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[UADDSAT]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
%add = add i32 %x, %y
@@ -961,10 +955,7 @@ define i1 @icmp_uge_uaddsat_add(i32 %x, i32 %y) {
define i1 @icmp_ugt_uaddsat_add_commuted1(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_ugt_uaddsat_add_commuted1(
-; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[ADD]], [[UADDSAT]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
%add = add i32 %x, %y
@@ -974,12 +965,7 @@ define i1 @icmp_ugt_uaddsat_add_commuted1(i32 %x, i32 %y) {
define i1 @icmp_ult_uaddsat_add_commuted2(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_ult_uaddsat_add_commuted2(
-; CHECK-NEXT: [[XX:%.*]] = mul i32 [[X:%.*]], 998244353
-; CHECK-NEXT: [[YY:%.*]] = mul i32 [[Y:%.*]], 998244353
-; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[XX]], i32 [[YY]])
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[YY]], [[XX]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%xx = mul i32 %x, 998244353
%yy = mul i32 %y, 998244353
@@ -991,10 +977,7 @@ define i1 @icmp_ult_uaddsat_add_commuted2(i32 %x, i32 %y) {
define i1 @icmp_ule_usubsat_sub(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_ule_usubsat_sub(
-; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[X]], [[Y]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[USUBSAT]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
%add = sub i32 %x, %y
@@ -1004,10 +987,7 @@ define i1 @icmp_ule_usubsat_sub(i32 %x, i32 %y) {
define i1 @icmp_ugt_usubsat_sub(i32 %x, i32 %y) {
; CHECK-LABEL: @icmp_ugt_usubsat_sub(
-; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[X]], [[Y]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[USUBSAT]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
%add = sub i32 %x, %y
More information about the llvm-commits
mailing list