Author: Sanjay Patel Date: 2021-08-16T11:35:29-07:00 New Revision: f4006c59497d425f5a3df5e68da5add21f8e467d
URL: https://github.com/llvm/llvm-project/commit/f4006c59497d425f5a3df5e68da5add21f8e467d DIFF: https://github.com/llvm/llvm-project/commit/f4006c59497d425f5a3df5e68da5add21f8e467d.diff LOG: [InstSimplify] fold min/max with limit constant This is already done within InstCombine: https://alive2.llvm.org/ce/z/MiGE22 ...but leaving it out of analysis makes it harder to avoid infinite loops there. (cherry picked from commit e260e10c4a21784c146c94a2a14b7e78b09a9cf7) Added: Modified: llvm/include/llvm/Analysis/ValueTracking.h llvm/lib/Analysis/InstructionSimplify.cpp llvm/lib/Analysis/ValueTracking.cpp llvm/test/Transforms/InstSimplify/maxmin.ll Removed: ################################################################################ diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 90ec742f18e67..f46e66641c082 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -744,6 +744,10 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6; /// minimum/maximum flavor. CmpInst::Predicate getInverseMinMaxPred(SelectPatternFlavor SPF); + /// Return the minimum or maximum constant value for the specified integer + /// min/max flavor and type. + APInt getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth); + /// Check if the values in \p VL are select instructions that can be converted /// to a min or max (vector) intrinsic. Returns the intrinsic ID, if such a /// conversion is possible, together with a bool indicating whether all select diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 23083bc8178e7..69ab0052b0a74 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4080,6 +4080,22 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, std::swap(TrueVal, FalseVal); } + // Check for integer min/max with a limit constant: + // X > MIN_INT ? X : MIN_INT --> X + // X < MAX_INT ? X : MAX_INT --> X + if (TrueVal->getType()->isIntOrIntVectorTy()) { + Value *X, *Y; + SelectPatternFlavor SPF = + matchDecomposedSelectPattern(cast<ICmpInst>(CondVal), TrueVal, FalseVal, + X, Y).Flavor; + if (SelectPatternResult::isMinOrMax(SPF) && Pred == getMinMaxPred(SPF)) { + APInt LimitC = getMinMaxLimit(getInverseMinMaxFlavor(SPF), + X->getType()->getScalarSizeInBits()); + if (match(Y, m_SpecificInt(LimitC))) + return X; + } + } + if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) { Value *X; const APInt *Y; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 522d21812c6a5..6e3ca5c4e08ae 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6253,6 +6253,16 @@ CmpInst::Predicate llvm::getInverseMinMaxPred(SelectPatternFlavor SPF) { return getMinMaxPred(getInverseMinMaxFlavor(SPF)); } +APInt llvm::getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth) { + switch (SPF) { + case SPF_SMAX: return APInt::getSignedMaxValue(BitWidth); + case SPF_SMIN: return APInt::getSignedMinValue(BitWidth); + case SPF_UMAX: return APInt::getMaxValue(BitWidth); + case SPF_UMIN: return APInt::getMinValue(BitWidth); + default: llvm_unreachable("Unexpected flavor"); + } +} + std::pair<Intrinsic::ID, bool> llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) { // Check if VL contains select instructions that can be folded into a min/max diff --git a/llvm/test/Transforms/InstSimplify/maxmin.ll b/llvm/test/Transforms/InstSimplify/maxmin.ll index e9fff33f63114..1dea800e6ecd0 100644 --- a/llvm/test/Transforms/InstSimplify/maxmin.ll +++ b/llvm/test/Transforms/InstSimplify/maxmin.ll @@ -3,9 +3,7 @@ define i8 @smax_min_limit(i8 %x) { ; CHECK-LABEL: @smax_min_limit( -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -128 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 -128 -; CHECK-NEXT: ret i8 [[SEL]] +; CHECK-NEXT: ret i8 [[X:%.*]] ; %cmp = icmp sgt i8 %x, -128 %sel = select i1 %cmp, i8 %x, i8 -128 @@ -14,9 +12,7 @@ define i8 @smax_min_limit(i8 %x) { define i8 @smin_max_limit(i8 %x) { ; CHECK-LABEL: @smin_max_limit( -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 127 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 127 -; CHECK-NEXT: ret i8 [[SEL]] +; CHECK-NEXT: ret i8 [[X:%.*]] ; %cmp = icmp slt i8 %x, 127 %sel = select i1 %cmp, i8 %x, i8 127 @@ -25,9 +21,7 @@ define i8 @smin_max_limit(i8 %x) { define <2 x i8> @umax_min_limit(<2 x i8> %x) { ; CHECK-LABEL: @umax_min_limit( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i8> [[X:%.*]], zeroinitializer -; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[X]], <2 x i8> zeroinitializer -; CHECK-NEXT: ret <2 x i8> [[SEL]] +; CHECK-NEXT: ret <2 x i8> [[X:%.*]] ; %cmp = icmp ugt <2 x i8> %x, zeroinitializer %sel = select <2 x i1> %cmp, <2 x i8> %x, <2 x i8> zeroinitializer @@ -36,15 +30,15 @@ define <2 x i8> @umax_min_limit(<2 x i8> %x) { define i8 @umin_max_limit(i8 %x) { ; CHECK-LABEL: @umin_max_limit( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X:%.*]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[X]], i8 -1 -; CHECK-NEXT: ret i8 [[SEL]] +; CHECK-NEXT: ret i8 [[X:%.*]] ; %cmp = icmp ult i8 %x, 255 %sel = select i1 %cmp, i8 %x, i8 255 ret i8 %sel } +; negative test - wrong limit + define i8 @smax_not_min_limit(i8 %x) { ; CHECK-LABEL: @smax_not_min_limit( ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -127 @@ -56,6 +50,8 @@ define i8 @smax_not_min_limit(i8 %x) { ret i8 %sel } +; negative test - wrong limit + define i8 @smin_not_min_limit(i8 %x) { ; CHECK-LABEL: @smin_not_min_limit( ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
