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

Reset _defMergedNodes in global VP on every basic block #6121

Merged
merged 1 commit into from
Aug 26, 2021

Conversation

gita-omr
Copy link
Contributor

@gita-omr gita-omr commented Jul 28, 2021

defMergedNodes is supposed to keep track of commonned nodes.
So it's safe to reset it on every basic block. Also add an assert
that there are no extended blocks during global VP.

@gita-omr gita-omr requested a review from vijaysun-omr as a code owner July 28, 2021 17:54
@gita-omr
Copy link
Contributor Author

The fix is based on @vijaysun-omr suggestion. @jdmpapin maybe you can review?

@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 5, 2021

Related:
[1] de38489

@jdmpapin
Copy link
Contributor

jdmpapin commented Aug 5, 2021

The change looks safe. I think this will help the case where an outermost loop has no other nested regions within it. Are there other cases it's meant to benefit? If it's only that one case, it might be possible to express the intention more clearly by adding a call to _defMergedNodes->empty() right after the first pass, e.g.

diff --git a/compiler/optimizer/OMRValuePropagation.cpp b/compiler/optimizer/OMRValuePropagation.cpp
index b932647da..7720eb87b 100644
--- a/compiler/optimizer/OMRValuePropagation.cpp
+++ b/compiler/optimizer/OMRValuePropagation.cpp
@@ -4142,6 +4142,14 @@ void TR::GlobalValuePropagation::processNaturalLoop(TR_StructureSubGraphNode *no
       _visitCount--;
       processRegionSubgraph(node, false, true, true);

+      // Reset the nodes seen in mergeDefConstraints() between passes through
+      // the loop. This is needed to recognize that loads within the loop have
+      // not yet been evaluated the second time through in case there are no
+      // nested regions (or possibly in case there is a block directly in the
+      // loop which we process after all nested regions the first time, but
+      // somehow before all nested regions the second time).
+      _defMergedNodes->empty();
+
       // having processed the loop the first time we want to make sure to wipe out any
       // seenOnAllPaths information on the back edges - we use this notion only for the current iteration
       for (auto itr = region->getEntry()->getPredecessors().begin(), end = region->getEntry()->getPredecessors().end(); itr != end; ++itr)

Copy link
Contributor

@jdmpapin jdmpapin left a comment

Choose a reason for hiding this comment

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

LGTM - my other comment is only a suggestion

@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 6, 2021

I think the idea is that _defMergedNodes essentially is just keeping track of commoned nodes and therefore could be reset on every extended block. So resetting it in processRegionSubgraph would be the closest to doing that.

@jdmpapin @vijaysun-omr

@jdmpapin
Copy link
Contributor

jdmpapin commented Aug 6, 2021

OK, I buy that logic 🙂

By the way, I got worried about extended blocks as I was reading this code yesterday. If GVP can encounter extended blocks, then I think the use of _defMergedNodes is already broken in one or maybe two ways, unrelated to your changes. But from looking at all of the strategies, I believe GVP doesn't run after block extension. (It looks like it's technically possible that it could in OpenJ9, but only with -Xjit:enableSequentialLoadStoreCold)

@jdmpapin
Copy link
Contributor

jdmpapin commented Aug 6, 2021

Come to think of it, maybe we should just assert that no block is an extension of another and reset it every block

@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 6, 2021

Thanks @jdmpapin ! I just a bit worry that we might want to run GVP on extended blocks in the future, but I guess you are saying it's broken already... Not sure if we should fix that or assert. I would let @vijaysun-omr comment...

@vijaysun-omr
Copy link
Contributor

I think this may get a bit more complicated if we ran GVP on extended basic blocks (which I think we don't in any strategy currently). For example, we may run into a case when we start an extended basic block inside a loop but take the loop back edge midway through that extended basic block and the remainder of the extended basic block is outside the loop. Since GVP does its processing for a natural loop at a time, this could complicate matters about what we want to do with the bit vector for visited status when we are analyzing the part of the extended basic block that is outside the loop.

I'd prefer not to have to deal with this right now and add an assertion instead if we detected extended basic blocks in GVP (giving this above rationale for the assert) if you agree, especially as I did'nt think we allowed GVP for extended blocks presently.

This may have been what you were thinking too (@jdmpapin and @gita-omr) in which case we should go ahead.

@jdmpapin
Copy link
Contributor

jdmpapin commented Aug 6, 2021

Thanks for the great example, @vijaysun-omr. I'll elaborate on the issues that I was thinking of too, just for additional motivation

First consider a diamond within an acyclic region A→B, A→C, B→D, C→D:

  A
 / \
B   C
 \ /
  D

Suppose that A, B, are blocks and C is a nested region, e.g. a loop, and suppose further that B is an extension of A. I don't believe there's anything to stop GVP from processing these nodes in the order A, C, B, D, but if we process them in that order, we'll inappropriately reset _defMergedNodes between A and B.

For the second example - I'm less sure about this one, but - I think it might be possible for an acyclic region or improper region to start partway through an extended block, i.e. so that the entry block of the region is an extension of a block outside. If so, then when we reset _defMergedNodes at the beginning of the region, that will be partway through an extended block

@vijaysun-omr
Copy link
Contributor

vijaysun-omr commented Aug 6, 2021

I think those are both good examples, Devin and your comment as a whole may be worth adding to the comment next to the assert if that we what we are planning to add to GVP.

Comment on lines 4099 to 4102
// Only commoned nodes within a block need to be set in _defMergedNodes.
// So it should be reset here
TR_ASSERT(!node->getBlock()->isExtensionOfPreviousBlock(), "This optimization does not run on extended blocks");
_defMergedNodes->empty();
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you mind using TR_ASSERT_FATAL here? I think that TR_ASSERT still doesn't get checked in most (or even all?) of the testing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I was wondering about that but all asserts in this file are non-fatal. Anyways, let me make it FATAL just to be sure.

@vijaysun-omr
Copy link
Contributor

Jenkins build all

@gita-omr gita-omr changed the title Reset _defMergedNodes in VP more frequently WIP:Reset _defMergedNodes in VP more frequently Aug 9, 2021
@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 9, 2021

Made WIP while I am retesting with TR_ASSERT_FATAL. Not sure why but I somehow believed that all asserts are fatal now...

@gita-omr gita-omr force-pushed the pr_vijays_vp_fix branch 2 times, most recently from a14b5d6 to d9beb56 Compare August 9, 2021 20:47
@jdmpapin
Copy link
Contributor

jdmpapin commented Aug 9, 2021

Since we seem to be going with the reset on every block with an assertion, would you mind squashing the two commits, @gita-omr? The first commit would just be noise in the history

@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 9, 2021

Since we seem to be going with the reset on every block with an assertion, would you mind squashing the two commits, @gita-omr? The first commit would just be noise in the history

Definitely, but let me finish all the testing first. BTW: please note the change in getting the block out of the node. Note sure how the first commit worked...

_defMergedNodes is supposed to keep track of commonned nodes.
So it's safe to reset it on every basic block. Also add an assert
that there are no extended blocks during global VP.
@gita-omr
Copy link
Contributor Author

gita-omr commented Aug 10, 2021

All tests passed. Squashed the commits.

@jdmpapin @vijaysun-omr

@gita-omr gita-omr changed the title WIP:Reset _defMergedNodes in VP more frequently Reset _defMergedNodes in global VP on every basic block Aug 10, 2021
@vijaysun-omr
Copy link
Contributor

Jenkins build all

@rmnattas
Copy link
Contributor

Merging this also solves GHE openj9-jit-power#207

@vijaysun-omr
Copy link
Contributor

Checks have passed and reviews are also done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants