summaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGCoroutine.cpp
AgeCommit message (Collapse)Author
2025-04-03[CodeGen] Don't include CGDebugInfo.h in CodeGenFunction.h (NFC) (#134100)Nikita Popov
This is an expensive header, only include it where needed. Move some functions out of line to achieve that. This reduces time to build clang by ~0.5% in terms of instructions retired.
2025-02-28[Coroutines] Mark parameter allocas with coro.outside.frame metadata (#127653)Hans Wennborg
Parameters to a coroutine get copied (moved) to coroutine-local instances which code inside the coroutine then uses. The original parameters should not be part of the frame. Normally CoroSplit figures that out by itself, but for [[clang::trivial_abi]] parameters which, get destructed at the end of the ramp function, it does not (see bug), causing use-after-free's if the frame is destroyed before the end of the ramp (as happens if it doesn't suspend). Since Clang knows these should never be part of the frame, use metadata to make it so. Fixes #127499
2025-02-28[Coroutines] [CodeGen] Don't change AST in CodeGen/CoroutinesChuanqi Xu
The root source of other odd bugs. We performed a hack in CodeGen/Coroutines. But we didn't recognize that the CodeGen is a consumer of AST. The CodeGen shouldn't change AST in any ways. It'll break the assumption about the ASTConsumer in Clang's framework, which may break any other clang-based tools which depends on multiple consumers to work together. The fix here is simple. But I am not super happy about the test. It is too specific and verbose. We can remove this if we can get the signature of the AST in ASTContext.
2025-01-24[NFC][DebugInfo] Use iterator moveBefore at many call-sites (#123583)Jeremy Morse
As part of the "RemoveDIs" project, BasicBlock::iterator now carries a debug-info bit that's needed when getFirstNonPHI and similar feed into instruction insertion positions. Call-sites where that's necessary were updated a year ago; but to ensure some type safety however, we'd like to have all calls to moveBefore use iterators. This patch adds a (guaranteed dereferenceable) iterator-taking moveBefore, and changes a bunch of call-sites where it's obviously safe to change to use it by just calling getIterator() on an instruction pointer. A follow-up patch will contain less-obviously-safe changes. We'll eventually deprecate and remove the instruction-pointer insertBefore, but not before adding concise documentation of what considerations are needed (very few).
2024-08-09[DebugInfo][RemoveDIs] Use iterator-inserters in clang (#102006)Jeremy Morse
As part of the LLVM effort to eliminate debug-info intrinsics, we're moving to a world where only iterators should be used to insert instructions. This isn't a problem in clang when instructions get generated before any debug-info is inserted, however we're planning on deprecating and removing the instruction-pointer insertion routines. Scatter some calls to getIterator in a few places, remove a deref-then-addrof on another iterator, and add an overload for the createLoadInstBefore utility. Some callers passes a null insertion point, which we need to handle explicitly now.
2024-06-29[clang] Use std::make_unique (NFC) (#97176)Kazu Hirata
This patch is based on clang-tidy's modernize-make-unique but limited to those cases where type names are mentioned twice like `std::unique_ptr<Type>(new Type())`, which is a bit mouthful.
2024-05-15[coro] Lower `llvm.coro.await.suspend.handle` to resume with tail call (#89751)Hans
The C++ standard requires that symmetric transfer from one coroutine to another is performed via a tail call. Failure to do so is a miscompile and often breaks programs by quickly overflowing the stack. Until now, the coro split pass tried to ensure this in the `addMustTailToCoroResumes()` function by searching for `llvm.coro.resume` calls to lower as tail calls if the conditions were right: the right function arguments, attributes, calling convention etc., and if a `ret void` was sure to be reached after traversal with some ad-hoc constant folding following the call. This was brittle, as the kind of implicit variants required for a tail call to happen could easily be broken by other passes (e.g. if some instruction got in between the `resume` and `ret`), see for example 9d1cb18d19862fc0627e4a56e1e491a498e84c71 and 284da049f5feb62b40f5abc41dda7895e3d81d72. Also the logic seemed backwards: instead of searching for possible tail call candidates and doing them if the circumstances are right, it seems better to start with the intention of making the tail calls we need, and forcing the circumstances to be right. Now that we have the `llvm.coro.await.suspend.handle` intrinsic (since f78688134026686288a8d310b493d9327753a022) which corresponds exactly to symmetric transfer, change the lowering of that to also include the `resume` part, always lowered as a tail call.
2024-04-23[clang] coroutine: generate valid mangled name in ↵Haojian Wu
CodeGenFunction::generateAwaitSuspendWrapper (#89731) Fixes https://github.com/llvm/llvm-project/issues/89723
2024-03-28[CodeGen][arm64e] Add methods and data members to Address, which are needed ↵Akira Hatanaka
to authenticate signed pointers (#86923) To authenticate pointers, CodeGen needs access to the key and discriminators that were used to sign the pointer. That information is sometimes known from the context, but not always, which is why `Address` needs to hold that information. This patch adds methods and data members to `Address`, which will be needed in subsequent patches to authenticate signed pointers, and uses the newly added methods throughout CodeGen. Although this patch isn't strictly NFC as it causes CodeGen to use different code paths in some cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any changes in functionality as it doesn't add any information needed for authentication. In addition to the changes mentioned above, this patch introduces class `RawAddress`, which contains a pointer that we know is unsigned, and adds several new functions for creating `Address` and `LValue` objects. This reapplies d9a685a9dd589486e882b722e513ee7b8c84870c, which was reverted because it broke ubsan bots. There seems to be a bug in coroutine code-gen, which is causing EmitTypeCheck to use the wrong alignment. For now, pass alignment zero to EmitTypeCheck so that it can compute the correct alignment based on the passed type (see function EmitCXXMemberOrOperatorMemberCallExpr).
2024-03-27Revert "[CodeGen][arm64e] Add methods and data members to Address, which are ↵Akira Hatanaka
needed to authenticate signed pointers (#86721)" (#86898) This reverts commit d9a685a9dd589486e882b722e513ee7b8c84870c. The commit broke ubsan bots.
2024-03-27[CodeGen][arm64e] Add methods and data members to Address, which are needed ↵Akira Hatanaka
to authenticate signed pointers (#86721) To authenticate pointers, CodeGen needs access to the key and discriminators that were used to sign the pointer. That information is sometimes known from the context, but not always, which is why `Address` needs to hold that information. This patch adds methods and data members to `Address`, which will be needed in subsequent patches to authenticate signed pointers, and uses the newly added methods throughout CodeGen. Although this patch isn't strictly NFC as it causes CodeGen to use different code paths in some cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any changes in functionality as it doesn't add any information needed for authentication. In addition to the changes mentioned above, this patch introduces class `RawAddress`, which contains a pointer that we know is unsigned, and adds several new functions for creating `Address` and `LValue` objects. This reapplies 8bd1f9116aab879183f34707e6d21c7051d083b6. The commit broke msan bots because LValue::IsKnownNonNull was uninitialized.
2024-03-26Revert "[CodeGen][arm64e] Add methods and data members to Address, which are ↵Akira Hatanaka
needed to authenticate signed pointers (#67454)" (#86674) This reverts commit 8bd1f9116aab879183f34707e6d21c7051d083b6. It appears that the commit broke msan bots.
2024-03-25[CodeGen][arm64e] Add methods and data members to Address, which are needed ↵Akira Hatanaka
to authenticate signed pointers (#67454) To authenticate pointers, CodeGen needs access to the key and discriminators that were used to sign the pointer. That information is sometimes known from the context, but not always, which is why `Address` needs to hold that information. This patch adds methods and data members to `Address`, which will be needed in subsequent patches to authenticate signed pointers, and uses the newly added methods throughout CodeGen. Although this patch isn't strictly NFC as it causes CodeGen to use different code paths in some cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any changes in functionality as it doesn't add any information needed for authentication. In addition to the changes mentioned above, this patch introduces class `RawAddress`, which contains a pointer that we know is unsigned, and adds several new functions for creating `Address` and `LValue` objects.
2024-03-11[coroutine] Implement llvm.coro.await.suspend intrinsic (#79712)fpasserby
Implement `llvm.coro.await.suspend` intrinsics, to deal with performance regression after prohibiting `.await_suspend` inlining, as suggested in #64945. Actually, there are three new intrinsics, which directly correspond to each of three forms of `await_suspend`: ``` void llvm.coro.await.suspend.void(ptr %awaiter, ptr %frame, ptr @wrapperFunction) i1 llvm.coro.await.suspend.bool(ptr %awaiter, ptr %frame, ptr @wrapperFunction) ptr llvm.coro.await.suspend.handle(ptr %awaiter, ptr %frame, ptr @wrapperFunction) ``` There are three different versions instead of one, because in `bool` case it's result is used for resuming via a branch, and in `coroutine_handle` case exceptions from `await_suspend` are handled in the coroutine, and exceptions from the subsequent `.resume()` are propagated to the caller. Await-suspend block is simplified down to intrinsic calls only, for example for symmetric transfer: ``` %id = call token @llvm.coro.save(ptr null) %handle = call ptr @llvm.coro.await.suspend.handle(ptr %awaiter, ptr %frame, ptr @wrapperFunction) call void @llvm.coro.resume(%handle) %result = call i8 @llvm.coro.suspend(token %id, i1 false) switch i8 %result, ... ``` All await-suspend logic is moved out into a wrapper function, generated for each suspension point. The signature of the function is `<type> wrapperFunction(ptr %awaiter, ptr %frame)` where `<type>` is one of `void` `i1` or `ptr`, depending on the return type of `await_suspend`. Intrinsic calls are lowered during `CoroSplit` pass, right after the split. Because I'm new to LLVM, I'm not sure if the helper function generation, calls to them and lowering are implemented in the right way, especially with regard to various metadata and attributes, i. e. for TBAA. All things that seemed questionable are marked with `FIXME` comments. There is another detail: in case of symmetric transfer raw pointer to the frame of coroutine, that should be resumed, is returned from the helper function and a direct call to `@llvm.coro.resume` is generated. C++ standard demands, that `.resume()` method is evaluated. Not sure how important is this, because code has been generated in the same way before, sans helper function.
2023-11-28[Clang] CGCoroutines skip emitting try block for value returning `noexcept` ↵Yuxuan Chen
init `await_resume` calls (#73160) Previously we were not properly skipping the generation of the `try { }` block around the `init_suspend.await_resume()` if the `await_resume` is not returning void. The reason being that the resume expression was wrapped in a `CXXBindTemporaryExpr` and the first dyn_cast failed, silently ignoring the noexcept. This only mattered for `init_suspend` because it had its own try block. This patch changes to first extract the sub expression when we see a `CXXBindTemporaryExpr`. Then perform the same logic to check for `noexcept`. Another version of this patch also wanted to assert the second step by `cast<CXXMemberCallExpr>` and as far as I understand it should be a valid assumption. I can change to that if upstream prefers.
2023-11-21[Clang][Coroutines] Properly emit EH code for initial suspend `await_resume` ↵Yuxuan Chen
(#73073) This change aims to fix an ICE in issue https://github.com/llvm/llvm-project/issues/63803 The crash happens in `ExitCXXTryStmt` because `EmitAnyExpr()` adds additional cleanup to the `EHScopeStack`. This messes up the assumption in `ExitCXXTryStmt` that the top of the stack should be a `EHCatchScope`. However, since we never read a value returned from `await_resume()` of an init suspend, we can skip the part that builds this `RValue`. The code here may not be in the best shape. There's another bug that `memberCallExpressionCanThrow` doesn't work on the current Expr due to type mismatch. I am preparing a separate PR to address it plus some refactoring might be beneficial.
2023-11-09[Coroutines] Introduce [[clang::coro_only_destroy_when_complete]] (#71014)Chuanqi Xu
Close https://github.com/llvm/llvm-project/issues/56980. This patch tries to introduce a light-weight optimization attribute for coroutines which are guaranteed to only be destroyed after it reached the final suspend. The rationale behind the patch is simple. See the example: ```C++ A foo() { dtor d; co_await something(); dtor d1; co_await something(); dtor d2; co_return 43; } ``` Generally the generated .destroy function may be: ```C++ void foo.destroy(foo.Frame *frame) { switch(frame->suspend_index()) { case 1: frame->d.~dtor(); break; case 2: frame->d.~dtor(); frame->d1.~dtor(); break; case 3: frame->d.~dtor(); frame->d1.~dtor(); frame->d2.~dtor(); break; default: // coroutine completed or haven't started break; } frame->promise.~promise_type(); delete frame; } ``` Since the compiler need to be ready for all the cases that the coroutine may be destroyed in a valid state. However, from the user's perspective, we can understand that certain coroutine types may only be destroyed after it reached to the final suspend point. And we need a method to teach the compiler about this. Then this is the patch. After the compiler recognized that the coroutines can only be destroyed after complete, it can optimize the above example to: ```C++ void foo.destroy(foo.Frame *frame) { frame->promise.~promise_type(); delete frame; } ``` I spent a lot of time experimenting and experiencing this in the downstream. The numbers are really good. In a real-world coroutine-heavy workload, the size of the build dir (including .o files) reduces 14%. And the size of final libraries (excluding the .o files) reduces 8% in Debug mode and 1% in Release mode.
2023-09-21[Clang][LLVM][Coroutines] Prevent __coro_gro from outliving __promise (#66706)Bruno Cardoso Lopes
When dealing with short-circuiting coroutines (e.g. expected), the deferred calls that resolve the get_return_object are currently being emitted after we delete the coroutine frame. This was caught by ASAN when using optimizations -O1 and above: optimizations after inlining would place the __coro_gro in the heap, and subsequent delete of the coroframe followed by the conversion -> BOOM. This patch forbids the GRO to be placed in the coroutine frame, by adding a new metadata node that can be attached to `alloca` instructions. Fix #49843
2023-09-15[clang] Remove spurious trailing whitespaceLouis Dionne
2023-09-15Extend `retcon.once` coroutines lowering to optionally produce a normal ↵Anton Korobeynikov
result (#66333) One of the main user of these kind of coroutines is swift. There yield-once (`retcon.once`) coroutines are used to temporary "expose" pointers to internal fields of various objects creating borrow scopes. However, in some cases it might be useful also to allow these coroutines to produce a normal result, but there is no convenient way to represent this (as compared to switched-resume kind of coroutines where C++ `co_return` is transformed to a member / callback call on promise object). The extension is simple: we allow continuation function to have a non-void result and accept optional extra arguments via a special `llvm.coro.end.result` intrinsic that would essentially forward them as normal results.
2023-08-28Recommit [C++20] [Coroutines] Mark await_suspend as noinline if the awaiter ↵Chuanqi Xu
is not empty The original patch is incorrect since it marks too many calls to be noinline. It shows that it is bad to do analysis in the frontend again. This patch tries to mark the await_suspend function as noinlne only. --- Close https://github.com/llvm/llvm-project/issues/56301 Close https://github.com/llvm/llvm-project/issues/64151 Close https://github.com/llvm/llvm-project/issues/65018 See the summary and the discussion of https://reviews.llvm.org/D157070 to get the full context. As @rjmccall pointed out, the key point of the root cause is that currently we didn't implement the semantics for '@llvm.coro.save' well ("after the await-ready returns false, the coroutine is considered to be suspended ") well. Since the semantics implies that we (the compiler) shouldn't write the spills into the coroutine frame in the await_suspend. But now it is possible due to some combinations of the optimizations so the semantics are broken. And the inlining is the root optimization of such optimizations. So in this patch, we tried to add the `noinline` attribute to the await_suspend function. This looks slightly problematic since the users are able to call the await_suspend function standalone. This is limited by the implementation. On the one hand, we don't want the workaround solution (See the proposed solution later) to be too complex. On the other hand, it is rare to call await_suspend standalone. Also it is not semantically incorrect to do so since the inlining is not part of the C++ standard. Also as an optimization, we don't add the `noinline` attribute to the await_suspend function if the awaiter is an empty class. This should be correct since the programmers can't access the local variables in await_suspend if the awaiter is empty. I think this is necessary for the performance since it is pretty common. The long term solution is: call @llvm.coro.await_suspend(ptr %awaiter, ptr %handle, ptr @awaitSuspendFn) Then it is much easier to perform the safety analysis in the middle end. If it is safe to inline the call to awaitSuspend, we can replace it in the CoroEarly pass. Otherwise we could replace it in the CoroSplit pass. Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D157833
2023-08-28Revert "[C++20] [Coroutines] Mark await_suspend as noinline if the awaiter ↵Chuanqi Xu
is not empty" This reverts commit 9d9c25f81456aace2bec4b58498a420e650007d9. This reverts commit 19ab2664ad3182ffa8fe3a95bb19765e4ae84653. This reverts commit c4672454743e942f148a1aff1e809dae73e464f6. As the issue https://github.com/llvm/llvm-project/issues/65018 shows, the previous fix introduce a regression actually. So this commit reverts the fix by our policies.
2023-08-22[C++20] [Coroutines] Mark await_suspend as noinline if the awaiter is not emptyChuanqi Xu
Close https://github.com/llvm/llvm-project/issues/56301 Close https://github.com/llvm/llvm-project/issues/64151 See the summary and the discussion of https://reviews.llvm.org/D157070 to get the full context. As @rjmccall pointed out, the key point of the root cause is that currently we didn't implement the semantics for '@llvm.coro.save' well ("after the await-ready returns false, the coroutine is considered to be suspended ") well. Since the semantics implies that we (the compiler) shouldn't write the spills into the coroutine frame in the await_suspend. But now it is possible due to some combinations of the optimizations so the semantics are broken. And the inlining is the root optimization of such optimizations. So in this patch, we tried to add the `noinline` attribute to the await_suspend call. Also as an optimization, we don't add the `noinline` attribute to the await_suspend call if the awaiter is an empty class. This should be correct since the programmers can't access the local variables in await_suspend if the awaiter is empty. I think this is necessary for the performance since it is pretty common. Another potential optimization is: call @llvm.coro.await_suspend(ptr %awaiter, ptr %handle, ptr @awaitSuspendFn) Then it is much easier to perform the safety analysis in the middle end. If it is safe to inline the call to awaitSuspend, we can replace it in the CoroEarly pass. Otherwise we could replace it in the CoroSplit pass. Reviewed By: rjmccall Differential Revision: https://reviews.llvm.org/D157833
2023-08-10[clang] Drop some references to typed pointers (getInt8PtrTy). NFCBjorn Pettersson
Differential Revision: https://reviews.llvm.org/D157550
2023-06-26[C++] [Coroutines] Assume the allocation doesn't return nullptrChuanqi Xu
In case of 'get_return_object_on_allocation_failure' get declared, the compiler is required to call 'operator new(size_t, nothrow_t)' and the handle the failure case by calling 'get_return_object_on_allocation_failure()'. But the failure case should be rare and we can assume the allocation is successful and pass the information to the optimizer.
2023-04-06[C++20] [Coroutines] Handle function-try-block in SemaCoroutineChuanqi Xu
In https://reviews.llvm.org/D146758, we handled the rare case that the coroutine has a function-try-block. But it will be better to handle it in the Sema part. This patch handles the preprocess.
2023-03-30Fix codegen for coroutine with function-try-blockMatthias Braun
This fixes an assertion error when writing a coroutine with a function-try-block. In this case the function body is not a `CompoundStmt` so the code constructing an artificial CXXTryStmt must also construct a `CompoundStmt` for it. While on it adjust the `CXXStmt::Create` function to only accept `CompoundStmt*`. Differential Revision: https://reviews.llvm.org/D146758
2023-03-21[Coroutines] Implement fix for cwg2563 issue and enable RVO under certain ↵Bruno Cardoso Lopes
conditions - The cwg2563 issue is fixed by delaying GRO initialization only when the types mismatch between GRO and function return. - When the types match directly initialize, which indirectly enables RVO to kick in, partially restores behavior introduced in https://reviews.llvm.org/D117087. - Add entry to release notes. Background: https://github.com/llvm/llvm-project/issues/56532 https://cplusplus.github.io/CWG/issues/2563.html https://github.com/cplusplus/papers/issues/1414 Differential Revision: https://reviews.llvm.org/D145641
2023-03-21[Coroutines] Fix premature conversion of return objectBruno Cardoso Lopes
Fix https://github.com/llvm/llvm-project/issues/56532 Effectively, this reverts behavior introduced in https://reviews.llvm.org/D117087, which did two things: 1. Change delayed to early conversion of return object. 2. Introduced RVO possibilities because of early conversion. This patches fixes (1) and removes (2). I already worked on a follow up for (2) in a separated patch. I believe it's important to split these two because if the RVO causes any problems we can explore reverting (2) while maintaining (1). Notes on some testcase changes: - `pr59221.cpp` changed to `-O1` so we can check that the front-end honors the value checked for. Sounds like `-O3` without RVO is more likely to work with LLVM optimizations... - Comment out delete members `coroutine-no-move-ctor.cpp` since behavior now requires copies again. Differential Revision: https://reviews.llvm.org/D145639
2023-03-17Revert "[Coroutines] Fix premature conversion of return object"Ilya Biryukov
This reverts commit 54225c457a336b1609c6d064b2b606a9238a28b9. The lack of RVO causes compile errors in our code. Reverting to unblock our integrate. See D145639 for full discussion.
2023-03-09[Coroutines] Fix premature conversion of return objectBruno Cardoso Lopes
Fix https://github.com/llvm/llvm-project/issues/56532 Effectively, this reverts behavior introduced in https://reviews.llvm.org/D117087, which did two things: 1. Change delayed to early conversion of return object. 2. Introduced RVO possibilities because of early conversion. This patches fixes (1) and removes (2). I already worked on a follow up for (2) in a separated patch. I believe it's important to split these two because if the RVO causes any problems we can explore reverting (2) while maintaining (1). Notes on some testcase changes: - `pr59221.cpp` changed to `-O1` so we can check that the front-end honors the value checked for. Sounds like `-O3` without RVO is more likely to work with LLVM optimizations... - Comment out delete members `coroutine-no-move-ctor.cpp` since behavior now requires copies again. Differential Revision: https://reviews.llvm.org/D145639
2023-02-28[Coroutines] Avoid creating conditional cleanup markers in suspend blockWei Wang
We shouldn't access coro frame after returning from `await_suspend()` and before `llvm.coro.suspend()`. Make sure we always hoist conditional cleanup markers when inside the `await.suspend` block. Fix https://github.com/llvm/llvm-project/issues/59181 Reviewed By: ChuanqiXu Differential Revision: https://reviews.llvm.org/D144680
2022-09-22[C++] [Coroutines] Prefer aligned (de)allocation for coroutines -Chuanqi Xu
implement the option2 of P2014R0 This implements the option2 of https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2014r0.pdf. This also fixes https://github.com/llvm/llvm-project/issues/56671. Although wg21 didn't get consensus for the direction of the problem, we're happy to have some implementation and user experience first. And from issue56671, the option2 should be the pursued one. Reviewed By: ychen Differential Revision: https://reviews.llvm.org/D133341
2022-09-07[NFC] [Frontend] Correct the use of 'auto' in SemaCoroutine and CGCoroutineChuanqi Xu
We should only use 'auto' in case we can know the type from the right hand side of the expression. Also we need keep '*' around if the type is a pointer actually. Few uses of 'auto' in SemaCoroutine.cpp and CGCoroutine.cpp violates the rule. This commit tries to fix it.
2022-09-01[NFC] Emit builtin coroutine calls uniforallyChuanqi Xu
All the coroutine builtins were emitted in EmitCoroutineIntrinsic except __builtin_coro_size. This patch tries to emit all the corotine builtins uniformally.
2022-08-08[clang] LLVM_FALLTHROUGH => [[fallthrough]]. NFCFangrui Song
With C++17 there is no Clang pedantic warning or MSVC C5051. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D131346
2022-07-03[FPEnv] Allow CompoundStmt to keep FP optionsSerge Pavlov
This is a recommit of b822efc7404bf09ccfdc1ab7657475026966c3b2, reverted in dc34d8df4c48b3a8f474360970cae8a58e6c84f0. The commit caused fails because the test ast-print-fp-pragmas.c did not specify particular target, and it failed on targets which do not support constrained intrinsics. The original commit message is below. AST does not have special nodes for pragmas. Instead a pragma modifies some state variables of Sema, which in turn results in modified attributes of AST nodes. This technique applies to floating point operations as well. Every AST node that can depend on FP options keeps current set of them. This technique works well for options like exception behavior or fast math options. They represent instructions to the compiler how to modify code generation for the affected nodes. However treatment of FP control modes has problems with this technique. Modifying FP control mode (like rounding direction) usually requires operations on hardware, like writing to control registers. It must be done prior to the first operation that depends on the control mode. In particular, such operations are required for implementation of `pragma STDC FENV_ROUND`, compiler should set up necessary rounding direction at the beginning of compound statement where the pragma occurs. As there is no representation for pragmas in AST, the code generation becomes a complicated task in this case. To solve this issue FP options are kept inside CompoundStmt. Unlike to FP options in expressions, these does not affect any operation on FP values, but only inform the codegen about the FP options that act in the body of the statement. As all pragmas that modify FP environment may occurs only at the start of compound statement or at global level, such solution works for all relevant pragmas. The options are kept as a difference from the options in the enclosing compound statement or default options, it helps codegen to set only changed control modes. Differential Revision: https://reviews.llvm.org/D123952
2022-07-01Revert "[FPEnv] Allow CompoundStmt to keep FP options"Serge Pavlov
On some buildbots test `ast-print-fp-pragmas.c` fails, need to investigate it. This reverts commit 0401fd12d4aa0553347fe34d666fb236d8719173. This reverts commit b822efc7404bf09ccfdc1ab7657475026966c3b2.
2022-07-01[FPEnv] Allow CompoundStmt to keep FP optionsSerge Pavlov
AST does not have special nodes for pragmas. Instead a pragma modifies some state variables of Sema, which in turn results in modified attributes of AST nodes. This technique applies to floating point operations as well. Every AST node that can depend on FP options keeps current set of them. This technique works well for options like exception behavior or fast math options. They represent instructions to the compiler how to modify code generation for the affected nodes. However treatment of FP control modes has problems with this technique. Modifying FP control mode (like rounding direction) usually requires operations on hardware, like writing to control registers. It must be done prior to the first operation that depends on the control mode. In particular, such operations are required for implementation of `pragma STDC FENV_ROUND`, compiler should set up necessary rounding direction at the beginning of compound statement where the pragma occurs. As there is no representation for pragmas in AST, the code generation becomes a complicated task in this case. To solve this issue FP options are kept inside CompoundStmt. Unlike to FP options in expressions, these does not affect any operation on FP values, but only inform the codegen about the FP options that act in the body of the statement. As all pragmas that modify FP environment may occurs only at the start of compound statement or at global level, such solution works for all relevant pragmas. The options are kept as a difference from the options in the enclosing compound statement or default options, it helps codegen to set only changed control modes. Differential Revision: https://reviews.llvm.org/D123952
2022-06-14[Coroutines] Convert coroutine.presplit to enum attrChuanqi Xu
This is required by @nikic in https://reviews.llvm.org/D127383 to decrease the cost to check whether a function is a coroutine and this fixes a FIXME too. Reviewed By: rjmccall, ezhulenev Differential Revision: https://reviews.llvm.org/D127471
2022-02-16[C++20] [Coroutines] Implement return value optimization for get_return_objectChuanqi Xu
This patch tries to implement RVO for coroutine's return object got from get_return_object. From [dcl.fct.def.coroutine]/p7 we could know that the return value of get_return_object is either a reference or a prvalue. So it makes sense to do copy elision for the return value. The return object should be constructed directly into the storage where they would otherwise be copied/moved to. Test Plan: folly, check-all Reviewed By: junparser Differential revision: https://reviews.llvm.org/D117087
2022-01-05[Coroutines] Set presplit attribute in Clang and mlirChuanqi Xu
This fixes bug49264. Simply, coroutine shouldn't be inlined before CoroSplit. And the marker for pre-splited coroutine is created in CoroEarly pass, which ran after AlwaysInliner Pass in O0 pipeline. So that the AlwaysInliner couldn't detect it shouldn't inline a coroutine. So here is the error. This patch set the presplit attribute in clang and mlir. So the inliner would always detect the attribute before splitting. Reviewed By: rjmccall, ezhulenev Differential Revision: https://reviews.llvm.org/D115790
2021-12-24[C++20] Conform coroutine's comments in clang (NFC-ish)Chuanqi Xu
The comments for coroutine in clang wrote for coroutine-TS. Now coroutine is merged into standard. Try to conform the comments.
2021-04-18Revert "[Coroutines] Set presplit attribute in Clang instead of CoroEarly pass"Xun Li
This reverts commit fa6b54c44ab1d5f579304eadb7ac8bd7e72d0e77. The commited patch broke mlir tests. It seems that mlir tests depend on coroutine function properties set in CoroEarly pass.
2021-04-18[Coroutines] Set presplit attribute in Clang instead of CoroEarly passXun Li
Presplit coroutines cannot be inlined. During AlwaysInliner we check if a function is a presplit coroutine, if so we skip inlining. The presplit coroutine attributes are set in CoroEarly pass. However in O0 pipeline, AlwaysInliner runs before CoroEarly, so the attribute isn't set yet and will still inline the coroutine. This causes Clang to crash: https://bugs.llvm.org/show_bug.cgi?id=49920 To fix this, we set the attributes in the Clang front-end instead of in CoroEarly pass. Reviewed By: rjmccall, ChuanqiXu Differential Revision: https://reviews.llvm.org/D100282
2021-04-18Revert "[Coroutines] Move CoroEarly pass to before AlwaysInliner"Xun Li
This reverts commit 2b50f5a4343f8fb06acaa5c36355bcf58092c9cd. Forgot to update the description of the commit to sync with phabricator. Going to redo the commit.
2021-04-18[Coroutines] Move CoroEarly pass to before AlwaysInlinerXun Li
Presplit coroutines cannot be inlined. During AlwaysInliner we check if a function is a presplit coroutine, if so we skip inlining. The presplit coroutine attributes are set in CoroEarly pass. However in O0 pipeline, AlwaysInliner runs before CoroEarly, so the attribute isn't set yet and will still inline the coroutine. This causes Clang to crash: https://bugs.llvm.org/show_bug.cgi?id=49920 Differential Revision: https://reviews.llvm.org/D100282
2021-04-12[Clang][Coroutine][DebugInfo] In c++ coroutine, clang will emit different ↵yifeng.dongyifeng
debug info variables for parameters and move-parameters. The first one is the real parameters of the coroutine function, the other one just for copying parameters to the coroutine frame. Considering the following c++ code: ``` struct coro { ... }; coro foo(struct test & t) { ... co_await suspend_always(); ... co_await suspend_always(); ... co_await suspend_always(); } int main(int argc, char *argv[]) { auto c = foo(...); c.handle.resume(); ... } ``` Function foo is the standard coroutine function, and it has only one parameter named t (ignoring this at first), when we use the llvm code to compile this function, we can get the following ir: ``` !2921 = distinct !DISubprogram(name: "foo", linkageName: "_ZN6Object3fooE4test", scope: !2211, file: !45, li\ ne: 48, type: !2329, scopeLine: 48, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefi\ nition | DISPFlagOptimized, unit: !44, declaration: !2328, retainedNodes: !2922) !2924 = !DILocalVariable(name: "t", arg: 2, scope: !2921, file: !45, line: 48, type: !838) ... !2926 = !DILocalVariable(name: "t", scope: !2921, type: !838, flags: DIFlagArtificial) ``` We can find there are two `the same` DIVariable named t in the same dwarf scope for foo.resume. And when we try to use llvm-dwarfdump to dump the dwarf info of this elf, we get the following output: ``` 0x00006684: DW_TAG_subprogram DW_AT_low_pc (0x00000000004013a0) DW_AT_high_pc (0x00000000004013a8) DW_AT_frame_base (DW_OP_reg7 RSP) DW_AT_object_pointer (0x0000669c) DW_AT_GNU_all_call_sites (true) DW_AT_specification (0x00005b5c "_ZN6Object3fooE4test") 0x000066a5: DW_TAG_formal_parameter DW_AT_name ("t") DW_AT_decl_file ("/disk1/yifeng.dongyifeng/my_code/llvm/build/bin/coro-debug-1.cpp") DW_AT_decl_line (48) DW_AT_type (0x00004146 "test") 0x000066ba: DW_TAG_variable DW_AT_name ("t") DW_AT_type (0x00004146 "test") DW_AT_artificial (true) ``` The elf also has two 't' in the same scope. But unluckily, it might let the debugger confused. And failed to print parameters for O0 or above. This patch will make coroutine parameters and move parameters use the same DIVar and try to fix the problems that I mentioned before. Test Plan: check-clang Reviewed By: aprantl, jmorse Differential Revision: https://reviews.llvm.org/D97533
2021-03-25[Coroutine][Clang] Force emit lifetime intrinsics for CoroutinesXun Li
tl;dr Correct implementation of Corouintes requires having lifetime intrinsics available. Coroutine functions are functions that can be suspended and resumed latter. To do so, data that need to stay alive after suspension must be put on the heap (i.e. the coroutine frame). The optimizer is responsible for analyzing each AllocaInst and figure out whether it should be put on the stack or the frame. In most cases, for data that we are unable to accurately analyze lifetime, we can just conservatively put them on the heap. Unfortunately, there exists a few cases where certain data MUST be put on the stack, not on the heap. Without lifetime intrinsics, we are unable to correctly analyze those data's lifetime. To dig into more details, there exists cases where at certain code points, the current coroutine frame may have already been destroyed. Hence no frame access would be allowed beyond that point. The following is a common code pattern called "Symmetric Transfer" in coroutine: ``` auto tmp = await_suspend(); __builtin_coro_resume(tmp.address()); return; ``` In the above code example, `await_suspend()` returns a new coroutine handle, which we will obtain the address and then resume that coroutine. This essentially "transfered" from the current coroutine to a different coroutine. During the call to `await_suspend()`, the current coroutine may be destroyed, which should be fine because we are not accessing any data afterwards. However when LLVM is emitting IR for the above code, it needs to emit an AllocaInst for `tmp`. It will then call the `address` function on tmp. `address` function is a member function of coroutine, and there is no way for the LLVM optimizer to know that it does not capture the `tmp` pointer. So when the optimizer looks at it, it has to conservatively assume that `tmp` may escape and hence put it on the heap. Furthermore, in some cases `address` call would be inlined, which will generate a bunch of store/load instructions that move the `tmp` pointer around. Those stores will also make the compiler to think that `tmp` might escape. To summarize, it's really difficult for the mid-end to figure out that the `tmp` data is short-lived. I made some attempt in D98638, but it appears to be way too complex and is basically doing the same thing as inserting lifetime intrinsics in coroutines. Also, for reference, we already force emitting lifetime intrinsics in O0 for AlwaysInliner: https://github.com/llvm/llvm-project/blob/main/llvm/lib/Passes/PassBuilder.cpp#L1893 Differential Revision: https://reviews.llvm.org/D99227
2020-03-16[Coroutines] Do not evaluate InitListExpr of a co_returnJun Ma
Differential Revision: https://reviews.llvm.org/D76118