LLVM: add DISubprogram and DIType lowering; handle dbg_stmt

This commit is contained in:
Andrew Kelley 2022-03-07 19:54:35 -07:00
parent 627209253c
commit 0d24bc7da0
3 changed files with 589 additions and 32 deletions

View File

@ -226,6 +226,21 @@ pub const LNCT = struct {
pub const hi_user = 0x3fff;
};
pub const CC = enum(u8) {
normal = 0x1,
program = 0x2,
nocall = 0x3,
pass_by_reference = 0x4,
pass_by_value = 0x5,
lo_user = 0x40,
hi_user = 0xff,
GNU_renesas_sh = 0x40,
GNU_borland_fastcall_i386 = 0x41,
};
const PcRange = struct {
start: u64,
end: u64,

View File

@ -161,7 +161,12 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
pub const Object = struct {
llvm_module: *const llvm.Module,
dibuilder: ?*llvm.DIBuilder,
di_builder: ?*llvm.DIBuilder,
/// One of these mappings:
/// - *Module.File => *DIFile
/// - *Module.Decl => *DISubprogram
di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DIScope),
di_compile_unit: ?*llvm.DICompileUnit,
context: *const llvm.Context,
target_machine: *const llvm.TargetMachine,
target_data: *const llvm.TargetData,
@ -224,16 +229,18 @@ pub const Object = struct {
}
llvm_module.setTarget(llvm_target_triple.ptr);
var opt_dbuilder: ?*llvm.DIBuilder = null;
errdefer if (opt_dbuilder) |dibuilder| dibuilder.dispose();
var opt_di_builder: ?*llvm.DIBuilder = null;
errdefer if (opt_di_builder) |di_builder| di_builder.dispose();
var di_compile_unit: ?*llvm.DICompileUnit = null;
if (!options.strip) {
switch (options.object_format) {
.coff => llvm_module.addModuleCodeViewFlag(),
else => llvm_module.addModuleDebugInfoFlag(),
}
const dibuilder = llvm_module.createDIBuilder(true);
opt_dbuilder = dibuilder;
const di_builder = llvm_module.createDIBuilder(true);
opt_di_builder = di_builder;
// Don't use the version string here; LLVM misparses it when it
// includes the git revision.
@ -262,9 +269,9 @@ pub const Object = struct {
const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);
defer gpa.free(compile_unit_dir_z);
_ = dibuilder.createCompileUnit(
di_compile_unit = di_builder.createCompileUnit(
DW.LANG.C99,
dibuilder.createFile(options.root_name, compile_unit_dir_z),
di_builder.createFile(options.root_name, compile_unit_dir_z),
producer,
options.optimize_mode != .Debug,
"", // flags
@ -320,7 +327,9 @@ pub const Object = struct {
return Object{
.llvm_module = llvm_module,
.dibuilder = opt_dbuilder,
.di_map = .{},
.di_builder = opt_di_builder,
.di_compile_unit = di_compile_unit,
.context = context,
.target_machine = target_machine,
.target_data = target_data,
@ -332,7 +341,10 @@ pub const Object = struct {
}
pub fn deinit(self: *Object, gpa: Allocator) void {
if (self.dibuilder) |dib| dib.dispose();
if (self.di_builder) |dib| {
dib.dispose();
self.di_map.deinit(gpa);
}
self.target_data.dispose();
self.target_machine.dispose();
self.llvm_module.dispose();
@ -413,6 +425,9 @@ pub const Object = struct {
pub fn flushModule(self: *Object, comp: *Compilation) !void {
try self.genErrorNameTable(comp);
if (self.di_builder) |dib| dib.finalize();
if (comp.verbose_llvm_ir) {
self.llvm_module.dump();
}
@ -526,8 +541,9 @@ pub const Object = struct {
const target = dg.module.getTarget();
const sret = firstParamSRet(fn_info, target);
const ret_ptr = if (sret) llvm_func.getParam(0) else null;
const gpa = dg.gpa;
var args = std.ArrayList(*const llvm.Value).init(dg.gpa);
var args = std.ArrayList(*const llvm.Value).init(gpa);
defer args.deinit();
const param_offset: c_uint = @boolToInt(ret_ptr != null);
@ -538,8 +554,53 @@ pub const Object = struct {
try args.append(llvm_func.getParam(llvm_arg_i));
}
var di_file: ?*llvm.DIFile = null;
var di_scope: ?*llvm.DIScope = null;
if (dg.object.di_builder) |dib| {
di_file = s: {
const file = decl.src_namespace.file_scope;
const gop = try dg.object.di_map.getOrPut(gpa, file);
if (!gop.found_existing) {
const dir_path = file.pkg.root_src_directory.path orelse ".";
const sub_file_path_z = try gpa.dupeZ(u8, file.sub_file_path);
defer gpa.free(sub_file_path_z);
const dir_path_z = try gpa.dupeZ(u8, dir_path);
defer gpa.free(dir_path_z);
gop.value_ptr.* = dib.createFile(sub_file_path_z, dir_path_z).toScope();
}
break :s @ptrCast(*llvm.DIFile, gop.value_ptr.*);
};
const line_number = decl.src_line + 1;
const is_internal_linkage = decl.val.tag() != .extern_fn and
!dg.module.decl_exports.contains(decl);
const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
llvm.DIFlags.NoReturn
else
0;
const subprogram = dib.createFunction(
di_file.?.toScope(),
decl.name,
llvm_func.getValueName(),
di_file.?,
line_number,
try dg.lowerDebugType(decl.ty),
is_internal_linkage,
true, // is definition
line_number + func.lbrace_line, // scope line
llvm.DIFlags.StaticMember | noret_bit,
dg.module.comp.bin_file.options.optimize_mode != .Debug,
null, // decl_subprogram
);
llvm_func.fnSetSubprogram(subprogram);
di_scope = subprogram.toScope();
}
var fg: FuncGen = .{
.gpa = dg.gpa,
.gpa = gpa,
.air = air,
.liveness = liveness,
.context = dg.context,
@ -552,6 +613,8 @@ pub const Object = struct {
.llvm_func = llvm_func,
.blocks = .{},
.single_threaded = module.comp.bin_file.options.single_threaded,
.di_scope = di_scope,
.di_file = di_file,
};
defer fg.deinit();
@ -1827,6 +1890,418 @@ pub const DeclGen = struct {
}
}
fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {
const gpa = dg.gpa;
const target = dg.module.getTarget();
const dib = dg.object.di_builder.?;
switch (ty.zigTypeTag()) {
.Void, .NoReturn => return dib.createBasicType("void", 0, DW.ATE.signed),
.Int => {
const info = ty.intInfo(target);
assert(info.bits != 0);
const name = try ty.nameAlloc(gpa); // TODO this is a leak
const dwarf_encoding: c_uint = switch (info.signedness) {
.signed => DW.ATE.signed,
.unsigned => DW.ATE.unsigned,
};
return dib.createBasicType(name, info.bits, dwarf_encoding);
},
.Enum => {
@panic("TODO debug info type for enums");
//var buffer: Type.Payload.Bits = undefined;
//const int_ty = ty.intTagType(&buffer);
//const bit_count = int_ty.intInfo(target).bits;
//assert(bit_count != 0);
//return dg.context.intType(bit_count);
},
.Float => {
const bits = ty.floatBits(target);
const name = try ty.nameAlloc(gpa); // TODO this is a leak
return dib.createBasicType(name, bits, DW.ATE.float);
},
.Bool => return dib.createBasicType("bool", 1, DW.ATE.boolean),
.Pointer => {
if (ty.isSlice()) {
@panic("TODO debug info type for slices");
//var buf: Type.SlicePtrFieldTypeBuffer = undefined;
//const ptr_type = ty.slicePtrFieldType(&buf);
//const fields: [2]*const llvm.Type = .{
// try dg.llvmType(ptr_type),
// try dg.llvmType(Type.usize),
//};
//return dg.context.structType(&fields, fields.len, .False);
}
const ptr_info = ty.ptrInfo().data;
const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
const name = try ty.nameAlloc(gpa); // TODO this is a leak
return dib.createPointerType(
elem_di_ty,
target.cpu.arch.ptrBitWidth(),
ty.ptrAlignment(target) * 8,
name,
);
},
.Opaque => {
@panic("TODO debug info type for opaque");
},
.Array => {
const elem_di_ty = try lowerDebugType(dg, ty.childType());
return dib.createArrayType(
ty.abiSize(target) * 8,
ty.abiAlignment(target) * 8,
elem_di_ty,
@intCast(c_int, ty.arrayLen()),
);
},
.Vector => {
@panic("TODO debug info type for vector");
},
.Optional => {
@panic("TODO debug info type for optional");
//var buf: Type.Payload.ElemType = undefined;
//const child_type = ty.optionalChild(&buf);
//if (!child_type.hasRuntimeBits()) {
// return dg.context.intType(1);
//}
//const payload_llvm_ty = try dg.llvmType(child_type);
//if (ty.isPtrLikeOptional()) {
// return payload_llvm_ty;
//} else if (!child_type.hasRuntimeBits()) {
// return dg.context.intType(1);
//}
//const fields: [2]*const llvm.Type = .{
// payload_llvm_ty, dg.context.intType(1),
//};
//return dg.context.structType(&fields, fields.len, .False);
},
.ErrorUnion => {
const err_set_ty = ty.errorUnionSet();
const err_set_di_ty = try dg.lowerDebugType(err_set_ty);
const payload_ty = ty.errorUnionPayload();
if (!payload_ty.hasRuntimeBits()) {
return err_set_di_ty;
}
const payload_di_ty = try dg.lowerDebugType(payload_ty);
const name = try ty.nameAlloc(gpa); // TODO this is a leak
const di_file: ?*llvm.DIFile = null;
const line = 0;
const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
const fwd_decl = dib.createReplaceableCompositeType(
DW.TAG.structure_type,
name.ptr,
compile_unit_scope,
di_file,
line,
);
const err_set_size = err_set_ty.abiSize(target);
const err_set_align = err_set_ty.abiAlignment(target);
const payload_size = payload_ty.abiSize(target);
const payload_align = payload_ty.abiAlignment(target);
var offset: u64 = 0;
offset += err_set_size;
offset = std.mem.alignForwardGeneric(u64, offset, payload_align);
const payload_offset = offset;
const fields: [2]*llvm.DIType = .{
dib.createMemberType(
fwd_decl.toScope(),
"tag",
di_file,
line,
err_set_size * 8, // size in bits
err_set_align * 8, // align in bits
0, // offset in bits
0, // flags
err_set_di_ty,
),
dib.createMemberType(
fwd_decl.toScope(),
"value",
di_file,
line,
payload_size * 8, // size in bits
payload_align * 8, // align in bits
payload_offset * 8, // offset in bits
0, // flags
payload_di_ty,
),
};
const replacement_di_type = dib.createStructType(
compile_unit_scope,
name.ptr,
di_file,
line,
ty.abiSize(target) * 8, // size in bits
ty.abiAlignment(target) * 8, // align in bits
0, // flags
null, // derived from
&fields,
fields.len,
0, // run time lang
null, // vtable holder
"", // unique id
);
dib.replaceTemporary(fwd_decl, replacement_di_type);
return replacement_di_type;
},
.ErrorSet => {
// TODO make this a proper enum with all the error codes in it.
// will need to consider how to take incremental compilation into account.
return dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
},
.Struct => {
@panic("TODO debug info type for struct");
//const gop = try dg.object.type_map.getOrPut(gpa, ty);
//if (gop.found_existing) return gop.value_ptr.*;
//// The Type memory is ephemeral; since we want to store a longer-lived
//// reference, we need to copy it here.
//gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
//if (ty.isTupleOrAnonStruct()) {
// const tuple = ty.tupleFields();
// const llvm_struct_ty = dg.context.structCreateNamed("");
// gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
// var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
// defer llvm_field_types.deinit(gpa);
// try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
// comptime assert(struct_layout_version == 2);
// var offset: u64 = 0;
// var big_align: u32 = 0;
// for (tuple.types) |field_ty, i| {
// const field_val = tuple.values[i];
// if (field_val.tag() != .unreachable_value) continue;
// const field_align = field_ty.abiAlignment(target);
// big_align = @maximum(big_align, field_align);
// const prev_offset = offset;
// offset = std.mem.alignForwardGeneric(u64, offset, field_align);
// const padding_len = offset - prev_offset;
// if (padding_len > 0) {
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
// try llvm_field_types.append(gpa, llvm_array_ty);
// }
// const field_llvm_ty = try dg.llvmType(field_ty);
// try llvm_field_types.append(gpa, field_llvm_ty);
// offset += field_ty.abiSize(target);
// }
// {
// const prev_offset = offset;
// offset = std.mem.alignForwardGeneric(u64, offset, big_align);
// const padding_len = offset - prev_offset;
// if (padding_len > 0) {
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
// try llvm_field_types.append(gpa, llvm_array_ty);
// }
// }
// llvm_struct_ty.structSetBody(
// llvm_field_types.items.ptr,
// @intCast(c_uint, llvm_field_types.items.len),
// .False,
// );
// return llvm_struct_ty;
//}
//const struct_obj = ty.castTag(.@"struct").?.data;
//if (struct_obj.layout == .Packed) {
// var buf: Type.Payload.Bits = undefined;
// const int_ty = struct_obj.packedIntegerType(target, &buf);
// const int_llvm_ty = try dg.llvmType(int_ty);
// gop.value_ptr.* = int_llvm_ty;
// return int_llvm_ty;
//}
//const name = try struct_obj.getFullyQualifiedName(gpa);
//defer gpa.free(name);
//const llvm_struct_ty = dg.context.structCreateNamed(name);
//gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
//assert(struct_obj.haveFieldTypes());
//var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
//defer llvm_field_types.deinit(gpa);
//try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count());
//comptime assert(struct_layout_version == 2);
//var offset: u64 = 0;
//var big_align: u32 = 0;
//for (struct_obj.fields.values()) |field| {
// if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
// const field_align = field.normalAlignment(target);
// big_align = @maximum(big_align, field_align);
// const prev_offset = offset;
// offset = std.mem.alignForwardGeneric(u64, offset, field_align);
// const padding_len = offset - prev_offset;
// if (padding_len > 0) {
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
// try llvm_field_types.append(gpa, llvm_array_ty);
// }
// const field_llvm_ty = try dg.llvmType(field.ty);
// try llvm_field_types.append(gpa, field_llvm_ty);
// offset += field.ty.abiSize(target);
//}
//{
// const prev_offset = offset;
// offset = std.mem.alignForwardGeneric(u64, offset, big_align);
// const padding_len = offset - prev_offset;
// if (padding_len > 0) {
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
// try llvm_field_types.append(gpa, llvm_array_ty);
// }
//}
//llvm_struct_ty.structSetBody(
// llvm_field_types.items.ptr,
// @intCast(c_uint, llvm_field_types.items.len),
// .False,
//);
//return llvm_struct_ty;
},
.Union => {
@panic("TODO debug info type for union");
//const gop = try dg.object.type_map.getOrPut(gpa, ty);
//if (gop.found_existing) return gop.value_ptr.*;
//// The Type memory is ephemeral; since we want to store a longer-lived
//// reference, we need to copy it here.
//gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
//const layout = ty.unionGetLayout(target);
//const union_obj = ty.cast(Type.Payload.Union).?.data;
//if (layout.payload_size == 0) {
// const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
// gop.value_ptr.* = enum_tag_llvm_ty;
// return enum_tag_llvm_ty;
//}
//const name = try union_obj.getFullyQualifiedName(gpa);
//defer gpa.free(name);
//const llvm_union_ty = dg.context.structCreateNamed(name);
//gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
//const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
//const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);
//const llvm_payload_ty = ty: {
// if (layout.most_aligned_field_size == layout.payload_size) {
// break :ty llvm_aligned_field_ty;
// }
// const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
// const fields: [2]*const llvm.Type = .{
// llvm_aligned_field_ty,
// dg.context.intType(8).arrayType(padding_len),
// };
// break :ty dg.context.structType(&fields, fields.len, .True);
//};
//if (layout.tag_size == 0) {
// var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty};
// llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
// return llvm_union_ty;
//}
//const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
//// Put the tag before or after the payload depending on which one's
//// alignment is greater.
//var llvm_fields: [3]*const llvm.Type = undefined;
//var llvm_fields_len: c_uint = 2;
//if (layout.tag_align >= layout.payload_align) {
// llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
//} else {
// llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
//}
//// Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
//if (layout.padding != 0) {
// llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding);
// llvm_fields_len = 3;
//}
//llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
//return llvm_union_ty;
},
.Fn => {
const fn_info = ty.fnInfo();
const sret = firstParamSRet(fn_info, target);
var param_di_types = std.ArrayList(*llvm.DIType).init(dg.gpa);
defer param_di_types.deinit();
// Return type goes first.
const di_ret_ty = if (sret) Type.void else fn_info.return_type;
try param_di_types.append(try dg.lowerDebugType(di_ret_ty));
if (sret) {
var ptr_ty_payload: Type.Payload.ElemType = .{
.base = .{ .tag = .single_mut_pointer },
.data = fn_info.return_type,
};
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
try param_di_types.append(try dg.lowerDebugType(ptr_ty));
}
for (fn_info.param_types) |param_ty| {
if (!param_ty.hasRuntimeBits()) continue;
if (isByRef(param_ty)) {
var ptr_ty_payload: Type.Payload.ElemType = .{
.base = .{ .tag = .single_mut_pointer },
.data = param_ty,
};
const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
try param_di_types.append(try dg.lowerDebugType(ptr_ty));
} else {
try param_di_types.append(try dg.lowerDebugType(param_ty));
}
}
return dib.createSubroutineType(
param_di_types.items.ptr,
@intCast(c_int, param_di_types.items.len),
0,
);
},
.ComptimeInt => unreachable,
.ComptimeFloat => unreachable,
.Type => unreachable,
.Undefined => unreachable,
.Null => unreachable,
.EnumLiteral => unreachable,
.BoundFn => @panic("TODO remove BoundFn from the language"),
.Frame => @panic("TODO implement lowerDebugType for Frame types"),
.AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"),
}
}
const ParentPtr = struct {
ty: Type,
llvm_ptr: *const llvm.Value,
@ -2141,6 +2616,8 @@ pub const FuncGen = struct {
liveness: Liveness,
context: *const llvm.Context,
builder: *const llvm.Builder,
di_scope: ?*llvm.DIScope,
di_file: ?*llvm.DIFile,
/// 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.
@ -2156,7 +2633,7 @@ pub const FuncGen = struct {
/// it omits 0-bit types. If the function uses sret as the first parameter,
/// this slice does not include it.
args: []const *const llvm.Value,
arg_index: usize,
arg_index: c_uint,
llvm_func: *const llvm.Value,
@ -2386,10 +2863,7 @@ pub const FuncGen = struct {
.constant => unreachable,
.const_ty => unreachable,
.unreach => self.airUnreach(inst),
.dbg_stmt => blk: {
// TODO: implement debug info
break :blk null;
},
.dbg_stmt => self.airDbgStmt(inst),
// zig fmt: on
};
if (opt_value) |val| {
@ -3099,6 +3573,17 @@ pub const FuncGen = struct {
return null;
}
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.builder.setCurrentDebugLocation(
@intCast(c_int, dbg_stmt.line + 1),
@intCast(c_int, dbg_stmt.column + 1),
di_scope,
);
return null;
}
fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
// Eventually, the Zig compiler needs to be reworked to have inline assembly go
// through the same parsing code regardless of backend, and have LLVM-flavored
@ -4299,15 +4784,31 @@ pub const FuncGen = struct {
self.arg_index += 1;
const inst_ty = self.air.typeOfIndex(inst);
if (isByRef(inst_ty)) {
// TODO declare debug variable
return arg_val;
} else {
const ptr_val = self.buildAlloca(try self.dg.llvmType(inst_ty));
_ = self.builder.buildStore(arg_val, ptr_val);
// TODO declare debug variable
return arg_val;
const result = r: {
if (isByRef(inst_ty)) {
break :r arg_val;
} else {
const ptr_val = self.buildAlloca(try self.dg.llvmType(inst_ty));
_ = self.builder.buildStore(arg_val, ptr_val);
break :r arg_val;
}
};
if (self.dg.object.di_builder) |dib| {
const func = self.dg.decl.getFunction().?;
_ = dib.createParameterVariable(
self.di_scope.?,
func.getParamName(self.arg_index - 1).ptr, // TODO test 0 bit args
self.di_file.?,
func.owner_decl.src_line + func.lbrace_line + 1,
try self.dg.lowerDebugType(inst_ty),
true, // always preserve
0, // flags
self.arg_index, // includes +1 because 0 is return type
);
}
return result;
}
fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@ -4830,7 +5331,7 @@ pub const FuncGen = struct {
const prev_debug_location = self.builder.getCurrentDebugLocation2();
defer {
self.builder.positionBuilderAtEnd(prev_block);
if (!self.dg.module.comp.bin_file.options.strip) {
if (self.di_scope != null) {
self.builder.setCurrentDebugLocation2(prev_debug_location);
}
}

View File

@ -193,6 +193,9 @@ pub const Value = opaque {
pub const setValueName2 = LLVMSetValueName2;
extern fn LLVMSetValueName2(Val: *const Value, Name: [*]const u8, NameLen: usize) void;
pub const getValueName = LLVMGetValueName;
extern fn LLVMGetValueName(Val: *const Value) [*:0]const u8;
pub const takeName = ZigLLVMTakeName;
extern fn ZigLLVMTakeName(new_owner: *const Value, victim: *const Value) void;
@ -836,7 +839,7 @@ 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 zigSetCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void;
pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
@ -1505,16 +1508,16 @@ pub const DIBuilder = opaque {
dib: *DIBuilder,
scope: *DIScope,
name: [*:0]const u8,
file: *DIFile,
file: ?*DIFile,
line_number: c_uint,
size_in_bits: u64,
align_in_bits: u64,
flags: c_uint,
derived_from: *DIType,
derived_from: ?*DIType,
types_array: [*]const *DIType,
types_array_len: c_int,
run_time_lang: c_uint,
vtable_holder: *DIType,
vtable_holder: ?*DIType,
unique_id: [*:0]const u8,
) *DIType;
@ -1539,7 +1542,7 @@ pub const DIBuilder = opaque {
dib: *DIBuilder,
scope: *DIScope,
name: [*:0]const u8,
file: *DIFile,
file: ?*DIFile,
line: c_uint,
size_in_bits: u64,
align_in_bits: u64,
@ -1554,7 +1557,7 @@ pub const DIBuilder = opaque {
tag: c_uint,
name: [*:0]const u8,
scope: *DIScope,
file: *DIFile,
file: ?*DIFile,
line: c_uint,
) *DIType;
@ -1668,7 +1671,7 @@ pub const DIBuilder = opaque {
scope_line: c_uint,
flags: c_uint,
is_optimized: bool,
decl_subprogram: *DISubprogram,
decl_subprogram: ?*DISubprogram,
) *DISubprogram;
pub const createVectorType = ZigLLVMDIBuilderCreateVectorType;
@ -1698,3 +1701,41 @@ pub const DIBuilder = opaque {
insert_before_instr: *const Value,
) *const Value;
};
pub const DIFlags = opaque {
pub const Zero = 0;
pub const Private = 1;
pub const Protected = 2;
pub const Public = 3;
pub const FwdDecl = 1 << 2;
pub const AppleBlock = 1 << 3;
pub const BlockByrefStruct = 1 << 4;
pub const Virtual = 1 << 5;
pub const Artificial = 1 << 6;
pub const Explicit = 1 << 7;
pub const Prototyped = 1 << 8;
pub const ObjcClassComplete = 1 << 9;
pub const ObjectPointer = 1 << 10;
pub const Vector = 1 << 11;
pub const StaticMember = 1 << 12;
pub const LValueReference = 1 << 13;
pub const RValueReference = 1 << 14;
pub const Reserved = 1 << 15;
pub const SingleInheritance = 1 << 16;
pub const MultipleInheritance = 2 << 16;
pub const VirtualInheritance = 3 << 16;
pub const IntroducedVirtual = 1 << 18;
pub const BitField = 1 << 19;
pub const NoReturn = 1 << 20;
pub const TypePassByValue = 1 << 22;
pub const TypePassByReference = 1 << 23;
pub const EnumClass = 1 << 24;
pub const Thunk = 1 << 25;
pub const NonTrivial = 1 << 26;
pub const BigEndian = 1 << 27;
pub const LittleEndian = 1 << 28;
pub const AllCallsDescribed = 1 << 29;
};