-
Notifications
You must be signed in to change notification settings - Fork 85
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
[CIR] Introduce CIR simplification #696
base: main
Are you sure you want to change the base?
Conversation
Sorry I didn't had the time to look just yet, but should do that soon, can you update post rebase? |
@bcardosolopes updated! |
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 PR introduce cir simplification pass. The idea is to have a pass for the redundant operations removal/update.
Right now two pattern implemented, both related to the redundant
bool
operations. First pattern removes redundant casts frombool
toint
and back that for some reasons appear in the code. Second pattern removes sequential unary not operations (!!
) .
Neat!
- I have no idea if it's useful for the community
Definetely great to get rid of these chains of redundant casts.
- There is a test fail - unfortunately current pattern rewriter run DCE underneath the hood and looks like we can't workaround it.
Is this something related to the same issues we see with the canonicalizer? Is it worth adding this case to the bug tracking it?
It's enough just to add an operation to the list - in this case
UnaryOp
- and callapplyOpPatternsAndFold
. I could rewrite a test a little in order to make everything non dead or implement a simple fix point algorithm for the particular task (I would do the former).
Former is a fine solution, I'm a bit worried about the overall approach though (more comments inline), I think we should try as much as possible to fix some of these problems at the MLIR level if necessary, I'm afraid those will keep piling up and might accumlate be too much technical debt in the future (e.g. CIR reinventing the wheel to workaround MLIR issues). Thoughts?
}; | ||
|
||
class SimplifyBoolCasts : public mlir::OpRewritePattern<mlir::cir::CastOp> { | ||
|
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.
Any specific reason why can't this be implemented in CastOp::fold
?
}; | ||
|
||
class SimplifyUnaryNot : public mlir::OpRewritePattern<mlir::cir::UnaryOp> { | ||
|
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.
Similar question for UnaryOp, can't that be done with fold
method?
}; | ||
|
||
void CIRSimplifyPass::runOnOperation() { | ||
RewritePatternSet patterns(&getContext()); |
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.
If we need to create a new pass (after we go over the other comments), perhaps this is a good opportunity to rename MergeCleanups to CIRSimplify and add this over there instead.
@bcardosolopes
but anyway got a type error. Maybe I'm doing something wrong though and didn't get how I should work wtih folders. Another thought is that from the future optimizations point of view, I would have CIR simplified as much as we can do it, and better to do it explicit with the pass, than implicit with
I would say it's not a bug, it's a feature!! which may hit us only in tests. It's slightly remind us the case with the canonicalizer since it also run the version of To summarize:
|
From the canonicalization docs:
In this case sounds like it wouldn't be a problem for the folder for
Simplifications might work better in face of canonicalized IR, but it's a blurry line sometimes where things should live. In the
MergeCleanups is not about My overall feedback is that I want to see the same optimizations you are trying to implement. But my feedback for this PR is that such simplification is doing too much in one place, pieces should be more independent, behave more like traditional |
!s32i = !cir.int<s, 32> | ||
!s64i = !cir.int<s, 64> | ||
module { | ||
cir.func @foo(%arg0: !cir.ptr<!s32i>) { |
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.
What's the C code corresponding to this? Add a C code test instead with what you want to optimize.
For a cir-opt
tests, better to split into two really simple CIR functions, each one testing the specific opt, so it's pretty clear you are adding coverage for different individual peepholes.
@@ -155,28 +155,28 @@ int *inc_p(int *i) { | |||
|
|||
void floats(float f) { | |||
// CHECK: cir.func @{{.+}}floats{{.+}} | |||
+f; // CHECK: %{{[0-9]+}} = cir.unary(plus, %{{[0-9]+}}) : !cir.float, !cir.float | |||
-f; // CHECK: %{{[0-9]+}} = cir.unary(minus, %{{[0-9]+}}) : !cir.float, !cir.float | |||
f = +f; // CHECK: %{{[0-9]+}} = cir.unary(plus, %{{[0-9]+}}) : !cir.float, !cir.float |
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.
Do you need to change the source here because otherwise these operations are removed? Does everything else in the function touching f
gets removed or just this one? Perhaps the function should return a float instead so that the value is used? If simplification is getting too aggresive, perhaps we should instead tie it up with O1
or higher, because -O0
shouldn't delete as much operations. Example: https://godbolt.org/z/6zP7qnjdP
%10 = cir.cast(int_to_bool, %9 : !s32i), !cir.bool | ||
%11 = cir.unary(not, %10) : !cir.bool, !cir.bool | ||
%12 = cir.cast(bool_to_int, %11 : !cir.bool), !s32i | ||
%13 = cir.cast(integral, %12 : !s32i), !s64i |
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.
The opt logic seems not to take into account integer promotion happening with casts here, which could be unsafe. Depending on the pattern you are trying to get rid off, it might be better to make sure CIRGen gets it right out of the bat.
This PR introduce cir simplification pass. The idea is to have a pass for the redundant operations removal/update.
Right now two pattern implemented, both related to the redundant
bool
operations.First pattern removes redundant casts from
bool
toint
and back that for some reasons appear in the code.Second pattern removes sequential unary not operations (
!!
) .For example, the code from the test is expanded from the simple check that is common for C code:
I mark this PR as a draft for the following reasons:
It's enough just to add an operation to the list - in this case
UnaryOp
- and callapplyOpPatternsAndFold
. I could rewrite a test a little in order to make everything non dead or implement a simple fix point algorithm for the particular task (I would do the former).