This is an archive of the discontinued LLVM Phabricator instance.

[Polly][DeLICM] Use Known information when comparing Existing.Occupied and Proposed.Occupied.
ClosedPublic

Authored by Meinersbur on Apr 13 2017, 9:48 AM.

Details

Summary

This change only affects unit tests, but no functional changes are
expected on LLVM-IR, as no Known information is yet extracted and
consequently this functionality is only triggered through unit tests.

Diff Detail

Repository
rL LLVM

Event Timeline

Meinersbur created this revision.Apr 13 2017, 9:48 AM
grosser edited edge metadata.Apr 14 2017, 6:34 AM

Hi Michael,

thank you for reducing the size of the proposed patches. This is now a lot easier to review in-depth! Thanks a lot.

First, I don't think this is a 'NFC'. We clearly change the semantics of the code (as shown by the unit tests), but the tests are just expected to not yet influence the IR we generate. Instead of calling it 'NFC', I would state that this currently only affects the unit tests.

Technically the patch looks correct. However, it seems more complicated than necessary. Is this some kind of performance tuning?

Also, I had some problems understanding the comments. I added some of the thoughts I had while reading the comments. Maybe they can help to make the comments a little more clear.

lib/Transform/DeLICM.cpp
381 ↗(On Diff #95146)

Nice. Can you possibly add a comment that repeats the information that "Written values that cannot be identified are represented by an unknown ValInst[] (an unnamed tuple of 0 dimension). It conflicts with itself. " and add a comment that more details can be found in the documentation for known?

633 ↗(On Diff #95146)

conflicting -> conflict

635 ↗(On Diff #95146)

I was confused why you wrote "element / lifetime interval", as I did not understand if these were identical terms for the same thing or different things. Maybe you can clarify in half a sentence what element and lifetime mean here. Maybe something like:

"In order to not conflict, one of the following conditions must apply for each element or each lifetime. (We reason about single elements in case ... and about lifetimes in case ...)"

641 ↗(On Diff #95146)

I am surprised you formulate this as symmetric condition. The code below does not seem to be symmetric, as it does not even look at Proposed.Unused. Meaning, it would not return true if a value is in Existing.Occupied and not in Proposed.Unused. For me, it would probably have been easier to understand if the comment would be formulated closer to the asymmetric check the code performs.

E.g., something like the following:

In order to not conflict, one of the following conditions must apply:

1. If occupied in Proposed, it is unused in Existing

2. If occupied in Proposed and occupied in Existing, the Known value in proposed must match the known value in Existing.

If the behavior is indeed symmetric, it might make sense to mention this afterwards and explain why the asymmetric code indeed results in symmetric behavior.

645 ↗(On Diff #95146)

conditions -> condition
will also apply -> also applies

I did not understand what you mean by "Instead of partitioning the lifetimes into a part occupied by both". I would probably have calculated this as:

+    auto KnownIdentical = Proposed.Known.intersect(Existing.Known).domain();
+    auto ProposedOccupied = Proposed.Occupied.subtract(KnownIdentical);
+    if (!ProposedOccupied.is_subset(Existing.Unused)) {

This has the benefit that we do not affect compile time for cases where no Known information is available. Also, this 'unknown' stuff does not need to be explained. Was there a reason you did not take this approach?

If you found cases where such a subtract would become too expensive, it would be good to have a such a test case committed and describe both the simple and the more complex solution as well as the reason why the more complex solution was taken.

646 ↗(On Diff #95146)

Not sure what you mean by "the value occupying Proposed"?

650 ↗(On Diff #95146)

Has this later check already been committed? Are you indeed referring to a later commit, or just to the line where SomeVal is computed?

657 ↗(On Diff #95146)

What does SomeVal mean?

660 ↗(On Diff #95146)

I initially thought you could just compare ProposedValues and ExistingValues directly, but a problem arises in situations where values are known in Proposed and unused in Existing. In this case the ProposedValues are not a subset of the ExistingValues, even though the Proposed Knowledge is indeed not conflicting with the Existing Knowledge. It would be nice to explain this situation.

unittests/DeLICM/DeLICMTest.cpp
244 ↗(On Diff #95146)

Can you add test cases:

EXPECT_TRUE(checkIsConflictingKnown(
   {"{ Dom[i] -> [] }", nullptr, "{}"},
   {"{ Dom[i] -> [] }", nullptr, "{}"}
));

Hi Michael,

it also seems as if as part of this commit and the next two commits you exploit more of the new isl C++ bindings in isConflicting. It might make sense to just have a first [NFC] which switches the complete function over and commit this change ahead of time. In general, after the C++ bindings are now mostly through, it seems we can be more free in moving parts of Polly over. At least from my perspective, patches that just move parts of Polly step by step to the new bindings are in such obvious cases as here probably OK to commit even without pre-commit review.

Meinersbur marked 8 inline comments as done.Apr 24 2017, 5:54 PM
Meinersbur added inline comments.
lib/Transform/DeLICM.cpp
381 ↗(On Diff #95146)

Note that a more detailed explanation of what "ValInst" means is part of the makeValInst documentation in D31247.

I expanded the comment here anyway.

635 ↗(On Diff #95146)

The domain has the form `[Element[] -> Zone[]]` which I tried to express as "element / lifetime interval". I.e. the cross product, not the union as I would understand from your suggestion.

I'll try to reformulate.

641 ↗(On Diff #95146)

The conceptional behavior of isConflicting is indeed symmetric, as tested by DeLICMTests.

Asymmetry comes in because "Existing" defines occupied, but "Proposed" defines unused, which was done to avoid a complement operation.

The comment first describes what the code intends to do (which is as mentioned symmetric) and then how this behavior was implemented.

I'd be very confused if it was the other way around. How can I understand an implementation without knowing what it was supposed to do? That could be called reverse engineering.

645 ↗(On Diff #95146)

Your code does exactly what I described in "instead of ..." part. I added a test case where the subtract would blow up.

If Known is empty, the unites just return the Unused/Occupied set. No additional cost.

650 ↗(On Diff #95146)

removed

657 ↗(On Diff #95146)

Renamed to MatchingVals

unittests/DeLICM/DeLICMTest.cpp
244 ↗(On Diff #95146)

This is identical to

EXPECT_TRUE(checkIsConflicting({"{ Dom[i] }", nullptr, "{}"},
                               {"{ Dom[i] }", nullptr, "{}"}));

at line 118.

Meinersbur retitled this revision from [Polly][DeLICM] Use Known information when comparing Existing.Occupied and Proposed.Occupied. NFC. to [Polly][DeLICM] Use Known information when comparing Existing.Occupied and Proposed.Occupied..Apr 24 2017, 5:54 PM
Meinersbur edited the summary of this revision. (Show Details)
Meinersbur updated this revision to Diff 96491.Apr 24 2017, 6:41 PM
Meinersbur marked 5 inline comments as done.

Addressed Tobias' comments.

grosser accepted this revision.Apr 24 2017, 9:10 PM

lgtm

lib/Transform/DeLICM.cpp
379–380 ↗(On Diff #96491)

BE represented

684 ↗(On Diff #96491)

these TO check

This revision is now accepted and ready to land.Apr 24 2017, 9:10 PM
This revision was automatically updated to reflect the committed changes.