stage2 llvm: keep track of inlined functions

This commit is contained in:
Veikka Tuominen 2022-03-15 18:27:09 +02:00
parent 0343811836
commit d83a26f068
14 changed files with 133 additions and 47 deletions

View File

@ -326,9 +326,12 @@ pub const Inst = struct {
/// Result type is always void.
/// Uses the `dbg_stmt` field.
dbg_stmt,
/// Marks change of source function. Emitted around an inline call.
/// Marks the start of an inline call.
/// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
dbg_func,
dbg_inline_begin,
/// Marks the end of an inline call.
/// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
dbg_inline_end,
/// Marks the beginning of a local variable. The operand is a pointer pointing
/// to the storage for the variable. The local may be a const or a var.
/// Result type is always void.
@ -973,7 +976,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.breakpoint,
.dbg_stmt,
.dbg_func,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
.dbg_var_val,
.store,

View File

@ -314,7 +314,8 @@ fn analyzeInst(
.const_ty,
.breakpoint,
.dbg_stmt,
.dbg_func,
.dbg_inline_begin,
.dbg_inline_end,
.unreach,
.fence,
.ret_addr,

View File

@ -4765,7 +4765,9 @@ fn analyzeCall(
}
const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
if (!is_comptime_call) try sema.emitDbgFunc(block, parent_func.?, module_fn, new_func_resolved_ty);
if (!is_comptime_call) {
try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
}
const result = result: {
sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
@ -4781,7 +4783,9 @@ fn analyzeCall(
break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
};
if (!is_comptime_call) try sema.emitDbgFunc(block, module_fn, parent_func.?, parent_func.?.owner_decl.ty);
if (!is_comptime_call) {
try sema.emitDbgInline(block, module_fn, parent_func.?, parent_func.?.owner_decl.ty, .dbg_inline_end);
}
if (should_memoize and is_comptime_call) {
const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result);
@ -5187,19 +5191,20 @@ fn instantiateGenericCall(
return func_inst;
}
fn emitDbgFunc(
fn emitDbgInline(
sema: *Sema,
block: *Block,
old_func: *Module.Fn,
new_func: *Module.Fn,
new_func_ty: Type,
tag: Air.Inst.Tag,
) CompileError!void {
// No change of file; no dbg_func needed.
// No change of file; no dbg_inline needed.
if (old_func == new_func) return;
try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func));
_ = try block.addInst(.{
.tag = .dbg_func,
.tag = tag,
.data = .{ .ty_pl = .{
.ty = try sema.addType(new_func_ty),
.payload = @intCast(u32, sema.air_values.items.len - 1),

View File

@ -598,7 +598,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_func => try self.airDbgFunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
@ -650,6 +649,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
@ -2716,7 +2719,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}
fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change

View File

@ -595,7 +595,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_func => try self.airDbgFunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
@ -647,6 +646,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
@ -2836,7 +2839,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}
fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change

View File

@ -562,7 +562,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_func => try self.airDbgFunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
@ -614,6 +613,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
@ -1641,7 +1644,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}
fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change

View File

@ -1227,7 +1227,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
// TODO
.dbg_stmt,
.dbg_func,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
.dbg_var_val,
=> WValue.none,

View File

@ -679,7 +679,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.fence => try self.airFence(),
.cond_br => try self.airCondBr(inst),
.dbg_stmt => try self.airDbgStmt(inst),
.dbg_func => try self.airDbgFunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.intcast => try self.airIntCast(inst),
@ -731,6 +730,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),
.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
@ -3671,7 +3674,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}
fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void {
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change

View File

@ -1687,7 +1687,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.block => try airBlock(f, inst),
.bitcast => try airBitcast(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
.dbg_func => try airDbgFunc(f, inst),
.intcast => try airIntCast(f, inst),
.trunc => try airTrunc(f, inst),
.bool_to_int => try airBoolToInt(f, inst),
@ -1727,6 +1726,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.dbg_var_val,
=> try airDbgVar(f, inst),
.dbg_inline_begin,
.dbg_inline_end,
=> try airDbgInline(f, inst),
.call => try airCall(f, inst, .auto),
.call_always_tail => try airCall(f, inst, .always_tail),
.call_never_tail => try airCall(f, inst, .never_tail),
@ -2661,7 +2664,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue.none;
}
fn airDbgFunc(f: *Function, inst: Air.Inst.Index) !CValue {
fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const writer = f.object.writer();
const function = f.air.values[ty_pl.payload].castTag(.function).?.data;

View File

@ -620,7 +620,8 @@ pub const Object = struct {
llvm_func.fnSetSubprogram(subprogram);
di_scope = subprogram.toScope();
const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file.?, line_number, 1);
di_scope = lexical_block.toScope();
}
var fg: FuncGen = .{
@ -639,6 +640,7 @@ pub const Object = struct {
.single_threaded = module.comp.bin_file.options.single_threaded,
.di_scope = di_scope,
.di_file = di_file,
.base_line = dg.decl.src_line,
.prev_dbg_line = 0,
.prev_dbg_column = 0,
};
@ -3210,9 +3212,13 @@ pub const FuncGen = struct {
builder: *const llvm.Builder,
di_scope: ?*llvm.DIScope,
di_file: ?*llvm.DIFile,
base_line: u32,
prev_dbg_line: c_uint,
prev_dbg_column: c_uint,
/// Stack of locations where a call was inlined.
dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
/// This stores the LLVM values used in a function, such that they can be referred to
/// in other instructions. This table is cleared before every function is generated.
func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *const llvm.Value),
@ -3240,11 +3246,13 @@ pub const FuncGen = struct {
single_threaded: bool,
const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
fn deinit(self: *FuncGen) void {
self.builder.dispose();
self.dbg_inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
}
@ -3463,7 +3471,8 @@ pub const FuncGen = struct {
.const_ty => unreachable,
.unreach => self.airUnreach(inst),
.dbg_stmt => self.airDbgStmt(inst),
.dbg_func => try self.airDbgFunc(inst),
.dbg_inline_begin => try self.airDbgInline(inst, true),
.dbg_inline_end => try self.airDbgInline(inst, false),
.dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst),
// zig fmt: on
@ -4179,24 +4188,44 @@ pub const FuncGen = struct {
fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value {
const di_scope = self.di_scope orelse return null;
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
self.prev_dbg_line = @intCast(c_uint, self.dg.decl.src_line + dbg_stmt.line + 1);
self.prev_dbg_line = @intCast(c_uint, self.base_line + dbg_stmt.line + 1);
self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1);
self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope);
const inlined_at = if (self.dbg_inlined.items.len > 0)
self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
else
null;
self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
return null;
}
fn airDbgFunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
fn airDbgInline(self: *FuncGen, inst: Air.Inst.Index, start: bool) !?*const llvm.Value {
const dib = self.dg.object.di_builder orelse return null;
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
const decl = function.owner_decl;
const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator());
const llvm_func = try self.dg.resolveLlvmFunctionExtra(decl, fn_ty);
const fn_info = fn_ty.fnInfo();
const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
const func = self.air.values[ty_pl.payload].castTag(.function).?.data;
const decl = func.owner_decl;
const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
self.di_file = di_file;
const line_number = decl.src_line + 1;
const cur_debug_location = self.builder.getCurrentDebugLocation2();
if (start) {
try self.dbg_inlined.append(self.gpa, .{
.loc = @ptrCast(*llvm.DILocation, cur_debug_location),
.scope = self.di_scope.?,
.base_line = self.base_line,
});
} else {
const old = self.dbg_inlined.pop();
self.di_scope = old.scope;
self.base_line = old.base_line;
return null;
}
const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator());
const fqn = try decl.getFullyQualifiedName(self.gpa);
defer self.gpa.free(fqn);
const fn_info = fn_ty.fnInfo();
const is_internal_linkage = !self.dg.module.decl_exports.contains(decl);
const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
llvm.DIFlags.NoReturn
@ -4205,22 +4234,23 @@ pub const FuncGen = struct {
const subprogram = dib.createFunction(
di_file.toScope(),
decl.name,
llvm_func.getValueName(),
fqn,
di_file,
line_number,
try self.dg.lowerDebugType(fn_ty),
try self.dg.object.lowerDebugType(fn_ty, .full),
is_internal_linkage,
true, // is definition
line_number + function.lbrace_line, // scope line
line_number + func.lbrace_line, // scope line
llvm.DIFlags.StaticMember | noret_bit,
self.dg.module.comp.bin_file.options.optimize_mode != .Debug,
null, // decl_subprogram
);
try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode());
llvm_func.fnSetSubprogram(subprogram);
self.di_scope = subprogram.toScope();
const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
self.di_scope = lexical_block.toScope();
self.base_line = decl.src_line;
return null;
}
@ -4240,7 +4270,11 @@ pub const FuncGen = struct {
true, // always preserve
0, // flags
);
const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);
const inlined_at = if (self.dbg_inlined.items.len > 0)
self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
else
null;
const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
const insert_block = self.builder.getInsertBlock();
_ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
return null;
@ -4262,7 +4296,11 @@ pub const FuncGen = struct {
true, // always preserve
0, // flags
);
const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);
const inlined_at = if (self.dbg_inlined.items.len > 0)
self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
else
null;
const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
const insert_block = self.builder.getInsertBlock();
if (isByRef(operand_ty)) {
_ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
@ -5524,7 +5562,7 @@ pub const FuncGen = struct {
self.arg_index, // includes +1 because 0 is return type
);
const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?);
const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
const insert_block = self.builder.getInsertBlock();
if (isByRef(inst_ty)) {
_ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);

