Skip to content

Commit

Permalink
[InstCombine] add min/max intrinsics as freely invertible candidates
Browse files Browse the repository at this point in the history
In the optimized test, we are able to peak through the
min/max that has 2 min/max operands and invert them all:
https://alive2.llvm.org/ce/z/7gYMN5
  • Loading branch information
rotateright committed Aug 19, 2021
1 parent 610d3d5 commit eee0ded
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 8 deletions.
6 changes: 6 additions & 0 deletions llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
Expand Up @@ -259,6 +259,12 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
m_Not(PatternMatch::m_Value()))))
return WillInvertAllUses;

// Min/max may be in the form of intrinsics, so handle those identically
// to select patterns.
if (match(V, m_MaxOrMin(m_Not(PatternMatch::m_Value()),
m_Not(PatternMatch::m_Value()))))
return WillInvertAllUses;

return false;
}

Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Expand Up @@ -3577,9 +3577,13 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
// ~max(~X, Y) --> min(X, ~Y)
auto *II = dyn_cast<IntrinsicInst>(Op0);
if (II && II->hasOneUse() && match(Op1, m_AllOnes())) {
if (match(Op0, m_MaxOrMin(m_Not(m_Value(X)), m_Not(m_Value(Y))))) {
if (match(Op0, m_MaxOrMin(m_Value(X), m_Value(Y))) &&
isFreeToInvert(X, X->hasOneUse()) &&
isFreeToInvert(Y, Y->hasOneUse())) {
Intrinsic::ID InvID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y);
Value *NotX = Builder.CreateNot(X);
Value *NotY = Builder.CreateNot(Y);
Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, NotX, NotY);
return replaceInstUsesWith(I, InvMaxMin);
}
if (match(Op0, m_c_MaxOrMin(m_Not(m_Value(X)), m_Value(Y)))) {
Expand Down
11 changes: 5 additions & 6 deletions llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
Expand Up @@ -1158,7 +1158,7 @@ define i8 @freeToInvert(i8 %x, i8 %y, i8 %z) {
; CHECK-NEXT: call void @use(i8 [[NY]])
; CHECK-NEXT: call void @use(i8 [[NZ]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[TMP1]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[TMP2]]
;
%nx = xor i8 %x, -1
Expand Down Expand Up @@ -1266,11 +1266,10 @@ define i8 @freeToInvert_two_minmax_ops(i8 %x, i8 %y, i8 %z, i8 %w) {
; CHECK-NEXT: call void @use(i8 [[NY]])
; CHECK-NEXT: call void @use(i8 [[NZ]])
; CHECK-NEXT: call void @use(i8 [[NW]])
; CHECK-NEXT: [[M1:%.*]] = call i8 @llvm.umax.i8(i8 [[NX]], i8 [[NY]])
; CHECK-NEXT: [[M2:%.*]] = call i8 @llvm.smax.i8(i8 [[NW]], i8 [[NZ]])
; CHECK-NEXT: [[M3:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 [[M2]])
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[M3]], -1
; CHECK-NEXT: ret i8 [[NOT]]
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smin.i8(i8 [[W]], i8 [[Z]])
; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[TMP2]])
; CHECK-NEXT: ret i8 [[TMP3]]
;
%nx = xor i8 %x, -1
%ny = xor i8 %y, -1
Expand Down

0 comments on commit eee0ded

Please sign in to comment.