From a6de63243abed1c0a03e9db92c9b26dcdf53fd9d Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Fri, 17 Dec 2021 21:36:24 +0300 Subject: [PATCH] JIT: handle more cases for MOD/DIV -> UMOD/UDIV transformation (#62394) * Introduce IsNeverNegative * Address feedback * Apply suggestions from code review Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> * Address feedback * fix build on x86 Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/gentree.cpp | 23 +++++++++++++++++++++++ src/coreclr/jit/gentree.h | 2 ++ src/coreclr/jit/morph.cpp | 18 ++++++++---------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 89b2cdfcf7050..09dff5c7803f1 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -21681,3 +21681,26 @@ bool GenTree::IsInvariant() const GenTree* lclVarTree = nullptr; return OperIsConst() || Compiler::impIsAddressInLocal(this, &lclVarTree); } + +//------------------------------------------------------------------------ +// IsNeverNegative: returns true if the given tree is known to be never +// negative, i. e. the upper bit will always be zero. +// Only valid for integral types. +// +// Arguments: +// comp - Compiler object, needed for IntegralRange::ForNode +// +// Return Value: +// true if the given tree is known to be never negative +// +bool GenTree::IsNeverNegative(Compiler* comp) const +{ + assert(varTypeIsIntegral(this)); + + if (IsIntegralConst()) + { + return AsIntConCommon()->IntegralValue() >= 0; + } + // TODO-Casts: extend IntegralRange to handle constants + return IntegralRange::ForNode((GenTree*)this, comp).IsPositive(); +} diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 7f95d46938bf9..53bba64997b8e 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2260,6 +2260,8 @@ struct GenTree bool IsInvariant() const; + bool IsNeverNegative(Compiler* comp) const; + bool IsReuseRegVal() const { // This can be extended to non-constant nodes, but not to local or indir nodes. diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 7f829454761ad..0729d06e414f1 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -11159,13 +11159,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } } - // array.Length is always positive so GT_DIV can be changed to GT_UDIV - // if op2 is a positive cns - if (!optValnumCSE_phase && op1->OperIs(GT_ARR_LENGTH) && op2->IsIntegralConst() && - op2->AsIntCon()->IconValue() >= 2) // for 0 and 1 it doesn't matter if it's UDIV or DIV + // Convert DIV to UDIV if boths op1 and op2 are known to be never negative + if (!gtIsActiveCSE_Candidate(tree) && varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && + op2->IsNeverNegative(this)) { assert(tree->OperIs(GT_DIV)); - tree->ChangeOper(GT_UDIV); + tree->ChangeOper(GT_UDIV, GenTree::PRESERVE_VN); return fgMorphSmpOp(tree, mac); } @@ -11228,13 +11227,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) goto USE_HELPER_FOR_ARITH; } - // array.Length is always positive so GT_DIV can be changed to GT_UDIV - // if op2 is a positive cns - if (!optValnumCSE_phase && op1->OperIs(GT_ARR_LENGTH) && op2->IsIntegralConst() && - op2->AsIntCon()->IconValue() >= 2) // for 0 and 1 it doesn't matter if it's UMOD or MOD + // Convert MOD to UMOD if boths op1 and op2 are known to be never negative + if (!gtIsActiveCSE_Candidate(tree) && varTypeIsIntegral(tree) && op1->IsNeverNegative(this) && + op2->IsNeverNegative(this)) { assert(tree->OperIs(GT_MOD)); - tree->ChangeOper(GT_UMOD); + tree->ChangeOper(GT_UMOD, GenTree::PRESERVE_VN); return fgMorphSmpOp(tree, mac); }