sdesmalen created this revision.
sdesmalen added reviewers: echristo, aprantl, dexonsmith, clayborg, pcc, 
kristof.beyls.
Herald added a subscriber: JDevlieghere.

This patch enables debugging of C99 VLA types by generating more precise
LLVM Debug metadata, using the extended DISubrange 'count' field that
takes a DIVariable.

      

This should implement:

  Bug 30553: Debug info generated for arrays is not what GDB expects (not as 
good as GCC's)

https://bugs.llvm.org/show_bug.cgi?id=30553


https://reviews.llvm.org/D41698

Files:
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGDebugInfo.h
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/debug-info-vla.c
  test/CodeGenCXX/debug-info-vla.cpp

Index: test/CodeGenCXX/debug-info-vla.cpp
===================================================================
--- test/CodeGenCXX/debug-info-vla.cpp
+++ test/CodeGenCXX/debug-info-vla.cpp
@@ -13,8 +13,10 @@
 // CHECK: [[ELEM_TYPE]] = !{[[NOCOUNT:.*]]}
 // CHECK: [[NOCOUNT]] = !DISubrange(count: -1)
 //
+// CHECK: [[VAR:![0-9]+]] = !DILocalVariable(name: "vla_expr"
 // CHECK: !DICompositeType(tag: DW_TAG_array_type,
 // CHECK-NOT:                               size:
 // CHECK-SAME:                              elements: [[ELEM_TYPE:![0-9]+]]
-// CHECK: [[ELEM_TYPE]] = !{[[THREE:.*]], [[NOCOUNT]]}
+// CHECK: [[ELEM_TYPE]] = !{[[THREE:.*]], [[VARRANGE:![0-9]+]]}
 // CHECK: [[THREE]] = !DISubrange(count: 3)
+// CHECK: [[VARRANGE]] = !DISubrange(count: [[VAR]])
Index: test/CodeGen/debug-info-vla.c
===================================================================
--- test/CodeGen/debug-info-vla.c
+++ test/CodeGen/debug-info-vla.c
@@ -2,9 +2,11 @@
 
 void testVLAwithSize(int s)
 {
-// CHECK: dbg.declare
-// CHECK: dbg.declare({{.*}}, metadata ![[VAR:.*]], metadata !DIExpression())
-// CHECK: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+1]]
+// CHECK-DAG: dbg.declare({{.*}} %vla_expr, metadata ![[VLAEXPR:[0-9]+]]
+// CHECK-DAG: dbg.declare({{.*}} %vla, metadata ![[VAR:[0-9]+]]
+// CHECK-DAG: ![[VLAEXPR]] = !DILocalVariable(name: "vla_expr"
+// CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "vla",{{.*}} line: [[@LINE+2]]
+// CHECK-DAG: !DISubrange(count: ![[VLAEXPR]])
   int vla[s];
   int i;
   for (i = 0; i < s; i++) {
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -2193,6 +2193,12 @@
   /// This function can be called with a null (unreachable) insert point.
   void EmitVariablyModifiedType(QualType Ty);
 
+  /// getVLAElements1D returns the number of elements for a single dimension
+  /// for the given array type.
+  std::pair<llvm::Value *, QualType>
+  getVLAElements1D(const VariableArrayType *vla);
+  std::pair<llvm::Value *, QualType> getVLAElements1D(QualType vla);
+
   /// getVLASize - Returns an LLVM value that corresponds to the size,
   /// in non-variably-sized elements, of a variable length array type,
   /// plus that largest non-variably-sized element type.  Assumes that
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -1948,6 +1948,21 @@
   return std::pair<llvm::Value*,QualType>(numElements, elementType);
 }
 
+std::pair<llvm::Value *, QualType>
+CodeGenFunction::getVLAElements1D(QualType type) {
+  const VariableArrayType *vla = getContext().getAsVariableArrayType(type);
+  assert(vla && "type was not a variable array type!");
+  return getVLAElements1D(vla);
+}
+
+std::pair<llvm::Value *, QualType>
+CodeGenFunction::getVLAElements1D(const VariableArrayType *Vla) {
+  llvm::Value *VlaSize = VLASizeMap[Vla->getSizeExpr()];
+  assert(VlaSize && "no size for VLA!");
+  assert(VlaSize->getType() == SizeTy);
+  return std::pair<llvm::Value *, QualType>(VlaSize, Vla->getElementType());
+}
+
 void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
   assert(type->isVariablyModifiedType() &&
          "Must pass variably modified type to EmitVLASizes!");
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -975,6 +975,10 @@
   if (Ty->isVariablyModifiedType())
     EmitVariablyModifiedType(Ty);
 
+  auto *DI = getDebugInfo();
+  bool EmitDebugInfo = DI && CGM.getCodeGenOpts().getDebugInfo() >=
+                                 codegenoptions::LimitedDebugInfo;
+
   Address address = Address::invalid();
   if (Ty->isConstantSizeType()) {
     bool NRVO = getLangOpts().ElideConstructors &&
@@ -1116,20 +1120,60 @@
 
     // Allocate memory for the array.
     address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount);
+
+    // If we have debug info enabled, describe the VLA dimensions properly.
+    if (EmitDebugInfo) {
+      QualType Type1D = Ty;
+      while (getContext().getAsVariableArrayType(Type1D)) {
+        llvm::Value *ElementCount1D;
+        QualType ElementType1D;
+        std::tie(ElementCount1D, ElementType1D) = getVLAElements1D(Type1D);
+
+        if (auto *C = dyn_cast<llvm::ConstantInt>(ElementCount1D)) {
+          auto *Const = llvm::ConstantAsMetadata::get(C);
+          DI->registerVLASizeExpression(Type1D.getUnqualifiedType(), Const);
+        } else {
+          // Allocate memory for the address of the vla expression
+          // We can use this for debugging purposes
+          auto SizeExprAddr = CreateDefaultAlignTempAlloca(
+              ElementCount1D->getType(), "vla_expr");
+          Builder.CreateStore(ElementCount1D, SizeExprAddr);
+
+          auto QT = getContext().getIntTypeForBitwidth(
+              ElementCount1D->getType()->getScalarSizeInBits(), false);
+
+          // Now create a 'fake' VarDecl that we'll generate debug info for.
+          IdentifierInfo &NameIdent = getContext().Idents.getOwn(
+              cast<llvm::AllocaInst>(SizeExprAddr.getPointer())->getName());
+          auto *FakeDecl = VarDecl::Create(
+              getContext(), const_cast<DeclContext *>(D.getDeclContext()),
+              D.getLocation(), D.getLocation(), &NameIdent, QT,
+              getContext().CreateTypeSourceInfo(QT), SC_Auto);
+
+          llvm::Optional<llvm::Metadata *> SizeExprDebugDecl;
+          DI->EmitDeclareOfAutoVariable(FakeDecl, SizeExprAddr.getPointer(),
+                                        SizeExprDebugDecl, Builder);
+
+          // Next, connect this fake VarDecl to the 'size' expression in
+          // DISubrange.
+          assert(SizeExprDebugDecl.hasValue() &&
+                 "No Size expression debug node created");
+          DI->registerVLASizeExpression(Type1D.getUnqualifiedType(),
+                                        *SizeExprDebugDecl);
+        }
+        Type1D = ElementType1D;
+      }
+    }
   }
 
   setAddrOfLocalVar(&D, address);
   emission.Addr = address;
 
   // Emit debug info for local var declaration.
-  if (HaveInsertPoint())
-    if (CGDebugInfo *DI = getDebugInfo()) {
-      if (CGM.getCodeGenOpts().getDebugInfo() >=
-          codegenoptions::LimitedDebugInfo) {
-        DI->setLocation(D.getLocation());
-        DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder);
-      }
-    }
+  if (EmitDebugInfo && HaveInsertPoint()) {
+    DI->setLocation(D.getLocation());
+    DI->EmitDeclareOfAutoVariable(&D, address.getPointer(), Builder);
+  }
 
   if (D.hasAttr<AnnotateAttr>())
     EmitVarAnnotations(&D, address.getPointer());
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h
+++ lib/CodeGen/CGDebugInfo.h
@@ -81,6 +81,10 @@
 
   llvm::SmallDenseMap<llvm::StringRef, llvm::StringRef> DebugPrefixMap;
 
