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
Core: Add IsTerminator trait #1080
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Happy to see that coming!
xdsl/ir.py
Outdated
"Operation with block successors must terminate its parent block" | ||
) | ||
|
||
if not self.has_trait(IsTerminator): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (len(self.successors) > 0 -> has_trait(IsTerminator)
) should be checked even if the operation has no parents right?
Should we move this higher up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, is there a point in checking for the terminator conditions if the operation is not part of some control flow (i.e., in a block and region?
I moved the condition up and then got verification errors from things like this.
I can fix those tests, but I'm unsure what we want here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@math-fehr I ended up moving the condition for has_trait(IsTerminator)
one indentation level since indeed there was an implicit assumption that a terminator must have successors, which is indeed not the case.
But my point regarding control flow (i.e., not belonging to a block/region) still stands; or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm that's a good question. It turns out that you cannot jump to the entry block, so technically it is not allowed.
We don't raise an error yet, the question is where should we raise an error.
I believe we should raise it here, as it reduce the amount of corner cases we have (otherwise, we rely on another verification pass to handle that case, and I feel this is very error-prone if that makes sense).
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a good point to "piggyback" this check here.
Hence, I'll just check separately that if an operation has successors and doesn't belong to a parent block or region, then it should fail verification.
This is regardless of the IsTerminator
trait.
After this, we can continue with the current verification logic and enhance/supplement it with the follow-up NoTerminator
trait patch.
3f2cea3
to
d5fca71
Compare
) is not None: | ||
# TODO single-block regions dealt when the NoTerminator trait is | ||
# implemented (https://github.com/xdslproject/xdsl/issues/1093) | ||
if len(parent_region.blocks) > 1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case where there is a single block, we still need to check that an operation that is not the last does not have a successor (with or without NoTerminator
), right?
Or is it different since you technically are not allowed to jump to the entry block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is right but I was thinking it might be simpler to check for both cases when the NoTerminator
trait is implemented. I guess the branching off for a non-last op is irrelevant to that, so we can just test it now.
Am I understanding correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed my mind on this, it's simpler and more clear to check that an operation should not have successors unless it is the last operation in its parent block (regardless of the number of blocks in the parent region or the existence of the NoTerminator
trait.
The PR is now updated to reflect this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks a lot
No problem, thanks for the input; I'll address your remaining feedback and ping you again. |
Regarding the failing filecheck My idea here was to add a |
Seems that graph regions broke in the tests |
I commented on this above, although now I think this is not what we might want. It seems the graph regions are limited to a single basic block, so this might be a clue towards a solution. |
Oh, I see what happened! |
…ess of number of blocks in a region
1cbfc6e
to
b669515
Compare
@math-fehr I think I have addressed all comments now. |
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #1080 +/- ##
==========================================
+ Coverage 86.95% 87.00% +0.05%
==========================================
Files 137 137
Lines 20676 20774 +98
Branches 3128 3143 +15
==========================================
+ Hits 17979 18075 +96
- Misses 2179 2180 +1
- Partials 518 519 +1
☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thanks a lot, that looks good to me!
@webmiche @superlopuh, is that good for you as well? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that I don't like, though that is probably an MLIR design issue, is that the IsTerminator trait is very closely coupled into the core datastructures now. So no block can be without a terminator essentially. This makes the dependencies within the code very hard to follow and couples different parts very closely together. To me, that is particularly apparent by the fact that you added two kinds of tests in this PR.
That's all to say, nice to have this in, I think we really need this and I think we can merge. But I will reserve the right to change this coupling at some point, if we manage to design this cleaner than MLIR does.
I mostly agree with this. When I started this, I wanted to implement everything in the trait's Regardless of these deficiencies, I like the additional verification they provide. |
This PR implements the [`IsTerminator`][3] trait. It is a spinoff of the discussion [here][1] and specifically [this][2] recommendation regarding the initial (and pending) attempt to add the `NoTerminator` trait. [1]: xdslproject#1049 [2]: xdslproject#1049 (comment) [3]: https://mlir.llvm.org/docs/Traits/#terminator
This PR adds the
IsTerminator
trait.It is a spinoff of the discussion here and specifically this recommendation regarding the initial (and pending) attempt to add the
NoTerminator
trait.