Skip to content

Commit

Permalink
[InstCombine] hoist min/max intrinsics above select with constant op
Browse files Browse the repository at this point in the history
This is an extension of the handling for unary intrinsics and
follows the logic that we use for binary ops.

We don't canonicalize to min/max intrinsics yet, but this might
help unlock other folds seen in D98152.
  • Loading branch information
rotateright committed Jun 27, 2021
1 parent 81fcdae commit 153da08
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 23 deletions.
5 changes: 5 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Expand Up @@ -1041,6 +1041,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *Sel = foldClampRangeOfTwo(II, Builder))
return Sel;

if (match(I1, m_ImmConstant()))
if (auto *Sel = dyn_cast<SelectInst>(I0))
if (Instruction *R = FoldOpIntoSelect(*II, Sel))
return R;

break;
}
case Intrinsic::bswap: {
Expand Down
17 changes: 10 additions & 7 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Expand Up @@ -942,13 +942,16 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO,
assert(canConstantFoldCallTo(II, cast<Function>(II->getCalledOperand())) &&
"Expected constant-foldable intrinsic");
Intrinsic::ID IID = II->getIntrinsicID();
SmallVector<Value *, 2> Args = {SO};

// Propagate the zero-is-undef argument to the new instruction.
if (IID == Intrinsic::ctlz || IID == Intrinsic::cttz)
Args.push_back(II->getArgOperand(1));

return Builder.CreateIntrinsic(IID, I.getType(), Args);
if (II->getNumArgOperands() == 1)
return Builder.CreateUnaryIntrinsic(IID, SO);

// This works for real binary ops like min/max (where we always expect the
// constant operand to be canonicalized as op1) and unary ops with a bonus
// constant argument like ctlz/cttz.
// TODO: Handle non-commutative binary intrinsics as below for binops.
assert(II->getNumArgOperands() == 2 && "Expected binary intrinsic");
assert(isa<Constant>(II->getArgOperand(1)) && "Expected constant operand");
return Builder.CreateBinaryIntrinsic(IID, SO, II->getArgOperand(1));
}

