Skip to content

Commit caeefe7

Browse files
authored
[InstCombine] Extend foldSelectInstWithICmpConst to handle minmax (llvm#125346)
This patch extends llvm@f6bb156 to handle minmax intrinsics. Motivating case: https://alive2.llvm.org/ce/z/JFKbYn Addresses a regression caused by llvm#121958. It also works for `*.sat`. But no real-world benefit is observed.
1 parent 2eabcb7 commit caeefe7

File tree

2 files changed

+87
-12
lines changed

2 files changed

+87
-12
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,26 +1771,38 @@ static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
17711771
return Builder.CreateBinaryIntrinsic(Intrinsic::smin, V, TVal);
17721772
}
17731773

1774-
BinaryOperator *BO;
1774+
// Fold icmp(X) ? f(X) : C to f(X) when f(X) is guaranteed to be equal to C
1775+
// for all X in the exact range of the inverse predicate.
1776+
Instruction *Op;
17751777
const APInt *C;
17761778
CmpInst::Predicate CPred;
1777-
if (match(&SI, m_Select(m_Specific(ICI), m_APInt(C), m_BinOp(BO))))
1779+
if (match(&SI, m_Select(m_Specific(ICI), m_APInt(C), m_Instruction(Op))))
17781780
CPred = ICI->getPredicate();
1779-
else if (match(&SI, m_Select(m_Specific(ICI), m_BinOp(BO), m_APInt(C))))
1781+
else if (match(&SI, m_Select(m_Specific(ICI), m_Instruction(Op), m_APInt(C))))
17801782
CPred = ICI->getInversePredicate();
17811783
else
17821784
return nullptr;
17831785

1784-
const APInt *BinOpC;
1785-
if (!match(BO, m_BinOp(m_Specific(V), m_APInt(BinOpC))))
1786-
return nullptr;
1787-
1788-
ConstantRange R = ConstantRange::makeExactICmpRegion(CPred, *CmpC)
1789-
.binaryOp(BO->getOpcode(), *BinOpC);
1790-
if (R == *C) {
1791-
BO->dropPoisonGeneratingFlags();
1792-
return BO;
1786+
ConstantRange InvDomCR = ConstantRange::makeExactICmpRegion(CPred, *CmpC);
1787+
const APInt *OpC;
1788+
if (match(Op, m_BinOp(m_Specific(V), m_APInt(OpC)))) {
1789+
ConstantRange R = InvDomCR.binaryOp(
1790+
static_cast<Instruction::BinaryOps>(Op->getOpcode()), *OpC);
1791+
if (R == *C) {
1792+
Op->dropPoisonGeneratingFlags();
1793+
return Op;
1794+
}
1795+
}
1796+
if (auto *MMI = dyn_cast<MinMaxIntrinsic>(Op);
1797+
MMI && MMI->getLHS() == V && match(MMI->getRHS(), m_APInt(OpC))) {
1798+
ConstantRange R = ConstantRange::intrinsic(MMI->getIntrinsicID(),
1799+
{InvDomCR, ConstantRange(*OpC)});
1800+
if (R == *C) {
1801+
MMI->dropPoisonGeneratingAnnotations();
1802+
return MMI;
1803+
}
17931804
}
1805+
17941806
return nullptr;
17951807
}
17961808

llvm/test/Transforms/InstCombine/select-min-max.ll

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,66 @@ define i8 @not_smin_swap(i8 %i41, i8 %i43) {
301301
%spec.select = select i1 %i44, i8 %i46, i8 0
302302
ret i8 %spec.select
303303
}
304+
305+
define i8 @sel_umin_constant(i8 %x) {
306+
; CHECK-LABEL: @sel_umin_constant(
307+
; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 16)
308+
; CHECK-NEXT: ret i8 [[UMIN]]
309+
;
310+
%cmp = icmp sgt i8 %x, -1
311+
%umin = call i8 @llvm.umin.i8(i8 %x, i8 16)
312+
%sel = select i1 %cmp, i8 %umin, i8 16
313+
ret i8 %sel
314+
}
315+
316+
define i8 @sel_constant_smax_with_range_attr(i8 %x) {
317+
; CHECK-LABEL: @sel_constant_smax_with_range_attr(
318+
; CHECK-NEXT: [[SEL:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 16)
319+
; CHECK-NEXT: ret i8 [[SEL]]
320+
;
321+
%cmp = icmp slt i8 %x, 0
322+
%smax = call range(i8 8, 16) i8 @llvm.smax.i8(i8 %x, i8 16)
323+
%sel = select i1 %cmp, i8 16, i8 %smax
324+
ret i8 %sel
325+
}
326+
327+
; Negative tests
328+
329+
define i8 @sel_umin_constant_mismatch(i8 %x) {
330+
; CHECK-LABEL: @sel_umin_constant_mismatch(
331+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
332+
; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 16)
333+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[UMIN]], i8 15
334+
; CHECK-NEXT: ret i8 [[SEL]]
335+
;
336+
%cmp = icmp sgt i8 %x, -1
337+
%umin = call i8 @llvm.umin.i8(i8 %x, i8 16)
338+
%sel = select i1 %cmp, i8 %umin, i8 15
339+
ret i8 %sel
340+
}
341+
342+
define i8 @sel_umin_constant_op_mismatch(i8 %x, i8 %y) {
343+
; CHECK-LABEL: @sel_umin_constant_op_mismatch(
344+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
345+
; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 16)
346+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[UMIN]], i8 16
347+
; CHECK-NEXT: ret i8 [[SEL]]
348+
;
349+
%cmp = icmp sgt i8 %x, -1
350+
%umin = call i8 @llvm.umin.i8(i8 %y, i8 16)
351+
%sel = select i1 %cmp, i8 %umin, i8 16
352+
ret i8 %sel
353+
}
354+
355+
define i8 @sel_umin_non_constant(i8 %x, i8 %y) {
356+
; CHECK-LABEL: @sel_umin_non_constant(
357+
; CHECK-NEXT: [[UMIN:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 16)
358+
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[X]], 0
359+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Y:%.*]], i8 [[UMIN]]
360+
; CHECK-NEXT: ret i8 [[SEL]]
361+
;
362+
%cmp = icmp sgt i8 %x, -1
363+
%umin = call i8 @llvm.umin.i8(i8 %x, i8 16)
364+
%sel = select i1 %cmp, i8 %umin, i8 %y
365+
ret i8 %sel
366+
}

0 commit comments

Comments
 (0)