diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -8,6 +8,7 @@ #include "llvm/Transforms/Coroutines/CoroEarly.h" #include "CoroInternal.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" @@ -37,7 +38,7 @@ ->getPointerTo()) {} void lowerEarlyIntrinsics(Function &F); }; -} +} // namespace // Replace a direct call to coro.resume or coro.destroy with an indirect call to // an address returned by coro.subfn.addr intrinsic. This is done so that @@ -65,8 +66,8 @@ auto *SampleStruct = StructType::get(Context, {AnyResumeFnPtrTy, AnyResumeFnPtrTy, Int8Ty}); const DataLayout &DL = TheModule.getDataLayout(); - int64_t Offset = alignTo( - DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment); + int64_t Offset = + alignTo(DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment); if (Intrin->isFromPromise()) Offset = -Offset; @@ -100,6 +101,24 @@ II->eraseFromParent(); } +static void buildDebugInfoForNoopResumeDestroyFunc(Function *NoopFn) { + Module &M = *NoopFn->getParent(); + if (!M.debug_compile_units().empty()) { + DICompileUnit *CU = *M.debug_compile_units_begin(); + DIBuilder DB(M, /*AllowUnresolved*/ false, CU); + std::array Params{nullptr, nullptr}; + auto *SubroutineType = + DB.createSubroutineType(DB.getOrCreateTypeArray(Params)); + StringRef Name = NoopFn->getName(); + auto *SP = DB.createFunction( + CU, /*Name=*/Name, /*LinkageName=*/Name, /*File*/ nullptr, + /*LineNo=*/0, SubroutineType, /*ScopeLine=*/0, DINode::FlagArtificial, + DISubprogram::SPFlagDefinition); + NoopFn->setSubprogram(SP); + DB.finalize(); + } +} + void Lowerer::lowerCoroNoop(IntrinsicInst *II) { if (!NoopCoro) { LLVMContext &C = Builder.getContext(); @@ -116,17 +135,18 @@ // Create a Noop function that does nothing. Function *NoopFn = Function::Create(FnTy, GlobalValue::LinkageTypes::PrivateLinkage, - "NoopCoro.ResumeDestroy", &M); + "__NoopCoro_ResumeDestroy", &M); NoopFn->setCallingConv(CallingConv::Fast); + buildDebugInfoForNoopResumeDestroyFunc(NoopFn); 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"); + 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); @@ -155,57 +175,57 @@ continue; switch (CB->getIntrinsicID()) { - default: - continue; - case Intrinsic::coro_free: - CoroFrees.push_back(cast(&I)); - break; - case Intrinsic::coro_suspend: - // Make sure that final suspend point is not duplicated as CoroSplit - // pass expects that there is at most one final suspend point. - if (cast(&I)->isFinal()) - CB->setCannotDuplicate(); - HasCoroSuspend = true; - break; - case Intrinsic::coro_end_async: - case Intrinsic::coro_end: - // Make sure that fallthrough coro.end is not duplicated as CoroSplit - // pass expects that there is at most one fallthrough coro.end. - if (cast(&I)->isFallthrough()) - CB->setCannotDuplicate(); - break; - case Intrinsic::coro_noop: - lowerCoroNoop(cast(&I)); - break; - case Intrinsic::coro_id: - if (auto *CII = cast(&I)) { - if (CII->getInfo().isPreSplit()) { - assert(F.isPresplitCoroutine() && - "The frontend uses Swtich-Resumed ABI should emit " - "\"coroutine.presplit\" attribute for the coroutine."); - setCannotDuplicate(CII); - CII->setCoroutineSelf(); - CoroId = cast(&I); - } + default: + continue; + case Intrinsic::coro_free: + CoroFrees.push_back(cast(&I)); + break; + case Intrinsic::coro_suspend: + // Make sure that final suspend point is not duplicated as CoroSplit + // pass expects that there is at most one final suspend point. + if (cast(&I)->isFinal()) + CB->setCannotDuplicate(); + HasCoroSuspend = true; + break; + case Intrinsic::coro_end_async: + case Intrinsic::coro_end: + // Make sure that fallthrough coro.end is not duplicated as CoroSplit + // pass expects that there is at most one fallthrough coro.end. + if (cast(&I)->isFallthrough()) + CB->setCannotDuplicate(); + break; + case Intrinsic::coro_noop: + lowerCoroNoop(cast(&I)); + break; + case Intrinsic::coro_id: + if (auto *CII = cast(&I)) { + if (CII->getInfo().isPreSplit()) { + assert(F.isPresplitCoroutine() && + "The frontend uses Swtich-Resumed ABI should emit " + "\"coroutine.presplit\" attribute for the coroutine."); + setCannotDuplicate(CII); + CII->setCoroutineSelf(); + CoroId = cast(&I); } - break; - case Intrinsic::coro_id_retcon: - case Intrinsic::coro_id_retcon_once: - case Intrinsic::coro_id_async: - F.setPresplitCoroutine(); - break; - case Intrinsic::coro_resume: - lowerResumeOrDestroy(*CB, CoroSubFnInst::ResumeIndex); - break; - case Intrinsic::coro_destroy: - lowerResumeOrDestroy(*CB, CoroSubFnInst::DestroyIndex); - break; - case Intrinsic::coro_promise: - lowerCoroPromise(cast(&I)); - break; - case Intrinsic::coro_done: - lowerCoroDone(cast(&I)); - break; + } + break; + case Intrinsic::coro_id_retcon: + case Intrinsic::coro_id_retcon_once: + case Intrinsic::coro_id_async: + F.setPresplitCoroutine(); + break; + case Intrinsic::coro_resume: + lowerResumeOrDestroy(*CB, CoroSubFnInst::ResumeIndex); + break; + case Intrinsic::coro_destroy: + lowerResumeOrDestroy(*CB, CoroSubFnInst::DestroyIndex); + break; + case Intrinsic::coro_promise: + lowerCoroPromise(cast(&I)); + break; + case Intrinsic::coro_done: + lowerCoroDone(cast(&I)); + break; } } diff --git a/llvm/test/Transforms/Coroutines/coro-noop.ll b/llvm/test/Transforms/Coroutines/coro-noop.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-noop.ll @@ -0,0 +1,25 @@ +; Tests that CoroEarly pass correctly lowers coro.noop +; RUN: opt < %s -S -passes=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: @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 +} + +declare i8* @llvm.coro.noop() + + +; CHECK: define private fastcc void @_NoopCoro_ResumeDestroy(%NoopCoro.Frame* %0) !dbg ![[RESUME:[0-9]+]] { +; CHECK-NEXT: entry +; CHECK-NEXT: ret void + +; CHECK: ![[RESUME]] = distinct !DISubprogram(name: "_NoopCoro_ResumeDestroy", linkageName: "_NoopCoro_ResumeDestroy" + diff --git a/llvm/test/Transforms/Coroutines/coro-early.ll b/llvm/test/Transforms/Coroutines/coro-resume-destroy.ll rename from llvm/test/Transforms/Coroutines/coro-early.ll rename to llvm/test/Transforms/Coroutines/coro-resume-destroy.ll --- a/llvm/test/Transforms/Coroutines/coro-early.ll +++ b/llvm/test/Transforms/Coroutines/coro-resume-destroy.ll @@ -1,10 +1,6 @@ ; Tests that CoroEarly pass correctly lowers coro.resume, coro.destroy -; and other intrinsics managed by this pass. ; RUN: opt < %s -S -passes=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 @@ -41,20 +37,5 @@ } -; 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* %0) { -; CHECK-NEXT: entry -; CHECK-NEXT: ret void - - declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) -declare i8* @llvm.coro.noop()