================
@@ -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

Reply via email to