================
@@ -706,13 +706,22 @@ mlir::LogicalResult CIRGenFunction::emitGotoStmt(const
clang::GotoStmt &s) {
mlir::LogicalResult
CIRGenFunction::emitIndirectGotoStmt(const IndirectGotoStmt &s) {
+ // An indirect goto that branches out of a scope needing cleanup (a VLA stack
+ // restore or a non-trivial destructor on the edge) must run that cleanup on
+ // the branch. That is not implemented, so report it rather than emit a
+ // branch that silently skips the cleanup.
+ if (ehStack.stable_begin() != prologueCleanupDepth) {
+ cgm.errorNYI(s.getSourceRange(), "indirect goto across a cleanup scope");
----------------
Andres-Salamanca wrote:
>From my understanding, the IR would look something like the example below,
>using a `cir.cleanup.scope`.
```mlir
cir.func @_Z3vlai(%arg0: !s32i) -> (!s32i){
%0 = cir.alloca "n" align(4) init : !cir.ptr<!s32i>
%1 = cir.alloca "__retval" align(4) : !cir.ptr<!s32i>
%2 = cir.alloca "saved_stack" align(8) : !cir.ptr<!cir.ptr<!u8i>>
%blkadd = cir.alloca "p" align(8) init : !cir.ptr<!cir.ptr<!void>>
loc(#loc38)
cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
%3 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
%4 = cir.cast integral %3 : !s32i -> !u64i
%5 = cir.stacksave : !cir.ptr<!u8i>
cir.store align(8) %5, %2 : !cir.ptr<!u8i>, !cir.ptr<!cir.ptr<!u8i>>
cir.cleanup.scope {
%6 = cir.alloca "a" align(16) size(%4) : !cir.ptr<!s32i>
%blkaddattr = cir.block_address <@_Z3vlai, "done"> : !cir.ptr<!void>
cir.store align(8) %blkadd, %blkadd : !cir.ptr<!void>,
!cir.ptr<!cir.ptr<!void>>
%reload= cir.load align(8) %blkadd : !cir.ptr<!cir.ptr<!void>>,
!cir.ptr<!void>
cir.indirect_goto %reload: !cir.ptr<!void>
^bb1: // no predecessors
cir.label "done"
%7 = cir.const #cir.int<0> : !s64i
%8 = cir.ptr_stride %6, %7 : (!cir.ptr<!s32i>, !s64i) -> !cir.ptr<!s32i>
%9 = cir.load align(16) %8 : !cir.ptr<!s32i>, !s32i
cir.store %9, %1 : !s32i, !cir.ptr<!s32i>
%10 = cir.load %1 : !cir.ptr<!s32i>, !s32i
cir.return %10 : !s32i
^bb2: // no predecessors
cir.yield
} cleanup normal {
%6 = cir.load align(8) %2 : !cir.ptr<!cir.ptr<!u8i>>, !cir.ptr<!u8i>
cir.stackrestore %6 : !cir.ptr<!u8i>
cir.yield
}
cir.trap
}
```
I don't see a problem with emitting this IR because `FlattenCFG` is responsible
for lowering `cir.cleanup.scope` and inserting the appropriate cleanup
execution paths. The important part is determining whether the
`cir.indirect_goto` leaves the cleanup scope. If it does, then the cleanup must
be executed, if it stays within the same cleanup scope, then there is no need
to run it.
In your example, the cleanup is actually triggered by the `cir.return`, not by
the `cir.indirect_goto` itself. The `cir.indirect_goto` only transfers control
to another block inside the same cleanup scope, so it is not responsible for
executing the cleanup.
That said, I don't mind keeping this check if we don't want to support this
case yet. My only point is that I don't think the IR is inherently incorrect at
this stage, since it is still expected to go through `FlattenCFG`, which should
handle the cleanup lowering correctly.
https://github.com/llvm/llvm-project/pull/206176
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits