aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig532
-rw-r--r--src/codegen/llvm.zig193
-rw-r--r--src/codegen/spirv.zig5
3 files changed, 132 insertions, 598 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index f659827f09..d2d594c901 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -78,7 +78,6 @@ const LoopDepth = u16;
const Local = struct {
cty_idx: CType.Index,
alignas: CType.AlignAs,
- is_in_clone: bool,
pub fn getType(local: Local) LocalType {
return .{ .cty_idx = local.cty_idx, .alignas = local.alignas };
@@ -275,16 +274,13 @@ pub const Function = struct {
/// All the locals, to be emitted at the top of the function.
locals: std.ArrayListUnmanaged(Local) = .{},
/// Which locals are available for reuse, based on Type.
- /// Only locals in the last stack entry are available for reuse,
- /// other entries will become available on loop exit.
free_locals_map: LocalsMap = .{},
- is_in_clone: bool = false,
/// Locals which will not be freed by Liveness. This is used after a
/// Function body is lowered in order to make `free_locals_map` have
/// 100% of the locals within so that it can be used to render the block
/// of variable declarations at the top of a function, sorted descending
/// by type alignment.
- /// The value is whether the alloc is static or not.
+ /// The value is whether the alloc needs to be emitted in the header.
allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},
/// Needed for memory used by the keys of free_locals_map entries.
arena: std.heap.ArenaAllocator,
@@ -302,7 +298,7 @@ pub const Function = struct {
const alignment = 0;
const decl_c_value = try f.allocLocalValue(ty, alignment);
const gpa = f.object.dg.gpa;
- try f.allocs.put(gpa, decl_c_value.new_local, true);
+ try f.allocs.put(gpa, decl_c_value.new_local, false);
try writer.writeAll("static ");
try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
try writer.writeAll(" = ");
@@ -323,14 +319,15 @@ pub const Function = struct {
};
}
- /// Skips the reuse logic.
+ /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
+ /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
+ /// that responsibility lies with the caller.
fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
const gpa = f.object.dg.gpa;
const target = f.object.dg.module.getTarget();
try f.locals.append(gpa, .{
.cty_idx = try f.typeToIndex(ty, .complete),
.alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),
- .is_in_clone = f.is_in_clone,
});
return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
}
@@ -341,7 +338,8 @@ pub const Function = struct {
return result;
}
- /// Only allocates the local; does not print anything.
+ /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
+ /// not be used for persistent locals (i.e. those in `allocs`).
fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
const target = f.object.dg.module.getTarget();
if (f.free_locals_map.getPtr(.{
@@ -2586,7 +2584,7 @@ pub fn genFunc(f: *Function) !void {
f.free_locals_map.clearRetainingCapacity();
const main_body = f.air.getMainBody();
- try genBody(f, main_body);
+ try genBodyResolveState(f, undefined, &.{}, main_body, false);
try o.indent_writer.insertNewline();
@@ -2597,8 +2595,8 @@ pub fn genFunc(f: *Function) !void {
// alignment, descending.
const free_locals = &f.free_locals_map;
assert(f.value_map.count() == 0); // there must not be any unfreed locals
- for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
- if (value) continue; // static
+ for (f.allocs.keys(), f.allocs.values()) |local_index, should_emit| {
+ if (!should_emit) continue;
const local = f.locals.items[local_index];
log.debug("inserting local {d} into free_locals", .{local_index});
const gop = try free_locals.getOrPut(gpa, local.getType());
@@ -2715,6 +2713,10 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
}
}
+/// Generate code for an entire body which ends with a `noreturn` instruction. The states of
+/// `value_map` and `free_locals_map` are undefined after the generation, and new locals may not
+/// have been added to `free_locals_map`. For a version of this function that restores this state,
+/// see `genBodyResolveState`.
fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
const writer = f.object.writer();
if (body.len == 0) {
@@ -2728,10 +2730,69 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
}
}
+/// Generate code for an entire body which ends with a `noreturn` instruction. The states of
+/// `value_map` and `free_locals_map` are restored to their original values, and any non-allocated
+/// locals introduced within the body are correctly added to `free_locals_map`. Operands in
+/// `leading_deaths` have their deaths processed before the body is generated.
+/// A scope is introduced (using braces) only if `inner` is `false`.
+/// If `leading_deaths` is empty, `inst` may be `undefined`.
+fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) error{ AnalysisFail, OutOfMemory }!void {
+ if (body.len == 0) {
+ // Don't go to the expense of cloning everything!
+ if (!inner) try f.object.writer().writeAll("{}");
+ return;
+ }
+
+ // TODO: we can probably avoid the copies in some other common cases too.
+
+ const gpa = f.object.dg.gpa;
+
+ // Save the original value_map and free_locals_map so that we can restore them after the body.
+ var old_value_map = try f.value_map.clone();
+ defer old_value_map.deinit();
+ var old_free_locals = try cloneFreeLocalsMap(gpa, &f.free_locals_map);
+ defer deinitFreeLocalsMap(gpa, &old_free_locals);
+
+ // Remember how many locals there were before entering the body so that we can free any that
+ // were newly introduced. Any new locals must necessarily be logically free after the then
+ // branch is complete.
+ const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
+
+ for (leading_deaths) |death| {
+ try die(f, inst, Air.indexToRef(death));
+ }
+
+ if (inner) {
+ try genBodyInner(f, body);
+ } else {
+ try genBody(f, body);
+ }
+
+ f.value_map.deinit();
+ f.value_map = old_value_map.move();
+ deinitFreeLocalsMap(gpa, &f.free_locals_map);
+ f.free_locals_map = old_free_locals.move();
+
+ // Now, use the lengths we stored earlier to detect any locals the body generated, and free
+ // them, unless they were used to store allocs.
+
+ for (pre_locals_len..f.locals.items.len) |local_i| {
+ const local_index = @intCast(LocalIndex, local_i);
+ if (f.allocs.contains(local_index)) {
+ continue;
+ }
+ try freeLocal(f, inst, local_index, 0);
+ }
+}
+
fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
const air_tags = f.air.instructions.items(.tag);
for (body) |inst| {
+ if (f.liveness.isUnused(inst) and !f.air.mustLower(inst)) {
+ continue;
+ }
+
const result_value = switch (air_tags[inst]) {
// zig fmt: off
.constant => unreachable, // excluded from function bodies
@@ -3009,11 +3070,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -3032,10 +3088,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.air.typeOfIndex(inst);
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- const ptr_ty = f.air.typeOf(bin_op.lhs);
- if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
- !inst_ty.hasRuntimeBitsIgnoreComptime())
- {
+ if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
@@ -3074,11 +3127,6 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const ptr_ty = f.air.typeOf(bin_op.lhs);
const child_ty = ptr_ty.childType();
@@ -3116,10 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.air.typeOfIndex(inst);
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- const slice_ty = f.air.typeOf(bin_op.lhs);
- if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
- !inst_ty.hasRuntimeBitsIgnoreComptime())
- {
+ if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
@@ -3158,11 +3203,6 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const slice_ty = f.air.typeOf(bin_op.lhs);
const child_ty = slice_ty.elemType2();
const slice = try f.resolveInst(bin_op.lhs);
@@ -3188,7 +3228,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
const inst_ty = f.air.typeOfIndex(inst);
- if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
+ if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
@@ -3224,40 +3264,34 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
-
const inst_ty = f.air.typeOfIndex(inst);
const elem_type = inst_ty.elemType();
if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
const target = f.object.dg.module.getTarget();
- const local = try f.allocAlignedLocal(
+ const local = try f.allocLocalValue(
elem_type,
- CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
inst_ty.ptrAlignment(target),
);
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
const gpa = f.object.dg.module.gpa;
- try f.allocs.put(gpa, local.new_local, false);
+ try f.allocs.put(gpa, local.new_local, true);
return .{ .local_ref = local.new_local };
}
fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
-
const inst_ty = f.air.typeOfIndex(inst);
const elem_ty = inst_ty.elemType();
if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
const target = f.object.dg.module.getTarget();
- const local = try f.allocAlignedLocal(
+ const local = try f.allocLocalValue(
elem_ty,
- CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
inst_ty.ptrAlignment(target),
);
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
const gpa = f.object.dg.module.gpa;
- try f.allocs.put(gpa, local.new_local, false);
+ try f.allocs.put(gpa, local.new_local, true);
return .{ .local_ref = local.new_local };
}
@@ -3293,9 +3327,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const ptr_info = ptr_scalar_ty.ptrInfo().data;
const src_ty = ptr_info.pointee_type;
- if (!src_ty.hasRuntimeBitsIgnoreComptime() or
- (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
- {
+ if (!src_ty.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{ty_op.operand});
return .none;
}
@@ -3442,11 +3474,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -3470,10 +3497,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -3569,10 +3592,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const writer = f.object.writer();
@@ -3746,11 +3765,6 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
@@ -3790,11 +3804,6 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
const scalar_ty = operand_ty.scalarType();
if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits);
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const op = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -3829,11 +3838,6 @@ fn airBinOp(
if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat())
return try airBinBuiltinCall(f, inst, operation, info);
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
@@ -3865,11 +3869,6 @@ fn airCmpOp(
data: anytype,
operator: std.math.CompareOperator,
) !CValue {
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ data.lhs, data.rhs });
- return .none;
- }
-
const operand_ty = f.air.typeOf(data.lhs);
const scalar_ty = operand_ty.scalarType();
@@ -3918,11 +3917,6 @@ fn airEquality(
) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const operand_ty = f.air.typeOf(bin_op.lhs);
const target = f.object.dg.module.getTarget();
const operand_bits = operand_ty.bitSize(target);
@@ -3987,11 +3981,6 @@ fn airEquality(
fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
@@ -4008,10 +3997,6 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
@@ -4059,11 +4044,6 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const inst_scalar_ty = inst_ty.scalarType();
@@ -4107,11 +4087,6 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const ptr = try f.resolveInst(bin_op.lhs);
const len = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
@@ -4316,6 +4291,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.Block, ty_pl.payload);
const body = f.air.extra[extra.end..][0..extra.data.body_len];
+ const liveness_block = f.liveness.getBlock(inst);
const block_id: usize = f.next_block_index;
f.next_block_index += 1;
@@ -4332,7 +4308,15 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
.result = result,
});
- try genBodyInner(f, body);
+ try genBodyResolveState(f, inst, &.{}, body, true);
+
+ assert(f.blocks.remove(inst));
+
+ // The body might result in some values we had beforehand being killed
+ for (liveness_block.deaths) |death| {
+ try die(f, inst, Air.indexToRef(death));
+ }
+
try f.object.indent_writer.insertNewline();
// label might be unused, add a dummy goto
// label must be followed by an expression, add an empty one.
@@ -4366,6 +4350,7 @@ fn lowerTry(
) !CValue {
const err_union = try f.resolveInst(operand);
const result_ty = f.air.typeOfIndex(inst);
+ const liveness_condbr = f.liveness.getCondBr(inst);
const writer = f.object.writer();
const payload_ty = err_union_ty.errorUnionPayload();
const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
@@ -4389,10 +4374,15 @@ fn lowerTry(
}
try writer.writeByte(')');
- try genBody(f, body);
+ try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
try f.object.indent_writer.insertNewline();
}
+ // Now we have the "then branch" (in terms of the liveness data); process any deaths.
+ for (liveness_condbr.then_deaths) |death| {
+ try die(f, inst, Air.indexToRef(death));
+ }
+
if (!payload_has_bits) {
if (!operand_is_ptr) {
return .none;
@@ -4466,10 +4456,6 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
const dest_ty = f.air.typeOfIndex(inst);
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -4593,7 +4579,6 @@ fn airBreakpoint(writer: anytype) !CValue {
}
fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
const writer = f.object.writer();
const local = try f.allocLocal(inst, Type.usize);
try f.writeCValue(writer, local, .Other);
@@ -4604,7 +4589,6 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
const writer = f.object.writer();
const local = try f.allocLocal(inst, Type.usize);
try f.writeCValue(writer, local, .Other);
@@ -4637,17 +4621,12 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const loop = f.air.extraData(Air.Block, ty_pl.payload);
const body = f.air.extra[loop.end..][0..loop.data.body_len];
- const liveness_loop = f.liveness.getLoop(inst);
const writer = f.object.writer();
try writer.writeAll("for (;;) ");
- try genBody(f, body);
+ try genBody(f, body); // no need to restore state, we're noreturn
try writer.writeByte('\n');
- for (liveness_loop.deaths) |operand| {
- try die(f, inst, Air.indexToRef(operand));
- }
-
return .none;
}
@@ -4661,61 +4640,24 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
const liveness_condbr = f.liveness.getCondBr(inst);
const writer = f.object.writer();
- // Keep using the original for the then branch; use a clone of the value
- // map for the else branch.
- const gpa = f.object.dg.gpa;
- var cloned_map = try f.value_map.clone();
- defer cloned_map.deinit();
- var cloned_frees = try cloneFreeLocalsMap(gpa, &f.free_locals_map);
- defer deinitFreeLocalsMap(gpa, &cloned_frees);
-
- // Remember how many locals there were before entering the then branch so
- // that we can notice and use them in the else branch. Any new locals must
- // necessarily be free already after the then branch is complete.
- const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
- // Remember how many allocs there were before entering the then branch so
- // that we can notice and make sure not to use them in the else branch.
- // Any new allocs must be removed from the free list.
- const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
- const was_in_clone = f.is_in_clone;
- f.is_in_clone = true;
-
- for (liveness_condbr.then_deaths) |operand| {
- try die(f, inst, Air.indexToRef(operand));
- }
-
try writer.writeAll("if (");
try f.writeCValue(writer, cond, .Other);
try writer.writeAll(") ");
- try genBody(f, then_body);
- // TODO: If body ends in goto, elide the else block?
- const needs_else = then_body.len <= 0 or f.air.instructions.items(.tag)[then_body[then_body.len - 1]] != .br;
- if (needs_else) {
- try writer.writeAll(" else ");
- } else {
- try writer.writeByte('\n');
- }
+ try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false);
- f.value_map.deinit();
- f.value_map = cloned_map.move();
- const free_locals = &f.free_locals_map;
- deinitFreeLocalsMap(gpa, free_locals);
- free_locals.* = cloned_frees.move();
- f.is_in_clone = was_in_clone;
- for (liveness_condbr.else_deaths) |operand| {
- try die(f, inst, Air.indexToRef(operand));
- }
-
- try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
+ // We don't need to use `genBodyResolveState` for the else block, because this instruction is
+ // noreturn so must terminate a body, therefore we don't need to leave `value_map` or
+ // `free_locals_map` well defined (our parent is responsible for doing that).
- if (needs_else) {
- try genBody(f, else_body);
- } else {
- try genBodyInner(f, else_body);
+ for (liveness_condbr.else_deaths) |death| {
+ try die(f, inst, Air.indexToRef(death));
}
- try f.object.indent_writer.insertNewline();
+ // We never actually need an else block, because our branches are noreturn so must (for
+ // instance) `br` to a block (label).
+
+ try genBodyInner(f, else_body);
return .none;
}
@@ -4746,9 +4688,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1);
defer gpa.free(liveness.deaths);
- // On the final iteration we do not clone the map. This ensures that
- // lowering proceeds after the switch_br taking into account the
- // mutations to the liveness information.
+ // On the final iteration we do not need to fix any state. This is because, like in the `else`
+ // branch of a `cond_br`, our parent has to do it for this entire body anyway.
const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
var extra_index: usize = switch_br.end;
@@ -4772,56 +4713,23 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeByte(' ');
if (case_i != last_case_i) {
- const old_value_map = f.value_map;
- f.value_map = try old_value_map.clone();
- var free_locals = &f.free_locals_map;
- const old_free_locals = free_locals.*;
- free_locals.* = try cloneFreeLocalsMap(gpa, free_locals);
-
- // Remember how many locals there were before entering each branch so that
- // we can notice and use them in subsequent branches. Any new locals must
- // necessarily be free already after the previous branch is complete.
- const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
- // Remember how many allocs there were before entering each branch so that
- // we can notice and make sure not to use them in subsequent branches.
- // Any new allocs must be removed from the free list.
- const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
- const was_in_clone = f.is_in_clone;
- f.is_in_clone = true;
-
- {
- defer {
- f.is_in_clone = was_in_clone;
- f.value_map.deinit();
- deinitFreeLocalsMap(gpa, free_locals);
- f.value_map = old_value_map;
- free_locals.* = old_free_locals;
- }
-
- for (liveness.deaths[case_i]) |operand| {
- try die(f, inst, Air.indexToRef(operand));
- }
-
- try genBody(f, case_body);
- }
-
- try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
+ try genBodyResolveState(f, inst, liveness.deaths[case_i], case_body, false);
} else {
- for (liveness.deaths[case_i]) |operand| {
- try die(f, inst, Air.indexToRef(operand));
+ for (liveness.deaths[case_i]) |death| {
+ try die(f, inst, Air.indexToRef(death));
}
try genBody(f, case_body);
}
// The case body must be noreturn so we don't need to insert a break.
-
}
const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
try f.object.indent_writer.insertNewline();
if (else_body.len > 0) {
- for (liveness.deaths[liveness.deaths.len - 1]) |operand| {
- try die(f, inst, Air.indexToRef(operand));
+ // Note that this must be the last case (i.e. the `last_case_i` case was not hit above)
+ for (liveness.deaths[liveness.deaths.len - 1]) |death| {
+ try die(f, inst, Air.indexToRef(death));
}
try writer.writeAll("default: ");
try genBody(f, else_body);
@@ -4848,6 +4756,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const extra = f.air.extraData(Air.Asm, ty_pl.payload);
const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0;
const clobbers_len = @truncate(u31, extra.data.flags);
+ const gpa = f.object.dg.gpa;
var extra_i: usize = extra.end;
const outputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
@@ -4855,8 +4764,6 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
extra_i += inputs.len;
const result = result: {
- if (!is_volatile and f.liveness.isUnused(inst)) break :result .none;
-
const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
@@ -4892,6 +4799,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll("register ");
const alignment = 0;
const local_value = try f.allocLocalValue(output_ty, alignment);
+ try f.allocs.put(gpa, local_value.new_local, false);
try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
try writer.writeAll(" __asm(\"");
try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
@@ -4924,6 +4832,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
if (is_reg) try writer.writeAll("register ");
const alignment = 0;
const local_value = try f.allocLocalValue(input_ty, alignment);
+ try f.allocs.put(gpa, local_value.new_local, false);
try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
if (is_reg) {
try writer.writeAll(" __asm(\"");
@@ -5106,11 +5015,6 @@ fn airIsNull(
) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const writer = f.object.writer();
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
@@ -5156,11 +5060,6 @@ fn airIsNull(
fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const opt_ty = f.air.typeOf(ty_op.operand);
@@ -5208,11 +5107,6 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const writer = f.object.writer();
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -5342,11 +5236,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{extra.struct_operand});
- return .none;
- }
-
const container_ptr_val = try f.resolveInst(extra.struct_operand);
try reap(f, inst, &.{extra.struct_operand});
const container_ptr_ty = f.air.typeOf(extra.struct_operand);
@@ -5356,11 +5245,6 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const container_ptr_val = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const container_ptr_ty = f.air.typeOf(ty_op.operand);
@@ -5371,11 +5255,6 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{extra.field_ptr});
- return .none;
- }
-
const target = f.object.dg.module.getTarget();
const container_ptr_ty = f.air.typeOfIndex(inst);
const container_ty = container_ptr_ty.childType();
@@ -5494,11 +5373,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{extra.struct_operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
try reap(f, inst, &.{extra.struct_operand});
@@ -5644,11 +5518,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
const operand_ty = f.air.typeOf(ty_op.operand);
@@ -5681,11 +5550,6 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -5723,11 +5587,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const payload = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -5769,10 +5628,6 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const writer = f.object.writer();
const operand = try f.resolveInst(ty_op.operand);
@@ -5836,7 +5691,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
+ _ = inst;
return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
}
@@ -5852,10 +5707,6 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const inst_ty = f.air.typeOfIndex(inst);
const payload_ty = inst_ty.errorUnionPayload();
@@ -5890,11 +5741,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const writer = f.object.writer();
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
@@ -5928,11 +5774,6 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const inst_ty = f.air.typeOfIndex(inst);
@@ -5966,11 +5807,6 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -6014,11 +5850,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const inst_ty = f.air.typeOfIndex(inst);
@@ -6042,11 +5873,6 @@ fn airUnBuiltinCall(
) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
const inst_ty = f.air.typeOfIndex(inst);
@@ -6090,11 +5916,6 @@ fn airBinBuiltinCall(
) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
-
const operand_ty = f.air.typeOf(bin_op.lhs);
const operand_cty = try f.typeToCType(operand_ty, .complete);
const is_big = operand_cty.tag() == .array;
@@ -6147,11 +5968,6 @@ fn airCmpBuiltinCall(
operation: enum { cmp, operator },
info: BuiltinInfo,
) !CValue {
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ data.lhs, data.rhs });
- return .none;
- }
-
const lhs = try f.resolveInst(data.lhs);
const rhs = try f.resolveInst(data.rhs);
try reap(f, inst, &.{ data.lhs, data.rhs });
@@ -6322,9 +6138,6 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const ptr = try f.resolveInst(atomic_load.ptr);
try reap(f, inst, &.{atomic_load.ptr});
const ptr_ty = f.air.typeOf(atomic_load.ptr);
- if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
- return .none;
- }
const inst_ty = f.air.typeOfIndex(inst);
const writer = f.object.writer();
@@ -6468,11 +6281,6 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -6496,11 +6304,6 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const inst_ty = f.air.typeOfIndex(inst);
const enum_ty = f.air.typeOf(un_op);
const operand = try f.resolveInst(un_op);
@@ -6521,11 +6324,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
-
const writer = f.object.writer();
const inst_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
@@ -6542,11 +6340,6 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
-
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
@@ -6578,11 +6371,6 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
- return .none;
- }
-
const pred = try f.resolveInst(pl_op.operand);
const lhs = try f.resolveInst(extra.lhs);
const rhs = try f.resolveInst(extra.rhs);
@@ -6614,11 +6402,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ extra.a, extra.b });
- return .none;
- }
-
const mask = f.air.values[extra.mask];
const lhs = try f.resolveInst(extra.a);
const rhs = try f.resolveInst(extra.b);
@@ -6660,11 +6443,6 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
const reduce = f.air.instructions.items(.data)[inst].reduce;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{reduce.operand});
- return .none;
- }
-
const target = f.object.dg.module.getTarget();
const scalar_ty = f.air.typeOfIndex(inst);
const operand = try f.resolveInst(reduce.operand);
@@ -6836,8 +6614,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
}
}
- if (f.liveness.isUnused(inst)) return .none;
-
const target = f.object.dg.module.getTarget();
const writer = f.object.writer();
@@ -7004,11 +6780,6 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{extra.init});
- return .none;
- }
-
const union_ty = f.air.typeOfIndex(inst);
const target = f.object.dg.module.getTarget();
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
@@ -7075,8 +6846,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
-
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const writer = f.object.writer();
@@ -7109,10 +6878,6 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
@@ -7138,10 +6903,6 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{un_op});
- return .none;
- }
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
@@ -7169,10 +6930,6 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
@@ -7205,10 +6962,6 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
- return .none;
- }
const mulend1 = try f.resolveInst(bin_op.lhs);
const mulend2 = try f.resolveInst(bin_op.rhs);
@@ -7241,8 +6994,6 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
- if (f.liveness.isUnused(inst)) return .none;
-
const inst_ty = f.air.typeOfIndex(inst);
const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
@@ -7261,10 +7012,6 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const inst_ty = f.air.typeOfIndex(inst);
const va_list = try f.resolveInst(ty_op.operand);
@@ -7296,10 +7043,6 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
- if (f.liveness.isUnused(inst)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
const inst_ty = f.air.typeOfIndex(inst);
const va_list = try f.resolveInst(ty_op.operand);
@@ -7863,7 +7606,6 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in
const gpa = f.object.dg.gpa;
const local = &f.locals.items[local_index];
log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });
- if (f.is_in_clone != local.is_in_clone) return;
const gop = try f.free_locals_map.getOrPut(gpa, local.getType());
if (!gop.found_existing) gop.value_ptr.* = .{};
if (std.debug.runtime_safety) {
@@ -7921,35 +7663,3 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
}
map.deinit(gpa);
}
-
-fn noticeBranchFrees(
- f: *Function,
- pre_locals_len: LocalIndex,
- pre_allocs_len: LocalIndex,
- inst: Air.Inst.Index,
-) !void {
- for (f.locals.items[pre_locals_len..], pre_locals_len..) |*local, local_i| {
- const local_index = @intCast(LocalIndex, local_i);
- if (f.allocs.contains(local_index)) {
- if (std.debug.runtime_safety) {
- // new allocs are no longer freeable, so make sure they aren't in the free list
- if (f.free_locals_map.getPtr(local.getType())) |locals_list| {
- assert(!locals_list.contains(local_index));
- }
- }
- continue;
- }
-
- // free cloned locals from other branches at current cloned-ness
- std.debug.assert(local.is_in_clone or !f.is_in_clone);
- local.is_in_clone = f.is_in_clone;
- try freeLocal(f, inst, local_index, 0);
- }
-
- for (f.allocs.keys()[pre_allocs_len..]) |local_i| {
- const local_index = @intCast(LocalIndex, local_i);
- const local = &f.locals.items[local_index];
- // new allocs are no longer freeable, so remove them from the free list
- if (f.free_locals_map.getPtr(local.getType())) |locals_list| _ = locals_list.swapRemove(local_index);
- }
-}
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index a081448155..897a582952 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -4523,6 +4523,10 @@ pub const FuncGen = struct {
fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
const air_tags = self.air.instructions.items(.tag);
for (body, 0..) |inst, i| {
+ if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
+ continue;
+ }
+
const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
// zig fmt: off
.add => try self.airAdd(inst, false),
@@ -5166,8 +5170,6 @@ pub const FuncGen = struct {
}
fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const list = try self.resolveInst(ty_op.operand);
const arg_ty = self.air.getRefType(ty_op.ty);
@@ -5177,8 +5179,6 @@ pub const FuncGen = struct {
}
fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const src_list = try self.resolveInst(ty_op.operand);
const va_list_ty = self.air.getRefType(ty_op.ty);
@@ -5226,8 +5226,6 @@ pub const FuncGen = struct {
}
fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const va_list_ty = self.air.typeOfIndex(inst);
const llvm_va_list_ty = try self.dg.lowerType(va_list_ty);
@@ -5254,7 +5252,6 @@ pub const FuncGen = struct {
}
fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -5266,7 +5263,6 @@ pub const FuncGen = struct {
}
fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
@@ -5281,8 +5277,6 @@ pub const FuncGen = struct {
}
fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const llvm_fn = try self.getCmpLtErrorsLenFunction();
@@ -5650,9 +5644,6 @@ pub const FuncGen = struct {
}
fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand_ty = self.air.typeOf(ty_op.operand);
const array_ty = operand_ty.childType();
@@ -5674,9 +5665,6 @@ pub const FuncGen = struct {
}
fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
@@ -5733,9 +5721,6 @@ pub const FuncGen = struct {
}
fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
self.builder.setFastMath(want_fast_math);
const target = self.dg.module.getTarget();
@@ -5792,16 +5777,12 @@ pub const FuncGen = struct {
}
fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
return self.builder.buildExtractValue(operand, index, "");
}
fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const slice_ptr = try self.resolveInst(ty_op.operand);
const slice_ptr_ty = self.air.typeOf(ty_op.operand);
@@ -5814,8 +5795,6 @@ pub const FuncGen = struct {
const inst = body_tail[0];
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const slice_ty = self.air.typeOf(bin_op.lhs);
- if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
-
const slice = try self.resolveInst(bin_op.lhs);
const index = try self.resolveInst(bin_op.rhs);
const elem_ty = slice_ty.childType();
@@ -5835,7 +5814,6 @@ pub const FuncGen = struct {
}
fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const slice_ty = self.air.typeOf(bin_op.lhs);
@@ -5850,7 +5828,6 @@ pub const FuncGen = struct {
fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
const inst = body_tail[0];
- if (self.liveness.isUnused(inst)) return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const array_ty = self.air.typeOf(bin_op.lhs);
@@ -5881,8 +5858,6 @@ pub const FuncGen = struct {
const inst = body_tail[0];
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const ptr_ty = self.air.typeOf(bin_op.lhs);
- if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
-
const elem_ty = ptr_ty.childType();
const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty);
const base_ptr = try self.resolveInst(bin_op.lhs);
@@ -5908,8 +5883,6 @@ pub const FuncGen = struct {
}
fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const ptr_ty = self.air.typeOf(bin_op.lhs);
@@ -5934,9 +5907,6 @@ pub const FuncGen = struct {
}
fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
const struct_ptr = try self.resolveInst(struct_field.struct_operand);
@@ -5949,8 +5919,6 @@ pub const FuncGen = struct {
inst: Air.Inst.Index,
field_index: u32,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const struct_ptr = try self.resolveInst(ty_op.operand);
const struct_ptr_ty = self.air.typeOf(ty_op.operand);
@@ -5959,8 +5927,6 @@ pub const FuncGen = struct {
fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
const inst = body_tail[0];
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
const struct_ty = self.air.typeOf(struct_field.struct_operand);
@@ -6060,8 +6026,6 @@ pub const FuncGen = struct {
}
fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
@@ -6083,9 +6047,6 @@ pub const FuncGen = struct {
}
fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
@@ -6263,8 +6224,6 @@ pub const FuncGen = struct {
const clobbers_len = @truncate(u31, extra.data.flags);
var extra_i: usize = extra.end;
- if (!is_volatile and self.liveness.isUnused(inst)) return null;
-
const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
@@ -6610,8 +6569,6 @@ pub const FuncGen = struct {
operand_is_ptr: bool,
pred: llvm.IntPredicate,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const operand_ty = self.air.typeOf(un_op);
@@ -6659,8 +6616,6 @@ pub const FuncGen = struct {
op: llvm.IntPredicate,
operand_is_ptr: bool,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const operand_ty = self.air.typeOf(un_op);
@@ -6701,8 +6656,6 @@ pub const FuncGen = struct {
}
fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.air.typeOf(ty_op.operand).childType();
@@ -6756,8 +6709,6 @@ pub const FuncGen = struct {
fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
const inst = body_tail[0];
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.air.typeOf(ty_op.operand);
@@ -6780,8 +6731,6 @@ pub const FuncGen = struct {
operand_is_ptr: bool,
) !?*llvm.Value {
const inst = body_tail[0];
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
@@ -6817,9 +6766,6 @@ pub const FuncGen = struct {
inst: Air.Inst.Index,
operand_is_ptr: bool,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
@@ -6893,8 +6839,6 @@ pub const FuncGen = struct {
}
fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.module.getTarget();
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
@@ -6911,8 +6855,6 @@ pub const FuncGen = struct {
}
fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const payload_ty = self.air.typeOf(ty_op.operand);
const non_null_bit = self.context.intType(8).constInt(1, .False);
@@ -6943,8 +6885,6 @@ pub const FuncGen = struct {
}
fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const err_un_ty = self.air.typeOfIndex(inst);
const operand = try self.resolveInst(ty_op.operand);
@@ -6978,8 +6918,6 @@ pub const FuncGen = struct {
}
fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const err_un_ty = self.air.typeOfIndex(inst);
const payload_ty = err_un_ty.errorUnionPayload();
@@ -7015,8 +6953,6 @@ pub const FuncGen = struct {
}
fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const index = pl_op.payload;
const llvm_u32 = self.context.intType(32);
@@ -7061,8 +6997,6 @@ pub const FuncGen = struct {
}
fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7074,8 +7008,6 @@ pub const FuncGen = struct {
}
fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7087,8 +7019,6 @@ pub const FuncGen = struct {
}
fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const ptr = try self.resolveInst(bin_op.lhs);
@@ -7103,7 +7033,6 @@ pub const FuncGen = struct {
}
fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7118,7 +7047,6 @@ pub const FuncGen = struct {
}
fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7129,8 +7057,6 @@ pub const FuncGen = struct {
}
fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7144,7 +7070,6 @@ pub const FuncGen = struct {
}
fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7159,7 +7084,6 @@ pub const FuncGen = struct {
}
fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7170,8 +7094,6 @@ pub const FuncGen = struct {
}
fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7184,7 +7106,6 @@ pub const FuncGen = struct {
}
fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7199,7 +7120,6 @@ pub const FuncGen = struct {
}
fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7210,8 +7130,6 @@ pub const FuncGen = struct {
}
fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7224,7 +7142,6 @@ pub const FuncGen = struct {
}
fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7236,7 +7153,6 @@ pub const FuncGen = struct {
}
fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7254,7 +7170,6 @@ pub const FuncGen = struct {
}
fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7287,7 +7202,6 @@ pub const FuncGen = struct {
}
fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7302,7 +7216,6 @@ pub const FuncGen = struct {
}
fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7317,7 +7230,6 @@ pub const FuncGen = struct {
}
fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@@ -7347,8 +7259,6 @@ pub const FuncGen = struct {
}
fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const base_ptr = try self.resolveInst(bin_op.lhs);
@@ -7368,8 +7278,6 @@ pub const FuncGen = struct {
}
fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const base_ptr = try self.resolveInst(bin_op.lhs);
@@ -7395,9 +7303,6 @@ pub const FuncGen = struct {
signed_intrinsic: []const u8,
unsigned_intrinsic: []const u8,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -7686,8 +7591,6 @@ pub const FuncGen = struct {
}
fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
@@ -7700,9 +7603,6 @@ pub const FuncGen = struct {
}
fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -7759,8 +7659,6 @@ pub const FuncGen = struct {
}
fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7768,8 +7666,6 @@ pub const FuncGen = struct {
}
fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7777,8 +7673,6 @@ pub const FuncGen = struct {
}
fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -7786,8 +7680,6 @@ pub const FuncGen = struct {
}
fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
@@ -7809,8 +7701,6 @@ pub const FuncGen = struct {
}
fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
@@ -7831,8 +7721,6 @@ pub const FuncGen = struct {
}
fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
@@ -7876,8 +7764,6 @@ pub const FuncGen = struct {
}
fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs);
@@ -7912,9 +7798,6 @@ pub const FuncGen = struct {
}
fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const target = self.dg.module.getTarget();
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const dest_ty = self.air.typeOfIndex(inst);
@@ -7937,8 +7820,6 @@ pub const FuncGen = struct {
}
fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
@@ -7946,9 +7827,6 @@ pub const FuncGen = struct {
}
fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
@@ -7978,9 +7856,6 @@ pub const FuncGen = struct {
}
fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
@@ -8010,9 +7885,6 @@ pub const FuncGen = struct {
}
fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
@@ -8020,8 +7892,6 @@ pub const FuncGen = struct {
}
fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand_ty = self.air.typeOf(ty_op.operand);
const inst_ty = self.air.typeOfIndex(inst);
@@ -8137,9 +8007,6 @@ pub const FuncGen = struct {
}
fn airBoolToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
return operand;
@@ -8189,7 +8056,6 @@ pub const FuncGen = struct {
}
fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
const ptr_ty = self.air.typeOfIndex(inst);
const pointee_type = ptr_ty.childType();
if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
@@ -8201,7 +8067,6 @@ pub const FuncGen = struct {
}
fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
const ptr_ty = self.air.typeOfIndex(inst);
const ret_ty = ptr_ty.childType();
if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
@@ -8289,8 +8154,6 @@ pub const FuncGen = struct {
const ptr = try fg.resolveInst(ty_op.operand);
elide: {
- if (ptr_info.@"volatile") break :elide;
- if (fg.liveness.isUnused(inst)) return null;
if (!isByRef(ptr_info.pointee_type)) break :elide;
if (!canElideLoad(fg, body_tail)) break :elide;
return ptr;
@@ -8314,8 +8177,7 @@ pub const FuncGen = struct {
}
fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
+ _ = inst;
const llvm_usize = try self.dg.lowerType(Type.usize);
const target = self.dg.module.getTarget();
if (!target_util.supportsReturnAddress(target)) {
@@ -8331,8 +8193,7 @@ pub const FuncGen = struct {
}
fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
+ _ = inst;
const llvm_i32 = self.context.intType(32);
const llvm_fn_name = "llvm.frameaddress.p0";
const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
@@ -8462,8 +8323,6 @@ pub const FuncGen = struct {
const ptr = try self.resolveInst(atomic_load.ptr);
const ptr_ty = self.air.typeOf(atomic_load.ptr);
const ptr_info = ptr_ty.ptrInfo().data;
- if (!ptr_info.@"volatile" and self.liveness.isUnused(inst))
- return null;
const elem_ty = ptr_info.pointee_type;
if (!elem_ty.hasRuntimeBitsIgnoreComptime())
return null;
@@ -8577,8 +8436,6 @@ pub const FuncGen = struct {
}
fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const un_ty = self.air.typeOf(ty_op.operand);
const target = self.dg.module.getTarget();
@@ -8603,8 +8460,6 @@ pub const FuncGen = struct {
}
fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const operand_ty = self.air.typeOf(un_op);
@@ -8613,7 +8468,6 @@ pub const FuncGen = struct {
}
fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const un_op = self.air.instructions.items(.data)[inst].un_op;
@@ -8624,8 +8478,6 @@ pub const FuncGen = struct {
}
fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand_ty = self.air.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
@@ -8652,8 +8504,6 @@ pub const FuncGen = struct {
}
fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand_ty = self.air.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
@@ -8679,8 +8529,6 @@ pub const FuncGen = struct {
}
fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.module.getTarget();
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand_ty = self.air.typeOf(ty_op.operand);
@@ -8734,8 +8582,6 @@ pub const FuncGen = struct {
}
fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const error_set_ty = self.air.getRefType(ty_op.ty);
@@ -8781,8 +8627,6 @@ pub const FuncGen = struct {
}
fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const enum_ty = self.air.typeOf(un_op);
@@ -8862,8 +8706,6 @@ pub const FuncGen = struct {
}
fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const enum_ty = self.air.typeOf(un_op);
@@ -8995,8 +8837,6 @@ pub const FuncGen = struct {
}
fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const slice_ty = self.air.typeOfIndex(inst);
@@ -9011,8 +8851,6 @@ pub const FuncGen = struct {
}
fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const scalar = try self.resolveInst(ty_op.operand);
const vector_ty = self.air.typeOfIndex(inst);
@@ -9021,8 +8859,6 @@ pub const FuncGen = struct {
}
fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
const pred = try self.resolveInst(pl_op.operand);
@@ -9033,8 +8869,6 @@ pub const FuncGen = struct {
}
fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
const a = try self.resolveInst(extra.a);
@@ -9134,7 +8968,6 @@ pub const FuncGen = struct {
}
fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const target = self.dg.module.getTarget();
@@ -9221,8 +9054,6 @@ pub const FuncGen = struct {
}
fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const result_ty = self.air.typeOfIndex(inst);
const len = @intCast(usize, result_ty.arrayLen());
@@ -9360,8 +9191,6 @@ pub const FuncGen = struct {
}
fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
const union_ty = self.air.typeOfIndex(inst);
@@ -9566,8 +9395,6 @@ pub const FuncGen = struct {
}
fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const inst_ty = self.air.typeOfIndex(inst);
const operand = try self.resolveInst(ty_op.operand);
@@ -9592,8 +9419,6 @@ pub const FuncGen = struct {
}
fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.module.getTarget();
assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
@@ -9603,8 +9428,6 @@ pub const FuncGen = struct {
}
fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.module.getTarget();
assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
@@ -9634,8 +9457,6 @@ pub const FuncGen = struct {
}
fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.module.getTarget();
assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
@@ -9756,8 +9577,6 @@ pub const FuncGen = struct {
struct_ptr_ty: Type,
field_index: u32,
) !?*llvm.Value {
- if (self.liveness.isUnused(inst)) return null;
-
const target = self.dg.object.target;
const struct_ty = struct_ptr_ty.childType();
switch (struct_ty.zigTypeTag()) {
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 58da5539ac..87b72c6726 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -1507,6 +1507,11 @@ pub const DeclGen = struct {
}
fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void {
+ // TODO: remove now-redundant isUnused calls from AIR handler functions
+ if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
+ return;
+ }
+
const air_tags = self.air.instructions.items(.tag);
const maybe_result_id: ?IdRef = switch (air_tags[inst]) {
// zig fmt: off