diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 9ab2bd8f70aa1..755e44c3838e2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1687,6 +1687,39 @@ static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI, return nullptr; } +static Value *foldSelectInstWithICmpOr(SelectInst &SI, ICmpInst *ICI, + InstCombiner::BuilderTy &Builder) { + // a > -1 ? 1 : ( a | (+ve)value) --> smin(1, a | (+ve)value) + // a < -1 ? ( a | (+ve)value) : 1 --> smin(1, a | (+ve)value) + Value *C; + const APInt *Cmp; + Value *A = ICI->getOperand(0); + Value *B = ICI->getOperand(1); + Value *TVal = SI.getTrueValue(); + Value *FVal = SI.getFalseValue(); + ICmpInst::Predicate Pred = ICI->getPredicate(); + + if (!match(B, m_APInt(Cmp))) + return nullptr; + + if (Pred == ICmpInst::ICMP_SLT) + std::swap(TVal, FVal); + + if (!(match(TVal, m_One()) || match(TVal, m_Zero()) || + match(TVal, m_AllOnes())) || + !(match(FVal, m_Or(m_Value(A), m_Value(C))))) + return nullptr; + + if (!match(C, m_StrictlyPositive())) + return nullptr; + + if ((Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT)) + if ((match(TVal, m_One()) || match(TVal, m_Zero()) || + match(TVal, m_AllOnes())) && + (Cmp->isAllOnes() || Cmp->isZero())) + return Builder.CreateBinaryIntrinsic(Intrinsic::smin, TVal, FVal); +} + /// Visit a SelectInst that has an ICmpInst as its first operand. Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI) { @@ -1700,6 +1733,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder)) return replaceInstUsesWith(SI, V); + if (Value *V = foldSelectInstWithICmpOr(SI, ICI, Builder)) + return replaceInstUsesWith(SI, V); + if (Value *V = canonicalizeClampLike(SI, *ICI, Builder)) return replaceInstUsesWith(SI, V); diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll index 59d2a1b165c0f..a30868b53f721 100644 --- a/llvm/test/Transforms/InstCombine/icmp-select.ll +++ b/llvm/test/Transforms/InstCombine/icmp-select.ll @@ -628,3 +628,57 @@ define i1 @icmp_slt_select(i1 %cond, i32 %a, i32 %b) { %res = icmp slt i32 %lhs, %rhs ret i1 %res } + +define i8 @icmp_pos_sgt_select_or(i8 %inl, i8 %y) { +; CHECK-LABEL: @icmp_pos_sgt_select_or( +; CHECK-NEXT: [[POS:%.*]] = icmp sgt i8 [[Y:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[POS]]) +; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], [[Y]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[INL]], -1 +; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 1, i8 [[OR]] +; CHECK-NEXT: ret i8 [[S]] +; + %pos = icmp sgt i8 %y, 0 + call void @llvm.assume(i1 %pos) + + %or = or i8 %inl, %y + %cmp = icmp sgt i8 %inl, -1 + %s = select i1 %cmp, i8 1, i8 %or + ret i8 %s +} + +define i8 @icmp_neg_sgt_select_or(i8 %inl, i8 %y) { +; CHECK-LABEL: @icmp_neg_sgt_select_or( +; CHECK-NEXT: [[NEG:%.*]] = icmp slt i8 [[Y:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[NEG]]) +; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], [[Y]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[INL]], -1 +; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 1, i8 [[OR]] +; CHECK-NEXT: ret i8 [[S]] +; + %neg = icmp slt i8 %y, 0 + call void @llvm.assume(i1 %neg) + + %or = or i8 %inl, %y + %cmp = icmp sgt i8 %inl, -1 + %s = select i1 %cmp, i8 1, i8 %or + ret i8 %s +} + +define i8 @icmp_nonneg_sgt_select_or(i8 %inl, i8 %y) { +; CHECK-LABEL: @icmp_nonneg_sgt_select_or( +; CHECK-NEXT: [[NNEG:%.*]] = icmp sgt i8 [[Y:%.*]], -1 +; CHECK-NEXT: call void @llvm.assume(i1 [[NNEG]]) +; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], [[Y]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[INL]], -1 +; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 1, i8 [[OR]] +; CHECK-NEXT: ret i8 [[S]] +; + %nneg = icmp sgt i8 %y, -1 + call void @llvm.assume(i1 %nneg) + + %or = or i8 %inl, %y + %cmp = icmp sgt i8 %inl, -1 + %s = select i1 %cmp, i8 1, i8 %or + ret i8 %s +}