assert(I.isBinaryOp() && "Unexpected opcode for select folding");
Expand Down
28 changes: 12 additions & 16 deletions llvm/test/Transforms/InstCombine/select-min-max.ll
Expand Up @@ -111,8 +111,7 @@ define i5 @umin_umin_common_op_10_uses(i1 %cond, i5 %x, i5 %y, i5 %z, i5* %p1, i

define i5 @smin_select_const_const(i1 %b) {
; CHECK-LABEL: @smin_select_const_const(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i5 -3, i5 8
; CHECK-NEXT: [[C:%.*]] = call i5 @llvm.smin.i5(i5 [[S]], i5 5)
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i5 -3, i5 5
; CHECK-NEXT: ret i5 [[C]]
;
%s = select i1 %b, i5 -3, i5 8
Expand All @@ -122,8 +121,7 @@ define i5 @smin_select_const_const(i1 %b) {

define <2 x i8> @smax_select_const_const(<2 x i1> %b) {
; CHECK-LABEL: @smax_select_const_const(
; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> <i8 1, i8 3>, <2 x i8> <i8 5, i8 43>
; CHECK-NEXT: [[C:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[S]], <2 x i8> <i8 0, i8 42>)
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> <i8 1, i8 42>, <2 x i8> <i8 5, i8 43>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%s = select <2 x i1> %b, <2 x i8> <i8 1, i8 3>, <2 x i8> <i8 5, i8 43>
Expand All @@ -133,8 +131,7 @@ define <2 x i8> @smax_select_const_const(<2 x i1> %b) {

define i5 @umin_select_const_const(i1 %b) {
; CHECK-LABEL: @umin_select_const_const(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i5 8, i5 3
; CHECK-NEXT: [[C:%.*]] = call i5 @llvm.umin.i5(i5 [[S]], i5 4)
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i5 4, i5 3
; CHECK-NEXT: ret i5 [[C]]
;
%s = select i1 %b, i5 8, i5 3
Expand All @@ -144,8 +141,7 @@ define i5 @umin_select_const_const(i1 %b) {

define <3 x i5> @umax_select_const_const(<3 x i1> %b) {
; CHECK-LABEL: @umax_select_const_const(
; CHECK-NEXT: [[S:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> <i5 2, i5 3, i5 4>, <3 x i5> <i5 7, i5 8, i5 9>
; CHECK-NEXT: [[C:%.*]] = call <3 x i5> @llvm.umax.v3i5(<3 x i5> [[S]], <3 x i5> <i5 5, i5 8, i5 -16>)
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> <i5 5, i5 8, i5 -16>, <3 x i5> <i5 7, i5 8, i5 -16>
; CHECK-NEXT: ret <3 x i5> [[C]]
;
%s = select <3 x i1> %b, <3 x i5> <i5 2, i5 3, i5 4>, <3 x i5> <i5 7, i5 8, i5 9>
Expand All @@ -155,8 +151,8 @@ define <3 x i5> @umax_select_const_const(<3 x i1> %b) {

define i5 @smin_select_const(i1 %b, i5 %x) {
; CHECK-LABEL: @smin_select_const(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i5 -3, i5 [[X:%.*]]
; CHECK-NEXT: [[C:%.*]] = call i5 @llvm.smin.i5(i5 [[S]], i5 5)
; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smin.i5(i5 [[X:%.*]], i5 5)
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i5 -3, i5 [[TMP1]]
; CHECK-NEXT: ret i5 [[C]]
;
%s = select i1 %b, i5 -3, i5 %x
Expand All @@ -166,8 +162,8 @@ define i5 @smin_select_const(i1 %b, i5 %x) {

define <2 x i8> @smax_select_const(<2 x i1> %b, <2 x i8> %x) {
; CHECK-LABEL: @smax_select_const(
; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> [[X:%.*]], <2 x i8> <i8 5, i8 43>
; CHECK-NEXT: [[C:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[S]], <2 x i8> <i8 0, i8 42>)
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 0, i8 42>)
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> [[TMP1]], <2 x i8> <i8 5, i8 43>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%s = select <2 x i1> %b, <2 x i8> %x, <2 x i8> <i8 5, i8 43>
Expand All @@ -177,8 +173,8 @@ define <2 x i8> @smax_select_const(<2 x i1> %b, <2 x i8> %x) {

define i5 @umin_select_const(i1 %b, i5 %x) {
; CHECK-LABEL: @umin_select_const(
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i5 [[X:%.*]], i5 3
; CHECK-NEXT: [[C:%.*]] = call i5 @llvm.umin.i5(i5 [[S]], i5 4)
; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umin.i5(i5 [[X:%.*]], i5 4)
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i5 [[TMP1]], i5 3
; CHECK-NEXT: ret i5 [[C]]
;
%s = select i1 %b, i5 %x, i5 3
Expand All @@ -188,8 +184,8 @@ define i5 @umin_select_const(i1 %b, i5 %x) {

define <3 x i5> @umax_select_const(<3 x i1> %b, <3 x i5> %x) {
; CHECK-LABEL: @umax_select_const(
; CHECK-NEXT: [[S:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> <i5 2, i5 3, i5 4>, <3 x i5> [[X:%.*]]
; CHECK-NEXT: [[C:%.*]] = call <3 x i5> @llvm.umax.v3i5(<3 x i5> [[S]], <3 x i5> <i5 5, i5 8, i5 1>)
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.umax.v3i5(<3 x i5> [[X:%.*]], <3 x i5> <i5 5, i5 8, i5 1>)
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> <i5 5, i5 8, i5 4>, <3 x i5> [[TMP1]]
; CHECK-NEXT: ret <3 x i5> [[C]]
;
%s = select <3 x i1> %b, <3 x i5> <i5 2, i5 3, i5 4>, <3 x i5> %x
Expand Down

0 comments on commit 153da08

Please sign in to comment.