[llvm] [InstCombine] Implement folds of icmp of UCMP/SCMP call and a constant (PR #96118)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 21 12:13:06 PDT 2024


https://github.com/Poseydon42 updated https://github.com/llvm/llvm-project/pull/96118

>From af26a2001d5a1661690c2b79a7f257ff6a190570 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Wed, 19 Jun 2024 22:57:46 +0100
Subject: [PATCH 1/6] [InstCombine] Added tests for various folds of icmp
 (UCMP/SCMP, C)

---
 llvm/test/Transforms/InstCombine/scmp.ll | 170 +++++++++++++++++++++++
 llvm/test/Transforms/InstCombine/ucmp.ll | 170 +++++++++++++++++++++++
 2 files changed, 340 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/scmp.ll
 create mode 100644 llvm/test/Transforms/InstCombine/ucmp.ll

diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
new file mode 100644
index 0000000000000..b694eac0f5e06
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @scmp_eq_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_eq_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_ne_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_ne_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_eq_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_eq_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @scmp_ne_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_ne_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @scmp_eq_negative_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_eq_negative_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @scmp_ne_negative_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_ne_negative_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @scmp_sgt_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sgt_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sgt i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_sgt_neg_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sgt_neg_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sgt i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @scmp_sge_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sge_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sge i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_sge_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sge_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sge i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @scmp_slt_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_slt_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp slt i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_slt_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_slt_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp slt i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @scmp_sle_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sle_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sle i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @scmp_sle_neg_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @scmp_sle_neg_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %2 = icmp sle i8 %1, -1
+  ret i1 %2
+}
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
new file mode 100644
index 0000000000000..88b23fd0972fe
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @ucmp_eq_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_eq_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_ne_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_ne_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_eq_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_eq_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @ucmp_ne_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_ne_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @ucmp_eq_negative_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_eq_negative_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp eq i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @ucmp_ne_negative_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_ne_negative_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp ne i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @ucmp_sgt_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sgt_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sgt i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_sgt_neg_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sgt_neg_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sgt i8 %1, -1
+  ret i1 %2
+}
+
+define i1 @ucmp_sge_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sge_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sge i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_sge_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sge_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sge i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @ucmp_slt_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_slt_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp slt i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_slt_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_slt_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp slt i8 %1, 1
+  ret i1 %2
+}
+
+define i1 @ucmp_sle_0(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sle_0(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sle i8 %1, 0
+  ret i1 %2
+}
+
+define i1 @ucmp_sle_neg_1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @ucmp_sle_neg_1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    ret i1 [[TMP2]]
+;
+  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %2 = icmp sle i8 %1, -1
+  ret i1 %2
+}

>From 9d00eb33f9b8346ac27b4b9b0b742860c03a897c Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Wed, 19 Jun 2024 22:59:36 +0100
Subject: [PATCH 2/6] [InstCombine] Implement folds of icmp with UCMP/SCMP and
 a constant

---
 .../InstCombine/InstCombineCompares.cpp       | 91 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/scmp.ll      | 42 +++------
 llvm/test/Transforms/InstCombine/ucmp.ll      | 42 +++------
 3 files changed, 119 insertions(+), 56 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 34b0f8b860497..cb0351259a1f9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3926,6 +3926,92 @@ foldICmpUSubSatOrUAddSatWithConstant(ICmpInst::Predicate Pred,
       ConstantInt::get(Op1->getType(), EquivInt));
 }
 
