diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp index 54402124209aec..bda5e9bac316bd 100644 --- a/src/coreclr/jit/lclmorph.cpp +++ b/src/coreclr/jit/lclmorph.cpp @@ -677,6 +677,34 @@ class LocalAddressVisitor final : public GenTreeVisitor 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(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()) { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 0a588abae2be45..ee150eb59822f6 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -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); @@ -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; @@ -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: @@ -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: