Commit c757f19790

William Sengir <william@sengir.com>
2022-03-13 08:28:34
stage2: add debug info for globals in the LLVM backend
LLVM backend: generate DIGlobalVariable's for non-function globals and rename linkage names when exporting functions and globals. zig_llvm.cpp: add some wrappers to convert a handful of DI classes into DINode's since DIGlobalVariable is not a DIScope like the others. zig_llvm.cpp: add some wrappers to allow replacing the LinkageName of DISubprogram and DIGlobalVariable. zig_llvm.cpp: fix DI class mixup causing nonsense reinterpret_cast. The end result is that GDB is now usable since you now no longer need to manually cast every global nor fully qualify every export.
1 parent f36bf85
src/codegen/llvm/bindings.zig
@@ -855,7 +855,17 @@ pub const Builder = opaque {
     extern fn LLVMBuildShuffleVector(*const Builder, V1: *const Value, V2: *const Value, Mask: *const Value, Name: [*:0]const u8) *const Value;
 };
 
-pub const DIScope = opaque {};
+pub const MDString = opaque {
+    pub const get = LLVMMDStringInContext2;
+    extern fn LLVMMDStringInContext2(C: *const Context, Str: [*]const u8, SLen: usize) *MDString;
+};
+
+pub const DIScope = opaque {
+    pub const toNode = ZigLLVMScopeToNode;
+    extern fn ZigLLVMScopeToNode(scope: *DIScope) *DINode;
+};
+
+pub const DINode = opaque {};
 pub const Metadata = opaque {};
 
 pub const IntPredicate = enum(c_uint) {
@@ -1421,28 +1431,52 @@ pub const address_space = struct {
 
 pub const DIEnumerator = opaque {};
 pub const DILocalVariable = opaque {};
-pub const DIGlobalVariable = opaque {};
 pub const DILocation = opaque {};
 
+pub const DIGlobalVariable = opaque {
+    pub const toNode = ZigLLVMGlobalVariableToNode;
+    extern fn ZigLLVMGlobalVariableToNode(global_variable: *DIGlobalVariable) *DINode;
+
+    pub const replaceLinkageName = ZigLLVMGlobalVariableReplaceLinkageName;
+    extern fn ZigLLVMGlobalVariableReplaceLinkageName(global_variable: *DIGlobalVariable, linkage_name: *MDString) void;
+};
 pub const DIType = opaque {
     pub const toScope = ZigLLVMTypeToScope;
     extern fn ZigLLVMTypeToScope(ty: *DIType) *DIScope;
+
+    pub const toNode = ZigLLVMTypeToNode;
+    extern fn ZigLLVMTypeToNode(ty: *DIType) *DINode;
 };
 pub const DIFile = opaque {
     pub const toScope = ZigLLVMFileToScope;
     extern fn ZigLLVMFileToScope(difile: *DIFile) *DIScope;
+
+    pub const toNode = ZigLLVMFileToNode;
+    extern fn ZigLLVMFileToNode(difile: *DIFile) *DINode;
 };
 pub const DILexicalBlock = opaque {
     pub const toScope = ZigLLVMLexicalBlockToScope;
     extern fn ZigLLVMLexicalBlockToScope(lexical_block: *DILexicalBlock) *DIScope;
+
+    pub const toNode = ZigLLVMLexicalBlockToNode;
+    extern fn ZigLLVMLexicalBlockToNode(lexical_block: *DILexicalBlock) *DINode;
 };
 pub const DICompileUnit = opaque {
     pub const toScope = ZigLLVMCompileUnitToScope;
     extern fn ZigLLVMCompileUnitToScope(compile_unit: *DICompileUnit) *DIScope;
+
+    pub const toNode = ZigLLVMCompileUnitToNode;
+    extern fn ZigLLVMCompileUnitToNode(compile_unit: *DICompileUnit) *DINode;
 };
 pub const DISubprogram = opaque {
     pub const toScope = ZigLLVMSubprogramToScope;
     extern fn ZigLLVMSubprogramToScope(subprogram: *DISubprogram) *DIScope;
+
+    pub const toNode = ZigLLVMSubprogramToNode;
+    extern fn ZigLLVMSubprogramToNode(subprogram: *DISubprogram) *DINode;
+
+    pub const replaceLinkageName = ZigLLVMSubprogramReplaceLinkageName;
+    extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void;
 };
 
 pub const getDebugLoc = ZigLLVMGetDebugLoc;
src/codegen/llvm.zig
@@ -164,8 +164,9 @@ pub const Object = struct {
     di_builder: ?*llvm.DIBuilder,
     /// One of these mappings:
     /// - *Module.File => *DIFile
-    /// - *Module.Decl => *DISubprogram
-    di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DIScope),
+    /// - *Module.Decl (Fn) => *DISubprogram
+    /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
+    di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode),
     di_compile_unit: ?*llvm.DICompileUnit,
     context: *const llvm.Context,
     target_machine: *const llvm.TargetMachine,
@@ -591,6 +592,7 @@ pub const Object = struct {
                 dg.module.comp.bin_file.options.optimize_mode != .Debug,
                 null, // decl_subprogram
             );
+            try dg.object.di_map.put(gpa, decl, subprogram.toNode());
 
             llvm_func.fnSetSubprogram(subprogram);
 
@@ -667,6 +669,17 @@ pub const Object = struct {
             llvm_global.setValueName(decl.name);
             llvm_global.setUnnamedAddr(.False);
             llvm_global.setLinkage(.External);
+            if (self.di_map.get(decl)) |di_node| {
+                if (try decl.isFunction()) {
+                    const di_func = @ptrCast(*llvm.DISubprogram, di_node);
+                    const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name));
+                    di_func.replaceLinkageName(linkage_name);
+                } else {
+                    const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node);
+                    const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name));
+                    di_global.replaceLinkageName(linkage_name);
+                }
+            }
             if (decl.val.castTag(.variable)) |variable| {
                 if (variable.data.is_threadlocal) {
                     llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
@@ -681,6 +694,17 @@ pub const Object = struct {
             const exp_name = exports[0].options.name;
             llvm_global.setValueName2(exp_name.ptr, exp_name.len);
             llvm_global.setUnnamedAddr(.False);
+            if (self.di_map.get(decl)) |di_node| {
+                if (try decl.isFunction()) {
+                    const di_func = @ptrCast(*llvm.DISubprogram, di_node);
+                    const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
+                    di_func.replaceLinkageName(linkage_name);
+                } else {
+                    const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node);
+                    const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len);
+                    di_global.replaceLinkageName(linkage_name);
+                }
+            }
             switch (exports[0].options.linkage) {
                 .Internal => unreachable,
                 .Strong => llvm_global.setLinkage(.External),
@@ -746,7 +770,7 @@ pub const Object = struct {
         const dir_path_z = try gpa.dupeZ(u8, dir_path);
         defer gpa.free(dir_path_z);
         const di_file = o.di_builder.?.createFile(sub_file_path_z, dir_path_z);
-        gop.value_ptr.* = di_file.toScope();
+        gop.value_ptr.* = di_file.toNode();
         return di_file;
     }
 };
@@ -784,7 +808,7 @@ pub const DeclGen = struct {
             _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl);
         } else {
             const target = dg.module.getTarget();
-            const global = try dg.resolveGlobalDecl(decl);
+            var global = try dg.resolveGlobalDecl(decl);
             global.setAlignment(decl.getAlignment(target));
             assert(decl.has_tv);
             const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
@@ -828,8 +852,27 @@ pub const DeclGen = struct {
                     dg.object.decl_map.putAssumeCapacity(decl, new_global);
                     new_global.takeName(global);
                     global.deleteGlobal();
+                    global = new_global;
                 }
             }
