-
Notifications
You must be signed in to change notification settings - Fork 100
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][Codegen] IfOp flattening #537
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.
Mostly LGTM, one comment before we move forward.
The last cir.return becomes unreachable after flattening and hence is not reachable in the lowering
I see two options:
- Add a cleanup pass that removes unrecheable blocks before LLVM lowering. I believe https://mlir.llvm.org/docs/Passes/#-canonicalize does that.
- Lowering should also look at unrechable blocks?
Thus, I added lowering for the unreachable code as well in LowerToLLVM.cpp
(2) sounds good, it's correct, but (1) would be more compiler friendly (we likely don't want to spend compilation time lowering pieces we don't care about). Before we go on with collect_unreachable
, can you check whether adding canonicalize to the lowering pipeline could fix the problem?
And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR?
I believe so but I haven't tried to use just yet, I could be wrong.
The part of IfOp lowering related to elimination of the vain casts for condition branch moved directly to the lowering of BrCondOp with some refactoring and guarding.
Ok.
Just note, that now cir-opt is able to dump the flat cir as well: cir-opt -cir-flat-cfg
Nice.
At the first glance the First of all, ~30 lowering tests fails - maybe it's not a problem, but anyway just want to let you know. For example, the next test (alloca.cir);
fails because Next, take a look how the llvm dialect looks like for the example from the PR message (after the pass applied):
But I ran the codebase I use for work with CIR (e.g. gcc code) and got around 1000 new errors like:
So let's come back again to the choice - which one do you prefer? if it's still the first one - I start to investigate a new bug. so, what do you think? |
@bcardosolopes & @gitoleg, I have a question in mind regarding this discussion: What is our current approach to dealing with unreachable code? Do we want CIRGen to emit it into CIR for some reason, or would it be preferable to eliminate it as soon as possible to prevent passes from dealing with errors related to it?
@gitoleg it might be better to add this DCE pass right after codegen instead so that it does not affect any of the existing CIR to LLVM lowering tests. |
@sitio-couto
The problem is that unreachable code may be introduced by flattening as well. Previously, when all the region inlining was done during the lowering, the unreachable code also could be introduced but it was llvm dialect code, so no complains from the verification happened. Now, when unreachable code is CIR one, it won't be lowered because the code processed in the dominance order where unreachable blocks doesn't participate. Hence, the problem. And now we need to decide how to handle the unreachable code. |
Yea, this is not a new problem, before we had our merge cleanup pass, I tried to use the canonicalizer but it was too aggressive. We can probably fix that by making sure more operations has side-effects, so it wouldn't eliminate as much.
Oh =(
Unreachable code should live until before lowering prepare: at some point we want to use CIR for producing unrecheable warnings in clang.
See my reply above.
I think we should use |
@bcardosolopes |
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.
Good job on the extra explanation comment, LGTM
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in #516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in #516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in #516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for `cir::IfOp` Basically, we just move the code from `LowerToLLVM.cpp` to `FlattenCFG.cpp`. There are several important things though I would like to highlight. 1) Consider the next code from the tests: ``` cir.func @foo(%arg0: !s32i) -> !s32i { %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool cir.if %4 { %5 = cir.const(#cir.int<1> : !s32i) : !s32i cir.return %5 : !s32i } else { %5 = cir.const(#cir.int<0> : !s32i) : !s32i cir.return %5 : !s32i } cir.return %arg0 : !s32i } ``` The last `cir.return` becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error: ``` error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for' cir.return %arg0 : !s32i ``` the parent after lowering is `llvm.func`. And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in `LowerToLLVM.cpp`. But may be you have another solution in your mind. 2) Please, pay attention on the flattening pass - I'm not that familiar with `mlir` builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations. 3) As you requested in #516, `cir-to-llvm-internal` is renamed to `cir-flat-to-llvm`. The only thing remain undone is related to the following: > Since it would be wrong to run cir-flat-to-llvm without running cir-flatten-cfg, we should make cir-flat-to-llvm pass to require cir-flatten-cfg pass to be run before. And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR? 4) The part of `IfOp` lowering related to elimination of the vain casts for condition branch moved directly to the lowering of `BrCondOp` with some refactoring and guarding. 5) Just note, that now `cir-opt` is able to dump the flat cir as well: `cir-opt -cir-flat-cfg`
This PR perform flattening for
cir::IfOp
Basically, we just move the code from
LowerToLLVM.cpp
toFlattenCFG.cpp
.There are several important things though I would like to highlight.
The last
cir.return
becomes unreachable after flattening and hence is not reachable in the lowering. So we got the next error:the parent after lowering is
llvm.func
.And this is only the beginning - the more operations will be flatten, the more similar fails will happen. Thus, I added lowering for the unreachable code as well in
LowerToLLVM.cpp
. But may be you have another solution in your mind.Please, pay attention on the flattening pass - I'm not that familiar with
mlir
builders as you are, so may be I'm doing something wrong. The idea was to start flattening from the most nested operations.As you requested in [CIR] Introduce a flattening pass #516,
cir-to-llvm-internal
is renamed tocir-flat-to-llvm
. The only thing remain undone is related to the following:And I'm not sure I know how to do it exactly - is there something similar to pass dependencies from LLVM IR?
The part of
IfOp
lowering related to elimination of the vain casts for condition branch moved directly to the lowering ofBrCondOp
with some refactoring and guarding.Just note, that now
cir-opt
is able to dump the flat cir as well:cir-opt -cir-flat-cfg