Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -56,6 +56,7 @@ CodeGenModule &CGM; const codegenoptions::DebugInfoKind DebugKind; bool DebugTypeExtRefs; + bool LocationEnabled = true; llvm::DIBuilder DBuilder; llvm::DICompileUnit *TheCU = nullptr; ModuleMap *ClangModuleMap = nullptr; @@ -314,6 +315,13 @@ /// Set the main CU's DwoId field to \p Signature. void setDwoId(uint64_t Signature); + bool getLocationEnabled() const { return LocationEnabled; } + + /// Used to enable/disable location tracking. This is used by + /// ApplyDebugLocation to inhibit the emission of location information + /// for nested calls. + void setLocationEnabled(bool Enabled) { LocationEnabled = Enabled; } + /// When generating debug information for a clang module or /// precompiled header, this module map will be used to determine /// the module of origin of each Decl. @@ -685,6 +693,39 @@ ~ApplyInlineDebugLocation(); }; +/// Scoped helper to inhibit location emission. +class InhibitDebugLocation { +public: + InhibitDebugLocation() : DI(nullptr), ReEnable(false) {} + explicit InhibitDebugLocation(CGDebugInfo *DI) + : DI(DI), ReEnable(DI && DI->getLocationEnabled()) { + if (DI) + DI->setLocationEnabled(false); + } + + InhibitDebugLocation(const InhibitDebugLocation &Other) = delete; + InhibitDebugLocation(InhibitDebugLocation &&Other) { + ReEnable = false; + *this = std::move(Other); + } + + InhibitDebugLocation &operator=(const InhibitDebugLocation &Other) = delete; + InhibitDebugLocation &operator=(InhibitDebugLocation &&Other) { + DI = Other.DI; + ReEnable = Other.ReEnable; + Other.ReEnable = false; + return *this; + } + ~InhibitDebugLocation() { + if (ReEnable) + DI->setLocationEnabled(true); + } + +private: + CGDebugInfo *DI; + bool ReEnable; +}; + } // namespace CodeGen } // namespace clang Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -161,8 +161,7 @@ } void CGDebugInfo::setLocation(SourceLocation Loc) { - // If the new location isn't valid return. - if (Loc.isInvalid()) + if (!LocationEnabled || Loc.isInvalid()) return; CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); Index: clang/lib/CodeGen/CGException.cpp =================================================================== --- clang/lib/CodeGen/CGException.cpp +++ clang/lib/CodeGen/CGException.cpp @@ -1889,7 +1889,7 @@ // debug info). We have to do this ourselves because we are on the // "simple" statement path. if (HaveInsertPoint()) - EmitStopPoint(&S); + EmitExprLocation(&S); // This must be a __leave from a __finally block, which we warn on and is UB. // Just emit unreachable. Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -35,13 +35,24 @@ // Statement Emission //===----------------------------------------------------------------------===// -void CodeGenFunction::EmitStopPoint(const Stmt *S) { - if (CGDebugInfo *DI = getDebugInfo()) { +InhibitDebugLocation CodeGenFunction::EmitStmtLocation(const Stmt *S) { + InhibitDebugLocation IDL; + if (HaveInsertPoint()) { + EmitExprLocation(S); + if (!CGM.getNestedExpressionLocationsEnabled()) + IDL = InhibitDebugLocation(getDebugInfo()); + } + return IDL; +} + +void CodeGenFunction::EmitExprLocation(const Stmt *S) { + CGDebugInfo *DI = getDebugInfo(); + if (DI && DI->getLocationEnabled()) { SourceLocation Loc; Loc = S->getLocStart(); DI->EmitLocation(Builder, Loc); - LastStopPoint = Loc; + LastDebugLocation = Loc; } } @@ -72,7 +83,16 @@ } // Generate a stoppoint if we are emitting debug info. - EmitStopPoint(S); + InhibitDebugLocation IDL; + switch (S->getStmtClass()) { + case Stmt::CallExprClass: + case Stmt::DeclStmtClass: + case Stmt::ReturnStmtClass: + IDL = EmitStmtLocation(S); + break; + default: + EmitExprLocation(S); + } switch (S->getStmtClass()) { case Stmt::NoStmtClass: @@ -579,7 +599,7 @@ // debug info). We have to do this ourselves because we are on the // "simple" statement path. if (HaveInsertPoint()) - EmitStopPoint(&S); + EmitExprLocation(&S); EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel())); } @@ -756,7 +776,7 @@ // Immediately force cleanup. ConditionScope.ForceCleanup(); - EmitStopPoint(&S); + EmitExprLocation(&S); // Branch to the loop header again. EmitBranch(LoopHeader.getBlock()); @@ -920,7 +940,7 @@ ConditionScope.ForceCleanup(); - EmitStopPoint(&S); + EmitExprLocation(&S); EmitBranch(CondBlock); ForScope.ForceCleanup(); @@ -991,7 +1011,7 @@ EmitStmt(S.getBody()); } - EmitStopPoint(&S); + EmitExprLocation(&S); // If there is an increment, emit it next. EmitBlock(Continue.getBlock()); EmitStmt(S.getInc()); @@ -1110,8 +1130,7 @@ void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) { // As long as debug info is modeled with instructions, we have to ensure we // have a place to insert here and write the stop point here. - if (HaveInsertPoint()) - EmitStopPoint(&S); + InhibitDebugLocation IDL = EmitStmtLocation(&S); for (const auto *I : S.decls()) EmitDecl(*I); @@ -1124,7 +1143,7 @@ // debug info). We have to do this ourselves because we are on the // "simple" statement path. if (HaveInsertPoint()) - EmitStopPoint(&S); + EmitExprLocation(&S); EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock); } @@ -1136,7 +1155,7 @@ // debug info). We have to do this ourselves because we are on the // "simple" statement path. if (HaveInsertPoint()) - EmitStopPoint(&S); + EmitExprLocation(&S); EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock); } Index: clang/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- clang/lib/CodeGen/CGStmtOpenMP.cpp +++ clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1508,7 +1508,7 @@ const OMPLoopDirective &S, CodeGenFunction::JumpDest LoopExit) { CGF.EmitOMPLoopBody(S, LoopExit); - CGF.EmitStopPoint(&S); + CGF.EmitExprLocation(&S); } void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { @@ -1569,7 +1569,7 @@ S.getInc(), [&S](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, JumpDest()); - CGF.EmitStopPoint(&S); + CGF.EmitExprLocation(&S); }, [](CodeGenFunction &) {}); CGF.EmitOMPSimdFinal( @@ -2250,7 +2250,7 @@ S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); - CGF.EmitStopPoint(&S); + CGF.EmitExprLocation(&S); }, [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); @@ -3649,7 +3649,7 @@ auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitStopPoint(CS); + CGF.EmitExprLocation(CS); EmitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(), S.getV(), S.getExpr(), S.getUpdateExpr(), S.isXLHSInRHSPart(), S.getLocStart()); @@ -4201,7 +4201,7 @@ S.getInc(), [&S](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, JumpDest()); - CGF.EmitStopPoint(&S); + CGF.EmitExprLocation(&S); }, [](CodeGenFunction &) {}); // Emit: if (PreCond) - end. Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -87,6 +87,7 @@ class BlockByrefInfo; class BlockFlags; class BlockFieldFlags; +class InhibitDebugLocation; class RegionCodeGenTy; class TargetCodeGenInfo; struct OMPTaskDataTy; @@ -1244,7 +1245,7 @@ unsigned NumSimpleReturnExprs; /// The last regular (non-return) debug location (breakpoint) in the function. - SourceLocation LastStopPoint; + SourceLocation LastDebugLocation; public: /// A scope within which we are constructing the fields of an object which @@ -2525,8 +2526,14 @@ // Statement Emission //===--------------------------------------------------------------------===// - /// EmitStopPoint - Emit a debug stoppoint if we are emitting debug info. - void EmitStopPoint(const Stmt *S); + /// Emit a debug location for a statement if we are emitting debug info. If + /// getNestedExpressionLocationsEnabled() returns false, this also inhibits + /// the emission of debug location information until the returned + /// InhibitDebugLocation object is destroyed. + InhibitDebugLocation EmitStmtLocation(const Stmt *S); + + /// Emit a debug location for an expression if we are emitting debug info. + void EmitExprLocation(const Stmt *S); /// EmitStmt - Emit the code for the statement \arg S. It is legal to call /// this function even if there is no current insertion point. Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -318,7 +318,7 @@ // all will be fine. if (CGDebugInfo *DI = getDebugInfo()) { if (OnlySimpleReturnStmts) - DI->EmitLocation(Builder, LastStopPoint); + DI->EmitLocation(Builder, LastDebugLocation); else DI->EmitLocation(Builder, EndLoc); } Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -29,6 +29,7 @@ #include "clang/Basic/Module.h" #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/XRayLists.h" +#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -70,7 +71,6 @@ class ValueDecl; class VarDecl; class LangOptions; -class CodeGenOptions; class HeaderSearchOptions; class PreprocessorOptions; class DiagnosticsEngine; @@ -513,6 +513,11 @@ /// Finalize LLVM code generation. void Release(); + /// Return true if we should emit location information for nested expressions. + bool getNestedExpressionLocationsEnabled() const { + return !CodeGenOpts.EmitCodeView || CodeGenOpts.DebugColumnInfo; + } + /// Return a reference to the configured Objective-C runtime. CGObjCRuntime &getObjCRuntime() { if (!ObjCRuntime) createObjCRuntime(); Index: clang/test/CodeGenCXX/debug-info-nested-exprs.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-nested-exprs.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-windows-msvc -debug-info-kind=limited \ +// RUN: -gcodeview -emit-llvm -o - %s | FileCheck -check-prefix=NONEST %s +// RUN: %clang_cc1 -triple=x86_64-pc-windows-msvc -debug-info-kind=limited \ +// RUN: -gcodeview -dwarf-column-info -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=COLUMNS %s +// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -debug-info-kind=limited \ +// RUN: -emit-llvm -o - %s | FileCheck -check-prefix=NESTED %s +// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -debug-info-kind=limited \ +// RUN: -dwarf-column-info -emit-llvm -o - %s \ +// RUN: | FileCheck -check-prefix=COLUMNS %s + +// NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[LOC:[0-9]+]] +// NONEST: call i32 @{{.*}}baz{{.*}}, !dbg ![[LOC]] +// NONEST: call i32 @{{.*}}qux{{.*}}, !dbg ![[LOC]] +// NONEST: store i32 {{.*}}, !dbg ![[LOC]] +// NONEST: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]] +// NONEST: store i32 0, i32* %b,{{.*}} !dbg ![[ILOC]] +// NONEST: store i32 0, i32* %c,{{.*}} !dbg ![[ILOC]] +// NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]] +// NONEST: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]] +// NONEST: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]] +// NONEST: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]] +// NONEST: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]] +// NONEST: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]] +// NONEST: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]] +// NONEST: mul nsw i32 {{.*}}, !dbg ![[RETLOC:[0-9]+]] +// NONEST: sub nsw i32 {{.*}}, !dbg ![[RETLOC]] +// NONEST: ret i32 {{.*}}, !dbg ![[RETLOC]] +// NONEST: ![[WHILE1]] = !DILocation( +// NONEST: ![[WHILE2]] = !DILocation( +// NONEST: ![[FOR1]] = !DILocation( +// NONEST: ![[FOR2]] = !DILocation( +// NONEST: ![[IF1]] = !DILocation( +// NONEST: ![[IF2]] = !DILocation( +// NONEST: ![[IF3]] = !DILocation( + +// NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]] +// NESTED: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]] +// NESTED: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]] +// NESTED: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]] +// NESTED: store i32 0, i32* %b,{{.*}} !dbg ![[ILOC]] +// NESTED: store i32 0, i32* %c,{{.*}} !dbg ![[ILOC]] +// NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]] +// NESTED: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]] +// NESTED: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]] +// NESTED: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]] +// NESTED: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]] +// NESTED: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]] +// NESTED: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]] +// NESTED: mul nsw i32 {{.*}}, !dbg ![[RETMUL:[0-9]+]] +// NESTED: sub nsw i32 {{.*}}, !dbg ![[RETSUB:[0-9]+]] +// NESTED: ret i32 {{.*}}, !dbg ! +// NESTED: ![[BAR]] = !DILocation( +// NESTED: ![[BAZ]] = !DILocation( +// NESTED: ![[QUX]] = !DILocation( +// NESTED: ![[RETSUB]] = !DILocation( +// NESTED: ![[RETMUL]] = !DILocation( + +// COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[BAR:[0-9]+]] +// COLUMNS: call i32 @{{.*}}baz{{.*}}, !dbg ![[BAZ:[0-9]+]] +// COLUMNS: call i32 @{{.*}}qux{{.*}}, !dbg ![[QUX:[0-9]+]] +// COLUMNS: store i32 1, i32* %i,{{.*}} !dbg ![[ILOC:[0-9]+]] +// COLUMNS: store i32 0, i32* %b,{{.*}} !dbg ![[BLOC:[0-9]+]] +// COLUMNS: store i32 0, i32* %c,{{.*}} !dbg ![[CLOC:[0-9]+]] +// COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[WHILE1:[0-9]+]] +// COLUMNS: store i32 %{{[^,]+}}, i32* %i,{{.*}} !dbg ![[WHILE2:[0-9]+]] +// COLUMNS: call i32 @{{.*}}bar{{.*}}, !dbg ![[FOR1:[0-9]+]] +// COLUMNS: call i32 @{{.*}}qux{{.*}}, !dbg ![[FOR2:[0-9]+]] +// COLUMNS: store i32 %{{[^,]+}}, i32* %t,{{.*}} !dbg ![[IF1:[0-9]+]] +// COLUMNS: store i32 %{{[^,]+}}, i32* %a,{{.*}} !dbg ![[IF2:[0-9]+]] +// COLUMNS: store i32 %{{[^,]+}}, i32* %b,{{.*}} !dbg ![[IF3:[0-9]+]] +// COLUMNS: mul nsw i32 {{.*}}, !dbg ![[RETMUL:[0-9]+]] +// COLUMNS: sub nsw i32 {{.*}}, !dbg ![[RETSUB:[0-9]+]] +// COLUMNS: ret i32 {{.*}}, !dbg ! +// COLUMNS: ![[BAR]] = !DILocation( +// COLUMNS: ![[BAZ]] = !DILocation( +// COLUMNS: ![[QUX]] = !DILocation( +// COLUMNS: ![[ILOC]] = !DILocation( +// COLUMNS: ![[BLOC]] = !DILocation( +// COLUMNS: ![[CLOC]] = !DILocation( +// COLUNMS: ![[RETSUB]] = !DILocation( +// COLUMNS: ![[RETMUL]] = !DILocation( + +int bar(int x, int y); +int baz(int x, int y); +int qux(int x, int y); + +int foo(int x, int y, int z) { + int a = bar(x, y) + + baz(x, z) + + qux(y, z); + + int i = 1, b = 0, c = 0; + while (i > 0) { + b = bar(a, b); + --i; + } + for (i = 0; i < 1; i++) { + b = bar(a, b); + c = qux(a, c); + } + if (a < b) { + int t = a; + a = b; + b = t; + } + + return a - + (b * z); +}