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

via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 6 02:39:00 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Acthinks Yang (Acthinks)

<details>
<summary>Changes</summary>


Proof: https://alive2.llvm.org/ce/z/5K6q5z
Closes https://github.com/llvm/llvm-project/issues/146642

---
Full diff: https://github.com/llvm/llvm-project/pull/147182.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+110) 
- (added) llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll (+326) 


``````````diff
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
new file mode 100644
index 0000000000000..944d0a00bfe75
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-select-operator-constant.ll
@@ -0,0 +1,326 @@
+; 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 sgt 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 ugt 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 ult 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 uge 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 sgt 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 ugt 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 uge 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 ult 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 slt 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
+}

``````````

</details>


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


More information about the llvm-commits mailing list