View File

@ -839,8 +839,8 @@ pub const Builder = opaque {
pub const buildExactSDiv = LLVMBuildExactSDiv;
extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope) void;
pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation2;
extern fn ZigLLVMSetCurrentDebugLocation2(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope, inlined_at: ?*DILocation) void;
pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;
@ -1479,8 +1479,8 @@ pub const DISubprogram = opaque {
extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void;
};
pub const getDebugLoc = ZigLLVMGetDebugLoc;
extern fn ZigLLVMGetDebugLoc(line: c_uint, col: c_uint, scope: *DIScope) *DILocation;
pub const getDebugLoc = ZigLLVMGetDebugLoc2;
extern fn ZigLLVMGetDebugLoc2(line: c_uint, col: c_uint, scope: *DIScope, inlined_at: ?*DILocation) *DILocation;
pub const DIBuilder = opaque {
pub const dispose = ZigLLVMDisposeDIBuilder;

View File

@ -242,7 +242,8 @@ const Writer = struct {
.constant => try w.writeConstant(s, inst),
.assembly => try w.writeAssembly(s, inst),
.dbg_stmt => try w.writeDbgStmt(s, inst),
.dbg_func => try w.writeDbgFunc(s, inst),
.dbg_inline_begin, .dbg_inline_end => try w.writeDbgInline(s, inst),
.aggregate_init => try w.writeAggregateInit(s, inst),
.union_init => try w.writeUnionInit(s, inst),
.br => try w.writeBr(s, inst),
@ -553,7 +554,7 @@ const Writer = struct {
try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
}
fn writeDbgFunc(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const function = w.air.values[ty_pl.payload].castTag(.function).?.data;
try s.print("{s}", .{function.owner_decl.name});

View File

@ -799,6 +799,15 @@ void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,
unwrap(builder)->SetCurrentDebugLocation(debug_loc);
}
void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at)
{
DIScope* di_scope = reinterpret_cast<DIScope*>(scope);
DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, column, di_scope,
reinterpret_cast<DILocation *>(inlined_at), false);
unwrap(builder)->SetCurrentDebugLocation(debug_loc);
}
void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder) {
unwrap(builder)->SetCurrentDebugLocation(DebugLoc());
}
@ -1025,6 +1034,14 @@ ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScop
return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get());
}
ZigLLVMDILocation *ZigLLVMGetDebugLoc2(unsigned line, unsigned col, ZigLLVMDIScope *scope,
ZigLLVMDILocation *inlined_at) {
DIScope* di_scope = reinterpret_cast<DIScope*>(scope);
DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, col, di_scope,
reinterpret_cast<DILocation *>(inlined_at), false);
return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get());
}
void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
if (on_state) {
FastMathFlags fmf;

View File

@ -232,6 +232,8 @@ ZIG_EXTERN_C void ZigLLVMSetModuleCodeModel(LLVMModuleRef module, LLVMCodeModel
ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,
unsigned int line, unsigned int column, struct ZigLLVMDIScope *scope);
ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at);
ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block);
@ -290,6 +292,8 @@ ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col,
struct ZigLLVMDIScope *scope);
ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc2(unsigned line, unsigned col,
ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at);
ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dib,
LLVMValueRef storage, struct ZigLLVMDILocalVariable *var_info,