authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-08 07:36:35-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-20 20:49:34+01:00
log488d804a1c205583e22aee4076e41f497b3ef1b0
treed3a71ecda95b19f428b6c1f675b2746eacb2ec50
parent6f09a7041ecf328f761df60fae007c800ee1e2ec
signaturelock-open Commit is signed but in an unrecognized format.

x86_64: rewrite inst tracking


3 files changed, 495 insertions(+), 667 deletions(-)

src/arch/x86_64/CodeGen.zig+491-666
...@@ -79,14 +79,8 @@ end_di_column: u32,...@@ -79,14 +79,8 @@ end_di_column: u32,
79/// which is a relative jump, based on the address following the reloc.79/// which is a relative jump, based on the address following the reloc.
80exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},80exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
8181
82/// Whenever there is a runtime branch, we push a Branch onto this stack,82const_tracking: InstTrackingMap = .{},
83/// and pop it off when the runtime branch joins. This provides an "overlay"83inst_tracking: InstTrackingMap = .{},
84/// of the table of mappings from instructions to `MCValue` from within the branch.
85/// This way we can modify the `MCValue` for an instruction in different ways
86/// within different branches. Special consideration is needed when a branch
87/// joins with its parent, to make sure all instructions have the same MCValue
88/// across each runtime branch upon joining.
89branch_stack: *std.ArrayList(Branch),
9084
91// Key is the block instruction85// Key is the block instruction
92blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},86blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
...@@ -95,6 +89,9 @@ register_manager: RegisterManager = .{},...@@ -95,6 +89,9 @@ register_manager: RegisterManager = .{},
95/// Maps offset to what is stored there.89/// Maps offset to what is stored there.
96stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},90stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9791
92/// Index of the current scope.
93scope_index: u32 = 0,
94
98/// 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.
99max_end_stack: u32 = 0,96max_end_stack: u32 = 0,
100/// Represents the current end stack offset. If there is no existing slot97/// Represents the current end stack offset. If there is no existing slot
...@@ -105,10 +102,12 @@ next_stack_offset: u32 = 0,...@@ -105,10 +102,12 @@ next_stack_offset: u32 = 0,
105air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,102air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
106103
107/// For mir debug info, maps a mir index to a air index104/// For mir debug info, maps a mir index to a air index
108mir_to_air_map: if (builtin.mode == .Debug) std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index) else void,105mir_to_air_map: @TypeOf(mir_to_air_map_init) = mir_to_air_map_init,
109106
110const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};107const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
111108
109const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged(Mir.Inst.Index, Air.Inst.Index){} else {};
110
112pub const MCValue = union(enum) {111pub const MCValue = union(enum) {
113 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.112 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
114 /// TODO Look into deleting this tag and using `dead` instead, since every use113 /// TODO Look into deleting this tag and using `dead` instead, since every use
...@@ -117,7 +116,8 @@ pub const MCValue = union(enum) {...@@ -117,7 +116,8 @@ pub const MCValue = union(enum) {
117 /// Control flow will not allow this value to be observed.116 /// Control flow will not allow this value to be observed.
118 unreach,117 unreach,
119 /// No more references to this value remain.118 /// No more references to this value remain.
120 dead,119 /// The payload is the value of scope_index at the point where the death occurred
120 dead: u32,
121 /// The value is undefined.121 /// The value is undefined.
122 undef,122 undef,
123 /// A pointer-sized integer that fits in a register.123 /// A pointer-sized integer that fits in a register.
...@@ -183,47 +183,92 @@ pub const MCValue = union(enum) {...@@ -183,47 +183,92 @@ pub const MCValue = union(enum) {
183 }183 }
184};184};
185185
186const Branch = struct {186const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking);
187 inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{},187const InstTracking = struct {
188 long: MCValue,
189 short: MCValue,
188190
189 fn deinit(self: *Branch, gpa: Allocator) void {191 fn init(result: MCValue) InstTracking {
190 self.inst_table.deinit(gpa);192 return .{ .long = result, .short = result };
191 self.* = undefined;193 }
194
195 fn getReg(self: InstTracking) ?Register {
196 return switch (self.short) {
197 .register => |reg| reg,
198 .register_overflow => |ro| ro.reg,
199 else => null,
200 };
201 }
202
203 fn getCondition(self: InstTracking) ?Condition {
204 return switch (self.short) {
205 .eflags => |eflags| eflags,
206 .register_overflow => |ro| ro.eflags,
207 else => null,
208 };
209 }
210
211 fn spill(self: *InstTracking, function: *Self, inst: Air.Inst.Index) !void {
212 switch (self.long) {
213 .none,
214 .dead,
215 .unreach,
216 => unreachable,
217 .register,
218 .register_overflow,
219 .eflags,
220 => self.long = try function.allocRegOrMem(inst, self.short == .eflags),
221 .stack_offset => {},
222 .undef,
223 .immediate,
224 .memory,
225 .linker_load,
226 .tlv_reloc,
227 .ptr_stack_offset,
228 => return, // these can be rematerialized without using a stack slot
229 }
230 log.debug("spilling %{d} from {} to {}", .{ inst, self.short, self.long });
231 const ty = function.air.typeOfIndex(inst);
232 try function.setRegOrMem(ty, self.long, self.short);
192 }233 }
193234
194 const FormatContext = struct {235 fn trackSpill(self: *InstTracking, function: *Self) void {
195 insts: []const Air.Inst.Index,236 if (self.getReg()) |reg| function.register_manager.freeReg(reg);
196 mcvs: []const MCValue,237 switch (self.short) {
197 };238 .none, .dead, .unreach => unreachable,
198239 else => {},
199 fn fmt(
200 ctx: FormatContext,
201 comptime unused_format_string: []const u8,
202 options: std.fmt.FormatOptions,
203 writer: anytype,
204 ) @TypeOf(writer).Error!void {
205 _ = options;
206 comptime assert(unused_format_string.len == 0);
207 try writer.writeAll("Branch {\n");
208 for (ctx.insts, ctx.mcvs) |inst, mcv| {
209 try writer.print(" %{d} => {}\n", .{ inst, mcv });
210 }240 }
211 try writer.writeAll("}");241 self.short = self.long;
212 }242 }
213243
214 fn format(branch: Branch, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {244 fn materialize(self: *InstTracking, function: *Self, inst: Air.Inst.Index, reg: Register) !void {
215 _ = branch;245 const ty = function.air.typeOfIndex(inst);
216 _ = unused_format_string;246 try function.genSetReg(ty, reg, self.long);
217 _ = options;
218 _ = writer;
219 @compileError("do not format Branch directly; use ty.fmtDebug()");
220 }247 }
221248
222 fn fmtDebug(self: @This()) std.fmt.Formatter(fmt) {249 fn trackMaterialize(self: *InstTracking, function: *Self, inst: Air.Inst.Index, reg: Register) void {
223 return .{ .data = .{250 assert(inst == function.register_manager.registers[
224 .insts = self.inst_table.keys(),251 RegisterManager.indexOfRegIntoTracked(reg).?
225 .mcvs = self.inst_table.values(),252 ]);
226 } };253 self.short = .{ .register = reg };
254 }
255
256 fn resurrect(self: *InstTracking, scope_index: u32) void {
257 switch (self.short) {
258 .dead => |die_index| if (die_index >= scope_index) {
259 self.short = self.long;
260 },
261 else => {},
262 }
263 }
264
265 fn die(self: *InstTracking, function: *Self) void {
266 function.freeValue(self.short);
267 self.reuse(function);
268 }
269
270 fn reuse(self: *InstTracking, function: *Self) void {
271 self.short = .{ .dead = function.scope_index };
227 }272 }
228};273};
229274
...@@ -235,39 +280,14 @@ const StackAllocation = struct {...@@ -235,39 +280,14 @@ const StackAllocation = struct {
235280
236const BlockData = struct {281const BlockData = struct {
237 relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},282 relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
238 branch: Branch = .{},283 state: State,
239 branch_depth: u32,
240284
241 fn deinit(self: *BlockData, gpa: Allocator) void {285 fn deinit(self: *BlockData, gpa: Allocator) void {
242 self.branch.deinit(gpa);
243 self.relocs.deinit(gpa);286 self.relocs.deinit(gpa);
244 self.* = undefined;287 self.* = undefined;
245 }288 }
246};289};
247290
248const BigTomb = struct {
249 function: *Self,
250 inst: Air.Inst.Index,
251 lbt: Liveness.BigTomb,
252
253 fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
254 const dies = bt.lbt.feed();
255 const op_index = Air.refToIndex(op_ref) orelse return;
256 if (!dies) return;
257 bt.function.processDeath(op_index);
258 }
259
260 fn finishAir(bt: *BigTomb, result: MCValue) void {
261 const is_used = !bt.function.liveness.isUnused(bt.inst);
262 if (is_used) {
263 log.debug(" (saving %{d} => {})", .{ bt.inst, result });
264 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
265 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
266 }
267 bt.function.finishAirBookkeeping();
268 }
269};
270
271const Self = @This();291const Self = @This();
272292
273pub fn generate(293pub fn generate(
...@@ -294,19 +314,9 @@ pub fn generate(...@@ -294,19 +314,9 @@ pub fn generate(
294 stderr.writeAll(":\n") catch {};314 stderr.writeAll(":\n") catch {};
295 }315 }
296316
297 var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);317 const gpa = bin_file.allocator;
298 try branch_stack.ensureUnusedCapacity(2);
299 // The outermost branch is used for constants only.
300 branch_stack.appendAssumeCapacity(.{});
301 branch_stack.appendAssumeCapacity(.{});
302 defer {
303 assert(branch_stack.items.len == 2);
304 for (branch_stack.items) |*branch| branch.deinit(bin_file.allocator);
305 branch_stack.deinit();
306 }
307
308 var function = Self{318 var function = Self{
309 .gpa = bin_file.allocator,319 .gpa = gpa,
310 .air = air,320 .air = air,
311 .liveness = liveness,321 .liveness = liveness,
312 .target = &bin_file.options.target,322 .target = &bin_file.options.target,
...@@ -318,21 +328,21 @@ pub fn generate(...@@ -318,21 +328,21 @@ pub fn generate(
318 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`328 .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
319 .fn_type = fn_type,329 .fn_type = fn_type,
320 .arg_index = 0,330 .arg_index = 0,
321 .branch_stack = &branch_stack,
322 .src_loc = src_loc,331 .src_loc = src_loc,
323 .stack_align = undefined,332 .stack_align = undefined,
324 .end_di_line = module_fn.rbrace_line,333 .end_di_line = module_fn.rbrace_line,
325 .end_di_column = module_fn.rbrace_column,334 .end_di_column = module_fn.rbrace_column,
326 .mir_to_air_map = if (builtin.mode == .Debug)
327 std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator)
328 else {},
329 };335 };
330 defer function.stack.deinit(bin_file.allocator);336 defer {
331 defer function.blocks.deinit(bin_file.allocator);337 function.stack.deinit(gpa);
332 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);338 function.blocks.deinit(gpa);
333 defer function.mir_instructions.deinit(bin_file.allocator);339 function.inst_tracking.deinit(gpa);
334 defer function.mir_extra.deinit(bin_file.allocator);340 function.const_tracking.deinit(gpa);
335 defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit();341 function.exitlude_jump_relocs.deinit(gpa);
342 function.mir_instructions.deinit(gpa);
343 function.mir_extra.deinit(gpa);
344 if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa);
345 }
336346
337 var call_info = function.resolveCallingConventionValues(fn_type, &.{}) catch |err| switch (err) {347 var call_info = function.resolveCallingConventionValues(fn_type, &.{}) catch |err| switch (err) {
338 error.CodegenFail => return Result{ .fail = function.err_msg.? },348 error.CodegenFail => return Result{ .fail = function.err_msg.? },
...@@ -911,9 +921,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -911,9 +921,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
911 }921 }
912922
913 const old_air_bookkeeping = self.air_bookkeeping;923 const old_air_bookkeeping = self.air_bookkeeping;
914 try self.ensureProcessDeathCapacity(Liveness.bpi);924 try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1);
915 if (builtin.mode == .Debug) {925 if (builtin.mode == .Debug) {
916 try self.mir_to_air_map.put(@intCast(Mir.Inst.Index, self.mir_instructions.len), inst);926 const mir_inst = @intCast(Mir.Inst.Index, self.mir_instructions.len);
927 try self.mir_to_air_map.put(self.gpa, mir_inst, inst);
917 }928 }
918 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(929 if (debug_wip_mir) @import("../../print_air.zig").dumpInst(
919 inst,930 inst,
...@@ -1085,7 +1096,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1085,7 +1096,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
10851096
1086 .field_parent_ptr => try self.airFieldParentPtr(inst),1097 .field_parent_ptr => try self.airFieldParentPtr(inst),
10871098
1088 .switch_br => try self.airSwitch(inst),1099 .switch_br => try self.airSwitchBr(inst),
1089 .slice_ptr => try self.airSlicePtr(inst),1100 .slice_ptr => try self.airSlicePtr(inst),
1090 .slice_len => try self.airSliceLen(inst),1101 .slice_len => try self.airSliceLen(inst),
10911102
...@@ -1171,8 +1182,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1171,8 +1182,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1171 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });1182 var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
1172 while (it.next()) |index| {1183 while (it.next()) |index| {
1173 const tracked_inst = self.register_manager.registers[index];1184 const tracked_inst = self.register_manager.registers[index];
1174 const tracked_mcv = self.getResolvedInstValue(tracked_inst).?.*;1185 const tracking = self.getResolvedInstValue(tracked_inst).?;
1175 assert(RegisterManager.indexOfRegIntoTracked(switch (tracked_mcv) {1186 assert(RegisterManager.indexOfRegIntoTracked(switch (tracking.short) {
1176 .register => |reg| reg,1187 .register => |reg| reg,
1177 .register_overflow => |ro| ro.reg,1188 .register_overflow => |ro| ro.reg,
1178 else => unreachable,1189 else => unreachable,
...@@ -1210,16 +1221,16 @@ fn freeValue(self: *Self, value: MCValue) void {...@@ -1210,16 +1221,16 @@ fn freeValue(self: *Self, value: MCValue) void {
1210 }1221 }
1211}1222}
12121223
1224fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void {
1225 if (bt.feed()) if (Air.refToIndex(operand)) |inst| self.processDeath(inst);
1226}
1227
1213/// Asserts there is already capacity to insert into top branch inst_table.1228/// Asserts there is already capacity to insert into top branch inst_table.
1214fn processDeath(self: *Self, inst: Air.Inst.Index) void {1229fn processDeath(self: *Self, inst: Air.Inst.Index) void {
1215 const air_tags = self.air.instructions.items(.tag);1230 const air_tags = self.air.instructions.items(.tag);
1216 if (air_tags[inst] == .constant) return; // Constants are immortal.1231 if (air_tags[inst] == .constant) return;
1217 const prev_value = (self.getResolvedInstValue(inst) orelse return).*;
1218 log.debug("%{d} => {}", .{ inst, MCValue.dead });1232 log.debug("%{d} => {}", .{ inst, MCValue.dead });
1219 // When editing this function, note that the logic must synchronize with `reuseOperand`.1233 if (self.getResolvedInstValue(inst)) |tracking| tracking.die(self);
1220 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1221 branch.inst_table.putAssumeCapacity(inst, .dead);
1222 self.freeValue(prev_value);
1223}1234}
12241235
1225/// Called when there are no operands, and the instruction is always unreferenced.1236/// Called when there are no operands, and the instruction is always unreferenced.
...@@ -1229,6 +1240,21 @@ fn finishAirBookkeeping(self: *Self) void {...@@ -1229,6 +1240,21 @@ fn finishAirBookkeeping(self: *Self) void {
1229 }1240 }
1230}1241}
12311242
1243fn finishAirResult(self: *Self, inst: Air.Inst.Index, result: MCValue) void {
1244 if (self.liveness.isUnused(inst)) switch (result) {
1245 .none, .dead, .unreach => {},
1246 else => unreachable, // Why didn't the result die?
1247 } else {
1248 log.debug("%{d} => {}", .{ inst, result });
1249 self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(result));
1250 // In some cases, an operand may be reused as the result.
1251 // If that operand died and was a register, it was freed by
1252 // processDeath, so we have to "re-allocate" the register.
1253 self.getValue(result, inst);
1254 }
1255 self.finishAirBookkeeping();
1256}
1257
1232fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {1258fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
1233 var tomb_bits = self.liveness.getTombBits(inst);1259 var tomb_bits = self.liveness.getTombBits(inst);
1234 for (operands) |op| {1260 for (operands) |op| {
...@@ -1240,26 +1266,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live...@@ -1240,26 +1266,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
1240 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);1266 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
1241 self.processDeath(op_index);1267 self.processDeath(op_index);
1242 }1268 }
1243 const is_used = @truncate(u1, tomb_bits) == 0;1269 self.finishAirResult(inst, result);
1244 if (is_used) {
1245 log.debug("%{d} => {}", .{ inst, result });
1246 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1247 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
1248 // In some cases, an operand may be reused as the result.
1249 // If that operand died and was a register, it was freed by
1250 // processDeath, so we have to "re-allocate" the register.
1251 self.getValue(result, inst);
1252 } else switch (result) {
1253 .none, .dead, .unreach => {},
1254 else => unreachable, // Why didn't the result die?
1255 }
1256 self.finishAirBookkeeping();
1257}
1258
1259fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
1260 // In addition to the caller's needs, we need enough space to spill every register and eflags.
1261 const table = &self.branch_stack.items[self.branch_stack.items.len - 1].inst_table;
1262 try table.ensureUnusedCapacity(self.gpa, additional_count + self.register_manager.registers.len + 1);
1263}1270}
12641271
1265fn allocMem(self: *Self, inst: ?Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {1272fn allocMem(self: *Self, inst: ?Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
...@@ -1344,66 +1351,121 @@ fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_...@@ -1344,66 +1351,121 @@ fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_
1344}1351}
13451352
1346const State = struct {1353const State = struct {
1347 registers: abi.RegisterManager.TrackedRegisters,1354 registers: RegisterManager.TrackedRegisters,
1348 free_registers: abi.RegisterManager.RegisterBitSet,1355 free_registers: RegisterManager.RegisterBitSet,
1349 eflags_inst: ?Air.Inst.Index,1356 inst_tracking_len: u32,
1357 scope_index: u32,
1350};1358};
13511359
1352fn captureState(self: *Self) State {1360fn initRetroactiveState(self: *Self) State {
1353 return State{1361 var state: State = undefined;
1354 .registers = self.register_manager.registers,1362 state.inst_tracking_len = @intCast(u32, self.inst_tracking.count());
1355 .free_registers = self.register_manager.free_registers,1363 state.scope_index = self.scope_index;
1356 .eflags_inst = self.eflags_inst,1364 return state;
1365}
1366
1367fn saveRetroactiveState(self: *Self, state: *State, comptime hack_around_liveness_bug: bool) !void {
1368 try self.spillEflagsIfOccupied();
1369 state.registers = self.register_manager.registers;
1370 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);
1357 };1375 };
1358}1376}
13591377
1360fn revertState(self: *Self, state: State) void {1378fn saveState(self: *Self) !State {
1361 self.eflags_inst = state.eflags_inst;1379 var state = self.initRetroactiveState();
1362 self.register_manager.free_registers = state.free_registers;1380 try self.saveRetroactiveState(&state, false);
1363 self.register_manager.registers = state.registers;1381 return state;
1364}1382}
13651383
1366pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {1384fn restoreState(self: *Self, state: State, comptime opts: struct {
1367 const stack_mcv = try self.allocRegOrMem(inst, false);1385 emit_instructions: bool,
1368 log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });1386 update_tracking: bool,
1369 const reg_mcv = self.getResolvedInstValue(inst).?.*;1387 resurrect: bool,
1370 switch (reg_mcv) {1388 close_scope: bool,
1371 .register => |other| {1389}) !void {
1372 assert(reg.to64() == other.to64());1390 if (opts.close_scope) {
1373 },1391 if (std.debug.runtime_safety) {
1374 .register_overflow => |ro| {1392 for (self.inst_tracking.values()[state.inst_tracking_len..]) |tracking| {
1375 assert(reg.to64() == ro.reg.to64());1393 switch (tracking.short) {
1376 },1394 .dead, .unreach => {},
1377 else => {},1395 else => unreachable,
1396 }
1397 }
1398 }
1399 self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
1378 }1400 }
1379 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1380 branch.inst_table.putAssumeCapacity(inst, stack_mcv);
1381 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{});
1382}
13831401
1384pub fn spillEflagsIfOccupied(self: *Self) !void {1402 if (opts.resurrect)
1385 if (self.eflags_inst) |inst_to_save| {1403 for (self.inst_tracking.values()) |*tracking| tracking.resurrect(state.scope_index);
1386 const mcv = self.getResolvedInstValue(inst_to_save).?.*;
1387 const new_mcv = switch (mcv) {
1388 .register_overflow => try self.allocRegOrMem(inst_to_save, false),
1389 .eflags => try self.allocRegOrMem(inst_to_save, true),
1390 else => unreachable,
1391 };
13921404
1393 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);1405 for (0..state.registers.len) |index| {
1394 log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv });1406 const current_maybe_inst = if (self.register_manager.free_registers.isSet(index))
1407 null
1408 else
1409 self.register_manager.registers[index];
1410 const target_maybe_inst = if (state.free_registers.isSet(index))
1411 null
1412 else
1413 state.registers[index];
1414 if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|
1415 assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
1416 if (current_maybe_inst == target_maybe_inst) continue;
1417 const reg = RegisterManager.regAtTrackedIndex(
1418 @intCast(RegisterManager.RegisterBitSet.ShiftInt, index),
1419 );
1420 if (opts.emit_instructions) {
1421 if (current_maybe_inst) |current_inst| {
1422 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
1423 }
1424 if (target_maybe_inst) |target_inst| {
1425 try self.inst_tracking.getPtr(target_inst).?.materialize(self, target_inst, reg);
1426 }
1427 }
1428 if (opts.update_tracking) {
1429 if (current_maybe_inst) |current_inst| {
1430 self.inst_tracking.getPtr(current_inst).?.trackSpill(self);
1431 }
1432 self.register_manager.freeReg(reg);
1433 self.register_manager.getRegAssumeFree(reg, target_maybe_inst);
1434 if (target_maybe_inst) |target_inst| {
1435 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(self, target_inst, reg);
1436 }
1437 }
1438 }
1439 if (opts.emit_instructions) if (self.eflags_inst) |inst|
1440 try self.inst_tracking.getPtr(inst).?.spill(self, inst);
1441 if (opts.update_tracking) if (self.eflags_inst) |inst| {
1442 self.eflags_inst = null;
1443 self.inst_tracking.getPtr(inst).?.trackSpill(self);
1444 };
13951445
1396 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1446 if (opts.update_tracking and std.debug.runtime_safety) {
1397 branch.inst_table.putAssumeCapacity(inst_to_save, new_mcv);1447 assert(self.eflags_inst == null);
1448 assert(self.register_manager.free_registers.eql(state.free_registers));
1449 var used_reg_it = state.free_registers.iterator(.{ .kind = .unset });
1450 while (used_reg_it.next()) |index|
1451 assert(self.register_manager.registers[index] == state.registers[index]);
1452 }
1453}
13981454
1399 self.eflags_inst = null;1455pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
1456 const tracking = self.inst_tracking.getPtr(inst).?;
1457 assert(tracking.getReg().?.to64() == reg.to64());
1458 try tracking.spill(self, inst);
1459 tracking.trackSpill(self);
1460}
14001461
1401 // TODO consolidate with register manager and spillInstruction1462pub fn spillEflagsIfOccupied(self: *Self) !void {
1402 // this call should really belong in the register manager!1463 if (self.eflags_inst) |inst| {
1403 switch (mcv) {1464 self.eflags_inst = null;
1404 .register_overflow => |ro| self.register_manager.freeReg(ro.reg),1465 const tracking = self.inst_tracking.getPtr(inst).?;
1405 else => {},1466 assert(tracking.getCondition() != null);
1406 }1467 try tracking.spill(self, inst);
1468 tracking.trackSpill(self);
1407 }1469 }
1408}1470}
14091471
...@@ -1448,7 +1510,7 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty...@@ -1448,7 +1510,7 @@ fn copyToRegisterWithInstTracking(self: *Self, reg_owner: Air.Inst.Index, ty: Ty
14481510
1449fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {1511fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
1450 const result: MCValue = result: {1512 const result: MCValue = result: {
1451 if (self.liveness.isUnused(inst)) break :result .dead;1513 if (self.liveness.isUnused(inst)) break :result .unreach;
14521514
1453 const stack_offset = try self.allocMemPtr(inst);1515 const stack_offset = try self.allocMemPtr(inst);
1454 break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };1516 break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };
...@@ -1458,7 +1520,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {...@@ -1458,7 +1520,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
14581520
1459fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {1521fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
1460 const result: MCValue = result: {1522 const result: MCValue = result: {
1461 if (self.liveness.isUnused(inst)) break :result .dead;1523 if (self.liveness.isUnused(inst)) break :result .unreach;
14621524
1463 const stack_offset = try self.allocMemPtr(inst);1525 const stack_offset = try self.allocMemPtr(inst);
1464 break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };1526 break :result .{ .ptr_stack_offset = @intCast(i32, stack_offset) };
...@@ -1482,7 +1544,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {...@@ -1482,7 +1544,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
14821544
1483fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {1545fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1484 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1546 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1485 const result = if (self.liveness.isUnused(inst)) .dead else result: {1547 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
1486 const src_ty = self.air.typeOf(ty_op.operand);1548 const src_ty = self.air.typeOf(ty_op.operand);
1487 const src_int_info = src_ty.intInfo(self.target.*);1549 const src_int_info = src_ty.intInfo(self.target.*);
1488 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));1550 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
...@@ -1560,7 +1622,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1560,7 +1622,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
15601622
1561fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1623fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1562 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1624 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1563 const result = if (self.liveness.isUnused(inst)) .dead else result: {1625 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
1564 const dst_ty = self.air.typeOfIndex(inst);1626 const dst_ty = self.air.typeOfIndex(inst);
1565 const dst_abi_size = dst_ty.abiSize(self.target.*);1627 const dst_abi_size = dst_ty.abiSize(self.target.*);
1566 if (dst_abi_size > 8) {1628 if (dst_abi_size > 8) {
...@@ -1590,7 +1652,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -1590,7 +1652,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1590fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {1652fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
1591 const un_op = self.air.instructions.items(.data)[inst].un_op;1653 const un_op = self.air.instructions.items(.data)[inst].un_op;
1592 const operand = try self.resolveInst(un_op);1654 const operand = try self.resolveInst(un_op);
1593 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand;1655 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else operand;
1594 return self.finishAir(inst, result, .{ un_op, .none, .none });1656 return self.finishAir(inst, result, .{ un_op, .none, .none });
1595}1657}
15961658
...@@ -1599,7 +1661,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1599,7 +1661,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1599 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1661 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
16001662
1601 if (self.liveness.isUnused(inst)) {1663 if (self.liveness.isUnused(inst)) {
1602 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1664 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
1603 }1665 }
16041666
1605 const ptr = try self.resolveInst(bin_op.lhs);1667 const ptr = try self.resolveInst(bin_op.lhs);
...@@ -1619,7 +1681,7 @@ fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1619,7 +1681,7 @@ fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1619 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1681 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
16201682
1621 const result = if (self.liveness.isUnused(inst))1683 const result = if (self.liveness.isUnused(inst))
1622 .dead1684 .unreach
1623 else1685 else
1624 try self.genUnOp(inst, tag, ty_op.operand);1686 try self.genUnOp(inst, tag, ty_op.operand);
1625 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1687 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1629,7 +1691,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1629,7 +1691,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1629 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1691 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
16301692
1631 const result = if (self.liveness.isUnused(inst))1693 const result = if (self.liveness.isUnused(inst))
1632 .dead1694 .unreach
1633 else1695 else
1634 try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);1696 try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1635 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1697 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1640,7 +1702,7 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void...@@ -1640,7 +1702,7 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
1640 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1702 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
16411703
1642 const result = if (self.liveness.isUnused(inst))1704 const result = if (self.liveness.isUnused(inst))
1643 .dead1705 .unreach
1644 else1706 else
1645 try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);1707 try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1646 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1708 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1683,7 +1745,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {...@@ -1683,7 +1745,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 {
16831745
1684fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {1746fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
1685 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1747 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1686 const result = if (self.liveness.isUnused(inst)) .dead else result: {1748 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
1687 const tag = self.air.instructions.items(.tag)[inst];1749 const tag = self.air.instructions.items(.tag)[inst];
1688 const dst_ty = self.air.typeOfIndex(inst);1750 const dst_ty = self.air.typeOfIndex(inst);
1689 if (dst_ty.zigTypeTag() == .Float)1751 if (dst_ty.zigTypeTag() == .Float)
...@@ -1714,7 +1776,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1714,7 +1776,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
17141776
1715fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {1777fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
1716 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1778 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1717 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1779 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1718 const ty = self.air.typeOf(bin_op.lhs);1780 const ty = self.air.typeOf(bin_op.lhs);
17191781
1720 const lhs_mcv = try self.resolveInst(bin_op.lhs);1782 const lhs_mcv = try self.resolveInst(bin_op.lhs);
...@@ -1767,7 +1829,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1767,7 +1829,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
17671829
1768fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {1830fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1769 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1831 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1770 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1832 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1771 const ty = self.air.typeOf(bin_op.lhs);1833 const ty = self.air.typeOf(bin_op.lhs);
17721834
1773 const lhs_mcv = try self.resolveInst(bin_op.lhs);1835 const lhs_mcv = try self.resolveInst(bin_op.lhs);
...@@ -1818,7 +1880,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1818,7 +1880,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
18181880
1819fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {1881fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1820 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1882 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1821 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1883 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1822 const ty = self.air.typeOf(bin_op.lhs);1884 const ty = self.air.typeOf(bin_op.lhs);
18231885
1824 try self.spillRegisters(&.{ .rax, .rdx });1886 try self.spillRegisters(&.{ .rax, .rdx });
...@@ -1875,7 +1937,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1875,7 +1937,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1875fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1937fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1876 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1938 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1877 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1939 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1878 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1940 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1879 const tag = self.air.instructions.items(.tag)[inst];1941 const tag = self.air.instructions.items(.tag)[inst];
1880 const ty = self.air.typeOf(bin_op.lhs);1942 const ty = self.air.typeOf(bin_op.lhs);
1881 switch (ty.zigTypeTag()) {1943 switch (ty.zigTypeTag()) {
...@@ -1934,7 +1996,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1934,7 +1996,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1934fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1996fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1935 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1997 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1936 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1998 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1937 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1999 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1938 const lhs_ty = self.air.typeOf(bin_op.lhs);2000 const lhs_ty = self.air.typeOf(bin_op.lhs);
1939 const rhs_ty = self.air.typeOf(bin_op.rhs);2001 const rhs_ty = self.air.typeOf(bin_op.rhs);
1940 switch (lhs_ty.zigTypeTag()) {2002 switch (lhs_ty.zigTypeTag()) {
...@@ -2056,7 +2118,7 @@ fn genSetStackTruncatedOverflowCompare(...@@ -2056,7 +2118,7 @@ fn genSetStackTruncatedOverflowCompare(
2056fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {2118fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2057 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2119 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2058 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2120 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2059 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2121 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2060 const dst_ty = self.air.typeOf(bin_op.lhs);2122 const dst_ty = self.air.typeOf(bin_op.lhs);
2061 switch (dst_ty.zigTypeTag()) {2123 switch (dst_ty.zigTypeTag()) {
2062 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),2124 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
...@@ -2246,7 +2308,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2246,7 +2308,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
2246 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2308 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
22472309
2248 if (self.liveness.isUnused(inst)) {2310 if (self.liveness.isUnused(inst)) {
2249 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2311 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
2250 }2312 }
22512313
2252 try self.spillRegisters(&.{.rcx});2314 try self.spillRegisters(&.{.rcx});
...@@ -2266,7 +2328,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2266,7 +2328,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
2266fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {2328fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
2267 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2329 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2268 const result: MCValue = if (self.liveness.isUnused(inst))2330 const result: MCValue = if (self.liveness.isUnused(inst))
2269 .dead2331 .unreach
2270 else2332 else
2271 return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});2333 return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
2272 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2334 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -2275,7 +2337,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2275,7 +2337,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
2275fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {2337fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
2276 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2338 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2277 const result: MCValue = result: {2339 const result: MCValue = result: {
2278 if (self.liveness.isUnused(inst)) break :result .none;2340 if (self.liveness.isUnused(inst)) break :result .unreach;
22792341
2280 const pl_ty = self.air.typeOfIndex(inst);2342 const pl_ty = self.air.typeOfIndex(inst);
2281 const opt_mcv = try self.resolveInst(ty_op.operand);2343 const opt_mcv = try self.resolveInst(ty_op.operand);
...@@ -2302,7 +2364,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -2302,7 +2364,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
2302fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {2364fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
2303 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2365 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2304 const result: MCValue = result: {2366 const result: MCValue = result: {
2305 if (self.liveness.isUnused(inst)) break :result .dead;2367 if (self.liveness.isUnused(inst)) break :result .unreach;
23062368
2307 const dst_ty = self.air.typeOfIndex(inst);2369 const dst_ty = self.air.typeOfIndex(inst);
2308 const opt_mcv = try self.resolveInst(ty_op.operand);2370 const opt_mcv = try self.resolveInst(ty_op.operand);
...@@ -2325,7 +2387,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2325,7 +2387,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
23252387
2326 if (opt_ty.optionalReprIsPayload()) {2388 if (opt_ty.optionalReprIsPayload()) {
2327 break :result if (self.liveness.isUnused(inst))2389 break :result if (self.liveness.isUnused(inst))
2328 .dead2390 .unreach
2329 else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))2391 else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
2330 src_mcv2392 src_mcv
2331 else2393 else
...@@ -2344,7 +2406,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2344,7 +2406,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2344 Memory.sib(.byte, .{ .base = dst_mcv.register, .disp = pl_abi_size }),2406 Memory.sib(.byte, .{ .base = dst_mcv.register, .disp = pl_abi_size }),
2345 Immediate.u(1),2407 Immediate.u(1),
2346 );2408 );
2347 break :result if (self.liveness.isUnused(inst)) .dead else dst_mcv;2409 break :result if (self.liveness.isUnused(inst)) .unreach else dst_mcv;
2348 };2410 };
2349 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2411 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2350}2412}
...@@ -2352,7 +2414,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2352,7 +2414,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2352fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {2414fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2353 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2415 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2354 if (self.liveness.isUnused(inst)) {2416 if (self.liveness.isUnused(inst)) {
2355 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });2417 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2356 }2418 }
2357 const err_union_ty = self.air.typeOf(ty_op.operand);2419 const err_union_ty = self.air.typeOf(ty_op.operand);
2358 const err_ty = err_union_ty.errorUnionSet();2420 const err_ty = err_union_ty.errorUnionSet();
...@@ -2397,7 +2459,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2397,7 +2459,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2397fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {2459fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
2398 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2460 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2399 if (self.liveness.isUnused(inst)) {2461 if (self.liveness.isUnused(inst)) {
2400 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });2462 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2401 }2463 }
2402 const err_union_ty = self.air.typeOf(ty_op.operand);2464 const err_union_ty = self.air.typeOf(ty_op.operand);
2403 const operand = try self.resolveInst(ty_op.operand);2465 const operand = try self.resolveInst(ty_op.operand);
...@@ -2450,7 +2512,7 @@ fn genUnwrapErrorUnionPayloadMir(...@@ -2450,7 +2512,7 @@ fn genUnwrapErrorUnionPayloadMir(
2450fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {2512fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2451 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2513 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2452 const result: MCValue = result: {2514 const result: MCValue = result: {
2453 if (self.liveness.isUnused(inst)) break :result .dead;2515 if (self.liveness.isUnused(inst)) break :result .unreach;
24542516
2455 const src_ty = self.air.typeOf(ty_op.operand);2517 const src_ty = self.air.typeOf(ty_op.operand);
2456 const src_mcv = try self.resolveInst(ty_op.operand);2518 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -2484,7 +2546,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2484,7 +2546,7 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void {
2484fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {2546fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {
2485 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2547 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2486 const result: MCValue = result: {2548 const result: MCValue = result: {
2487 if (self.liveness.isUnused(inst)) break :result .dead;2549 if (self.liveness.isUnused(inst)) break :result .unreach;
24882550
2489 const src_ty = self.air.typeOf(ty_op.operand);2551 const src_ty = self.air.typeOf(ty_op.operand);
2490 const src_mcv = try self.resolveInst(ty_op.operand);2552 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -2540,7 +2602,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2540,7 +2602,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2540 Immediate.u(0),2602 Immediate.u(0),
2541 );2603 );
25422604
2543 if (self.liveness.isUnused(inst)) break :result .dead;2605 if (self.liveness.isUnused(inst)) break :result .unreach;
25442606
2545 const dst_ty = self.air.typeOfIndex(inst);2607 const dst_ty = self.air.typeOfIndex(inst);
2546 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))2608 const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
...@@ -2564,7 +2626,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2564,7 +2626,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
25642626
2565fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {2627fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2566 const result: MCValue = if (self.liveness.isUnused(inst))2628 const result: MCValue = if (self.liveness.isUnused(inst))
2567 .dead2629 .unreach
2568 else2630 else
2569 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});2631 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
2570 return self.finishAir(inst, result, .{ .none, .none, .none });2632 return self.finishAir(inst, result, .{ .none, .none, .none });
...@@ -2583,7 +2645,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {...@@ -2583,7 +2645,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void {
2583fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {2645fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
2584 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2646 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2585 const result: MCValue = result: {2647 const result: MCValue = result: {
2586 if (self.liveness.isUnused(inst)) break :result .dead;2648 if (self.liveness.isUnused(inst)) break :result .unreach;
25872649
2588 const pl_ty = self.air.typeOf(ty_op.operand);2650 const pl_ty = self.air.typeOf(ty_op.operand);
2589 if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 };2651 if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 };
...@@ -2630,7 +2692,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -2630,7 +2692,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
2630 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2692 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26312693
2632 if (self.liveness.isUnused(inst)) {2694 if (self.liveness.isUnused(inst)) {
2633 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });2695 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2634 }2696 }
26352697
2636 const error_union_ty = self.air.getRefType(ty_op.ty);2698 const error_union_ty = self.air.getRefType(ty_op.ty);
...@@ -2660,7 +2722,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -2660,7 +2722,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
2660fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {2722fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2661 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2723 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2662 if (self.liveness.isUnused(inst)) {2724 if (self.liveness.isUnused(inst)) {
2663 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });2725 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
2664 }2726 }
2665 const error_union_ty = self.air.getRefType(ty_op.ty);2727 const error_union_ty = self.air.getRefType(ty_op.ty);
2666 const payload_ty = error_union_ty.errorUnionPayload();2728 const payload_ty = error_union_ty.errorUnionPayload();
...@@ -2687,7 +2749,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2687,7 +2749,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
26872749
2688fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {2750fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
2689 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2751 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2690 const result = if (self.liveness.isUnused(inst)) .dead else result: {2752 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
2691 const src_mcv = try self.resolveInst(ty_op.operand);2753 const src_mcv = try self.resolveInst(ty_op.operand);
2692 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;2754 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
26932755
...@@ -2701,7 +2763,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2701,7 +2763,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
27012763
2702fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {2764fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2703 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2765 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2704 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2766 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
2705 const operand = try self.resolveInst(ty_op.operand);2767 const operand = try self.resolveInst(ty_op.operand);
2706 const dst_mcv: MCValue = blk: {2768 const dst_mcv: MCValue = blk: {
2707 switch (operand) {2769 switch (operand) {
...@@ -2720,7 +2782,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -2720,7 +2782,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2720fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {2782fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
2721 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2783 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2722 const result: MCValue = result: {2784 const result: MCValue = result: {
2723 if (self.liveness.isUnused(inst)) break :result .dead;2785 if (self.liveness.isUnused(inst)) break :result .unreach;
27242786
2725 const src_ty = self.air.typeOf(ty_op.operand);2787 const src_ty = self.air.typeOf(ty_op.operand);
2726 const src_mcv = try self.resolveInst(ty_op.operand);2788 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -2756,7 +2818,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2756,7 +2818,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
2756fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {2818fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
2757 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2819 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2758 const result: MCValue = result: {2820 const result: MCValue = result: {
2759 if (self.liveness.isUnused(inst)) break :result .dead;2821 if (self.liveness.isUnused(inst)) break :result .unreach;
27602822
2761 const dst_ty = self.air.typeOfIndex(inst);2823 const dst_ty = self.air.typeOfIndex(inst);
2762 const opt_mcv = try self.resolveInst(ty_op.operand);2824 const opt_mcv = try self.resolveInst(ty_op.operand);
...@@ -2834,7 +2896,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -2834,7 +2896,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2834fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {2896fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2835 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2897 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2836 const slice_ty = self.air.typeOf(bin_op.lhs);2898 const slice_ty = self.air.typeOf(bin_op.lhs);
2837 const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {2899 const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: {
2838 var buf: Type.SlicePtrFieldTypeBuffer = undefined;2900 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2839 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);2901 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
2840 const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);2902 const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
...@@ -2849,7 +2911,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2849,7 +2911,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2849 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2911 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2850 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2912 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2851 const result: MCValue = if (self.liveness.isUnused(inst))2913 const result: MCValue = if (self.liveness.isUnused(inst))
2852 .dead2914 .unreach
2853 else2915 else
2854 try self.genSliceElemPtr(extra.lhs, extra.rhs);2916 try self.genSliceElemPtr(extra.lhs, extra.rhs);
2855 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2917 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2859,7 +2921,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2859,7 +2921,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2859 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2921 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
28602922
2861 if (self.liveness.isUnused(inst)) {2923 if (self.liveness.isUnused(inst)) {
2862 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2924 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
2863 }2925 }
28642926
2865 const array_ty = self.air.typeOf(bin_op.lhs);2927 const array_ty = self.air.typeOf(bin_op.lhs);
...@@ -2928,7 +2990,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2928,7 +2990,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2928fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {2990fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2929 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2991 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2930 const ptr_ty = self.air.typeOf(bin_op.lhs);2992 const ptr_ty = self.air.typeOf(bin_op.lhs);
2931 const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {2993 const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .unreach else result: {
2932 // this is identical to the `airPtrElemPtr` codegen expect here an2994 // this is identical to the `airPtrElemPtr` codegen expect here an
2933 // additional `mov` is needed at the end to get the actual value2995 // additional `mov` is needed at the end to get the actual value
29342996
...@@ -2971,7 +3033,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2971,7 +3033,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2971 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3033 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2972 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;3034 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
29733035
2974 const result = if (self.liveness.isUnused(inst)) .dead else result: {3036 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
2975 const ptr_ty = self.air.typeOf(extra.lhs);3037 const ptr_ty = self.air.typeOf(extra.lhs);
2976 const ptr = try self.resolveInst(extra.lhs);3038 const ptr = try self.resolveInst(extra.lhs);
2977 const ptr_lock: ?RegisterLock = switch (ptr) {3039 const ptr_lock: ?RegisterLock = switch (ptr) {
...@@ -3041,7 +3103,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -3041,7 +3103,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
3041fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {3103fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
3042 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3104 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3043 if (self.liveness.isUnused(inst)) {3105 if (self.liveness.isUnused(inst)) {
3044 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });3106 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
3045 }3107 }
30463108
3047 const tag_ty = self.air.typeOfIndex(inst);3109 const tag_ty = self.air.typeOfIndex(inst);
...@@ -3094,7 +3156,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -3094,7 +3156,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
3094fn airClz(self: *Self, inst: Air.Inst.Index) !void {3156fn airClz(self: *Self, inst: Air.Inst.Index) !void {
3095 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3157 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3096 const result = result: {3158 const result = result: {
3097 if (self.liveness.isUnused(inst)) break :result .dead;3159 if (self.liveness.isUnused(inst)) break :result .unreach;
30983160
3099 const dst_ty = self.air.typeOfIndex(inst);3161 const dst_ty = self.air.typeOfIndex(inst);
3100 const src_ty = self.air.typeOf(ty_op.operand);3162 const src_ty = self.air.typeOf(ty_op.operand);
...@@ -3163,7 +3225,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3163,7 +3225,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
3163fn airCtz(self: *Self, inst: Air.Inst.Index) !void {3225fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
3164 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3226 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3165 const result = result: {3227 const result = result: {
3166 if (self.liveness.isUnused(inst)) break :result .dead;3228 if (self.liveness.isUnused(inst)) break :result .unreach;
31673229
3168 const dst_ty = self.air.typeOfIndex(inst);3230 const dst_ty = self.air.typeOfIndex(inst);
3169 const src_ty = self.air.typeOf(ty_op.operand);3231 const src_ty = self.air.typeOf(ty_op.operand);
...@@ -3221,7 +3283,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -3221,7 +3283,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
3221fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {3283fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3222 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3284 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3223 const result: MCValue = result: {3285 const result: MCValue = result: {
3224 if (self.liveness.isUnused(inst)) break :result .dead;3286 if (self.liveness.isUnused(inst)) break :result .unreach;
32253287
3226 const src_ty = self.air.typeOf(ty_op.operand);3288 const src_ty = self.air.typeOf(ty_op.operand);
3227 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));3289 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
...@@ -3392,7 +3454,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m...@@ -3392,7 +3454,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
3392fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {3454fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3393 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3455 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3394 const result = result: {3456 const result = result: {
3395 if (self.liveness.isUnused(inst)) break :result .dead;3457 if (self.liveness.isUnused(inst)) break :result .unreach;
33963458
3397 const src_ty = self.air.typeOf(ty_op.operand);3459 const src_ty = self.air.typeOf(ty_op.operand);
3398 const src_mcv = try self.resolveInst(ty_op.operand);3460 const src_mcv = try self.resolveInst(ty_op.operand);
...@@ -3416,7 +3478,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -3416,7 +3478,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3416fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {3478fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
3417 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3479 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3418 const result = result: {3480 const result = result: {
3419 if (self.liveness.isUnused(inst)) break :result .dead;3481 if (self.liveness.isUnused(inst)) break :result .unreach;
34203482
3421 const src_ty = self.air.typeOf(ty_op.operand);3483 const src_ty = self.air.typeOf(ty_op.operand);
3422 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));3484 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
...@@ -3529,7 +3591,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -3529,7 +3591,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
3529fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {3591fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void {
3530 const un_op = self.air.instructions.items(.data)[inst].un_op;3592 const un_op = self.air.instructions.items(.data)[inst].un_op;
3531 const result: MCValue = if (self.liveness.isUnused(inst))3593 const result: MCValue = if (self.liveness.isUnused(inst))
3532 .dead3594 .unreach
3533 else3595 else
3534 return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch});3596 return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch});
3535 return self.finishAir(inst, result, .{ un_op, .none, .none });3597 return self.finishAir(inst, result, .{ un_op, .none, .none });
...@@ -3564,10 +3626,7 @@ fn reuseOperand(...@@ -3564,10 +3626,7 @@ fn reuseOperand(
35643626
3565 // Prevent the operand deaths processing code from deallocating it.3627 // Prevent the operand deaths processing code from deallocating it.
3566 self.liveness.clearOperandDeath(inst, op_index);3628 self.liveness.clearOperandDeath(inst, op_index);
35673629 if (self.getResolvedInstValue(Air.refToIndex(operand).?)) |tracking| tracking.reuse(self);
3568 // That makes us responsible for doing the rest of the stuff that processDeath would have done.
3569 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
3570 branch.inst_table.putAssumeCapacity(Air.refToIndex(operand).?, .dead);
35713630
3572 return true;3631 return true;
3573}3632}
...@@ -3709,7 +3768,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3709,7 +3768,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
37093768
3710 const ptr = try self.resolveInst(ty_op.operand);3769 const ptr = try self.resolveInst(ty_op.operand);
3711 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();3770 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();
3712 if (self.liveness.isUnused(inst) and !is_volatile) break :result .dead;3771 if (self.liveness.isUnused(inst) and !is_volatile) break :result .unreach;
37133772
3714 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))3773 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))
3715 // The MCValue that holds the pointer can be re-used as the value.3774 // The MCValue that holds the pointer can be re-used as the value.
...@@ -4008,7 +4067,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {...@@ -4008,7 +4067,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
40084067
4009fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {4068fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
4010 if (self.liveness.isUnused(inst)) {4069 if (self.liveness.isUnused(inst)) {
4011 return MCValue.dead;4070 return MCValue.unreach;
4012 }4071 }
40134072
4014 const mcv = try self.resolveInst(operand);4073 const mcv = try self.resolveInst(operand);
...@@ -4077,7 +4136,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32...@@ -4077,7 +4136,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
4077fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {4136fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4078 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;4137 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4079 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;4138 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
4080 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4139 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
4081 const operand = extra.struct_operand;4140 const operand = extra.struct_operand;
4082 const index = extra.field_index;4141 const index = extra.field_index;
40834142
...@@ -4226,7 +4285,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -4226,7 +4285,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
4226fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {4285fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
4227 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4286 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4228 const result: MCValue = if (self.liveness.isUnused(inst))4287 const result: MCValue = if (self.liveness.isUnused(inst))
4229 .dead4288 .unreach
4230 else4289 else
4231 return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch});4290 return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch});
4232 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4291 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -5449,7 +5508,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -5449,7 +5508,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
5449 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index);5508 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index);
54505509
5451 const result: MCValue = result: {5510 const result: MCValue = result: {
5452 if (self.liveness.isUnused(inst)) break :result .dead;5511 if (self.liveness.isUnused(inst)) break :result .unreach;
54535512
5454 const dst_mcv: MCValue = switch (mcv) {5513 const dst_mcv: MCValue = switch (mcv) {
5455 .register => |reg| blk: {5514 .register => |reg| blk: {
...@@ -5541,7 +5600,7 @@ fn airBreakpoint(self: *Self) !void {...@@ -5541,7 +5600,7 @@ fn airBreakpoint(self: *Self) !void {
5541}5600}
55425601
5543fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {5602fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
5544 const result = if (self.liveness.isUnused(inst)) .dead else result: {5603 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
5545 const dst_mcv = try self.allocRegOrMem(inst, true);5604 const dst_mcv = try self.allocRegOrMem(inst, true);
5546 try self.setRegOrMem(Type.usize, dst_mcv, .{5605 try self.setRegOrMem(Type.usize, dst_mcv, .{
5547 .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)),5606 .stack_offset = -@as(i32, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)),
...@@ -5552,7 +5611,7 @@ fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {...@@ -5552,7 +5611,7 @@ fn airRetAddr(self: *Self, inst: Air.Inst.Index) !void {
5552}5611}
55535612
5554fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {5613fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
5555 const result = if (self.liveness.isUnused(inst)) .dead else result: {5614 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
5556 const dst_mcv = try self.allocRegOrMem(inst, true);5615 const dst_mcv = try self.allocRegOrMem(inst, true);
5557 try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp });5616 try self.setRegOrMem(Type.usize, dst_mcv, .{ .register = .rbp });
5558 break :result dst_mcv;5617 break :result dst_mcv;
...@@ -5754,7 +5813,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5754,7 +5813,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5754 }5813 }
57555814
5756 const result: MCValue = result: {5815 const result: MCValue = result: {
5757 if (self.liveness.isUnused(inst)) break :result .dead;5816 if (self.liveness.isUnused(inst)) break :result .unreach;
57585817
5759 switch (info.return_value) {5818 switch (info.return_value) {
5760 .register => {5819 .register => {
...@@ -5776,12 +5835,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -5776,12 +5835,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
5776 std.mem.copy(Air.Inst.Ref, buf[1..], args);5835 std.mem.copy(Air.Inst.Ref, buf[1..], args);
5777 return self.finishAir(inst, result, buf);5836 return self.finishAir(inst, result, buf);
5778 }5837 }
5779 var bt = try self.iterateBigTomb(inst, 1 + args.len);5838 var bt = self.liveness.iterateBigTomb(inst);
5780 bt.feed(callee);5839 self.feed(&bt, callee);
5781 for (args) |arg| {5840 for (args) |arg| self.feed(&bt, arg);
5782 bt.feed(arg);5841 return self.finishAirResult(inst, result);
5783 }
5784 return bt.finishAir(result);
5785}5842}
57865843
5787fn airRet(self: *Self, inst: Air.Inst.Index) !void {5844fn airRet(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5804,7 +5861,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -5804,7 +5861,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
5804 // which is available if the jump is 127 bytes or less forward.5861 // which is available if the jump is 127 bytes or less forward.
5805 const jmp_reloc = try self.asmJmpReloc(undefined);5862 const jmp_reloc = try self.asmJmpReloc(undefined);
5806 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);5863 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
5807 return self.finishAir(inst, .dead, .{ un_op, .none, .none });5864 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
5808}5865}
58095866
5810fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {5867fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
...@@ -5834,12 +5891,12 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -5834,12 +5891,12 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
5834 // which is available if the jump is 127 bytes or less forward.5891 // which is available if the jump is 127 bytes or less forward.
5835 const jmp_reloc = try self.asmJmpReloc(undefined);5892 const jmp_reloc = try self.asmJmpReloc(undefined);
5836 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);5893 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
5837 return self.finishAir(inst, .dead, .{ un_op, .none, .none });5894 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
5838}5895}
58395896
5840fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {5897fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
5841 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5898 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5842 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {5899 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
5843 const ty = self.air.typeOf(bin_op.lhs);5900 const ty = self.air.typeOf(bin_op.lhs);
5844 const ty_abi_size = ty.abiSize(self.target.*);5901 const ty_abi_size = ty.abiSize(self.target.*);
5845 const can_reuse = ty_abi_size <= 8;5902 const can_reuse = ty_abi_size <= 8;
...@@ -5904,7 +5961,7 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {...@@ -5904,7 +5961,7 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
59045961
5905fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {5962fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void {
5906 const un_op = self.air.instructions.items(.data)[inst].un_op;5963 const un_op = self.air.instructions.items(.data)[inst].un_op;
5907 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {5964 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
5908 const addr_reg = try self.register_manager.allocReg(null, gp);5965 const addr_reg = try self.register_manager.allocReg(null, gp);
5909 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);5966 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
5910 defer self.register_manager.unlockReg(addr_lock);5967 defer self.register_manager.unlockReg(addr_lock);
...@@ -5993,7 +6050,7 @@ fn genTry(...@@ -5993,7 +6050,7 @@ fn genTry(
5993 try self.genBody(body);6050 try self.genBody(body);
5994 try self.performReloc(reloc);6051 try self.performReloc(reloc);
5995 const result = if (self.liveness.isUnused(inst))6052 const result = if (self.liveness.isUnused(inst))
5996 .dead6053 .unreach
5997 else6054 else
5998 try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, err_union);6055 try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, err_union);
5999 return result;6056 return result;
...@@ -6018,12 +6075,12 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {...@@ -6018,12 +6075,12 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
6018 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;6075 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
6019 // TODO emit debug info for function change6076 // TODO emit debug info for function change
6020 _ = function;6077 _ = function;
6021 return self.finishAir(inst, .dead, .{ .none, .none, .none });6078 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
6022}6079}
60236080
6024fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {6081fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
6025 // TODO emit debug info lexical block6082 // TODO emit debug info lexical block
6026 return self.finishAir(inst, .dead, .{ .none, .none, .none });6083 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
6027}6084}
60286085
6029fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {6086fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
...@@ -6039,7 +6096,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -6039,7 +6096,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
6039 const tag = self.air.instructions.items(.tag)[inst];6096 const tag = self.air.instructions.items(.tag)[inst];
6040 try self.genVarDbgInfo(tag, ty, mcv, name);6097 try self.genVarDbgInfo(tag, ty, mcv, name);
60416098
6042 return self.finishAir(inst, .dead, .{ operand, .none, .none });6099 return self.finishAir(inst, .unreach, .{ operand, .none, .none });
6043}6100}
60446101
6045fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {6102fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
...@@ -6087,60 +6144,31 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6087,60 +6144,31 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
6087 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);6144 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
6088 }6145 }
60896146
6090 // Capture the state of register and stack allocation state so that we can revert to it.6147 const outer_state = try self.saveState();
6091 const saved_state = self.captureState();
6092
6093 {6148 {
6094 try self.branch_stack.append(.{});6149 self.scope_index += 1;
6095 errdefer _ = self.branch_stack.pop();6150 const inner_state = try self.saveState();
60966151
6097 try self.ensureProcessDeathCapacity(liveness_condbr.then_deaths.len);6152 for (liveness_condbr.then_deaths) |operand| self.processDeath(operand);
6098 for (liveness_condbr.then_deaths) |operand| {
6099 self.processDeath(operand);
6100 }
6101 try self.genBody(then_body);6153 try self.genBody(then_body);
6102 }6154 try self.restoreState(inner_state, .{
61036155 .emit_instructions = false,
6104 // Revert to the previous register and stack allocation state.6156 .update_tracking = true,
61056157 .resurrect = true,
6106 var then_branch = self.branch_stack.pop();6158 .close_scope = true,
6107 defer then_branch.deinit(self.gpa);6159 });
6108
6109 self.revertState(saved_state);
6110
6111 try self.performReloc(reloc);
61126160
6113 {6161 try self.performReloc(reloc);
6114 try self.branch_stack.append(.{});
6115 errdefer _ = self.branch_stack.pop();
61166162
6117 try self.ensureProcessDeathCapacity(liveness_condbr.else_deaths.len);6163 for (liveness_condbr.else_deaths) |operand| self.processDeath(operand);
6118 for (liveness_condbr.else_deaths) |operand| {
6119 self.processDeath(operand);
6120 }
6121 try self.genBody(else_body);6164 try self.genBody(else_body);
6122 }6165 }
61236166 try self.restoreState(outer_state, .{
6124 var else_branch = self.branch_stack.pop();6167 .emit_instructions = false,
6125 defer else_branch.deinit(self.gpa);6168 .update_tracking = false,
61266169 .resurrect = false,
6127 // At this point, each branch will possibly have conflicting values for where6170 .close_scope = true,
6128 // each instruction is stored. They agree, however, on which instructions are alive/dead.6171 });
6129 // We use the first ("then") branch as canonical, and here emit
6130 // instructions into the second ("else") branch to make it conform.
6131 // We continue respect the data structure semantic guarantees of the else_branch so
6132 // that we can use all the code emitting abstractions. This is why at the bottom we
6133 // assert that parent_branch.free_registers equals the saved_then_branch.free_registers
6134 // rather than assigning it.
6135 log.debug("airCondBr: %{d}", .{inst});
6136 log.debug("Upper branches:", .{});
6137 for (self.branch_stack.items) |bs| {
6138 log.debug("{}", .{bs.fmtDebug()});
6139 }
6140 log.debug("Then branch: {}", .{then_branch.fmtDebug()});
6141 log.debug("Else branch: {}", .{else_branch.fmtDebug()});
6142
6143 try self.canonicaliseBranches(true, &then_branch, &else_branch, true, true);
61446172
6145 // We already took care of pl_op.operand earlier, so we're going6173 // We already took care of pl_op.operand earlier, so we're going
6146 // to pass .none here6174 // to pass .none here
...@@ -6314,7 +6342,7 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa...@@ -6314,7 +6342,7 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa
63146342
6315fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {6343fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
6316 const un_op = self.air.instructions.items(.data)[inst].un_op;6344 const un_op = self.air.instructions.items(.data)[inst].un_op;
6317 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6345 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6318 const operand = try self.resolveInst(un_op);6346 const operand = try self.resolveInst(un_op);
6319 const ty = self.air.typeOf(un_op);6347 const ty = self.air.typeOf(un_op);
6320 break :result try self.isNull(inst, ty, operand);6348 break :result try self.isNull(inst, ty, operand);
...@@ -6324,7 +6352,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {...@@ -6324,7 +6352,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
63246352
6325fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {6353fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
6326 const un_op = self.air.instructions.items(.data)[inst].un_op;6354 const un_op = self.air.instructions.items(.data)[inst].un_op;
6327 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6355 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6328 const operand = try self.resolveInst(un_op);6356 const operand = try self.resolveInst(un_op);
6329 const ty = self.air.typeOf(un_op);6357 const ty = self.air.typeOf(un_op);
6330 break :result try self.isNullPtr(inst, ty, operand);6358 break :result try self.isNullPtr(inst, ty, operand);
...@@ -6334,7 +6362,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6334,7 +6362,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
63346362
6335fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {6363fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
6336 const un_op = self.air.instructions.items(.data)[inst].un_op;6364 const un_op = self.air.instructions.items(.data)[inst].un_op;
6337 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6365 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6338 const operand = try self.resolveInst(un_op);6366 const operand = try self.resolveInst(un_op);
6339 const ty = self.air.typeOf(un_op);6367 const ty = self.air.typeOf(un_op);
6340 break :result switch (try self.isNull(inst, ty, operand)) {6368 break :result switch (try self.isNull(inst, ty, operand)) {
...@@ -6347,7 +6375,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {...@@ -6347,7 +6375,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
63476375
6348fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {6376fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
6349 const un_op = self.air.instructions.items(.data)[inst].un_op;6377 const un_op = self.air.instructions.items(.data)[inst].un_op;
6350 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6378 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6351 const operand = try self.resolveInst(un_op);6379 const operand = try self.resolveInst(un_op);
6352 const ty = self.air.typeOf(un_op);6380 const ty = self.air.typeOf(un_op);
6353 break :result switch (try self.isNullPtr(inst, ty, operand)) {6381 break :result switch (try self.isNullPtr(inst, ty, operand)) {
...@@ -6360,7 +6388,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6360,7 +6388,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
63606388
6361fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {6389fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
6362 const un_op = self.air.instructions.items(.data)[inst].un_op;6390 const un_op = self.air.instructions.items(.data)[inst].un_op;
6363 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6391 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6364 const operand = try self.resolveInst(un_op);6392 const operand = try self.resolveInst(un_op);
6365 const ty = self.air.typeOf(un_op);6393 const ty = self.air.typeOf(un_op);
6366 break :result try self.isErr(inst, ty, operand);6394 break :result try self.isErr(inst, ty, operand);
...@@ -6372,7 +6400,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6372,7 +6400,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
6372 const un_op = self.air.instructions.items(.data)[inst].un_op;6400 const un_op = self.air.instructions.items(.data)[inst].un_op;
63736401
6374 if (self.liveness.isUnused(inst)) {6402 if (self.liveness.isUnused(inst)) {
6375 return self.finishAir(inst, .dead, .{ un_op, .none, .none });6403 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
6376 }6404 }
63776405
6378 const operand_ptr = try self.resolveInst(un_op);6406 const operand_ptr = try self.resolveInst(un_op);
...@@ -6400,7 +6428,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6400,7 +6428,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
64006428
6401fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {6429fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
6402 const un_op = self.air.instructions.items(.data)[inst].un_op;6430 const un_op = self.air.instructions.items(.data)[inst].un_op;
6403 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {6431 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
6404 const operand = try self.resolveInst(un_op);6432 const operand = try self.resolveInst(un_op);
6405 const ty = self.air.typeOf(un_op);6433 const ty = self.air.typeOf(un_op);
6406 break :result try self.isNonErr(inst, ty, operand);6434 break :result try self.isNonErr(inst, ty, operand);
...@@ -6412,7 +6440,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -6412,7 +6440,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
6412 const un_op = self.air.instructions.items(.data)[inst].un_op;6440 const un_op = self.air.instructions.items(.data)[inst].un_op;
64136441
6414 if (self.liveness.isUnused(inst)) {6442 if (self.liveness.isUnused(inst)) {
6415 return self.finishAir(inst, .dead, .{ un_op, .none, .none });6443 return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
6416 }6444 }
64176445
6418 const operand_ptr = try self.resolveInst(un_op);6446 const operand_ptr = try self.resolveInst(un_op);
...@@ -6445,27 +6473,16 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -6445,27 +6473,16 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
6445 const body = self.air.extra[loop.end..][0..loop.data.body_len];6473 const body = self.air.extra[loop.end..][0..loop.data.body_len];
6446 const jmp_target = @intCast(u32, self.mir_instructions.len);6474 const jmp_target = @intCast(u32, self.mir_instructions.len);
64476475
6448 {6476 self.scope_index += 1;
6449 try self.branch_stack.append(.{});6477 const state = try self.saveState();
6450 errdefer _ = self.branch_stack.pop();
6451
6452 try self.genBody(body);
6453 }
6454
6455 var branch = self.branch_stack.pop();
6456 defer branch.deinit(self.gpa);
6457
6458 log.debug("airLoop: %{d}", .{inst});
6459 log.debug("Upper branches:", .{});
6460 for (self.branch_stack.items) |bs| {
6461 log.debug("{}", .{bs.fmtDebug()});
6462 }
6463 log.debug("Loop branch: {}", .{branch.fmtDebug()});
6464
6465 var dummy_branch = Branch{};
6466 defer dummy_branch.deinit(self.gpa);
6467 try self.canonicaliseBranches(true, &dummy_branch, &branch, true, false);
64686478
6479 try self.genBody(body);
6480 try self.restoreState(state, .{
6481 .emit_instructions = true,
6482 .update_tracking = false,
6483 .resurrect = false,
6484 .close_scope = true,
6485 });
6469 _ = try self.asmJmpReloc(jmp_target);6486 _ = try self.asmJmpReloc(jmp_target);
64706487
6471 return self.finishAirBookkeeping();6488 return self.finishAirBookkeeping();
...@@ -6473,68 +6490,52 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -6473,68 +6490,52 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
64736490
6474fn airBlock(self: *Self, inst: Air.Inst.Index) !void {6491fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
6475 // A block is a setup to be able to jump to the end.6492 // A block is a setup to be able to jump to the end.
6476 const branch_depth = @intCast(u32, self.branch_stack.items.len);6493 const ty = self.air.typeOfIndex(inst);
6477 try self.blocks.putNoClobber(self.gpa, inst, .{ .branch_depth = branch_depth });6494
6495 // Here we use .{ .long = .unreach } to represent a null value so that the
6496 // first break instruction will choose a MCValue for the block result and
6497 // overwrite this field. Following break instructions will use that MCValue
6498 // to put their block results.
6499 self.inst_tracking.putAssumeCapacityNoClobber(inst, .{
6500 .long = .unreach,
6501 .short = if (ty.isNoReturn()) .unreach else .none,
6502 });
6503
6504 self.scope_index += 1;
6505 try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });
6478 defer {6506 defer {
6479 var block_data = self.blocks.fetchRemove(inst).?.value;6507 var block_data = self.blocks.fetchRemove(inst).?.value;
6480 block_data.deinit(self.gpa);6508 block_data.deinit(self.gpa);
6481 }6509 }
64826510
6483 const ty = self.air.typeOfIndex(inst);6511 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6484 const unused = !ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(inst);6512 const extra = self.air.extraData(Air.Block, ty_pl.payload);
64856513 const body = self.air.extra[extra.end..][0..extra.data.body_len];
6486 {6514 try self.genBody(body);
6487 // Here we use `.none` to represent a null value so that the first break
6488 // instruction will choose a MCValue for the block result and overwrite
6489 // this field. Following break instructions will use that MCValue to put
6490 // their block results.
6491 const result: MCValue = if (unused) .dead else .none;
6492 const branch = &self.branch_stack.items[branch_depth - 1];
6493 try branch.inst_table.putNoClobber(self.gpa, inst, result);
6494 }
6495
6496 {
6497 try self.branch_stack.append(.{});
6498 errdefer _ = self.branch_stack.pop();
6499
6500 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6501 const extra = self.air.extraData(Air.Block, ty_pl.payload);
6502 const body = self.air.extra[extra.end..][0..extra.data.body_len];
6503 try self.genBody(body);
6504 }
65056515
6516 const tracking = self.inst_tracking.getPtr(inst).?;
6506 const block_data = self.blocks.getPtr(inst).?;6517 const block_data = self.blocks.getPtr(inst).?;
6507 const target_branch = self.branch_stack.pop();6518 if (tracking.short != .unreach) try self.restoreState(block_data.state, .{
65086519 .emit_instructions = false,
6509 log.debug("airBlock: %{d}", .{inst});6520 .update_tracking = true,
6510 log.debug("Upper branches:", .{});6521 .resurrect = false,
6511 for (self.branch_stack.items) |bs| {6522 .close_scope = true,
6512 log.debug("{}", .{bs.fmtDebug()});6523 });
6513 }
6514 log.debug("Block branch: {}", .{block_data.branch.fmtDebug()});
6515 log.debug("Target branch: {}", .{target_branch.fmtDebug()});
6516
6517 try self.canonicaliseBranches(true, &block_data.branch, &target_branch, false, false);
6518
6519 for (block_data.relocs.items) |reloc| try self.performReloc(reloc);6524 for (block_data.relocs.items) |reloc| try self.performReloc(reloc);
65206525
6521 const result = if (unused) .dead else self.getResolvedInstValue(inst).?.*;6526 if (self.liveness.isUnused(inst)) tracking.die(self);
6522 self.getValue(result, inst);6527 self.getValue(tracking.short, inst);
6523 self.finishAirBookkeeping();6528 self.finishAirBookkeeping();
6524}6529}
65256530
6526fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {6531fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
6527 const pl_op = self.air.instructions.items(.data)[inst].pl_op;6532 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6528 const condition = try self.resolveInst(pl_op.operand);6533 const condition = try self.resolveInst(pl_op.operand);
6529 const condition_ty = self.air.typeOf(pl_op.operand);6534 const condition_ty = self.air.typeOf(pl_op.operand);
6530 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);6535 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
6531 var extra_index: usize = switch_br.end;6536 var extra_index: usize = switch_br.end;
6532 var case_i: u32 = 0;6537 var case_i: u32 = 0;
6533 const liveness = try self.liveness.getSwitchBr(6538 const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.data.cases_len + 1);
6534 self.gpa,
6535 inst,
6536 switch_br.data.cases_len + 1,
6537 );
6538 defer self.gpa.free(liveness.deaths);6539 defer self.gpa.free(liveness.deaths);
65396540
6540 // If the condition dies here in this switch instruction, process6541 // If the condition dies here in this switch instruction, process
...@@ -6544,186 +6545,64 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -6544,186 +6545,64 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
6544 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);6545 if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst);
6545 }6546 }
65466547
6547 log.debug("airSwitch: %{d}", .{inst});6548 const outer_state = try self.saveState();
6548 log.debug("Upper branches:", .{});6549 {
6549 for (self.branch_stack.items) |bs| {6550 self.scope_index += 1;
6550 log.debug("{}", .{bs.fmtDebug()});6551 const inner_state = try self.saveState();
6551 }6552
65526553 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
6553 var prev_branch: ?Branch = null;6554 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
6554 defer if (prev_branch) |*branch| branch.deinit(self.gpa);6555 const items = @ptrCast(
65556556 []const Air.Inst.Ref,
6556 // Capture the state of register and stack allocation state so that we can revert to it.6557 self.air.extra[case.end..][0..case.data.items_len],
6557 const saved_state = self.captureState();6558 );
65586559 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
6559 const cases_len = switch_br.data.cases_len + @boolToInt(switch_br.data.else_body_len > 0);6560 extra_index = case.end + items.len + case_body.len;
6560 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
6561 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
6562 const items = @ptrCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]);
6563 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
6564 extra_index = case.end + items.len + case_body.len;
6565
6566 // Revert to the previous register and stack allocation state.
6567 if (prev_branch) |_| self.revertState(saved_state);
6568
6569 var relocs = try self.gpa.alloc(u32, items.len);
6570 defer self.gpa.free(relocs);
6571
6572 for (items, relocs) |item, *reloc| {
6573 try self.spillEflagsIfOccupied();
6574 const item_mcv = try self.resolveInst(item);
6575 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
6576 reloc.* = try self.asmJccReloc(undefined, .ne);
6577 }
65786561
6579 {6562 var relocs = try self.gpa.alloc(u32, items.len);
6580 if (cases_len > 1) try self.branch_stack.append(.{});6563 defer self.gpa.free(relocs);
6581 errdefer _ = if (cases_len > 1) self.branch_stack.pop();
65826564
6583 try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len);6565 for (items, relocs) |item, *reloc| {
6584 for (liveness.deaths[case_i]) |operand| {6566 try self.spillEflagsIfOccupied();
6585 self.processDeath(operand);6567 const item_mcv = try self.resolveInst(item);
6568 try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv);
6569 reloc.* = try self.asmJccReloc(undefined, .ne);
6586 }6570 }
65876571
6588 try self.genBody(case_body);6572 for (liveness.deaths[case_i]) |operand| self.processDeath(operand);
6589 }
65906573
6591 // Consolidate returned MCValues between prongs like we do in airCondBr.6574 try self.genBody(case_body);
6592 if (cases_len > 1) {6575 if (case_i < switch_br.data.cases_len - 1 or switch_br.data.else_body_len > 0)
6593 var case_branch = self.branch_stack.pop();6576 try self.restoreState(inner_state, .{
6594 errdefer case_branch.deinit(self.gpa);6577 .emit_instructions = false,
6578 .update_tracking = true,
6579 .resurrect = true,
6580 .close_scope = true,
6581 });
65956582
6596 log.debug("Case-{d} branch: {}", .{ case_i, case_branch.fmtDebug() });6583 for (relocs) |reloc| try self.performReloc(reloc);
6597 const final = case_i == cases_len - 1;
6598 if (prev_branch) |*canon_branch| {
6599 try self.canonicaliseBranches(final, canon_branch, &case_branch, true, true);
6600 canon_branch.deinit(self.gpa);
6601 }
6602 prev_branch = case_branch;
6603 }6584 }
66046585
6605 for (relocs) |reloc| try self.performReloc(reloc);6586 if (switch_br.data.else_body_len > 0) {
6606 }6587 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
6607
6608 if (switch_br.data.else_body_len > 0) {
6609 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
6610
6611 // Revert to the previous register and stack allocation state.
6612 if (prev_branch) |_| self.revertState(saved_state);
6613
6614 {
6615 if (cases_len > 1) try self.branch_stack.append(.{});
6616 errdefer _ = if (cases_len > 1) self.branch_stack.pop();
66176588
6618 const else_deaths = liveness.deaths.len - 1;6589 const else_deaths = liveness.deaths.len - 1;
6619 try self.ensureProcessDeathCapacity(liveness.deaths[else_deaths].len);6590 for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand);
6620 for (liveness.deaths[else_deaths]) |operand| {
6621 self.processDeath(operand);
6622 }
66236591
6624 try self.genBody(else_body);6592 try self.genBody(else_body);
6625 }6593 }
6626
6627 // Consolidate returned MCValues between a prong and the else branch like we do in airCondBr.
6628 if (cases_len > 1) {
6629 var else_branch = self.branch_stack.pop();
6630 errdefer else_branch.deinit(self.gpa);
6631
6632 log.debug("Else branch: {}", .{else_branch.fmtDebug()});
6633 if (prev_branch) |*canon_branch| {
6634 try self.canonicaliseBranches(true, canon_branch, &else_branch, true, true);
6635 canon_branch.deinit(self.gpa);
6636 }
6637 prev_branch = else_branch;
6638 }
6639 }6594 }
6595 try self.restoreState(outer_state, .{
6596 .emit_instructions = false,
6597 .update_tracking = false,
6598 .resurrect = false,
6599 .close_scope = true,
6600 });
66406601
6641 // We already took care of pl_op.operand earlier, so we're going to pass .none here6602 // We already took care of pl_op.operand earlier, so we're going to pass .none here
6642 return self.finishAir(inst, .unreach, .{ .none, .none, .none });6603 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
6643}6604}
66446605
6645fn canonicaliseBranches(
6646 self: *Self,
6647 update_parent: bool,
6648 canon_branch: *Branch,
6649 target_branch: *const Branch,
6650 comptime set_values: bool,
6651 comptime assert_same_deaths: bool,
6652) !void {
6653 var hazard_map = std.AutoHashMap(MCValue, void).init(self.gpa);
6654 defer hazard_map.deinit();
6655
6656 const parent_branch =
6657 if (update_parent) &self.branch_stack.items[self.branch_stack.items.len - 1] else undefined;
6658
6659 if (update_parent) try self.ensureProcessDeathCapacity(target_branch.inst_table.count());
6660 var target_it = target_branch.inst_table.iterator();
6661 while (target_it.next()) |target_entry| {
6662 const target_key = target_entry.key_ptr.*;
6663 const target_value = target_entry.value_ptr.*;
6664 const canon_mcv = if (canon_branch.inst_table.fetchSwapRemove(target_key)) |canon_entry| blk: {
6665 // The instruction's MCValue is overridden in both branches.
6666 if (target_value == .dead) {
6667 if (update_parent) {
6668 parent_branch.inst_table.putAssumeCapacity(target_key, .dead);
6669 }
6670 if (assert_same_deaths) assert(canon_entry.value == .dead);
6671 continue;
6672 }
6673 if (update_parent) {
6674 parent_branch.inst_table.putAssumeCapacity(target_key, canon_entry.value);
6675 }
6676 break :blk canon_entry.value;
6677 } else blk: {
6678 if (target_value == .dead) {
6679 if (update_parent) {
6680 parent_branch.inst_table.putAssumeCapacity(target_key, .dead);
6681 }
6682 continue;
6683 }
6684 // The instruction is only overridden in the else branch.
6685 // If integer overflow occurs, the question is: why wasn't the instruction marked dead?
6686 break :blk self.getResolvedInstValue(target_key).?.*;
6687 };
6688 log.debug("consolidating target_entry %{d} {}=>{}", .{ target_key, target_value, canon_mcv });
6689 // TODO handle the case where the destination stack offset / register has something
6690 // going on there.
6691 assert(!hazard_map.contains(target_value));
6692 try hazard_map.putNoClobber(canon_mcv, {});
6693 if (set_values) {
6694 try self.setRegOrMem(self.air.typeOfIndex(target_key), canon_mcv, target_value);
6695 } else self.getValue(canon_mcv, target_key);
6696 self.freeValue(target_value);
6697 // TODO track the new register / stack allocation
6698 }
6699
6700 if (update_parent) try self.ensureProcessDeathCapacity(canon_branch.inst_table.count());
6701 var canon_it = canon_branch.inst_table.iterator();
6702 while (canon_it.next()) |canon_entry| {
6703 const canon_key = canon_entry.key_ptr.*;
6704 const canon_value = canon_entry.value_ptr.*;
6705 // We already deleted the items from this table that matched the target_branch.
6706 // So these are all instructions that are only overridden in the canon branch.
6707 const parent_mcv =
6708 if (canon_value != .dead) self.getResolvedInstValue(canon_key).?.* else undefined;
6709 if (canon_value != .dead) {
6710 log.debug("consolidating canon_entry %{d} {}=>{}", .{ canon_key, parent_mcv, canon_value });
6711 // TODO handle the case where the destination stack offset / register has something
6712 // going on there.
6713 assert(!hazard_map.contains(parent_mcv));
6714 try hazard_map.putNoClobber(canon_value, {});
6715 if (set_values) {
6716 try self.setRegOrMem(self.air.typeOfIndex(canon_key), canon_value, parent_mcv);
6717 } else self.getValue(canon_value, canon_key);
6718 self.freeValue(parent_mcv);
6719 // TODO track the new register / stack allocation
6720 }
6721 if (update_parent) {
6722 parent_branch.inst_table.putAssumeCapacity(canon_key, canon_value);
6723 }
6724 }
6725}
6726
6727fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {6606fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
6728 const next_inst = @intCast(u32, self.mir_instructions.len);6607 const next_inst = @intCast(u32, self.mir_instructions.len);
6729 switch (self.mir_instructions.items(.tag)[reloc]) {6608 switch (self.mir_instructions.items(.tag)[reloc]) {
...@@ -6739,69 +6618,38 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {...@@ -6739,69 +6618,38 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
67396618
6740fn airBr(self: *Self, inst: Air.Inst.Index) !void {6619fn airBr(self: *Self, inst: Air.Inst.Index) !void {
6741 const br = self.air.instructions.items(.data)[inst].br;6620 const br = self.air.instructions.items(.data)[inst].br;
6742 const block = br.block_inst;6621 const block_ty = self.air.typeOfIndex(br.block_inst);
67436622 const block_unused =
6744 // The first break instruction encounters `.none` here and chooses a6623 !block_ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(br.block_inst);
6745 // machine code value for the block result, populating this field.
6746 // Following break instructions encounter that value and use it for
6747 // the location to store their block results.
6748 if (self.getResolvedInstValue(block)) |dst_mcv| {
6749 const src_mcv = try self.resolveInst(br.operand);
6750 switch (dst_mcv.*) {
6751 .none => {
6752 const result = result: {
6753 if (self.reuseOperand(inst, br.operand, 0, src_mcv)) break :result src_mcv;
6754
6755 const new_mcv = try self.allocRegOrMem(block, true);
6756 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, src_mcv);
6757 break :result new_mcv;
6758 };
6759 dst_mcv.* = result;
6760 self.freeValue(result);
6761 },
6762 else => try self.setRegOrMem(self.air.typeOfIndex(block), dst_mcv.*, src_mcv),
6763 }
6764 }
67656624
6766 // Process operand death early so that it is properly accounted for in the Branch below.6625 // Process operand death early so that it is properly accounted for in the State below.
6626 const src_mcv = try self.resolveInst(br.operand);
6767 if (self.liveness.operandDies(inst, 0)) {6627 if (self.liveness.operandDies(inst, 0)) {
6768 if (Air.refToIndex(br.operand)) |op_inst| self.processDeath(op_inst);6628 if (Air.refToIndex(br.operand)) |op_inst| self.processDeath(op_inst);
6769 }6629 }
67706630
6771 const block_data = self.blocks.getPtr(block).?;6631 const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
6772 {6632 const block_data = self.blocks.getPtr(br.block_inst).?;
6773 var branch = Branch{};6633 if (block_tracking.long == .unreach) {
6774 errdefer branch.deinit(self.gpa);6634 const result = result: {
67756635 if (block_unused) break :result .none;
6776 var branch_i = self.branch_stack.items.len - 1;6636 if (self.reuseOperand(inst, br.operand, 0, src_mcv)) break :result src_mcv;
6777 while (branch_i >= block_data.branch_depth) : (branch_i -= 1) {
6778 const table = &self.branch_stack.items[branch_i].inst_table;
6779 try branch.inst_table.ensureUnusedCapacity(self.gpa, table.count());
6780 var it = table.iterator();
6781 while (it.next()) |entry| {
6782 // This loop could be avoided by tracking inst depth, which
6783 // will be needed later anyway for reusing loop deaths.
6784 var parent_branch_i = block_data.branch_depth - 1;
6785 while (parent_branch_i > 0) : (parent_branch_i -= 1) {
6786 const parent_table = &self.branch_stack.items[parent_branch_i].inst_table;
6787 if (parent_table.contains(entry.key_ptr.*)) break;
6788 } else continue;
6789 const gop = branch.inst_table.getOrPutAssumeCapacity(entry.key_ptr.*);
6790 if (!gop.found_existing) gop.value_ptr.* = entry.value_ptr.*;
6791 }
6792 }
67936637
6794 log.debug("airBr: %{d}", .{inst});6638 const new_mcv = try self.allocRegOrMem(br.block_inst, true);
6795 log.debug("Upper branches:", .{});6639 try self.setRegOrMem(block_ty, new_mcv, src_mcv);
6796 for (self.branch_stack.items) |bs| {6640 break :result new_mcv;
6797 log.debug("{}", .{bs.fmtDebug()});6641 };
6798 }6642 block_tracking.* = InstTracking.init(result);
6799 log.debug("Prev branch: {}", .{block_data.branch.fmtDebug()});6643 try self.saveRetroactiveState(&block_data.state, true);
6800 log.debug("Cur branch: {}", .{branch.fmtDebug()});6644 self.freeValue(result);
68016645 } else {
6802 try self.canonicaliseBranches(false, &block_data.branch, &branch, true, false);6646 if (!block_unused) try self.setRegOrMem(block_ty, block_tracking.short, src_mcv);
6803 block_data.branch.deinit(self.gpa);6647 try self.restoreState(block_data.state, .{
6804 block_data.branch = branch;6648 .emit_instructions = true,
6649 .update_tracking = false,
6650 .resurrect = false,
6651 .close_scope = false,
6652 });
6805 }6653 }
68066654
6807 // Emit a jump with a relocation. It will be patched up after the block ends.6655 // Emit a jump with a relocation. It will be patched up after the block ends.
...@@ -6825,7 +6673,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6825,7 +6673,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6825 extra_i += inputs.len;6673 extra_i += inputs.len;
68266674
6827 var result: MCValue = .none;6675 var result: MCValue = .none;
6828 if (!is_volatile and self.liveness.isUnused(inst)) result = .dead else {6676 if (!is_volatile and self.liveness.isUnused(inst)) result = .unreach else {
6829 var args = std.StringArrayHashMap(MCValue).init(self.gpa);6677 var args = std.StringArrayHashMap(MCValue).init(self.gpa);
6830 try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);6678 try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);
6831 defer {6679 defer {
...@@ -7051,25 +6899,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -7051,25 +6899,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
7051 std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs);6899 std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs);
7052 return self.finishAir(inst, result, buf);6900 return self.finishAir(inst, result, buf);
7053 }6901 }
7054 var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len);6902 var bt = self.liveness.iterateBigTomb(inst);
7055 for (outputs) |output| {6903 for (outputs) |output| if (output != .none) self.feed(&bt, output);
7056 if (output == .none) continue;6904 for (inputs) |input| self.feed(&bt, input);
70576905 return self.finishAirResult(inst, result);
7058 bt.feed(output);
7059 }
7060 for (inputs) |input| {
7061 bt.feed(input);
7062 }
7063 return bt.finishAir(result);
7064}
7065
7066fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
7067 try self.ensureProcessDeathCapacity(operand_count + 1);
7068 return BigTomb{
7069 .function = self,
7070 .inst = inst,
7071 .lbt = self.liveness.iterateBigTomb(inst),
7072 };
7073}6906}
70746907
7075/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.6908/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
...@@ -7951,7 +7784,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -7951,7 +7784,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
79517784
7952fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {7785fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
7953 const un_op = self.air.instructions.items(.data)[inst].un_op;7786 const un_op = self.air.instructions.items(.data)[inst].un_op;
7954 const result = if (self.liveness.isUnused(inst)) .dead else result: {7787 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
7955 const src_mcv = try self.resolveInst(un_op);7788 const src_mcv = try self.resolveInst(un_op);
7956 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;7789 if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
79577790
...@@ -7965,7 +7798,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -7965,7 +7798,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
79657798
7966fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {7799fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
7967 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7800 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7968 const result = if (self.liveness.isUnused(inst)) .dead else result: {7801 const result = if (self.liveness.isUnused(inst)) .unreach else result: {
7969 const operand = try self.resolveInst(ty_op.operand);7802 const operand = try self.resolveInst(ty_op.operand);
7970 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;7803 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
79717804
...@@ -7990,7 +7823,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -7990,7 +7823,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
7990 const ptr = try self.resolveInst(ty_op.operand);7823 const ptr = try self.resolveInst(ty_op.operand);
7991 const array_ty = ptr_ty.childType();7824 const array_ty = ptr_ty.childType();
7992 const array_len = array_ty.arrayLen();7825 const array_len = array_ty.arrayLen();
7993 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {7826 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else blk: {
7994 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));7827 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
7995 try self.genSetStack(ptr_ty, stack_offset, ptr, .{});7828 try self.genSetStack(ptr_ty, stack_offset, ptr, .{});
7996 try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{});7829 try self.genSetStack(Type.u64, stack_offset - 8, .{ .immediate = array_len }, .{});
...@@ -8002,7 +7835,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -8002,7 +7835,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
8002fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {7835fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
8003 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7836 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8004 const result: MCValue = if (self.liveness.isUnused(inst))7837 const result: MCValue = if (self.liveness.isUnused(inst))
8005 .dead7838 .unreach
8006 else7839 else
8007 return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch});7840 return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch});
8008 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });7841 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -8011,7 +7844,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -8011,7 +7844,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
8011fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {7844fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
8012 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7845 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8013 if (self.liveness.isUnused(inst))7846 if (self.liveness.isUnused(inst))
8014 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });7847 return self.finishAir(inst, .unreach, .{ ty_op.operand, .none, .none });
80157848
8016 const src_ty = self.air.typeOf(ty_op.operand);7849 const src_ty = self.air.typeOf(ty_op.operand);
8017 const dst_ty = self.air.typeOfIndex(inst);7850 const dst_ty = self.air.typeOfIndex(inst);
...@@ -8113,7 +7946,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -8113,7 +7946,7 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
8113 }7946 }
81147947
8115 const result: MCValue = result: {7948 const result: MCValue = result: {
8116 if (self.liveness.isUnused(inst)) break :result .dead;7949 if (self.liveness.isUnused(inst)) break :result .unreach;
81177950
8118 if (val_abi_size <= 8) {7951 if (val_abi_size <= 8) {
8119 self.eflags_inst = inst;7952 self.eflags_inst = inst;
...@@ -8211,7 +8044,7 @@ fn atomicOp(...@@ -8211,7 +8044,7 @@ fn atomicOp(
8211 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8044 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8212 } } });8045 } } });
82138046
8214 return if (unused) .none else dst_mcv;8047 return if (unused) .unreach else dst_mcv;
8215 },8048 },
8216 .loop => _ = if (val_abi_size <= 8) {8049 .loop => _ = if (val_abi_size <= 8) {
8217 const tmp_reg = try self.register_manager.allocReg(null, gp);8050 const tmp_reg = try self.register_manager.allocReg(null, gp);
...@@ -8284,7 +8117,7 @@ fn atomicOp(...@@ -8284,7 +8117,7 @@ fn atomicOp(
8284 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),8117 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
8285 } } });8118 } } });
8286 _ = try self.asmJccReloc(loop, .ne);8119 _ = try self.asmJccReloc(loop, .ne);
8287 return if (unused) .none else .{ .register = .rax };8120 return if (unused) .unreach else .{ .register = .rax };
8288 } else {8121 } else {
8289 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{8122 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
8290 .base = ptr_mem.sib.base,8123 .base = ptr_mem.sib.base,
...@@ -8353,7 +8186,7 @@ fn atomicOp(...@@ -8353,7 +8186,7 @@ fn atomicOp(
8353 } });8186 } });
8354 _ = try self.asmJccReloc(loop, .ne);8187 _ = try self.asmJccReloc(loop, .ne);
83558188
8356 if (unused) return .none;8189 if (unused) return .unreach;
8357 const dst_mcv = try self.allocTempRegOrMem(val_ty, false);8190 const dst_mcv = try self.allocTempRegOrMem(val_ty, false);
8358 try self.asmMemoryRegister(8191 try self.asmMemoryRegister(
8359 .mov,8192 .mov,
...@@ -8396,7 +8229,7 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -8396,7 +8229,7 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
8396 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;8229 const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
83978230
8398 const result: MCValue = result: {8231 const result: MCValue = result: {
8399 if (self.liveness.isUnused(inst)) break :result .dead;8232 if (self.liveness.isUnused(inst)) break :result .unreach;
84008233
8401 const ptr_ty = self.air.typeOf(atomic_load.ptr);8234 const ptr_ty = self.air.typeOf(atomic_load.ptr);
8402 const ptr_mcv = try self.resolveInst(atomic_load.ptr);8235 const ptr_mcv = try self.resolveInst(atomic_load.ptr);
...@@ -8458,7 +8291,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {...@@ -8458,7 +8291,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
84588291
8459 try self.genInlineMemset(dst_ptr, src_val, len, .{});8292 try self.genInlineMemset(dst_ptr, src_val, len, .{});
84608293
8461 return self.finishAir(inst, .none, .{ pl_op.operand, extra.lhs, extra.rhs });8294 return self.finishAir(inst, .unreach, .{ pl_op.operand, extra.lhs, extra.rhs });
8462}8295}
84638296
8464fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {8297fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
...@@ -8488,13 +8321,13 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {...@@ -8488,13 +8321,13 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
84888321
8489 try self.genInlineMemcpy(dst_ptr, src_ptr, len, .{});8322 try self.genInlineMemcpy(dst_ptr, src_ptr, len, .{});
84908323
8491 return self.finishAir(inst, .none, .{ pl_op.operand, extra.lhs, extra.rhs });8324 return self.finishAir(inst, .unreach, .{ pl_op.operand, extra.lhs, extra.rhs });
8492}8325}
84938326
8494fn airTagName(self: *Self, inst: Air.Inst.Index) !void {8327fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
8495 const un_op = self.air.instructions.items(.data)[inst].un_op;8328 const un_op = self.air.instructions.items(.data)[inst].un_op;
8496 const operand = try self.resolveInst(un_op);8329 const operand = try self.resolveInst(un_op);
8497 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {8330 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else {
8498 _ = operand;8331 _ = operand;
8499 return self.fail("TODO implement airTagName for x86_64", .{});8332 return self.fail("TODO implement airTagName for x86_64", .{});
8500 };8333 };
...@@ -8503,7 +8336,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8503,7 +8336,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
85038336
8504fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {8337fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
8505 const un_op = self.air.instructions.items(.data)[inst].un_op;8338 const un_op = self.air.instructions.items(.data)[inst].un_op;
8506 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {8339 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
8507 const err_ty = self.air.typeOf(un_op);8340 const err_ty = self.air.typeOf(un_op);
8508 const err_mcv = try self.resolveInst(un_op);8341 const err_mcv = try self.resolveInst(un_op);
8509 const err_reg = try self.copyToTmpRegister(err_ty, err_mcv);8342 const err_reg = try self.copyToTmpRegister(err_ty, err_mcv);
...@@ -8589,26 +8422,26 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {...@@ -8589,26 +8422,26 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void {
85898422
8590fn airSplat(self: *Self, inst: Air.Inst.Index) !void {8423fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
8591 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8424 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8592 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSplat for x86_64", .{});8425 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSplat for x86_64", .{});
8593 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });8426 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
8594}8427}
85958428
8596fn airSelect(self: *Self, inst: Air.Inst.Index) !void {8429fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
8597 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8430 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
8598 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;8431 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
8599 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for x86_64", .{});8432 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airSelect for x86_64", .{});
8600 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });8433 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
8601}8434}
86028435
8603fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {8436fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
8604 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8437 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8605 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for x86_64", .{});8438 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airShuffle for x86_64", .{});
8606 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });8439 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
8607}8440}
86088441
8609fn airReduce(self: *Self, inst: Air.Inst.Index) !void {8442fn airReduce(self: *Self, inst: Air.Inst.Index) !void {
8610 const reduce = self.air.instructions.items(.data)[inst].reduce;8443 const reduce = self.air.instructions.items(.data)[inst].reduce;
8611 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airReduce for x86_64", .{});8444 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else return self.fail("TODO implement airReduce for x86_64", .{});
8612 return self.finishAir(inst, result, .{ reduce.operand, .none, .none });8445 return self.finishAir(inst, result, .{ reduce.operand, .none, .none });
8613}8446}
86148447
...@@ -8620,7 +8453,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -8620,7 +8453,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
8620 const abi_size = @intCast(u32, result_ty.abiSize(self.target.*));8453 const abi_size = @intCast(u32, result_ty.abiSize(self.target.*));
8621 const abi_align = result_ty.abiAlignment(self.target.*);8454 const abi_align = result_ty.abiAlignment(self.target.*);
8622 const result: MCValue = res: {8455 const result: MCValue = res: {
8623 if (self.liveness.isUnused(inst)) break :res MCValue.dead;8456 if (self.liveness.isUnused(inst)) break :res MCValue.unreach;
8624 switch (result_ty.zigTypeTag()) {8457 switch (result_ty.zigTypeTag()) {
8625 .Struct => {8458 .Struct => {
8626 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));8459 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
...@@ -8739,18 +8572,16 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -8739,18 +8572,16 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
8739 std.mem.copy(Air.Inst.Ref, &buf, elements);8572 std.mem.copy(Air.Inst.Ref, &buf, elements);
8740 return self.finishAir(inst, result, buf);8573 return self.finishAir(inst, result, buf);
8741 }8574 }
8742 var bt = try self.iterateBigTomb(inst, elements.len);8575 var bt = self.liveness.iterateBigTomb(inst);
8743 for (elements) |elem| {8576 for (elements) |elem| self.feed(&bt, elem);
8744 bt.feed(elem);8577 return self.finishAirResult(inst, result);
8745 }
8746 return bt.finishAir(result);
8747}8578}
87488579
8749fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {8580fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
8750 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;8581 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
8751 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;8582 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
8752 const result: MCValue = res: {8583 const result: MCValue = res: {
8753 if (self.liveness.isUnused(inst)) break :res MCValue.dead;8584 if (self.liveness.isUnused(inst)) break :res MCValue.unreach;
8754 return self.fail("TODO implement airAggregateInit for x86_64", .{});8585 return self.fail("TODO implement airAggregateInit for x86_64", .{});
8755 };8586 };
8756 return self.finishAir(inst, result, .{ extra.init, .none, .none });8587 return self.finishAir(inst, result, .{ extra.init, .none, .none });
...@@ -8758,63 +8589,57 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -8758,63 +8589,57 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
87588589
8759fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {8590fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
8760 const prefetch = self.air.instructions.items(.data)[inst].prefetch;8591 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
8761 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });8592 return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none });
8762}8593}
87638594
8764fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {8595fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
8765 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8596 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
8766 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;8597 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
8767 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else {8598 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else {
8768 return self.fail("TODO implement airMulAdd for x86_64", .{});8599 return self.fail("TODO implement airMulAdd for x86_64", .{});
8769 };8600 };
8770 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });8601 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
8771}8602}
87728603
8773fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {8604fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
8774 // First section of indexes correspond to a set number of constant values.8605 const ty = self.air.typeOf(ref);
8775 const ref_int = @enumToInt(inst);
8776 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
8777 const tv = Air.Inst.Ref.typed_value_map[ref_int];
8778 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
8779 return .none;
8780 }
8781 return self.genTypedValue(tv);
8782 }
87838606
8784 // If the type has no codegen bits, no need to store it.8607 // If the type has no codegen bits, no need to store it.
8785 const inst_ty = self.air.typeOf(inst);8608 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isError()) return .none;
8786 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())8609
8787 return .none;8610 if (Air.refToIndex(ref)) |inst| {
87888611 const mcv = switch (self.air.instructions.items(.tag)[inst]) {
8789 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);8612 .constant => tracking: {
8790 switch (self.air.instructions.items(.tag)[inst_index]) {8613 const gop = try self.const_tracking.getOrPut(self.gpa, inst);
8791 .constant => {8614 if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{
8792 // Constants have static lifetimes, so they are always memoized in the outer most table.8615 .ty = ty,
8793 const branch = &self.branch_stack.items[0];8616 .val = self.air.value(ref).?,
8794 const gop = try branch.inst_table.getOrPut(self.gpa, inst_index);8617 }));
8795 if (!gop.found_existing) {8618 break :tracking gop.value_ptr;
8796 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;8619 },
8797 gop.value_ptr.* = try self.genTypedValue(.{8620 .const_ty => unreachable,
8798 .ty = inst_ty,8621 else => self.inst_tracking.getPtr(inst).?,
8799 .val = self.air.values[ty_pl.payload],8622 }.short;
8800 });8623 switch (mcv) {
8801 }8624 .none, .unreach => unreachable,
8802 return gop.value_ptr.*;8625 else => return mcv,
8803 },8626 }
8804 .const_ty => unreachable,
8805 else => return self.getResolvedInstValue(inst_index).?.*,
8806 }8627 }
8628
8629 return self.genTypedValue(.{ .ty = ty, .val = self.air.value(ref).? });
8807}8630}
88088631
8809fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?*MCValue {8632fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) ?*InstTracking {
8810 // Treat each stack item as a "layer" on top of the previous one.8633 const tracking = switch (self.air.instructions.items(.tag)[inst]) {
8811 var i: usize = self.branch_stack.items.len;8634 .constant => self.const_tracking.getPtr(inst) orelse return null,
8812 while (true) {8635 .const_ty => unreachable,
8813 i -= 1;8636 else => self.inst_tracking.getPtr(inst).?,
8814 if (self.branch_stack.items[i].inst_table.getPtr(inst)) |mcv| {8637 };
8815 return if (mcv.* != .dead) mcv else null;8638 return switch (tracking.short) {
8816 }8639 .unreach => unreachable,
8817 }8640 .dead => null,
8641 else => tracking,
8642 };
8818}8643}
88198644
8820/// If the MCValue is an immediate, and it does not fit within this type,8645/// If the MCValue is an immediate, and it does not fit within this type,
src/register_manager.zig+4
...@@ -95,6 +95,10 @@ pub fn RegisterManager(...@@ -95,6 +95,10 @@ pub fn RegisterManager(
95 return indexOfReg(tracked_registers, reg);95 return indexOfReg(tracked_registers, reg);
96 }96 }
9797
98 pub fn regAtTrackedIndex(index: RegisterBitSet.ShiftInt) Register {
99 return tracked_registers[index];
100 }
101
98 /// Returns true when this register is not tracked102 /// Returns true when this register is not tracked
99 pub fn isRegFree(self: Self, reg: Register) bool {103 pub fn isRegFree(self: Self, reg: Register) bool {
100 const index = indexOfRegIntoTracked(reg) orelse return true;104 const index = indexOfRegIntoTracked(reg) orelse return true;
test/behavior/for.zig-1
...@@ -274,7 +274,6 @@ test "two counters" {...@@ -274,7 +274,6 @@ test "two counters" {
274test "1-based counter and ptr to array" {274test "1-based counter and ptr to array" {
275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
278277
279 var ok: usize = 0;278 var ok: usize = 0;
280279