This is an alternative to D97915.
Background: The alignment for ::operator new(size_t) would be 16 generally, which would be used to allocate memories for coroutine frame. But if there is variables requiring more alignment in the frame, it may be possible that the variable may not get align correctly. One solution would be searching ::operator new(size_t, align_val_t) in the front end. But it requires the support from the language side. Another solution is to do over align by the compiler. By allocate llvm.coro.size() + frame_align - new_align, we could make sure that the frame must could get aligned correctly in the over allocated storage. To avoid memory leak, we need one extra fields in the frame to store the address of allocated storage.
The main differences for this diff with D97915 are:
- Add only one extra optional coroutine intrinsics in switch style.
- Make the main work to over-align coroutine frame in CoroFrame.cpp.
The first point may be more important. Since coroutine language intrinsics is a language itself. Although it looks like that the switch style is used by C++ coroutine only, from the design it could and should be used by other languages easily. So less the intrinsics we add, the more clear the coroutine intrinsics would be. And I guess the extra intrinsic added in this diff may be more easy for user to use. If the user need to over align the frame due to limited allocator's alignment, it could emit one coro.overalign for the allocated memory and set the corresponding limited alignment. And every thing would be the same if the user doesn't need it.
The second point makes this diff more easy to review and edit.
Test Plan: check-llvm, https://gcc.godbolt.org/z/rGzaco, https://gcc.godbolt.org/z/W3ocj778M
Another question: if it is possible that we add the tests into the llvm? It looks like the test and unit test can't check the runtime behavior. I know there are slow tests in CI system, how could I edit that?
The reason why that I don't support ::operator new(size_t, align_t) is that I am confused about the detailed semantics. For example, it the user provides two allocator, which one should be chosen? If we think it could be chosen by the compiler. Another question is that, do we need to consider both of the allocator if the user doesn't provide two of them? For example, if the user provides promise_type::operator new(size_t) only, need we consider ::operator new(size_t, align_t)? Or if the user provides promise_type::new(size_t, align_t), do we still need to consider ::operator new(size_t)? I feel there must be decisions to make. I know it is easy to make a decision. But I think it is hard to get in consensus. So I don't support operator new(size_t, align_t).
But I think it should not be hard to support them based on this diff. For example, let's define the two expression:
Expr *AlignedAllocator; Expr *AlignedDeallocator;
Then we need to initialize them in the Sema part. And in the CodeGen part, we could do:
Alloc: ; controlled by `llvm.coro.alloc` %aligned = call i1 @llvm.coro.aligned() br %aligned, label %align_alloc, label %normal_alloc ; ... Dealloc: ; controlled by the null ness of `llvm.coro.free` br %aligned, label %align_dealloc, label %normal_dealloc
Then in the middle end, we could replace the value for llvm.coro.aligned simply.
clang-tidy: warning: 'auto CF' can be declared as 'auto *CF' [llvm-qualified-auto]
not useful