Index: clang/lib/CodeGen/CGCoroutine.cpp =================================================================== --- clang/lib/CodeGen/CGCoroutine.cpp +++ clang/lib/CodeGen/CGCoroutine.cpp @@ -600,10 +600,22 @@ CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB); { + CGDebugInfo *DI = getDebugInfo(); ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap); CodeGenFunction::RunCleanupsScope ResumeScope(*this); EHStack.pushCleanup(NormalAndEHCleanup, S.getDeallocate()); + // Create map between parameters and copy-params for coroutine function + auto ParamMoves = S.getParamMoves(); + assert((ParamMoves.size() == 0 || (ParamMoves.size() == FnArgs.size())) && + "should be same"); + if (ParamMoves.size() == FnArgs.size() && DI) + for (uint64_t i = 0, ParamSize = ParamMoves.size(); i < ParamSize; i++) { + assert(isa(FnArgs[i]) && "should be parameter"); + if (const auto *ParmDecl = dyn_cast_or_null(FnArgs[i])) + DI->appendParamDecl2Stmt(ParmDecl, ParamMoves[i]); + } + // Create parameter copies. We do it before creating a promise, since an // evolution of coroutine TS may allow promise constructor to observe // parameter copies. @@ -615,6 +627,10 @@ // not needed. } + // Clear map + if (DI) + DI->clearParamDecl2Stmt(); + EmitStmt(S.getPromiseDeclStmt()); Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl()); Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -161,6 +161,15 @@ llvm::DenseMap> StaticDataMemberCache; + using ParamDecl2StmtTy = llvm::DenseMap; + using Param2DILocTy = + llvm::DenseMap; + + /// The key is coroutine real parameters, value is coroutine move parameters + ParamDecl2StmtTy CoroutineParameterMappings; + /// The key is coroutine real parameters, value is DIVariable in LLVM IR + Param2DILocTy ParamDbgMappings; + /// Helper functions for getOrCreateType. /// @{ /// Currently the checksum of an interface includes the number of @@ -463,8 +472,10 @@ /// Emit call to \c llvm.dbg.declare for an argument variable /// declaration. - void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, - unsigned ArgNo, CGBuilderTy &Builder); + llvm::DILocalVariable *EmitDeclareOfArgVariable(const VarDecl *Decl, + llvm::Value *AI, + unsigned ArgNo, + CGBuilderTy &Builder); /// Emit call to \c llvm.dbg.declare for the block-literal argument /// to a block invocation function. @@ -533,6 +544,24 @@ SourceLocation LineLoc, SourceLocation FileLoc); + void copyCoroParamMappingsIfEmpty(ParamDecl2StmtTy &CoroParamMappings) { + if (!CoroutineParameterMappings.empty()) + return; + for (auto KeyVal : CoroParamMappings) + CoroutineParameterMappings.insert(KeyVal); + } + + void appendParam2DILoc(const ParmVarDecl *Var, + llvm::DILocalVariable *DILocalVar) { + ParamDbgMappings.insert({Var, DILocalVar}); + } + + void appendParamDecl2Stmt(const ParmVarDecl *Param, const Stmt *MovParam) { + CoroutineParameterMappings.insert({Param, MovParam}); + } + + void clearParamDecl2Stmt() { ParamDbgMappings.clear(); } + private: /// Emit call to llvm.dbg.declare for a variable declaration. /// Returns a pointer to the DILocalVariable associated with the Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -411,7 +411,7 @@ } else { PresumedLoc PLoc = SM.getPresumedLoc(Loc); FileName = PLoc.getFilename(); - + if (FileName.empty()) { FileName = TheCU->getFile()->getFilename(); } else { @@ -4352,13 +4352,63 @@ } // Create the descriptor for the variable. - auto *D = ArgNo ? DBuilder.createParameterVariable( - Scope, Name, *ArgNo, Unit, Line, Ty, - CGM.getLangOpts().Optimize, Flags) - : DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty, - CGM.getLangOpts().Optimize, - Flags, Align); + llvm::DILocalVariable *D = nullptr; + if (ArgNo) { + D = DBuilder.createParameterVariable(Scope, Name, *ArgNo, Unit, Line, Ty, + CGM.getLangOpts().Optimize, Flags); + } else { + // For normal local variable, we will try to find out whether 'VD' is the + // copy parameter of coroutine. + // If yes, we would love to use DIVariable of the origin parameter instead + // of creating the new one. + // If no, it might a normal alloc, we just create a new one for it. + + // Check whether the VD is move parameters + ParmVarDecl *PD = nullptr; + for (auto &Pair : CoroutineParameterMappings) + if (const DeclStmt *DeclStmtPtr = + dyn_cast_or_null(Pair.second)) { + const DeclGroupRef DeclGroup = DeclStmtPtr->getDeclGroup(); + const Decl *Decl = DeclGroup.getSingleDecl(); + if (const VarDecl *Var = dyn_cast_or_null(Decl)) + if (Var == VD) { + PD = const_cast(Pair.first); + break; + } + } + + // If yes, use the the same DIVariable of coroutine paarameters + if (PD) { + for (auto &DbgPair : ParamDbgMappings) + if (DbgPair.first == PD) { + D = const_cast(DbgPair.second); + break; + } + + // scope must be same + assert(D && "D should not be nullptr"); + + do { + // The scope of parameter and move-parameter should be distinct + // DISubprogram. + if (!isa(Scope) || !Scope->isDistinct()) { + D = nullptr; + break; + } + + // Scope should be same + if (D->getScope() != Scope) { + D = nullptr; + break; + } + } while (0); + } + // Or we will create a new DIVariable for this Decl + if (!D) + D = DBuilder.createAutoVariable(Scope, Name, Unit, Line, Ty, + CGM.getLangOpts().Optimize, Flags, Align); + } // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), llvm::DILocation::get(CGM.getLLVMContext(), Line, @@ -4483,11 +4533,11 @@ DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock()); } -void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, - unsigned ArgNo, - CGBuilderTy &Builder) { +llvm::DILocalVariable * +CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, + unsigned ArgNo, CGBuilderTy &Builder) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); - EmitDeclare(VD, AI, ArgNo, Builder); + return EmitDeclare(VD, AI, ArgNo, Builder); } namespace { Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -2568,7 +2568,10 @@ // Emit debug info for param declarations in non-thunk functions. if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk) { - DI->EmitDeclareOfArgVariable(&D, DeclPtr.getPointer(), ArgNo, Builder); + llvm::DILocalVariable *DILocalVar = DI->EmitDeclareOfArgVariable( + &D, DeclPtr.getPointer(), ArgNo, Builder); + if (const auto *Var = dyn_cast_or_null(&D)) + DI->appendParam2DILoc(Var, DILocalVar); } } Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -325,6 +325,9 @@ QualType FnRetTy; llvm::Function *CurFn = nullptr; + /// Save Parameter Decl for coroutine + llvm::SmallVector FnArgs; + // Holds coroutine data if the current function is a coroutine. We use a // wrapper to manage its lifetime, so that we don't have to define CGCoroData // in this header. Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -1317,6 +1317,11 @@ // Emit the standard function prologue. StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin()); + // Save parameters for coroutine function + if (Body && isa(Body)) + for (const auto *ParamDecl : FD->parameters()) + FnArgs.push_back(ParamDecl); + // Generate the body of the function. PGO.assignRegionCounters(GD, CurFn); if (isa(FD)) Index: clang/test/CodeGenCoroutines/coro-dwarf.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCoroutines/coro-dwarf.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -std=c++2a -fcoroutines-ts -triple=x86_64 -dwarf-version=4 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +namespace std::experimental { +template struct coroutine_traits; + +template struct coroutine_handle { + coroutine_handle() = default; + static coroutine_handle from_address(void *) noexcept; +}; +template <> struct coroutine_handle { + static coroutine_handle from_address(void *) noexcept; + coroutine_handle() = default; + template + coroutine_handle(coroutine_handle) noexcept; +}; +} // namespace std::experimental + +struct suspend_always { + bool await_ready() noexcept; + void await_suspend(std::experimental::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +template struct std::experimental::coroutine_traits { + struct promise_type { + void get_return_object() noexcept; + suspend_always initial_suspend() noexcept; + suspend_always final_suspend() noexcept; + void return_void() noexcept; + promise_type(); + ~promise_type() noexcept; + void unhandled_exception() noexcept; + }; +}; + +// TODO: Not supported yet +struct CopyOnly { + int val; + CopyOnly(const CopyOnly &) noexcept; + CopyOnly(CopyOnly &&) = delete; + ~CopyOnly(); +}; + +struct MoveOnly { + int val; + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) noexcept; + ~MoveOnly(); +}; + +struct MoveAndCopy { + int val; + MoveAndCopy(const MoveAndCopy &) noexcept; + MoveAndCopy(MoveAndCopy &&) noexcept; + ~MoveAndCopy(); +}; + +void consume(int, int, int) noexcept; + +void f_coro(int val, MoveOnly moParam, MoveAndCopy mcParam) { + consume(val, moParam.val, mcParam.val); + co_return; +} + +// CHECK: ![[SP:[0-9]+]] = distinct !DISubprogram(name: "f_coro", linkageName: "_Z6f_coroi8MoveOnly11MoveAndCopy" +// CHECK: !{{[0-9]+}} = !DILocalVariable(name: "val", arg: 1, scope: ![[SP]], file: !8, line: 60, type: !{{[0-9]+}}) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 60, column: 17, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocalVariable(name: "moParam", arg: 2, scope: ![[SP]], file: !8, line: 60, type: !{{[0-9]+}}) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 60, column: 31, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocalVariable(name: "mcParam", arg: 3, scope: ![[SP]], file: !8, line: 60, type: !{{[0-9]+}}) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 60, column: 52, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 60, column: 61, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 60, column: 6, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 0, scope: ![[SP]]) +// CHECK-NEXT: !{{[0-9]+}} = !DILocation(line: 62, column: 3, scope: ![[SP]])