Skip to content

Commit 107601e

Browse files
authored
[InstCombine] Allow min/max in constant BOp min/max folding (#142878)
Extend folding for `X Pred C2 ? X BOp C1 : C2 BOp C1` to `min/max(X, C2) BOp C1` to allow min and max as `BOp`. This ensures a constant clamping pattern is folded into a pair of min/max instructions. Here is a simplified example of a case where this folding is not occurring currently. int clampToU8(int v) { if (v < 0) return 0; if (v > 255) return 255; return v; } https://godbolt.org/z/78jhKPWbv Generic proof: https://alive2.llvm.org/ce/z/cdpLYy
1 parent bc7f1ea commit 107601e

File tree

2 files changed

+84
-14
lines changed

2 files changed

+84
-14
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,7 +1826,6 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
18261826
static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
18271827
Value *FalseVal,
18281828
IRBuilderBase &Builder) {
1829-
BinaryOperator *BOp;
18301829
Constant *C1, *C2, *C3;
18311830
Value *X;
18321831
CmpPredicate Predicate;
@@ -1842,30 +1841,48 @@ static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
18421841
Predicate = ICmpInst::getInversePredicate(Predicate);
18431842
}
18441843

1845-
if (!match(TrueVal, m_BinOp(BOp)) || !match(FalseVal, m_Constant(C3)))
1844+
if (!match(FalseVal, m_Constant(C3)) || !TrueVal->hasOneUse())
18461845
return nullptr;
18471846

1848-
unsigned Opcode = BOp->getOpcode();
1847+
bool IsIntrinsic;
1848+
unsigned Opcode;
1849+
if (BinaryOperator *BOp = dyn_cast<BinaryOperator>(TrueVal)) {
1850+
Opcode = BOp->getOpcode();
1851+
IsIntrinsic = false;
18491852

1850-
// This fold causes some regressions and is primarily intended for
1851-
// add and sub. So we early exit for div and rem to minimize the
1852-
// regressions.
1853-
if (Instruction::isIntDivRem(Opcode))
1854-
return nullptr;
1853+
// This fold causes some regressions and is primarily intended for
1854+
// add and sub. So we early exit for div and rem to minimize the
1855+
// regressions.
1856+
if (Instruction::isIntDivRem(Opcode))
1857+
return nullptr;
18551858

1856-
if (!match(BOp, m_OneUse(m_BinOp(m_Specific(X), m_Constant(C2)))))
1859+
if (!match(BOp, m_BinOp(m_Specific(X), m_Constant(C2))))
1860+
return nullptr;
1861+
1862+
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(TrueVal)) {
1863+
if (!match(II, m_MaxOrMin(m_Specific(X), m_Constant(C2))))
1864+
return nullptr;
1865+
Opcode = II->getIntrinsicID();
1866+
IsIntrinsic = true;
1867+
} else {
18571868
return nullptr;
1869+
}
18581870

18591871
Value *RHS;
18601872
SelectPatternFlavor SPF;
1861-
const DataLayout &DL = BOp->getDataLayout();
1873+
const DataLayout &DL = Cmp->getDataLayout();
18621874
auto Flipped = getFlippedStrictnessPredicateAndConstant(Predicate, C1);
18631875

1864-
if (C3 == ConstantFoldBinaryOpOperands(Opcode, C1, C2, DL)) {
1876+
auto FoldBinaryOpOrIntrinsic = [&](Constant *LHS, Constant *RHS) {
1877+
return IsIntrinsic ? ConstantFoldBinaryIntrinsic(Opcode, LHS, RHS,
1878+
LHS->getType(), nullptr)
1879+
: ConstantFoldBinaryOpOperands(Opcode, LHS, RHS, DL);
1880+
};
1881+
1882+
if (C3 == FoldBinaryOpOrIntrinsic(C1, C2)) {
18651883
SPF = getSelectPattern(Predicate).Flavor;
18661884
RHS = C1;
1867-
} else if (Flipped && C3 == ConstantFoldBinaryOpOperands(
1868-
Opcode, Flipped->second, C2, DL)) {
1885+
} else if (Flipped && C3 == FoldBinaryOpOrIntrinsic(Flipped->second, C2)) {
18691886
SPF = getSelectPattern(Flipped->first).Flavor;
18701887
RHS = Flipped->second;
18711888
} else {
@@ -1874,7 +1891,9 @@ static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
18741891

18751892
Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
18761893
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, X, RHS);
1877-
return Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2);
1894+
return IsIntrinsic ? Builder.CreateBinaryIntrinsic(Opcode, Intrinsic, C2)
1895+
: Builder.CreateBinOp(Instruction::BinaryOps(Opcode),
1896+
Intrinsic, C2);
18781897
}
18791898

18801899
/// Visit a SelectInst that has an ICmpInst as its first operand.

llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,54 @@ define i8 @sub_const_on_lhs_negative(i8 %x) {
399399
%s = select i1 %cmp, i8 %sub, i8 50
400400
ret i8 %s
401401
}
402+
403+
define i8 @smin_ugt(i8 %x) {
404+
; CHECK-LABEL: define i8 @smin_ugt(
405+
; CHECK-SAME: i8 [[X:%.*]]) {
406+
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 50)
407+
; CHECK-NEXT: ret i8 [[S]]
408+
;
409+
%smin = call i8 @llvm.smin.i8(i8 %x, i8 50)
410+
%cmp = icmp ugt i8 %x, 100
411+
%s = select i1 %cmp, i8 50, i8 %smin
412+
ret i8 %s
413+
}
414+
415+
define i8 @smax_ugt(i8 %x) {
416+
; CHECK-LABEL: define i8 @smax_ugt(
417+
; CHECK-SAME: i8 [[X:%.*]]) {
418+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100)
419+
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 50)
420+
; CHECK-NEXT: ret i8 [[S]]
421+
;
422+
%smax = call i8 @llvm.smax.i8(i8 %x, i8 50)
423+
%cmp = icmp ugt i8 %x, 100
424+
%s = select i1 %cmp, i8 100, i8 %smax
425+
ret i8 %s
426+
}
427+
428+
define i8 @umin_slt(i8 %x) {
429+
; CHECK-LABEL: define i8 @umin_slt(
430+
; CHECK-SAME: i8 [[X:%.*]]) {
431+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 0)
432+
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.umin.i8(i8 [[TMP1]], i8 100)
433+
; CHECK-NEXT: ret i8 [[S]]
434+
;
435+
%cmp = icmp slt i8 %x, 0
436+
%umin = tail call i8 @llvm.umin.i8(i8 %x, i8 100)
437+
%s = select i1 %cmp, i8 0, i8 %umin
438+
ret i8 %s
439+
}
440+
441+
define i8 @umax_sgt(i8 %x) {
442+
; CHECK-LABEL: define i8 @umax_sgt(
443+
; CHECK-SAME: i8 [[X:%.*]]) {
444+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
445+
; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.umax.i8(i8 [[TMP1]], i8 50)
446+
; CHECK-NEXT: ret i8 [[S]]
447+
;
448+
%cmp = icmp sgt i8 %x, 100
449+
%umax = tail call i8 @llvm.umax.i8(i8 %x, i8 50)
450+
%s = select i1 %cmp, i8 100, i8 %umax
451+
ret i8 %s
452+
}

0 commit comments

Comments
 (0)