mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
[coroutines] Add support for llvm.coro.noop intrinsics
Summary: A recent addition to Coroutines TS (https://wg21.link/p0913) adds a pre-defined coroutine noop_coroutine that does nothing. To implement this feature, we implemented an llvm.coro.noop intrinsic that returns a coroutine handle to a coroutine that does nothing when resumed or destroyed. Reviewers: EricWF, modocache, rnk, lewissbaker Reviewed By: modocache Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D45114 llvm-svn: 328986
This commit is contained in:
parent
5f173c78ac
commit
6e7dd71020
@ -880,6 +880,32 @@ Example:
|
||||
%phi = phi i8* [ null, %entry ], [ %alloc, %coro.alloc ]
|
||||
%frame = call i8* @llvm.coro.begin(token %id, i8* %phi)
|
||||
|
||||
.. _coro.noop:
|
||||
|
||||
'llvm.coro.noop' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
::
|
||||
|
||||
declare i8* @llvm.coro.noop()
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.noop``' intrinsic returns an address of the coroutine frame of
|
||||
a coroutine that does nothing when resumed or destroyed.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
None
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This intrinsic is lowered to refer to a private constant coroutine frame. The
|
||||
resume and destroy handlers for this frame are empty functions that do nothing.
|
||||
Note that in different translation units llvm.coro.noop may return different pointers.
|
||||
|
||||
.. _coro.frame:
|
||||
|
||||
'llvm.coro.frame' Intrinsic
|
||||
|
@ -768,6 +768,7 @@ def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
|
||||
def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []>;
|
||||
|
||||
def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
|
||||
def int_coro_noop : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>;
|
||||
def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>;
|
||||
|
||||
def int_coro_save : Intrinsic<[llvm_token_ty], [llvm_ptr_ty], []>;
|
||||
|
@ -27,10 +27,12 @@ namespace {
|
||||
class Lowerer : public coro::LowererBase {
|
||||
IRBuilder<> Builder;
|
||||
PointerType *const AnyResumeFnPtrTy;
|
||||
Constant *NoopCoro = nullptr;
|
||||
|
||||
void lowerResumeOrDestroy(CallSite CS, CoroSubFnInst::ResumeKind);
|
||||
void lowerCoroPromise(CoroPromiseInst *Intrin);
|
||||
void lowerCoroDone(IntrinsicInst *II);
|
||||
void lowerCoroNoop(IntrinsicInst *II);
|
||||
|
||||
public:
|
||||
Lowerer(Module &M)
|
||||
@ -103,6 +105,41 @@ void Lowerer::lowerCoroDone(IntrinsicInst *II) {
|
||||
II->eraseFromParent();
|
||||
}
|
||||
|
||||
void Lowerer::lowerCoroNoop(IntrinsicInst *II) {
|
||||
if (!NoopCoro) {
|
||||
LLVMContext &C = Builder.getContext();
|
||||
Module &M = *II->getModule();
|
||||
|
||||
// Create a noop.frame struct type.
|
||||
StructType *FrameTy = StructType::create(C, "NoopCoro.Frame");
|
||||
auto *FramePtrTy = FrameTy->getPointerTo();
|
||||
auto *FnTy = FunctionType::get(Type::getVoidTy(C), FramePtrTy,
|
||||
/*IsVarArgs=*/false);
|
||||
auto *FnPtrTy = FnTy->getPointerTo();
|
||||
FrameTy->setBody({FnPtrTy, FnPtrTy});
|
||||
|
||||
// Create a Noop function that does nothing.
|
||||
Function *NoopFn =
|
||||
Function::Create(FnTy, GlobalValue::LinkageTypes::PrivateLinkage,
|
||||
"NoopCoro.ResumeDestroy", &M);
|
||||
NoopFn->setCallingConv(CallingConv::Fast);
|
||||
auto *Entry = BasicBlock::Create(C, "entry", NoopFn);
|
||||
ReturnInst::Create(C, Entry);
|
||||
|
||||
// Create a constant struct for the frame.
|
||||
Constant* Values[] = {NoopFn, NoopFn};
|
||||
Constant* NoopCoroConst = ConstantStruct::get(FrameTy, Values);
|
||||
NoopCoro = new GlobalVariable(M, NoopCoroConst->getType(), /*isConstant=*/true,
|
||||
GlobalVariable::PrivateLinkage, NoopCoroConst,
|
||||
"NoopCoro.Frame.Const");
|
||||
}
|
||||
|
||||
Builder.SetInsertPoint(II);
|
||||
auto *NoopCoroVoidPtr = Builder.CreateBitCast(NoopCoro, Int8Ptr);
|
||||
II->replaceAllUsesWith(NoopCoroVoidPtr);
|
||||
II->eraseFromParent();
|
||||
}
|
||||
|
||||
// Prior to CoroSplit, calls to coro.begin needs to be marked as NoDuplicate,
|
||||
// as CoroSplit assumes there is exactly one coro.begin. After CoroSplit,
|
||||
// NoDuplicate attribute will be removed from coro.begin otherwise, it will
|
||||
@ -138,6 +175,9 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {
|
||||
if (cast<CoroEndInst>(&I)->isFallthrough())
|
||||
CS.setCannotDuplicate();
|
||||
break;
|
||||
case Intrinsic::coro_noop:
|
||||
lowerCoroNoop(cast<IntrinsicInst>(&I));
|
||||
break;
|
||||
case Intrinsic::coro_id:
|
||||
// Mark a function that comes out of the frontend that has a coro.id
|
||||
// with a coroutine attribute.
|
||||
@ -192,10 +232,10 @@ struct CoroEarly : public FunctionPass {
|
||||
// This pass has work to do only if we find intrinsics we are going to lower
|
||||
// in the module.
|
||||
bool doInitialization(Module &M) override {
|
||||
if (coro::declaresIntrinsics(M, {"llvm.coro.id", "llvm.coro.destroy",
|
||||
"llvm.coro.done", "llvm.coro.end",
|
||||
"llvm.coro.free", "llvm.coro.promise",
|
||||
"llvm.coro.resume", "llvm.coro.suspend"}))
|
||||
if (coro::declaresIntrinsics(
|
||||
M, {"llvm.coro.id", "llvm.coro.destroy", "llvm.coro.done",
|
||||
"llvm.coro.end", "llvm.coro.noop", "llvm.coro.free",
|
||||
"llvm.coro.promise", "llvm.coro.resume", "llvm.coro.suspend"}))
|
||||
L = llvm::make_unique<Lowerer>(M);
|
||||
return false;
|
||||
}
|
||||
|
@ -125,9 +125,10 @@ static bool isCoroutineIntrinsicName(StringRef Name) {
|
||||
static const char *const CoroIntrinsics[] = {
|
||||
"llvm.coro.alloc", "llvm.coro.begin", "llvm.coro.destroy",
|
||||
"llvm.coro.done", "llvm.coro.end", "llvm.coro.frame",
|
||||
"llvm.coro.free", "llvm.coro.id", "llvm.coro.param",
|
||||
"llvm.coro.promise", "llvm.coro.resume", "llvm.coro.save",
|
||||
"llvm.coro.size", "llvm.coro.subfn.addr", "llvm.coro.suspend",
|
||||
"llvm.coro.free", "llvm.coro.id", "llvm.coro.noop",
|
||||
"llvm.coro.param", "llvm.coro.promise", "llvm.coro.resume",
|
||||
"llvm.coro.save", "llvm.coro.size", "llvm.coro.subfn.addr",
|
||||
"llvm.coro.suspend",
|
||||
};
|
||||
return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
; Tests that CoroEarly pass correctly lowers coro.resume and coro.destroy
|
||||
; intrinsics.
|
||||
; Tests that CoroEarly pass correctly lowers coro.resume, coro.destroy
|
||||
; and other intrinsics managed by this pass.
|
||||
; RUN: opt < %s -S -coro-early | FileCheck %s
|
||||
|
||||
; CHECK: %NoopCoro.Frame = type { void (%NoopCoro.Frame*)*, void (%NoopCoro.Frame*)* }
|
||||
; CHECK: @NoopCoro.Frame.Const = private constant %NoopCoro.Frame { void (%NoopCoro.Frame*)* @NoopCoro.ResumeDestroy, void (%NoopCoro.Frame*)* @NoopCoro.ResumeDestroy }
|
||||
|
||||
; CHECK-LABEL: @callResume(
|
||||
define void @callResume(i8* %hdl) {
|
||||
; CHECK-NEXT: entry
|
||||
@ -37,5 +40,21 @@ ehcleanup:
|
||||
cleanupret from %0 unwind to caller
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: @noop(
|
||||
define i8* @noop() {
|
||||
; CHECK-NEXT: entry
|
||||
entry:
|
||||
; CHECK-NEXT: ret i8* bitcast (%NoopCoro.Frame* @NoopCoro.Frame.Const to i8*)
|
||||
%n = call i8* @llvm.coro.noop()
|
||||
ret i8* %n
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define private fastcc void @NoopCoro.ResumeDestroy(%NoopCoro.Frame*) {
|
||||
; CHECK-NEXT: entry
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
|
||||
declare void @llvm.coro.resume(i8*)
|
||||
declare void @llvm.coro.destroy(i8*)
|
||||
declare i8* @llvm.coro.noop()
|
||||
|
Loading…
Reference in New Issue
Block a user