[llvm] [InstCombine] fold icmp of select with constants and invertible op (PR #147182)

Acthinks Yang via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 10 05:09:32 PDT 2025


https://github.com/Acthinks updated https://github.com/llvm/llvm-project/pull/147182

>From 65c071f98235aba983083825af75815afdfe3c93 Mon Sep 17 00:00:00 2001
From: Acthinks <yangzhh at mail.ustc.edu.cn>
Date: Sat, 5 Jul 2025 22:48:16 +0800
Subject: [PATCH 1/4] [Precommit] fold icmp of select with constants and
 invertible op

---
 .../icmp-select-operator-constant.ll          | 342 ++++++++++++++++++
 1 file changed, 342 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll

diff --git a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
new file mode 100644
index 0000000000000..f6c9a19cde79d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
@@ -0,0 +1,342 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; shl nsw
+; scmp
+define i1 @shl_nsw_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nsw_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nsw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 16
+  %cmp = icmp sgt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+; scmp commutative
+define i1 @c_shl_nsw_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @c_shl_nsw_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 16
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL]], [[A_SHL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sel = select i1 %cond, i8 8, i8 16
+  %a_shl = shl nsw i8 %a, 3
+  %cmp = icmp sgt i8 %sel, %a_shl
+  ret i1 %cmp
+}
+; scmp mismatch
+define i1 @shl_nsw_scmp_mismatch(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nsw_scmp_mismatch(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nsw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 1
+  %cmp = icmp sgt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+; ucmp
+define i1 @shl_nsw_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nsw_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nsw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 24
+  %cmp = icmp ugt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+; shl nuw only ucmp/eq/ne
+; ucmp
+define i1 @shl_nuw_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nuw_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nuw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 32
+  %cmp = icmp ult i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+; eq
+define i1 @shl_nuw_eqcmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nuw_eqcmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL]], [[A_SHL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nuw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 64
+  %cmp = icmp eq i8 %sel, %a_shl
+  ret i1 %cmp
+}
+
+; scmp mismatch
+define i1 @shl_nuw_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @shl_nuw_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nuw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 32
+  %cmp = icmp slt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+; ashr exact
+; ucmp
+define i1 @ashr_exact_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @ashr_exact_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = ashr exact i8 [[A]], 2
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 12, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = ashr exact i8 %a, 2
+  %sel = select i1 %cond, i8 12, i8 4
+  %cmp = icmp uge i8 %a_shl, %sel
+  ret i1 %cmp
+}
+; scmp
+define i1 @ashr_exact_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @ashr_exact_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = ashr exact i8 [[A]], 2
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = ashr exact i8 %a, 2
+  %sel = select i1 %cond, i8 8, i8 4
+  %cmp = icmp sgt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+; lshr exact only ucmp/eq/ne
+; ucmp
+define i1 @lshr_exact_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @lshr_exact_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = lshr exact i8 [[A]], 1
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 1, i8 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = lshr exact i8 %a, 1
+  %sel = select i1 %cond, i8 1, i8 3
+  %cmp = icmp ugt i8 %a_shl, %sel
+  ret i1 %cmp
+}
+; scmp mismatch
+define i1 @lshr_exact_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @lshr_exact_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[A_SHL:%.*]] = lshr exact i8 [[A]], 1
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 1, i8 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign uge i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = lshr exact i8 %a, 1
+  %sel = select i1 %cond, i8 1, i8 3
+  %cmp = icmp sge i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+; zext only ucmp/eq/ne
+; ucmp
+define i1 @zext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
+; CHECK-LABEL: define i1 @zext_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[IDX:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 128, i16 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %idx = zext i8 %a to i16
+  %sel = select i1 %cond, i16 128, i16 64
+  %cmp = icmp ult i16 %idx, %sel
+  ret i1 %cmp
+}
+; scmp mismatch
+define i1 @zext_scmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
+; CHECK-LABEL: define i1 @zext_scmp_mismatch(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[IDX:%.*]] = zext i8 [[A]] to i16
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 128, i16 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %idx = zext i8 %a to i16
+  %sel = select i1 %cond, i16 128, i16 64
+  %cmp = icmp slt i16 %idx, %sel
+  ret i1 %cmp
+}
+
+; sext
+; ucmp
+define i1 @sext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
+; CHECK-LABEL: define i1 @sext_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -127, i16 126
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %idx = sext i8 %a to i16
+  %sel = select i1 %cond, i16 -127, i16 126
+  %cmp = icmp ult i16 %idx, %sel
+  ret i1 %cmp
+}
+; ucmp mismatch
+define i1 @sext_ucmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
+; CHECK-LABEL: define i1 @sext_ucmp_mismatch(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -129, i16 128
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %idx = sext i8 %a to i16
+  %sel = select i1 %cond, i16 -129, i16 128
+  %cmp = icmp ult i16 %idx, %sel
+  ret i1 %cmp
+}
+; scmp
+define i1 @sext_scmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
+; CHECK-LABEL: define i1 @sext_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -5, i16 9
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %idx = sext i8 %a to i16
+  %sel = select i1 %cond, i16 -5, i16 9
+  %cmp = icmp slt i16 %idx, %sel
+  ret i1 %cmp
+}
+
+; or disjoint
+; ucmp
+define i1 @or_disjoint_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @or_disjoint_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[OR]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or disjoint i8 %a, 3
+  %sel = select i1 %cond, i8 11, i8 7
+  %cmp = icmp ult i8 %or, %sel
+  ret i1 %cmp
+}
+; scmp mismatch
+define i1 @or_disjoint_scmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @or_disjoint_scmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 7
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[OR]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or disjoint i8 %a, 3
+  %sel = select i1 %cond, i8 11, i8 7
+  %cmp = icmp slt i8 %or, %sel
+  ret i1 %cmp
+}
+; mismatch constant '4' not disjoint
+define i1 @or_ucmp_mismatch(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @or_ucmp_mismatch(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[OR]], [[SEL]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or disjoint i8 %a, 3
+  %sel = select i1 %cond, i8 11, i8 4
+  %cmp = icmp ult i8 %or, %sel
+  ret i1 %cmp
+}
+
+; sub only eq/ne
+define i1 @sub_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @sub_eq(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 4, i8 12
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i8 %a, 5
+  %sel = select i1 %cond, i8 -1, i8 7
+  %cmp = icmp eq i8 %sub, %sel
+  ret i1 %cmp
+}
+; ucmp mismatch
+define i1 @sub_ucmp(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @sub_ucmp(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[A]], -13
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 [[TMP1]], -8
+; CHECK-NEXT:    [[NOT_COND:%.*]] = xor i1 [[COND]], true
+; CHECK-NEXT:    [[CMP:%.*]] = select i1 [[NOT_COND]], i1 [[CMP1]], i1 false
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = sub i8 %a, 5
+  %sel = select i1 %cond, i8 -1, i8 7
+  %cmp = icmp ugt i8 %sub, %sel
+  ret i1 %cmp
+}
+
+; add only eq/ne
+define i1 @add_ne(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @add_ne(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 -6, i8 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[A]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = add i8 %a, 5
+  %sel = select i1 %cond, i8 -1, i8 7
+  %cmp = icmp ne i8 %sub, %sel
+  ret i1 %cmp
+}
+
+; xor only eq/ne
+define i1 @xor_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: define i1 @xor_eq(
+; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 -1, i8 7
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[A]], [[SEL]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 5
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sub = xor i8 %a, 5
+  %sel = select i1 %cond, i8 -1, i8 7
+  %cmp = icmp eq i8 %sub, %sel
+  ret i1 %cmp
+}

>From e633e7e29d82625ac323d9943bd8ee86d8c070af Mon Sep 17 00:00:00 2001
From: Acthinks <yangzhh at mail.ustc.edu.cn>
Date: Fri, 4 Jul 2025 19:25:09 +0800
Subject: [PATCH 2/4] [InstCombine] fold icmp of select with constants and
 invertible op

Proof: https://alive2.llvm.org/ce/z/5K6q5z
Closes #146642
---
 .../InstCombine/InstCombineCompares.cpp       | 110 ++++++++++++++++++
 .../icmp-select-operator-constant.ll          |  84 ++++++-------
 2 files changed, 144 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c6f317a668cfe..ee5ed3b5b75e6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4332,6 +4332,98 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstantNotInt(ICmpInst &I) {
   return nullptr;
 }
 
+/// If the APInt C has the same invertible function with Operator RefOp in Pred,
+/// return the operands of the function corresponding to each input. Otherwise,
+/// return std::nullopt. This is equivalent to saying that Op1 pred Op2 is true
+/// exactly when the specified pair of RefOp pred C is true.
+/// alive2: https://alive2.llvm.org/ce/z/4jniEb
+static std::optional<std::pair<Value *, Value *>>
+getInvertibleOperandsWithPredicte(const Operator *RefOp, const APInt C,
+                                  CmpInst::Predicate Pred) {
+  APInt Op1C;
+  // for BinaryOperator just handle RefOp with constant Operand(1)
+  if (isa<BinaryOperator>(RefOp)) {
+    if (isa<ConstantInt>(RefOp->getOperand(1)))
+      Op1C = cast<ConstantInt>(RefOp->getOperand(1))->getValue();
+    else
+      return std::nullopt;
+  }
+
+  auto getOperands = [&](APInt A) -> auto {
+    return std::make_pair(RefOp->getOperand(0),
+                          ConstantInt::get(RefOp->getOperand(0)->getType(), A));
+  };
+  switch (RefOp->getOpcode()) {
+  default:
+    break;
+  case Instruction::Or:
+    if (cast<PossiblyDisjointInst>(RefOp)->isDisjoint() && ((C & Op1C) == Op1C))
+      return getOperands(C ^ Op1C);
+    break;
+  case Instruction::Add: {
+    // TODO: add/sub could support nsw/nuw for scmp/ucmp
+    if (CmpInst::isEquality(Pred))
+      return getOperands(C - Op1C);
+    break;
+  }
+  case Instruction::Xor: {
+    if (CmpInst::isEquality(Pred))
+      return getOperands(C ^ Op1C);
+    break;
+  }
+  case Instruction::Sub: {
+    if (CmpInst::isEquality(Pred))
+      return getOperands(C + Op1C);
+    break;
+  }
+  // alive2: https://alive2.llvm.org/ce/z/WPQznV
+  case Instruction::Shl: {
+    // Z = shl nsw X, Y <=> X = ashr exact Z, Y
+    // Z = shl nuw X, Y <=> X = lshr exact Z, Y
+    if (C.ashr(Op1C).shl(Op1C) == C) {
+      auto *OBO1 = cast<OverflowingBinaryOperator>(RefOp);
+      if (OBO1->hasNoSignedWrap())
+        return getOperands(C.ashr(Op1C));
+      else if (OBO1->hasNoUnsignedWrap() && !ICmpInst::isSigned(Pred))
+        return getOperands(C.lshr(Op1C));
+    }
+    break;
+  }
+  case Instruction::AShr: {
+    // Z = ashr exact X, Y <=> X = shl nsw Z, Y
+    auto *PEO1 = cast<PossiblyExactOperator>(RefOp);
+    if (PEO1->isExact() && C.shl(Op1C).ashr(Op1C) == C)
+      return getOperands(C.shl(Op1C));
+    break;
+  }
+  case Instruction::LShr: {
+    // Z = lshr exact X, Y <=> X = shl nuw Z, Y
+    auto *PEO1 = cast<PossiblyExactOperator>(RefOp);
+    if (PEO1->isExact() && C.shl(Op1C).lshr(Op1C) == C &&
+        !ICmpInst::isSigned(Pred))
+      return getOperands(C.shl(Op1C));
+    break;
+  }
+  case Instruction::SExt: {
+    unsigned NumBits = RefOp->getType()->getScalarSizeInBits();
+    unsigned NumBitsOp0 =
+        RefOp->getOperand(0)->getType()->getScalarSizeInBits();
+    if (C.trunc(NumBitsOp0).sext(NumBits) == C)
+      return getOperands(C.trunc(NumBitsOp0));
+    break;
+  }
+  case Instruction::ZExt: {
+    unsigned NumBits = RefOp->getType()->getScalarSizeInBits();
+    unsigned NumBitsOp0 =
+        RefOp->getOperand(0)->getType()->getScalarSizeInBits();
+    if (C.trunc(NumBitsOp0).zext(NumBits) == C && !ICmpInst::isSigned(Pred))
+      return getOperands(C.trunc(NumBitsOp0));
+    break;
+  }
+  }
+  return std::nullopt;
+}
+
 Instruction *InstCombinerImpl::foldSelectICmp(CmpPredicate Pred, SelectInst *SI,
                                               Value *RHS, const ICmpInst &I) {
   // Try to fold the comparison into the select arms, which will cause the
@@ -4391,6 +4483,24 @@ Instruction *InstCombinerImpl::foldSelectICmp(CmpPredicate Pred, SelectInst *SI,
     return SelectInst::Create(SI->getOperand(0), Op1, Op2);
   }
 
+  // fold select with constants and invertible op
+  Value *Cond;
+  const APInt *C1, *C2;
+  auto *RHSOp = dyn_cast<Operator>(RHS);
+  if (RHSOp &&
+      match(SI, m_OneUse(m_Select(m_Value(Cond), m_APInt(C1), m_APInt(C2))))) {
+    if (auto Values0 = getInvertibleOperandsWithPredicte(RHSOp, *C1, Pred)) {
+      if (auto Values1 = getInvertibleOperandsWithPredicte(RHSOp, *C2, Pred)) {
+        assert(Values0->first == Values1->first &&
+               "Invertible Operand0 mismatch");
+        auto *NewSI = Builder.CreateSelect(Cond, Values0->second,
+                                           Values1->second, SI->getName());
+        return ICmpInst::Create(Instruction::ICmp, I.getPredicate(), NewSI,
+                                Values0->first, I.getName());
+      }
+    }
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
index f6c9a19cde79d..944d0a00bfe75 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
@@ -6,9 +6,8 @@
 define i1 @shl_nsw_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nsw_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nsw i8 %a, 3
@@ -20,9 +19,8 @@ define i1 @shl_nsw_scmp(i8 %a, i1 %cond) {
 define i1 @c_shl_nsw_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @c_shl_nsw_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 16
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL]], [[A_SHL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sel = select i1 %cond, i8 8, i8 16
@@ -48,9 +46,8 @@ define i1 @shl_nsw_scmp_mismatch(i8 %a, i1 %cond) {
 define i1 @shl_nsw_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nsw_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 24
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 3
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nsw i8 %a, 3
@@ -64,9 +61,8 @@ define i1 @shl_nsw_ucmp(i8 %a, i1 %cond) {
 define i1 @shl_nuw_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nuw_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 32
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nuw i8 %a, 3
@@ -79,9 +75,8 @@ define i1 @shl_nuw_ucmp(i8 %a, i1 %cond) {
 define i1 @shl_nuw_eqcmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nuw_eqcmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 64
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL]], [[A_SHL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nuw i8 %a, 3
@@ -110,9 +105,8 @@ define i1 @shl_nuw_scmp(i8 %a, i1 %cond) {
 define i1 @ashr_exact_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @ashr_exact_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = ashr exact i8 [[A]], 2
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 12, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 48, i8 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = ashr exact i8 %a, 2
@@ -124,9 +118,8 @@ define i1 @ashr_exact_ucmp(i8 %a, i1 %cond) {
 define i1 @ashr_exact_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @ashr_exact_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = ashr exact i8 [[A]], 2
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 32, i8 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = ashr exact i8 %a, 2
@@ -140,9 +133,8 @@ define i1 @ashr_exact_scmp(i8 %a, i1 %cond) {
 define i1 @lshr_exact_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @lshr_exact_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = lshr exact i8 [[A]], 1
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 1, i8 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = lshr exact i8 %a, 1
@@ -154,9 +146,8 @@ define i1 @lshr_exact_ucmp(i8 %a, i1 %cond) {
 define i1 @lshr_exact_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @lshr_exact_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = lshr exact i8 [[A]], 1
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 1, i8 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign uge i8 [[A_SHL]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = lshr exact i8 %a, 1
@@ -170,9 +161,8 @@ define i1 @lshr_exact_scmp(i8 %a, i1 %cond) {
 define i1 @zext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 ; CHECK-LABEL: define i1 @zext_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[IDX:%.*]] = zext i8 [[A]] to i16
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 128, i16 64
-; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -128, i8 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %idx = zext i8 %a to i16
@@ -184,9 +174,8 @@ define i1 @zext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 define i1 @zext_scmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 ; CHECK-LABEL: define i1 @zext_scmp_mismatch(
 ; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[IDX:%.*]] = zext i8 [[A]] to i16
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 128, i16 64
-; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -128, i8 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %idx = zext i8 %a to i16
@@ -200,9 +189,8 @@ define i1 @zext_scmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 define i1 @sext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 ; CHECK-LABEL: define i1 @sext_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -127, i16 126
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -127, i8 126
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %idx = sext i8 %a to i16
@@ -228,9 +216,8 @@ define i1 @sext_ucmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 define i1 @sext_scmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 ; CHECK-LABEL: define i1 @sext_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -5, i16 9
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i16 [[SEL]], [[IDX]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -5, i8 9
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %idx = sext i8 %a to i16
@@ -244,9 +231,8 @@ define i1 @sext_scmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
 define i1 @or_disjoint_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @or_disjoint_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[OR]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %or = or disjoint i8 %a, 3
@@ -258,9 +244,8 @@ define i1 @or_disjoint_ucmp(i8 %a, i1 %cond) {
 define i1 @or_disjoint_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @or_disjoint_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[OR]], [[SEL]]
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %or = or disjoint i8 %a, 3
@@ -288,7 +273,7 @@ define i1 @sub_eq(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @sub_eq(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 4, i8 12
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A]], [[TMP1]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sub = sub i8 %a, 5
@@ -317,7 +302,7 @@ define i1 @add_ne(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @add_ne(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 -6, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[A]], [[TMP1]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[TMP1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sub = add i8 %a, 5
@@ -330,9 +315,8 @@ define i1 @add_ne(i8 %a, i1 %cond) {
 define i1 @xor_eq(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @xor_eq(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 -1, i8 7
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[A]], [[SEL]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 5
+; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -6, i8 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sub = xor i8 %a, 5

>From 528aa2ba78ef9e526edefc350104734f9b1d02c2 Mon Sep 17 00:00:00 2001
From: Acthinks Yang <yangzhh at mail.ustc.edu.cn>
Date: Sun, 6 Jul 2025 22:47:22 +0800
Subject: [PATCH 3/4] get the right Pred

Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
 .../InstCombine/InstCombineCompares.cpp        |  4 ++--
 .../icmp-select-operator-constant.ll           | 18 +++++++++---------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index ee5ed3b5b75e6..89b5302889c8b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4495,8 +4495,8 @@ Instruction *InstCombinerImpl::foldSelectICmp(CmpPredicate Pred, SelectInst *SI,
                "Invertible Operand0 mismatch");
         auto *NewSI = Builder.CreateSelect(Cond, Values0->second,
                                            Values1->second, SI->getName());
-        return ICmpInst::Create(Instruction::ICmp, I.getPredicate(), NewSI,
-                                Values0->first, I.getName());
+        return ICmpInst::Create(Instruction::ICmp, Pred, NewSI, Values0->first,
+                                I.getName());
       }
     }
   }
diff --git a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
index 944d0a00bfe75..ebe6283ee0ce0 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
@@ -7,7 +7,7 @@ define i1 @shl_nsw_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nsw_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nsw i8 %a, 3
@@ -47,7 +47,7 @@ define i1 @shl_nsw_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nsw_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nsw i8 %a, 3
@@ -62,7 +62,7 @@ define i1 @shl_nuw_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @shl_nuw_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = shl nuw i8 %a, 3
@@ -106,7 +106,7 @@ define i1 @ashr_exact_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @ashr_exact_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 48, i8 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = ashr exact i8 %a, 2
@@ -119,7 +119,7 @@ define i1 @ashr_exact_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @ashr_exact_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 32, i8 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = ashr exact i8 %a, 2
@@ -134,7 +134,7 @@ define i1 @lshr_exact_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @lshr_exact_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = lshr exact i8 %a, 1
@@ -147,7 +147,7 @@ define i1 @lshr_exact_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @lshr_exact_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %a_shl = lshr exact i8 %a, 1
@@ -232,7 +232,7 @@ define i1 @or_disjoint_ucmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @or_disjoint_ucmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %or = or disjoint i8 %a, 3
@@ -245,7 +245,7 @@ define i1 @or_disjoint_scmp(i8 %a, i1 %cond) {
 ; CHECK-LABEL: define i1 @or_disjoint_scmp(
 ; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
 ; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %or = or disjoint i8 %a, 3

>From bca4a725304cb6159e28f56675d2064165a98261 Mon Sep 17 00:00:00 2001
From: Acthinks <yangzhh at mail.ustc.edu.cn>
Date: Thu, 10 Jul 2025 18:39:56 +0800
Subject: [PATCH 4/4] use foldICmpEqualityWithOffset

---
 llvm/lib/Analysis/InstructionSimplify.cpp     |   8 +
 .../InstCombine/InstCombineCompares.cpp       | 128 +------
 .../icmp-select-operator-constant.ll          | 326 ------------------
 .../Transforms/InstCombine/icmp-select.ll     |  60 ++++
 llvm/test/Transforms/InstSimplify/xor.ll      |  18 +
 5 files changed, 104 insertions(+), 436 deletions(-)
 delete mode 100644 llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 90baa054eed4c..311064eebf99d 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2557,6 +2557,14 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
       return X;
   }
 
+  // (xor (or disjoint X, Y), Y) -> X
+  {
+    Value *X;
+    if (match(Op0, m_c_DisjointOr(m_Value(X), m_Specific(Op1))) ||
+        match(Op1, m_c_DisjointOr(m_Value(X), m_Specific(Op0))))
+      return X;
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 89b5302889c8b..e87e31e162c29 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4332,98 +4332,6 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstantNotInt(ICmpInst &I) {
   return nullptr;
 }
 
-/// If the APInt C has the same invertible function with Operator RefOp in Pred,
-/// return the operands of the function corresponding to each input. Otherwise,
-/// return std::nullopt. This is equivalent to saying that Op1 pred Op2 is true
-/// exactly when the specified pair of RefOp pred C is true.
-/// alive2: https://alive2.llvm.org/ce/z/4jniEb
-static std::optional<std::pair<Value *, Value *>>
-getInvertibleOperandsWithPredicte(const Operator *RefOp, const APInt C,
-                                  CmpInst::Predicate Pred) {
-  APInt Op1C;
-  // for BinaryOperator just handle RefOp with constant Operand(1)
-  if (isa<BinaryOperator>(RefOp)) {
-    if (isa<ConstantInt>(RefOp->getOperand(1)))
-      Op1C = cast<ConstantInt>(RefOp->getOperand(1))->getValue();
-    else
-      return std::nullopt;
-  }
-
-  auto getOperands = [&](APInt A) -> auto {
-    return std::make_pair(RefOp->getOperand(0),
-                          ConstantInt::get(RefOp->getOperand(0)->getType(), A));
-  };
-  switch (RefOp->getOpcode()) {
-  default:
-    break;
-  case Instruction::Or:
-    if (cast<PossiblyDisjointInst>(RefOp)->isDisjoint() && ((C & Op1C) == Op1C))
-      return getOperands(C ^ Op1C);
-    break;
-  case Instruction::Add: {
-    // TODO: add/sub could support nsw/nuw for scmp/ucmp
-    if (CmpInst::isEquality(Pred))
-      return getOperands(C - Op1C);
-    break;
-  }
-  case Instruction::Xor: {
-    if (CmpInst::isEquality(Pred))
-      return getOperands(C ^ Op1C);
-    break;
-  }
-  case Instruction::Sub: {
-    if (CmpInst::isEquality(Pred))
-      return getOperands(C + Op1C);
-    break;
-  }
-  // alive2: https://alive2.llvm.org/ce/z/WPQznV
-  case Instruction::Shl: {
-    // Z = shl nsw X, Y <=> X = ashr exact Z, Y
-    // Z = shl nuw X, Y <=> X = lshr exact Z, Y
-    if (C.ashr(Op1C).shl(Op1C) == C) {
-      auto *OBO1 = cast<OverflowingBinaryOperator>(RefOp);
-      if (OBO1->hasNoSignedWrap())
-        return getOperands(C.ashr(Op1C));
-      else if (OBO1->hasNoUnsignedWrap() && !ICmpInst::isSigned(Pred))
-        return getOperands(C.lshr(Op1C));
-    }
-    break;
-  }
-  case Instruction::AShr: {
-    // Z = ashr exact X, Y <=> X = shl nsw Z, Y
-    auto *PEO1 = cast<PossiblyExactOperator>(RefOp);
-    if (PEO1->isExact() && C.shl(Op1C).ashr(Op1C) == C)
-      return getOperands(C.shl(Op1C));
-    break;
-  }
-  case Instruction::LShr: {
-    // Z = lshr exact X, Y <=> X = shl nuw Z, Y
-    auto *PEO1 = cast<PossiblyExactOperator>(RefOp);
-    if (PEO1->isExact() && C.shl(Op1C).lshr(Op1C) == C &&
-        !ICmpInst::isSigned(Pred))
-      return getOperands(C.shl(Op1C));
-    break;
-  }
-  case Instruction::SExt: {
-    unsigned NumBits = RefOp->getType()->getScalarSizeInBits();
-    unsigned NumBitsOp0 =
-        RefOp->getOperand(0)->getType()->getScalarSizeInBits();
-    if (C.trunc(NumBitsOp0).sext(NumBits) == C)
-      return getOperands(C.trunc(NumBitsOp0));
-    break;
-  }
-  case Instruction::ZExt: {
-    unsigned NumBits = RefOp->getType()->getScalarSizeInBits();
-    unsigned NumBitsOp0 =
-        RefOp->getOperand(0)->getType()->getScalarSizeInBits();
-    if (C.trunc(NumBitsOp0).zext(NumBits) == C && !ICmpInst::isSigned(Pred))
-      return getOperands(C.trunc(NumBitsOp0));
-    break;
-  }
-  }
-  return std::nullopt;
-}
-
 Instruction *InstCombinerImpl::foldSelectICmp(CmpPredicate Pred, SelectInst *SI,
                                               Value *RHS, const ICmpInst &I) {
   // Try to fold the comparison into the select arms, which will cause the
@@ -4483,24 +4391,6 @@ Instruction *InstCombinerImpl::foldSelectICmp(CmpPredicate Pred, SelectInst *SI,
     return SelectInst::Create(SI->getOperand(0), Op1, Op2);
   }
 
-  // fold select with constants and invertible op
-  Value *Cond;
-  const APInt *C1, *C2;
-  auto *RHSOp = dyn_cast<Operator>(RHS);
-  if (RHSOp &&
-      match(SI, m_OneUse(m_Select(m_Value(Cond), m_APInt(C1), m_APInt(C2))))) {
-    if (auto Values0 = getInvertibleOperandsWithPredicte(RHSOp, *C1, Pred)) {
-      if (auto Values1 = getInvertibleOperandsWithPredicte(RHSOp, *C2, Pred)) {
-        assert(Values0->first == Values1->first &&
-               "Invertible Operand0 mismatch");
-        auto *NewSI = Builder.CreateSelect(Cond, Values0->second,
-                                           Values1->second, SI->getName());
-        return ICmpInst::Create(Instruction::ICmp, Pred, NewSI, Values0->first,
-                                I.getName());
-      }
-    }
-  }
-
   return nullptr;
 }
 
@@ -5976,6 +5866,24 @@ static void collectOffsetOp(Value *V, SmallVectorImpl<OffsetOp> &Offsets,
     Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1));
     Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0));
     break;
+  case Instruction::Or:
+    if (cast<PossiblyDisjointInst>(Inst)->isDisjoint())
+      Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1));
+    Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0));
+    break;
+  case Instruction::Shl:
+    if (auto *OBO = cast<OverflowingBinaryOperator>(Inst)) {
+      if (OBO->hasNoSignedWrap())
+        Offsets.emplace_back(Instruction::AShr, Inst->getOperand(1));
+      else if (OBO->hasNoUnsignedWrap())
+        Offsets.emplace_back(Instruction::LShr, Inst->getOperand(1));
+    }
+    break;
+  case Instruction::AShr:
+  case Instruction::LShr:
+    if (auto *PEO = cast<PossiblyExactOperator>(Inst); PEO && PEO->isExact())
+      Offsets.emplace_back(Instruction::Shl, Inst->getOperand(1));
+    break;
   case Instruction::Select:
     if (AllowRecursion) {
       collectOffsetOp(Inst->getOperand(1), Offsets, /*AllowRecursion=*/false);
diff --git a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
deleted file mode 100644
index ebe6283ee0ce0..0000000000000
--- a/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
+++ /dev/null
@@ -1,326 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
-; RUN: opt -S -passes=instcombine < %s | FileCheck %s
-
-; shl nsw
-; scmp
-define i1 @shl_nsw_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nsw_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nsw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 16
-  %cmp = icmp sgt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-; scmp commutative
-define i1 @c_shl_nsw_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @c_shl_nsw_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sel = select i1 %cond, i8 8, i8 16
-  %a_shl = shl nsw i8 %a, 3
-  %cmp = icmp sgt i8 %sel, %a_shl
-  ret i1 %cmp
-}
-; scmp mismatch
-define i1 @shl_nsw_scmp_mismatch(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nsw_scmp_mismatch(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nsw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[A_SHL]], [[SEL]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nsw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 1
-  %cmp = icmp sgt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-; ucmp
-define i1 @shl_nsw_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nsw_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nsw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 24
-  %cmp = icmp ugt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-
-; shl nuw only ucmp/eq/ne
-; ucmp
-define i1 @shl_nuw_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nuw_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nuw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 32
-  %cmp = icmp ult i8 %a_shl, %sel
-  ret i1 %cmp
-}
-
-; eq
-define i1 @shl_nuw_eqcmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nuw_eqcmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 1, i8 8
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nuw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 64
-  %cmp = icmp eq i8 %sel, %a_shl
-  ret i1 %cmp
-}
-
-; scmp mismatch
-define i1 @shl_nuw_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @shl_nuw_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[A_SHL:%.*]] = shl nuw i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 8, i8 32
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[A_SHL]], [[SEL]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = shl nuw i8 %a, 3
-  %sel = select i1 %cond, i8 8, i8 32
-  %cmp = icmp slt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-
-; ashr exact
-; ucmp
-define i1 @ashr_exact_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @ashr_exact_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 48, i8 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = ashr exact i8 %a, 2
-  %sel = select i1 %cond, i8 12, i8 4
-  %cmp = icmp uge i8 %a_shl, %sel
-  ret i1 %cmp
-}
-; scmp
-define i1 @ashr_exact_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @ashr_exact_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 32, i8 16
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = ashr exact i8 %a, 2
-  %sel = select i1 %cond, i8 8, i8 4
-  %cmp = icmp sgt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-
-; lshr exact only ucmp/eq/ne
-; ucmp
-define i1 @lshr_exact_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @lshr_exact_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = lshr exact i8 %a, 1
-  %sel = select i1 %cond, i8 1, i8 3
-  %cmp = icmp ugt i8 %a_shl, %sel
-  ret i1 %cmp
-}
-; scmp mismatch
-define i1 @lshr_exact_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @lshr_exact_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 2, i8 6
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %a_shl = lshr exact i8 %a, 1
-  %sel = select i1 %cond, i8 1, i8 3
-  %cmp = icmp sge i8 %a_shl, %sel
-  ret i1 %cmp
-}
-
-; zext only ucmp/eq/ne
-; ucmp
-define i1 @zext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
-; CHECK-LABEL: define i1 @zext_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -128, i8 64
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %idx = zext i8 %a to i16
-  %sel = select i1 %cond, i16 128, i16 64
-  %cmp = icmp ult i16 %idx, %sel
-  ret i1 %cmp
-}
-; scmp mismatch
-define i1 @zext_scmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
-; CHECK-LABEL: define i1 @zext_scmp_mismatch(
-; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -128, i8 64
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %idx = zext i8 %a to i16
-  %sel = select i1 %cond, i16 128, i16 64
-  %cmp = icmp slt i16 %idx, %sel
-  ret i1 %cmp
-}
-
-; sext
-; ucmp
-define i1 @sext_ucmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
-; CHECK-LABEL: define i1 @sext_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -127, i8 126
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %idx = sext i8 %a to i16
-  %sel = select i1 %cond, i16 -127, i16 126
-  %cmp = icmp ult i16 %idx, %sel
-  ret i1 %cmp
-}
-; ucmp mismatch
-define i1 @sext_ucmp_mismatch(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
-; CHECK-LABEL: define i1 @sext_ucmp_mismatch(
-; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[IDX:%.*]] = sext i8 [[A]] to i16
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i16 -129, i16 128
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i16 [[SEL]], [[IDX]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %idx = sext i8 %a to i16
-  %sel = select i1 %cond, i16 -129, i16 128
-  %cmp = icmp ult i16 %idx, %sel
-  ret i1 %cmp
-}
-; scmp
-define i1 @sext_scmp(i8 %a, i16 %c0, i16 %c1, i1 %cond) {
-; CHECK-LABEL: define i1 @sext_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i16 [[C0:%.*]], i16 [[C1:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -5, i8 9
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %idx = sext i8 %a to i16
-  %sel = select i1 %cond, i16 -5, i16 9
-  %cmp = icmp slt i16 %idx, %sel
-  ret i1 %cmp
-}
-
-; or disjoint
-; ucmp
-define i1 @or_disjoint_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @or_disjoint_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or disjoint i8 %a, 3
-  %sel = select i1 %cond, i8 11, i8 7
-  %cmp = icmp ult i8 %or, %sel
-  ret i1 %cmp
-}
-; scmp mismatch
-define i1 @or_disjoint_scmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @or_disjoint_scmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 8, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or disjoint i8 %a, 3
-  %sel = select i1 %cond, i8 11, i8 7
-  %cmp = icmp slt i8 %or, %sel
-  ret i1 %cmp
-}
-; mismatch constant '4' not disjoint
-define i1 @or_ucmp_mismatch(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @or_ucmp_mismatch(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i8 [[A]], 3
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[COND]], i8 11, i8 4
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[OR]], [[SEL]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %or = or disjoint i8 %a, 3
-  %sel = select i1 %cond, i8 11, i8 4
-  %cmp = icmp ult i8 %or, %sel
-  ret i1 %cmp
-}
-
-; sub only eq/ne
-define i1 @sub_eq(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @sub_eq(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 4, i8 12
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sub = sub i8 %a, 5
-  %sel = select i1 %cond, i8 -1, i8 7
-  %cmp = icmp eq i8 %sub, %sel
-  ret i1 %cmp
-}
-; ucmp mismatch
-define i1 @sub_ucmp(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @sub_ucmp(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[A]], -13
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 [[TMP1]], -8
-; CHECK-NEXT:    [[NOT_COND:%.*]] = xor i1 [[COND]], true
-; CHECK-NEXT:    [[CMP:%.*]] = select i1 [[NOT_COND]], i1 [[CMP1]], i1 false
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sub = sub i8 %a, 5
-  %sel = select i1 %cond, i8 -1, i8 7
-  %cmp = icmp ugt i8 %sub, %sel
-  ret i1 %cmp
-}
-
-; add only eq/ne
-define i1 @add_ne(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @add_ne(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i8 -6, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[TMP1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sub = add i8 %a, 5
-  %sel = select i1 %cond, i8 -1, i8 7
-  %cmp = icmp ne i8 %sub, %sel
-  ret i1 %cmp
-}
-
-; xor only eq/ne
-define i1 @xor_eq(i8 %a, i1 %cond) {
-; CHECK-LABEL: define i1 @xor_eq(
-; CHECK-SAME: i8 [[A:%.*]], i1 [[COND:%.*]]) {
-; CHECK-NEXT:    [[SEL1:%.*]] = select i1 [[COND]], i8 -6, i8 2
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SEL1]], [[A]]
-; CHECK-NEXT:    ret i1 [[CMP]]
-;
-  %sub = xor i8 %a, 5
-  %sel = select i1 %cond, i8 -1, i8 7
-  %cmp = icmp eq i8 %sub, %sel
-  ret i1 %cmp
-}
diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll
index a038731abbc48..2a4009d24fcf2 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select.ll
@@ -836,3 +836,63 @@ define i1 @discr_eq_constantexpr(ptr %p) {
   %cmp = icmp eq i64 %sub, -1
   ret i1 %cmp
 }
+
+define i1 @or_disjoint_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: @or_disjoint_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 8, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %or = or disjoint i8 %a, 3
+  %sel = select i1 %cond, i8 11, i8 7
+  %cmp = icmp eq i8 %or, %sel
+  ret i1 %cmp
+}
+
+define i1 @shl_nsw_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: @shl_nsw_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nsw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 16
+  %cmp = icmp eq i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+define i1 @shl_nuw_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: @shl_nuw_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = shl nuw i8 %a, 3
+  %sel = select i1 %cond, i8 8, i8 32
+  %cmp = icmp eq i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+define i1 @ashr_exact_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: @ashr_exact_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 48, i8 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = ashr exact i8 %a, 2
+  %sel = select i1 %cond, i8 12, i8 4
+  %cmp = icmp eq i8 %a_shl, %sel
+  ret i1 %cmp
+}
+
+define i1 @lshr_exact_eq(i8 %a, i1 %cond) {
+; CHECK-LABEL: @lshr_exact_eq(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 48, i8 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %a_shl = lshr exact i8 %a, 2
+  %sel = select i1 %cond, i8 12, i8 4
+  %cmp = icmp eq i8 %a_shl, %sel
+  ret i1 %cmp
+}
diff --git a/llvm/test/Transforms/InstSimplify/xor.ll b/llvm/test/Transforms/InstSimplify/xor.ll
index eaa016b6614e1..c7b0766bb65c4 100644
--- a/llvm/test/Transforms/InstSimplify/xor.ll
+++ b/llvm/test/Transforms/InstSimplify/xor.ll
@@ -301,3 +301,21 @@ define <2 x i4> @xor_or_and_not_poison_elt(<2 x i4> %a, <2 x i4> %b) {
   %r = xor <2 x i4> %or, %and
   ret <2 x i4> %r
 }
+
+define i8 @xor_or_disjoint(i8 %a, i8 %b) {
+; CHECK-LABEL: @xor_or_disjoint(
+; CHECK-NEXT:    ret i8 [[B:%.*]]
+;
+  %or = or disjoint i8 %a, %b
+  %xor = xor i8 %or, %a
+  ret i8 %xor
+}
+
+define i8 @xor_or_disjoint_c(i8 %a, i8 %b) {
+; CHECK-LABEL: @xor_or_disjoint_c(
+; CHECK-NEXT:    ret i8 [[B:%.*]]
+;
+  %or = or disjoint i8 %b, %a
+  %xor = xor i8 %a, %or
+  ret i8 %xor
+}



More information about the llvm-commits mailing list