Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -81,6 +81,10 @@ llvm::SmallDenseMap DebugPrefixMap; + /// Cache that maps VLA types to size expressions for that type, + /// represented by instantiated Metadata nodes. + llvm::SmallDenseMap SizeExprCache; + struct ObjCInterfaceCacheEntry { const ObjCInterfaceType *Type; llvm::DIType *Decl; @@ -309,6 +313,11 @@ void finalize(); + /// 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. @@ -379,8 +388,11 @@ /// Emit call to \c llvm.dbg.declare for an automatic variable /// declaration. + /// \param MetadataDecl is optional and when given it is used to collect + /// the created Metadata declaration for the variable. void EmitDeclareOfAutoVariable(const VarDecl *Decl, llvm::Value *AI, - CGBuilderTy &Builder); + CGBuilderTy &Builder, + llvm::Metadata **MetadataDecl = nullptr); /// Emit call to \c llvm.dbg.declare for an imported variable /// declaration in a block. @@ -451,10 +463,15 @@ llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent, SourceLocation LineLoc, SourceLocation FileLoc); + private: /// Emit call to llvm.dbg.declare for a variable declaration. + /// \param MetadataDecl can be given to collect the created Metadata + /// declaration for the variable. void EmitDeclare(const VarDecl *decl, llvm::Value *AI, - llvm::Optional ArgNo, CGBuilderTy &Builder); + llvm::Optional ArgNo, + CGBuilderTy &Builder, + llvm::Metadata **MetadataDecl = nullptr); /// 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,14 @@ 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); + auto SizeExpr = SizeExprCache.find(QTy); + if (SizeExpr != SizeExprCache.end()) + Subscript = DBuilder.getOrCreateSubrange(0, SizeExpr->getSecond()); + else + Subscript = DBuilder.getOrCreateSubrange(0, Count ? Count : -1); llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); uint64_t Size = CGM.getContext().getTypeSize(Ty); @@ -2353,8 +2355,12 @@ } } - // FIXME: Verify this is right for VLAs. - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); + auto SizeNode = SizeExprCache.find(EltTy); + if (SizeNode != SizeExprCache.end()) + Subscripts.push_back( + DBuilder.getOrCreateSubrange(0, SizeNode->getSecond())); + else + Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count)); EltTy = Ty->getElementType(); } @@ -3463,9 +3469,11 @@ nullptr, Elements); } -void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, +void CGDebugInfo::EmitDeclare(const VarDecl *VD, + llvm::Value *Storage, llvm::Optional ArgNo, - CGBuilderTy &Builder) { + CGBuilderTy &Builder, + llvm::Metadata **MetadataDecl) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (VD->hasAttr()) @@ -3583,13 +3591,17 @@ DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); + + if (MetadataDecl) + *MetadataDecl = D; } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, - CGBuilderTy &Builder) { + CGBuilderTy &Builder, + llvm::Metadata **MetadataDecl) { assert(DebugKind >= codegenoptions::LimitedDebugInfo); - EmitDeclare(VD, Storage, llvm::None, Builder); + return EmitDeclare(VD, Storage, llvm::None, Builder, MetadataDecl); } llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -955,6 +955,55 @@ C->setDoesNotThrow(); } +/// RegisterVariableArrayDimensions - Emits the alloca and debug information for +/// the size expressions for each dimension of an array. It registers the +/// association of its (1-dimensional) QualTypes and size expression's debug +/// node, so that CGDebugInfo can reference this node when creating the +/// DISubrange object to describe the array types. +void CodeGenFunction::EmitAndRegisterVariableArrayDimensions(CGDebugInfo *DI, + const VarDecl &D) { + QualType Type1D = D.getType(); + while (getContext().getAsVariableArrayType(Type1D)) { + llvm::Value *ElementCount1D; + QualType ElementType1D; + std::tie(ElementCount1D, ElementType1D) = getVLAElements1D(Type1D); + + if (auto *C = dyn_cast(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(SizeExprAddr.getPointer())->getName()); + auto *FakeDecl = VarDecl::Create( + getContext(), const_cast(D.getDeclContext()), + D.getLocation(), D.getLocation(), &NameIdent, QT, + getContext().CreateTypeSourceInfo(QT), SC_Auto); + + llvm::Metadata *SizeExprDebugDecl = nullptr; + DI->EmitDeclareOfAutoVariable(FakeDecl, SizeExprAddr.getPointer(), + Builder, &SizeExprDebugDecl); + + // Next, connect this fake VarDecl to the 'size' expression in + // DISubrange. + assert(SizeExprDebugDecl && + "No Size expression debug node created"); + DI->registerVLASizeExpression(Type1D.getUnqualifiedType(), + SizeExprDebugDecl); + } + Type1D = ElementType1D; + } +} + /// EmitAutoVarAlloca - Emit the alloca and debug information for a /// local variable. Does not emit initialization or destruction. CodeGenFunction::AutoVarEmission @@ -975,6 +1024,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 +1169,22 @@ // Allocate memory for the array. address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount); + + // If we have debug info enabled, properly describe the VLA dimensions for + // this type by registering the vla size expression for each of the + // dimensions. + if (EmitDebugInfo) + EmitAndRegisterVariableArrayDimensions(DI, D); } 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()) EmitVarAnnotations(&D, address.getPointer()); 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 + getVLAElements1D(const VariableArrayType *vla); + std::pair 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 @@ -2505,6 +2511,8 @@ void EmitAutoVarCleanups(const AutoVarEmission &emission); void emitAutoVarTypeCleanup(const AutoVarEmission &emission, QualType::DestructionKind dtorKind); + void EmitAndRegisterVariableArrayDimensions(CGDebugInfo *DI, + const VarDecl &D); void EmitStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -1948,6 +1948,21 @@ return std::pair(numElements, elementType); } +std::pair +CodeGenFunction::getVLAElements1D(QualType type) { + const VariableArrayType *vla = getContext().getAsVariableArrayType(type); + assert(vla && "type was not a variable array type!"); + return getVLAElements1D(vla); +} + +std::pair +CodeGenFunction::getVLAElements1D(const VariableArrayType *Vla) { + llvm::Value *VlaSize = VLASizeMap[Vla->getSizeExpr()]; + assert(VlaSize && "no size for VLA!"); + assert(VlaSize->getType() == SizeTy); + return { VlaSize, Vla->getElementType() }; +} + void CodeGenFunction::EmitVariablyModifiedType(QualType type) { assert(type->isVariablyModifiedType() && "Must pass variably modified type to EmitVLASizes!"); 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: 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]])