diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
commit | b60736ec1405bb0a8dd40989f67ef4c93da068ab (patch) | |
tree | 5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /llvm/lib/Transforms/Coroutines/Coroutines.cpp | |
parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) |
Diffstat (limited to 'llvm/lib/Transforms/Coroutines/Coroutines.cpp')
-rw-r--r-- | llvm/lib/Transforms/Coroutines/Coroutines.cpp | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp index 87c3a8b0d0cf..6699a5c46313 100644 --- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -69,7 +69,7 @@ static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder, static void addCoroutineSCCPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createCoroSplitLegacyPass()); + PM.add(createCoroSplitLegacyPass(Builder.OptLevel != 0)); } static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, @@ -124,17 +124,23 @@ static bool isCoroutineIntrinsicName(StringRef Name) { // NOTE: Must be sorted! static const char *const CoroIntrinsics[] = { "llvm.coro.alloc", + "llvm.coro.async.context.alloc", + "llvm.coro.async.context.dealloc", + "llvm.coro.async.store_resume", "llvm.coro.begin", "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.param", + "llvm.coro.prepare.async", "llvm.coro.prepare.retcon", "llvm.coro.promise", "llvm.coro.resume", @@ -142,6 +148,7 @@ static bool isCoroutineIntrinsicName(StringRef Name) { "llvm.coro.size", "llvm.coro.subfn.addr", "llvm.coro.suspend", + "llvm.coro.suspend.async", "llvm.coro.suspend.retcon", }; return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1; @@ -269,6 +276,12 @@ void coro::Shape::buildFrom(Function &F) { if (II->use_empty()) UnusedCoroSaves.push_back(cast<CoroSaveInst>(II)); break; + case Intrinsic::coro_suspend_async: { + auto *Suspend = cast<CoroSuspendAsyncInst>(II); + Suspend->checkWellFormed(); + CoroSuspends.push_back(Suspend); + break; + } case Intrinsic::coro_suspend_retcon: { auto Suspend = cast<CoroSuspendRetconInst>(II); CoroSuspends.push_back(Suspend); @@ -304,11 +317,16 @@ void coro::Shape::buildFrom(Function &F) { CoroBegin = CB; break; } + case Intrinsic::coro_end_async: case Intrinsic::coro_end: - CoroEnds.push_back(cast<CoroEndInst>(II)); - if (CoroEnds.back()->isFallthrough()) { + CoroEnds.push_back(cast<AnyCoroEndInst>(II)); + if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(II)) { + AsyncEnd->checkWellFormed(); + } + if (CoroEnds.back()->isFallthrough() && isa<CoroEndInst>(II)) { // Make sure that the fallthrough coro.end is the first element in the // CoroEnds vector. + // Note: I don't think this is neccessary anymore. if (CoroEnds.size() > 1) { if (CoroEnds.front()->isFallthrough()) report_fatal_error( @@ -341,7 +359,7 @@ void coro::Shape::buildFrom(Function &F) { } // Replace all coro.ends with unreachable instruction. - for (CoroEndInst *CE : CoroEnds) + for (AnyCoroEndInst *CE : CoroEnds) changeToUnreachable(CE, /*UseLLVMTrap=*/false); return; @@ -371,7 +389,23 @@ void coro::Shape::buildFrom(Function &F) { } break; } - + case Intrinsic::coro_id_async: { + auto *AsyncId = cast<CoroIdAsyncInst>(Id); + AsyncId->checkWellFormed(); + this->ABI = coro::ABI::Async; + this->AsyncLowering.Context = AsyncId->getStorage(); + this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex(); + this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize(); + this->AsyncLowering.ContextAlignment = + AsyncId->getStorageAlignment().value(); + this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer(); + auto &Context = F.getContext(); + auto *Int8PtrTy = Type::getInt8PtrTy(Context); + auto *VoidTy = Type::getVoidTy(Context); + this->AsyncLowering.AsyncFuncTy = + FunctionType::get(VoidTy, {Int8PtrTy, Int8PtrTy, Int8PtrTy}, false); + break; + }; case Intrinsic::coro_id_retcon: case Intrinsic::coro_id_retcon_once: { auto ContinuationId = cast<AnyCoroIdRetconInst>(Id); @@ -512,6 +546,8 @@ Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size, addCallToCallGraph(CG, Call, Alloc); return Call; } + case coro::ABI::Async: + llvm_unreachable("can't allocate memory in coro async-lowering"); } llvm_unreachable("Unknown coro::ABI enum"); } @@ -532,6 +568,8 @@ void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr, addCallToCallGraph(CG, Call, Dealloc); return; } + case coro::ABI::Async: + llvm_unreachable("can't allocate memory in coro async-lowering"); } llvm_unreachable("Unknown coro::ABI enum"); } @@ -633,6 +671,67 @@ void AnyCoroIdRetconInst::checkWellFormed() const { checkWFDealloc(this, getArgOperand(DeallocArg)); } +static void checkAsyncFuncPointer(const Instruction *I, Value *V) { + auto *AsyncFuncPtrAddr = dyn_cast<GlobalVariable>(V->stripPointerCasts()); + if (!AsyncFuncPtrAddr) + fail(I, "llvm.coro.id.async async function pointer not a global", V); + + auto *StructTy = + cast<StructType>(AsyncFuncPtrAddr->getType()->getPointerElementType()); + if (StructTy->isOpaque() || !StructTy->isPacked() || + StructTy->getNumElements() != 2 || + !StructTy->getElementType(0)->isIntegerTy(32) || + !StructTy->getElementType(1)->isIntegerTy(32)) + fail(I, + "llvm.coro.id.async async function pointer argument's type is not " + "<{i32, i32}>", + V); +} + +void CoroIdAsyncInst::checkWellFormed() const { + checkConstantInt(this, getArgOperand(SizeArg), + "size argument to coro.id.async must be constant"); + checkConstantInt(this, getArgOperand(AlignArg), + "alignment argument to coro.id.async must be constant"); + checkConstantInt(this, getArgOperand(StorageArg), + "storage argument offset to coro.id.async must be constant"); + checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg)); +} + +static void checkAsyncContextProjectFunction(const Instruction *I, + Function *F) { + auto *FunTy = cast<FunctionType>(F->getType()->getPointerElementType()); + if (!FunTy->getReturnType()->isPointerTy() || + !FunTy->getReturnType()->getPointerElementType()->isIntegerTy(8)) + fail(I, + "llvm.coro.suspend.async resume function projection function must " + "return an i8* type", + F); + if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() || + !FunTy->getParamType(0)->getPointerElementType()->isIntegerTy(8)) + fail(I, + "llvm.coro.suspend.async resume function projection function must " + "take one i8* type as parameter", + F); +} + +void CoroSuspendAsyncInst::checkWellFormed() const { + checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction()); +} + +void CoroAsyncEndInst::checkWellFormed() const { + auto *MustTailCallFunc = getMustTailCallFunction(); + if (!MustTailCallFunc) + return; + auto *FnTy = + cast<FunctionType>(MustTailCallFunc->getType()->getPointerElementType()); + if (FnTy->getNumParams() != (getNumArgOperands() - 3)) + fail(this, + "llvm.coro.end.async must tail call function argument type must " + "match the tail arguments", + MustTailCallFunc); +} + void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createCoroEarlyLegacyPass()); } |