[clang] [clang][DebugInfo] Attach DW_AT_const_value to static data-member definitions if available (PR #72730)

Michael Buch via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 20 08:17:29 PST 2023


https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/72730

>From 6dcb09dcc50a9b9e92640412242927b3e226929e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 18 Nov 2023 00:20:05 +0000
Subject: [PATCH 1/8] [clang][DebugInfo][NFC] Create
 evaluateConstantInitializer helper function

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0b52d99ad07f164..4840581b5d03f89 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -69,6 +69,19 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
   return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
 }
 
+APValue const * evaluateConstantInitializer(clang::VarDecl const * VD) {
+  assert (VD != nullptr);
+
+  VD = VD->getCanonicalDecl();
+  if (!VD)
+    return nullptr;
+
+  if (!VD->hasConstantInitialization() || !VD->hasInit())
+    return nullptr;
+
+  return VD->evaluateValue();
+}
+
 CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
     : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
       DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -5596,14 +5609,11 @@ void CGDebugInfo::EmitGlobalVariable(const VarDecl *VD) {
   if (VD->hasAttr<NoDebugAttr>())
     return;
 
-  if (!VD->hasInit())
-    return;
-
   const auto CacheIt = DeclCache.find(VD);
   if (CacheIt != DeclCache.end())
     return;
 
-  auto const *InitVal = VD->evaluateValue();
+  auto const * InitVal = evaluateConstantInitializer(VD);
   if (!InitVal)
     return;
 

>From fcc6e19d108798fb18c1973e4d4cc3800da07f9f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 18 Nov 2023 00:52:24 +0000
Subject: [PATCH 2/8] fixup! clang-format

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 4840581b5d03f89..9bba6e6b13e9318 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -69,8 +69,8 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
   return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
 }
 
