llvm.org GIT mirror llvm / f09c6d5
Add LLVM IR debug info support for Fortran COMMON blocks COMMON blocks are a feature of Fortran that has no direct analog in C languages, but they are similar to data sections in assembly language programming. A COMMON block is a named area of memory that holds a collection of variables. Fortran subprograms may map the COMMON block memory area to their own, possibly distinct, non-empty list of variables. A Fortran COMMON block might look like the following example. COMMON /ALPHA/ I, J For this construct, the compiler generates a new scope-like DI construct (!DICommonBlock) into which variables (see I, J above) can be placed. As the common block implies a range of storage with global lifetime, the !DICommonBlock refers to a !DIGlobalVariable. The Fortran variable that comprise the COMMON block are also linked via metadata to offsets within the global variable that stands for the entire common block. @alpha_ = common global %alphabytes_ zeroinitializer, align 64, !dbg !27, !dbg !30, !dbg !33 !14 = distinct !DISubprogram(…) !20 = distinct !DICommonBlock(scope: !14, declaration: !25, name: "alpha") !25 = distinct !DIGlobalVariable(scope: !20, name: "common alpha", type: !24) !27 = !DIGlobalVariableExpression(var: !25, expr: !DIExpression()) !29 = distinct !DIGlobalVariable(scope: !20, name: "i", file: !3, type: !28) !30 = !DIGlobalVariableExpression(var: !29, expr: !DIExpression()) !31 = distinct !DIGlobalVariable(scope: !20, name: "j", file: !3, type: !28) !32 = !DIExpression(DW_OP_plus_uconst, 4) !33 = !DIGlobalVariableExpression(var: !31, expr: !32) The DWARF generated for this is as follows. DW_TAG_common_block: DW_AT_name: alpha DW_AT_location: @alpha_+0 DW_TAG_variable: DW_AT_name: common alpha DW_AT_type: array of 8 bytes DW_AT_location: @alpha_+0 DW_TAG_variable: DW_AT_name: i DW_AT_type: integer*4 DW_AT_location: @Alpha+0 DW_TAG_variable: DW_AT_name: j DW_AT_type: integer*4 DW_AT_location: @Alpha+4 Patch by Eric Schweitz! Differential Revision: https://reviews.llvm.org/D54327 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357934 91177308-0d34-0410-b5e6-96231b3b80d8 Adrian Prantl 4 months ago
18 changed file(s) with 294 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
309309 METADATA_INDEX_OFFSET = 38, // [offset]
310310 METADATA_INDEX = 39, // [bitpos]
311311 METADATA_LABEL = 40, // [distinct, scope, name, file, line]
312 METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...]
312313 };
313314
314315 // The constants block (CONSTANTS_BLOCK_ID) describes emission for each
705705 DITemplateParameterArray TParams = nullptr,
706706 DITypeArray ThrownTypes = nullptr);
707707
708 /// Create common block entry for a Fortran common block
709 /// \param Scope Scope of this common block
710 /// \param Name The name of this common block
711 /// \param File The file this common block is defined
712 /// \param LineNo Line number
713 /// \param VarList List of variables that a located in common block
714 DICommonBlock *createCommonBlock(DIScope *Scope, DIGlobalVariable *decl,
715 StringRef Name, DIFile *File,
716 unsigned LineNo);
717
708718 /// This creates new descriptor for a namespace with the specified
709719 /// parent scope.
710720 /// \param Scope Namespace scope
226226 case DILexicalBlockKind:
227227 case DILexicalBlockFileKind:
228228 case DINamespaceKind:
229 case DICommonBlockKind:
229230 case DITemplateTypeParameterKind:
230231 case DITemplateValueParameterKind:
231232 case DIGlobalVariableKind:
484485 case DILexicalBlockKind:
485486 case DILexicalBlockFileKind:
486487 case DINamespaceKind:
488 case DICommonBlockKind:
487489 case DIModuleKind:
488490 return true;
489491 }
26722674 }
26732675 };
26742676
2677 class DICommonBlock : public DIScope {
2678 unsigned LineNo;
2679
2680 friend class LLVMContextImpl;
2681 friend class MDNode;
2682
2683 DICommonBlock(LLVMContext &Context, StorageType Storage, unsigned LineNo,
2684 ArrayRef Ops)
2685 : DIScope(Context, DICommonBlockKind, Storage, dwarf::DW_TAG_common_block,
2686 Ops), LineNo(LineNo) {}
2687
2688 static DICommonBlock *getImpl(LLVMContext &Context, DIScope *Scope,
2689 DIGlobalVariable *Decl, StringRef Name,
2690 DIFile *File, unsigned LineNo,
2691 StorageType Storage,
2692 bool ShouldCreate = true) {
2693 return getImpl(Context, Scope, Decl, getCanonicalMDString(Context, Name),
2694 File, LineNo, Storage, ShouldCreate);
2695 }
2696 static DICommonBlock *getImpl(LLVMContext &Context, Metadata *Scope,
2697 Metadata *Decl, MDString *Name, Metadata *File,
2698 unsigned LineNo,
2699 StorageType Storage, bool ShouldCreate = true);
2700
2701 TempDICommonBlock cloneImpl() const {
2702 return getTemporary(getContext(), getScope(), getDecl(), getName(),
2703 getFile(), getLineNo());
2704 }
2705
2706 public:
2707 DEFINE_MDNODE_GET(DICommonBlock,
2708 (DIScope *Scope, DIGlobalVariable *Decl, StringRef Name,
2709 DIFile *File, unsigned LineNo),
2710 (Scope, Decl, Name, File, LineNo))
2711 DEFINE_MDNODE_GET(DICommonBlock,
2712 (Metadata *Scope, Metadata *Decl, MDString *Name,
2713 Metadata *File, unsigned LineNo),
2714 (Scope, Decl, Name, File, LineNo))
2715
2716 TempDICommonBlock clone() const { return cloneImpl(); }
2717
2718 DIScope *getScope() const { return cast_or_null(getRawScope()); }
2719 DIGlobalVariable *getDecl() const {
2720 return cast_or_null(getRawDecl());
2721 }
2722 StringRef getName() const { return getStringOperand(2); }
2723 DIFile *getFile() const { return cast_or_null(getRawFile()); }
2724 unsigned getLineNo() const { return LineNo; }
2725
2726 Metadata *getRawScope() const { return getOperand(0); }
2727 Metadata *getRawDecl() const { return getOperand(1); }
2728 MDString *getRawName() const { return getOperandAs(2); }
2729 Metadata *getRawFile() const { return getOperand(3); }
2730
2731 static bool classof(const Metadata *MD) {
2732 return MD->getMetadataID() == DICommonBlockKind;
2733 }
2734 };
2735
26752736 /// Local variable.
26762737 ///
26772738 /// TODO: Split up flags.
112112 HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode)
113113 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
114114 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)
115 HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DICommonBlock)
115116
116117 #undef HANDLE_METADATA
117118 #undef HANDLE_METADATA_LEAF
158158 LLVMDIObjCPropertyMetadataKind,
159159 LLVMDIImportedEntityMetadataKind,
160160 LLVMDIMacroMetadataKind,
161 LLVMDIMacroFileMetadataKind
161 LLVMDIMacroFileMetadataKind,
162 LLVMDICommonBlockMetadataKind
162163 };
163164 typedef unsigned LLVMMetadataKind;
164165
46634663 return false;
46644664 }
46654665
4666 /// ParseDICommonBlock:
4667 /// ::= !DICommonBlock(scope: !0, file: !2, name: "COMMON name", line: 9)
4668 bool LLParser::ParseDICommonBlock(MDNode *&Result, bool IsDistinct) {
4669 #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
4670 REQUIRED(scope, MDField, ); \
4671 OPTIONAL(declaration, MDField, ); \
4672 OPTIONAL(name, MDStringField, ); \
4673 OPTIONAL(file, MDField, ); \
4674 OPTIONAL(line, LineField, );
4675 PARSE_MD_FIELDS();
4676 #undef VISIT_MD_FIELDS
4677
4678 Result = GET_OR_DISTINCT(DICommonBlock,
4679 (Context, scope.Val, declaration.Val, name.Val,
4680 file.Val, line.Val));
4681 return false;
4682 }
4683
46664684 /// ParseDINamespace:
46674685 /// ::= !DINamespace(scope: !0, file: !2, name: "SomeNamespace", line: 9)
46684686 bool LLParser::ParseDINamespace(MDNode *&Result, bool IsDistinct) {
810810 case bitc::METADATA_LEXICAL_BLOCK:
811811 case bitc::METADATA_LEXICAL_BLOCK_FILE:
812812 case bitc::METADATA_NAMESPACE:
813 case bitc::METADATA_COMMON_BLOCK:
813814 case bitc::METADATA_MACRO:
814815 case bitc::METADATA_MACRO_FILE:
815816 case bitc::METADATA_TEMPLATE_TYPE:
15271528 NextMetadataNo++;
15281529 break;
15291530 }
1531 case bitc::METADATA_COMMON_BLOCK: {
1532 IsDistinct = Record[0] & 1;
1533 MetadataList.assignValue(
1534 GET_OR_DISTINCT(DICommonBlock,
1535 (Context, getMDOrNull(Record[1]),
1536 getMDOrNull(Record[2]), getMDString(Record[3]),
1537 getMDOrNull(Record[4]), Record[5])),
1538 NextMetadataNo);
1539 NextMetadataNo++;
1540 break;
1541 }
15301542 case bitc::METADATA_NAMESPACE: {
15311543 // Newer versions of DINamespace dropped file and line.
15321544 MDString *Name;
316316 void writeDILexicalBlockFile(const DILexicalBlockFile *N,
317317 SmallVectorImpl &Record,
318318 unsigned Abbrev);
319 void writeDICommonBlock(const DICommonBlock *N,
320 SmallVectorImpl &Record, unsigned Abbrev);
319321 void writeDINamespace(const DINamespace *N, SmallVectorImpl &Record,
320322 unsigned Abbrev);
321323 void writeDIMacro(const DIMacro *N, SmallVectorImpl &Record,
16851687 Record.clear();
16861688 }
16871689
1690 void ModuleBitcodeWriter::writeDICommonBlock(const DICommonBlock *N,
1691 SmallVectorImpl &Record,
1692 unsigned Abbrev) {
1693 Record.push_back(N->isDistinct());
1694 Record.push_back(VE.getMetadataOrNullID(N->getScope()));
1695 Record.push_back(VE.getMetadataOrNullID(N->getDecl()));
1696 Record.push_back(VE.getMetadataOrNullID(N->getRawName()));
1697 Record.push_back(VE.getMetadataOrNullID(N->getFile()));
1698 Record.push_back(N->getLineNo());
1699
1700 Stream.EmitRecord(bitc::METADATA_COMMON_BLOCK, Record, Abbrev);
1701 Record.clear();
1702 }
1703
16881704 void ModuleBitcodeWriter::writeDINamespace(const DINamespace *N,
16891705 SmallVectorImpl &Record,
16901706 unsigned Abbrev) {
122122
123123 // Construct the context before querying for the existence of the DIE in
124124 // case such construction creates the DIE.
125 DIE *ContextDIE = getOrCreateContextDIE(GVContext);
125 auto *CB = GVContext ? dyn_cast(GVContext) : nullptr;
126 DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs)
127 : getOrCreateContextDIE(GVContext);
126128
127129 // Add to map.
128130 DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV);
165167 addTemplateParams(*VariableDIE, DINodeArray(TP));
166168
167169 // Add location.
170 addLocationAttribute(VariableDIE, GV, GlobalExprs);
171
172 return VariableDIE;
173 }
174
175 void DwarfCompileUnit::addLocationAttribute(
176 DIE *VariableDIE, const DIGlobalVariable *GV, ArrayRef GlobalExprs) {
168177 bool addToAccelTable = false;
169178 DIELoc *Loc = nullptr;
170179 Optional NVPTXAddressSpace;
287296 DD->useAllLinkageNames())
288297 DD->addAccelName(*CUNode, GV->getLinkageName(), *VariableDIE);
289298 }
290
291 return VariableDIE;
299 }
300
301 DIE *DwarfCompileUnit::getOrCreateCommonBlock(
302 const DICommonBlock *CB, ArrayRef GlobalExprs) {
303 // Construct the context before querying for the existence of the DIE in case
304 // such construction creates the DIE.
305 DIE *ContextDIE = getOrCreateContextDIE(CB->getScope());
306
307 if (DIE *NDie = getDIE(CB))
308 return NDie;
309 DIE &NDie = createAndAddDIE(dwarf::DW_TAG_common_block, *ContextDIE, CB);
310 StringRef Name = CB->getName().empty() ? "_BLNK_" : CB->getName();
311 addString(NDie, dwarf::DW_AT_name, Name);
312 addGlobalName(Name, NDie, CB->getScope());
313 if (CB->getFile())
314 addSourceLine(NDie, CB->getLineNo(), CB->getFile());
315 if (DIGlobalVariable *V = CB->getDecl())
316 getCU().addLocationAttribute(&NDie, V, GlobalExprs);
317 return &NDie;
292318 }
293319
294320 void DwarfCompileUnit::addRange(RangeSpan Range) {
138138 getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV,
139139 ArrayRef GlobalExprs);
140140
141 DIE *getOrCreateCommonBlock(const DICommonBlock *CB,
142 ArrayRef GlobalExprs);
143
144 void addLocationAttribute(DIE *ToDIE, const DIGlobalVariable *GV,
145 ArrayRef GlobalExprs);
146
141147 /// addLabelAddress - Add a dwarf label attribute data and value using
142148 /// either DW_FORM_addr or DW_FORM_GNU_addr_index.
143149 void addLabelAddress(DIE &Die, dwarf::Attribute Attribute,
688688 DD->addAccelType(*CUNode, Ty->getName(), TyDIE, Flags);
689689
690690 if (!Context || isa(Context) || isa(Context) ||
691 isa(Context))
691 isa(Context) || isa(Context))
692692 addGlobalType(Ty, TyDIE, Context);
693693 }
694694 }
20002000 Out << ")";
20012001 }
20022002
2003 static void writeDICommonBlock(raw_ostream &Out, const DICommonBlock *N,
2004 TypePrinting *TypePrinter, SlotTracker *Machine,
2005 const Module *Context) {
2006 Out << "!DICommonBlock(";
2007 MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
2008 Printer.printMetadata("scope", N->getRawScope(), false);
2009 Printer.printMetadata("declaration", N->getRawDecl(), false);
2010 Printer.printString("name", N->getName());
2011 Printer.printMetadata("file", N->getRawFile());
2012 Printer.printInt("line", N->getLineNo());
2013 Out << ")";
2014 }
2015
20032016 static void writeDIMacro(raw_ostream &Out, const DIMacro *N,
20042017 TypePrinting *TypePrinter, SlotTracker *Machine,
20052018 const Module *Context) {
804804 return SP;
805805 }
806806
807 DICommonBlock *DIBuilder::createCommonBlock(
808 DIScope *Scope, DIGlobalVariable *Decl, StringRef Name, DIFile *File,
809 unsigned LineNo) {
810 return DICommonBlock::get(
811 VMContext, Scope, Decl, Name, File, LineNo);
812 }
813
807814 DINamespace *DIBuilder::createNameSpace(DIScope *Scope, StringRef Name,
808815 bool ExportSymbols) {
809816
221221 if (auto *NS = dyn_cast(this))
222222 return NS->getScope();
223223
224 if (auto *CB = dyn_cast(this))
225 return CB->getScope();
226
224227 if (auto *M = dyn_cast(this))
225228 return M->getScope();
226229
236239 return SP->getName();
237240 if (auto *NS = dyn_cast(this))
238241 return NS->getName();
242 if (auto *CB = dyn_cast(this))
243 return CB->getName();
239244 if (auto *M = dyn_cast(this))
240245 return M->getName();
241246 assert((isa(this) || isa(this) ||
693698 DEFINE_GETIMPL_STORE(DINamespace, (ExportSymbols), Ops);
694699 }
695700
701 DICommonBlock *DICommonBlock::getImpl(LLVMContext &Context, Metadata *Scope,
702 Metadata *Decl, MDString *Name,
703 Metadata *File, unsigned LineNo,
704 StorageType Storage, bool ShouldCreate) {
705 assert(isCanonical(Name) && "Expected canonical MDString");
706 DEFINE_GETIMPL_LOOKUP(DICommonBlock, (Scope, Decl, Name, File, LineNo));
707 // The nullptr is for DIScope's File operand. This should be refactored.
708 Metadata *Ops[] = {Scope, Decl, Name, File};
709 DEFINE_GETIMPL_STORE(DICommonBlock, (LineNo), Ops);
710 }
711
696712 DIModule *DIModule::getImpl(LLVMContext &Context, Metadata *Scope,
697713 MDString *Name, MDString *ConfigurationMacros,
698714 MDString *IncludePath, MDString *ISysRoot,
788788 }
789789 };
790790
791 template <> struct MDNodeKeyImpl {
792 Metadata *Scope;
793 Metadata *Decl;
794 MDString *Name;
795 Metadata *File;
796 unsigned LineNo;
797
798 MDNodeKeyImpl(Metadata *Scope, Metadata *Decl, MDString *Name,
799 Metadata *File, unsigned LineNo)
800 : Scope(Scope), Decl(Decl), Name(Name), File(File), LineNo(LineNo) {}
801 MDNodeKeyImpl(const DICommonBlock *N)
802 : Scope(N->getRawScope()), Decl(N->getRawDecl()), Name(N->getRawName()),
803 File(N->getRawFile()), LineNo(N->getLineNo()) {}
804
805 bool isKeyOf(const DICommonBlock *RHS) const {
806 return Scope == RHS->getRawScope() && Decl == RHS->getRawDecl() &&
807 Name == RHS->getRawName() && File == RHS->getRawFile() &&
808 LineNo == RHS->getLineNo();
809 }
810
811 unsigned getHashValue() const {
812 return hash_combine(Scope, Decl, Name, File, LineNo);
813 }
814 };
815
791816 template <> struct MDNodeKeyImpl {
792817 Metadata *Scope;
793818 MDString *Name;
11551155 visitDILexicalBlockBase(N);
11561156 }
11571157
1158 void Verifier::visitDICommonBlock(const DICommonBlock &N) {
1159 AssertDI(N.getTag() == dwarf::DW_TAG_common_block, "invalid tag", &N);
1160 if (auto *S = N.getRawScope())
1161 AssertDI(isa(S), "invalid scope ref", &N, S);
1162 if (auto *S = N.getRawDecl())
1163 AssertDI(isa(S), "invalid declaration", &N, S);
1164 }
1165
11581166 void Verifier::visitDINamespace(const DINamespace &N) {
11591167 AssertDI(N.getTag() == dwarf::DW_TAG_namespace, "invalid tag", &N);
11601168 if (auto *S = N.getRawScope())
12231231 visitDIVariable(N);
12241232
12251233 AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N);
1226 AssertDI(!N.getName().empty(), "missing global variable name", &N);
12271234 AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType());
12281235 AssertDI(N.getType(), "missing global variable type", &N);
12291236 if (auto *Member = N.getRawStaticDataMemberDeclaration()) {
0 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
1 ; CHECK-DAG: [[MD:![0-9]+]] = !DICommonBlock({{.*}}name: "a"
2 ; CHECK-DAG: !DIGlobalVariable({{.*}}name: "c",{{.*}}scope: [[MD]]
3
4 @common_a = common global [32 x i8] zeroinitializer, align 8, !dbg !13, !dbg !15
5
6 !llvm.dbg.cu = !{!0}
7 !llvm.module.flags = !{!6, !7}
8 !llvm.ident = !{!8}
9
10 !0 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !1, producer: "PGI Fortran", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, retainedTypes: !14, globals: !3)
11 !1 = !DIFile(filename: "none.f90", directory: "/not/here/")
12 !2 = distinct !DIGlobalVariable(scope: !5, name: "c", file: !1, type: !12, isDefinition: true)
13 !3 = !{!13, !15}
14 !4 = distinct !DIGlobalVariable(scope: !5, name: "COMMON /foo/", file: !1, line: 4, isLocal: false, isDefinition: true, type: !12)
15 !5 = !DICommonBlock(scope: !9, declaration: !4, name: "a", file: !1, line: 4)
16 !6 = !{i32 2, !"Dwarf Version", i32 4}
17 !7 = !{i32 2, !"Debug Info Version", i32 3}
18 !8 = !{!"PGI Fortran"}
19 !9 = distinct !DISubprogram(name: "subrtn", scope: !0, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, unit: !0)
20 !10 = !DISubroutineType(types: !11)
21 !11 = !{!12, !12}
22 !12 = !DIBasicType(name: "int", size: 32)
23 !13 = !DIGlobalVariableExpression(var: !4, expr: !DIExpression())
24 !14 = !{!12, !10}
25 !15 = !DIGlobalVariableExpression(var: !2, expr: !DIExpression(DW_OP_plus_uconst, 4))
0 ; REQUIRES: object-emission
1 ; RUN: %llc_dwarf -O0 -filetype=obj < %s > %t
2 ; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
3 ; CHECK: DW_TAG_common_block
4 ; CHECK-DAG: DW_AT_name{{.*}}"a"
5 ; CHECK-DAG: DW_AT_location
6 ; CHECK: DW_TAG_variable
7 ; CHECK-DAG: DW_AT_name{{.*}}"c"
8 ; CHECK-DAG: DW_AT_location{{.*}}DW_OP_plus_uconst{{.*}}4
9 ; CHECK: {{DW_TAG|NULL}}
10
11 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
12
13 @common_a = common global [32 x i8] zeroinitializer, align 8, !dbg !13, !dbg !15
14
15 define i32 @subr() !dbg !9 {
16 %1 = getelementptr inbounds [32 x i8], [32 x i8]* @common_a, i64 0, i32 8
17 %2 = bitcast i8* %1 to i32*
18 %3 = load i32, i32* %2
19 ret i32 %3
20 }
21
22 !llvm.dbg.cu = !{!0}
23 !llvm.module.flags = !{!6, !7}
24 !llvm.ident = !{!8}
25
26 !0 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !1, producer: "PGI Fortran", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, retainedTypes: !14, globals: !3)
27 !1 = !DIFile(filename: "none.f90", directory: "/not/here/")
28 !2 = distinct !DIGlobalVariable(scope: !5, name: "c", file: !1, type: !12, isDefinition: true)
29 !3 = !{!13, !15}
30 !4 = distinct !DIGlobalVariable(scope: !5, name: "COMMON /foo/", file: !1, line: 4, isLocal: false, isDefinition: true, type: !12)
31 !5 = !DICommonBlock(scope: !9, declaration: !4, name: "a", file: !1, line: 4)
32 !6 = !{i32 2, !"Dwarf Version", i32 4}
33 !7 = !{i32 2, !"Debug Info Version", i32 3}
34 !8 = !{!"PGI Fortran"}
35 !9 = distinct !DISubprogram(name: "s", scope: !0, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, unit: !0)
36 !10 = !DISubroutineType(types: !11)
37 !11 = !{!12, !12}
38 !12 = !DIBasicType(name: "int", size: 32)
39 !13 = !DIGlobalVariableExpression(var: !4, expr: !DIExpression())
40 !14 = !{!12, !10}
41 !15 = !DIGlobalVariableExpression(var: !2, expr: !DIExpression(DW_OP_plus_uconst, 4))