+  /// Cache that maps VLA types to size expressions for that type,
+  /// represented by instantiated Metadata nodes.
+  llvm::SmallDenseMap<QualType, llvm::Metadata *> SizeExprCache;
+
   struct ObjCInterfaceCacheEntry {
     const ObjCInterfaceType *Type;
     llvm::DIType *Decl;
@@ -309,6 +313,17 @@
 
   void finalize();
 
+  llvm::Metadata *getVLASizeExpressionForType(QualType Ty) {
+    if (SizeExprCache.count(Ty))
+      return SizeExprCache[Ty];
+    return nullptr;
+  }
+
+  /// Register VLA size expression debug node with the qualified type.
+  void registerVLASizeExpression(QualType Ty, llvm::Metadata *SizeExpr) {
+    SizeExprCache[Ty] = SizeExpr;
+  }
+
   /// Module debugging: Support for building PCMs.
   /// @{
   /// Set the main CU's DwoId field to \p Signature.
@@ -381,6 +396,13 @@
   /// declaration.
   void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
                                  CGBuilderTy &Builder);
+  /// Emit call to \c llvm.dbg.declare for an automatic variable
+  /// declaration.
+  /// \param MetadataDecl can be optionally filled in with the created Metadata
+  /// declaration for the variable.
+  void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI,
+                                 llvm::Optional<llvm::Metadata *> &MetadataDecl,
+                                 CGBuilderTy &Builder);
 
   /// Emit call to \c llvm.dbg.declare for an imported variable
   /// declaration in a block.