-APValue const * evaluateConstantInitializer(clang::VarDecl const * VD) {
-  assert (VD != nullptr);
+APValue const *evaluateConstantInitializer(clang::VarDecl const *VD) {
+  assert(VD != nullptr);
 
   VD = VD->getCanonicalDecl();
   if (!VD)
@@ -5613,7 +5613,7 @@ void CGDebugInfo::EmitGlobalVariable(const VarDecl *VD) {
   if (CacheIt != DeclCache.end())
     return;
 
-  auto const * InitVal = evaluateConstantInitializer(VD);
+  auto const *InitVal = evaluateConstantInitializer(VD);
   if (!InitVal)
     return;
 

>From 148ab1793a866111060f77807ff065040fad92d8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 18 Nov 2023 00:22:06 +0000
Subject: [PATCH 3/8] [clang][DebugInfo] Attach DW_AT_const_value to static
 data-member definitions if available

---
 clang/lib/CodeGen/CGDebugInfo.cpp                      | 10 ++++++++--
 .../CodeGenCXX/debug-info-static-inline-member.cpp     |  2 +-
 clang/test/CodeGenCXX/inline-dllexport-member.cpp      |  2 +-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 9bba6e6b13e9318..e01c57baef19931 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -5516,11 +5516,17 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
     }
     AppendAddressSpaceXDeref(AddressSpace, Expr);
 
+    llvm::DIExpression *E = nullptr;
+    if (Expr.empty()) {
+      if (auto const *InitVal = evaluateConstantInitializer(D))
+        E = createConstantValueExpression(D, *InitVal);
+    } else
+      E = DBuilder.createExpression(Expr);
+
     llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
     GVE = DBuilder.createGlobalVariableExpression(
         DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
-        Var->hasLocalLinkage(), true,
-        Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
+        Var->hasLocalLinkage(), true, E,
         getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
         Align, Annotations);
     Var->addDebugInfo(GVE);
diff --git a/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
index f2d4d9408a8297a..950ea9b302b290c 100644
--- a/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
+++ b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
@@ -43,7 +43,7 @@ int main() {
 // CHECK:      @{{.*}}cexpr_struct_with_addr{{.*}} = 
 // CHECK-SAME    !dbg ![[EMPTY_GLOBAL:[0-9]+]]
 
-// CHECK:      !DIGlobalVariableExpression(var: ![[INT_VAR:[0-9]+]], expr: !DIExpression())
+// CHECK:      !DIGlobalVariableExpression(var: ![[INT_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 25, DW_OP_stack_value))
 // CHECK:      ![[INT_VAR]] = distinct !DIGlobalVariable(name: "cexpr_int_with_addr", linkageName:
 // CHECK-SAME:                isLocal: false, isDefinition: true, declaration: ![[INT_DECL:[0-9]+]])
 
diff --git a/clang/test/CodeGenCXX/inline-dllexport-member.cpp b/clang/test/CodeGenCXX/inline-dllexport-member.cpp
index d6b004d66dc6cbd..6bc01599c466780 100644
--- a/clang/test/CodeGenCXX/inline-dllexport-member.cpp
+++ b/clang/test/CodeGenCXX/inline-dllexport-member.cpp
@@ -7,7 +7,7 @@ struct __declspec(dllexport) s {
   static const unsigned int ui = 0;
 };
 
-// CHECK: [[UI]] = !DIGlobalVariableExpression(var: [[UIV:.*]], expr: !DIExpression())
+// CHECK: [[UI]] = !DIGlobalVariableExpression(var: [[UIV:.*]], expr: !DIExpression(DW_OP_constu, 0, DW_OP_stack_value))
 // CHECK: [[UIV]] = distinct !DIGlobalVariable(name: "ui", linkageName: "?ui at s@@2IB", scope: ![[SCOPE:[0-9]+]],
 // CHECK: ![[SCOPE]] = distinct !DICompileUnit(
 

>From d654d67012fa3370904c440a7045885d237b2389 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 18 Nov 2023 00:55:01 +0000
Subject: [PATCH 4/8] fixup! make helper static

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index e01c57baef19931..b0460c93acb4f67 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -69,7 +69,7 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
   return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
 }
 
-APValue const *evaluateConstantInitializer(clang::VarDecl const *VD) {
+static APValue const *evaluateConstantInitializer(clang::VarDecl const *VD) {
   assert(VD != nullptr);
 
   VD = VD->getCanonicalDecl();

>From e21fb80c09d66ff036b65425ff29f69f95eba226 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 18 Nov 2023 14:15:24 +0000
Subject: [PATCH 5/8] fixup! add braces to adhere to llvm-code style

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index b0460c93acb4f67..0db72ad33cdd1d2 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -5520,8 +5520,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
     if (Expr.empty()) {
       if (auto const *InitVal = evaluateConstantInitializer(D))
         E = createConstantValueExpression(D, *InitVal);
-    } else
+    } else {
       E = DBuilder.createExpression(Expr);
+    }
 
     llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
     GVE = DBuilder.createGlobalVariableExpression(

>From c5a6f0e4b6eea316f3d9a9ef32fb787cb4836354 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 20 Nov 2023 10:38:19 +0000
Subject: [PATCH 6/8] fixup! use getAnyInitializer instead of canonical decl

This is more idiomatic
---
 clang/lib/CodeGen/CGDebugInfo.cpp | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0db72ad33cdd1d2..54a368db7f77d16 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -69,17 +69,27 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
   return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0;
 }
 
-static APValue const *evaluateConstantInitializer(clang::VarDecl const *VD) {
+/// Given a VarDecl corresponding to either the definition or
+/// declaration of a C++ static data member, if it has a constant
+/// initializer and is evaluatable, return the evaluated value.
+/// Returns std::nullopt on failure.
+static std::optional<APValue>
+evaluateConstantInitializer(const clang::VarDecl *VD,
+                            const clang::ASTContext &Ctx) {
   assert(VD != nullptr);
 
-  VD = VD->getCanonicalDecl();
-  if (!VD)
-    return nullptr;
+  if (!VD->isStaticDataMember())
+    return std::nullopt;
 
-  if (!VD->hasConstantInitialization() || !VD->hasInit())
-    return nullptr;
+  if (!VD->isUsableInConstantExpressions(Ctx))
+    return std::nullopt;
+
+  auto const *InitExpr = VD->getAnyInitializer();
+  Expr::EvalResult Result;
+  if (!InitExpr->EvaluateAsConstantExpr(Result, Ctx))
+    return std::nullopt;
 
-  return VD->evaluateValue();
+  return Result.Val;
 }
 
 CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
@@ -5518,7 +5528,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
 
     llvm::DIExpression *E = nullptr;
     if (Expr.empty()) {
-      if (auto const *InitVal = evaluateConstantInitializer(D))
+      if (const auto InitVal = evaluateConstantInitializer(D, CGM.getContext()))
         E = createConstantValueExpression(D, *InitVal);
     } else {
       E = DBuilder.createExpression(Expr);
@@ -5620,7 +5630,7 @@ void CGDebugInfo::EmitGlobalVariable(const VarDecl *VD) {
   if (CacheIt != DeclCache.end())
     return;
 
-  auto const *InitVal = evaluateConstantInitializer(VD);
+  const auto InitVal = evaluateConstantInitializer(VD, CGM.getContext());
   if (!InitVal)
     return;
 

>From 6677a50749f717b8c8ef6f56bc1fb771da8a4cd0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 20 Nov 2023 12:43:19 +0000
Subject: [PATCH 7/8] fixup! fix tests

* `debug-info-static-member.cpp`:
  * We added the check for `const_b` as part of the
    patch series in `638a8393615e911b729d5662096f60ef49f1c65e`.
    The new check `isUsableAsConstantExpression` doesn't support
    constant inline floats (since they are neither constexpr nor
    integrals). This isn't a regression since before said patch series
    we wouldn't ever emit the definition for `const_b` anyway. Now
    we just don't do it for `const float`s. This is consistent with
    GCC's behaviour starting with C++11.

* `debug-info-static-inline-member`:
  * This was just a bug which is now fixed. We shouldn't emit
    a `DW_AT_const_value` for a non-const static.
---
 .../CodeGenCXX/debug-info-static-inline-member.cpp |  9 ---------
 clang/test/CodeGenCXX/debug-info-static-member.cpp | 14 +++++++-------
 2 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
index 950ea9b302b290c..b7683f9dc8825d2 100644
--- a/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
+++ b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp
@@ -67,10 +67,6 @@ int main() {
 // CHECK-SAME:                          flags: DIFlagStaticMember
 // CHECK-NOT:                           extraData:
 
-// CHECK:      ![[IENUM_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "inline_enum",
-// CHECK-SAME:                          flags: DIFlagStaticMember
-// CHECK-NOT:                           extraData:
-
 // CHECK:      ![[EMPTY_TEMPLATED_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "empty_templated",
 // CHECK-SAME:                                    flags: DIFlagStaticMember
 // CHECK-NOT:                                     extraData:
@@ -98,11 +94,6 @@ int main() {
 // CHECK-NOT:                  linkageName:
 // CHECK-SAME:                 isLocal: true, isDefinition: true, declaration: ![[ENUM_DECL]])
 
-// CHECK:      !DIGlobalVariableExpression(var: ![[IENUM_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value))
-// CHECK:      ![[IENUM_VAR]] = distinct !DIGlobalVariable(name: "inline_enum"
-// CHECK-NOT:                   linkageName:
-// CHECK-SAME:                  isLocal: true, isDefinition: true, declaration: ![[IENUM_DECL]])
-
 // CHECK:      !DIGlobalVariableExpression(var: ![[EMPTY_TEMPLATED_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value))
 // CHECK:      ![[EMPTY_TEMPLATED_VAR]] = distinct !DIGlobalVariable(name: "empty_templated"
 // CHECK-NOT:                             linkageName:
diff --git a/clang/test/CodeGenCXX/debug-info-static-member.cpp b/clang/test/CodeGenCXX/debug-info-static-member.cpp
index a2d25e98ed1cb62..519c971e1fbf1b9 100644
--- a/clang/test/CodeGenCXX/debug-info-static-member.cpp
+++ b/clang/test/CodeGenCXX/debug-info-static-member.cpp
@@ -1,8 +1,8 @@
-// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-4 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,NOT-MS %s
+// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-4 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,CPP11,NOT-MS %s
 // RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-4 -std=c++98 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,NOT-MS %s
-// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-4 -std=c++11 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,NOT-MS %s
-// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-5 -std=c++11 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF5 %s
-// RUN: %clangxx -target x86_64-windows-msvc -g -gdwarf-4 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4 %s
+// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-4 -std=c++11 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,CPP11,NOT-MS %s
+// RUN: %clangxx -target x86_64-unknown-unknown -g -gdwarf-5 -std=c++11 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF5,CPP11 %s
+// RUN: %clangxx -target x86_64-windows-msvc -g -gdwarf-4 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,DWARF4,CPP11 %s
 // PR14471
 
 // CHECK: @{{.*}}a{{.*}} = dso_local global i32 4, align 4, !dbg [[A:![0-9]+]]
@@ -171,9 +171,9 @@ int y::z;
 // CHECK:      ![[CONST_A_VAR]] = distinct !DIGlobalVariable(name: "const_a"
 // CHECK-SAME:                    isLocal: true, isDefinition: true, declaration: ![[CONST_A_DECL]])
 
-// CHECK:      !DIGlobalVariableExpression(var: ![[CONST_B_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value))
-// CHECK:      ![[CONST_B_VAR]] = distinct !DIGlobalVariable(name: "const_b"
-// CHECK-SAME:                    isLocal: true, isDefinition: true, declaration: ![[CONST_B_DECL]])
+// CPP11:      !DIGlobalVariableExpression(var: ![[CONST_B_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value))
+// CPP11:      ![[CONST_B_VAR]] = distinct !DIGlobalVariable(name: "const_b"
+// CPP11-SAME:                    isLocal: true, isDefinition: true, declaration: ![[CONST_B_DECL]])
 
 // CHECK:      !DIGlobalVariableExpression(var: ![[CONST_C_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 18, DW_OP_stack_value))
 // CHECK:      ![[CONST_C_VAR]] = distinct !DIGlobalVariable(name: "const_c"

>From 3e5ed7b53661f93907d255b56f7e2d5ee602e011 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 20 Nov 2023 16:17:06 +0000
Subject: [PATCH 8/8] fixup! clarify function comment

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 54a368db7f77d16..7b79612fc7ad50e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -72,7 +72,7 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) {
 /// Given a VarDecl corresponding to either the definition or
 /// declaration of a C++ static data member, if it has a constant
 /// initializer and is evaluatable, return the evaluated value.
-/// Returns std::nullopt on failure.
+/// Returns std::nullopt otherwise.
 static std::optional<APValue>
 evaluateConstantInitializer(const clang::VarDecl *VD,
                             const clang::ASTContext &Ctx) {



More information about the cfe-commits mailing list