LLVM Builder: Add debug locations to instructions

This commit is contained in:
antlilja 2024-02-19 23:04:13 +01:00
parent a456631e29
commit 049cad4411

View File

@ -3935,6 +3935,8 @@ pub const Function = struct {
names: [*]const String = &[0]String{},
value_indices: [*]const u32 = &[0]u32{},
metadata: ?[*]const Metadata = null,
debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, ?DebugLocation) = .{},
debug_values: []const Instruction.Index = &.{},
extra: []const u32 = &.{},
pub const Index = enum(u32) {
@ -5031,7 +5033,8 @@ pub const Function = struct {
pub fn deinit(self: *Function, gpa: Allocator) void {
gpa.free(self.extra);
if (self.metadata) |metadata| gpa.free(metadata[0..self.instructions.len]);
gpa.free(self.debug_values);
self.debug_locations.deinit(gpa);
gpa.free(self.value_indices[0..self.instructions.len]);
gpa.free(self.names[0..self.instructions.len]);
self.instructions.deinit(gpa);
@ -5103,6 +5106,13 @@ pub const Function = struct {
}
};
pub const DebugLocation = struct {
line: u32,
column: u32,
scope: Metadata,
inlined_at: Metadata,
};
pub const WipFunction = struct {
builder: *Builder,
function: Function.Index,
@ -5111,11 +5121,14 @@ pub const WipFunction = struct {
blocks: std.ArrayListUnmanaged(*llvm.BasicBlock),
instructions: std.ArrayListUnmanaged(*llvm.Value),
} else void,
last_debug_location: ?DebugLocation,
current_debug_location: ?DebugLocation,
cursor: Cursor,
blocks: std.ArrayListUnmanaged(Block),
instructions: std.MultiArrayList(Instruction),
names: std.ArrayListUnmanaged(String),
metadata: std.ArrayListUnmanaged(Metadata),
debug_locations: std.AutoArrayHashMapUnmanaged(Instruction.Index, ?DebugLocation),
debug_values: std.AutoArrayHashMapUnmanaged(Instruction.Index, void),
extra: std.ArrayListUnmanaged(u32),
pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 };
@ -5169,20 +5182,27 @@ pub const WipFunction = struct {
.blocks = .{},
.instructions = .{},
.names = .{},
.metadata = .{},
.debug_locations = .{},
.debug_values = .{},
.extra = .{},
.current_debug_location = null,
.last_debug_location = null,
};
errdefer self.deinit();
const params_len = function.typeOf(self.builder).functionParameters(self.builder).len;
try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
if (!self.builder.strip) {
try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
}
if (self.builder.useLibLlvm())
try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
for (0..params_len) |param_index| {
self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
if (!self.builder.strip) self.names.appendAssumeCapacity(.empty); // TODO: param names
if (!self.builder.strip) {
self.names.appendAssumeCapacity(.empty); // TODO: param names
}
if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
function.toLlvm(self.builder).getParam(@intCast(param_index)),
);
@ -6395,6 +6415,22 @@ pub const WipFunction = struct {
return instruction.toValue();
}
pub fn debugValue(self: *WipFunction, value: Value) Allocator.Error!Metadata {
if (self.builder.strip) return .none;
return switch (value.unwrap()) {
.instruction => |instr_index| blk: {
const gop = try self.debug_values.getOrPut(self.builder.gpa, instr_index);
const metadata: Metadata = @enumFromInt(Metadata.first_local_metadata + gop.index);
if (!gop.found_existing) gop.key_ptr.* = instr_index;
break :blk metadata;
},
.constant => |constant| try self.builder.debugConstant(constant),
.metadata => |metadata| metadata,
};
}
pub fn finish(self: *WipFunction) Allocator.Error!void {
const gpa = self.builder.gpa;
const function = self.function.ptr(self.builder);
@ -6426,9 +6462,12 @@ pub const WipFunction = struct {
const value_indices = try gpa.alloc(u32, final_instructions_len);
errdefer gpa.free(value_indices);
const metadata =
if (self.builder.strip) null else try gpa.alloc(Metadata, final_instructions_len);
errdefer if (metadata) |new_metadata| gpa.free(new_metadata);
var debug_locations = std.AutoHashMapUnmanaged(Instruction.Index, ?DebugLocation){};
errdefer debug_locations.deinit(gpa);
try debug_locations.ensureUnusedCapacity(gpa, @intCast(self.debug_locations.count()));
const debug_values = try gpa.alloc(Instruction.Index, self.debug_values.count());
errdefer gpa.free(debug_values);
var wip_extra: struct {
index: Instruction.ExtraIndex = 0,
@ -6482,8 +6521,10 @@ pub const WipFunction = struct {
gpa.free(function.blocks);
function.blocks = &.{};
gpa.free(function.names[0..function.instructions.len]);
if (function.metadata) |old_metadata| gpa.free(old_metadata[0..function.instructions.len]);
function.metadata = null;
function.debug_locations.deinit(gpa);
function.debug_locations = .{};
gpa.free(function.debug_values);
function.debug_values = &.{};
gpa.free(function.extra);
function.extra = &.{};
@ -6532,6 +6573,12 @@ pub const WipFunction = struct {
names[@intFromEnum(new_argument_index)] = wip_name.map(
if (self.builder.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
);
if (self.debug_locations.get(old_argument_index)) |location| {
debug_locations.putAssumeCapacity(new_argument_index, location);
}
if (self.debug_values.getIndex(old_argument_index)) |index| {
debug_values[index] = new_argument_index;
}
}
for (self.blocks.items) |current_block| {
const new_block_index: Instruction.Index = @enumFromInt(function.instructions.len);
@ -6846,6 +6893,14 @@ pub const WipFunction = struct {
else
self.names.items[@intFromEnum(old_instruction_index)]);
if (self.debug_locations.get(old_instruction_index)) |location| {
debug_locations.putAssumeCapacity(new_instruction_index, location);
}
if (self.debug_values.getIndex(old_instruction_index)) |index| {
debug_values[index] = new_instruction_index;
}
value_indices[@intFromEnum(new_instruction_index)] = value_index;
if (old_instruction_index.hasResultWip(self)) value_index += 1;
}
@ -6856,12 +6911,14 @@ pub const WipFunction = struct {
function.blocks = blocks;
function.names = names.ptr;
function.value_indices = value_indices.ptr;
function.metadata = if (metadata) |new_metadata| new_metadata.ptr else null;
function.debug_locations = debug_locations;
function.debug_values = debug_values;
}
pub fn deinit(self: *WipFunction) void {
self.extra.deinit(self.builder.gpa);
self.metadata.deinit(self.builder.gpa);
self.debug_values.deinit(self.builder.gpa);
self.debug_locations.deinit(self.builder.gpa);
self.names.deinit(self.builder.gpa);
self.instructions.deinit(self.builder.gpa);
for (self.blocks.items) |*b| b.instructions.deinit(self.builder.gpa);
@ -7137,7 +7194,16 @@ pub const WipFunction = struct {
) Allocator.Error!Instruction.Index {
const block_instructions = &self.cursor.block.ptr(self).instructions;
try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
if (!self.builder.strip) try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
if (!self.builder.strip) {
try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
if (!std.mem.eql(
u8,
std.mem.asBytes(&self.current_debug_location),
std.mem.asBytes(&self.last_debug_location),
)) {
try self.debug_locations.ensureUnusedCapacity(self.builder.gpa, 1);
}
}
try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
if (self.builder.useLibLlvm())
try self.llvm.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
@ -7158,7 +7224,17 @@ pub const WipFunction = struct {
const index: Instruction.Index = @enumFromInt(self.instructions.len);
self.instructions.appendAssumeCapacity(instruction);
if (!self.builder.strip) self.names.appendAssumeCapacity(final_name);
if (!self.builder.strip) {
self.names.appendAssumeCapacity(final_name);
if (!std.mem.eql(
u8,
std.mem.asBytes(&self.current_debug_location),
std.mem.asBytes(&self.last_debug_location),
)) {
self.debug_locations.putAssumeCapacity(index, self.current_debug_location);
self.last_debug_location = self.current_debug_location;
}
}
block_instructions.insertAssumeCapacity(self.cursor.instruction, index);
self.cursor.instruction += 1;
return index;