[llvm] 09a136b - [InstCombine] narrow min/max intrinsics with extended inputs
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 25 04:58:31 PST 2021
Author: Sanjay Patel
Date: 2021-01-25T07:52:50-05:00
New Revision: 09a136bcc6947128df86492d88f1733bdff745d1
URL: https://github.com/llvm/llvm-project/commit/09a136bcc6947128df86492d88f1733bdff745d1
DIFF: https://github.com/llvm/llvm-project/commit/09a136bcc6947128df86492d88f1733bdff745d1.diff
LOG: [InstCombine] narrow min/max intrinsics with extended inputs
We can sink extends after min/max if they match and would
not change the sign-interpreted compare. The only combo
that doesn't work is zext+smin/smax because the zexts
could change a negative number into positive:
https://alive2.llvm.org/ce/z/D6sz6J
Sext+umax/umin works:
define i32 @src(i8 %x, i8 %y) {
%0:
%sx = sext i8 %x to i32
%sy = sext i8 %y to i32
%m = umax i32 %sx, %sy
ret i32 %m
}
=>
define i32 @tgt(i8 %x, i8 %y) {
%0:
%m = umax i8 %x, %y
%r = sext i8 %m to i32
ret i32 %r
}
Transformation seems to be correct!
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 5ba51d255109..0b4246feecee 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -830,6 +830,30 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
break;
}
+ case Intrinsic::umax:
+ case Intrinsic::umin: {
+ Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1);
+ Value *X, *Y;
+ if (match(I0, m_ZExt(m_Value(X))) && match(I1, m_ZExt(m_Value(Y))) &&
+ (I0->hasOneUse() || I1->hasOneUse()) && X->getType() == Y->getType()) {
+ Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, Y);
+ return CastInst::Create(Instruction::ZExt, NarrowMaxMin, II->getType());
+ }
+ // If both operands of unsigned min/max are sign-extended, it is still ok
+ // to narrow the operation.
+ LLVM_FALLTHROUGH;
+ }
+ case Intrinsic::smax:
+ case Intrinsic::smin: {
+ Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1);
+ Value *X, *Y;
+ if (match(I0, m_SExt(m_Value(X))) && match(I1, m_SExt(m_Value(Y))) &&
+ (I0->hasOneUse() || I1->hasOneUse()) && X->getType() == Y->getType()) {
+ Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, Y);
+ return CastInst::Create(Instruction::SExt, NarrowMaxMin, II->getType());
+ }
+ break;
+ }
case Intrinsic::bswap: {
Value *IIOperand = II->getArgOperand(0);
Value *X = nullptr;
diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
index bccfac81bdce..97ed799f32a8 100644
--- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
@@ -50,9 +50,8 @@ define i8 @smax_known_bits(i8 %x, i8 %y) {
define i8 @smax_sext(i5 %x, i5 %y) {
; CHECK-LABEL: @smax_sext(
-; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8
-; CHECK-NEXT: [[SY:%.*]] = sext i5 [[Y:%.*]] to i8
-; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[SX]], i8 [[SY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smax.i5(i5 [[X:%.*]], i5 [[Y:%.*]])
+; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8
; CHECK-NEXT: ret i8 [[M]]
;
%sx = sext i5 %x to i8
@@ -61,12 +60,14 @@ define i8 @smax_sext(i5 %x, i5 %y) {
ret i8 %m
}
+; Extra use is ok.
+
define i8 @smin_sext(i5 %x, i5 %y) {
; CHECK-LABEL: @smin_sext(
-; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8
; CHECK-NEXT: [[SY:%.*]] = sext i5 [[Y:%.*]] to i8
; CHECK-NEXT: call void @use(i8 [[SY]])
-; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[SX]], i8 [[SY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.smin.i5(i5 [[X:%.*]], i5 [[Y]])
+; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8
; CHECK-NEXT: ret i8 [[M]]
;
%sx = sext i5 %x to i8
@@ -76,12 +77,14 @@ define i8 @smin_sext(i5 %x, i5 %y) {
ret i8 %m
}
+; Sext doesn't change unsigned min/max comparison of narrow values.
+
define i8 @umax_sext(i5 %x, i5 %y) {
; CHECK-LABEL: @umax_sext(
; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8
; CHECK-NEXT: call void @use(i8 [[SX]])
-; CHECK-NEXT: [[SY:%.*]] = sext i5 [[Y:%.*]] to i8
-; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[SX]], i8 [[SY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umax.i5(i5 [[X]], i5 [[Y:%.*]])
+; CHECK-NEXT: [[M:%.*]] = sext i5 [[TMP1]] to i8
; CHECK-NEXT: ret i8 [[M]]
;
%sx = sext i5 %x to i8
@@ -93,9 +96,8 @@ define i8 @umax_sext(i5 %x, i5 %y) {
define <3 x i8> @umin_sext(<3 x i5> %x, <3 x i5> %y) {
; CHECK-LABEL: @umin_sext(
-; CHECK-NEXT: [[SX:%.*]] = sext <3 x i5> [[X:%.*]] to <3 x i8>
-; CHECK-NEXT: [[SY:%.*]] = sext <3 x i5> [[Y:%.*]] to <3 x i8>
-; CHECK-NEXT: [[M:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[SX]], <3 x i8> [[SY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.umin.v3i5(<3 x i5> [[X:%.*]], <3 x i5> [[Y:%.*]])
+; CHECK-NEXT: [[M:%.*]] = sext <3 x i5> [[TMP1]] to <3 x i8>
; CHECK-NEXT: ret <3 x i8> [[M]]
;
%sx = sext <3 x i5> %x to <3 x i8>
@@ -104,6 +106,8 @@ define <3 x i8> @umin_sext(<3 x i5> %x, <3 x i5> %y) {
ret <3 x i8> %m
}
+; Negative test - zext may change sign of inputs
+
define i8 @smax_zext(i5 %x, i5 %y) {
; CHECK-LABEL: @smax_zext(
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
@@ -117,6 +121,8 @@ define i8 @smax_zext(i5 %x, i5 %y) {
ret i8 %m
}
+; Negative test - zext may change sign of inputs
+
define i8 @smin_zext(i5 %x, i5 %y) {
; CHECK-LABEL: @smin_zext(
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
@@ -132,9 +138,8 @@ define i8 @smin_zext(i5 %x, i5 %y) {
define i8 @umax_zext(i5 %x, i5 %y) {
; CHECK-LABEL: @umax_zext(
-; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
-; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8
-; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[ZX]], i8 [[ZY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umax.i5(i5 [[X:%.*]], i5 [[Y:%.*]])
+; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8
; CHECK-NEXT: ret i8 [[M]]
;
%zx = zext i5 %x to i8
@@ -145,9 +150,8 @@ define i8 @umax_zext(i5 %x, i5 %y) {
define i8 @umin_zext(i5 %x, i5 %y) {
; CHECK-LABEL: @umin_zext(
-; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
-; CHECK-NEXT: [[ZY:%.*]] = zext i5 [[Y:%.*]] to i8
-; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[ZX]], i8 [[ZY]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i5 @llvm.umin.i5(i5 [[X:%.*]], i5 [[Y:%.*]])
+; CHECK-NEXT: [[M:%.*]] = zext i5 [[TMP1]] to i8
; CHECK-NEXT: ret i8 [[M]]
;
%zx = zext i5 %x to i8
@@ -156,6 +160,8 @@ define i8 @umin_zext(i5 %x, i5 %y) {
ret i8 %m
}
+; Negative test - mismatched types
+
define i8 @umin_zext_types(i6 %x, i5 %y) {
; CHECK-LABEL: @umin_zext_types(
; CHECK-NEXT: [[ZX:%.*]] = zext i6 [[X:%.*]] to i8
@@ -169,6 +175,8 @@ define i8 @umin_zext_types(i6 %x, i5 %y) {
ret i8 %m
}
+; Negative test - mismatched extends
+
define i8 @umin_ext(i5 %x, i5 %y) {
; CHECK-LABEL: @umin_ext(
; CHECK-NEXT: [[SX:%.*]] = sext i5 [[X:%.*]] to i8
@@ -182,6 +190,8 @@ define i8 @umin_ext(i5 %x, i5 %y) {
ret i8 %m
}
+; Negative test - too many uses.
+
define i8 @umin_zext_uses(i5 %x, i5 %y) {
; CHECK-LABEL: @umin_zext_uses(
; CHECK-NEXT: [[ZX:%.*]] = zext i5 [[X:%.*]] to i8
More information about the llvm-commits
mailing list