Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Coroutines] Mark 'coroutine_handle<>::address' as always-inline
Close #65054 The direct issue is still the call to coroutine_handle<>::address() after await_suspend(). Without optimizations, the current logic will put the temporary result of await_suspend() to the coroutine frame since the middle end feel the temporary is escaped from coroutine_handle<>::address. To fix this fundamentally, we should wrap the whole logic about await-suspend into a standalone function. See #64945 And as a short-term workaround, we probably can mark coroutine_handle<>::address() as always-inline so that the temporary result may not be thought to be escaped then it won't be put on the coroutine frame. Although it looks dirty, it is probably do-able since the compiler are allowed to do special tricks to standard library components.
- Loading branch information
1 parent
bbf0733
commit 20e6515
Showing
2 changed files
with
82 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 \ | ||
// RUN: -O0 -disable-llvm-passes -emit-llvm %s -o - \ | ||
// RUN: | FileCheck %s --check-prefix=FRONTEND | ||
|
||
// The output of O0 is highly redundant and hard to test. Also it is not good | ||
// limit the output of O0. So we test the optimized output from O0. The idea | ||
// is the optimizations shouldn't change the semantics of the program. | ||
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 \ | ||
// RUN: -O0 -emit-llvm %s -o - -disable-O0-optnone \ | ||
// RUN: | opt -passes='sroa,mem2reg,simplifycfg' -S | FileCheck %s --check-prefix=CHECK-O0 | ||
|
||
#include "Inputs/coroutine.h" | ||
|
||
// A simple awaiter type with an await_suspend method that can't be | ||
// inlined. | ||
struct Awaiter { | ||
const int& x; | ||
|
||
bool await_ready() { return false; } | ||
std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h); | ||
void await_resume() {} | ||
}; | ||
|
||
struct MyTask { | ||
// A lazy promise with an await_transform method that supports awaiting | ||
// integer references using the Awaiter struct above. | ||
struct promise_type { | ||
MyTask get_return_object() { | ||
return MyTask{ | ||
std::coroutine_handle<promise_type>::from_promise(*this), | ||
}; | ||
} | ||
|
||
std::suspend_always initial_suspend() { return {}; } | ||
std::suspend_always final_suspend() noexcept { return {}; } | ||
void unhandled_exception(); | ||
|
||
auto await_transform(const int& x) { return Awaiter{x}; } | ||
}; | ||
|
||
std::coroutine_handle<> h; | ||
}; | ||
|
||
// A global array of integers. | ||
int g_array[32]; | ||
|
||
// A coroutine that awaits each integer in the global array. | ||
MyTask FooBar() { | ||
for (const int& x : g_array) { | ||
co_await x; | ||
} | ||
} | ||
|
||
// FRONTEND: define{{.*}}@_ZNKSt16coroutine_handleIvE7addressEv{{.*}}#[[address_attr:[0-9]+]] | ||
// FRONTEND: attributes #[[address_attr]] = {{.*}}alwaysinline | ||
|
||
// CHECK-O0: define{{.*}}@_Z6FooBarv.resume | ||
// CHECK-O0: call{{.*}}@_ZN7Awaiter13await_suspendESt16coroutine_handleIvE | ||
// CHECK-O0-NOT: store | ||
// CHECK-O0: ret void |