committed by
Andrew Kelley
parent
3fc6a2f113
commit
2eeb735822
@@ -148,10 +148,10 @@ pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.uns
|
||||
value >>= 7;
|
||||
ptr[i] = byte;
|
||||
}
|
||||
ptr[i] = @as(u8, @truncate(value));
|
||||
ptr[i] = @truncate(value);
|
||||
}
|
||||
|
||||
test "writeUnsignedFixed" {
|
||||
test writeUnsignedFixed {
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeUnsignedFixed(4, &buf, 0);
|
||||
@@ -174,6 +174,65 @@ test "writeUnsignedFixed" {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is an "advanced" function. It allows one to use a fixed amount of memory to store an
|
||||
/// ILEB128. This defeats the entire purpose of using this data encoding; it will no longer use
|
||||
/// fewer bytes to store smaller numbers. The advantage of using a fixed width is that it makes
|
||||
/// fields have a predictable size and so depending on the use case this tradeoff can be worthwhile.
|
||||
/// An example use case of this is in emitting DWARF info where one wants to make a ILEB128 field
|
||||
/// "relocatable", meaning that it becomes possible to later go back and patch the number to be a
|
||||
/// different value without shifting all the following code.
|
||||
pub fn writeSignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(.signed, l * 7)) void {
|
||||
const T = @TypeOf(int);
|
||||
const U = if (@typeInfo(T).Int.bits < 8) u8 else T;
|
||||
var value: U = @intCast(int);
|
||||
|
||||
comptime var i = 0;
|
||||
inline while (i < (l - 1)) : (i += 1) {
|
||||
const byte: u8 = @bitCast(@as(i8, @truncate(value)) | -0b1000_0000);
|
||||
value >>= 7;
|
||||
ptr[i] = byte;
|
||||
}
|
||||
ptr[i] = @as(u7, @bitCast(@as(i7, @truncate(value))));
|
||||
}
|
||||
|
||||
test writeSignedFixed {
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, 0);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == 0);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, 1);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == 1);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, -1);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == -1);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, 1000);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == 1000);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, -1000);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == -1000);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, -10000000);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == -10000000);
|
||||
}
|
||||
{
|
||||
var buf: [4]u8 = undefined;
|
||||
writeSignedFixed(4, &buf, 10000000);
|
||||
try testing.expect((try test_read_ileb128(i64, &buf)) == 10000000);
|
||||
}
|
||||
}
|
||||
|
||||
// tests
|
||||
fn test_read_stream_ileb128(comptime T: type, encoded: []const u8) !T {
|
||||
var reader = std.io.fixedBufferStream(encoded);
|
||||
|
||||
@@ -10576,12 +10576,12 @@ fn genVarDbgInfo(
|
||||
|
||||
fn airTrap(self: *Self) !void {
|
||||
try self.asmOpOnly(.{ ._, .ud2 });
|
||||
return self.finishAirBookkeeping();
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBreakpoint(self: *Self) !void {
|
||||
try self.asmOpOnly(.{ ._, .int3 });
|
||||
return self.finishAirBookkeeping();
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
@@ -10603,7 +10603,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.Acquire, .Release, .AcqRel => {},
|
||||
.SeqCst => try self.asmOpOnly(.{ ._, .mfence }),
|
||||
}
|
||||
return self.finishAirBookkeeping();
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
|
||||
@@ -11419,21 +11419,23 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.column = dbg_stmt.column,
|
||||
} },
|
||||
});
|
||||
return self.finishAirBookkeeping();
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const mod = self.bin_file.options.module.?;
|
||||
const ty_fn = self.air.instructions.items(.data)[inst].ty_fn;
|
||||
const func = mod.funcInfo(ty_fn.func);
|
||||
// TODO emit debug info for function change
|
||||
_ = func;
|
||||
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
|
||||
_ = try self.addInst(.{
|
||||
.tag = .pseudo,
|
||||
.ops = .pseudo_dbg_inline_func,
|
||||
.data = .{ .func = ty_fn.func },
|
||||
});
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
|
||||
_ = inst;
|
||||
// TODO emit debug info lexical block
|
||||
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
|
||||
@@ -11518,9 +11520,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.close_scope = true,
|
||||
});
|
||||
|
||||
// We already took care of pl_op.operand earlier, so we're going
|
||||
// to pass .none here
|
||||
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
|
||||
// We already took care of pl_op.operand earlier, so there's nothing left to do.
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
|
||||
@@ -11865,7 +11866,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
|
||||
});
|
||||
_ = try self.asmJmpReloc(jmp_target);
|
||||
|
||||
return self.finishAirBookkeeping();
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
|
||||
@@ -11977,8 +11978,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
});
|
||||
}
|
||||
|
||||
// We already took care of pl_op.operand earlier, so we're going to pass .none here
|
||||
return self.finishAir(inst, .unreach, .{ .none, .none, .none });
|
||||
// We already took care of pl_op.operand earlier, so there's nothing left to do
|
||||
self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
|
||||
|
||||
@@ -151,7 +151,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
else => unreachable,
|
||||
},
|
||||
.target = target,
|
||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||
.offset = @intCast(end_offset - 4),
|
||||
.addend = 0,
|
||||
.pcrel = true,
|
||||
.length = 2,
|
||||
@@ -173,7 +173,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
else => unreachable,
|
||||
},
|
||||
.target = target,
|
||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||
.offset = @intCast(end_offset - 4),
|
||||
.addend = 0,
|
||||
.pcrel = true,
|
||||
.length = 2,
|
||||
@@ -182,7 +182,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const atom_index = symbol.atom_index;
|
||||
try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
|
||||
.target = symbol.sym_index, // we set sym_index to just be the atom index
|
||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||
.offset = @intCast(end_offset - 4),
|
||||
.addend = 0,
|
||||
.type = .pcrel,
|
||||
});
|
||||
@@ -229,6 +229,18 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.none => {},
|
||||
}
|
||||
},
|
||||
.pseudo_dbg_inline_func => {
|
||||
switch (emit.debug_output) {
|
||||
.dwarf => |dw| {
|
||||
log.debug("mirDbgInline (line={d}, col={d})", .{
|
||||
emit.prev_di_line, emit.prev_di_column,
|
||||
});
|
||||
try dw.setInlineFunc(mir_inst.data.func);
|
||||
},
|
||||
.plan9 => {},
|
||||
.none => {},
|
||||
}
|
||||
},
|
||||
.pseudo_dead_none => {},
|
||||
},
|
||||
}
|
||||
@@ -269,17 +281,18 @@ fn fixupRelocs(emit: *Emit) Error!void {
|
||||
for (emit.relocs.items) |reloc| {
|
||||
const target = emit.code_offset_mapping.get(reloc.target) orelse
|
||||
return emit.fail("JMP/CALL relocation target not found!", .{});
|
||||
const disp = @as(i32, @intCast(@as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length))));
|
||||
mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], disp, .little);
|
||||
const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length));
|
||||
mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little);
|
||||
}
|
||||
}
|
||||
|
||||
fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
|
||||
const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
|
||||
const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line);
|
||||
const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
|
||||
log.debug(" (advance pc={d} and line={d})", .{ delta_line, delta_pc });
|
||||
switch (emit.debug_output) {
|
||||
.dwarf => |dw| {
|
||||
if (column != emit.prev_di_column) try dw.setColumn(column);
|
||||
try dw.advancePCAndLine(delta_line, delta_pc);
|
||||
emit.prev_di_line = line;
|
||||
emit.prev_di_column = column;
|
||||
@@ -289,7 +302,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
|
||||
if (delta_pc <= 0) return; // only do this when the pc changes
|
||||
|
||||
// increasing the line number
|
||||
try link.File.Plan9.changeLine(&dbg_out.dbg_line, delta_line);
|
||||
try link.File.Plan9.changeLine(&dbg_out.dbg_line, @intCast(delta_line));
|
||||
// increasing the pc
|
||||
const d_pc_p9 = @as(i64, @intCast(delta_pc)) - dbg_out.pc_quanta;
|
||||
if (d_pc_p9 > 0) {
|
||||
@@ -297,16 +310,16 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
|
||||
var diff = @divExact(d_pc_p9, dbg_out.pc_quanta) - dbg_out.pc_quanta;
|
||||
while (diff > 0) {
|
||||
if (diff < 64) {
|
||||
try dbg_out.dbg_line.append(@as(u8, @intCast(diff + 128)));
|
||||
try dbg_out.dbg_line.append(@intCast(diff + 128));
|
||||
diff = 0;
|
||||
} else {
|
||||
try dbg_out.dbg_line.append(@as(u8, @intCast(64 + 128)));
|
||||
try dbg_out.dbg_line.append(@intCast(64 + 128));
|
||||
diff -= 64;
|
||||
}
|
||||
}
|
||||
if (dbg_out.pcop_change_index) |pci|
|
||||
dbg_out.dbg_line.items[pci] += 1;
|
||||
dbg_out.pcop_change_index = @as(u32, @intCast(dbg_out.dbg_line.items.len - 1));
|
||||
dbg_out.pcop_change_index = @intCast(dbg_out.dbg_line.items.len - 1);
|
||||
} else if (d_pc_p9 == 0) {
|
||||
// we don't need to do anything, because adding the pc quanta does it for us
|
||||
} else unreachable;
|
||||
|
||||
@@ -259,6 +259,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
.pseudo_dbg_prologue_end_none,
|
||||
.pseudo_dbg_line_line_column,
|
||||
.pseudo_dbg_epilogue_begin_none,
|
||||
.pseudo_dbg_inline_func,
|
||||
.pseudo_dead_none,
|
||||
=> {},
|
||||
else => unreachable,
|
||||
|
||||
@@ -6,19 +6,6 @@
|
||||
//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
|
||||
//! so that, for example, the smaller encodings of jump instructions can be used.
|
||||
|
||||
const Mir = @This();
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const bits = @import("bits.zig");
|
||||
const encoder = @import("encoder.zig");
|
||||
|
||||
const Air = @import("../../Air.zig");
|
||||
const CodeGen = @import("CodeGen.zig");
|
||||
const IntegerBitSet = std.bit_set.IntegerBitSet;
|
||||
const Register = bits.Register;
|
||||
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
extra: []const u32,
|
||||
@@ -884,6 +871,8 @@ pub const Inst = struct {
|
||||
pseudo_dbg_line_line_column,
|
||||
/// Start of epilogue
|
||||
pseudo_dbg_epilogue_begin_none,
|
||||
/// Start or end of inline function
|
||||
pseudo_dbg_inline_func,
|
||||
|
||||
/// Tombstone
|
||||
/// Emitter should skip this instruction.
|
||||
@@ -987,6 +976,7 @@ pub const Inst = struct {
|
||||
line: u32,
|
||||
column: u32,
|
||||
},
|
||||
func: InternPool.Index,
|
||||
/// Register list
|
||||
reg_list: RegisterList,
|
||||
};
|
||||
@@ -1198,3 +1188,14 @@ pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
|
||||
} else mem,
|
||||
};
|
||||
}
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const bits = @import("bits.zig");
|
||||
const builtin = @import("builtin");
|
||||
const encoder = @import("encoder.zig");
|
||||
const std = @import("std");
|
||||
|
||||
const IntegerBitSet = std.bit_set.IntegerBitSet;
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
const Mir = @This();
|
||||
const Register = bits.Register;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user