[all-commits] [llvm/llvm-project] 7dccdd: [Coroutines] Don't mark the parameter attribute of...

Chuanqi Xu via All-commits all-commits at lists.llvm.org
Mon Dec 12 18:20:05 PST 2022


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 7dccdd76b3749508f4a4147b0ba1f7f2689bebb2
      https://github.com/llvm/llvm-project/commit/7dccdd76b3749508f4a4147b0ba1f7f2689bebb2
  Author: Chuanqi Xu <yedeng.yd at linux.alibaba.com>
  Date:   2022-12-13 (Tue, 13 Dec 2022)

  Changed paths:
    A clang/test/CodeGenCoroutines/pr59221.cpp
    M llvm/lib/Transforms/Coroutines/CoroSplit.cpp
    M llvm/test/Transforms/Coroutines/coro-debug-dbg.addr.ll
    M llvm/test/Transforms/Coroutines/coro-debug-dbg.values-not_used_in_frame.ll
    M llvm/test/Transforms/Coroutines/coro-debug-dbg.values.ll
    M llvm/test/Transforms/Coroutines/coro-debug.ll
    M llvm/test/Transforms/Coroutines/coro-frame.ll

  Log Message:
  -----------
  [Coroutines] Don't mark the parameter attribute of resume function as noalias

Close https://github.com/llvm/llvm-project/issues/59221.

The root cause for the problem is that we marked the parameter of the
resume/destroy functions as noalias previously. But this is not true.

See https://github.com/llvm/llvm-project/issues/59221 for the details.
Long story short, for this C++ program
(https://compiler-explorer.com/z/6qGcozG93), the optimized frame will be
something like:

```
struct test_frame {
    void (*__resume_)(), // a function pointer points to the
`test.resume` function, which can be imaged as the test() function in
the example.
    ....
    struct a_frame {
          ...
          void **caller; // may points to test_frame at runtime.
    };
};
```

And the function a and function test looks just like:

```
define i32 @a(ptr noalias %alloc_8) {
  %alloc_8_16 = getelementptr ptr, ptr %alloc_8, i64 16
  store i32 42, ptr %alloc_8_16, align 8
  %alloc_8_8 = getelementptr ptr, ptr %alloc_8, i64 8
  %alloc = load ptr, ptr %alloc_8_8, align 8
  %p = load ptr, ptr %alloc, align 8
  %r = call i32 %p(ptr %alloc)
  ret i32 %r
}

define i32 @b(ptr %p) {
entry:
  %alloc = alloca [128 x i8], align 8
  %alloc_8 = getelementptr ptr, ptr %alloc, i64 8
  %alloc_8_8 = getelementptr ptr, ptr %alloc_8, i64 8
  store ptr %alloc, ptr %alloc_8_8, align 8
  store ptr %p, ptr %alloc, align 8
  %r = call i32 @a(ptr nonnull %alloc_8)
  ret i32 %r
}
```

Here inside the function `a`,  we can access the parameter `%alloc_8` by
`%alloc` and we pass `%alloc` to an unknown function. So it breaks the
assumption of `noalias` parameter.

Note that although only CoroElide optimization can put a frame inside
another frame directly, the following case is not valid too:

```
struct test_frame {
    ....
   void **a_frame; // may points to a_frame at runtime.
};

 struct a_frame {
    void **caller; // may points to test_frame at runtime.
};
```

Since the C++ language allows the programmer to get the address of
coroutine frames, we can't assume the above case wouldn't happen in the
source codes. So we can't set the parameter as noalias no matter if
CoroElide applies or not. And for other languages, it may be safe if
they don't allow the programmers to get the address of coroutine frames.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D139295




More information about the All-commits mailing list