[llvm] d7c119d - [InstSimplify] Fold min/max intrinsic based on icmp of operands

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 13:03:10 PDT 2020


Author: Nikita Popov
Date: 2020-08-26T22:02:57+02:00
New Revision: d7c119d89c5f6d0789cfd0a139c80e23912c0bb0

URL: https://github.com/llvm/llvm-project/commit/d7c119d89c5f6d0789cfd0a139c80e23912c0bb0
DIFF: https://github.com/llvm/llvm-project/commit/d7c119d89c5f6d0789cfd0a139c80e23912c0bb0.diff

LOG: [InstSimplify] Fold min/max intrinsic based on icmp of operands

This is a reboot of D84655, now performing the inner icmp
simplification query without undef folds.

It should be possible to handle the current foldMinMaxSharedOp()
fold based on this, by moving the logic into icmp of min/max instead,
making it more general. We can't drop the folds for constant operands,
because those also allow undef, which we exclude here.

The tests use assumes for exhaustive coverage, and have a few
more examples of misc folds we get based on icmp simplification.

Differential Revision: https://reviews.llvm.org/D85929

Added: 
    

Modified: 
    llvm/lib/Analysis/InstructionSimplify.cpp
    llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 887079445ecc..eb0d95182c73 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -5232,6 +5232,16 @@ static APInt getMaxMinLimit(Intrinsic::ID IID, unsigned BitWidth) {
   }
 }
 
+static ICmpInst::Predicate getMaxMinPredicate(Intrinsic::ID IID) {
+  switch (IID) {
+  case Intrinsic::smax: return ICmpInst::ICMP_SGE;
+  case Intrinsic::smin: return ICmpInst::ICMP_SLE;
+  case Intrinsic::umax: return ICmpInst::ICMP_UGE;
+  case Intrinsic::umin: return ICmpInst::ICMP_ULE;
+  default: llvm_unreachable("Unexpected intrinsic");
+  }
+}
+
 /// Given a min/max intrinsic, see if it can be removed based on having an
 /// operand that is another min/max intrinsic with shared operand(s). The caller
 /// is expected to swap the operand arguments to handle commutation.
@@ -5324,6 +5334,12 @@ static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1,
     if (Value *V = foldMinMaxSharedOp(IID, Op1, Op0))
       return V;
 
+    ICmpInst::Predicate Pred = getMaxMinPredicate(IID);
+    if (isICmpTrue(Pred, Op0, Op1, Q.getWithoutUndef(), RecursionLimit))
+      return Op0;
+    if (isICmpTrue(Pred, Op1, Op0, Q.getWithoutUndef(), RecursionLimit))
+      return Op1;
+
     break;
   }
   case Intrinsic::usub_with_overflow:

diff  --git a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
index 99239db4650e..c2c0f9ebf82d 100644
--- a/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
+++ b/llvm/test/Transforms/InstSimplify/maxmin_intrinsics.ll
@@ -1895,8 +1895,7 @@ define i8 @umin_assume_uge(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umin_assume_uge(
 ; CHECK-NEXT:    [[C:%.*]] = icmp uge i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp uge i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1908,8 +1907,7 @@ define i8 @umin_assume_ugt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umin_assume_ugt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp ugt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1921,8 +1919,7 @@ define i8 @umin_assume_ule(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umin_assume_ule(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ule i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp ule i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1934,8 +1931,7 @@ define i8 @umin_assume_ult(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umin_assume_ult(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp ult i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1947,8 +1943,7 @@ define i8 @umax_assume_uge(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umax_assume_uge(
 ; CHECK-NEXT:    [[C:%.*]] = icmp uge i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp uge i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1960,8 +1955,7 @@ define i8 @umax_assume_ugt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umax_assume_ugt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ugt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp ugt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1973,8 +1967,7 @@ define i8 @umax_assume_ule(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umax_assume_ule(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ule i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp ule i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1986,8 +1979,7 @@ define i8 @umax_assume_ult(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umax_assume_ult(
 ; CHECK-NEXT:    [[C:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp ult i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -1999,8 +1991,7 @@ define i8 @smin_assume_sge(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smin_assume_sge(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sge i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp sge i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2012,8 +2003,7 @@ define i8 @smin_assume_sgt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smin_assume_sgt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp sgt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2025,8 +2015,7 @@ define i8 @smin_assume_sle(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smin_assume_sle(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sle i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp sle i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2038,8 +2027,7 @@ define i8 @smin_assume_slt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smin_assume_slt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp slt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp slt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2051,8 +2039,7 @@ define i8 @smax_assume_sge(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smax_assume_sge(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sge i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp sge i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2064,8 +2051,7 @@ define i8 @smax_assume_sgt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smax_assume_sgt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[X]]
 ;
   %c = icmp sgt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2077,8 +2063,7 @@ define i8 @smax_assume_sle(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smax_assume_sle(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sle i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp sle i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2090,8 +2075,7 @@ define i8 @smax_assume_slt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @smax_assume_slt(
 ; CHECK-NEXT:    [[C:%.*]] = icmp slt i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT:    [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[M]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %c = icmp slt i8 %x, %y
   call void @llvm.assume(i1 %c)
@@ -2102,8 +2086,7 @@ define i8 @smax_assume_slt(i8 %x, i8 %y) {
 define i8 @umax_add_nuw_1(i8 %x) {
 ; CHECK-LABEL: @umax_add_nuw_1(
 ; CHECK-NEXT:    [[ADD:%.*]] = add nuw i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD]], i8 [[X]])
-; CHECK-NEXT:    ret i8 [[MAX]]
+; CHECK-NEXT:    ret i8 [[ADD]]
 ;
   %add = add nuw i8 %x, 1
   %max = call i8 @llvm.umax.i8(i8 %add, i8 %x)
@@ -2113,8 +2096,7 @@ define i8 @umax_add_nuw_1(i8 %x) {
 define i8 @umax_add_nuw_2(i8 %x) {
 ; CHECK-LABEL: @umax_add_nuw_2(
 ; CHECK-NEXT:    [[ADD:%.*]] = add nuw i8 [[X:%.*]], 42
-; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ADD]], i8 42)
-; CHECK-NEXT:    ret i8 [[MAX]]
+; CHECK-NEXT:    ret i8 [[ADD]]
 ;
   %add = add nuw i8 %x, 42
   %max = call i8 @llvm.umax.i8(i8 %add, i8 42)
@@ -2123,10 +2105,8 @@ define i8 @umax_add_nuw_2(i8 %x) {
 
 define i8 @umax_range_metadata(i8* %p1, i8* %p2) {
 ; CHECK-LABEL: @umax_range_metadata(
-; CHECK-NEXT:    [[X:%.*]] = load i8, i8* [[P1:%.*]], align 1, [[RNG0:!range !.*]]
-; CHECK-NEXT:    [[Y:%.*]] = load i8, i8* [[P2:%.*]], align 1, [[RNG1:!range !.*]]
-; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]])
-; CHECK-NEXT:    ret i8 [[MAX]]
+; CHECK-NEXT:    [[Y:%.*]] = load i8, i8* [[P2:%.*]], align 1, [[RNG0:!range !.*]]
+; CHECK-NEXT:    ret i8 [[Y]]
 ;
   %x = load i8, i8* %p1, !range !{i8 0, i8 10}
   %y = load i8, i8* %p2, !range !{i8 20, i8 30}
@@ -2136,10 +2116,8 @@ define i8 @umax_range_metadata(i8* %p1, i8* %p2) {
 
 define i8 @umax_zext_sext(i4 %x) {
 ; CHECK-LABEL: @umax_zext_sext(
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i4 [[X:%.*]] to i8
-; CHECK-NEXT:    [[SEXT:%.*]] = sext i4 [[X]] to i8
-; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[ZEXT]], i8 [[SEXT]])
-; CHECK-NEXT:    ret i8 [[MAX]]
+; CHECK-NEXT:    [[SEXT:%.*]] = sext i4 [[X:%.*]] to i8
+; CHECK-NEXT:    ret i8 [[SEXT]]
 ;
   %zext = zext i4 %x to i8
   %sext = sext i4 %x to i8
@@ -2149,9 +2127,7 @@ define i8 @umax_zext_sext(i4 %x) {
 
 define i8 @umax_lshr(i8 %x, i8 %y) {
 ; CHECK-LABEL: @umax_lshr(
-; CHECK-NEXT:    [[SHR:%.*]] = lshr i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[SHR]])
-; CHECK-NEXT:    ret i8 [[MAX]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %shr = lshr i8 %x, %y
   %max = call i8 @llvm.umax.i8(i8 %x, i8 %shr)


        


More information about the llvm-commits mailing list