From 65c071f98235aba983083825af75815afdfe3c93 Mon Sep 17 00:00:00 2001 From: Acthinks 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 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> +getInvertibleOperandsWithPredicte(const Operator *RefOp, const APInt C, + CmpInst::Predicate Pred) { + APInt Op1C; + // for BinaryOperator just handle RefOp with constant Operand(1) + if (isa(RefOp)) { + if (isa(RefOp->getOperand(1))) + Op1C = cast(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(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(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(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(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(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 Date: Sun, 6 Jul 2025 22:47:22 +0800 Subject: [PATCH 3/4] get the right Pred Co-authored-by: Yingwei Zheng --- .../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 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> -getInvertibleOperandsWithPredicte(const Operator *RefOp, const APInt C, - CmpInst::Predicate Pred) { - APInt Op1C; - // for BinaryOperator just handle RefOp with constant Operand(1) - if (isa(RefOp)) { - if (isa(RefOp->getOperand(1))) - Op1C = cast(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(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(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(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(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(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 &Offsets, Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1)); Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0)); break; + case Instruction::Or: + if (cast(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(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(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 +}