[llvm] [InstCombine] Factorise add/sub and max/min using distributivity (PR #101507)
Jorge Botto via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 1 11:49:53 PDT 2024
https://github.com/jf-botto updated https://github.com/llvm/llvm-project/pull/101507
>From 0448916556f9490f887473531a628495b6464f44 Mon Sep 17 00:00:00 2001
From: Jorge Botto <jorge.botto.16 at ucl.ac.uk>
Date: Thu, 1 Aug 2024 18:42:53 +0100
Subject: [PATCH 1/2] Precommit test
---
.../InstCombine/intrinsic-distributive.ll | 226 ++++++++++++++++++
1 file changed, 226 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
new file mode 100644
index 0000000000000..b09a7e21ca97d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
@@ -0,0 +1,226 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s 2>&1 | FileCheck %s
+
+define i8 @umin_of_umax(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umin_of_umax(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %max1 = call i8 @llvm.umax.i8(i8 %x, i8 %z)
+ %max2 = call i8 @llvm.umax.i8(i8 %y, i8 %z)
+ %min = call i8 @llvm.umin.i8(i8 %max1, i8 %max2)
+ ret i8 %min
+}
+
+define i8 @umin_of_umax_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umin_of_umax_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.umax.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.umax.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %max1 = call i8 @llvm.umax.i8(i8 %z, i8 %x)
+ %max2 = call i8 @llvm.umax.i8(i8 %z, i8 %y)
+ %min = call i8 @llvm.umin.i8(i8 %max1, i8 %max2)
+ ret i8 %min
+}
+
+define i8 @smin_of_smax(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smin_of_smax(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %max1 = call i8 @llvm.smax.i8(i8 %x, i8 %z)
+ %max2 = call i8 @llvm.smax.i8(i8 %y, i8 %z)
+ %min = call i8 @llvm.smin.i8(i8 %max1, i8 %max2)
+ ret i8 %min
+}
+
+define i8 @smin_of_smax_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smin_of_smax_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %max1 = call i8 @llvm.smax.i8(i8 %z, i8 %x)
+ %max2 = call i8 @llvm.smax.i8(i8 %z, i8 %y)
+ %min = call i8 @llvm.smin.i8(i8 %max1, i8 %max2)
+ ret i8 %min
+}
+
+define i8 @umax_of_umin(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umax_of_umin(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %min1 = call i8 @llvm.umin.i8(i8 %x, i8 %z)
+ %min2 = call i8 @llvm.umin.i8(i8 %y, i8 %z)
+ %max = call i8 @llvm.umax.i8(i8 %min1, i8 %min2)
+ ret i8 %max
+}
+
+define i8 @umax_of_umin_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umax_of_umin_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.umin.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.umin.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %min1 = call i8 @llvm.umin.i8(i8 %z, i8 %x)
+ %min2 = call i8 @llvm.umin.i8(i8 %z, i8 %y)
+ %max = call i8 @llvm.umax.i8(i8 %min1, i8 %min2)
+ ret i8 %max
+}
+
+define i8 @smax_of_smin(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smax_of_smin(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.smin.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %min1 = call i8 @llvm.smin.i8(i8 %x, i8 %z)
+ %min2 = call i8 @llvm.smin.i8(i8 %y, i8 %z)
+ %max = call i8 @llvm.smax.i8(i8 %min1, i8 %min2)
+ ret i8 %max
+}
+
+define i8 @smax_of_smin_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smax_of_smin_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.smin.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.smin.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %min1 = call i8 @llvm.smin.i8(i8 %z, i8 %x)
+ %min2 = call i8 @llvm.smin.i8(i8 %z, i8 %y)
+ %max = call i8 @llvm.smax.i8(i8 %min1, i8 %min2)
+ ret i8 %max
+}
+
+define i8 @umax_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umax_of_uadd_sat(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %add1 = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %z)
+ %add2 = call i8 @llvm.uadd.sat.i8(i8 %y, i8 %z)
+ %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2)
+ ret i8 %max
+}
+
+define i8 @umax_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umax_of_uadd_sat_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %add1 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %x)
+ %add2 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %y)
+ %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2)
+ ret i8 %max
+}
+
+define i8 @umin_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umin_of_uadd_sat(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %add1 = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %z)
+ %add2 = call i8 @llvm.uadd.sat.i8(i8 %y, i8 %z)
+ %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2)
+ ret i8 %min
+}
+
+define i8 @umin_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @umin_of_uadd_sat_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %add1 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %x)
+ %add2 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %y)
+ %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2)
+ ret i8 %min
+}
+
+define i8 @smax_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smax_of_sadd_sat(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %add1 = call i8 @llvm.sadd.sat.i8(i8 %x, i8 %z)
+ %add2 = call i8 @llvm.sadd.sat.i8(i8 %y, i8 %z)
+ %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2)
+ ret i8 %max
+}
+
+define i8 @smax_of_sadd_sat_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smax_of_sadd_sat_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MAX]]
+;
+ %add1 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %x)
+ %add2 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %y)
+ %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2)
+ ret i8 %max
+}
+
+define i8 @smin_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smin_of_sadd_sat(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X]], i8 [[Z]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Y]], i8 [[Z]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %add1 = call i8 @llvm.sadd.sat.i8(i8 %x, i8 %z)
+ %add2 = call i8 @llvm.sadd.sat.i8(i8 %y, i8 %z)
+ %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2)
+ ret i8 %min
+}
+
+define i8 @smin_of_sadd_sat_comm(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: define i8 @smin_of_sadd_sat_comm(
+; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[X]])
+; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: ret i8 [[MIN]]
+;
+ %add1 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %x)
+ %add2 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %y)
+ %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2)
+ ret i8 %min
+}
>From 4780a3920ea470dd019eebeb7796de7e0003dc17 Mon Sep 17 00:00:00 2001
From: Jorge Botto <jorge.botto.16 at ucl.ac.uk>
Date: Thu, 1 Aug 2024 19:39:10 +0100
Subject: [PATCH 2/2] Adding missed optimisation
---
.../InstCombine/InstCombineCalls.cpp | 75 +++++++++++++++++
.../InstCombine/intrinsic-distributive.ll | 80 ++++++++-----------
2 files changed, 107 insertions(+), 48 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index cc68fd4cf1c1b..fba2583405869 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1505,6 +1505,78 @@ foldMinimumOverTrailingOrLeadingZeroCount(Value *I0, Value *I1,
ConstantInt::getTrue(ZeroUndef->getType()));
}
+/// Return whether "X LOp (Y ROp Z)" is always equal to
+/// "(X LOp Y) ROp (X LOp Z)".
+static bool leftDistributesOverRightIntrinsic(Intrinsic::ID LOp,
+ Intrinsic::ID ROp) {
+ switch (LOp) {
+ case Intrinsic::umax:
+ return ROp == Intrinsic::umin;
+ case Intrinsic::smax:
+ return ROp == Intrinsic::smin;
+ case Intrinsic::umin:
+ return ROp == Intrinsic::umax;
+ case Intrinsic::smin:
+ return ROp == Intrinsic::smax;
+ case Intrinsic::uadd_sat:
+ return ROp == Intrinsic::umax || ROp == Intrinsic::umin;
+ case Intrinsic::sadd_sat:
+ return ROp == Intrinsic::smax || ROp == Intrinsic::smin;
+ default:
+ return false;
+ }
+}
+
+// Attempts to factorise a common term
+// in an instruction that has the form "(A op' B) op (C op' D)
+static Value *
+foldIntrinsicUsingDistributiveLaws(IntrinsicInst *II,
+ InstCombiner::BuilderTy &Builder) {
+ Value *LHS = II->getOperand(0), *RHS = II->getOperand(1);
+ Intrinsic::ID TopLevelOpcode = II->getIntrinsicID();
+
+ if (LHS && RHS) {
+ IntrinsicInst *Op0 = dyn_cast<IntrinsicInst>(LHS);
+ IntrinsicInst *Op1 = dyn_cast<IntrinsicInst>(RHS);
+
+ if (!Op0 || !Op1)
+ return nullptr;
+
+ if (Op0->getIntrinsicID() != Op1->getIntrinsicID())
+ return nullptr;
+
+ Intrinsic::ID InnerOpcode = Op0->getIntrinsicID();
+
+ if (!leftDistributesOverRightIntrinsic(InnerOpcode, TopLevelOpcode))
+ return nullptr;
+
+ assert(II->isCommutative() && Op0->isCommutative() &&
+ "Only inner and outer commutative op codes are supported.");
+
+ Value *A = Op0->getOperand(0);
+ Value *B = Op0->getOperand(1);
+ Value *C = Op1->getOperand(0);
+ Value *D = Op1->getOperand(1);
+
+ if (A == C || A == D) {
+ if (A != C)
+ std::swap(C, D);
+
+ Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, B, D);
+ return Builder.CreateBinaryIntrinsic(InnerOpcode, NewIntrinsic, A);
+ }
+
+ if (B == D || B == C) {
+ if (B != D)
+ std::swap(C, D);
+
+ Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, A, C);
+ return Builder.CreateBinaryIntrinsic(InnerOpcode, NewIntrinsic, B);
+ }
+ }
+ return nullptr;
+}
+
/// CallInst simplification. This mostly only handles folding of intrinsic
/// instructions. For normal calls, it allows visitCallBase to do the heavy
/// lifting.
@@ -1929,6 +2001,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
}
+ if (Value *V = foldIntrinsicUsingDistributiveLaws(II, Builder))
+ return replaceInstUsesWith(*II, V);
+
break;
}
case Intrinsic::bitreverse: {
diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
index b09a7e21ca97d..8c8ee8c3e5fa8 100644
--- a/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
+++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll
@@ -4,9 +4,8 @@
define i8 @umin_of_umax(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umin_of_umax(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umax.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%max1 = call i8 @llvm.umax.i8(i8 %x, i8 %z)
@@ -18,9 +17,8 @@ define i8 @umin_of_umax(i8 %x, i8 %y, i8 %z) {
define i8 @umin_of_umax_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umin_of_umax_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.umax.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.umax.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umax.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%max1 = call i8 @llvm.umax.i8(i8 %z, i8 %x)
@@ -32,9 +30,8 @@ define i8 @umin_of_umax_comm(i8 %x, i8 %y, i8 %z) {
define i8 @smin_of_smax(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smin_of_smax(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%max1 = call i8 @llvm.smax.i8(i8 %x, i8 %z)
@@ -46,9 +43,8 @@ define i8 @smin_of_smax(i8 %x, i8 %y, i8 %z) {
define i8 @smin_of_smax_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smin_of_smax_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MAX1:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[MAX2:%.*]] = call i8 @llvm.smax.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[MAX1]], i8 [[MAX2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smax.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%max1 = call i8 @llvm.smax.i8(i8 %z, i8 %x)
@@ -60,9 +56,8 @@ define i8 @smin_of_smax_comm(i8 %x, i8 %y, i8 %z) {
define i8 @umax_of_umin(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umax_of_umin(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.umin.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umin.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%min1 = call i8 @llvm.umin.i8(i8 %x, i8 %z)
@@ -74,9 +69,8 @@ define i8 @umax_of_umin(i8 %x, i8 %y, i8 %z) {
define i8 @umax_of_umin_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umax_of_umin_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.umin.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.umin.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umin.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%min1 = call i8 @llvm.umin.i8(i8 %z, i8 %x)
@@ -88,9 +82,8 @@ define i8 @umax_of_umin_comm(i8 %x, i8 %y, i8 %z) {
define i8 @smax_of_smin(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smax_of_smin(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.smin.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%min1 = call i8 @llvm.smin.i8(i8 %x, i8 %z)
@@ -102,9 +95,8 @@ define i8 @smax_of_smin(i8 %x, i8 %y, i8 %z) {
define i8 @smax_of_smin_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smax_of_smin_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[MIN1:%.*]] = call i8 @llvm.smin.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[MIN2:%.*]] = call i8 @llvm.smin.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[MIN1]], i8 [[MIN2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%min1 = call i8 @llvm.smin.i8(i8 %z, i8 %x)
@@ -116,9 +108,8 @@ define i8 @smax_of_smin_comm(i8 %x, i8 %y, i8 %z) {
define i8 @umax_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umax_of_uadd_sat(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%add1 = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %z)
@@ -130,9 +121,8 @@ define i8 @umax_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
define i8 @umax_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umax_of_uadd_sat_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%add1 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %x)
@@ -144,9 +134,8 @@ define i8 @umax_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
define i8 @umin_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umin_of_uadd_sat(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%add1 = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %z)
@@ -158,9 +147,8 @@ define i8 @umin_of_uadd_sat(i8 %x, i8 %y, i8 %z) {
define i8 @umin_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @umin_of_uadd_sat_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.umin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%add1 = call i8 @llvm.uadd.sat.i8(i8 %z, i8 %x)
@@ -172,9 +160,8 @@ define i8 @umin_of_uadd_sat_comm(i8 %x, i8 %y, i8 %z) {
define i8 @smax_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smax_of_sadd_sat(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%add1 = call i8 @llvm.sadd.sat.i8(i8 %x, i8 %z)
@@ -186,9 +173,8 @@ define i8 @smax_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
define i8 @smax_of_sadd_sat_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smax_of_sadd_sat_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MAX:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MAX]]
;
%add1 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %x)
@@ -200,9 +186,8 @@ define i8 @smax_of_sadd_sat_comm(i8 %x, i8 %y, i8 %z) {
define i8 @smin_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smin_of_sadd_sat(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[X]], i8 [[Z]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%add1 = call i8 @llvm.sadd.sat.i8(i8 %x, i8 %z)
@@ -214,9 +199,8 @@ define i8 @smin_of_sadd_sat(i8 %x, i8 %y, i8 %z) {
define i8 @smin_of_sadd_sat_comm(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: define i8 @smin_of_sadd_sat_comm(
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]], i8 [[Z:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[X]])
-; CHECK-NEXT: [[ADD2:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[Z]], i8 [[Y]])
-; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[ADD1]], i8 [[ADD2]])
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.sadd.sat.i8(i8 [[TMP1]], i8 [[Z]])
; CHECK-NEXT: ret i8 [[MIN]]
;
%add1 = call i8 @llvm.sadd.sat.i8(i8 %z, i8 %x)
More information about the llvm-commits
mailing list