From: Jakob Botsch Nielsen Date: Thu, 8 Jun 2023 15:04:35 +0000 (+0200) Subject: JIT: Fix a couple of inequalities in promotion decomposition (#87186) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~1759 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=897093def5c96503576f38b7ba0724bbbe9bfd84;p=platform%2Fupstream%2Fdotnet%2Fruntime.git JIT: Fix a couple of inequalities in promotion decomposition (#87186) These checks were of the form `end < start` when more precisely they can be `end <= start`. It was causing some unnecessarily conservative writebacks to occur in some cases. Also skip entries in the decomposition plan that are writing to the remainder when the remainder is dead. Saw a bunch of these cases in the regressions and realized we were missing this case. --- diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index d0df8b9..f0a6e0f 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -698,21 +698,8 @@ private: entry.ToReplacement->NeedsReadBack = false; } - if (CanSkipEntry(entry, dstDeaths, remainderStrategy)) + if (CanSkipEntry(entry, dstDeaths, remainderStrategy DEBUGARG(/* dump */ true))) { - if (entry.FromReplacement != nullptr) - { - JITDUMP( - " Skipping dst+%03u <- V%02u (%s); it is up-to-date in its struct local and will be handled " - "as part of the remainder\n", - entry.Offset, entry.FromReplacement->LclNum, entry.FromReplacement->Description); - } - else if (entry.ToReplacement != nullptr) - { - JITDUMP(" Skipping def of V%02u (%s); it is dying", entry.ToReplacement->LclNum, - entry.ToReplacement->Description); - } - continue; } @@ -824,9 +811,13 @@ private: // // Parameters: // entry - The init/copy entry + // deaths - Liveness information for the destination; only valid if m_dstInvolvedReplacements is true. // remainderStrategy - The strategy we are using for the remainder + // dump - Whether to JITDUMP decisions made // - bool CanSkipEntry(const Entry& entry, const StructDeaths& deaths, const RemainderStrategy& remainderStrategy) + bool CanSkipEntry(const Entry& entry, + const StructDeaths& deaths, + const RemainderStrategy& remainderStrategy DEBUGARG(bool dump = false)) { if (entry.ToReplacement != nullptr) { @@ -841,6 +832,32 @@ private: size_t replacementIndex = entry.ToReplacement - firstRep; if (deaths.IsReplacementDying((unsigned)replacementIndex)) { +#ifdef DEBUG + if (dump) + { + JITDUMP(" Skipping def of V%02u (%s); it is dying\n", entry.ToReplacement->LclNum, + entry.ToReplacement->Description); + } +#endif + + return true; + } + } + else + { + // If the destination has replacements we still have usable + // liveness information for the remainder. This case happens if the + // source was also promoted. + if (m_dstInvolvesReplacements && deaths.IsRemainderDying()) + { +#ifdef DEBUG + if (dump) + { + JITDUMP(" Skipping write to dst+%03u; it is the remainder and the remainder is dying\n", + entry.Offset); + } +#endif + return true; } } @@ -848,8 +865,20 @@ private: if (entry.FromReplacement != nullptr) { // Check if the remainder is going to handle it. - return (remainderStrategy.Type == RemainderStrategy::FullBlock) && !entry.FromReplacement->NeedsWriteBack && - (entry.ToLclNum == BAD_VAR_NUM); + if ((remainderStrategy.Type == RemainderStrategy::FullBlock) && !entry.FromReplacement->NeedsWriteBack && + (entry.ToLclNum == BAD_VAR_NUM)) + { +#ifdef DEBUG + if (dump) + { + JITDUMP(" Skipping dst+%03u <- V%02u (%s); it is up-to-date in its struct local and will be " + "handled as part of the remainder\n", + entry.Offset, entry.FromReplacement->LclNum, entry.FromReplacement->Description); + } +#endif + + return true; + } } return false; @@ -1336,7 +1365,7 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, if ((dstRep < dstEndRep) && (srcRep < srcEndRep)) { - if (srcRep->Offset - srcBaseOffs + genTypeSize(srcRep->AccessType) < dstRep->Offset - dstBaseOffs) + if (srcRep->Offset - srcBaseOffs + genTypeSize(srcRep->AccessType) <= dstRep->Offset - dstBaseOffs) { // This source replacement ends before the next destination replacement starts. // Write it directly to the destination struct local. @@ -1348,7 +1377,7 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, continue; } - if (dstRep->Offset - dstBaseOffs + genTypeSize(dstRep->AccessType) < srcRep->Offset - srcBaseOffs) + if (dstRep->Offset - dstBaseOffs + genTypeSize(dstRep->AccessType) <= srcRep->Offset - srcBaseOffs) { // Destination replacement ends before the next source replacement starts. // Read it directly from the source struct local. @@ -1402,7 +1431,7 @@ void ReplaceVisitor::CopyBetweenFields(GenTree* store, { plan->CopyBetweenReplacements(dstRep, fieldLcl, offs); JITDUMP(" V%02u (%s)%s <- V%02u (%s)\n", dstRep->LclNum, dstRep->Description, - LastUseString(dstLcl, dstRep), dsc->lvReason); + LastUseString(dstLcl, dstRep), fieldLcl, dsc->lvReason); dstRep++; continue; }