From f6a8775c5d9fa6cd49f404da70982f2e7b91c88c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 11:42:21 +0200 Subject: [PATCH] [InstSimplify] Fold icmp of uadd.sat/usub.sat (PR63381) Fold uadd.sat(X, Y) uge X and usub.sat(X, Y) ule X to true. Proof: https://alive2.llvm.org/ce/z/596m9X Fixes https://github.com/llvm/llvm-project/issues/63381. --- llvm/lib/Analysis/InstructionSimplify.cpp | 36 ++++++++++++++++++++++ .../Transforms/InstSimplify/saturating-add-sub.ll | 32 +++++-------------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 616873f..48ffa83 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3682,6 +3682,36 @@ static Value *simplifyICmpWithDominatingAssume(CmpInst::Predicate Predicate, return nullptr; } +static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred, + Value *LHS, Value *RHS) { + auto *II = dyn_cast(LHS); + if (!II) + return nullptr; + + switch (II->getIntrinsicID()) { + case Intrinsic::uadd_sat: + // uadd.sat(X, Y) uge X, uadd.sat(X, Y) uge Y + if (II->getArgOperand(0) == RHS || II->getArgOperand(1) == RHS) { + if (Pred == ICmpInst::ICMP_UGE) + return ConstantInt::getTrue(getCompareTy(II)); + if (Pred == ICmpInst::ICMP_ULT) + return ConstantInt::getFalse(getCompareTy(II)); + } + return nullptr; + case Intrinsic::usub_sat: + // usub.sat(X, Y) ule X + if (II->getArgOperand(0) == RHS) { + if (Pred == ICmpInst::ICMP_ULE) + return ConstantInt::getTrue(getCompareTy(II)); + if (Pred == ICmpInst::ICMP_UGT) + return ConstantInt::getFalse(getCompareTy(II)); + } + return nullptr; + default: + return nullptr; + } +} + /// Given operands for an ICmpInst, see if we can fold the result. /// If not, this returns null. static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, @@ -3946,6 +3976,12 @@ static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, if (Value *V = simplifyICmpWithMinMax(Pred, LHS, RHS, Q, MaxRecurse)) return V; + if (Value *V = simplifyICmpWithIntrinsicOnLHS(Pred, LHS, RHS)) + return V; + if (Value *V = simplifyICmpWithIntrinsicOnLHS( + ICmpInst::getSwappedPredicate(Pred), RHS, LHS)) + return V; + if (Value *V = simplifyICmpWithDominatingAssume(Pred, LHS, RHS, Q)) return V; diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll index 616a206..6fb1261 100644 --- a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll @@ -797,9 +797,7 @@ define i1 @ssub_icmp_op1_smin(i8 %a) { define i1 @uadd_uge(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %sat, %x @@ -808,9 +806,7 @@ define i1 @uadd_uge(i8 %x, i8 %y) { define i1 @uadd_uge_rhs(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge_rhs( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[Y]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %sat, %y @@ -819,9 +815,7 @@ define i1 @uadd_uge_rhs(i8 %x, i8 %y) { define i1 @uadd_uge_commuted(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge_commuted( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X]], [[SAT]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp ule i8 %x, %sat @@ -830,9 +824,7 @@ define i1 @uadd_uge_commuted(i8 %x, i8 %y) { define i1 @uadd_ult(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_ult( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp ult i8 %sat, %x @@ -841,9 +833,7 @@ define i1 @uadd_ult(i8 %x, i8 %y) { define <2 x i1> @uadd_uge_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @uadd_uge_vec( -; CHECK-NEXT: [[SAT:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge <2 x i8> [[SAT]], [[X]] -; CHECK-NEXT: ret <2 x i1> [[CMP]] +; CHECK-NEXT: ret <2 x i1> ; %sat = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %x, <2 x i8> %y) %cmp = icmp uge <2 x i8> %sat, %x @@ -885,9 +875,7 @@ define i1 @uadd_uge_unrelated_op_fail(i8 %x, i8 %y, i8 %z) { define i1 @usub_ule(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ule( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp ule i8 %sat, %x @@ -907,9 +895,7 @@ define i1 @usub_ule_rhs_fail(i8 %x, i8 %y) { define i1 @usub_ule_commuted(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ule_commuted( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X]], [[SAT]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %x, %sat @@ -918,9 +904,7 @@ define i1 @usub_ule_commuted(i8 %x, i8 %y) { define i1 @usub_ugt(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ugt( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp ugt i8 %sat, %x -- 2.7.4