stage2 ARM: move genArgDbgInfo back to CodeGen

This removes the questionable Air -> Mir dependency that existed
before. The x86_64 backend also performed this change.
This commit is contained in:
joachimschmidt557 2022-04-15 19:22:35 +02:00 committed by Joachim Schmidt
parent 4c83b11f71
commit 3bfb1616db
3 changed files with 106 additions and 124 deletions

View File

@ -49,6 +49,7 @@ gpa: Allocator,
air: Air,
liveness: Liveness,
bin_file: *link.File,
debug_output: DebugInfoOutput,
target: *const std.Target,
mod_fn: *const Module.Fn,
err_msg: ?*ErrorMsg,
@ -73,6 +74,12 @@ end_di_column: u32,
/// which is a relative jump, based on the address following the reloc.
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{},
/// For every argument, we postpone the creation of debug info for
/// later after all Mir instructions have been generated. Only then we
/// will know saved_regs_stack_space which is necessary in order to
/// address parameters passed on the stack.
dbg_arg_relocs: std.ArrayListUnmanaged(DbgArgReloc) = .{},
/// Whenever there is a runtime branch, we push a Branch onto this stack,
/// and pop it off when the runtime branch joins. This provides an "overlay"
/// of the table of mappings from instructions to `MCValue` from within the branch.
@ -244,6 +251,11 @@ const BigTomb = struct {
}
};
const DbgArgReloc = struct {
inst: Air.Inst.Index,
index: u32,
};
const Self = @This();
pub fn generate(
@ -276,6 +288,7 @@ pub fn generate(
.liveness = liveness,
.target = &bin_file.options.target,
.bin_file = bin_file,
.debug_output = debug_output,
.mod_fn = module_fn,
.err_msg = null,
.args = undefined, // populated after `resolveCallingConventionValues`
@ -291,6 +304,7 @@ pub fn generate(
defer function.stack.deinit(bin_file.allocator);
defer function.blocks.deinit(bin_file.allocator);
defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
defer function.dbg_arg_relocs.deinit(bin_file.allocator);
var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {
error.CodegenFail => return FnResult{ .fail = function.err_msg.? },
@ -314,6 +328,10 @@ pub fn generate(
else => |e| return e,
};
for (function.dbg_arg_relocs.items) |reloc| {
try function.genArgDbgInfo(reloc.inst, reloc.index, call_info.stack_byte_count);
}
var mir = Mir{
.instructions = function.mir_instructions.toOwnedSlice(),
.extra = function.mir_extra.toOwnedSlice(bin_file.allocator),
@ -323,7 +341,6 @@ pub fn generate(
var emit = Emit{
.mir = mir,
.bin_file = bin_file,
.function = &function,
.debug_output = debug_output,
.target = &bin_file.options.target,
.src_loc = src_loc,
@ -3074,6 +3091,91 @@ fn genInlineMemcpy(
// end:
}
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
switch (self.debug_output) {
.dwarf => |dw| {
assert(ty.hasRuntimeBits());
const dbg_info = &dw.dbg_info;
const index = dbg_info.items.len;
try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
const atom = switch (self.bin_file.tag) {
.elf => &self.mod_fn.owner_decl.link.elf.dbg_info_atom,
.macho => unreachable,
else => unreachable,
};
try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
},
.plan9 => {},
.none => {},
}
}
fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {
const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space;
const mcv = self.args[arg_index];
const ty = self.air.instructions.items(.data)[inst].ty;
const name = self.mod_fn.getParamName(arg_index);
const name_with_null = name.ptr[0 .. name.len + 1];
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
try dbg_info.ensureUnusedCapacity(3);
dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
.stack_offset,
.stack_argument_offset,
=> {
switch (self.debug_output) {
.dwarf => |dw| {
// const abi_size = @intCast(u32, ty.abiSize(self.target.*));
const adjusted_stack_offset = switch (mcv) {
.stack_offset => |offset| -@intCast(i32, offset),
.stack_argument_offset => |offset| @intCast(i32, prologue_stack_space - offset),
else => unreachable,
};
const dbg_info = &dw.dbg_info;
try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
// DW.AT.location, DW.FORM.exprloc
// ULEB128 dwarf expression length
try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
try dbg_info.append(DW.OP.breg11);
try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
else => unreachable, // not a possible argument
}
}
fn airArg(self: *Self, inst: Air.Inst.Index) !void {
const arg_index = self.arg_index;
self.arg_index += 1;
@ -3094,13 +3196,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
else => result,
};
_ = try self.addInst(.{
.tag = .dbg_arg,
.cond = undefined,
.data = .{ .dbg_arg_info = .{
.air_inst = inst,
.arg_index = arg_index,
} },
try self.dbg_arg_relocs.append(self.gpa, .{
.inst = inst,
.index = arg_index,
});
if (self.liveness.isUnused(inst))

View File

@ -9,7 +9,6 @@ const Mir = @import("Mir.zig");
const bits = @import("bits.zig");
const link = @import("../../link.zig");
const Module = @import("../../Module.zig");
const Air = @import("../../Air.zig");
const Type = @import("../../type.zig").Type;
const ErrorMsg = Module.ErrorMsg;
const assert = std.debug.assert;
@ -23,7 +22,6 @@ const CodeGen = @import("CodeGen.zig");
mir: Mir,
bin_file: *link.File,
function: *const CodeGen,
debug_output: DebugInfoOutput,
target: *const std.Target,
err_msg: ?*ErrorMsg = null,
@ -102,8 +100,6 @@ pub fn emitMir(
.blx => try emit.mirBranchExchange(inst),
.bx => try emit.mirBranchExchange(inst),
.dbg_arg => try emit.mirDbgArg(inst),
.dbg_line => try emit.mirDbgLine(inst),
.dbg_prologue_end => try emit.mirDebugPrologueEnd(),
@ -189,7 +185,6 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
.dbg_line,
.dbg_epilogue_begin,
.dbg_prologue_end,
.dbg_arg,
=> return 0,
else => return 4,
}
@ -383,97 +378,6 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
}
}
/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
/// after codegen for this symbol is done.
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dw| {
assert(ty.hasRuntimeBits());
const dbg_info = &dw.dbg_info;
const index = dbg_info.items.len;
try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
const atom = switch (self.bin_file.tag) {
.elf => &self.function.mod_fn.owner_decl.link.elf.dbg_info_atom,
.macho => unreachable,
else => unreachable,
};
try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
},
.plan9 => {},
.none => {},
}
}
fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
const mcv = self.function.args[arg_index];
const ty = self.function.air.instructions.items(.data)[inst].ty;
const name = self.function.mod_fn.getParamName(arg_index);
const name_with_null = name.ptr[0 .. name.len + 1];
const target = self.target.*;
switch (mcv) {
.register => |reg| {
switch (self.debug_output) {
.dwarf => |dw| {
const dbg_info = &dw.dbg_info;
try dbg_info.ensureUnusedCapacity(3);
dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1, // ULEB128 dwarf expression length
reg.dwarfLocOp(),
});
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
.stack_offset,
.stack_argument_offset,
=> {
switch (self.debug_output) {
.dwarf => |dw| {
const abi_size = math.cast(u32, ty.abiSize(self.target.*)) catch {
return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(target)});
};
const adjusted_stack_offset = switch (mcv) {
.stack_offset => |offset| math.negateCast(offset + abi_size) catch {
return self.fail("Stack offset too large for arguments", .{});
},
.stack_argument_offset => |offset| math.cast(i32, self.prologue_stack_space - offset - abi_size) catch {
return self.fail("Stack offset too large for arguments", .{});
},
else => unreachable,
};
const dbg_info = &dw.dbg_info;
try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
// Get length of the LEB128 stack offset
var counting_writer = std.io.countingWriter(std.io.null_writer);
leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable;
// DW.AT.location, DW.FORM.exprloc
// ULEB128 dwarf expression length
try leb128.writeULEB128(dbg_info.writer(), counting_writer.bytes_written + 1);
try dbg_info.append(DW.OP.breg11);
try leb128.writeILEB128(dbg_info.writer(), adjusted_stack_offset);
try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
},
.plan9 => {},
.none => {},
}
},
else => unreachable, // not a possible argument
}
}
fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const cond = emit.mir.instructions.items(.cond)[inst];
@ -546,16 +450,6 @@ fn mirBranchExchange(emit: *Emit, inst: Mir.Inst.Index) !void {
}
}
fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
switch (tag) {
.dbg_arg => try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
else => unreachable,
}
}
fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;

View File

@ -12,7 +12,6 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const bits = @import("bits.zig");
const Air = @import("../../Air.zig");
const Register = bits.Register;
instructions: std.MultiArrayList(Inst).Slice,
@ -44,8 +43,6 @@ pub const Inst = struct {
bx,
/// Compare
cmp,
/// Pseudo-instruction: Argument
dbg_arg,
/// Pseudo-instruction: End of prologue
dbg_prologue_end,
/// Pseudo-instruction: Beginning of epilogue
@ -239,13 +236,6 @@ pub const Inst = struct {
line: u32,
column: u32,
},
/// Debug info: argument
///
/// Used by e.g. dbg_arg
dbg_arg_info: struct {
air_inst: Air.Inst.Index,
arg_index: u32,
},
};
// Make sure we don't accidentally make instructions bigger than expected.