diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h index ba0d41f9b74890..3f13df7b76b4b6 100644 --- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h +++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h @@ -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; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 46d8748854572c..5c05bc57a0cf52 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3577,9 +3577,13 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // ~max(~X, Y) --> min(X, ~Y) auto *II = dyn_cast(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)))) { diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll index 09e0545f107e0e..7816d5d6a32eea 100644 --- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll +++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll @@ -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 @@ -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