[Coroutines] Work on intrinsic IDs instead of names (NFCI) (#145518)

For the checks whether certain intrinsics are used, work with intrinsic
IDs instead of intrinsic names.

This also exposes that some of the checks were incorrect, because the
intrinsics were overloaded. There is no efficient way to determine
whether these are used. This change explicitly documents which
intrinsics are not checked for this reason.
This commit is contained in:
Nikita Popov
2025-07-01 09:22:23 +02:00
committed by GitHub
parent 9beb467d92
commit ab6316e219
5 changed files with 53 additions and 68 deletions

View File

@@ -110,11 +110,11 @@ bool Lowerer::lower(Function &F) {
static bool declaresCoroCleanupIntrinsics(const Module &M) {
return coro::declaresIntrinsics(
M, {"llvm.coro.alloc", "llvm.coro.begin", "llvm.coro.subfn.addr",
"llvm.coro.free", "llvm.coro.id", "llvm.coro.id.retcon",
"llvm.coro.id.async", "llvm.coro.id.retcon.once",
"llvm.coro.async.size.replace", "llvm.coro.async.resume",
"llvm.coro.begin.custom.abi"});
M, {Intrinsic::coro_alloc, Intrinsic::coro_begin,
Intrinsic::coro_subfn_addr, Intrinsic::coro_free, Intrinsic::coro_id,
Intrinsic::coro_id_retcon, Intrinsic::coro_id_async,
Intrinsic::coro_id_retcon_once, Intrinsic::coro_async_size_replace,
Intrinsic::coro_async_resume, Intrinsic::coro_begin_custom_abi});
}
PreservedAnalyses CoroCleanupPass::run(Module &M,

View File

@@ -279,12 +279,13 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
}
static bool declaresCoroEarlyIntrinsics(const Module &M) {
// coro_suspend omitted as it is overloaded.
return coro::declaresIntrinsics(
M, {"llvm.coro.id", "llvm.coro.id.retcon", "llvm.coro.id.retcon.once",
"llvm.coro.id.async", "llvm.coro.destroy", "llvm.coro.done",
"llvm.coro.end", "llvm.coro.end.async", "llvm.coro.noop",
"llvm.coro.free", "llvm.coro.promise", "llvm.coro.resume",
"llvm.coro.suspend"});
M, {Intrinsic::coro_id, Intrinsic::coro_id_retcon,
Intrinsic::coro_id_retcon_once, Intrinsic::coro_id_async,
Intrinsic::coro_destroy, Intrinsic::coro_done, Intrinsic::coro_end,
Intrinsic::coro_end_async, Intrinsic::coro_noop, Intrinsic::coro_free,
Intrinsic::coro_promise, Intrinsic::coro_resume});
}
PreservedAnalyses CoroEarlyPass::run(Module &M, ModuleAnalysisManager &) {

View File

@@ -450,7 +450,7 @@ bool CoroIdElider::attemptElide() {
PreservedAnalyses CoroElidePass::run(Function &F, FunctionAnalysisManager &AM) {
auto &M = *F.getParent();
if (!coro::declaresIntrinsics(M, {"llvm.coro.id"}))
if (!coro::declaresIntrinsics(M, Intrinsic::coro_id))
return PreservedAnalyses::all();
FunctionElideInfo FEI{&F};

View File

@@ -24,8 +24,7 @@ namespace coro {
bool isSuspendBlock(BasicBlock *BB);
bool declaresAnyIntrinsic(const Module &M);
bool declaresIntrinsics(const Module &M,
const std::initializer_list<StringRef>);
bool declaresIntrinsics(const Module &M, ArrayRef<Intrinsic::ID> List);
void replaceCoroFree(CoroIdInst *CoroId, bool Elide);
/// Replaces all @llvm.coro.alloc intrinsics calls associated with a given

View File

@@ -61,71 +61,56 @@ CallInst *coro::LowererBase::makeSubFnCall(Value *Arg, int Index,
return CallInst::Create(Fn, {Arg, IndexVal}, "", InsertPt->getIterator());
}
// NOTE: Must be sorted!
static const char *const CoroIntrinsics[] = {
"llvm.coro.align",
"llvm.coro.alloc",
"llvm.coro.async.context.alloc",
"llvm.coro.async.context.dealloc",
"llvm.coro.async.resume",
"llvm.coro.async.size.replace",
"llvm.coro.await.suspend.bool",
"llvm.coro.await.suspend.handle",
"llvm.coro.await.suspend.void",
"llvm.coro.begin",
"llvm.coro.begin.custom.abi",
"llvm.coro.destroy",
"llvm.coro.done",
"llvm.coro.end",
"llvm.coro.end.async",
"llvm.coro.frame",
"llvm.coro.free",
"llvm.coro.id",
"llvm.coro.id.async",
"llvm.coro.id.retcon",
"llvm.coro.id.retcon.once",
"llvm.coro.noop",
"llvm.coro.prepare.async",
"llvm.coro.prepare.retcon",
"llvm.coro.promise",
"llvm.coro.resume",
"llvm.coro.save",
"llvm.coro.size",
"llvm.coro.subfn.addr",
"llvm.coro.suspend",
"llvm.coro.suspend.async",
"llvm.coro.suspend.retcon",
// We can only efficiently check for non-overloaded intrinsics.
// The following intrinsics are absent for that reason:
// coro_align, coro_size, coro_suspend_async, coro_suspend_retcon
static Intrinsic::ID NonOverloadedCoroIntrinsics[] = {
Intrinsic::coro_alloc,
Intrinsic::coro_async_context_alloc,
Intrinsic::coro_async_context_dealloc,
Intrinsic::coro_async_resume,
Intrinsic::coro_async_size_replace,
Intrinsic::coro_await_suspend_bool,
Intrinsic::coro_await_suspend_handle,
Intrinsic::coro_await_suspend_void,
Intrinsic::coro_begin,
Intrinsic::coro_begin_custom_abi,
Intrinsic::coro_destroy,
Intrinsic::coro_done,
Intrinsic::coro_end,
Intrinsic::coro_end_async,
Intrinsic::coro_frame,
Intrinsic::coro_free,
Intrinsic::coro_id,
Intrinsic::coro_id_async,
Intrinsic::coro_id_retcon,
Intrinsic::coro_id_retcon_once,
Intrinsic::coro_promise,
Intrinsic::coro_resume,
Intrinsic::coro_save,
Intrinsic::coro_subfn_addr,
Intrinsic::coro_suspend,
};
#ifndef NDEBUG
static bool isCoroutineIntrinsicName(StringRef Name) {
return llvm::binary_search(CoroIntrinsics, Name);
}
#endif
bool coro::isSuspendBlock(BasicBlock *BB) {
return isa<AnyCoroSuspendInst>(BB->front());
}
bool coro::declaresAnyIntrinsic(const Module &M) {
for (StringRef Name : CoroIntrinsics) {
if (M.getNamedValue(Name))
return declaresIntrinsics(M, NonOverloadedCoroIntrinsics);
}
// Checks whether the module declares any of the listed intrinsics.
bool coro::declaresIntrinsics(const Module &M, ArrayRef<Intrinsic::ID> List) {
#ifndef NDEBUG
for (Intrinsic::ID ID : List)
assert(!Intrinsic::isOverloaded(ID) &&
"Only non-overloaded intrinsics supported");
#endif
for (Intrinsic::ID ID : List)
if (Intrinsic::getDeclarationIfExists(&M, ID))
return true;
}
return false;
}
// Verifies if a module has named values listed. Also, in debug mode verifies
// that names are intrinsic names.
bool coro::declaresIntrinsics(const Module &M,
const std::initializer_list<StringRef> List) {
for (StringRef Name : List) {
assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic");
if (M.getNamedValue(Name))
return true;
}
return false;
}