Index: llvm/trunk/include/llvm-c/DebugInfo.h =================================================================== --- llvm/trunk/include/llvm-c/DebugInfo.h +++ llvm/trunk/include/llvm-c/DebugInfo.h @@ -159,7 +159,8 @@ LLVMDIObjCPropertyMetadataKind, LLVMDIImportedEntityMetadataKind, LLVMDIMacroMetadataKind, - LLVMDIMacroFileMetadataKind + LLVMDIMacroFileMetadataKind, + LLVMDICommonBlockMetadataKind }; typedef unsigned LLVMMetadataKind; Index: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h @@ -310,6 +310,7 @@ METADATA_INDEX_OFFSET = 38, // [offset] METADATA_INDEX = 39, // [bitpos] METADATA_LABEL = 40, // [distinct, scope, name, file, line] + METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each Index: llvm/trunk/include/llvm/IR/DIBuilder.h =================================================================== --- llvm/trunk/include/llvm/IR/DIBuilder.h +++ llvm/trunk/include/llvm/IR/DIBuilder.h @@ -706,6 +706,16 @@ DITemplateParameterArray TParams = nullptr, DITypeArray ThrownTypes = nullptr); + /// Create common block entry for a Fortran common block + /// \param Scope Scope of this common block + /// \param Name The name of this common block + /// \param File The file this common block is defined + /// \param LineNo Line number + /// \param VarList List of variables that a located in common block + DICommonBlock *createCommonBlock(DIScope *Scope, DIGlobalVariable *decl, + StringRef Name, DIFile *File, + unsigned LineNo); + /// This creates new descriptor for a namespace with the specified /// parent scope. /// \param Scope Namespace scope Index: llvm/trunk/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/trunk/include/llvm/IR/DebugInfoMetadata.h +++ llvm/trunk/include/llvm/IR/DebugInfoMetadata.h @@ -227,6 +227,7 @@ case DILexicalBlockKind: case DILexicalBlockFileKind: case DINamespaceKind: + case DICommonBlockKind: case DITemplateTypeParameterKind: case DITemplateValueParameterKind: case DIGlobalVariableKind: @@ -485,6 +486,7 @@ case DILexicalBlockKind: case DILexicalBlockFileKind: case DINamespaceKind: + case DICommonBlockKind: case DIModuleKind: return true; } @@ -2673,6 +2675,65 @@ } }; +class DICommonBlock : public DIScope { + unsigned LineNo; + + friend class LLVMContextImpl; + friend class MDNode; + + DICommonBlock(LLVMContext &Context, StorageType Storage, unsigned LineNo, + ArrayRef Ops) + : DIScope(Context, DICommonBlockKind, Storage, dwarf::DW_TAG_common_block, + Ops), LineNo(LineNo) {} + + static DICommonBlock *getImpl(LLVMContext &Context, DIScope *Scope, + DIGlobalVariable *Decl, StringRef Name, + DIFile *File, unsigned LineNo, + StorageType Storage, + bool ShouldCreate = true) { + return getImpl(Context, Scope, Decl, getCanonicalMDString(Context, Name), + File, LineNo, Storage, ShouldCreate); + } + static DICommonBlock *getImpl(LLVMContext &Context, Metadata *Scope, + Metadata *Decl, MDString *Name, Metadata *File, + unsigned LineNo, + StorageType Storage, bool ShouldCreate = true); + + TempDICommonBlock cloneImpl() const { + return getTemporary(getContext(), getScope(), getDecl(), getName(), + getFile(), getLineNo()); + } + +public: + DEFINE_MDNODE_GET(DICommonBlock, + (DIScope *Scope, DIGlobalVariable *Decl, StringRef Name, + DIFile *File, unsigned LineNo), + (Scope, Decl, Name, File, LineNo)) + DEFINE_MDNODE_GET(DICommonBlock, + (Metadata *Scope, Metadata *Decl, MDString *Name, + Metadata *File, unsigned LineNo), + (Scope, Decl, Name, File, LineNo)) + + TempDICommonBlock clone() const { return cloneImpl(); } + + DIScope *getScope() const { return cast_or_null(getRawScope()); } + DIGlobalVariable *getDecl() const { + return cast_or_null(getRawDecl()); + } + StringRef getName() const { return getStringOperand(2); } + DIFile *getFile() const { return cast_or_null(getRawFile()); } + unsigned getLineNo() const { return LineNo; } + + Metadata *getRawScope() const { return getOperand(0); } + Metadata *getRawDecl() const { return getOperand(1); } + MDString *getRawName() const { return getOperandAs(2); } + Metadata *getRawFile() const { return getOperand(3); } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DICommonBlockKind; + } +}; + /// Local variable. /// /// TODO: Split up flags. Index: llvm/trunk/include/llvm/IR/Metadata.def =================================================================== --- llvm/trunk/include/llvm/IR/Metadata.def +++ llvm/trunk/include/llvm/IR/Metadata.def @@ -113,6 +113,7 @@ HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -4664,6 +4664,24 @@ return false; } +/// ParseDICommonBlock: +/// ::= !DICommonBlock(scope: !0, file: !2, name: "COMMON name", line: 9) +bool LLParser::ParseDICommonBlock(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(scope, MDField, ); \ + OPTIONAL(declaration, MDField, ); \ + OPTIONAL(name, MDStringField, ); \ + OPTIONAL(file, MDField, ); \ + OPTIONAL(line, LineField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DICommonBlock, + (Context, scope.Val, declaration.Val, name.Val, + file.Val, line.Val)); + return false; +} + /// ParseDINamespace: /// ::= !DINamespace(scope: !0, file: !2, name: "SomeNamespace", line: 9) bool LLParser::ParseDINamespace(MDNode *&Result, bool IsDistinct) { Index: llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/trunk/lib/Bitcode/Reader/MetadataLoader.cpp @@ -811,6 +811,7 @@ case bitc::METADATA_LEXICAL_BLOCK: case bitc::METADATA_LEXICAL_BLOCK_FILE: case bitc::METADATA_NAMESPACE: + case bitc::METADATA_COMMON_BLOCK: case bitc::METADATA_MACRO: case bitc::METADATA_MACRO_FILE: case bitc::METADATA_TEMPLATE_TYPE: @@ -1528,6 +1529,17 @@ NextMetadataNo++; break; } + case bitc::METADATA_COMMON_BLOCK: { + IsDistinct = Record[0] & 1; + MetadataList.assignValue( + GET_OR_DISTINCT(DICommonBlock, + (Context, getMDOrNull(Record[1]), + getMDOrNull(Record[2]), getMDString(Record[3]), + getMDOrNull(Record[4]), Record[5])), + NextMetadataNo); + NextMetadataNo++; + break; + } case bitc::METADATA_NAMESPACE: { // Newer versions of DINamespace dropped file and line. MDString *Name; Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -317,6 +317,8 @@ void writeDILexicalBlockFile(const DILexicalBlockFile *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDICommonBlock(const DICommonBlock *N, + SmallVectorImpl &Record, unsigned Abbrev); void writeDINamespace(const DINamespace *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIMacro(const DIMacro *N, SmallVectorImpl &Record, @@ -1686,6 +1688,20 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDICommonBlock(const DICommonBlock *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getDecl())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLineNo()); + + Stream.EmitRecord(bitc::METADATA_COMMON_BLOCK, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDINamespace(const DINamespace *N, SmallVectorImpl &Record, unsigned Abbrev) { Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -139,6 +139,12 @@ getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, ArrayRef GlobalExprs); + DIE *getOrCreateCommonBlock(const DICommonBlock *CB, + ArrayRef GlobalExprs); + + void addLocationAttribute(DIE *ToDIE, const DIGlobalVariable *GV, + ArrayRef GlobalExprs); + /// addLabelAddress - Add a dwarf label attribute data and value using /// either DW_FORM_addr or DW_FORM_GNU_addr_index. void addLabelAddress(DIE &Die, dwarf::Attribute Attribute, Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -123,7 +123,9 @@ // Construct the context before querying for the existence of the DIE in // case such construction creates the DIE. - DIE *ContextDIE = getOrCreateContextDIE(GVContext); + auto *CB = GVContext ? dyn_cast(GVContext) : nullptr; + DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs) + : getOrCreateContextDIE(GVContext); // Add to map. DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV); @@ -166,6 +168,13 @@ addTemplateParams(*VariableDIE, DINodeArray(TP)); // Add location. + addLocationAttribute(VariableDIE, GV, GlobalExprs); + + return VariableDIE; +} + +void DwarfCompileUnit::addLocationAttribute( + DIE *VariableDIE, const DIGlobalVariable *GV, ArrayRef GlobalExprs) { bool addToAccelTable = false; DIELoc *Loc = nullptr; Optional NVPTXAddressSpace; @@ -288,8 +297,25 @@ DD->useAllLinkageNames()) DD->addAccelName(*CUNode, GV->getLinkageName(), *VariableDIE); } +} - return VariableDIE; +DIE *DwarfCompileUnit::getOrCreateCommonBlock( + const DICommonBlock *CB, ArrayRef GlobalExprs) { + // Construct the context before querying for the existence of the DIE in case + // such construction creates the DIE. + DIE *ContextDIE = getOrCreateContextDIE(CB->getScope()); + + if (DIE *NDie = getDIE(CB)) + return NDie; + DIE &NDie = createAndAddDIE(dwarf::DW_TAG_common_block, *ContextDIE, CB); + StringRef Name = CB->getName().empty() ? "_BLNK_" : CB->getName(); + addString(NDie, dwarf::DW_AT_name, Name); + addGlobalName(Name, NDie, CB->getScope()); + if (CB->getFile()) + addSourceLine(NDie, CB->getLineNo(), CB->getFile()); + if (DIGlobalVariable *V = CB->getDecl()) + getCU().addLocationAttribute(&NDie, V, GlobalExprs); + return &NDie; } void DwarfCompileUnit::addRange(RangeSpan Range) { Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -689,7 +689,7 @@ DD->addAccelType(*CUNode, Ty->getName(), TyDIE, Flags); if (!Context || isa(Context) || isa(Context) || - isa(Context)) + isa(Context) || isa(Context)) addGlobalType(Ty, TyDIE, Context); } } Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -2001,6 +2001,19 @@ Out << ")"; } +static void writeDICommonBlock(raw_ostream &Out, const DICommonBlock *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DICommonBlock("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printMetadata("scope", N->getRawScope(), false); + Printer.printMetadata("declaration", N->getRawDecl(), false); + Printer.printString("name", N->getName()); + Printer.printMetadata("file", N->getRawFile()); + Printer.printInt("line", N->getLineNo()); + Out << ")"; +} + static void writeDIMacro(raw_ostream &Out, const DIMacro *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { Index: llvm/trunk/lib/IR/DIBuilder.cpp =================================================================== --- llvm/trunk/lib/IR/DIBuilder.cpp +++ llvm/trunk/lib/IR/DIBuilder.cpp @@ -805,6 +805,13 @@ return SP; } +DICommonBlock *DIBuilder::createCommonBlock( + DIScope *Scope, DIGlobalVariable *Decl, StringRef Name, DIFile *File, + unsigned LineNo) { + return DICommonBlock::get( + VMContext, Scope, Decl, Name, File, LineNo); +} + DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name, bool ExportSymbols) { Index: llvm/trunk/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/trunk/lib/IR/DebugInfoMetadata.cpp +++ llvm/trunk/lib/IR/DebugInfoMetadata.cpp @@ -222,6 +222,9 @@ if (auto *NS = dyn_cast(this)) return NS->getScope(); + if (auto *CB = dyn_cast(this)) + return CB->getScope(); + if (auto *M = dyn_cast(this)) return M->getScope(); @@ -237,6 +240,8 @@ return SP->getName(); if (auto *NS = dyn_cast(this)) return NS->getName(); + if (auto *CB = dyn_cast(this)) + return CB->getName(); if (auto *M = dyn_cast(this)) return M->getName(); assert((isa(this) || isa(this) || @@ -694,6 +699,17 @@ DEFINE_GETIMPL_STORE(DINamespace, (ExportSymbols), Ops); } +DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope, + Metadata *Decl, MDString *Name, + Metadata *File, unsigned LineNo, + StorageType Storage, bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DICommonBlock, (Scope, Decl, Name, File, LineNo)); + // The nullptr is for DIScope's File operand. This should be refactored. + Metadata *Ops[] = {Scope, Decl, Name, File}; + DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops); +} + DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *ISysRoot, Index: llvm/trunk/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/trunk/lib/IR/LLVMContextImpl.h +++ llvm/trunk/lib/IR/LLVMContextImpl.h @@ -789,6 +789,31 @@ } }; +template <> struct MDNodeKeyImpl { + Metadata *Scope; + Metadata *Decl; + MDString *Name; + Metadata *File; + unsigned LineNo; + + MDNodeKeyImpl(Metadata *Scope, Metadata *Decl, MDString *Name, + Metadata *File, unsigned LineNo) + : Scope(Scope), Decl(Decl), Name(Name), File(File), LineNo(LineNo) {} + MDNodeKeyImpl(const DICommonBlock *N) + : Scope(N->getRawScope()), Decl(N->getRawDecl()), Name(N->getRawName()), + File(N->getRawFile()), LineNo(N->getLineNo()) {} + + bool isKeyOf(const DICommonBlock *RHS) const { + return Scope == RHS->getRawScope() && Decl == RHS->getRawDecl() && + Name == RHS->getRawName() && File == RHS->getRawFile() && + LineNo == RHS->getLineNo(); + } + + unsigned getHashValue() const { + return hash_combine(Scope, Decl, Name, File, LineNo); + } +}; + template <> struct MDNodeKeyImpl { Metadata *Scope; MDString *Name; Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -1156,6 +1156,14 @@ visitDILexicalBlockBase(N); } +void Verifier::visitDICommonBlock(const DICommonBlock &N) { + AssertDI(N.getTag() == dwarf::DW_TAG_common_block, "invalid tag", &N); + if (auto *S = N.getRawScope()) + AssertDI(isa(S), "invalid scope ref", &N, S); + if (auto *S = N.getRawDecl()) + AssertDI(isa(S), "invalid declaration", &N, S); +} + void Verifier::visitDINamespace(const DINamespace &N) { AssertDI(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N); if (auto *S = N.getRawScope()) @@ -1224,7 +1232,6 @@ visitDIVariable(N); AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); - AssertDI(!N.getName().empty(), "missing global variable name", &N); AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); AssertDI(N.getType(), "missing global variable type", &N); if (auto *Member = N.getRawStaticDataMemberDeclaration()) { Index: llvm/trunk/test/Assembler/DICommonBlock.ll =================================================================== --- llvm/trunk/test/Assembler/DICommonBlock.ll +++ llvm/trunk/test/Assembler/DICommonBlock.ll @@ -0,0 +1,26 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; CHECK-DAG: [[MD:![0-9]+]] = !DICommonBlock({{.*}}name: "a" +; CHECK-DAG: !DIGlobalVariable({{.*}}name: "c",{{.*}}scope: [[MD]] + +@common_a = common global [32 x i8] zeroinitializer, align 8, !dbg !13, !dbg !15 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7} +!llvm.ident = !{!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !1, producer: "PGI Fortran", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, retainedTypes: !14, globals: !3) +!1 = !DIFile(filename: "none.f90", directory: "/not/here/") +!2 = distinct !DIGlobalVariable(scope: !5, name: "c", file: !1, type: !12, isDefinition: true) +!3 = !{!13, !15} +!4 = distinct !DIGlobalVariable(scope: !5, name: "COMMON /foo/", file: !1, line: 4, isLocal: false, isDefinition: true, type: !12) +!5 = !DICommonBlock(scope: !9, declaration: !4, name: "a", file: !1, line: 4) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{!"PGI Fortran"} +!9 = distinct !DISubprogram(name: "subrtn", scope: !0, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, unit: !0) +!10 = !DISubroutineType(types: !11) +!11 = !{!12, !12} +!12 = !DIBasicType(name: "int", size: 32) +!13 = !DIGlobalVariableExpression(var: !4, expr: !DIExpression()) +!14 = !{!12, !10} +!15 = !DIGlobalVariableExpression(var: !2, expr: !DIExpression(DW_OP_plus_uconst, 4)) Index: llvm/trunk/test/DebugInfo/Generic/DICommonBlock.ll =================================================================== --- llvm/trunk/test/DebugInfo/Generic/DICommonBlock.ll +++ llvm/trunk/test/DebugInfo/Generic/DICommonBlock.ll @@ -0,0 +1,42 @@ +; REQUIRES: object-emission +; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t +; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s +; CHECK: DW_TAG_common_block +; CHECK-DAG: DW_AT_name{{.*}}"a" +; CHECK-DAG: DW_AT_location +; CHECK: DW_TAG_variable +; CHECK-DAG: DW_AT_name{{.*}}"c" +; CHECK-DAG: DW_AT_location{{.*}}DW_OP_plus_uconst{{.*}}4 +; CHECK: {{DW_TAG|NULL}} + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +@common_a = common global [32 x i8] zeroinitializer, align 8, !dbg !13, !dbg !15 + +define i32 @subr() !dbg !9 { + %1 = getelementptr inbounds [32 x i8], [32 x i8]* @common_a, i64 0, i32 8 + %2 = bitcast i8* %1 to i32* + %3 = load i32, i32* %2 + ret i32 %3 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7} +!llvm.ident = !{!8} + +!0 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !1, producer: "PGI Fortran", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, retainedTypes: !14, globals: !3) +!1 = !DIFile(filename: "none.f90", directory: "/not/here/") +!2 = distinct !DIGlobalVariable(scope: !5, name: "c", file: !1, type: !12, isDefinition: true) +!3 = !{!13, !15} +!4 = distinct !DIGlobalVariable(scope: !5, name: "COMMON /foo/", file: !1, line: 4, isLocal: false, isDefinition: true, type: !12) +!5 = !DICommonBlock(scope: !9, declaration: !4, name: "a", file: !1, line: 4) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{!"PGI Fortran"} +!9 = distinct !DISubprogram(name: "s", scope: !0, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, unit: !0) +!10 = !DISubroutineType(types: !11) +!11 = !{!12, !12} +!12 = !DIBasicType(name: "int", size: 32) +!13 = !DIGlobalVariableExpression(var: !4, expr: !DIExpression()) +!14 = !{!12, !10} +!15 = !DIGlobalVariableExpression(var: !2, expr: !DIExpression(DW_OP_plus_uconst, 4))