This is an archive of the discontinued LLVM Phabricator instance.

[MLIR][FlatAffineConstraints] Remove duplicate divisions while merging local ids
ClosedPublic

Authored by Groverkss on Oct 30 2021, 12:53 AM.

Details

Summary

This patch implements detecting duplicate local identifiers by extracting their
division representation while merging local identifiers.

For example, given the FACs A, B:

A: (x, y)[s0] : (exists d0 = [x / 4], d1 = [y / 4]: d0 <= s0, d1 <= s0, x + y >= 2)
B: (x, y)[s0] : (exists d0 = [x / 4], d1 = [y / 4]: d0 <= s0, d1 <= s0, x + y >= 5)

The intersection of A and B without this patch would lead to the following FAC:

(x, y)[s0] : (exists d0 = [x / 4], d1 = [y / 4], d2 = [x / 4], d3 = [x / 4]: d0 <= s0, d1 <= s0, d2 <= s0, d3 <= s0, x + y >= 2, x + y >= 5)

after this patch, merging of local ids will detect that d0 = d2 and d1 = d3,
and the intersection of these two FACs will be (after removing duplicate constraints):

(x, y)[s0] : (exists d0 = [x / 4], d1 = [y / 4] : d0 <= s0, d1 <= s0, x + y >= 2, x + y >= 5)

This reduces the number of constraints by 2 (constraints) + 4 (2 constraints for each extra division) for this case.

This is used to reduce the output size representation of operations like
PresburgerSet::subtract, PresburgerSet::intersect which require merging local
variables.

Diff Detail

Event Timeline

Groverkss created this revision.Oct 30 2021, 12:53 AM
Groverkss requested review of this revision.Oct 30 2021, 12:53 AM
Groverkss edited the summary of this revision. (Show Details)Oct 30 2021, 12:56 AM
Groverkss updated this revision to Diff 383682.Oct 31 2021, 2:26 PM
  • Fix formatting errors
Groverkss updated this revision to Diff 383685.Oct 31 2021, 2:34 PM
  • Update docs for mergeLocalIds
arjunp requested changes to this revision.Nov 1 2021, 7:40 AM

Hi, thanks for this patch. Maybe you can add a line at the end of the patch summary about why this is important, e.g. mentioning that when operating on sets with many divisions, it is common for blowups in the number of variables to occur, which this heuristic prevents.

mlir/include/mlir/Analysis/AffineStructures.h
445

This looks like an implementation detail that doesn't need to be described here (extracting div representations). I would just say "local ids with identical division representations are merged".

447

Please write complete sentences: "The number of dimensions and symbol ids should..."

539

nit: representationS

539

What is a local representation? Do you mean a division representation?

540

nit: tildes for i^th but not denominator[i]?

542

Why std::vector here?

mlir/lib/Analysis/AffineStructures.cpp
1379

I think factoring out this function should be done in a separate commit.

1921–1950

There seem to be a multitude of different functions related to obtaining division representations. Are they all really needed? Can we factor out common functionality from them?

This revision now requires changes to proceed.Nov 1 2021, 7:40 AM
Groverkss updated this revision to Diff 385325.Nov 6 2021, 11:12 PM
Groverkss marked 3 inline comments as done.
  • Move division representation to a common function
  • Update docs
Groverkss marked 4 inline comments as done.Nov 6 2021, 11:16 PM

Addressed most comments.

mlir/include/mlir/Analysis/AffineStructures.h
542

I remember @bondhugula recommending not to use SmallVector<SmallVector> although I may be wrong. If you think I should use SmallVector instead, let me know.

bondhugula added inline comments.Nov 7 2021, 7:54 AM
mlir/include/mlir/Analysis/AffineStructures.h
542

SmallVector isn't really optimized to hold another SmallVector I had heard. Just using std::vector here would be fine.

arjunp added inline comments.Nov 7 2021, 11:22 AM
mlir/include/mlir/Analysis/AffineStructures.h
160–172

The dividend -> The dividends

162

For this overload, maybe mention that the denominator will be set to zero if no representation could be found.

163–164

nit: dividends is plural but denominator is singular?

445–446

nit: I think "The number of dimensions and symbol ids in this and other should match" reads more naturally

542

Maybe you could use Matrix here, if you want.

mlir/lib/Analysis/AffineStructures.cpp
1476–1495

I think this refactor can also be moved into a separate patch

1494–1499

Maybe it would be nicer for the users if we just resize it internally and don't require it to be initialized to that size.

1921–1950

