mirror of
https://github.com/ziglang/zig.git
synced 2025-12-10 16:23:07 +00:00
x86_64: un-regress loop and switch_br
This does *not* yet implement the new `loop_switch_br` instruction.
This commit is contained in:
parent
cb68c0917a
commit
fd70d9db99
@ -105,6 +105,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
|
|||||||
free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
|
free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
|
||||||
frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},
|
frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},
|
||||||
|
|
||||||
|
loop_repeat_info: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
|
||||||
|
/// The state to restore before branching.
|
||||||
|
state: State,
|
||||||
|
/// The branch target.
|
||||||
|
jmp_target: Mir.Inst.Index,
|
||||||
|
}) = .{},
|
||||||
|
|
||||||
/// Debug field, used to find bugs in the compiler.
|
/// Debug field, used to find bugs in the compiler.
|
||||||
air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
|
air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
|
||||||
|
|
||||||
@ -815,6 +822,7 @@ pub fn generate(
|
|||||||
function.frame_allocs.deinit(gpa);
|
function.frame_allocs.deinit(gpa);
|
||||||
function.free_frame_indices.deinit(gpa);
|
function.free_frame_indices.deinit(gpa);
|
||||||
function.frame_locs.deinit(gpa);
|
function.frame_locs.deinit(gpa);
|
||||||
|
function.loop_repeat_info.deinit(gpa);
|
||||||
var block_it = function.blocks.valueIterator();
|
var block_it = function.blocks.valueIterator();
|
||||||
while (block_it.next()) |block| block.deinit(gpa);
|
while (block_it.next()) |block| block.deinit(gpa);
|
||||||
function.blocks.deinit(gpa);
|
function.blocks.deinit(gpa);
|
||||||
@ -2247,7 +2255,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.bitcast => try self.airBitCast(inst),
|
.bitcast => try self.airBitCast(inst),
|
||||||
.block => try self.airBlock(inst),
|
.block => try self.airBlock(inst),
|
||||||
.br => try self.airBr(inst),
|
.br => try self.airBr(inst),
|
||||||
.repeat => return self.fail("TODO implement `repeat`", .{}),
|
.repeat => try self.airRepeat(inst),
|
||||||
.switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}),
|
.switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}),
|
||||||
.trap => try self.airTrap(),
|
.trap => try self.airTrap(),
|
||||||
.breakpoint => try self.airBreakpoint(),
|
.breakpoint => try self.airBreakpoint(),
|
||||||
@ -13629,15 +13637,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
self.scope_generation += 1;
|
self.scope_generation += 1;
|
||||||
const state = try self.saveState();
|
const state = try self.saveState();
|
||||||
|
|
||||||
const jmp_target: Mir.Inst.Index = @intCast(self.mir_instructions.len);
|
try self.loop_repeat_info.putNoClobber(self.gpa, inst, .{
|
||||||
try self.genBody(body);
|
.state = state,
|
||||||
try self.restoreState(state, &.{}, .{
|
.jmp_target = @intCast(self.mir_instructions.len),
|
||||||
.emit_instructions = true,
|
|
||||||
.update_tracking = false,
|
|
||||||
.resurrect = false,
|
|
||||||
.close_scope = true,
|
|
||||||
});
|
});
|
||||||
_ = try self.asmJmpReloc(jmp_target);
|
defer assert(self.loop_repeat_info.remove(inst));
|
||||||
|
|
||||||
|
try self.genBody(body);
|
||||||
|
|
||||||
self.finishAirBookkeeping();
|
self.finishAirBookkeeping();
|
||||||
}
|
}
|
||||||
@ -13680,12 +13686,19 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const zcu = self.pt.zcu;
|
||||||
const switch_br = self.air.unwrapSwitch(inst);
|
const switch_br = self.air.unwrapSwitch(inst);
|
||||||
const condition = try self.resolveInst(switch_br.operand);
|
const condition = try self.resolveInst(switch_br.operand);
|
||||||
const condition_ty = self.typeOf(switch_br.operand);
|
const condition_ty = self.typeOf(switch_br.operand);
|
||||||
const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);
|
const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1);
|
||||||
defer self.gpa.free(liveness.deaths);
|
defer self.gpa.free(liveness.deaths);
|
||||||
|
|
||||||
|
const signedness = switch (condition_ty.zigTypeTag(zcu)) {
|
||||||
|
.bool, .pointer => .unsigned,
|
||||||
|
.int, .@"enum", .error_set => condition_ty.intInfo(zcu).signedness,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
// If the condition dies here in this switch instruction, process
|
// If the condition dies here in this switch instruction, process
|
||||||
// that death now instead of later as this has an effect on
|
// that death now instead of later as this has an effect on
|
||||||
// whether it needs to be spilled in the branches
|
// whether it needs to be spilled in the branches
|
||||||
@ -13698,13 +13711,11 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
|
|
||||||
var it = switch_br.iterateCases();
|
var it = switch_br.iterateCases();
|
||||||
while (it.next()) |case| {
|
while (it.next()) |case| {
|
||||||
if (case.ranges.len > 0) return self.fail("TODO: switch with ranges", .{});
|
var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
|
||||||
|
|
||||||
var relocs = try self.gpa.alloc(Mir.Inst.Index, case.items.len);
|
|
||||||
defer self.gpa.free(relocs);
|
defer self.gpa.free(relocs);
|
||||||
|
|
||||||
try self.spillEflagsIfOccupied();
|
try self.spillEflagsIfOccupied();
|
||||||
for (case.items, relocs, 0..) |item, *reloc, i| {
|
for (case.items, relocs[0..case.items.len]) |item, *reloc| {
|
||||||
const item_mcv = try self.resolveInst(item);
|
const item_mcv = try self.resolveInst(item);
|
||||||
const cc: Condition = switch (condition) {
|
const cc: Condition = switch (condition) {
|
||||||
.eflags => |cc| switch (item_mcv.immediate) {
|
.eflags => |cc| switch (item_mcv.immediate) {
|
||||||
@ -13717,12 +13728,62 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
break :cc .e;
|
break :cc .e;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
reloc.* = try self.asmJccReloc(if (i < relocs.len - 1) cc else cc.negate(), undefined);
|
reloc.* = try self.asmJccReloc(cc, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (case.ranges, relocs[case.items.len..]) |range, *reloc| {
|
||||||
|
const min_mcv = try self.resolveInst(range[0]);
|
||||||
|
const max_mcv = try self.resolveInst(range[1]);
|
||||||
|
// `null` means always false.
|
||||||
|
const lt_min: ?Condition = switch (condition) {
|
||||||
|
.eflags => |cc| switch (min_mcv.immediate) {
|
||||||
|
0 => null, // condition never <0
|
||||||
|
1 => cc.negate(),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => cc: {
|
||||||
|
try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, min_mcv);
|
||||||
|
break :cc switch (signedness) {
|
||||||
|
.unsigned => .b,
|
||||||
|
.signed => .l,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const lt_min_reloc = if (lt_min) |cc| r: {
|
||||||
|
break :r try self.asmJccReloc(cc, undefined);
|
||||||
|
} else null;
|
||||||
|
// `null` means always true.
|
||||||
|
const lte_max: ?Condition = switch (condition) {
|
||||||
|
.eflags => |cc| switch (max_mcv.immediate) {
|
||||||
|
0 => cc.negate(),
|
||||||
|
1 => null, // condition always >=1
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => cc: {
|
||||||
|
try self.genBinOpMir(.{ ._, .cmp }, condition_ty, condition, max_mcv);
|
||||||
|
break :cc switch (signedness) {
|
||||||
|
.unsigned => .be,
|
||||||
|
.signed => .le,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// "Success" case is in `reloc`....
|
||||||
|
if (lte_max) |cc| {
|
||||||
|
reloc.* = try self.asmJccReloc(cc, undefined);
|
||||||
|
} else {
|
||||||
|
reloc.* = try self.asmJmpReloc(undefined);
|
||||||
|
}
|
||||||
|
// ...and "fail" case falls through to next checks.
|
||||||
|
if (lt_min_reloc) |r| self.performReloc(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The jump to skip this case if the conditions all failed.
|
||||||
|
const skip_case_reloc = try self.asmJmpReloc(undefined);
|
||||||
|
|
||||||
for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
|
for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
|
||||||
|
|
||||||
for (relocs[0 .. relocs.len - 1]) |reloc| self.performReloc(reloc);
|
// Relocate all success cases to the body we're about to generate.
|
||||||
|
for (relocs) |reloc| self.performReloc(reloc);
|
||||||
try self.genBody(case.body);
|
try self.genBody(case.body);
|
||||||
try self.restoreState(state, &.{}, .{
|
try self.restoreState(state, &.{}, .{
|
||||||
.emit_instructions = false,
|
.emit_instructions = false,
|
||||||
@ -13731,7 +13792,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
.close_scope = true,
|
.close_scope = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.performReloc(relocs[relocs.len - 1]);
|
// Relocate the "skip" branch to fall through to the next case.
|
||||||
|
self.performReloc(skip_case_reloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switch_br.else_body_len > 0) {
|
if (switch_br.else_body_len > 0) {
|
||||||
@ -13827,6 +13889,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
self.finishAirBookkeeping();
|
self.finishAirBookkeeping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airRepeat(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst;
|
||||||
|
const repeat_info = self.loop_repeat_info.get(loop_inst).?;
|
||||||
|
try self.restoreState(repeat_info.state, &.{}, .{
|
||||||
|
.emit_instructions = true,
|
||||||
|
.update_tracking = false,
|
||||||
|
.resurrect = false,
|
||||||
|
.close_scope = true,
|
||||||
|
});
|
||||||
|
_ = try self.asmJmpReloc(repeat_info.jmp_target);
|
||||||
|
self.finishAirBookkeeping();
|
||||||
|
}
|
||||||
|
|
||||||
fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
|
fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
const pt = self.pt;
|
const pt = self.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user