Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21730,3 +21730,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();
}
2 changes: 2 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2286,6 +2286,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.
Expand Down
18 changes: 8 additions & 10 deletions src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11152,13 +11152,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);
}

Expand Down Expand Up @@ -11221,13 +11220,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);
}

Expand Down