Please explain what this is doing in more detail. At the moment, someone looking at this function has no idea what it has to do with divisions? Maybe add a note saying it's intended to be used to remove redundancy when we have local variables that always take the same values. Or you can just call it mergeLocals. BTW, we are now using "merge" with a different meaning in mergeLocalIds and here, which could get confusing. You could call this one, e.g., eliminateRedundantLocalId.

1963

nit: why 8 above and 4 here?

1988
1990
1992
1995
1998
2001

I don't understand why this is needed. If they both depend on the same local variables in the same way, they should still always take the same values and should be able to be merged right? (the ith local variable here, is the same in both now after merging, right?)

mlir/unittests/Analysis/AffineStructuresTest.cpp
814

nit: z, y is counterintuitive when trying to read the coefficients. Writing the constraint in a comment next to each line would help improve readability.

Groverkss updated this revision to Diff 385621.Nov 8 2021, 1:46 PM
Groverkss marked 15 inline comments as done.
  • Address arjun's comments
  • Update tests for mergeLocalIds

Addressed @arjunp's comments.

mlir/lib/Analysis/AffineStructures.cpp
1963

My reasoning was that denoms only has columns for local ids while a division has columns for all ids. Usually, I would not expect local variables to exceed 3-4.

2001

I don't remember the reason why I did not consider such cases. But I don't find any now so I think I'll remove it.

Groverkss updated this revision to Diff 385629.Nov 8 2021, 2:02 PM
  • Update docs
Groverkss marked an inline comment as done.Nov 9 2021, 12:55 AM
Groverkss updated this revision to Diff 386100.Nov 10 2021, 2:19 AM
  • Fix clang-format errors
arjunp added inline comments.Nov 11 2021, 8:57 AM
mlir/lib/Analysis/AffineStructures.cpp
1928–1929

Less than or equal to? Shouldn't this be strict?

2014–2015

Use range-based for here?

2014–2020

I see you added some test cases. Did you add one that was failing before this change?

Groverkss marked 3 inline comments as done.
  • Fix asserts as suggested by Arjun
Groverkss added a comment.EditedNov 11 2021, 12:10 PM

Addressed @arjunp's comments

mlir/lib/Analysis/AffineStructures.cpp
1928–1929

Yes, thanks for catching this.

2014–2015

I don't think I can use range-based for loops here since I need to check if the division representation actually exists using denoms.

2014–2020

No, I think they worked before. I had previously assumed that local ids wouldn't be checked when checking for the same division. To allow local ids too, I had to add change some functionality and required more tests.

arjunp added inline comments.Nov 12 2021, 7:36 AM
mlir/lib/Analysis/AffineStructures.cpp
1925
1951

A top-level comment to explain what is being done would be useful.

1966–1969

It only makes sense to use division information if the division inequalities actually get added to both sets here, right?

1970–1985

I think it's better to first insert locals in the FACs and then get the local representation, then you can skip the extra insertions into divs1 and divs2 here.

Also, if we are actually adding the division constraints, then you can skip the appending at the end and just get the div repr from any on of the sets. In fact, then you can factor out removing redundant divs into a separate function. Such a function would anyway be useful in other contexts as well. There might be a little bit of duplicated work in detecting redundancies but thinking about that right now is probably premature optimization.

1985

If you want, you can use SmallVector::append here

1996
2001
2008

Just use operator !=?

2024

Might be useful to put a comment saying this is fine because j is never zero here.

mlir/unittests/Analysis/AffineStructuresTest.cpp
885
889
914

Is the denominator supposed to be 2 or 3?

920

Same here, 2 or 3?

Groverkss marked 13 inline comments as done.Nov 12 2021, 2:58 PM

Addressed @arjunp's comments.

mlir/lib/Analysis/AffineStructures.cpp
1951

The doc comment for this function is in the include file. I checked with others on discord and was recommended keeping doc comments in the header file only (for functions that are documented in the header file).

Are you asking for something else?

1966–1969

No, I think we can use the division information without actually adding the division inequalities. mergeLocalIds is only used to align local ids. Its only use is to allow comparing inequalities between two sets. Adding division constraints has no real use there.

1970–1985

This cannot be done unless division constraints are added to each set from the other, which I personally think is unnecessary :/

1985

It's not really appending. It's inserting before the coefficient for the constant.

Groverkss updated this revision to Diff 386960.Nov 12 2021, 2:58 PM
Groverkss marked 4 inline comments as done.
  • Addressed more comments
arjunp added inline comments.Nov 15 2021, 1:00 PM
mlir/include/mlir/Analysis/AffineStructures.h
444–454

I think the meanings of both "merge" and "align" are a little bit mysterious here. How about this:

Adds additional local ids to the sets such that they both have the union of the local ids in each set, without changing the set of points that actually lie in `this` and `other`. The orderings of the local ids in the sets may also be changed.

The number of dimensions and symbol ids in `this` and `other` should match.

Also, please update the documentation of mergeAndAlignIds, it currently says all local ids of A will appear before all local ids of B, which is not true anymore.

mlir/lib/Analysis/AffineStructures.cpp
1951

Yes, I meant a comment giving a high-level explanation of the implementation of the function. (Whereas the header has an explanation of when/why/how to use the function.)

1970–1985

You can still do the first part I guess, but then you would first have to erase the suffix of divs1 and denoms1 corresponding to the newly added locals which have no representation in the first set, and then append their representations from the second set. I leave it to you to decide if that's better or not

1985

It's not really appending. It's inserting before the coefficient for the constant.

I don't understand. I'm saying you could do

denoms1.append(denoms2) instead of
denoms1.insert(denoms1.end(), denoms2.begin(), denoms2.end());

Groverkss updated this revision to Diff 388186.Nov 18 2021, 6:53 AM
Groverkss marked 4 inline comments as done.

Rebase and address @arjunp's comments

mlir/include/mlir/Analysis/AffineStructures.h
444–454

Added this doc comment with some addition which I think is useful:

The ordering of the local ids in the sets may also be changed but is the same in both sets.
arjunp added inline comments.Nov 18 2021, 7:07 AM
mlir/include/mlir/Analysis/AffineStructures.h
444–454

I guess the question is, what is meant by "same in both sets". In what sense are two local ids same?

Maybe you can rather replace it with something like this:

The ordering of the local ids in the sets may be changed. After merging, if the ith local variable in one set has a known division representation, then the ith local variable in the other set either has the same division representation or no known division representation.

Groverkss marked an inline comment as done.Nov 18 2021, 7:34 AM
Groverkss updated this revision to Diff 388199.Nov 18 2021, 7:34 AM
  • Fix doc comment for mergeLocalIds.
arjunp accepted this revision.Nov 18 2021, 7:45 AM

LGTM!

mlir/lib/Analysis/AffineStructures.cpp
1973
1986
This revision is now accepted and ready to land.Nov 18 2021, 7:45 AM
Groverkss updated this revision to Diff 388230.Nov 18 2021, 9:04 AM
Groverkss marked an inline comment as done.
  • Addressed comments
This comment was removed by Groverkss.
Groverkss marked an inline comment as done.Nov 18 2021, 9:06 AM

Addressed suggested changes.

Thank you @arjunp for the review and helpful comments!

I'll wait for @bondhugula before landing in case he has any comments.

@bondhugula gentle ping. could you take a look at this patch? :)

bondhugula accepted this revision.Dec 2 2021, 8:36 AM
bondhugula added inline comments.
mlir/lib/Analysis/AffineStructures.cpp
496–498

The last sentence may be a bit unclear - rephrase along the lines of the other doc comment above.

1957–1958

Nit: Consider using facA and facB. Numbered suffixes aren't great in that it isn't clear if they are 0-based or 1-based.

1977–1980

Likewise.

Groverkss updated this revision to Diff 391446.Dec 2 2021, 1:40 PM
Groverkss marked 3 inline comments as done.
  • Address bondhugula's comments
This comment was removed by Groverkss.
This revision was landed with ongoing or failed builds.Dec 2 2021, 2:18 PM
This revision was automatically updated to reflect the committed changes.
Mogball added a subscriber: Mogball.Dec 2 2021, 2:40 PM

@Groverkss Please squash your commits next time :S

@Groverkss Please squash your commits next time :S

Sorry for that! I accidentally sent the commits directly instead of sending them from arcanist which caused that. I reverted them and send them correctly. Will not let this happen again :(

MaskRay added a subscriber: MaskRay.Dec 2 2021, 5:21 PM

There are many fix-up commits which seem to should be in one change.

You may find llvm/utils/git/pre-push.py useful.

There are many fix-up commits which seem to should be in one change.

You may find llvm/utils/git/pre-push.py useful.

To be clear, please do this: https://llvm.org/docs/GettingStarted.html#git-pre-push-hook

@Groverkss Please squash your commits next time :S

Sorry for that! I accidentally sent the commits directly instead of sending them from arcanist which caused that. I reverted them and send them correctly. Will not let this happen again :(

I use the workflow here to commit (instead of using arc to land) and always keep my revision commit as a single one on which arc diff is repeatedly used to update to phab:
https://llvm.org/docs/GettingStarted.html#for-developers-to-commit-changes-from-git