[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:04:24 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 351961cae5193dc8ccf69cfe8e488a4b2927450d 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..a6da07806336f 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