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
signature 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;...@@ -78,7 +78,6 @@ const LoopDepth = u16;
78const Local = struct {78const Local = struct {
79 cty_idx: CType.Index,79 cty_idx: CType.Index,
80 alignas: CType.AlignAs,80 alignas: CType.AlignAs,
81 is_in_clone: bool,
8281
83 pub fn getType(local: Local) LocalType {82 pub fn getType(local: Local) LocalType {
84 return .{ .cty_idx = local.cty_idx, .alignas = local.alignas };83 return .{ .cty_idx = local.cty_idx, .alignas = local.alignas };
...@@ -275,16 +274,13 @@ pub const Function = struct {...@@ -275,16 +274,13 @@ pub const Function = struct {
275 /// All the locals, to be emitted at the top of the function.274 /// All the locals, to be emitted at the top of the function.
276 locals: std.ArrayListUnmanaged(Local) = .{},275 locals: std.ArrayListUnmanaged(Local) = .{},
277 /// Which locals are available for reuse, based on Type.276 /// 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.
280 free_locals_map: LocalsMap = .{},277 free_locals_map: LocalsMap = .{},
281 is_in_clone: bool = false,
282 /// Locals which will not be freed by Liveness. This is used after a278 /// Locals which will not be freed by Liveness. This is used after a
283 /// Function body is lowered in order to make `free_locals_map` have279 /// Function body is lowered in order to make `free_locals_map` have
284 /// 100% of the locals within so that it can be used to render the block280 /// 100% of the locals within so that it can be used to render the block
285 /// of variable declarations at the top of a function, sorted descending281 /// of variable declarations at the top of a function, sorted descending
286 /// by type alignment.282 /// 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.
288 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},284 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},
289 /// Needed for memory used by the keys of free_locals_map entries.285 /// Needed for memory used by the keys of free_locals_map entries.
290 arena: std.heap.ArenaAllocator,286 arena: std.heap.ArenaAllocator,
...@@ -302,7 +298,7 @@ pub const Function = struct {...@@ -302,7 +298,7 @@ pub const Function = struct {
302 const alignment = 0;298 const alignment = 0;
303 const decl_c_value = try f.allocLocalValue(ty, alignment);299 const decl_c_value = try f.allocLocalValue(ty, alignment);
304 const gpa = f.object.dg.gpa;300 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);
306 try writer.writeAll("static ");302 try writer.writeAll("static ");
307 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);303 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
308 try writer.writeAll(" = ");304 try writer.writeAll(" = ");
...@@ -323,14 +319,15 @@ pub const Function = struct {...@@ -323,14 +319,15 @@ pub const Function = struct {
323 };319 };
324 }320 }
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.
327 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {325 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
328 const gpa = f.object.dg.gpa;326 const gpa = f.object.dg.gpa;
329 const target = f.object.dg.module.getTarget();327 const target = f.object.dg.module.getTarget();
330 try f.locals.append(gpa, .{328 try f.locals.append(gpa, .{
331 .cty_idx = try f.typeToIndex(ty, .complete),329 .cty_idx = try f.typeToIndex(ty, .complete),
332 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),330 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),
333 .is_in_clone = f.is_in_clone,
334 });331 });
335 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };332 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
336 }333 }
...@@ -341,7 +338,8 @@ pub const Function = struct {...@@ -341,7 +338,8 @@ pub const Function = struct {
341 return result;338 return result;
342 }339 }
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`).
345 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {343 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
346 const target = f.object.dg.module.getTarget();344 const target = f.object.dg.module.getTarget();
347 if (f.free_locals_map.getPtr(.{345 if (f.free_locals_map.getPtr(.{
...@@ -2586,7 +2584,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2586,7 +2584,7 @@ pub fn genFunc(f: *Function) !void {
2586 f.free_locals_map.clearRetainingCapacity();2584 f.free_locals_map.clearRetainingCapacity();
25872585
2588 const main_body = f.air.getMainBody();2586 const main_body = f.air.getMainBody();
2589 try genBody(f, main_body);2587 try genBodyResolveState(f, undefined, &.{}, main_body, false);
25902588
2591 try o.indent_writer.insertNewline();2589 try o.indent_writer.insertNewline();
25922590
...@@ -2597,8 +2595,8 @@ pub fn genFunc(f: *Function) !void {...@@ -2597,8 +2595,8 @@ pub fn genFunc(f: *Function) !void {
2597 // alignment, descending.2595 // alignment, descending.
2598 const free_locals = &f.free_locals_map;2596 const free_locals = &f.free_locals_map;
2599 assert(f.value_map.count() == 0); // there must not be any unfreed locals2597 assert(f.value_map.count() == 0); // there must not be any unfreed locals
2600 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {2598 for (f.allocs.keys(), f.allocs.values()) |local_index, should_emit| {
2601 if (value) continue; // static2599 if (!should_emit) continue;
2602 const local = f.locals.items[local_index];2600 const local = f.locals.items[local_index];
2603 log.debug("inserting local {d} into free_locals", .{local_index});2601 log.debug("inserting local {d} into free_locals", .{local_index});
2604 const gop = try free_locals.getOrPut(gpa, local.getType());2602 const gop = try free_locals.getOrPut(gpa, local.getType());
...@@ -2715,6 +2713,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2715,6 +2713,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2715 }2713 }
2716}2714}
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`.
2718fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {2720fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
2719 const writer = f.object.writer();2721 const writer = f.object.writer();
2720 if (body.len == 0) {2722 if (body.len == 0) {
...@@ -2728,10 +2730,69 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -2728,10 +2730,69 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
2728 }2730 }
2729}2731}
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
2731fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {2788fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
2732 const air_tags = f.air.instructions.items(.tag);2789 const air_tags = f.air.instructions.items(.tag);
27332790
2734 for (body) |inst| {2791 for (body) |inst| {
2792 if (f.liveness.isUnused(inst) and !f.air.mustLower(inst)) {
2793 continue;
2794 }
2795
2735 const result_value = switch (air_tags[inst]) {2796 const result_value = switch (air_tags[inst]) {
2736 // zig fmt: off2797 // zig fmt: off
2737 .constant => unreachable, // excluded from function bodies2798 .constant => unreachable, // excluded from function bodies
...@@ -3009,11 +3070,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3009,11 +3070,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3009fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {3070fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {
3010 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3071 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
3017 const inst_ty = f.air.typeOfIndex(inst);3073 const inst_ty = f.air.typeOfIndex(inst);
3018 const operand = try f.resolveInst(ty_op.operand);3074 const operand = try f.resolveInst(ty_op.operand);
3019 try reap(f, inst, &.{ty_op.operand});3075 try reap(f, inst, &.{ty_op.operand});
...@@ -3032,10 +3088,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [...@@ -3032,10 +3088,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
3032fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {3088fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3033 const inst_ty = f.air.typeOfIndex(inst);3089 const inst_ty = f.air.typeOfIndex(inst);
3034 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3090 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3035 const ptr_ty = f.air.typeOf(bin_op.lhs);3091 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
3036 if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
3037 !inst_ty.hasRuntimeBitsIgnoreComptime())
3038 {
3039 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3092 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3040 return .none;3093 return .none;
3041 }3094 }
...@@ -3074,11 +3127,6 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3074,11 +3127,6 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3074 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3127 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3075 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3128 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
3082 const inst_ty = f.air.typeOfIndex(inst);3130 const inst_ty = f.air.typeOfIndex(inst);
3083 const ptr_ty = f.air.typeOf(bin_op.lhs);3131 const ptr_ty = f.air.typeOf(bin_op.lhs);
3084 const child_ty = ptr_ty.childType();3132 const child_ty = ptr_ty.childType();
...@@ -3116,10 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3116,10 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3116fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {3164fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3117 const inst_ty = f.air.typeOfIndex(inst);3165 const inst_ty = f.air.typeOfIndex(inst);
3118 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3166 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3119 const slice_ty = f.air.typeOf(bin_op.lhs);3167 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
3120 if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
3121 !inst_ty.hasRuntimeBitsIgnoreComptime())
3122 {
3123 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3168 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3124 return .none;3169 return .none;
3125 }3170 }
...@@ -3158,11 +3203,6 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3158,11 +3203,6 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3158 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3203 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3159 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3204 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
3166 const slice_ty = f.air.typeOf(bin_op.lhs);3206 const slice_ty = f.air.typeOf(bin_op.lhs);
3167 const child_ty = slice_ty.elemType2();3207 const child_ty = slice_ty.elemType2();
3168 const slice = try f.resolveInst(bin_op.lhs);3208 const slice = try f.resolveInst(bin_op.lhs);
...@@ -3188,7 +3228,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3188,7 +3228,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3188fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {3228fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3189 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3229 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3190 const inst_ty = f.air.typeOfIndex(inst);3230 const inst_ty = f.air.typeOfIndex(inst);
3191 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {3231 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
3192 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3232 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3193 return .none;3233 return .none;
3194 }3234 }
...@@ -3224,40 +3264,34 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3224,40 +3264,34 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3224}3264}
32253265
3226fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {3266fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3227 if (f.liveness.isUnused(inst)) return .none;
3228
3229 const inst_ty = f.air.typeOfIndex(inst);3267 const inst_ty = f.air.typeOfIndex(inst);
3230 const elem_type = inst_ty.elemType();3268 const elem_type = inst_ty.elemType();
3231 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };3269 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32323270
3233 const target = f.object.dg.module.getTarget();3271 const target = f.object.dg.module.getTarget();
3234 const local = try f.allocAlignedLocal(3272 const local = try f.allocLocalValue(
3235 elem_type,3273 elem_type,
3236 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3237 inst_ty.ptrAlignment(target),3274 inst_ty.ptrAlignment(target),
3238 );3275 );
3239 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3276 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3240 const gpa = f.object.dg.module.gpa;3277 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);
3242 return .{ .local_ref = local.new_local };3279 return .{ .local_ref = local.new_local };
3243}3280}
32443281
3245fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3282fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3246 if (f.liveness.isUnused(inst)) return .none;
3247
3248 const inst_ty = f.air.typeOfIndex(inst);3283 const inst_ty = f.air.typeOfIndex(inst);
3249 const elem_ty = inst_ty.elemType();3284 const elem_ty = inst_ty.elemType();
3250 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };3285 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32513286
3252 const target = f.object.dg.module.getTarget();3287 const target = f.object.dg.module.getTarget();
3253 const local = try f.allocAlignedLocal(3288 const local = try f.allocLocalValue(
3254 elem_ty,3289 elem_ty,
3255 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3256 inst_ty.ptrAlignment(target),3290 inst_ty.ptrAlignment(target),
3257 );3291 );
3258 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3292 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3259 const gpa = f.object.dg.module.gpa;3293 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);
3261 return .{ .local_ref = local.new_local };3295 return .{ .local_ref = local.new_local };
3262}3296}
32633297
...@@ -3293,9 +3327,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3293,9 +3327,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3293 const ptr_info = ptr_scalar_ty.ptrInfo().data;3327 const ptr_info = ptr_scalar_ty.ptrInfo().data;
3294 const src_ty = ptr_info.pointee_type;3328 const src_ty = ptr_info.pointee_type;
32953329
3296 if (!src_ty.hasRuntimeBitsIgnoreComptime() or3330 if (!src_ty.hasRuntimeBitsIgnoreComptime()) {
3297 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
3298 {
3299 try reap(f, inst, &.{ty_op.operand});3331 try reap(f, inst, &.{ty_op.operand});
3300 return .none;3332 return .none;
3301 }3333 }
...@@ -3442,11 +3474,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3442,11 +3474,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3442fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {3474fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
3443 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3475 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
3450 const operand = try f.resolveInst(ty_op.operand);3477 const operand = try f.resolveInst(ty_op.operand);
3451 try reap(f, inst, &.{ty_op.operand});3478 try reap(f, inst, &.{ty_op.operand});
34523479
...@@ -3470,10 +3497,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3470,10 +3497,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
34703497
3471fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {3498fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3472 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3499 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
3478 const operand = try f.resolveInst(ty_op.operand);3501 const operand = try f.resolveInst(ty_op.operand);
3479 try reap(f, inst, &.{ty_op.operand});3502 try reap(f, inst, &.{ty_op.operand});
...@@ -3569,10 +3592,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3569,10 +3592,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
35693592
3570fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {3593fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
3571 const un_op = f.air.instructions.items(.data)[inst].un_op;3594 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 }
3576 const operand = try f.resolveInst(un_op);3595 const operand = try f.resolveInst(un_op);
3577 try reap(f, inst, &.{un_op});3596 try reap(f, inst, &.{un_op});
3578 const writer = f.object.writer();3597 const writer = f.object.writer();
...@@ -3746,11 +3765,6 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:...@@ -3746,11 +3765,6 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
3746 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3765 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3747 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3766 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
3754 const lhs = try f.resolveInst(bin_op.lhs);3768 const lhs = try f.resolveInst(bin_op.lhs);
3755 const rhs = try f.resolveInst(bin_op.rhs);3769 const rhs = try f.resolveInst(bin_op.rhs);
3756 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3770 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
...@@ -3790,11 +3804,6 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3790,11 +3804,6 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
3790 const scalar_ty = operand_ty.scalarType();3804 const scalar_ty = operand_ty.scalarType();
3791 if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits);3805 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
3798 const op = try f.resolveInst(ty_op.operand);3807 const op = try f.resolveInst(ty_op.operand);
3799 try reap(f, inst, &.{ty_op.operand});3808 try reap(f, inst, &.{ty_op.operand});
38003809
...@@ -3829,11 +3838,6 @@ fn airBinOp(...@@ -3829,11 +3838,6 @@ fn airBinOp(
3829 if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat())3838 if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat())
3830 return try airBinBuiltinCall(f, inst, operation, info);3839 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
3837 const lhs = try f.resolveInst(bin_op.lhs);3841 const lhs = try f.resolveInst(bin_op.lhs);
3838 const rhs = try f.resolveInst(bin_op.rhs);3842 const rhs = try f.resolveInst(bin_op.rhs);
3839 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3843 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
...@@ -3865,11 +3869,6 @@ fn airCmpOp(...@@ -3865,11 +3869,6 @@ fn airCmpOp(
3865 data: anytype,3869 data: anytype,
3866 operator: std.math.CompareOperator,3870 operator: std.math.CompareOperator,
3867) !CValue {3871) !CValue {
3868 if (f.liveness.isUnused(inst)) {
3869 try reap(f, inst, &.{ data.lhs, data.rhs });
3870 return .none;
3871 }
3872
3873 const operand_ty = f.air.typeOf(data.lhs);3872 const operand_ty = f.air.typeOf(data.lhs);
3874 const scalar_ty = operand_ty.scalarType();3873 const scalar_ty = operand_ty.scalarType();
38753874
...@@ -3918,11 +3917,6 @@ fn airEquality(...@@ -3918,11 +3917,6 @@ fn airEquality(
3918) !CValue {3917) !CValue {
3919 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3918 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
3926 const operand_ty = f.air.typeOf(bin_op.lhs);3920 const operand_ty = f.air.typeOf(bin_op.lhs);
3927 const target = f.object.dg.module.getTarget();3921 const target = f.object.dg.module.getTarget();
3928 const operand_bits = operand_ty.bitSize(target);3922 const operand_bits = operand_ty.bitSize(target);
...@@ -3987,11 +3981,6 @@ fn airEquality(...@@ -3987,11 +3981,6 @@ fn airEquality(
3987fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {3981fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
3988 const un_op = f.air.instructions.items(.data)[inst].un_op;3982 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
3995 const inst_ty = f.air.typeOfIndex(inst);3984 const inst_ty = f.air.typeOfIndex(inst);
3996 const operand = try f.resolveInst(un_op);3985 const operand = try f.resolveInst(un_op);
3997 try reap(f, inst, &.{un_op});3986 try reap(f, inst, &.{un_op});
...@@ -4008,10 +3997,6 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4008,10 +3997,6 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
4008fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {3997fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
4009 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3998 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4010 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3999 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
4016 const lhs = try f.resolveInst(bin_op.lhs);4001 const lhs = try f.resolveInst(bin_op.lhs);
4017 const rhs = try f.resolveInst(bin_op.rhs);4002 const rhs = try f.resolveInst(bin_op.rhs);
...@@ -4059,11 +4044,6 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4059,11 +4044,6 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
4059fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {4044fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
4060 const bin_op = f.air.instructions.items(.data)[inst].bin_op;4045 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
4067 const inst_ty = f.air.typeOfIndex(inst);4047 const inst_ty = f.air.typeOfIndex(inst);
4068 const inst_scalar_ty = inst_ty.scalarType();4048 const inst_scalar_ty = inst_ty.scalarType();
40694049
...@@ -4107,11 +4087,6 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4107,11 +4087,6 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
4107 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4087 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4108 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;4088 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
4115 const ptr = try f.resolveInst(bin_op.lhs);4090 const ptr = try f.resolveInst(bin_op.lhs);
4116 const len = try f.resolveInst(bin_op.rhs);4091 const len = try f.resolveInst(bin_op.rhs);
4117 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });4092 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
...@@ -4316,6 +4291,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4316,6 +4291,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4316 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4291 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4317 const extra = f.air.extraData(Air.Block, ty_pl.payload);4292 const extra = f.air.extraData(Air.Block, ty_pl.payload);
4318 const body = f.air.extra[extra.end..][0..extra.data.body_len];4293 const body = f.air.extra[extra.end..][0..extra.data.body_len];
4294 const liveness_block = f.liveness.getBlock(inst);
43194295
4320 const block_id: usize = f.next_block_index;4296 const block_id: usize = f.next_block_index;
4321 f.next_block_index += 1;4297 f.next_block_index += 1;
...@@ -4332,7 +4308,15 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4332,7 +4308,15 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4332 .result = result,4308 .result = result,
4333 });4309 });
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
4336 try f.object.indent_writer.insertNewline();4320 try f.object.indent_writer.insertNewline();
4337 // label might be unused, add a dummy goto4321 // label might be unused, add a dummy goto
4338 // label must be followed by an expression, add an empty one.4322 // label must be followed by an expression, add an empty one.
...@@ -4366,6 +4350,7 @@ fn lowerTry(...@@ -4366,6 +4350,7 @@ fn lowerTry(
4366) !CValue {4350) !CValue {
4367 const err_union = try f.resolveInst(operand);4351 const err_union = try f.resolveInst(operand);
4368 const result_ty = f.air.typeOfIndex(inst);4352 const result_ty = f.air.typeOfIndex(inst);
4353 const liveness_condbr = f.liveness.getCondBr(inst);
4369 const writer = f.object.writer();4354 const writer = f.object.writer();
4370 const payload_ty = err_union_ty.errorUnionPayload();4355 const payload_ty = err_union_ty.errorUnionPayload();
4371 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();4356 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
...@@ -4389,10 +4374,15 @@ fn lowerTry(...@@ -4389,10 +4374,15 @@ fn lowerTry(
4389 }4374 }
4390 try writer.writeByte(')');4375 try writer.writeByte(')');
43914376
4392 try genBody(f, body);4377 try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
4393 try f.object.indent_writer.insertNewline();4378 try f.object.indent_writer.insertNewline();
4394 }4379 }
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
4396 if (!payload_has_bits) {4386 if (!payload_has_bits) {
4397 if (!operand_is_ptr) {4387 if (!operand_is_ptr) {
4398 return .none;4388 return .none;
...@@ -4466,10 +4456,6 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4466,10 +4456,6 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4466fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {4456fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4467 const ty_op = f.air.instructions.items(.data)[inst].ty_op;4457 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4468 const dest_ty = f.air.typeOfIndex(inst);4458 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
4474 const operand = try f.resolveInst(ty_op.operand);4460 const operand = try f.resolveInst(ty_op.operand);
4475 try reap(f, inst, &.{ty_op.operand});4461 try reap(f, inst, &.{ty_op.operand});
...@@ -4593,7 +4579,6 @@ fn airBreakpoint(writer: anytype) !CValue {...@@ -4593,7 +4579,6 @@ fn airBreakpoint(writer: anytype) !CValue {
4593}4579}
45944580
4595fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {4581fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
4596 if (f.liveness.isUnused(inst)) return .none;
4597 const writer = f.object.writer();4582 const writer = f.object.writer();
4598 const local = try f.allocLocal(inst, Type.usize);4583 const local = try f.allocLocal(inst, Type.usize);
4599 try f.writeCValue(writer, local, .Other);4584 try f.writeCValue(writer, local, .Other);
...@@ -4604,7 +4589,6 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4604,7 +4589,6 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
4604}4589}
46054590
4606fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {4591fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
4607 if (f.liveness.isUnused(inst)) return .none;
4608 const writer = f.object.writer();4592 const writer = f.object.writer();
4609 const local = try f.allocLocal(inst, Type.usize);4593 const local = try f.allocLocal(inst, Type.usize);
4610 try f.writeCValue(writer, local, .Other);4594 try f.writeCValue(writer, local, .Other);
...@@ -4640,7 +4624,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4640,7 +4624,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
4640 const writer = f.object.writer();4624 const writer = f.object.writer();
46414625
4642 try writer.writeAll("for (;;) ");4626 try writer.writeAll("for (;;) ");
4643 try genBody(f, body);4627 try genBody(f, body); // no need to restore state, we're noreturn
4644 try writer.writeByte('\n');4628 try writer.writeByte('\n');
46454629
4646 return .none;4630 return .none;
...@@ -4656,61 +4640,24 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4656,61 +4640,24 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4656 const liveness_condbr = f.liveness.getCondBr(inst);4640 const liveness_condbr = f.liveness.getCondBr(inst);
4657 const writer = f.object.writer();4641 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
4682 try writer.writeAll("if (");4643 try writer.writeAll("if (");
4683 try f.writeCValue(writer, cond, .Other);4644 try f.writeCValue(writer, cond, .Other);
4684 try writer.writeAll(") ");4645 try writer.writeAll(") ");
4685 try genBody(f, then_body);
46864646
4687 // TODO: If body ends in goto, elide the else block?4647 try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false);
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 }
46944648
4695 f.value_map.deinit();4649 // We don't need to use `genBodyResolveState` for the else block, because this instruction is
4696 f.value_map = cloned_map.move();4650 // noreturn so must terminate a body, therefore we don't need to leave `value_map` or
4697 const free_locals = &f.free_locals_map;4651 // `free_locals_map` well defined (our parent is responsible for doing that).
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);
47064652
4707 if (needs_else) {4653 for (liveness_condbr.else_deaths) |death| {
4708 try genBody(f, else_body);4654 try die(f, inst, Air.indexToRef(death));
4709 } else {
4710 try genBodyInner(f, else_body);
4711 }4655 }
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
4715 return .none;4662 return .none;
4716}4663}
...@@ -4741,9 +4688,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4741,9 +4688,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4741 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1);4688 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1);
4742 defer gpa.free(liveness.deaths);4689 defer gpa.free(liveness.deaths);
47434690
4744 // On the final iteration we do not clone the map. This ensures that4691 // On the final iteration we do not need to fix any state. This is because, like in the `else`
4745 // lowering proceeds after the switch_br taking into account the4692 // branch of a `cond_br`, our parent has to do it for this entire body anyway.
4746 // mutations to the liveness information.
4747 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);4693 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
47484694
4749 var extra_index: usize = switch_br.end;4695 var extra_index: usize = switch_br.end;
...@@ -4767,56 +4713,23 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4767,56 +4713,23 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4767 try writer.writeByte(' ');4713 try writer.writeByte(' ');
47684714
4769 if (case_i != last_case_i) {4715 if (case_i != last_case_i) {
4770 const old_value_map = f.value_map;4716 try genBodyResolveState(f, inst, liveness.deaths[case_i], case_body, false);
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);
4804 } else {4717 } else {
4805 for (liveness.deaths[case_i]) |operand| {4718 for (liveness.deaths[case_i]) |death| {
4806 try die(f, inst, Air.indexToRef(operand));4719 try die(f, inst, Air.indexToRef(death));
4807 }4720 }
4808 try genBody(f, case_body);4721 try genBody(f, case_body);
4809 }4722 }
48104723
4811 // The case body must be noreturn so we don't need to insert a break.4724 // The case body must be noreturn so we don't need to insert a break.
4812
4813 }4725 }
48144726
4815 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];4727 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
4816 try f.object.indent_writer.insertNewline();4728 try f.object.indent_writer.insertNewline();
4817 if (else_body.len > 0) {4729 if (else_body.len > 0) {
4818 for (liveness.deaths[liveness.deaths.len - 1]) |operand| {4730 // Note that this must be the last case (i.e. the `last_case_i` case was not hit above)
4819 try die(f, inst, Air.indexToRef(operand));4731 for (liveness.deaths[liveness.deaths.len - 1]) |death| {
4732 try die(f, inst, Air.indexToRef(death));
4820 }4733 }
4821 try writer.writeAll("default: ");4734 try writer.writeAll("default: ");
4822 try genBody(f, else_body);4735 try genBody(f, else_body);
...@@ -4843,6 +4756,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4843,6 +4756,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4843 const extra = f.air.extraData(Air.Asm, ty_pl.payload);4756 const extra = f.air.extraData(Air.Asm, ty_pl.payload);
4844 const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;4757 const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
4845 const clobbers_len = @truncate(u31, extra.data.flags);4758 const clobbers_len = @truncate(u31, extra.data.flags);
4759 const gpa = f.object.dg.gpa;
4846 var extra_i: usize = extra.end;4760 var extra_i: usize = extra.end;
4847 const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);4761 const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);
4848 extra_i += outputs.len;4762 extra_i += outputs.len;
...@@ -4850,8 +4764,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4850,8 +4764,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4850 extra_i += inputs.len;4764 extra_i += inputs.len;
48514765
4852 const result = result: {4766 const result = result: {
4853 if (!is_volatile and f.liveness.isUnused(inst)) break :result .none;
4854
4855 const writer = f.object.writer();4767 const writer = f.object.writer();
4856 const inst_ty = f.air.typeOfIndex(inst);4768 const inst_ty = f.air.typeOfIndex(inst);
4857 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {4769 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
...@@ -4887,6 +4799,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4887,6 +4799,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4887 try writer.writeAll("register ");4799 try writer.writeAll("register ");
4888 const alignment = 0;4800 const alignment = 0;
4889 const local_value = try f.allocLocalValue(output_ty, alignment);4801 const local_value = try f.allocLocalValue(output_ty, alignment);
4802 try f.allocs.put(gpa, local_value.new_local, false);
4890 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);4803 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
4891 try writer.writeAll(" __asm(\"");4804 try writer.writeAll(" __asm(\"");
4892 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);4805 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
...@@ -4919,6 +4832,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4919,6 +4832,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4919 if (is_reg) try writer.writeAll("register ");4832 if (is_reg) try writer.writeAll("register ");
4920 const alignment = 0;4833 const alignment = 0;
4921 const local_value = try f.allocLocalValue(input_ty, alignment);4834 const local_value = try f.allocLocalValue(input_ty, alignment);
4835 try f.allocs.put(gpa, local_value.new_local, false);
4922 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);4836 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
4923 if (is_reg) {4837 if (is_reg) {
4924 try writer.writeAll(" __asm(\"");4838 try writer.writeAll(" __asm(\"");
...@@ -5101,11 +5015,6 @@ fn airIsNull(...@@ -5101,11 +5015,6 @@ fn airIsNull(
5101) !CValue {5015) !CValue {
5102 const un_op = f.air.instructions.items(.data)[inst].un_op;5016 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
5109 const writer = f.object.writer();5018 const writer = f.object.writer();
5110 const operand = try f.resolveInst(un_op);5019 const operand = try f.resolveInst(un_op);
5111 try reap(f, inst, &.{un_op});5020 try reap(f, inst, &.{un_op});
...@@ -5151,11 +5060,6 @@ fn airIsNull(...@@ -5151,11 +5060,6 @@ fn airIsNull(
5151fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {5060fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5152 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5061 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
5159 const operand = try f.resolveInst(ty_op.operand);5063 const operand = try f.resolveInst(ty_op.operand);
5160 try reap(f, inst, &.{ty_op.operand});5064 try reap(f, inst, &.{ty_op.operand});
5161 const opt_ty = f.air.typeOf(ty_op.operand);5065 const opt_ty = f.air.typeOf(ty_op.operand);
...@@ -5203,11 +5107,6 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5203,11 +5107,6 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5203fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {5107fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5204 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5108 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
5211 const writer = f.object.writer();5110 const writer = f.object.writer();
5212 const operand = try f.resolveInst(ty_op.operand);5111 const operand = try f.resolveInst(ty_op.operand);
5213 try reap(f, inst, &.{ty_op.operand});5112 try reap(f, inst, &.{ty_op.operand});
...@@ -5337,11 +5236,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5337,11 +5236,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5337 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;5236 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5338 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;5237 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
5345 const container_ptr_val = try f.resolveInst(extra.struct_operand);5239 const container_ptr_val = try f.resolveInst(extra.struct_operand);
5346 try reap(f, inst, &.{extra.struct_operand});5240 try reap(f, inst, &.{extra.struct_operand});
5347 const container_ptr_ty = f.air.typeOf(extra.struct_operand);5241 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
...@@ -5351,11 +5245,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5351,11 +5245,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5351fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {5245fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
5352 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5246 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
5359 const container_ptr_val = try f.resolveInst(ty_op.operand);5248 const container_ptr_val = try f.resolveInst(ty_op.operand);
5360 try reap(f, inst, &.{ty_op.operand});5249 try reap(f, inst, &.{ty_op.operand});
5361 const container_ptr_ty = f.air.typeOf(ty_op.operand);5250 const container_ptr_ty = f.air.typeOf(ty_op.operand);
...@@ -5366,11 +5255,6 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5366,11 +5255,6 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5366 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;5255 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5367 const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;5256 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
5374 const target = f.object.dg.module.getTarget();5258 const target = f.object.dg.module.getTarget();
5375 const container_ptr_ty = f.air.typeOfIndex(inst);5259 const container_ptr_ty = f.air.typeOfIndex(inst);
5376 const container_ty = container_ptr_ty.childType();5260 const container_ty = container_ptr_ty.childType();
...@@ -5489,11 +5373,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5489,11 +5373,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5489 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;5373 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5490 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;5374 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
5497 const inst_ty = f.air.typeOfIndex(inst);5376 const inst_ty = f.air.typeOfIndex(inst);
5498 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {5377 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
5499 try reap(f, inst, &.{extra.struct_operand});5378 try reap(f, inst, &.{extra.struct_operand});
...@@ -5639,11 +5518,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5639,11 +5518,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5639fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {5518fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5640 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5519 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
5647 const inst_ty = f.air.typeOfIndex(inst);5521 const inst_ty = f.air.typeOfIndex(inst);
5648 const operand = try f.resolveInst(ty_op.operand);5522 const operand = try f.resolveInst(ty_op.operand);
5649 const operand_ty = f.air.typeOf(ty_op.operand);5523 const operand_ty = f.air.typeOf(ty_op.operand);
...@@ -5676,11 +5550,6 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5676,11 +5550,6 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5676fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {5550fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
5677 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5551 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
5684 const inst_ty = f.air.typeOfIndex(inst);5553 const inst_ty = f.air.typeOfIndex(inst);
5685 const operand = try f.resolveInst(ty_op.operand);5554 const operand = try f.resolveInst(ty_op.operand);
5686 try reap(f, inst, &.{ty_op.operand});5555 try reap(f, inst, &.{ty_op.operand});
...@@ -5718,11 +5587,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5718,11 +5587,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
5718fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {5587fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
5719 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5588 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
5726 const inst_ty = f.air.typeOfIndex(inst);5590 const inst_ty = f.air.typeOfIndex(inst);
5727 const payload = try f.resolveInst(ty_op.operand);5591 const payload = try f.resolveInst(ty_op.operand);
5728 try reap(f, inst, &.{ty_op.operand});5592 try reap(f, inst, &.{ty_op.operand});
...@@ -5764,10 +5628,6 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5764,10 +5628,6 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
57645628
5765fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {5629fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5766 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5630 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
5772 const writer = f.object.writer();5632 const writer = f.object.writer();
5773 const operand = try f.resolveInst(ty_op.operand);5633 const operand = try f.resolveInst(ty_op.operand);
...@@ -5831,7 +5691,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5831,7 +5691,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5831}5691}
58325692
5833fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {5693fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
5834 if (f.liveness.isUnused(inst)) return .none;5694 _ = inst;
5835 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});5695 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
5836}5696}
58375697
...@@ -5847,10 +5707,6 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5847,10 +5707,6 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
58475707
5848fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {5708fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5849 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5709 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
5855 const inst_ty = f.air.typeOfIndex(inst);5711 const inst_ty = f.air.typeOfIndex(inst);
5856 const payload_ty = inst_ty.errorUnionPayload();5712 const payload_ty = inst_ty.errorUnionPayload();
...@@ -5885,11 +5741,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5885,11 +5741,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5885fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {5741fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
5886 const un_op = f.air.instructions.items(.data)[inst].un_op;5742 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
5893 const writer = f.object.writer();5744 const writer = f.object.writer();
5894 const operand = try f.resolveInst(un_op);5745 const operand = try f.resolveInst(un_op);
5895 try reap(f, inst, &.{un_op});5746 try reap(f, inst, &.{un_op});
...@@ -5923,11 +5774,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -5923,11 +5774,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
5923fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {5774fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5924 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5775 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
5931 const operand = try f.resolveInst(ty_op.operand);5777 const operand = try f.resolveInst(ty_op.operand);
5932 try reap(f, inst, &.{ty_op.operand});5778 try reap(f, inst, &.{ty_op.operand});
5933 const inst_ty = f.air.typeOfIndex(inst);5779 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5961,11 +5807,6 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5961,11 +5807,6 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5961fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {5807fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
5962 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5808 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
5969 const inst_ty = f.air.typeOfIndex(inst);5810 const inst_ty = f.air.typeOfIndex(inst);
5970 const operand = try f.resolveInst(ty_op.operand);5811 const operand = try f.resolveInst(ty_op.operand);
5971 try reap(f, inst, &.{ty_op.operand});5812 try reap(f, inst, &.{ty_op.operand});
...@@ -6009,11 +5850,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6009,11 +5850,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
6009fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {5850fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
6010 const un_op = f.air.instructions.items(.data)[inst].un_op;5851 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
6017 const operand = try f.resolveInst(un_op);5853 const operand = try f.resolveInst(un_op);
6018 try reap(f, inst, &.{un_op});5854 try reap(f, inst, &.{un_op});
6019 const inst_ty = f.air.typeOfIndex(inst);5855 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6037,11 +5873,6 @@ fn airUnBuiltinCall(...@@ -6037,11 +5873,6 @@ fn airUnBuiltinCall(
6037) !CValue {5873) !CValue {
6038 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5874 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
6045 const operand = try f.resolveInst(ty_op.operand);5876 const operand = try f.resolveInst(ty_op.operand);
6046 try reap(f, inst, &.{ty_op.operand});5877 try reap(f, inst, &.{ty_op.operand});
6047 const inst_ty = f.air.typeOfIndex(inst);5878 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6085,11 +5916,6 @@ fn airBinBuiltinCall(...@@ -6085,11 +5916,6 @@ fn airBinBuiltinCall(
6085) !CValue {5916) !CValue {
6086 const bin_op = f.air.instructions.items(.data)[inst].bin_op;5917 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
6093 const operand_ty = f.air.typeOf(bin_op.lhs);5919 const operand_ty = f.air.typeOf(bin_op.lhs);
6094 const operand_cty = try f.typeToCType(operand_ty, .complete);5920 const operand_cty = try f.typeToCType(operand_ty, .complete);
6095 const is_big = operand_cty.tag() == .array;5921 const is_big = operand_cty.tag() == .array;
...@@ -6142,11 +5968,6 @@ fn airCmpBuiltinCall(...@@ -6142,11 +5968,6 @@ fn airCmpBuiltinCall(
6142 operation: enum { cmp, operator },5968 operation: enum { cmp, operator },
6143 info: BuiltinInfo,5969 info: BuiltinInfo,
6144) !CValue {5970) !CValue {
6145 if (f.liveness.isUnused(inst)) {
6146 try reap(f, inst, &.{ data.lhs, data.rhs });
6147 return .none;
6148 }
6149
6150 const lhs = try f.resolveInst(data.lhs);5971 const lhs = try f.resolveInst(data.lhs);
6151 const rhs = try f.resolveInst(data.rhs);5972 const rhs = try f.resolveInst(data.rhs);
6152 try reap(f, inst, &.{ data.lhs, data.rhs });5973 try reap(f, inst, &.{ data.lhs, data.rhs });
...@@ -6317,9 +6138,6 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6317,9 +6138,6 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
6317 const ptr = try f.resolveInst(atomic_load.ptr);6138 const ptr = try f.resolveInst(atomic_load.ptr);
6318 try reap(f, inst, &.{atomic_load.ptr});6139 try reap(f, inst, &.{atomic_load.ptr});
6319 const ptr_ty = f.air.typeOf(atomic_load.ptr);6140 const ptr_ty = f.air.typeOf(atomic_load.ptr);
6320 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
6321 return .none;
6322 }
63236141
6324 const inst_ty = f.air.typeOfIndex(inst);6142 const inst_ty = f.air.typeOfIndex(inst);
6325 const writer = f.object.writer();6143 const writer = f.object.writer();
...@@ -6463,11 +6281,6 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6463,11 +6281,6 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6463fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6281fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6464 const ty_op = f.air.instructions.items(.data)[inst].ty_op;6282 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
6471 const operand = try f.resolveInst(ty_op.operand);6284 const operand = try f.resolveInst(ty_op.operand);
6472 try reap(f, inst, &.{ty_op.operand});6285 try reap(f, inst, &.{ty_op.operand});
64736286
...@@ -6491,11 +6304,6 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6491,11 +6304,6 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6491fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {6304fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6492 const un_op = f.air.instructions.items(.data)[inst].un_op;6305 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
6499 const inst_ty = f.air.typeOfIndex(inst);6307 const inst_ty = f.air.typeOfIndex(inst);
6500 const enum_ty = f.air.typeOf(un_op);6308 const enum_ty = f.air.typeOf(un_op);
6501 const operand = try f.resolveInst(un_op);6309 const operand = try f.resolveInst(un_op);
...@@ -6516,11 +6324,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6516,11 +6324,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6516fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {6324fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
6517 const un_op = f.air.instructions.items(.data)[inst].un_op;6325 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
6524 const writer = f.object.writer();6327 const writer = f.object.writer();
6525 const inst_ty = f.air.typeOfIndex(inst);6328 const inst_ty = f.air.typeOfIndex(inst);
6526 const operand = try f.resolveInst(un_op);6329 const operand = try f.resolveInst(un_op);
...@@ -6537,11 +6340,6 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6537,11 +6340,6 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
6537fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {6340fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6538 const ty_op = f.air.instructions.items(.data)[inst].ty_op;6341 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
6545 const operand = try f.resolveInst(ty_op.operand);6343 const operand = try f.resolveInst(ty_op.operand);
6546 try reap(f, inst, &.{ty_op.operand});6344 try reap(f, inst, &.{ty_op.operand});
65476345
...@@ -6573,11 +6371,6 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6573,11 +6371,6 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
6573 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6371 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
6574 const extra = f.air.extraData(Air.Bin, pl_op.payload).data;6372 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
6581 const pred = try f.resolveInst(pl_op.operand);6374 const pred = try f.resolveInst(pl_op.operand);
6582 const lhs = try f.resolveInst(extra.lhs);6375 const lhs = try f.resolveInst(extra.lhs);
6583 const rhs = try f.resolveInst(extra.rhs);6376 const rhs = try f.resolveInst(extra.rhs);
...@@ -6609,11 +6402,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6609,11 +6402,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
6609 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;6402 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
6610 const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data;6403 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
6617 const mask = f.air.values[extra.mask];6405 const mask = f.air.values[extra.mask];
6618 const lhs = try f.resolveInst(extra.a);6406 const lhs = try f.resolveInst(extra.a);
6619 const rhs = try f.resolveInst(extra.b);6407 const rhs = try f.resolveInst(extra.b);
...@@ -6655,11 +6443,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6655,11 +6443,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
6655fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {6443fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
6656 const reduce = f.air.instructions.items(.data)[inst].reduce;6444 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
6663 const target = f.object.dg.module.getTarget();6446 const target = f.object.dg.module.getTarget();
6664 const scalar_ty = f.air.typeOfIndex(inst);6447 const scalar_ty = f.air.typeOfIndex(inst);
6665 const operand = try f.resolveInst(reduce.operand);6448 const operand = try f.resolveInst(reduce.operand);
...@@ -6831,8 +6614,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6831,8 +6614,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6831 }6614 }
6832 }6615 }
68336616
6834 if (f.liveness.isUnused(inst)) return .none;
6835
6836 const target = f.object.dg.module.getTarget();6617 const target = f.object.dg.module.getTarget();
68376618
6838 const writer = f.object.writer();6619 const writer = f.object.writer();
...@@ -6999,11 +6780,6 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6999,11 +6780,6 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6999 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;6780 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
7000 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;6781 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
7007 const union_ty = f.air.typeOfIndex(inst);6783 const union_ty = f.air.typeOfIndex(inst);
7008 const target = f.object.dg.module.getTarget();6784 const target = f.object.dg.module.getTarget();
7009 const union_obj = union_ty.cast(Type.Payload.Union).?.data;6785 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
...@@ -7070,8 +6846,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7070,8 +6846,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
7070}6846}
70716847
7072fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {6848fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
7073 if (f.liveness.isUnused(inst)) return .none;
7074
7075 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6849 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
70766850
7077 const writer = f.object.writer();6851 const writer = f.object.writer();
...@@ -7104,10 +6878,6 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7104,10 +6878,6 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
71046878
7105fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {6879fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
7106 const un_op = f.air.instructions.items(.data)[inst].un_op;6880 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
7112 const operand = try f.resolveInst(un_op);6882 const operand = try f.resolveInst(un_op);
7113 try reap(f, inst, &.{un_op});6883 try reap(f, inst, &.{un_op});
...@@ -7133,10 +6903,6 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7133,10 +6903,6 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
71336903
7134fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {6904fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
7135 const un_op = f.air.instructions.items(.data)[inst].un_op;6905 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
7141 const operand = try f.resolveInst(un_op);6907 const operand = try f.resolveInst(un_op);
7142 try reap(f, inst, &.{un_op});6908 try reap(f, inst, &.{un_op});
...@@ -7164,10 +6930,6 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal...@@ -7164,10 +6930,6 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
71646930
7165fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {6931fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
7166 const bin_op = f.air.instructions.items(.data)[inst].bin_op;6932 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
7172 const lhs = try f.resolveInst(bin_op.lhs);6934 const lhs = try f.resolveInst(bin_op.lhs);
7173 const rhs = try f.resolveInst(bin_op.rhs);6935 const rhs = try f.resolveInst(bin_op.rhs);
...@@ -7200,10 +6962,6 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa...@@ -7200,10 +6962,6 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
7200fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {6962fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7201 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6963 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
7202 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;6964 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
7208 const mulend1 = try f.resolveInst(bin_op.lhs);6966 const mulend1 = try f.resolveInst(bin_op.lhs);
7209 const mulend2 = try f.resolveInst(bin_op.rhs);6967 const mulend2 = try f.resolveInst(bin_op.rhs);
...@@ -7236,8 +6994,6 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7236,8 +6994,6 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7236}6994}
72376995
7238fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {6996fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
7239 if (f.liveness.isUnused(inst)) return .none;
7240
7241 const inst_ty = f.air.typeOfIndex(inst);6997 const inst_ty = f.air.typeOfIndex(inst);
7242 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);6998 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
7243 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;6999 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 {...@@ -7256,10 +7012,6 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
72567012
7257fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {7013fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
7258 const ty_op = f.air.instructions.items(.data)[inst].ty_op;7014 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
7264 const inst_ty = f.air.typeOfIndex(inst);7016 const inst_ty = f.air.typeOfIndex(inst);
7265 const va_list = try f.resolveInst(ty_op.operand);7017 const va_list = try f.resolveInst(ty_op.operand);
...@@ -7291,10 +7043,6 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7291,10 +7043,6 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
72917043
7292fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {7044fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
7293 const ty_op = f.air.instructions.items(.data)[inst].ty_op;7045 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
7299 const inst_ty = f.air.typeOfIndex(inst);7047 const inst_ty = f.air.typeOfIndex(inst);
7300 const va_list = try f.resolveInst(ty_op.operand);7048 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...@@ -7858,7 +7606,6 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in
7858 const gpa = f.object.dg.gpa;7606 const gpa = f.object.dg.gpa;
7859 const local = &f.locals.items[local_index];7607 const local = &f.locals.items[local_index];
7860 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });7608 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });
7861 if (f.is_in_clone != local.is_in_clone) return;
7862 const gop = try f.free_locals_map.getOrPut(gpa, local.getType());7609 const gop = try f.free_locals_map.getOrPut(gpa, local.getType());
7863 if (!gop.found_existing) gop.value_ptr.* = .{};7610 if (!gop.found_existing) gop.value_ptr.* = .{};
7864 if (std.debug.runtime_safety) {7611 if (std.debug.runtime_safety) {
...@@ -7916,35 +7663,3 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {...@@ -7916,35 +7663,3 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
7916 }7663 }
7917 map.deinit(gpa);7664 map.deinit(gpa);
7918}7665}
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}