mirror of
https://github.com/ziglang/zig.git
synced 2026-02-17 14:59:14 +00:00
x86_64: rewrite
This commit is contained in:
parent
257054a146
commit
af1191ea8b
36
src/Air.zig
36
src/Air.zig
@ -893,14 +893,38 @@ pub const Inst = struct {
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn toRef(i: Index) Inst.Ref {
|
||||
assert(@intFromEnum(i) >> 31 == 0);
|
||||
return @enumFromInt((1 << 31) | @intFromEnum(i));
|
||||
pub fn unwrap(index: Index) union(enum) { ref: Inst.Ref, target: u31 } {
|
||||
const low_index: u31 = @truncate(@intFromEnum(index));
|
||||
return switch (@as(u1, @intCast(@intFromEnum(index) >> 31))) {
|
||||
0 => .{ .ref = @enumFromInt(@as(u32, 1 << 31) | low_index) },
|
||||
1 => .{ .target = low_index },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toTargetIndex(i: Index) u31 {
|
||||
assert(@intFromEnum(i) >> 31 == 1);
|
||||
return @truncate(@intFromEnum(i));
|
||||
pub fn toRef(index: Index) Inst.Ref {
|
||||
return index.unwrap().ref;
|
||||
}
|
||||
|
||||
pub fn fromTargetIndex(index: u31) Index {
|
||||
return @enumFromInt((1 << 31) | @as(u32, index));
|
||||
}
|
||||
|
||||
pub fn toTargetIndex(index: Index) u31 {
|
||||
return index.unwrap().target;
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
index: Index,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
try writer.writeByte('%');
|
||||
switch (index.unwrap()) {
|
||||
.ref => {},
|
||||
.target => try writer.writeByte('t'),
|
||||
}
|
||||
try writer.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -3067,6 +3067,7 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
// linker state
|
||||
switch (lf.tag) {
|
||||
.wasm => {
|
||||
dev.check(link.File.Tag.wasm.devFeature());
|
||||
const wasm = lf.cast(.wasm).?;
|
||||
const is_obj = comp.config.output_mode == .Obj;
|
||||
try bufs.ensureUnusedCapacity(85);
|
||||
|
||||
@ -202,14 +202,6 @@ pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool
|
||||
return (l.tomb_bits[usize_index] & mask) != 0;
|
||||
}
|
||||
|
||||
pub fn clearOperandDeath(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) void {
|
||||
assert(operand < bpi - 1);
|
||||
const usize_index = (@intFromEnum(inst) * bpi) / @bitSizeOf(usize);
|
||||
const mask = @as(usize, 1) <<
|
||||
@as(Log2Int(usize), @intCast((@intFromEnum(inst) % (@bitSizeOf(usize) / bpi)) * bpi + operand));
|
||||
l.tomb_bits[usize_index] &= ~mask;
|
||||
}
|
||||
|
||||
const OperandCategory = enum {
|
||||
/// The operand lives on, but this instruction cannot possibly mutate memory.
|
||||
none,
|
||||
@ -844,12 +836,6 @@ const Analysis = struct {
|
||||
special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
|
||||
fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
|
||||
const usize_index = (inst * bpi) / @bitSizeOf(usize);
|
||||
a.tomb_bits[usize_index] |= @as(usize, tomb_bits) <<
|
||||
@as(Log2Int(usize), @intCast((inst % (@bitSizeOf(usize) / bpi)) * bpi));
|
||||
}
|
||||
|
||||
fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 {
|
||||
const fields = std.meta.fields(@TypeOf(extra));
|
||||
try a.extra.ensureUnusedCapacity(a.gpa, fields.len);
|
||||
|
||||
@ -71,6 +71,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// We postpone the creation of debug info for function args and locals
|
||||
/// until after all Mir instructions have been generated. Only then we
|
||||
/// will know saved_regs_stack_space which is necessary in order to
|
||||
@ -646,6 +648,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.add => try self.airBinOp(inst, .add),
|
||||
@ -927,16 +930,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -3614,7 +3614,7 @@ fn reuseOperand(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
@ -72,6 +72,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// We postpone the creation of debug info for function args and locals
|
||||
/// until after all Mir instructions have been generated. Only then we
|
||||
/// will know saved_regs_stack_space which is necessary in order to
|
||||
@ -635,6 +637,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.add, => try self.airBinOp(inst, .add),
|
||||
@ -918,16 +921,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -2650,7 +2650,7 @@ fn reuseOperand(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
@ -82,6 +82,8 @@ scope_generation: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// 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.
|
||||
@ -1443,8 +1445,11 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
|
||||
verbose_tracking_log.debug("{}", .{func.fmtTracking()});
|
||||
|
||||
const old_air_bookkeeping = func.air_bookkeeping;
|
||||
try func.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
func.reused_operands = @TypeOf(func.reused_operands).initEmpty();
|
||||
try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1);
|
||||
const tag: Air.Inst.Tag = air_tags[@intFromEnum(inst)];
|
||||
const tag = air_tags[@intFromEnum(inst)];
|
||||
switch (tag) {
|
||||
// zig fmt: off
|
||||
.add,
|
||||
@ -1783,11 +1788,10 @@ fn finishAir(
|
||||
result: MCValue,
|
||||
operands: [Liveness.bpi - 1]Air.Inst.Ref,
|
||||
) !void {
|
||||
var tomb_bits = func.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const tomb_bits = func.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (func.reused_operands.isSet(op_index)) continue;
|
||||
try func.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
func.finishAirResult(inst, result);
|
||||
@ -4424,7 +4428,7 @@ fn reuseOperandAdvanced(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
func.liveness.clearOperandDeath(inst, op_index);
|
||||
func.reused_operands.set(op_index);
|
||||
const op_inst = operand.toIndex().?;
|
||||
func.getResolvedInstValue(op_inst).reuse(func, maybe_tracked_inst, op_inst);
|
||||
|
||||
|
||||
@ -78,6 +78,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// 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.
|
||||
@ -493,6 +495,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
|
||||
@ -3523,16 +3526,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -4568,7 +4568,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -250,9 +250,8 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8
|
||||
return memory_class;
|
||||
},
|
||||
.optional => {
|
||||
if (ty.isPtrLikeOptional(zcu)) {
|
||||
result[0] = .integer;
|
||||
return result;
|
||||
if (ty.optionalReprIsPayload(zcu)) {
|
||||
return classifySystemV(ty.optionalChild(zcu), zcu, target, ctx);
|
||||
}
|
||||
return memory_class;
|
||||
},
|
||||
|
||||
@ -547,7 +547,39 @@ pub const Memory = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Scale = enum(u2) { @"1", @"2", @"4", @"8" };
|
||||
pub const Scale = enum(u2) {
|
||||
@"1",
|
||||
@"2",
|
||||
@"4",
|
||||
@"8",
|
||||
|
||||
pub fn fromFactor(factor: u4) Scale {
|
||||
return switch (factor) {
|
||||
else => unreachable,
|
||||
1 => .@"1",
|
||||
2 => .@"2",
|
||||
4 => .@"4",
|
||||
8 => .@"8",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toFactor(scale: Scale) u4 {
|
||||
return switch (scale) {
|
||||
.@"1" => 1,
|
||||
.@"2" => 2,
|
||||
.@"4" => 4,
|
||||
.@"8" => 8,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromLog2(log2: u2) Scale {
|
||||
return @enumFromInt(log2);
|
||||
}
|
||||
|
||||
pub fn toLog2(scale: Scale) u2 {
|
||||
return @intFromEnum(scale);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Immediate = union(enum) {
|
||||
|
||||
@ -96,8 +96,8 @@ const Writer = struct {
|
||||
fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.print("%{d}{c}= {s}(", .{
|
||||
@intFromEnum(inst),
|
||||
try s.print("{}{c}= {s}(", .{
|
||||
inst,
|
||||
@as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
|
||||
@tagName(tag),
|
||||
});
|
||||
@ -409,7 +409,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_block.deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,7 +728,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -739,7 +739,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -765,7 +765,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -776,7 +776,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -807,7 +807,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.then_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -827,7 +827,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -884,7 +884,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -910,7 +910,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -994,7 +994,7 @@ const Writer = struct {
|
||||
dies: bool,
|
||||
) @TypeOf(s).Error!void {
|
||||
_ = w;
|
||||
try s.print("%{d}", .{@intFromEnum(inst)});
|
||||
try s.print("{}", .{inst});
|
||||
if (dies) try s.writeByte('!');
|
||||
}
|
||||
|
||||
|
||||
@ -383,7 +383,7 @@ def InstRef_SummaryProvider(value, _=None):
|
||||
'InternPool.Index(%d)' % value.unsigned if value.unsigned < 0x80000000 else 'instructions[%d]' % (value.unsigned - 0x80000000))
|
||||
|
||||
def InstIndex_SummaryProvider(value, _=None):
|
||||
return 'instructions[%d]' % value.unsigned
|
||||
return 'instructions[%d]' % value.unsigned if value.unsigned < 0x80000000 else 'temps[%d]' % (value.unsigned - 0x80000000)
|
||||
|
||||
class zig_DeclIndex_SynthProvider:
|
||||
def __init__(self, value, _=None): self.value = value
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user