diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -488,10 +488,10 @@ /// Emit call to \c llvm.dbg.declare for an argument variable /// declaration. - llvm::DILocalVariable *EmitDeclareOfArgVariable(const VarDecl *Decl, - llvm::Value *AI, - unsigned ArgNo, - CGBuilderTy &Builder); + llvm::DILocalVariable * + EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, unsigned ArgNo, + CGBuilderTy &Builder, + const bool UsePointerValue = false); /// Emit call to \c llvm.dbg.declare for the block-literal argument /// to a block invocation function. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4822,9 +4822,10 @@ llvm::DILocalVariable * CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, - unsigned ArgNo, CGBuilderTy &Builder) { + unsigned ArgNo, CGBuilderTy &Builder, + const bool UsePointerValue) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); - return EmitDeclare(VD, AI, ArgNo, Builder); + return EmitDeclare(VD, AI, ArgNo, Builder, UsePointerValue); } namespace { diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -2475,6 +2475,13 @@ Address AllocaPtr = Address::invalid(); bool DoStore = false; bool IsScalar = hasScalarEvaluationKind(Ty); + bool UseIndirectDebugAddress = false; + const bool ShouldEmitDebugInfo = [&] { + // Emit debug info for param declarations in non-thunk functions. + return getDebugInfo() && CGM.getCodeGenOpts().hasReducedDebugInfo() && + !CurFuncIsThunk && !NoDebugInfo; + }(); + // If we already have a pointer to the argument, reuse the input pointer. if (Arg.isIndirect()) { // If we have a prettier pointer type at this point, bitcast to that. @@ -2486,6 +2493,19 @@ auto AllocaAS = CGM.getASTAllocaAddressSpace(); auto *V = DeclPtr.getPointer(); AllocaPtr = DeclPtr; + + // For truly ABI indirect arguments, that is, they are not `byval`, store + // the address of the argument on the stack to preserve debug information. + ABIArgInfo ArgInfo = CurFnInfo->arguments()[ArgNo - 1].info; + if (ShouldEmitDebugInfo && ArgInfo.isIndirect()) + UseIndirectDebugAddress = !ArgInfo.getIndirectByVal(); + if (UseIndirectDebugAddress) { + auto PtrTy = getContext().getPointerType(Ty); + AllocaPtr = CreateMemTemp(PtrTy, getContext().getTypeAlignInChars(PtrTy), + D.getName() + ".indirect_addr"); + EmitStoreOfScalar(V, AllocaPtr, /* Volatile */ false, PtrTy); + } + auto SrcLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : AllocaAS; auto DestLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : LangAS::Default; @@ -2597,15 +2617,13 @@ setAddrOfLocalVar(&D, DeclPtr); - // Emit debug info for param declarations in non-thunk functions. - if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk && - !NoDebugInfo) { - llvm::DILocalVariable *DILocalVar = DI->EmitDeclareOfArgVariable( - &D, AllocaPtr.getPointer(), ArgNo, Builder); - if (const auto *Var = dyn_cast_or_null(&D)) - DI->getParamDbgMappings().insert({Var, DILocalVar}); - } + if (ShouldEmitDebugInfo) { + CGDebugInfo *DI = getDebugInfo(); + assert(DI); + llvm::DILocalVariable *DILocalVar = DI->EmitDeclareOfArgVariable( + &D, AllocaPtr.getPointer(), ArgNo, Builder, UseIndirectDebugAddress); + if (const auto *Var = dyn_cast_or_null(&D)) + DI->getParamDbgMappings().insert({Var, DILocalVar}); } if (D.hasAttr()) diff --git a/clang/test/CodeGenCXX/debug-info.cpp b/clang/test/CodeGenCXX/debug-info.cpp --- a/clang/test/CodeGenCXX/debug-info.cpp +++ b/clang/test/CodeGenCXX/debug-info.cpp @@ -4,7 +4,13 @@ // CHECK: @_ZN6pr96081xE ={{.*}} global ptr null, align 8, !dbg [[X:![0-9]+]] // CHECK: define{{.*}} void @_ZN7pr147634funcENS_3fooE -// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[F:[0-9]+]], metadata !DIExpression()) +// CHECK-SAME: ptr noundef [[param:%.*]]) +// CHECK-NEXT: entry: +// CHECK-NEXT: alloca ptr, align 8 +// CHECK-NEXT: [[param_addr_storage:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store +// CHECK-NEXT: store ptr [[param]], ptr [[param_addr_storage]], align 8 +// CHECK-NEXT: call void @llvm.dbg.declare(metadata ptr [[param_addr_storage]], metadata ![[F:[0-9]+]], metadata !DIExpression(DW_OP_deref)) // !llvm.dbg.cu pulls in globals and their types first. // CHECK-NOT: !DIGlobalVariable(name: "c"