authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-16 04:00:23+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-20 20:49:34+01:00
log6fc524de4267fce0d381215bfda9c2caca9a4f07
tree6ec94c4c2f4320a0433bedbdbdfd17225f51660f
parent407dc6eee4660bb0744c55f4565be77501ec7d37
signaturelock-open Commit is signed but in an unrecognized format.

cbe: integrate new Liveness behaviour


1 files changed, 121 insertions(+), 406 deletions(-)

src/codegen/c.zig+121-406
......@@ -78,7 +78,6 @@ const LoopDepth = u16;
7878const Local = struct {
7979 cty_idx: CType.Index,
8080 alignas: CType.AlignAs,
81 is_in_clone: bool,
8281
8382 pub fn getType(local: Local) LocalType {
8483 return .{ .cty_idx = local.cty_idx, .alignas = local.alignas };
......@@ -275,16 +274,13 @@ pub const Function = struct {
275274 /// All the locals, to be emitted at the top of the function.
276275 locals: std.ArrayListUnmanaged(Local) = .{},
277276 /// Which locals are available for reuse, based on Type.
278 /// Only locals in the last stack entry are available for reuse,
279 /// other entries will become available on loop exit.
280277 free_locals_map: LocalsMap = .{},
281 is_in_clone: bool = false,
282278 /// Locals which will not be freed by Liveness. This is used after a
283279 /// Function body is lowered in order to make `free_locals_map` have
284280 /// 100% of the locals within so that it can be used to render the block
285281 /// of variable declarations at the top of a function, sorted descending
286282 /// by type alignment.
287 /// The value is whether the alloc is static or not.
283 /// The value is whether the alloc needs to be emitted in the header.
288284 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},
289285 /// Needed for memory used by the keys of free_locals_map entries.
290286 arena: std.heap.ArenaAllocator,
......@@ -302,7 +298,7 @@ pub const Function = struct {
302298 const alignment = 0;
303299 const decl_c_value = try f.allocLocalValue(ty, alignment);
304300 const gpa = f.object.dg.gpa;
305 try f.allocs.put(gpa, decl_c_value.new_local, true);
301 try f.allocs.put(gpa, decl_c_value.new_local, false);
306302 try writer.writeAll("static ");
307303 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
308304 try writer.writeAll(" = ");
......@@ -323,14 +319,15 @@ pub const Function = struct {
323319 };
324320 }
325321
326 /// Skips the reuse logic.
322 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
323 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
324 /// that responsibility lies with the caller.
327325 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
328326 const gpa = f.object.dg.gpa;
329327 const target = f.object.dg.module.getTarget();
330328 try f.locals.append(gpa, .{
331329 .cty_idx = try f.typeToIndex(ty, .complete),
332330 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),
333 .is_in_clone = f.is_in_clone,
334331 });
335332 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
336333 }
......@@ -341,7 +338,8 @@ pub const Function = struct {
341338 return result;
342339 }
343340
344 /// Only allocates the local; does not print anything.
341 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
342 /// not be used for persistent locals (i.e. those in `allocs`).
345343 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
346344 const target = f.object.dg.module.getTarget();
347345 if (f.free_locals_map.getPtr(.{
......@@ -2586,7 +2584,7 @@ pub fn genFunc(f: *Function) !void {
25862584 f.free_locals_map.clearRetainingCapacity();
25872585
25882586 const main_body = f.air.getMainBody();
2589 try genBody(f, main_body);
2587 try genBodyResolveState(f, undefined, &.{}, main_body, false);
25902588
25912589 try o.indent_writer.insertNewline();
25922590
......@@ -2597,8 +2595,8 @@ pub fn genFunc(f: *Function) !void {
25972595 // alignment, descending.
25982596 const free_locals = &f.free_locals_map;
25992597 assert(f.value_map.count() == 0); // there must not be any unfreed locals
2600 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
2601 if (value) continue; // static
2598 for (f.allocs.keys(), f.allocs.values()) |local_index, should_emit| {
2599 if (!should_emit) continue;
26022600 const local = f.locals.items[local_index];
26032601 log.debug("inserting local {d} into free_locals", .{local_index});
26042602 const gop = try free_locals.getOrPut(gpa, local.getType());
......@@ -2715,6 +2713,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
27152713 }
27162714}
27172715
2716/// Generate code for an entire body which ends with a `noreturn` instruction. The states of
2717/// `value_map` and `free_locals_map` are undefined after the generation, and new locals may not
2718/// have been added to `free_locals_map`. For a version of this function that restores this state,
2719/// see `genBodyResolveState`.
27182720fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
27192721 const writer = f.object.writer();
27202722 if (body.len == 0) {
......@@ -2728,10 +2730,69 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
27282730 }
27292731}
27302732
2733/// Generate code for an entire body which ends with a `noreturn` instruction. The states of
2734/// `value_map` and `free_locals_map` are restored to their original values, and any non-allocated
2735/// locals introduced within the body are correctly added to `free_locals_map`. Operands in
2736/// `leading_deaths` have their deaths processed before the body is generated.
2737/// A scope is introduced (using braces) only if `inner` is `false`.
2738/// If `leading_deaths` is empty, `inst` may be `undefined`.
2739fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) error{ AnalysisFail, OutOfMemory }!void {
2740 if (body.len == 0) {
2741 // Don't go to the expense of cloning everything!
2742 if (!inner) try f.object.writer().writeAll("{}");
2743 return;
2744 }
2745
2746 // TODO: we can probably avoid the copies in some other common cases too.
2747
2748 const gpa = f.object.dg.gpa;
2749
2750 // Save the original value_map and free_locals_map so that we can restore them after the body.
2751 var old_value_map = try f.value_map.clone();
2752 defer old_value_map.deinit();
2753 var old_free_locals = try cloneFreeLocalsMap(gpa, &f.free_locals_map);
2754 defer deinitFreeLocalsMap(gpa, &old_free_locals);
2755
2756 // Remember how many locals there were before entering the body so that we can free any that
2757 // were newly introduced. Any new locals must necessarily be logically free after the then
2758 // branch is complete.
2759 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
2760
2761 for (leading_deaths) |death| {
2762 try die(f, inst, Air.indexToRef(death));
2763 }
2764
2765 if (inner) {
2766 try genBodyInner(f, body);
2767 } else {
2768 try genBody(f, body);
2769 }
2770
2771 f.value_map.deinit();
2772 f.value_map = old_value_map.move();
2773 deinitFreeLocalsMap(gpa, &f.free_locals_map);
2774 f.free_locals_map = old_free_locals.move();
2775
2776 // Now, use the lengths we stored earlier to detect any locals the body generated, and free
2777 // them, unless they were used to store allocs.
2778
2779 for (pre_locals_len..f.locals.items.len) |local_i| {
2780 const local_index = @intCast(LocalIndex, local_i);
2781 if (f.allocs.contains(local_index)) {
2782 continue;
2783 }
2784 try freeLocal(f, inst, local_index, 0);
2785 }
2786}
2787
27312788fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
27322789 const air_tags = f.air.instructions.items(.tag);
27332790
27342791 for (body) |inst| {
2792 if (f.liveness.isUnused(inst) and !f.air.mustLower(inst)) {
2793 continue;
2794 }
2795
27352796 const result_value = switch (air_tags[inst]) {
27362797 // zig fmt: off
27372798 .constant => unreachable, // excluded from function bodies
......@@ -3009,11 +3070,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
30093070fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {
30103071 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
30113072
3012 if (f.liveness.isUnused(inst)) {
3013 try reap(f, inst, &.{ty_op.operand});
3014 return .none;
3015 }
3016
30173073 const inst_ty = f.air.typeOfIndex(inst);
30183074 const operand = try f.resolveInst(ty_op.operand);
30193075 try reap(f, inst, &.{ty_op.operand});
......@@ -3032,10 +3088,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
30323088fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
30333089 const inst_ty = f.air.typeOfIndex(inst);
30343090 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3035 const ptr_ty = f.air.typeOf(bin_op.lhs);
3036 if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
3037 !inst_ty.hasRuntimeBitsIgnoreComptime())
3038 {
3091 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
30393092 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
30403093 return .none;
30413094 }
......@@ -3074,11 +3127,6 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30743127 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
30753128 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
30763129
3077 if (f.liveness.isUnused(inst)) {
3078 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3079 return .none;
3080 }
3081
30823130 const inst_ty = f.air.typeOfIndex(inst);
30833131 const ptr_ty = f.air.typeOf(bin_op.lhs);
30843132 const child_ty = ptr_ty.childType();
......@@ -3116,10 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
31163164fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31173165 const inst_ty = f.air.typeOfIndex(inst);
31183166 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3119 const slice_ty = f.air.typeOf(bin_op.lhs);
3120 if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
3121 !inst_ty.hasRuntimeBitsIgnoreComptime())
3122 {
3167 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
31233168 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
31243169 return .none;
31253170 }
......@@ -3158,11 +3203,6 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
31583203 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
31593204 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
31603205
3161 if (f.liveness.isUnused(inst)) {
3162 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3163 return .none;
3164 }
3165
31663206 const slice_ty = f.air.typeOf(bin_op.lhs);
31673207 const child_ty = slice_ty.elemType2();
31683208 const slice = try f.resolveInst(bin_op.lhs);
......@@ -3188,7 +3228,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
31883228fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31893229 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
31903230 const inst_ty = f.air.typeOfIndex(inst);
3191 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
3231 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
31923232 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
31933233 return .none;
31943234 }
......@@ -3224,40 +3264,34 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
32243264}
32253265
32263266fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3227 if (f.liveness.isUnused(inst)) return .none;
3228
32293267 const inst_ty = f.air.typeOfIndex(inst);
32303268 const elem_type = inst_ty.elemType();
32313269 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32323270
32333271 const target = f.object.dg.module.getTarget();
3234 const local = try f.allocAlignedLocal(
3272 const local = try f.allocLocalValue(
32353273 elem_type,
3236 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
32373274 inst_ty.ptrAlignment(target),
32383275 );
32393276 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
32403277 const gpa = f.object.dg.module.gpa;
3241 try f.allocs.put(gpa, local.new_local, false);
3278 try f.allocs.put(gpa, local.new_local, true);
32423279 return .{ .local_ref = local.new_local };
32433280}
32443281
32453282fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3246 if (f.liveness.isUnused(inst)) return .none;
3247
32483283 const inst_ty = f.air.typeOfIndex(inst);
32493284 const elem_ty = inst_ty.elemType();
32503285 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32513286
32523287 const target = f.object.dg.module.getTarget();
3253 const local = try f.allocAlignedLocal(
3288 const local = try f.allocLocalValue(
32543289 elem_ty,
3255 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
32563290 inst_ty.ptrAlignment(target),
32573291 );
32583292 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
32593293 const gpa = f.object.dg.module.gpa;
3260 try f.allocs.put(gpa, local.new_local, false);
3294 try f.allocs.put(gpa, local.new_local, true);
32613295 return .{ .local_ref = local.new_local };
32623296}
32633297
......@@ -3293,9 +3327,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
32933327 const ptr_info = ptr_scalar_ty.ptrInfo().data;
32943328 const src_ty = ptr_info.pointee_type;
32953329
3296 if (!src_ty.hasRuntimeBitsIgnoreComptime() or
3297 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
3298 {
3330 if (!src_ty.hasRuntimeBitsIgnoreComptime()) {
32993331 try reap(f, inst, &.{ty_op.operand});
33003332 return .none;
33013333 }
......@@ -3442,11 +3474,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
34423474fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
34433475 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
34443476
3445 if (f.liveness.isUnused(inst)) {
3446 try reap(f, inst, &.{ty_op.operand});
3447 return .none;
3448 }
3449
34503477 const operand = try f.resolveInst(ty_op.operand);
34513478 try reap(f, inst, &.{ty_op.operand});
34523479
......@@ -3470,10 +3497,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
34703497
34713498fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
34723499 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3473 if (f.liveness.isUnused(inst)) {
3474 try reap(f, inst, &.{ty_op.operand});
3475 return .none;
3476 }
34773500
34783501 const operand = try f.resolveInst(ty_op.operand);
34793502 try reap(f, inst, &.{ty_op.operand});
......@@ -3569,10 +3592,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
35693592
35703593fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
35713594 const un_op = f.air.instructions.items(.data)[inst].un_op;
3572 if (f.liveness.isUnused(inst)) {
3573 try reap(f, inst, &.{un_op});
3574 return .none;
3575 }
35763595 const operand = try f.resolveInst(un_op);
35773596 try reap(f, inst, &.{un_op});
35783597 const writer = f.object.writer();
......@@ -3746,11 +3765,6 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
37463765 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
37473766 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
37483767
3749 if (f.liveness.isUnused(inst)) {
3750 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3751 return .none;
3752 }
3753
37543768 const lhs = try f.resolveInst(bin_op.lhs);
37553769 const rhs = try f.resolveInst(bin_op.rhs);
37563770 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
......@@ -3790,11 +3804,6 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
37903804 const scalar_ty = operand_ty.scalarType();
37913805 if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits);
37923806
3793 if (f.liveness.isUnused(inst)) {
3794 try reap(f, inst, &.{ty_op.operand});
3795 return .none;
3796 }
3797
37983807 const op = try f.resolveInst(ty_op.operand);
37993808 try reap(f, inst, &.{ty_op.operand});
38003809
......@@ -3829,11 +3838,6 @@ fn airBinOp(
38293838 if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat())
38303839 return try airBinBuiltinCall(f, inst, operation, info);
38313840
3832 if (f.liveness.isUnused(inst)) {
3833 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3834 return .none;
3835 }
3836
38373841 const lhs = try f.resolveInst(bin_op.lhs);
38383842 const rhs = try f.resolveInst(bin_op.rhs);
38393843 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
......@@ -3865,11 +3869,6 @@ fn airCmpOp(
38653869 data: anytype,
38663870 operator: std.math.CompareOperator,
38673871) !CValue {
3868 if (f.liveness.isUnused(inst)) {
3869 try reap(f, inst, &.{ data.lhs, data.rhs });
3870 return .none;
3871 }
3872
38733872 const operand_ty = f.air.typeOf(data.lhs);
38743873 const scalar_ty = operand_ty.scalarType();
38753874
......@@ -3918,11 +3917,6 @@ fn airEquality(
39183917) !CValue {
39193918 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
39203919
3921 if (f.liveness.isUnused(inst)) {
3922 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3923 return .none;
3924 }
3925
39263920 const operand_ty = f.air.typeOf(bin_op.lhs);
39273921 const target = f.object.dg.module.getTarget();
39283922 const operand_bits = operand_ty.bitSize(target);
......@@ -3987,11 +3981,6 @@ fn airEquality(
39873981fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
39883982 const un_op = f.air.instructions.items(.data)[inst].un_op;
39893983
3990 if (f.liveness.isUnused(inst)) {
3991 try reap(f, inst, &.{un_op});
3992 return .none;
3993 }
3994
39953984 const inst_ty = f.air.typeOfIndex(inst);
39963985 const operand = try f.resolveInst(un_op);
39973986 try reap(f, inst, &.{un_op});
......@@ -4008,10 +3997,6 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
40083997fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
40093998 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
40103999 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
4011 if (f.liveness.isUnused(inst)) {
4012 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4013 return .none;
4014 }
40154000
40164001 const lhs = try f.resolveInst(bin_op.lhs);
40174002 const rhs = try f.resolveInst(bin_op.rhs);
......@@ -4059,11 +4044,6 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
40594044fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
40604045 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
40614046
4062 if (f.liveness.isUnused(inst)) {
4063 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4064 return .none;
4065 }
4066
40674047 const inst_ty = f.air.typeOfIndex(inst);
40684048 const inst_scalar_ty = inst_ty.scalarType();
40694049
......@@ -4107,11 +4087,6 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
41074087 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
41084088 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
41094089
4110 if (f.liveness.isUnused(inst)) {
4111 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4112 return .none;
4113 }
4114
41154090 const ptr = try f.resolveInst(bin_op.lhs);
41164091 const len = try f.resolveInst(bin_op.rhs);
41174092 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
......@@ -4316,6 +4291,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
43164291 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
43174292 const extra = f.air.extraData(Air.Block, ty_pl.payload);
43184293 const body = f.air.extra[extra.end..][0..extra.data.body_len];
4294 const liveness_block = f.liveness.getBlock(inst);
43194295
43204296 const block_id: usize = f.next_block_index;
43214297 f.next_block_index += 1;
......@@ -4332,7 +4308,15 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
43324308 .result = result,
43334309 });
43344310
4335 try genBodyInner(f, body);
4311 try genBodyResolveState(f, inst, &.{}, body, true);
4312
4313 assert(f.blocks.remove(inst));
4314
4315 // The body might result in some values we had beforehand being killed
4316 for (liveness_block.deaths) |death| {
4317 try die(f, inst, Air.indexToRef(death));
4318 }
4319
43364320 try f.object.indent_writer.insertNewline();
43374321 // label might be unused, add a dummy goto
43384322 // label must be followed by an expression, add an empty one.
......@@ -4366,6 +4350,7 @@ fn lowerTry(
43664350) !CValue {
43674351 const err_union = try f.resolveInst(operand);
43684352 const result_ty = f.air.typeOfIndex(inst);
4353 const liveness_condbr = f.liveness.getCondBr(inst);
43694354 const writer = f.object.writer();
43704355 const payload_ty = err_union_ty.errorUnionPayload();
43714356 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
......@@ -4389,10 +4374,15 @@ fn lowerTry(
43894374 }
43904375 try writer.writeByte(')');
43914376
4392 try genBody(f, body);
4377 try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
43934378 try f.object.indent_writer.insertNewline();
43944379 }
43954380
4381 // Now we have the "then branch" (in terms of the liveness data); process any deaths.
4382 for (liveness_condbr.then_deaths) |death| {
4383 try die(f, inst, Air.indexToRef(death));
4384 }
4385
43964386 if (!payload_has_bits) {
43974387 if (!operand_is_ptr) {
43984388 return .none;
......@@ -4466,10 +4456,6 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
44664456fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44674457 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
44684458 const dest_ty = f.air.typeOfIndex(inst);
4469 if (f.liveness.isUnused(inst)) {
4470 try reap(f, inst, &.{ty_op.operand});
4471 return .none;
4472 }
44734459
44744460 const operand = try f.resolveInst(ty_op.operand);
44754461 try reap(f, inst, &.{ty_op.operand});
......@@ -4593,7 +4579,6 @@ fn airBreakpoint(writer: anytype) !CValue {
45934579}
45944580
45954581fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
4596 if (f.liveness.isUnused(inst)) return .none;
45974582 const writer = f.object.writer();
45984583 const local = try f.allocLocal(inst, Type.usize);
45994584 try f.writeCValue(writer, local, .Other);
......@@ -4604,7 +4589,6 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
46044589}
46054590
46064591fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
4607 if (f.liveness.isUnused(inst)) return .none;
46084592 const writer = f.object.writer();
46094593 const local = try f.allocLocal(inst, Type.usize);
46104594 try f.writeCValue(writer, local, .Other);
......@@ -4640,7 +4624,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
46404624 const writer = f.object.writer();
46414625
46424626 try writer.writeAll("for (;;) ");
4643 try genBody(f, body);
4627 try genBody(f, body); // no need to restore state, we're noreturn
46444628 try writer.writeByte('\n');
46454629
46464630 return .none;
......@@ -4656,61 +4640,24 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
46564640 const liveness_condbr = f.liveness.getCondBr(inst);
46574641 const writer = f.object.writer();
46584642
4659 // Keep using the original for the then branch; use a clone of the value
4660 // map for the else branch.
4661 const gpa = f.object.dg.gpa;
4662 var cloned_map = try f.value_map.clone();
4663 defer cloned_map.deinit();
4664 var cloned_frees = try cloneFreeLocalsMap(gpa, &f.free_locals_map);
4665 defer deinitFreeLocalsMap(gpa, &cloned_frees);
4666
4667 // Remember how many locals there were before entering the then branch so
4668 // that we can notice and use them in the else branch. Any new locals must
4669 // necessarily be free already after the then branch is complete.
4670 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
4671 // Remember how many allocs there were before entering the then branch so
4672 // that we can notice and make sure not to use them in the else branch.
4673 // Any new allocs must be removed from the free list.
4674 const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
4675 const was_in_clone = f.is_in_clone;
4676 f.is_in_clone = true;
4677
4678 for (liveness_condbr.then_deaths) |operand| {
4679 try die(f, inst, Air.indexToRef(operand));
4680 }
4681
46824643 try writer.writeAll("if (");
46834644 try f.writeCValue(writer, cond, .Other);
46844645 try writer.writeAll(") ");
4685 try genBody(f, then_body);
46864646
4687 // TODO: If body ends in goto, elide the else block?
4688 const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br;
4689 if (needs_else) {
4690 try writer.writeAll(" else ");
4691 } else {
4692 try writer.writeByte('\n');
4693 }
4647 try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false);
46944648
4695 f.value_map.deinit();
4696 f.value_map = cloned_map.move();
4697 const free_locals = &f.free_locals_map;
4698 deinitFreeLocalsMap(gpa, free_locals);
4699 free_locals.* = cloned_frees.move();
4700 f.is_in_clone = was_in_clone;
4701 for (liveness_condbr.else_deaths) |operand| {
4702 try die(f, inst, Air.indexToRef(operand));
4703 }
4704
4705 try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
4649 // We don't need to use `genBodyResolveState` for the else block, because this instruction is
4650 // noreturn so must terminate a body, therefore we don't need to leave `value_map` or
4651 // `free_locals_map` well defined (our parent is responsible for doing that).
47064652
4707 if (needs_else) {
4708 try genBody(f, else_body);
4709 } else {
4710 try genBodyInner(f, else_body);
4653 for (liveness_condbr.else_deaths) |death| {
4654 try die(f, inst, Air.indexToRef(death));
47114655 }
47124656
4713 try f.object.indent_writer.insertNewline();
4657 // We never actually need an else block, because our branches are noreturn so must (for
4658 // instance) `br` to a block (label).
4659
4660 try genBodyInner(f, else_body);
47144661
47154662 return .none;
47164663}
......@@ -4741,9 +4688,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
47414688 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1);
47424689 defer gpa.free(liveness.deaths);
47434690
4744 // On the final iteration we do not clone the map. This ensures that
4745 // lowering proceeds after the switch_br taking into account the
4746 // mutations to the liveness information.
4691 // On the final iteration we do not need to fix any state. This is because, like in the `else`
4692 // branch of a `cond_br`, our parent has to do it for this entire body anyway.
47474693 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
47484694
47494695 var extra_index: usize = switch_br.end;
......@@ -4767,56 +4713,23 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
47674713 try writer.writeByte(' ');
47684714
47694715 if (case_i != last_case_i) {
4770 const old_value_map = f.value_map;
4771 f.value_map = try old_value_map.clone();
4772 var free_locals = &f.free_locals_map;
4773 const old_free_locals = free_locals.*;
4774 free_locals.* = try cloneFreeLocalsMap(gpa, free_locals);
4775
4776 // Remember how many locals there were before entering each branch so that
4777 // we can notice and use them in subsequent branches. Any new locals must
4778 // necessarily be free already after the previous branch is complete.
4779 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
4780 // Remember how many allocs there were before entering each branch so that
4781 // we can notice and make sure not to use them in subsequent branches.
4782 // Any new allocs must be removed from the free list.
4783 const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
4784 const was_in_clone = f.is_in_clone;
4785 f.is_in_clone = true;
4786
4787 {
4788 defer {
4789 f.is_in_clone = was_in_clone;
4790 f.value_map.deinit();
4791 deinitFreeLocalsMap(gpa, free_locals);
4792 f.value_map = old_value_map;
4793 free_locals.* = old_free_locals;
4794 }
4795
4796 for (liveness.deaths[case_i]) |operand| {
4797 try die(f, inst, Air.indexToRef(operand));
4798 }
4799
4800 try genBody(f, case_body);
4801 }
4802
4803 try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
4716 try genBodyResolveState(f, inst, liveness.deaths[case_i], case_body, false);
48044717 } else {
4805 for (liveness.deaths[case_i]) |operand| {
4806 try die(f, inst, Air.indexToRef(operand));
4718 for (liveness.deaths[case_i]) |death| {
4719 try die(f, inst, Air.indexToRef(death));
48074720 }
48084721 try genBody(f, case_body);
48094722 }
48104723
48114724 // The case body must be noreturn so we don't need to insert a break.
4812
48134725 }
48144726
48154727 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
48164728 try f.object.indent_writer.insertNewline();
48174729 if (else_body.len > 0) {
4818 for (liveness.deaths[liveness.deaths.len - 1]) |operand| {
4819 try die(f, inst, Air.indexToRef(operand));
4730 // Note that this must be the last case (i.e. the `last_case_i` case was not hit above)
4731 for (liveness.deaths[liveness.deaths.len - 1]) |death| {
4732 try die(f, inst, Air.indexToRef(death));
48204733 }
48214734 try writer.writeAll("default: ");
48224735 try genBody(f, else_body);
......@@ -4843,6 +4756,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48434756 const extra = f.air.extraData(Air.Asm, ty_pl.payload);
48444757 const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
48454758 const clobbers_len = @truncate(u31, extra.data.flags);
4759 const gpa = f.object.dg.gpa;
48464760 var extra_i: usize = extra.end;
48474761 const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);
48484762 extra_i += outputs.len;
......@@ -4850,8 +4764,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48504764 extra_i += inputs.len;
48514765
48524766 const result = result: {
4853 if (!is_volatile and f.liveness.isUnused(inst)) break :result .none;
4854
48554767 const writer = f.object.writer();
48564768 const inst_ty = f.air.typeOfIndex(inst);
48574769 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
......@@ -4887,6 +4799,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48874799 try writer.writeAll("register ");
48884800 const alignment = 0;
48894801 const local_value = try f.allocLocalValue(output_ty, alignment);
4802 try f.allocs.put(gpa, local_value.new_local, false);
48904803 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
48914804 try writer.writeAll(" __asm(\"");
48924805 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
......@@ -4919,6 +4832,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
49194832 if (is_reg) try writer.writeAll("register ");
49204833 const alignment = 0;
49214834 const local_value = try f.allocLocalValue(input_ty, alignment);
4835 try f.allocs.put(gpa, local_value.new_local, false);
49224836 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
49234837 if (is_reg) {
49244838 try writer.writeAll(" __asm(\"");
......@@ -5101,11 +5015,6 @@ fn airIsNull(
51015015) !CValue {
51025016 const un_op = f.air.instructions.items(.data)[inst].un_op;
51035017
5104 if (f.liveness.isUnused(inst)) {
5105 try reap(f, inst, &.{un_op});
5106 return .none;
5107 }
5108
51095018 const writer = f.object.writer();
51105019 const operand = try f.resolveInst(un_op);
51115020 try reap(f, inst, &.{un_op});
......@@ -5151,11 +5060,6 @@ fn airIsNull(
51515060fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
51525061 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
51535062
5154 if (f.liveness.isUnused(inst)) {
5155 try reap(f, inst, &.{ty_op.operand});
5156 return .none;
5157 }
5158
51595063 const operand = try f.resolveInst(ty_op.operand);
51605064 try reap(f, inst, &.{ty_op.operand});
51615065 const opt_ty = f.air.typeOf(ty_op.operand);
......@@ -5203,11 +5107,6 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
52035107fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
52045108 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
52055109
5206 if (f.liveness.isUnused(inst)) {
5207 try reap(f, inst, &.{ty_op.operand});
5208 return .none;
5209 }
5210
52115110 const writer = f.object.writer();
52125111 const operand = try f.resolveInst(ty_op.operand);
52135112 try reap(f, inst, &.{ty_op.operand});
......@@ -5337,11 +5236,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
53375236 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
53385237 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
53395238
5340 if (f.liveness.isUnused(inst)) {
5341 try reap(f, inst, &.{extra.struct_operand});
5342 return .none;
5343 }
5344
53455239 const container_ptr_val = try f.resolveInst(extra.struct_operand);
53465240 try reap(f, inst, &.{extra.struct_operand});
53475241 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
......@@ -5351,11 +5245,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
53515245fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
53525246 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
53535247
5354 if (f.liveness.isUnused(inst)) {
5355 try reap(f, inst, &.{ty_op.operand});
5356 return .none;
5357 }
5358
53595248 const container_ptr_val = try f.resolveInst(ty_op.operand);
53605249 try reap(f, inst, &.{ty_op.operand});
53615250 const container_ptr_ty = f.air.typeOf(ty_op.operand);
......@@ -5366,11 +5255,6 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
53665255 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
53675256 const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
53685257
5369 if (f.liveness.isUnused(inst)) {
5370 try reap(f, inst, &.{extra.field_ptr});
5371 return .none;
5372 }
5373
53745258 const target = f.object.dg.module.getTarget();
53755259 const container_ptr_ty = f.air.typeOfIndex(inst);
53765260 const container_ty = container_ptr_ty.childType();
......@@ -5489,11 +5373,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54895373 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
54905374 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
54915375
5492 if (f.liveness.isUnused(inst)) {
5493 try reap(f, inst, &.{extra.struct_operand});
5494 return .none;
5495 }
5496
54975376 const inst_ty = f.air.typeOfIndex(inst);
54985377 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
54995378 try reap(f, inst, &.{extra.struct_operand});
......@@ -5639,11 +5518,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
56395518fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
56405519 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
56415520
5642 if (f.liveness.isUnused(inst)) {
5643 try reap(f, inst, &.{ty_op.operand});
5644 return .none;
5645 }
5646
56475521 const inst_ty = f.air.typeOfIndex(inst);
56485522 const operand = try f.resolveInst(ty_op.operand);
56495523 const operand_ty = f.air.typeOf(ty_op.operand);
......@@ -5676,11 +5550,6 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
56765550fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
56775551 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
56785552
5679 if (f.liveness.isUnused(inst)) {
5680 try reap(f, inst, &.{ty_op.operand});
5681 return .none;
5682 }
5683
56845553 const inst_ty = f.air.typeOfIndex(inst);
56855554 const operand = try f.resolveInst(ty_op.operand);
56865555 try reap(f, inst, &.{ty_op.operand});
......@@ -5718,11 +5587,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
57185587fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
57195588 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
57205589
5721 if (f.liveness.isUnused(inst)) {
5722 try reap(f, inst, &.{ty_op.operand});
5723 return .none;
5724 }
5725
57265590 const inst_ty = f.air.typeOfIndex(inst);
57275591 const payload = try f.resolveInst(ty_op.operand);
57285592 try reap(f, inst, &.{ty_op.operand});
......@@ -5764,10 +5628,6 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
57645628
57655629fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
57665630 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5767 if (f.liveness.isUnused(inst)) {
5768 try reap(f, inst, &.{ty_op.operand});
5769 return .none;
5770 }
57715631
57725632 const writer = f.object.writer();
57735633 const operand = try f.resolveInst(ty_op.operand);
......@@ -5831,7 +5691,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
58315691}
58325692
58335693fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
5834 if (f.liveness.isUnused(inst)) return .none;
5694 _ = inst;
58355695 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
58365696}
58375697
......@@ -5847,10 +5707,6 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
58475707
58485708fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
58495709 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5850 if (f.liveness.isUnused(inst)) {
5851 try reap(f, inst, &.{ty_op.operand});
5852 return .none;
5853 }
58545710
58555711 const inst_ty = f.air.typeOfIndex(inst);
58565712 const payload_ty = inst_ty.errorUnionPayload();
......@@ -5885,11 +5741,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
58855741fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
58865742 const un_op = f.air.instructions.items(.data)[inst].un_op;
58875743
5888 if (f.liveness.isUnused(inst)) {
5889 try reap(f, inst, &.{un_op});
5890 return .none;
5891 }
5892
58935744 const writer = f.object.writer();
58945745 const operand = try f.resolveInst(un_op);
58955746 try reap(f, inst, &.{un_op});
......@@ -5923,11 +5774,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
59235774fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
59245775 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
59255776
5926 if (f.liveness.isUnused(inst)) {
5927 try reap(f, inst, &.{ty_op.operand});
5928 return .none;
5929 }
5930
59315777 const operand = try f.resolveInst(ty_op.operand);
59325778 try reap(f, inst, &.{ty_op.operand});
59335779 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5961,11 +5807,6 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
59615807fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
59625808 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
59635809
5964 if (f.liveness.isUnused(inst)) {
5965 try reap(f, inst, &.{ty_op.operand});
5966 return .none;
5967 }
5968
59695810 const inst_ty = f.air.typeOfIndex(inst);
59705811 const operand = try f.resolveInst(ty_op.operand);
59715812 try reap(f, inst, &.{ty_op.operand});
......@@ -6009,11 +5850,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
60095850fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
60105851 const un_op = f.air.instructions.items(.data)[inst].un_op;
60115852
6012 if (f.liveness.isUnused(inst)) {
6013 try reap(f, inst, &.{un_op});
6014 return .none;
6015 }
6016
60175853 const operand = try f.resolveInst(un_op);
60185854 try reap(f, inst, &.{un_op});
60195855 const inst_ty = f.air.typeOfIndex(inst);
......@@ -6037,11 +5873,6 @@ fn airUnBuiltinCall(
60375873) !CValue {
60385874 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
60395875
6040 if (f.liveness.isUnused(inst)) {
6041 try reap(f, inst, &.{ty_op.operand});
6042 return .none;
6043 }
6044
60455876 const operand = try f.resolveInst(ty_op.operand);
60465877 try reap(f, inst, &.{ty_op.operand});
60475878 const inst_ty = f.air.typeOfIndex(inst);
......@@ -6085,11 +5916,6 @@ fn airBinBuiltinCall(
60855916) !CValue {
60865917 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
60875918
6088 if (f.liveness.isUnused(inst)) {
6089 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6090 return .none;
6091 }
6092
60935919 const operand_ty = f.air.typeOf(bin_op.lhs);
60945920 const operand_cty = try f.typeToCType(operand_ty, .complete);
60955921 const is_big = operand_cty.tag() == .array;
......@@ -6142,11 +5968,6 @@ fn airCmpBuiltinCall(
61425968 operation: enum { cmp, operator },
61435969 info: BuiltinInfo,
61445970) !CValue {
6145 if (f.liveness.isUnused(inst)) {
6146 try reap(f, inst, &.{ data.lhs, data.rhs });
6147 return .none;
6148 }
6149
61505971 const lhs = try f.resolveInst(data.lhs);
61515972 const rhs = try f.resolveInst(data.rhs);
61525973 try reap(f, inst, &.{ data.lhs, data.rhs });
......@@ -6317,9 +6138,6 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
63176138 const ptr = try f.resolveInst(atomic_load.ptr);
63186139 try reap(f, inst, &.{atomic_load.ptr});
63196140 const ptr_ty = f.air.typeOf(atomic_load.ptr);
6320 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
6321 return .none;
6322 }
63236141
63246142 const inst_ty = f.air.typeOfIndex(inst);
63256143 const writer = f.object.writer();
......@@ -6463,11 +6281,6 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
64636281fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
64646282 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
64656283
6466 if (f.liveness.isUnused(inst)) {
6467 try reap(f, inst, &.{ty_op.operand});
6468 return .none;
6469 }
6470
64716284 const operand = try f.resolveInst(ty_op.operand);
64726285 try reap(f, inst, &.{ty_op.operand});
64736286
......@@ -6491,11 +6304,6 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
64916304fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
64926305 const un_op = f.air.instructions.items(.data)[inst].un_op;
64936306
6494 if (f.liveness.isUnused(inst)) {
6495 try reap(f, inst, &.{un_op});
6496 return .none;
6497 }
6498
64996307 const inst_ty = f.air.typeOfIndex(inst);
65006308 const enum_ty = f.air.typeOf(un_op);
65016309 const operand = try f.resolveInst(un_op);
......@@ -6516,11 +6324,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
65166324fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
65176325 const un_op = f.air.instructions.items(.data)[inst].un_op;
65186326
6519 if (f.liveness.isUnused(inst)) {
6520 try reap(f, inst, &.{un_op});
6521 return .none;
6522 }
6523
65246327 const writer = f.object.writer();
65256328 const inst_ty = f.air.typeOfIndex(inst);
65266329 const operand = try f.resolveInst(un_op);
......@@ -6537,11 +6340,6 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
65376340fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
65386341 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
65396342
6540 if (f.liveness.isUnused(inst)) {
6541 try reap(f, inst, &.{ty_op.operand});
6542 return .none;
6543 }
6544
65456343 const operand = try f.resolveInst(ty_op.operand);
65466344 try reap(f, inst, &.{ty_op.operand});
65476345
......@@ -6573,11 +6371,6 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
65736371 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
65746372 const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
65756373
6576 if (f.liveness.isUnused(inst)) {
6577 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
6578 return .none;
6579 }
6580
65816374 const pred = try f.resolveInst(pl_op.operand);
65826375 const lhs = try f.resolveInst(extra.lhs);
65836376 const rhs = try f.resolveInst(extra.rhs);
......@@ -6609,11 +6402,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
66096402 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
66106403 const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data;
66116404
6612 if (f.liveness.isUnused(inst)) {
6613 try reap(f, inst, &.{ extra.a, extra.b });
6614 return .none;
6615 }
6616
66176405 const mask = f.air.values[extra.mask];
66186406 const lhs = try f.resolveInst(extra.a);
66196407 const rhs = try f.resolveInst(extra.b);
......@@ -6655,11 +6443,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
66556443fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
66566444 const reduce = f.air.instructions.items(.data)[inst].reduce;
66576445
6658 if (f.liveness.isUnused(inst)) {
6659 try reap(f, inst, &.{reduce.operand});
6660 return .none;
6661 }
6662
66636446 const target = f.object.dg.module.getTarget();
66646447 const scalar_ty = f.air.typeOfIndex(inst);
66656448 const operand = try f.resolveInst(reduce.operand);
......@@ -6831,8 +6614,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
68316614 }
68326615 }
68336616
6834 if (f.liveness.isUnused(inst)) return .none;
6835
68366617 const target = f.object.dg.module.getTarget();
68376618
68386619 const writer = f.object.writer();
......@@ -6999,11 +6780,6 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
69996780 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
70006781 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
70016782
7002 if (f.liveness.isUnused(inst)) {
7003 try reap(f, inst, &.{extra.init});
7004 return .none;
7005 }
7006
70076783 const union_ty = f.air.typeOfIndex(inst);
70086784 const target = f.object.dg.module.getTarget();
70096785 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
......@@ -7070,8 +6846,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
70706846}
70716847
70726848fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
7073 if (f.liveness.isUnused(inst)) return .none;
7074
70756849 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
70766850
70776851 const writer = f.object.writer();
......@@ -7104,10 +6878,6 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
71046878
71056879fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
71066880 const un_op = f.air.instructions.items(.data)[inst].un_op;
7107 if (f.liveness.isUnused(inst)) {
7108 try reap(f, inst, &.{un_op});
7109 return .none;
7110 }
71116881
71126882 const operand = try f.resolveInst(un_op);
71136883 try reap(f, inst, &.{un_op});
......@@ -7133,10 +6903,6 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
71336903
71346904fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
71356905 const un_op = f.air.instructions.items(.data)[inst].un_op;
7136 if (f.liveness.isUnused(inst)) {
7137 try reap(f, inst, &.{un_op});
7138 return .none;
7139 }
71406906
71416907 const operand = try f.resolveInst(un_op);
71426908 try reap(f, inst, &.{un_op});
......@@ -7164,10 +6930,6 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
71646930
71656931fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
71666932 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
7167 if (f.liveness.isUnused(inst)) {
7168 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
7169 return .none;
7170 }
71716933
71726934 const lhs = try f.resolveInst(bin_op.lhs);
71736935 const rhs = try f.resolveInst(bin_op.rhs);
......@@ -7200,10 +6962,6 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
72006962fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
72016963 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
72026964 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
7203 if (f.liveness.isUnused(inst)) {
7204 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
7205 return .none;
7206 }
72076965
72086966 const mulend1 = try f.resolveInst(bin_op.lhs);
72096967 const mulend2 = try f.resolveInst(bin_op.rhs);
......@@ -7236,8 +6994,6 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
72366994}
72376995
72386996fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
7239 if (f.liveness.isUnused(inst)) return .none;
7240
72416997 const inst_ty = f.air.typeOfIndex(inst);
72426998 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
72436999 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
......@@ -7256,10 +7012,6 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
72567012
72577013fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
72587014 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
7259 if (f.liveness.isUnused(inst)) {
7260 try reap(f, inst, &.{ty_op.operand});
7261 return .none;
7262 }
72637015
72647016 const inst_ty = f.air.typeOfIndex(inst);
72657017 const va_list = try f.resolveInst(ty_op.operand);
......@@ -7291,10 +7043,6 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
72917043
72927044fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
72937045 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
7294 if (f.liveness.isUnused(inst)) {
7295 try reap(f, inst, &.{ty_op.operand});
7296 return .none;
7297 }
72987046
72997047 const inst_ty = f.air.typeOfIndex(inst);
73007048 const va_list = try f.resolveInst(ty_op.operand);
......@@ -7858,7 +7606,6 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in
78587606 const gpa = f.object.dg.gpa;
78597607 const local = &f.locals.items[local_index];
78607608 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });
7861 if (f.is_in_clone != local.is_in_clone) return;
78627609 const gop = try f.free_locals_map.getOrPut(gpa, local.getType());
78637610 if (!gop.found_existing) gop.value_ptr.* = .{};
78647611 if (std.debug.runtime_safety) {
......@@ -7916,35 +7663,3 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
79167663 }
79177664 map.deinit(gpa);
79187665}
7919
7920fn noticeBranchFrees(
7921 f: *Function,
7922 pre_locals_len: LocalIndex,
7923 pre_allocs_len: LocalIndex,
7924 inst: Air.Inst.Index,
7925) !void {
7926 for (f.locals.items[pre_locals_len..], pre_locals_len..) |*local, local_i| {
7927 const local_index = @intCast(LocalIndex, local_i);
7928 if (f.allocs.contains(local_index)) {
7929 if (std.debug.runtime_safety) {
7930 // new allocs are no longer freeable, so make sure they aren't in the free list
7931 if (f.free_locals_map.getPtr(local.getType())) |locals_list| {
7932 assert(!locals_list.contains(local_index));
7933 }
7934 }
7935 continue;
7936 }
7937
7938 // free cloned locals from other branches at current cloned-ness
7939 std.debug.assert(local.is_in_clone or !f.is_in_clone);
7940 local.is_in_clone = f.is_in_clone;
7941 try freeLocal(f, inst, local_index, 0);
7942 }
7943
7944 for (f.allocs.keys()[pre_allocs_len..]) |local_i| {
7945 const local_index = @intCast(LocalIndex, local_i);
7946 const local = &f.locals.items[local_index];
7947 // new allocs are no longer freeable, so remove them from the free list
7948 if (f.free_locals_map.getPtr(local.getType())) |locals_list| _ = locals_list.swapRemove(local_index);
7949 }
7950}