Skip to content

Commit

Permalink
[InstCombine] reassociate min/max intrinsics with constant operands
Browse files Browse the repository at this point in the history
Integer min/max operations are associative:
  max (max X, C0), C1 --> max X, (max C0, C1) --> max X, NewC

https://alive2.llvm.org/ce/z/wW5HVM

This would avoid a regression when we canonicalize to min/max intrinsics
(see D98152 ).

Differential Revision: https://reviews.llvm.org/D119754
  • Loading branch information
rotateright committed Feb 15, 2022
1 parent 1cd6454 commit 6357ccf
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
26 changes: 26 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Expand Up @@ -879,6 +879,29 @@ static Instruction *foldClampRangeOfTwo(IntrinsicInst *II,
return SelectInst::Create(Cmp, ConstantInt::get(II->getType(), *C0), I1);
}

/// If this min/max has a constant operand and an operand that is a matching
/// min/max with a constant operand, constant-fold the 2 constant operands.
static Instruction *reassociateMinMaxWithConstants(IntrinsicInst *II) {
Intrinsic::ID MinMaxID = II->getIntrinsicID();
auto *LHS = dyn_cast<IntrinsicInst>(II->getArgOperand(0));
if (!LHS || LHS->getIntrinsicID() != MinMaxID)
return nullptr;

Constant *C0, *C1;
if (!match(LHS->getArgOperand(1), m_ImmConstant(C0)) ||
!match(II->getArgOperand(1), m_ImmConstant(C1)))
return nullptr;

// max (max X, C0), C1 --> max X, (max C0, C1) --> max X, NewC
ICmpInst::Predicate Pred = MinMaxIntrinsic::getPredicate(MinMaxID);
Constant *CondC = ConstantExpr::getICmp(Pred, C0, C1);
Constant *NewC = ConstantExpr::getSelect(CondC, C0, C1);

Module *Mod = II->getModule();
Function *MinMax = Intrinsic::getDeclaration(Mod, MinMaxID, II->getType());
return CallInst::Create(MinMax, {LHS->getArgOperand(0), NewC});
}

/// Reduce a sequence of min/max intrinsics with a common operand.
static Instruction *factorizeMinMaxTree(IntrinsicInst *II) {
// Match 3 of the same min/max ops. Example: umin(umin(), umin()).
Expand Down Expand Up @@ -1224,6 +1247,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *R = FoldOpIntoSelect(*II, Sel))
return R;

if (Instruction *NewMinMax = reassociateMinMaxWithConstants(II))
return NewMinMax;

if (Instruction *NewMinMax = factorizeMinMaxTree(II))
return NewMinMax;

Expand Down
15 changes: 8 additions & 7 deletions llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
Expand Up @@ -2144,8 +2144,7 @@ define i8 @smax_offset_simplify(i8 %x) {

define <3 x i8> @smax_smax_reassoc_constants(<3 x i8> %x) {
; CHECK-LABEL: @smax_smax_reassoc_constants(
; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 42, i8 43, i8 44>)
; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>)
; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 43, i8 44>)
; CHECK-NEXT: ret <3 x i8> [[M2]]
;
%m1 = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>)
Expand All @@ -2155,8 +2154,7 @@ define <3 x i8> @smax_smax_reassoc_constants(<3 x i8> %x) {

define i8 @smin_smin_reassoc_constants(i8 %x) {
; CHECK-LABEL: @smin_smin_reassoc_constants(
; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97)
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 -3)
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 -3)
; CHECK-NEXT: ret i8 [[M2]]
;
%m1 = call i8 @llvm.smin.i8(i8 %x, i8 97)
Expand All @@ -2166,20 +2164,21 @@ define i8 @smin_smin_reassoc_constants(i8 %x) {

define <3 x i8> @umax_umax_reassoc_constants(<3 x i8> %x) {
; CHECK-LABEL: @umax_umax_reassoc_constants(
; CHECK-NEXT: [[M1:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 42, i8 43, i8 44>)
; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -113, i8 poison>)
; CHECK-NEXT: [[M2:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 -113, i8 poison>)
; CHECK-NEXT: ret <3 x i8> [[M2]]
;
%m1 = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>)
%m2 = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %m1, <3 x i8> <i8 43, i8 143, i8 poison>)
ret <3 x i8> %m2
}

; extra use is ok

define i8 @umin_umin_reassoc_constants(i8 %x) {
; CHECK-LABEL: @umin_umin_reassoc_constants(
; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 -116)
; CHECK-NEXT: call void @use(i8 [[M1]])
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[M1]], i8 42)
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-NEXT: ret i8 [[M2]]
;
%m1 = call i8 @llvm.umin.i8(i8 140, i8 %x)
Expand All @@ -2188,6 +2187,8 @@ define i8 @umin_umin_reassoc_constants(i8 %x) {
ret i8 %m2
}

; negative test - must have matching intrinsics

define i8 @smin_smax_reassoc_constants(i8 %x) {
; CHECK-LABEL: @smin_smax_reassoc_constants(
; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97)
Expand Down

0 comments on commit 6357ccf

Please sign in to comment.