Skip to content
28 changes: 28 additions & 0 deletions src/coreclr/jit/lclmorph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,34 @@ class LocalAddressVisitor final : public GenTreeVisitor<LocalAddressVisitor>
PopValue();
break;

case GT_SUB:
{
Value& rhs = TopValue(0);
Value& lhs = TopValue(1);
if (m_compiler->opts.OptimizationEnabled() && lhs.IsAddress() && rhs.IsAddress() &&
(lhs.LclNum() == rhs.LclNum()) && (rhs.Offset() <= lhs.Offset()) &&
FitsIn<int>(lhs.Offset() - rhs.Offset()))
{
// TODO-Bug: Due to inlining we may end up with incorrectly typed SUB trees here.
assert(node->TypeIs(TYP_I_IMPL, TYP_BYREF));

ssize_t result = (ssize_t)(lhs.Offset() - rhs.Offset());
node->BashToConst(result, TYP_I_IMPL);
INDEBUG(lhs.Consume());
INDEBUG(rhs.Consume());
PopValue();
PopValue();
m_stmtModified = true;
break;
}

EscapeValue(TopValue(0), node);
PopValue();
EscapeValue(TopValue(0), node);
PopValue();
break;
}

case GT_FIELD_ADDR:
if (node->AsField()->IsInstance())
{
Expand Down
39 changes: 36 additions & 3 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4450,7 +4450,7 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN
// (x - 0) == x
// (x - x) == 0
// This identity does not apply for floating point (when x == -0.0).
auto identityForSubtraction = [=]() -> ValueNum {
auto identityForSubtraction = [=](bool ovf) -> ValueNum {
if (!varTypeIsFloating(typ))
{
ValueNum ZeroVN = VNZeroForType(typ);
Expand All @@ -4462,6 +4462,39 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN
{
return ZeroVN;
}

if (!ovf)
{
// (x + a) - x == a
// (a + x) - x == a
VNFuncApp add;
if (GetVNFunc(arg0VN, &add) && (add.m_func == (VNFunc)GT_ADD))
{
if (add.m_args[0] == arg1VN)
return add.m_args[1];
if (add.m_args[1] == arg1VN)
return add.m_args[0];

// (x + a) - (x + b) == a - b
// (a + x) - (x + b) == a - b
// (x + a) - (b + x) == a - b
// (a + x) - (b + x) == a - b
VNFuncApp add2;
if (GetVNFunc(arg1VN, &add2) && (add2.m_func == (VNFunc)GT_ADD))
{
for (int a = 0; a < 2; a++)
{
for (int b = 0; b < 2; b++)
{
if (add.m_args[a] == add2.m_args[b])
{
return VNForFunc(typ, (VNFunc)GT_SUB, add.m_args[1 - a], add2.m_args[1 - b]);
}
}
}
}
}
}
}

return NoVN;
Expand Down Expand Up @@ -4515,7 +4548,7 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN
break;

case GT_SUB:
resultVN = identityForSubtraction();
resultVN = identityForSubtraction(/* ovf */ false);
break;

case GT_MUL:
Expand Down Expand Up @@ -4790,7 +4823,7 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN

case VNF_SUB_OVF:
case VNF_SUB_UN_OVF:
resultVN = identityForSubtraction();
resultVN = identityForSubtraction(/* ovf */ true);
break;

case VNF_MUL_OVF:
Expand Down