+static Instruction *
+foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
+                                   const APInt &C,
+                                   InstCombiner::BuilderTy &Builder) {
+  Intrinsic::ID IID = I->getIntrinsicID();
+  Value *LHS = I->getOperand(0);
+  Value *RHS = I->getOperand(1);
+
+  switch (Pred) {
+  case ICmpInst::ICMP_EQ:
+    if (C.isZero())
+      return new ICmpInst(Pred, LHS, RHS);
+    if (C.isOne())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
+                                                 : ICmpInst::ICMP_UGT,
+                          LHS, RHS);
+    if (C.isAllOnes())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
+                                                 : ICmpInst::ICMP_ULT,
+                          LHS, RHS);
+    break;
+
+  case ICmpInst::ICMP_NE:
+    if (C.isZero())
+      return new ICmpInst(Pred, LHS, RHS);
+    if (C.isOne())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
+                                                 : ICmpInst::ICMP_ULE,
+                          LHS, RHS);
+    if (C.isAllOnes())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
+                                                 : ICmpInst::ICMP_UGE,
+                          LHS, RHS);
+    break;
+
+  case ICmpInst::ICMP_SGT:
+    if (C.isAllOnes())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
+                                                 : ICmpInst::ICMP_UGE,
+                          LHS, RHS);
+    if (C.isZero())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
+                                                 : ICmpInst::ICMP_UGT,
+                          LHS, RHS);
+    break;
+
+  case ICmpInst::ICMP_SGE:
+    if (C.isZero())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
+                                                 : ICmpInst::ICMP_UGE,
+                          LHS, RHS);
+    if (C.isOne())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
+                                                 : ICmpInst::ICMP_UGT,
+                          LHS, RHS);
+    break;
+
+  case ICmpInst::ICMP_SLT:
+    if (C.isZero())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
+                                                 : ICmpInst::ICMP_ULT,
+                          LHS, RHS);
+    if (C.isOne())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
+                                                 : ICmpInst::ICMP_ULE,
+                          LHS, RHS);
+    break;
+
+  case llvm::ICmpInst::ICMP_SLE:
+    if (C.isZero())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
+                                                 : ICmpInst::ICMP_ULE,
+                          LHS, RHS);
+    if (C.isAllOnes())
+      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
+                                                 : ICmpInst::ICMP_ULT,
+                          LHS, RHS);
+    break;
+
+  default:
+    return nullptr;
+  }
+
+  return nullptr;
+}
+
 /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C.
 Instruction *InstCombinerImpl::foldICmpIntrinsicWithConstant(ICmpInst &Cmp,
                                                              IntrinsicInst *II,
@@ -3947,6 +4033,11 @@ Instruction *InstCombinerImpl::foldICmpIntrinsicWithConstant(ICmpInst &Cmp,
     if (Instruction *R = foldCtpopPow2Test(Cmp, II, C, Builder, Q))
       return R;
   } break;
+  case Intrinsic::scmp:
+  case Intrinsic::ucmp:
+    if (auto *Folded = foldICmpOfCmpIntrinsicWithConstant(Pred, II, C, Builder))
+      return Folded;
+    break;
   }
 
   if (Cmp.isEquality())
diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index b694eac0f5e06..4f903a79afd5d 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -4,8 +4,7 @@
 define i1 @scmp_eq_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_eq_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -16,8 +15,7 @@ define i1 @scmp_eq_0(i32 %x, i32 %y) {
 define i1 @scmp_ne_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_ne_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -28,8 +26,7 @@ define i1 @scmp_ne_0(i32 %x, i32 %y) {
 define i1 @scmp_eq_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_eq_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -40,8 +37,7 @@ define i1 @scmp_eq_1(i32 %x, i32 %y) {
 define i1 @scmp_ne_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_ne_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sle i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -52,8 +48,7 @@ define i1 @scmp_ne_1(i32 %x, i32 %y) {
 define i1 @scmp_eq_negative_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_eq_negative_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -64,8 +59,7 @@ define i1 @scmp_eq_negative_1(i32 %x, i32 %y) {
 define i1 @scmp_ne_negative_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_ne_negative_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -76,8 +70,7 @@ define i1 @scmp_ne_negative_1(i32 %x, i32 %y) {
 define i1 @scmp_sgt_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sgt_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -88,8 +81,7 @@ define i1 @scmp_sgt_0(i32 %x, i32 %y) {
 define i1 @scmp_sgt_neg_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sgt_neg_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -100,8 +92,7 @@ define i1 @scmp_sgt_neg_1(i32 %x, i32 %y) {
 define i1 @scmp_sge_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sge_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -112,8 +103,7 @@ define i1 @scmp_sge_0(i32 %x, i32 %y) {
 define i1 @scmp_sge_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sge_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -124,8 +114,7 @@ define i1 @scmp_sge_1(i32 %x, i32 %y) {
 define i1 @scmp_slt_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_slt_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -136,8 +125,7 @@ define i1 @scmp_slt_0(i32 %x, i32 %y) {
 define i1 @scmp_slt_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_slt_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sle i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -148,8 +136,7 @@ define i1 @scmp_slt_1(i32 %x, i32 %y) {
 define i1 @scmp_sle_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sle_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sle i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -160,8 +147,7 @@ define i1 @scmp_sle_0(i32 %x, i32 %y) {
 define i1 @scmp_sle_neg_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @scmp_sle_neg_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 88b23fd0972fe..9ab67560c9117 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -4,8 +4,7 @@
 define i1 @ucmp_eq_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_eq_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -16,8 +15,7 @@ define i1 @ucmp_eq_0(i32 %x, i32 %y) {
 define i1 @ucmp_ne_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_ne_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -28,8 +26,7 @@ define i1 @ucmp_ne_0(i32 %x, i32 %y) {
 define i1 @ucmp_eq_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_eq_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -40,8 +37,7 @@ define i1 @ucmp_eq_1(i32 %x, i32 %y) {
 define i1 @ucmp_ne_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_ne_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -52,8 +48,7 @@ define i1 @ucmp_ne_1(i32 %x, i32 %y) {
 define i1 @ucmp_eq_negative_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_eq_negative_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -64,8 +59,7 @@ define i1 @ucmp_eq_negative_1(i32 %x, i32 %y) {
 define i1 @ucmp_ne_negative_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_ne_negative_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -76,8 +70,7 @@ define i1 @ucmp_ne_negative_1(i32 %x, i32 %y) {
 define i1 @ucmp_sgt_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sgt_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -88,8 +81,7 @@ define i1 @ucmp_sgt_0(i32 %x, i32 %y) {
 define i1 @ucmp_sgt_neg_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sgt_neg_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -100,8 +92,7 @@ define i1 @ucmp_sgt_neg_1(i32 %x, i32 %y) {
 define i1 @ucmp_sge_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sge_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -112,8 +103,7 @@ define i1 @ucmp_sge_0(i32 %x, i32 %y) {
 define i1 @ucmp_sge_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sge_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sgt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ugt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -124,8 +114,7 @@ define i1 @ucmp_sge_1(i32 %x, i32 %y) {
 define i1 @ucmp_slt_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_slt_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -136,8 +125,7 @@ define i1 @ucmp_slt_0(i32 %x, i32 %y) {
 define i1 @ucmp_slt_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_slt_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -148,8 +136,7 @@ define i1 @ucmp_slt_1(i32 %x, i32 %y) {
 define i1 @ucmp_sle_0(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sle_0(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ule i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
@@ -160,8 +147,7 @@ define i1 @ucmp_sle_0(i32 %x, i32 %y) {
 define i1 @ucmp_sle_neg_1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i1 @ucmp_sle_neg_1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp slt i8 [[TMP1]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[TMP2]]
 ;
   %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)

>From b2ffd9c83b1ad768b8ae3e5efeffcc30e732256e Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Thu, 20 Jun 2024 20:37:31 +0100
Subject: [PATCH 3/6] Remove redundant cases and fix formatting

---
 .../InstCombine/InstCombineCompares.cpp       | 78 ++++++-------------
 1 file changed, 23 insertions(+), 55 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index cb0351259a1f9..65fccc1aedcf7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3930,79 +3930,47 @@ static Instruction *
 foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
                                    const APInt &C,
                                    InstCombiner::BuilderTy &Builder) {
-  Intrinsic::ID IID = I->getIntrinsicID();
+  bool IsScmp = I->getIntrinsicID() == Intrinsic::scmp;
   Value *LHS = I->getOperand(0);
   Value *RHS = I->getOperand(1);
 
   switch (Pred) {
   case ICmpInst::ICMP_EQ:
-    if (C.isZero())
-      return new ICmpInst(Pred, LHS, RHS);
-    if (C.isOne())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
-                                                 : ICmpInst::ICMP_UGT,
-                          LHS, RHS);
-    if (C.isAllOnes())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
-                                                 : ICmpInst::ICMP_ULT,
-                          LHS, RHS);
-    break;
-
   case ICmpInst::ICMP_NE:
     if (C.isZero())
       return new ICmpInst(Pred, LHS, RHS);
-    if (C.isOne())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
-                                                 : ICmpInst::ICMP_ULE,
-                          LHS, RHS);
-    if (C.isAllOnes())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
-                                                 : ICmpInst::ICMP_UGE,
-                          LHS, RHS);
+    if (C.isOne()) {
+      if (Pred == ICmpInst::ICMP_EQ)
+        return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT,
+                            LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, LHS,
+                          RHS);
+    }
+    if (C.isAllOnes()) {
+      if (Pred == ICmpInst::ICMP_EQ)
+        return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT,
+                            LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, LHS,
+                          RHS);
+    }
     break;
 
   case ICmpInst::ICMP_SGT:
     if (C.isAllOnes())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
-                                                 : ICmpInst::ICMP_UGE,
-                          LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, LHS,
+                          RHS);
     if (C.isZero())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
-                                                 : ICmpInst::ICMP_UGT,
-                          LHS, RHS);
-    break;
-
-  case ICmpInst::ICMP_SGE:
-    if (C.isZero())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGE
-                                                 : ICmpInst::ICMP_UGE,
-                          LHS, RHS);
-    if (C.isOne())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT
-                                                 : ICmpInst::ICMP_UGT,
-                          LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT, LHS,
+                          RHS);
     break;
 
   case ICmpInst::ICMP_SLT:
     if (C.isZero())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
-                                                 : ICmpInst::ICMP_ULT,
-                          LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, LHS,
+                          RHS);
     if (C.isOne())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
-                                                 : ICmpInst::ICMP_ULE,
-                          LHS, RHS);
-    break;
-
-  case llvm::ICmpInst::ICMP_SLE:
-    if (C.isZero())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLE
-                                                 : ICmpInst::ICMP_ULE,
-                          LHS, RHS);
-    if (C.isAllOnes())
-      return new ICmpInst(IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT
-                                                 : ICmpInst::ICMP_ULT,
-                          LHS, RHS);
+      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, LHS,
+                          RHS);
     break;
 
   default:

>From 451ceb6792a574d377370db4a6d3bda1cb418298 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Fri, 21 Jun 2024 17:00:04 +0100
Subject: [PATCH 4/6] Prettify the code

---
 .../InstCombine/InstCombineCompares.cpp       | 50 ++++++++-----------
 1 file changed, 21 insertions(+), 29 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 65fccc1aedcf7..7c2ecca183aa7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3930,54 +3930,46 @@ static Instruction *
 foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
                                    const APInt &C,
                                    InstCombiner::BuilderTy &Builder) {
-  bool IsScmp = I->getIntrinsicID() == Intrinsic::scmp;
-  Value *LHS = I->getOperand(0);
-  Value *RHS = I->getOperand(1);
-
+  std::optional<ICmpInst::Predicate> NewPredicate = std::nullopt;
   switch (Pred) {
   case ICmpInst::ICMP_EQ:
   case ICmpInst::ICMP_NE:
     if (C.isZero())
-      return new ICmpInst(Pred, LHS, RHS);
-    if (C.isOne()) {
-      if (Pred == ICmpInst::ICMP_EQ)
-        return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT,
-                            LHS, RHS);
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, LHS,
-                          RHS);
-    }
-    if (C.isAllOnes()) {
-      if (Pred == ICmpInst::ICMP_EQ)
-        return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT,
-                            LHS, RHS);
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, LHS,
-                          RHS);
-    }
+      NewPredicate = Pred;
+    if (C.isOne())
+      NewPredicate =
+          Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_UGT : ICmpInst::ICMP_ULE;
+    if (C.isAllOnes())
+      NewPredicate =
+          Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
     break;
 
   case ICmpInst::ICMP_SGT:
     if (C.isAllOnes())
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, LHS,
-                          RHS);
+      NewPredicate = ICmpInst::ICMP_UGE;
     if (C.isZero())
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT, LHS,
-                          RHS);
+      NewPredicate = ICmpInst::ICMP_UGT;
     break;
 
   case ICmpInst::ICMP_SLT:
     if (C.isZero())
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, LHS,
-                          RHS);
+      NewPredicate = ICmpInst::ICMP_ULT;
     if (C.isOne())
-      return new ICmpInst(IsScmp ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, LHS,
-                          RHS);
+      NewPredicate = ICmpInst::ICMP_ULE;
     break;
 
   default:
-    return nullptr;
+    break;
   }
 
-  return nullptr;
+  if (!NewPredicate)
+    return nullptr;
+
+  if (I->getIntrinsicID() == Intrinsic::scmp)
+    NewPredicate = ICmpInst::getSignedPredicate(NewPredicate.value());
+  Value *LHS = I->getOperand(0);
+  Value *RHS = I->getOperand(1);
+  return new ICmpInst(NewPredicate.value(), LHS, RHS);
 }
 
 /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C.

>From c7389c2b2523df36c6d4bf608e4ac723581c902b Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Fri, 21 Jun 2024 17:41:02 +0100
Subject: [PATCH 5/6] Add elseif's istead of a list of mutually exclusive ifs

---
 llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7c2ecca183aa7..fe5ffae5851c5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3936,10 +3936,10 @@ foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
   case ICmpInst::ICMP_NE:
     if (C.isZero())
       NewPredicate = Pred;
-    if (C.isOne())
+    else if (C.isOne())
       NewPredicate =
           Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_UGT : ICmpInst::ICMP_ULE;
-    if (C.isAllOnes())
+    else if (C.isAllOnes())
       NewPredicate =
           Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
     break;
@@ -3947,14 +3947,14 @@ foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
   case ICmpInst::ICMP_SGT:
     if (C.isAllOnes())
       NewPredicate = ICmpInst::ICMP_UGE;
-    if (C.isZero())
+    else if (C.isZero())
       NewPredicate = ICmpInst::ICMP_UGT;
     break;
 
   case ICmpInst::ICMP_SLT:
     if (C.isZero())
       NewPredicate = ICmpInst::ICMP_ULT;
-    if (C.isOne())
+    else if (C.isOne())
       NewPredicate = ICmpInst::ICMP_ULE;
     break;
 

>From af5c1729a537be26f6010768c8ee0c37d943bef5 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Fri, 21 Jun 2024 20:12:57 +0100
Subject: [PATCH 6/6] Replace .value() with dereference operator

Co-authored-by: Nikita Popov <github at npopov.com>
---
 llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index fe5ffae5851c5..1c400f55c017c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3966,10 +3966,10 @@ foldICmpOfCmpIntrinsicWithConstant(ICmpInst::Predicate Pred, IntrinsicInst *I,
     return nullptr;
 
   if (I->getIntrinsicID() == Intrinsic::scmp)
-    NewPredicate = ICmpInst::getSignedPredicate(NewPredicate.value());
+    NewPredicate = ICmpInst::getSignedPredicate(*NewPredicate);
   Value *LHS = I->getOperand(0);
   Value *RHS = I->getOperand(1);
-  return new ICmpInst(NewPredicate.value(), LHS, RHS);
+  return new ICmpInst(*NewPredicate, LHS, RHS);
 }
 
 /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C.



More information about the llvm-commits mailing list