+
+            if (dg.object.di_builder) |dib| {
+                const di_file = try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope);
+
+                const line_number = decl.src_line + 1;
+                const is_internal_linkage = !dg.module.decl_exports.contains(decl);
+                const di_global = dib.createGlobalVariable(
+                    di_file.toScope(),
+                    decl.name,
+                    global.getValueName(),
+                    di_file,
+                    line_number,
+                    try dg.lowerDebugType(decl.ty),
+                    is_internal_linkage,
+                );
+
+                try dg.object.di_map.put(dg.gpa, dg.decl, di_global.toNode());
+            }
         }
     }
 
src/Module.zig
@@ -663,7 +663,7 @@ pub const Decl = struct {
         return (try decl.typedValue()).val;
     }
 
-    pub fn isFunction(decl: *Decl) !bool {
+    pub fn isFunction(decl: Decl) !bool {
         const tv = try decl.typedValue();
         return tv.ty.zigTypeTag() == .Fn;
     }
src/zig_llvm.cpp
@@ -842,7 +842,7 @@ ZigLLVMDIGlobalVariable *ZigLLVMCreateGlobalVariable(ZigLLVMDIBuilder *dbuilder,
         line_no,
         reinterpret_cast<DIType*>(di_type),
         is_local_to_unit);
-    return reinterpret_cast<ZigLLVMDIGlobalVariable*>(result);
+    return reinterpret_cast<ZigLLVMDIGlobalVariable*>(result->getVariable());
 }
 
 ZigLLVMDILocalVariable *ZigLLVMCreateParameterVariable(ZigLLVMDIBuilder *dbuilder,
@@ -887,6 +887,56 @@ ZigLLVMDIScope *ZigLLVMTypeToScope(ZigLLVMDIType *type) {
     return reinterpret_cast<ZigLLVMDIScope*>(scope);
 }
 
+ZigLLVMDINode *ZigLLVMLexicalBlockToNode(ZigLLVMDILexicalBlock *lexical_block) {
+    DINode *node = reinterpret_cast<DILexicalBlock*>(lexical_block);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMCompileUnitToNode(ZigLLVMDICompileUnit *compile_unit) {
+    DINode *node = reinterpret_cast<DICompileUnit*>(compile_unit);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMFileToNode(ZigLLVMDIFile *difile) {
+    DINode *node = reinterpret_cast<DIFile*>(difile);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMSubprogramToNode(ZigLLVMDISubprogram *subprogram) {
+    DINode *node = reinterpret_cast<DISubprogram*>(subprogram);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMTypeToNode(ZigLLVMDIType *type) {
+    DINode *node = reinterpret_cast<DIType*>(type);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMScopeToNode(ZigLLVMDIScope *scope) {
+    DINode *node = reinterpret_cast<DIScope*>(scope);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+ZigLLVMDINode *ZigLLVMGlobalVariableToNode(ZigLLVMDIGlobalVariable *global_variable) {
+    DINode *node = reinterpret_cast<DIGlobalVariable*>(global_variable);
+    return reinterpret_cast<ZigLLVMDINode*>(node);
+}
+
+void ZigLLVMSubprogramReplaceLinkageName(ZigLLVMDISubprogram *subprogram,
+        ZigLLVMMDString *linkage_name)
+{
+    MDString *linkage_name_md = reinterpret_cast<MDString*>(linkage_name);
+    reinterpret_cast<DISubprogram*>(subprogram)->replaceLinkageName(linkage_name_md);
+}
+
+void ZigLLVMGlobalVariableReplaceLinkageName(ZigLLVMDIGlobalVariable *global_variable,
+        ZigLLVMMDString *linkage_name)
+{
+    Metadata *linkage_name_md = reinterpret_cast<MDString*>(linkage_name);
+    // NOTE: Operand index must match llvm::DIGlobalVariable
+    reinterpret_cast<DIGlobalVariable*>(global_variable)->replaceOperandWith(5, linkage_name_md);
+}
+
 ZigLLVMDICompileUnit *ZigLLVMCreateCompileUnit(ZigLLVMDIBuilder *dibuilder,
         unsigned lang, ZigLLVMDIFile *difile, const char *producer,
         bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name,
src/zig_llvm.h
@@ -38,6 +38,8 @@ struct ZigLLVMDIGlobalVariable;
 struct ZigLLVMDILocation;
 struct ZigLLVMDIEnumerator;
 struct ZigLLVMInsertionPoint;
+struct ZigLLVMDINode;
+struct ZigLLVMMDString;
 
 ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
 ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
@@ -238,6 +240,19 @@ ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMFileToScope(struct ZigLLVMDIFile *dif
 ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMSubprogramToScope(struct ZigLLVMDISubprogram *subprogram);
 ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMTypeToScope(struct ZigLLVMDIType *type);
 
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMLexicalBlockToNode(struct ZigLLVMDILexicalBlock *lexical_block);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMCompileUnitToNode(struct ZigLLVMDICompileUnit *compile_unit);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMFileToNode(struct ZigLLVMDIFile *difile);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMSubprogramToNode(struct ZigLLVMDISubprogram *subprogram);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMTypeToNode(struct ZigLLVMDIType *type);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMScopeToNode(struct ZigLLVMDIScope *scope);
+ZIG_EXTERN_C struct ZigLLVMDINode *ZigLLVMGlobalVariableToNode(struct ZigLLVMDIGlobalVariable *global_variable);
+
+ZIG_EXTERN_C void ZigLLVMSubprogramReplaceLinkageName(struct ZigLLVMDISubprogram *subprogram,
+        struct ZigLLVMMDString *linkage_name);
+ZIG_EXTERN_C void ZigLLVMGlobalVariableReplaceLinkageName(struct ZigLLVMDIGlobalVariable *global_variable,
+        struct ZigLLVMMDString *linkage_name);
+
 ZIG_EXTERN_C struct ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(struct ZigLLVMDIBuilder *dbuilder,
         struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_no,
         struct ZigLLVMDIType *type, bool always_preserve, unsigned flags);