[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