authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-08 23:20:13-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-20 20:49:35+01:00
logf18ee1e2a2d4fb7ece2741efbfe4bda8b056068e
tree4e32ae7b8011a2ea37f695d240f376209d8a2770
parent488d804a1c205583e22aee4076e41f497b3ef1b0
signature Commit is signed but in an unrecognized format.

x86_64: add block death workaround


1 files changed, 52 insertions(+), 37 deletions(-)

src/arch/x86_64/CodeGen.zig+52-37
...@@ -89,8 +89,8 @@ register_manager: RegisterManager = .{},...@@ -89,8 +89,8 @@ register_manager: RegisterManager = .{},
89/// Maps offset to what is stored there.89/// Maps offset to what is stored there.
90stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},90stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9191
92/// Index of the current scope.92/// Generation of the current scope, increments by 1 for every entered scope.
93scope_index: u32 = 0,93scope_generation: u32 = 0,
9494
95/// Offset from the stack base, representing the end of the stack frame.95/// Offset from the stack base, representing the end of the stack frame.
96max_end_stack: u32 = 0,96max_end_stack: u32 = 0,
...@@ -116,7 +116,7 @@ pub const MCValue = union(enum) {...@@ -116,7 +116,7 @@ pub const MCValue = union(enum) {
116 /// Control flow will not allow this value to be observed.116 /// Control flow will not allow this value to be observed.
117 unreach,117 unreach,
118 /// No more references to this value remain.118 /// No more references to this value remain.
119 /// The payload is the value of scope_index at the point where the death occurred119 /// The payload is the value of scope_generation at the point where the death occurred
120 dead: u32,120 dead: u32,
121 /// The value is undefined.121 /// The value is undefined.
122 undef,122 undef,
...@@ -253,9 +253,9 @@ const InstTracking = struct {...@@ -253,9 +253,9 @@ const InstTracking = struct {
253 self.short = .{ .register = reg };253 self.short = .{ .register = reg };
254 }254 }
255255
256 fn resurrect(self: *InstTracking, scope_index: u32) void {256 fn resurrect(self: *InstTracking, scope_generation: u32) void {
257 switch (self.short) {257 switch (self.short) {
258 .dead => |die_index| if (die_index >= scope_index) {258 .dead => |die_generation| if (die_generation >= scope_generation) {
259 self.short = self.long;259 self.short = self.long;
260 },260 },
261 else => {},261 else => {},
...@@ -268,7 +268,7 @@ const InstTracking = struct {...@@ -268,7 +268,7 @@ const InstTracking = struct {
268 }268 }
269269
270 fn reuse(self: *InstTracking, function: *Self) void {270 fn reuse(self: *InstTracking, function: *Self) void {
271 self.short = .{ .dead = function.scope_index };271 self.short = .{ .dead = function.scope_generation };
272 }272 }
273};273};
274274
...@@ -280,10 +280,12 @@ const StackAllocation = struct {...@@ -280,10 +280,12 @@ const StackAllocation = struct {
280280
281const BlockData = struct {281const BlockData = struct {
282 relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},282 relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
283 deaths: std.ArrayListUnmanaged(u32) = .{}, // inst_tracking indices
283 state: State,284 state: State,
284285
285 fn deinit(self: *BlockData, gpa: Allocator) void {286 fn deinit(self: *BlockData, gpa: Allocator) void {
286 self.relocs.deinit(gpa);287 self.relocs.deinit(gpa);
288 self.deaths.deinit(gpa);
287 self.* = undefined;289 self.* = undefined;
288 }290 }
289};291};
...@@ -1354,30 +1356,25 @@ const State = struct {...@@ -1354,30 +1356,25 @@ const State = struct {
1354 registers: RegisterManager.TrackedRegisters,1356 registers: RegisterManager.TrackedRegisters,
1355 free_registers: RegisterManager.RegisterBitSet,1357 free_registers: RegisterManager.RegisterBitSet,
1356 inst_tracking_len: u32,1358 inst_tracking_len: u32,
1357 scope_index: u32,1359 scope_generation: u32,
1358};1360};
13591361
1360fn initRetroactiveState(self: *Self) State {1362fn initRetroactiveState(self: *Self) State {
1361 var state: State = undefined;1363 var state: State = undefined;
1362 state.inst_tracking_len = @intCast(u32, self.inst_tracking.count());1364 state.inst_tracking_len = @intCast(u32, self.inst_tracking.count());
1363 state.scope_index = self.scope_index;1365 state.scope_generation = self.scope_generation;
1364 return state;1366 return state;
1365}1367}
13661368
1367fn saveRetroactiveState(self: *Self, state: *State, comptime hack_around_liveness_bug: bool) !void {1369fn saveRetroactiveState(self: *Self, state: *State) !void {
1368 try self.spillEflagsIfOccupied();1370 try self.spillEflagsIfOccupied();
1369 state.registers = self.register_manager.registers;1371 state.registers = self.register_manager.registers;
1370 state.free_registers = self.register_manager.free_registers;1372 state.free_registers = self.register_manager.free_registers;
1371 if (hack_around_liveness_bug) for (0..state.registers.len) |index| {
1372 if (state.free_registers.isSet(index)) continue;
1373 if (self.inst_tracking.getIndex(state.registers[index]).? < state.inst_tracking_len) continue;
1374 state.free_registers.set(index);
1375 };
1376}1373}
13771374
1378fn saveState(self: *Self) !State {1375fn saveState(self: *Self) !State {
1379 var state = self.initRetroactiveState();1376 var state = self.initRetroactiveState();
1380 try self.saveRetroactiveState(&state, false);1377 try self.saveRetroactiveState(&state);
1381 return state;1378 return state;
1382}1379}
13831380
...@@ -1388,19 +1385,12 @@ fn restoreState(self: *Self, state: State, comptime opts: struct {...@@ -1388,19 +1385,12 @@ fn restoreState(self: *Self, state: State, comptime opts: struct {
1388 close_scope: bool,1385 close_scope: bool,
1389}) !void {1386}) !void {
1390 if (opts.close_scope) {1387 if (opts.close_scope) {
1391 if (std.debug.runtime_safety) {1388 for (self.inst_tracking.values()[state.inst_tracking_len..]) |*tracking| tracking.die(self);
1392 for (self.inst_tracking.values()[state.inst_tracking_len..]) |tracking| {
1393 switch (tracking.short) {
1394 .dead, .unreach => {},
1395 else => unreachable,
1396 }
1397 }
1398 }
1399 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);1389 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
1400 }1390 }
14011391
1402 if (opts.resurrect)1392 if (opts.resurrect) for (self.inst_tracking.values()) |*tracking|
1403 for (self.inst_tracking.values()) |*tracking| tracking.resurrect(state.scope_index);1393 tracking.resurrect(state.scope_generation);
14041394
1405 for (0..state.registers.len) |index| {1395 for (0..state.registers.len) |index| {
1406 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))1396 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))
...@@ -6146,7 +6136,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6146,7 +6136,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
61466136
6147 const outer_state = try self.saveState();6137 const outer_state = try self.saveState();
6148 {6138 {
6149 self.scope_index += 1;6139 self.scope_generation += 1;
6150 const inner_state = try self.saveState();6140 const inner_state = try self.saveState();
61516141
6152 for (liveness_condbr.then_deaths) |operand| self.processDeath(operand);6142 for (liveness_condbr.then_deaths) |operand| self.processDeath(operand);
...@@ -6162,6 +6152,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6162,6 +6152,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
61626152
6163 for (liveness_condbr.else_deaths) |operand| self.processDeath(operand);6153 for (liveness_condbr.else_deaths) |operand| self.processDeath(operand);
6164 try self.genBody(else_body);6154 try self.genBody(else_body);
6155 try self.restoreState(inner_state, .{
6156 .emit_instructions = false,
6157 .update_tracking = true,
6158 .resurrect = true,
6159 .close_scope = true,
6160 });
6165 }6161 }
6166 try self.restoreState(outer_state, .{6162 try self.restoreState(outer_state, .{
6167 .emit_instructions = false,6163 .emit_instructions = false,
...@@ -6473,7 +6469,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -6473,7 +6469,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
6473 const body = self.air.extra[loop.end..][0..loop.data.body_len];6469 const body = self.air.extra[loop.end..][0..loop.data.body_len];
6474 const jmp_target = @intCast(u32, self.mir_instructions.len);6470 const jmp_target = @intCast(u32, self.mir_instructions.len);
64756471
6476 self.scope_index += 1;6472 self.scope_generation += 1;
6477 const state = try self.saveState();6473 const state = try self.saveState();
64786474
6479 try self.genBody(body);6475 try self.genBody(body);
...@@ -6501,7 +6497,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {...@@ -6501,7 +6497,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
6501 .short = if (ty.isNoReturn()) .unreach else .none,6497 .short = if (ty.isNoReturn()) .unreach else .none,
6502 });6498 });
65036499
6504 self.scope_index += 1;6500 self.scope_generation += 1;
6505 try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });6501 try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });
6506 defer {6502 defer {
6507 var block_data = self.blocks.fetchRemove(inst).?.value;6503 var block_data = self.blocks.fetchRemove(inst).?.value;
...@@ -6515,6 +6511,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {...@@ -6515,6 +6511,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
65156511
6516 const tracking = self.inst_tracking.getPtr(inst).?;6512 const tracking = self.inst_tracking.getPtr(inst).?;
6517 const block_data = self.blocks.getPtr(inst).?;6513 const block_data = self.blocks.getPtr(inst).?;
6514 for (block_data.deaths.items) |tracking_index| self.inst_tracking.values()[tracking_index].die(self);
6518 if (tracking.short != .unreach) try self.restoreState(block_data.state, .{6515 if (tracking.short != .unreach) try self.restoreState(block_data.state, .{
6519 .emit_instructions = false,6516 .emit_instructions = false,
6520 .update_tracking = true,6517 .update_tracking = true,
...@@ -6547,7 +6544,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6547,7 +6544,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
65476544
6548 const outer_state = try self.saveState();6545 const outer_state = try self.saveState();
6549 {6546 {
6550 self.scope_index += 1;6547 self.scope_generation += 1;
6551 const inner_state = try self.saveState();6548 const inner_state = try self.saveState();
65526549
6553 while (case_i < switch_br.data.cases_len) : (case_i += 1) {6550 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
...@@ -6572,13 +6569,12 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6572,13 +6569,12 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
6572 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);6569 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);
65736570
6574 try self.genBody(case_body);6571 try self.genBody(case_body);
6575 if (case_i < switch_br.data.cases_len - 1 or switch_br.data.else_body_len > 0)6572 try self.restoreState(inner_state, .{
6576 try self.restoreState(inner_state, .{6573 .emit_instructions = false,
6577 .emit_instructions = false,6574 .update_tracking = true,
6578 .update_tracking = true,6575 .resurrect = true,
6579 .resurrect = true,6576 .close_scope = true,
6580 .close_scope = true,6577 });
6581 });
65826578
6583 for (relocs) |reloc| try self.performReloc(reloc);6579 for (relocs) |reloc| try self.performReloc(reloc);
6584 }6580 }
...@@ -6590,6 +6586,12 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6590,6 +6586,12 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
6590 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);6586 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);
65916587
6592 try self.genBody(else_body);6588 try self.genBody(else_body);
6589 try self.restoreState(inner_state, .{
6590 .emit_instructions = false,
6591 .update_tracking = true,
6592 .resurrect = true,
6593 .close_scope = true,
6594 });
6593 }6595 }
6594 }6596 }
6595 try self.restoreState(outer_state, .{6597 try self.restoreState(outer_state, .{
...@@ -6631,6 +6633,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6631,6 +6633,19 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
6631 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;6633 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
6632 const block_data = self.blocks.getPtr(br.block_inst).?;6634 const block_data = self.blocks.getPtr(br.block_inst).?;
6633 if (block_tracking.long == .unreach) {6635 if (block_tracking.long == .unreach) {
6636 // .unreach is used to mean that we are the first branch
6637
6638 // We need to compute a list of deaths for later. This list needs to include
6639 // instructions that was born before, and has died since, the target block.
6640 for (self.inst_tracking.values()[0..block_data.state.inst_tracking_len], 0..) |
6641 *tracking,
6642 tracked_index,
6643 | switch (tracking.short) {
6644 .dead => |die_generation| if (die_generation >= block_data.state.scope_generation)
6645 try block_data.deaths.append(self.gpa, @intCast(u32, tracked_index)),
6646 else => {},
6647 };
6648
6634 const result = result: {6649 const result = result: {
6635 if (block_unused) break :result .none;6650 if (block_unused) break :result .none;
6636 if (self.reuseOperand(inst, br.operand, 0, src_mcv)) break :result src_mcv;6651 if (self.reuseOperand(inst, br.operand, 0, src_mcv)) break :result src_mcv;
...@@ -6640,7 +6655,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6640,7 +6655,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
6640 break :result new_mcv;6655 break :result new_mcv;
6641 };6656 };
6642 block_tracking.* = InstTracking.init(result);6657 block_tracking.* = InstTracking.init(result);
6643 try self.saveRetroactiveState(&block_data.state, true);6658 try self.saveRetroactiveState(&block_data.state);
6644 self.freeValue(result);6659 self.freeValue(result);
6645 } else {6660 } else {
6646 if (!block_unused) try self.setRegOrMem(block_ty, block_tracking.short, src_mcv);6661 if (!block_unused) try self.setRegOrMem(block_ty, block_tracking.short, src_mcv);