Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -3391,6 +3391,9 @@ if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + if (FD->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + if (Stub) { Flags |= getCallSiteRelatedAttrs(); SPFlags |= llvm::DISubprogram::SPFlagDefinition; @@ -3428,13 +3431,18 @@ llvm::DIScope *DContext = Unit; unsigned Line = getLineNumber(Loc); llvm::MDTuple *TemplateParameters = nullptr; + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, TemplateParameters, DContext); auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); + + if (VD->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + auto *GV = DBuilder.createTempGlobalVariableFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit), - !VD->isExternallyVisible(), nullptr, TemplateParameters, Align); + !VD->isExternallyVisible(), nullptr, TemplateParameters, Flags, Align); FwdDeclReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(cast(VD->getCanonicalDecl())), @@ -3694,6 +3702,12 @@ // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for // all subprograms instead of the actual context since subprogram definitions // are emitted as CU level entities by the backend. + + auto *FD = dyn_cast_or_null(GD.getDecl()); + + if (FD && FD->isConstexpr()) + FlagsForDef |= llvm::DINode::FlagConstExpr; + llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine, FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl); @@ -3760,6 +3774,10 @@ if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + auto *FD = dyn_cast_or_null(GD.getDecl()); + if (FD && FD->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, @@ -4073,7 +4091,6 @@ auto *D = DBuilder.createAutoVariable( Scope, FieldName, Unit, Line, FieldTy, CGM.getLangOpts().Optimize, Flags | llvm::DINode::FlagArtificial, FieldAlign); - // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare( Storage, D, DBuilder.createExpression(Expr), @@ -4093,6 +4110,9 @@ Expr.push_back(llvm::dwarf::DW_OP_deref); } + if (VD && VD->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + // Create the descriptor for the variable. auto *D = ArgNo ? DBuilder.createParameterVariable( Scope, Name, *ArgNo, Unit, Line, Ty, @@ -4476,7 +4496,7 @@ llvm::MDTuple *TemplateParameters = nullptr; collectVarDeclProps(D, Unit, LineNo, T, DeclName, LinkageName, TemplateParameters, DContext); - + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; // Attempt to store one global variable for the declaration - even if we // emit a lot of fields. llvm::DIGlobalVariableExpression *GVE = nullptr; @@ -4505,12 +4525,15 @@ } AppendAddressSpaceXDeref(AddressSpace, Expr); + if (D->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, - Align); + Flags, Align); Var->addDebugInfo(GVE); } DeclCache[D->getCanonicalDecl()].reset(GVE); @@ -4518,6 +4541,7 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (VD->hasAttr()) return; llvm::TimeTraceScope TimeScope("DebugConstGlobalVariable", [&]() { @@ -4608,15 +4632,19 @@ TemplateParameters = parameterNodes.get(); } + if (VarD && VarD->isConstexpr()) + Flags |= llvm::DINode::FlagConstExpr; + GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), - TemplateParameters, Align)); + TemplateParameters, Flags, Align)); } void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (D->hasAttr()) return; @@ -4629,7 +4657,7 @@ llvm::DIGlobalVariableExpression *GVE = DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(D->getLocation()), - Ty, false, false, nullptr, nullptr, nullptr, Align); + Ty, false, false, nullptr, nullptr, nullptr, Flags, Align); Var->addDebugInfo(GVE); } Index: clang/test/CodeGenCXX/constExpr.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/constExpr.cpp @@ -0,0 +1,22 @@ +// Test for DebugInfo for constexpr for C++ variables +// +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s +// +// CHECK: DIGlobalVariable(name: "bar", {{.*}} flags: DIFlagConstExpr) +// CHECK: DISubprogram(name: "main", {{.*}} flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, +// CHECK: DILocalVariable(name: "baz", {{.*}}, flags: DIFlagConstExpr) +// CHECK: DISubprogram(name: "fun", {{.*}}, flags: DIFlagPrototyped | DIFlagConstExpr + +constexpr int bar = 10; + +constexpr int fun(int x) { return x * 2; } + +int main(int argc, char **argv) { + int foo = bar; + constexpr int baz = 10; + int constVal = fun(10); + return 0; +} Index: llvm/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/include/llvm/IR/DIBuilder.h +++ llvm/include/llvm/IR/DIBuilder.h @@ -586,14 +586,16 @@ DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DIType *Ty, bool IsLocalToUnit, bool isDefined = true, DIExpression *Expr = nullptr, MDNode *Decl = nullptr, - MDTuple *TemplateParams = nullptr, uint32_t AlignInBits = 0); + MDTuple *TemplateParams = nullptr, + DINode::DIFlags Flags = DINode::FlagZero, uint32_t AlignInBits = 0); /// Identical to createGlobalVariable /// except that the resulting DbgNode is temporary and meant to be RAUWed. DIGlobalVariable *createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DIType *Ty, bool IsLocalToUnit, MDNode *Decl = nullptr, - MDTuple *TemplateParams= nullptr, uint32_t AlignInBits = 0); + MDTuple *TemplateParams = nullptr, + DINode::DIFlags Flags = DINode::FlagZero, uint32_t AlignInBits = 0); /// Create a new descriptor for an auto variable. This is a local variable /// that is not a subprogram parameter. Index: llvm/include/llvm/IR/DebugInfoFlags.def =================================================================== --- llvm/include/llvm/IR/DebugInfoFlags.def +++ llvm/include/llvm/IR/DebugInfoFlags.def @@ -58,6 +58,7 @@ HANDLE_DI_FLAG((1 << 27), BigEndian) HANDLE_DI_FLAG((1 << 28), LittleEndian) HANDLE_DI_FLAG((1 << 29), AllCallsDescribed) +HANDLE_DI_FLAG((1 << 30), ConstExpr) // To avoid needing a dedicated value for IndirectVirtualBase, we use // the bitwise or of Virtual and FwdDecl, which does not otherwise @@ -67,7 +68,7 @@ #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 29), Largest) +HANDLE_DI_FLAG((1 << 30), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1789,6 +1789,11 @@ // Returns true if this subprogram is a thunk generated by the compiler. bool isThunk() const { return getFlags() & FlagThunk; } + // Check if this routine return type is const expression . + // + // Returns true if this subprogram returns const expression. + bool isConstExpr() const { return getFlags() & FlagConstExpr; } + DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(2); } @@ -2622,59 +2627,62 @@ bool IsLocalToUnit; bool IsDefinition; + DIFlags Flags; DIGlobalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - bool IsLocalToUnit, bool IsDefinition, uint32_t AlignInBits, - ArrayRef Ops) + bool IsLocalToUnit, bool IsDefinition, DIFlags Flags, + uint32_t AlignInBits, ArrayRef Ops) : DIVariable(C, DIGlobalVariableKind, Storage, Line, Ops, AlignInBits), - IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {} + IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), Flags(Flags) { + } ~DIGlobalVariable() = default; - static DIGlobalVariable * - getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, - StringRef LinkageName, DIFile *File, unsigned Line, DIType *Type, - bool IsLocalToUnit, bool IsDefinition, - DIDerivedType *StaticDataMemberDeclaration, MDTuple *TemplateParams, - uint32_t AlignInBits, StorageType Storage, bool ShouldCreate = true) { + static DIGlobalVariable *getImpl(LLVMContext &Context, DIScope *Scope, + StringRef Name, StringRef LinkageName, + DIFile *File, unsigned Line, DIType *Type, + bool IsLocalToUnit, bool IsDefinition, + DIDerivedType *StaticDataMemberDeclaration, + MDTuple *TemplateParams, DIFlags Flags, + uint32_t AlignInBits, StorageType Storage, + bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, IsLocalToUnit, IsDefinition, StaticDataMemberDeclaration, - cast_or_null(TemplateParams), AlignInBits, Storage, - ShouldCreate); + cast_or_null(TemplateParams), Flags, AlignInBits, + Storage, ShouldCreate); } static DIGlobalVariable * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *StaticDataMemberDeclaration, Metadata *TemplateParams, - uint32_t AlignInBits, StorageType Storage, bool ShouldCreate = true); + DIFlags Flags, uint32_t AlignInBits, StorageType Storage, + bool ShouldCreate = true); TempDIGlobalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), isDefinition(), getStaticDataMemberDeclaration(), - getTemplateParams(), getAlignInBits()); + getTemplateParams(), getFlags(), getAlignInBits()); } public: - DEFINE_MDNODE_GET(DIGlobalVariable, - (DIScope * Scope, StringRef Name, StringRef LinkageName, - DIFile *File, unsigned Line, DIType *Type, - bool IsLocalToUnit, bool IsDefinition, - DIDerivedType *StaticDataMemberDeclaration, - MDTuple *TemplateParams, uint32_t AlignInBits), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, StaticDataMemberDeclaration, TemplateParams, - AlignInBits)) - DEFINE_MDNODE_GET(DIGlobalVariable, - (Metadata * Scope, MDString *Name, MDString *LinkageName, - Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, - Metadata *StaticDataMemberDeclaration, - Metadata *TemplateParams, uint32_t AlignInBits), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, StaticDataMemberDeclaration, TemplateParams, - AlignInBits)) + DEFINE_MDNODE_GET( + DIGlobalVariable, + (DIScope * Scope, StringRef Name, StringRef LinkageName, DIFile *File, + unsigned Line, DIType *Type, bool IsLocalToUnit, bool IsDefinition, + DIDerivedType *StaticDataMemberDeclaration, MDTuple *TemplateParams, + DIFlags Flags, uint32_t AlignInBits), + (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, TemplateParams, Flags, AlignInBits)) + DEFINE_MDNODE_GET( + DIGlobalVariable, + (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, + unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, + Metadata *StaticDataMemberDeclaration, Metadata *TemplateParams, + DIFlags Flags, uint32_t AlignInBits), + (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, TemplateParams, Flags, AlignInBits)) TempDIGlobalVariable clone() const { return cloneImpl(); } @@ -2685,6 +2693,8 @@ DIDerivedType *getStaticDataMemberDeclaration() const { return cast_or_null(getRawStaticDataMemberDeclaration()); } + DIFlags getFlags() const { return Flags; } + bool isConstExpr() const { return getFlags() & FlagConstExpr; } MDString *getRawLinkageName() const { return getOperandAs(5); } Metadata *getRawStaticDataMemberDeclaration() const { return getOperand(6); } @@ -2802,8 +2812,8 @@ (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits)) DEFINE_MDNODE_GET(DILocalVariable, (Metadata * Scope, MDString *Name, Metadata *File, - unsigned Line, Metadata *Type, unsigned Arg, - DIFlags Flags, uint32_t AlignInBits), + unsigned Line, Metadata *Type, unsigned Arg, DIFlags Flags, + uint32_t AlignInBits), (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits)) TempDILocalVariable clone() const { return cloneImpl(); } @@ -2821,6 +2831,7 @@ bool isArtificial() const { return getFlags() & FlagArtificial; } bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } + bool isConstExpr() const { return getFlags() & FlagConstExpr; } /// Check that a location is valid for this variable. /// Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -4677,8 +4677,9 @@ /// isDefinition: true, scopeLine: 8, containingType: !3, /// virtuality: DW_VIRTUALTIY_pure_virtual, /// virtualIndex: 10, thisAdjustment: 4, flags: 11, -/// spFlags: 10, isOptimized: false, templateParams: !4, -/// declaration: !5, retainedNodes: !6, thrownTypes: !7) +/// spFlags: 10, isOptimized: false, +/// templateParams: !4, declaration: !5, retainedNodes: !6, +/// thrownTypes: !7) bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) { auto Loc = Lex.getLoc(); #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ @@ -4886,15 +4887,16 @@ OPTIONAL(isDefinition, MDBoolField, (true)); \ OPTIONAL(templateParams, MDField, ); \ OPTIONAL(declaration, MDField, ); \ + OPTIONAL(flags, DIFlagField, ); \ OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = - GET_OR_DISTINCT(DIGlobalVariable, - (Context, scope.Val, name.Val, linkageName.Val, file.Val, - line.Val, type.Val, isLocal.Val, isDefinition.Val, - declaration.Val, templateParams.Val, align.Val)); + Result = GET_OR_DISTINCT(DIGlobalVariable, + (Context, scope.Val, name.Val, linkageName.Val, + file.Val, line.Val, type.Val, isLocal.Val, + isDefinition.Val, declaration.Val, + templateParams.Val, flags.Val, align.Val)); return false; } Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1549,24 +1549,24 @@ DISubprogram *SP = GET_OR_DISTINCT( DISubprogram, (Context, - getDITypeRefOrNull(Record[1]), // scope - getMDString(Record[2]), // name - getMDString(Record[3]), // linkageName - getMDOrNull(Record[4]), // file - Record[5], // line - getMDOrNull(Record[6]), // type - Record[7 + OffsetA], // scopeLine - getDITypeRefOrNull(Record[8 + OffsetA]), // containingType - Record[10 + OffsetA], // virtualIndex - HasThisAdj ? Record[16 + OffsetB] : 0, // thisAdjustment - Flags, // flags - SPFlags, // SPFlags - HasUnit ? CUorFn : nullptr, // unit - getMDOrNull(Record[13 + OffsetB]), // templateParams - getMDOrNull(Record[14 + OffsetB]), // declaration - getMDOrNull(Record[15 + OffsetB]), // retainedNodes + getDITypeRefOrNull(Record[1]), // scope + getMDString(Record[2]), // name + getMDString(Record[3]), // linkageName + getMDOrNull(Record[4]), // file + Record[5], // line + getMDOrNull(Record[6]), // type + Record[7 + OffsetA], // scopeLine + getDITypeRefOrNull(Record[8 + OffsetA]), // containingType + Record[10 + OffsetA], // virtualIndex + HasThisAdj ? Record[16 + OffsetB] : 0, // thisAdjustment + Flags, // flags + SPFlags, // SPFlags + HasUnit ? CUorFn : nullptr, // unit + getMDOrNull(Record[13 + OffsetB]), // templateParams + getMDOrNull(Record[14 + OffsetB]), // declaration + getMDOrNull(Record[15 + OffsetB]), // retainedNodes HasThrownTypes ? getMDOrNull(Record[17 + OffsetB]) - : nullptr // thrownTypes + : nullptr // thrownTypes )); MetadataList.assignValue(SP, NextMetadataNo); NextMetadataNo++; @@ -1699,28 +1699,31 @@ IsDistinct = Record[0] & 1; unsigned Version = Record[0] >> 1; + DINode::DIFlags Flags = static_cast(Record[7]); if (Version == 2) { MetadataList.assignValue( - GET_OR_DISTINCT( - DIGlobalVariable, - (Context, getMDOrNull(Record[1]), getMDString(Record[2]), - getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], - getDITypeRefOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[9]), getMDOrNull(Record[10]), Record[11])), + GET_OR_DISTINCT(DIGlobalVariable, + (Context, getMDOrNull(Record[1]), + getMDString(Record[2]), getMDString(Record[3]), + getMDOrNull(Record[4]), Record[5], + getDITypeRefOrNull(Record[6]), Record[7], Record[8], + getMDOrNull(Record[9]), getMDOrNull(Record[10]), + Flags, Record[12])), NextMetadataNo); NextMetadataNo++; } else if (Version == 1) { // No upgrade necessary. A null field will be introduced to indicate // that no parameter information is available. + MetadataList.assignValue( - GET_OR_DISTINCT(DIGlobalVariable, - (Context, getMDOrNull(Record[1]), - getMDString(Record[2]), getMDString(Record[3]), - getMDOrNull(Record[4]), Record[5], - getDITypeRefOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[10]), nullptr, Record[11])), + GET_OR_DISTINCT( + DIGlobalVariable, + (Context, getMDOrNull(Record[1]), getMDString(Record[2]), + getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], + getDITypeRefOrNull(Record[6]), Record[7], Record[8], + getMDOrNull(Record[10]), nullptr, Flags, Record[12])), NextMetadataNo); NextMetadataNo++; @@ -1730,10 +1733,10 @@ NeedUpgradeToDIGlobalVariableExpression = true; Metadata *Expr = getMDOrNull(Record[9]); uint32_t AlignInBits = 0; - if (Record.size() > 11) { + if (Record.size() > 12) { if (Record[11] > (uint64_t)std::numeric_limits::max()) return error("Alignment value is too large"); - AlignInBits = Record[11]; + AlignInBits = Record[12]; } GlobalVariable *Attach = nullptr; if (auto *CMD = dyn_cast_or_null(Expr)) { @@ -1748,12 +1751,13 @@ Expr = nullptr; } } + DINode::DIFlags Flags = static_cast(Record[11]); DIGlobalVariable *DGV = GET_OR_DISTINCT( DIGlobalVariable, (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], getDITypeRefOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[10]), nullptr, AlignInBits)); + getMDOrNull(Record[10]), nullptr, Flags, AlignInBits)); DIGlobalVariableExpression *DGVE = nullptr; if (Attach || Expr) Index: llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -179,6 +179,9 @@ // Add location. addLocationAttribute(VariableDIE, GV, GlobalExprs); + if (GV->isConstExpr()) + addFlag(*VariableDIE, dwarf::DW_AT_const_expr); + return VariableDIE; } @@ -432,6 +435,8 @@ } } + if (SP->isConstExpr()) + addFlag(*SPDie, dwarf::DW_AT_const_expr); // Add name to the name table, we do this here because we're guaranteed // to have concrete versions of our DW_TAG_subprogram nodes. DD->addSubprogramNames(*CUNode, SP, *SPDie); @@ -717,6 +722,8 @@ NVPTXAddressSpace ? *NVPTXAddressSpace : NVPTX_ADDR_local_space); } addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); + if (DV.getVariable()->isConstExpr()) + addFlag(*VariableDie, dwarf::DW_AT_const_expr); if (DwarfExpr.TagOffset) addUInt(*VariableDie, dwarf::DW_AT_LLVM_tag_offset, dwarf::DW_FORM_data1, *DwarfExpr.TagOffset); Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -2104,6 +2104,7 @@ Printer.printBool("isDefinition", N->isDefinition()); Printer.printMetadata("declaration", N->getRawStaticDataMemberDeclaration()); Printer.printMetadata("templateParams", N->getRawTemplateParams()); + Printer.printDIFlags("flags", N->getFlags()); Printer.printInt("align", N->getAlignInBits()); Out << ")"; } Index: llvm/lib/IR/DIBuilder.cpp =================================================================== --- llvm/lib/IR/DIBuilder.cpp +++ llvm/lib/IR/DIBuilder.cpp @@ -641,15 +641,15 @@ DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, - bool isDefined, DIExpression *Expr, - MDNode *Decl, MDTuple *TemplateParams, uint32_t AlignInBits) { + unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, bool isDefined, + DIExpression *Expr, MDNode *Decl, MDTuple *TemplateParams, + DINode::DIFlags Flags, uint32_t AlignInBits) { checkGlobalVariableScope(Context); auto *GV = DIGlobalVariable::getDistinct( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, IsLocalToUnit, isDefined, cast_or_null(Decl), - TemplateParams, AlignInBits); + LineNumber, Ty, IsLocalToUnit, isDefined, + cast_or_null(Decl), TemplateParams, Flags, AlignInBits); if (!Expr) Expr = createExpression(); auto *N = DIGlobalVariableExpression::get(VMContext, GV, Expr); @@ -660,13 +660,14 @@ DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, unsigned LineNumber, DIType *Ty, bool IsLocalToUnit, MDNode *Decl, - MDTuple *TemplateParams, uint32_t AlignInBits) { + MDTuple *TemplateParams, DINode::DIFlags Flags, uint32_t AlignInBits) { checkGlobalVariableScope(Context); return DIGlobalVariable::getTemporary( VMContext, cast_or_null(Context), Name, LinkageName, F, LineNumber, Ty, IsLocalToUnit, false, - cast_or_null(Decl), TemplateParams, AlignInBits) + cast_or_null(Decl), TemplateParams, Flags, + AlignInBits) .release(); } @@ -712,7 +713,7 @@ assert(ArgNo && "Expected non-zero argument number for parameter"); return createLocalVariable(VMContext, PreservedVariables, Scope, Name, ArgNo, File, LineNo, Ty, AlwaysPreserve, Flags, - /* AlignInBits */0); + /* AlignInBits */ 0); } DILabel *DIBuilder::createLabel( Index: llvm/lib/IR/DebugInfo.cpp =================================================================== --- llvm/lib/IR/DebugInfo.cpp +++ llvm/lib/IR/DebugInfo.cpp @@ -1309,12 +1309,13 @@ LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *Linkage, size_t LinkLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, - LLVMMetadataRef Expr, LLVMMetadataRef Decl, uint32_t AlignInBits) { + LLVMMetadataRef Expr, LLVMMetadataRef Decl, LLVMDIFlags Flags, + uint32_t AlignInBits) { return wrap(unwrap(Builder)->createGlobalVariableExpression( unwrapDI(Scope), {Name, NameLen}, {Linkage, LinkLen}, - unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, - true, unwrap(Expr), unwrapDI(Decl), - nullptr, AlignInBits)); + unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, true, + unwrap(Expr), unwrapDI(Decl), nullptr, + map_from_llvmDIFlags(Flags), AlignInBits)); } LLVMMetadataRef LLVMDIGlobalVariableExpressionGetVariable(LLVMMetadataRef GVE) { @@ -1359,11 +1360,12 @@ LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *Linkage, size_t LnkLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, - LLVMMetadataRef Decl, uint32_t AlignInBits) { + LLVMMetadataRef Decl, LLVMDIFlags Flags, uint32_t AlignInBits) { return wrap(unwrap(Builder)->createTempGlobalVariableFwdDecl( unwrapDI(Scope), {Name, NameLen}, {Linkage, LnkLen}, unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, - unwrapDI(Decl), nullptr, AlignInBits)); + unwrapDI(Decl), nullptr, map_from_llvmDIFlags(Flags), + AlignInBits)); } LLVMValueRef Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -749,14 +749,15 @@ MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *StaticDataMemberDeclaration, - Metadata *TemplateParams, uint32_t AlignInBits, - StorageType Storage, bool ShouldCreate) { + Metadata *TemplateParams, DIFlags Flags, + uint32_t AlignInBits, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, StaticDataMemberDeclaration, - TemplateParams, AlignInBits)); + TemplateParams, Flags, AlignInBits)); Metadata *Ops[] = {Scope, Name, File, @@ -766,7 +767,8 @@ StaticDataMemberDeclaration, TemplateParams}; DEFINE_GETIMPL_STORE(DIGlobalVariable, - (Line, IsLocalToUnit, IsDefinition, AlignInBits), Ops); + (Line, IsLocalToUnit, IsDefinition, Flags, AlignInBits), + Ops); } DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, @@ -781,9 +783,8 @@ assert(Scope && "Expected scope"); assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DILocalVariable, - (Scope, Name, File, Line, Type, Arg, Flags, - AlignInBits)); + DEFINE_GETIMPL_LOOKUP(DILocalVariable, (Scope, Name, File, Line, Type, Arg, + Flags, AlignInBits)); Metadata *Ops[] = {Scope, Name, File, Type}; DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops); } Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -886,25 +886,27 @@ bool IsDefinition; Metadata *StaticDataMemberDeclaration; Metadata *TemplateParams; + unsigned Flags; uint32_t AlignInBits; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, Metadata *StaticDataMemberDeclaration, Metadata *TemplateParams, - uint32_t AlignInBits) + unsigned Flags, uint32_t AlignInBits) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), StaticDataMemberDeclaration(StaticDataMemberDeclaration), - TemplateParams(TemplateParams), AlignInBits(AlignInBits) {} + TemplateParams(TemplateParams), Flags(Flags), AlignInBits(AlignInBits) { + } MDNodeKeyImpl(const DIGlobalVariable *N) : Scope(N->getRawScope()), Name(N->getRawName()), LinkageName(N->getRawLinkageName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()), - TemplateParams(N->getRawTemplateParams()), + TemplateParams(N->getRawTemplateParams()), Flags(N->getFlags()), AlignInBits(N->getAlignInBits()) {} bool isKeyOf(const DIGlobalVariable *RHS) const { @@ -916,7 +918,7 @@ StaticDataMemberDeclaration == RHS->getRawStaticDataMemberDeclaration() && TemplateParams == RHS->getRawTemplateParams() && - AlignInBits == RHS->getAlignInBits(); + Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits(); } unsigned getHashValue() const { @@ -929,7 +931,7 @@ // TODO: make hashing work fine with such situations return hash_combine(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, /* AlignInBits, */ - StaticDataMemberDeclaration); + StaticDataMemberDeclaration, Flags); } }; Index: llvm/test/DebugInfo/X86/constExpr.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/constExpr.ll @@ -0,0 +1,118 @@ +; RUN: %llc_dwarf %s -filetype=obj -o - | llvm-dwarfdump -v - | FileCheck %s + +; CHECK: .debug_info contents: + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name {{.*}} "bar" +; CHECK: DW_AT_const_expr {{.*}} (true) + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_const_expr {{.*}} (true) +; CHECK: DW_AT_linkage_name {{.*}} "_Z3funi" + + +; C++ source to regenerate: + +;constexpr int bar = 10; +; +;constexpr int fun(int x) { return x * 2; } +; +;int main(int argc, char **argv) { +; int foo = bar; +; constexpr int baz = 10; +; int constVal = fun(10); +; return 0; +;} + +; $ clang++ -O0 -g -gdwarf-5 debug-info-template-align.cpp -c + +; ModuleID = '/dir/test.cpp' +source_filename = "/dir/test.cpp" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +$_Z3funi = comdat any +; Function Attrs: noinline norecurse optnone uwtable + +define dso_local i32 @main(i32 %argc, i8** %argv) #0 !dbg !13 { +entry: + %retval = alloca i32, align 4 + %argc.addr = alloca i32, align 4 + %argv.addr = alloca i8**, align 8 + %foo = alloca i32, align 4 + %baz = alloca i32, align 4 + %constVal = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + store i32 %argc, i32* %argc.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %argc.addr, metadata !19, metadata !DIExpression()), !dbg !20 + store i8** %argv, i8*** %argv.addr, align 8 + call void @llvm.dbg.declare(metadata i8*** %argv.addr, metadata !21, metadata !DIExpression()), !dbg !22 + call void @llvm.dbg.declare(metadata i32* %foo, metadata !23, metadata !DIExpression()), !dbg !24 + store i32 10, i32* %foo, align 4, !dbg !24 + call void @llvm.dbg.declare(metadata i32* %baz, metadata !25, metadata !DIExpression()), !dbg !26 + store i32 10, i32* %baz, align 4, !dbg !26 + call void @llvm.dbg.declare(metadata i32* %constVal, metadata !27, metadata !DIExpression()), !dbg !28 + %call = call i32 @_Z3funi(i32 10), !dbg !29 + store i32 %call, i32* %constVal, align 4, !dbg !28 + ret i32 0, !dbg !30 +} +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr dso_local i32 @_Z3funi(i32 %x) #2 comdat !dbg !31 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !34, metadata !DIExpression()), !dbg !35 + %0 = load i32, i32* %x.addr, align 4, !dbg !36 + %mul = mul nsw i32 %0, 2, !dbg !37 + ret i32 %mul, !dbg !38 +} + +attributes #0 = { noinline norecurse optnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { noinline nounwind optnone uwtable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "/dir/test.cpp", directory: "/dir/", checksumkind: CSK_MD5, checksum: "b973c468913ba52f145c9b21705fe0e0") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression(DW_OP_constu, 10, DW_OP_stack_value)) +!5 = distinct !DIGlobalVariable(name: "bar", scope: !0, file: !6, line: 13, type: !7, isLocal: true, isDefinition: true, flags: DIFlagConstExpr) +!6 = !DIFile(filename: "/dir/test.cpp", directory: "/dir", checksumkind: CSK_MD5, checksum: "b973c468913ba52f145c9b21705fe0e0") +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 7, !"Dwarf Version", i32 5} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 11.0.0 "} +!13 = distinct !DISubprogram(name: "main", scope: !6, file: !6, line: 17, type: !14, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!8, !8, !16} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!19 = !DILocalVariable(name: "argc", arg: 1, scope: !13, file: !6, line: 17, type: !8) +!20 = !DILocation(line: 17, column: 14, scope: !13) +!21 = !DILocalVariable(name: "argv", arg: 2, scope: !13, file: !6, line: 17, type: !16) +!22 = !DILocation(line: 17, column: 27, scope: !13) +!23 = !DILocalVariable(name: "foo", scope: !13, file: !6, line: 18, type: !8) +!24 = !DILocation(line: 18, column: 7, scope: !13) +!25 = !DILocalVariable(name: "baz", scope: !13, file: !6, line: 19, type: !7, flags: DIFlagConstExpr) +!26 = !DILocation(line: 19, column: 17, scope: !13) +!27 = !DILocalVariable(name: "constVal", scope: !13, file: !6, line: 20, type: !8) +!28 = !DILocation(line: 20, column: 7, scope: !13) +!29 = !DILocation(line: 20, column: 18, scope: !13) +!30 = !DILocation(line: 21, column: 3, scope: !13) +!31 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funi", scope: !6, file: !6, line: 15, type: !32, scopeLine: 15, flags: DIFlagPrototyped | DIFlagConstExpr, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!32 = !DISubroutineType(types: !33) +!33 = !{!8, !8} +!34 = !DILocalVariable(name: "x", arg: 1, scope: !31, file: !6, line: 15, type: !8) +!35 = !DILocation(line: 15, column: 23, scope: !31) +!36 = !DILocation(line: 15, column: 35, scope: !31) +!37 = !DILocation(line: 15, column: 37, scope: !31) +!38 = !DILocation(line: 15, column: 28, scope: !31)