@@ -451,10 +473,20 @@
   llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent,
                                          SourceLocation LineLoc,
                                          SourceLocation FileLoc);
+
 private:
   /// Emit call to llvm.dbg.declare for a variable declaration.
   void EmitDeclare(const VarDecl *decl, llvm::Value *AI,
-                   llvm::Optional<unsigned> ArgNo, CGBuilderTy &Builder);
+                   llvm::Optional<unsigned> ArgNo,
+                   CGBuilderTy &Builder);
+
+  /// Emit call to llvm.dbg.declare for a variable declaration.
+  /// \param MetadataDecl can be filled in with the created Metadata
+  /// declaration for the variable.
+  void EmitDeclare(const VarDecl *decl, llvm::Value *AI,
+                   llvm::Optional<unsigned> ArgNo,
+                   llvm::Optional<llvm::Metadata *> &MetadataDecl,
+                   CGBuilderTy &Builder);
 
   /// Build up structure info for the byref.  See \a BuildByRefType.
   llvm::DIType *EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -2291,12 +2291,13 @@
                                       llvm::DIFile *Unit) {
   llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit);
   int64_t Count = Ty->getNumElements();
-  if (Count == 0)
-    // If number of elements are not known then this is an unbounded array.
-    // Use Count == -1 to express such arrays.
-    Count = -1;
 
-  llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange(0, Count);
+  llvm::Metadata *Subscript;
+  QualType QTy(Ty, 0);
+  if (auto *SizeExpr = getVLASizeExpressionForType(QTy))
+    Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr);
+  else
+    Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1);
   llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
 
   uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -2353,8 +2354,10 @@
       }
     }
 
-    // FIXME: Verify this is right for VLAs.
-    Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
+    if (auto *SizeNode = getVLASizeExpressionForType(EltTy))
+      Subscripts.push_back(DBuilder.getOrCreateSubrange(0, SizeNode));
+    else
+      Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
     EltTy = Ty->getElementType();
   }
 
@@ -3463,9 +3466,19 @@
                                    nullptr, Elements);
 }
 
-void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
+void CGDebugInfo::EmitDeclare(const VarDecl *VD,
+                              llvm::Value *Storage,
                               llvm::Optional<unsigned> ArgNo,
                               CGBuilderTy &Builder) {
+  llvm::Optional<llvm::Metadata *> Optional;
+  EmitDeclare(VD, Storage, ArgNo, Optional, Builder);
+}
+
+void CGDebugInfo::EmitDeclare(const VarDecl *VD,
+                              llvm::Value *Storage,
+                              llvm::Optional<unsigned> ArgNo,
+                              llvm::Optional<llvm::Metadata*> &MetadataDecl,
+                              CGBuilderTy &Builder) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
   assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
   if (VD->hasAttr<NoDebugAttr>())
@@ -3583,13 +3596,22 @@
   DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
                          llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
                          Builder.GetInsertBlock());
+
+  MetadataDecl = D;
 }
 
 void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
                                             llvm::Value *Storage,
                                             CGBuilderTy &Builder) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
-  EmitDeclare(VD, Storage, llvm::None, Builder);
+  return EmitDeclare(VD, Storage, llvm::None, Builder);
+}
+
+void CGDebugInfo::EmitDeclareOfAutoVariable(
+    const VarDecl *VD, llvm::Value *Storage,
+    llvm::Optional<llvm::Metadata *> &MetadataDecl, CGBuilderTy &Builder) {
+  assert(DebugKind >= codegenoptions::LimitedDebugInfo);
+  return EmitDeclare(VD, Storage, llvm::None, MetadataDecl, Builder);
 }
 
 llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to