Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with hoisting and copy prop interaction #85493

Merged
merged 4 commits into from
May 18, 2023

Conversation

BruceForstall
Copy link
Member

After hoisting creates a tree copy, it morphs it. That morph might lose the value numbers on LCL_VAR uses, but leave the SSA numbers. Copy prop was assuming that such a use had a VN. Instead, check this dynamically instead of asserting.

Fixes #84619

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 27, 2023
@ghost ghost assigned BruceForstall Apr 27, 2023
@ghost
Copy link

ghost commented Apr 27, 2023

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

After hoisting creates a tree copy, it morphs it. That morph might lose the value numbers on LCL_VAR uses, but leave the SSA numbers. Copy prop was assuming that such a use had a VN. Instead, check this dynamically instead of asserting.

Fixes #84619

Author: BruceForstall
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@BruceForstall
Copy link
Member Author

/azp run Fuzzlyn

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@BruceForstall
Copy link
Member Author

No asm diffs

Slight TP cost

@BruceForstall
Copy link
Member Author

@AndyAyersMS PTAL
cc @dotnet/jit-contrib

@AndyAyersMS
Copy link
Member

After hoisting creates a tree copy, it morphs it. That morph might lose the value numbers on LCL_VAR uses, but leave the SSA numbers. Copy prop was assuming that such a use had a VN. Instead, check this dynamically instead of asserting.

Fixes #84619

I hate to open a can of worms here, but why does hoisting call morph? Seems like maybe it shouldn't.

@BruceForstall
Copy link
Member Author

I hate to open a can of worms here, but why does hoisting call morph?

Disabling morphing only causes one family of diffs.

Another question, though: why does morphing lose VNs on LCL_VARs?

@SingleAccretion
Copy link
Contributor

The case from #84619 is optNarrowTree's work, and it cannot (easily) preserve VNs on trees that it transforms (although it has some logic that tries). What we've been doing with such transformation is putting them under if (fgGlobalMorph). This may be expensive CQ-wise in this case.

@AndyAyersMS
Copy link
Member

I hate to open a can of worms here, but why does hoisting call morph?

Disabling morphing only causes one family of diffs.

I was wondering if you'd actually see improvements, since hoisting relies on CSE and perhaps morphing the hoisted copy would break CSE (either by changing tree shape so it no longer matches the in-loop tree or perhaps by losing the GTF_MAKE_CSE flag) and hence messes up hoisting.

Oddly we don't check for GTF_MAKE_CSE in CSE proper, we just use it to keep morph and other things from deleting the thing we just hoisted.

Another question, though: why does morphing lose VNs on LCL_VARs?

Could be there's a missing surgical VN update that could be fixed, you'd have to dig in.

@AndyAyersMS
Copy link
Member

@BruceForstall you're not waiting on me here, are you?

@BruceForstall
Copy link
Member Author

@BruceForstall you're not waiting on me here, are you?

No. But the questions asked require investigations, which I've prioritized very low compared to other work (even though it would be nice to get Fuzzlyn cleaner, but it has good baselining anyway)

After hoisting creates a tree copy, it morphs it. That morph might
lose the value numbers on LCL_VAR uses, but leave the SSA numbers.
Copy prop was assuming that such a use had a VN. Instead, check this
dynamically instead of asserting.

Fixes dotnet#84619
If we optimize the cast, call `fgOptimizeCast` to see if it can be
optimized further.
@BruceForstall
Copy link
Member Author

@AndyAyersMS I updated this. I found the case that was creating a CAST that wasn't getting fully morphed/optimized, in fgOptimizeCastOnStore, and added a call to fgOptimizeCast. With this, the hoisted code that gets morphed doesn't actually optimize anything, and so the assert is avoided. (It turns out it doesn't create a CSE in this test case, either, but I didn't look into why.) I propose to leave the dynamic check in optBlockCopyProp for safety. Finally, if I remove morphing from hoisting there are no diffs now (at least on win-x64). Perhaps removing that can be done as a follow-up.

I also added a unit test.

There are a few diffs, with the additional call to fgOptimizeCast causing a few more cases of narrowing to kick in.

There is a bit of TP hit.

Comment on lines 394 to 395
else if (tree->OperIs(GT_LCL_VAR, GT_LCL_FLD) && tree->AsLclVarCommon()->HasSsaName() &&
tree->gtVNPair.BothDefined())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend removing this check. optCopyProp doesn't actually depends on the VNs being present for trees it examines, so this is effectively the same as removing the assert.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optCopyProp does assert(tree->gtVNPair.BothDefined()) which is why I added this.

But it's true that optCopyProp does not actually use the tree->gtVNPair : it looks up the VN in the lvPerSsaData for the SSA def of the local. Presumably this assert is a partial expression of the expectation that if a local has an SSA number, then its SSA def should have the same VN as the SSA use (I believe that should be true?). It would therefore seem odd to ignore the fact that a lclvar use has no VN but its SSA does, and just use the def. That seems to indicate something is odd/wrong, perhaps due to morph, like what happened here.

Of course, I could remove the assert from optCopyProp, too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this assert is a partial expression of the expectation that if a local has an SSA number, then its SSA def should have the same VN as the SSA use (I believe that should be true?).

Here is how this situation came to be: optCopyProp used to use the tree VN, but was changed to use the definition VN in #65250, with the main motivation being LCL_FLD handling. I left the tree VN assert as it seemed valuable on its own (indeed, as you say, to catch missing VNs - we are generally sorely lacking in validating this aspect of morph).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it seems like I could either:

  1. Remove both the tree->gtVNPair.BothDefined() check here and assert(tree->gtVNPair.BothDefined()) in optCopyProp (so optCopyProp will no longer check for "missing" VNs), or
  2. Leave it as I've written it -- with more testing/checking than maybe should be required, or
  3. Something else? (e.g., asserting for and fixing "missing VNs" -- but that seems out of scope for this fix)

Do you have a preference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to check for missing VNs and fix them (leave the assert without the check, or even migrate it to the general loop in optBlockCopyProp), but barring that removing the assert (1) seems better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the SSA checker should also be able to spot missing VNs, though not perhaps in as timely a manner.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the SSA checker should also be able to spot missing VNs, though not perhaps in as timely a manner.

Well, fgDebugCheckSsa() already has this comment: * Verify VNs on uses match the VN on the def :-)

@BruceForstall
Copy link
Member Author

Ok, I've removed the assert in optCopyProp.

@BruceForstall
Copy link
Member Author

@AndyAyersMS ping

@BruceForstall
Copy link
Member Author

ping

@BruceForstall BruceForstall merged commit 32b7be7 into dotnet:main May 18, 2023
@BruceForstall BruceForstall deleted the Fix84619 branch May 18, 2023 16:16
@ghost ghost locked as resolved and limited conversation to collaborators Jun 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
3 participants