mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 23:52:31 +00:00
Merge pull request #15355 from mlugg/feat/liveness-control-flow
Liveness: control flow analysis and other goodies
This commit is contained in:
commit
528b66f6ec
@ -13,7 +13,7 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
|
||||
|
||||
pub fn main() void {
|
||||
if (builtin.zig_backend == .stage2_wasm or
|
||||
builtin.zig_backend == .stage2_x86_64 or
|
||||
(builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) or
|
||||
builtin.zig_backend == .stage2_aarch64)
|
||||
{
|
||||
return mainSimple() catch @panic("test failure");
|
||||
|
214
src/Air.zig
214
src/Air.zig
@ -1375,3 +1375,217 @@ pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 {
|
||||
}
|
||||
return bytes[0..end :0];
|
||||
}
|
||||
|
||||
/// Returns whether the given instruction must always be lowered, for instance because it can cause
|
||||
/// side effects. If an instruction does not need to be lowered, and Liveness determines its result
|
||||
/// is unused, backends should avoid lowering it.
|
||||
pub fn mustLower(air: Air, inst: Air.Inst.Index) bool {
|
||||
const data = air.instructions.items(.data)[inst];
|
||||
return switch (air.instructions.items(.tag)[inst]) {
|
||||
.arg,
|
||||
.block,
|
||||
.loop,
|
||||
.br,
|
||||
.trap,
|
||||
.breakpoint,
|
||||
.call,
|
||||
.call_always_tail,
|
||||
.call_never_tail,
|
||||
.call_never_inline,
|
||||
.cond_br,
|
||||
.switch_br,
|
||||
.@"try",
|
||||
.try_ptr,
|
||||
.dbg_stmt,
|
||||
.dbg_block_begin,
|
||||
.dbg_block_end,
|
||||
.dbg_inline_begin,
|
||||
.dbg_inline_end,
|
||||
.dbg_var_ptr,
|
||||
.dbg_var_val,
|
||||
.ret,
|
||||
.ret_load,
|
||||
.store,
|
||||
.unreach,
|
||||
.optional_payload_ptr_set,
|
||||
.errunion_payload_ptr_set,
|
||||
.set_union_tag,
|
||||
.memset,
|
||||
.memcpy,
|
||||
.cmpxchg_weak,
|
||||
.cmpxchg_strong,
|
||||
.fence,
|
||||
.atomic_store_unordered,
|
||||
.atomic_store_monotonic,
|
||||
.atomic_store_release,
|
||||
.atomic_store_seq_cst,
|
||||
.atomic_rmw,
|
||||
.prefetch,
|
||||
.wasm_memory_grow,
|
||||
.set_err_return_trace,
|
||||
.vector_store_elem,
|
||||
.c_va_arg,
|
||||
.c_va_copy,
|
||||
.c_va_end,
|
||||
.c_va_start,
|
||||
=> true,
|
||||
|
||||
.add,
|
||||
.add_optimized,
|
||||
.addwrap,
|
||||
.addwrap_optimized,
|
||||
.add_sat,
|
||||
.sub,
|
||||
.sub_optimized,
|
||||
.subwrap,
|
||||
.subwrap_optimized,
|
||||
.sub_sat,
|
||||
.mul,
|
||||
.mul_optimized,
|
||||
.mulwrap,
|
||||
.mulwrap_optimized,
|
||||
.mul_sat,
|
||||
.div_float,
|
||||
.div_float_optimized,
|
||||
.div_trunc,
|
||||
.div_trunc_optimized,
|
||||
.div_floor,
|
||||
.div_floor_optimized,
|
||||
.div_exact,
|
||||
.div_exact_optimized,
|
||||
.rem,
|
||||
.rem_optimized,
|
||||
.mod,
|
||||
.mod_optimized,
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
.max,
|
||||
.min,
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.alloc,
|
||||
.ret_ptr,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
.shr,
|
||||
.shr_exact,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shl_sat,
|
||||
.xor,
|
||||
.not,
|
||||
.bitcast,
|
||||
.ret_addr,
|
||||
.frame_addr,
|
||||
.clz,
|
||||
.ctz,
|
||||
.popcount,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.tan,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
.neg,
|
||||
.neg_optimized,
|
||||
.cmp_lt,
|
||||
.cmp_lt_optimized,
|
||||
.cmp_lte,
|
||||
.cmp_lte_optimized,
|
||||
.cmp_eq,
|
||||
.cmp_eq_optimized,
|
||||
.cmp_gte,
|
||||
.cmp_gte_optimized,
|
||||
.cmp_gt,
|
||||
.cmp_gt_optimized,
|
||||
.cmp_neq,
|
||||
.cmp_neq_optimized,
|
||||
.cmp_vector,
|
||||
.cmp_vector_optimized,
|
||||
.constant,
|
||||
.const_ty,
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
.is_null_ptr,
|
||||
.is_non_null_ptr,
|
||||
.is_err,
|
||||
.is_non_err,
|
||||
.is_err_ptr,
|
||||
.is_non_err_ptr,
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
.ptrtoint,
|
||||
.bool_to_int,
|
||||
.fptrunc,
|
||||
.fpext,
|
||||
.intcast,
|
||||
.trunc,
|
||||
.optional_payload,
|
||||
.optional_payload_ptr,
|
||||
.wrap_optional,
|
||||
.unwrap_errunion_payload,
|
||||
.unwrap_errunion_err,
|
||||
.unwrap_errunion_payload_ptr,
|
||||
.unwrap_errunion_err_ptr,
|
||||
.wrap_errunion_payload,
|
||||
.wrap_errunion_err,
|
||||
.struct_field_ptr,
|
||||
.struct_field_ptr_index_0,
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.struct_field_val,
|
||||
.get_union_tag,
|
||||
.slice,
|
||||
.slice_len,
|
||||
.slice_ptr,
|
||||
.ptr_slice_len_ptr,
|
||||
.ptr_slice_ptr_ptr,
|
||||
.array_elem_val,
|
||||
.slice_elem_ptr,
|
||||
.ptr_elem_ptr,
|
||||
.array_to_slice,
|
||||
.float_to_int,
|
||||
.float_to_int_optimized,
|
||||
.int_to_float,
|
||||
.reduce,
|
||||
.reduce_optimized,
|
||||
.splat,
|
||||
.shuffle,
|
||||
.select,
|
||||
.is_named_enum_value,
|
||||
.tag_name,
|
||||
.error_name,
|
||||
.error_set_has_value,
|
||||
.aggregate_init,
|
||||
.union_init,
|
||||
.mul_add,
|
||||
.field_parent_ptr,
|
||||
.wasm_memory_size,
|
||||
.cmp_lt_errors_len,
|
||||
.err_return_trace,
|
||||
.addrspace_cast,
|
||||
.save_err_return_trace_index,
|
||||
.work_item_id,
|
||||
.work_group_size,
|
||||
.work_group_id,
|
||||
=> false,
|
||||
|
||||
.assembly => @truncate(u1, air.extraData(Air.Asm, data.ty_pl.payload).data.flags >> 31) != 0,
|
||||
.load => air.typeOf(data.ty_op.operand).isVolatilePtr(),
|
||||
.slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs).isVolatilePtr(),
|
||||
.atomic_load => air.typeOf(data.atomic_load.ptr).isVolatilePtr(),
|
||||
};
|
||||
}
|
||||
|
@ -3095,6 +3095,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
|
||||
|
||||
.file_failure,
|
||||
.sema_failure,
|
||||
.liveness_failure,
|
||||
.codegen_failure,
|
||||
.dependency_failure,
|
||||
.sema_failure_retryable,
|
||||
@ -3145,7 +3146,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
|
||||
|
||||
// emit-h only requires semantic analysis of the Decl to be complete,
|
||||
// it does not depend on machine code generation to succeed.
|
||||
.codegen_failure, .codegen_failure_retryable, .complete => {
|
||||
.liveness_failure, .codegen_failure, .codegen_failure_retryable, .complete => {
|
||||
const named_frame = tracy.namedFrame("emit_h_decl");
|
||||
defer named_frame.end();
|
||||
|
||||
|
1901
src/Liveness.zig
1901
src/Liveness.zig
File diff suppressed because it is too large
Load Diff
610
src/Liveness/Verify.zig
Normal file
610
src/Liveness/Verify.zig
Normal file
@ -0,0 +1,610 @@
|
||||
//! Verifies that liveness information is valid.
|
||||
|
||||
gpa: std.mem.Allocator,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
live: LiveMap = .{},
|
||||
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, LiveMap) = .{},
|
||||
|
||||
pub const Error = error{ LivenessInvalid, OutOfMemory };
|
||||
|
||||
pub fn deinit(self: *Verify) void {
|
||||
self.live.deinit(self.gpa);
|
||||
var block_it = self.blocks.valueIterator();
|
||||
while (block_it.next()) |block| block.deinit(self.gpa);
|
||||
self.blocks.deinit(self.gpa);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn verify(self: *Verify) Error!void {
|
||||
self.live.clearRetainingCapacity();
|
||||
self.blocks.clearRetainingCapacity();
|
||||
try self.verifyBody(self.air.getMainBody());
|
||||
// We don't care about `self.live` now, because the loop body was noreturn - everything being dead was checked on `ret` etc
|
||||
assert(self.blocks.count() == 0);
|
||||
}
|
||||
|
||||
const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void);
|
||||
|
||||
fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
|
||||
const tag = self.air.instructions.items(.tag);
|
||||
const data = self.air.instructions.items(.data);
|
||||
for (body) |inst| {
|
||||
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
|
||||
// This instruction will not be lowered and should be ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (tag[inst]) {
|
||||
// no operands
|
||||
.arg,
|
||||
.alloc,
|
||||
.ret_ptr,
|
||||
.constant,
|
||||
.const_ty,
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.dbg_inline_begin,
|
||||
.dbg_inline_end,
|
||||
.dbg_block_begin,
|
||||
.dbg_block_end,
|
||||
.fence,
|
||||
.ret_addr,
|
||||
.frame_addr,
|
||||
.wasm_memory_size,
|
||||
.err_return_trace,
|
||||
.save_err_return_trace_index,
|
||||
.c_va_start,
|
||||
.work_item_id,
|
||||
.work_group_size,
|
||||
.work_group_id,
|
||||
=> try self.verifyInst(inst, .{ .none, .none, .none }),
|
||||
|
||||
.trap, .unreach => {
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
// This instruction terminates the function, so everything should be dead
|
||||
if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
|
||||
},
|
||||
|
||||
// unary
|
||||
.not,
|
||||
.bitcast,
|
||||
.load,
|
||||
.fpext,
|
||||
.fptrunc,
|
||||
.intcast,
|
||||
.trunc,
|
||||
.optional_payload,
|
||||
.optional_payload_ptr,
|
||||
.optional_payload_ptr_set,
|
||||
.errunion_payload_ptr_set,
|
||||
.wrap_optional,
|
||||
.unwrap_errunion_payload,
|
||||
.unwrap_errunion_err,
|
||||
.unwrap_errunion_payload_ptr,
|
||||
.unwrap_errunion_err_ptr,
|
||||
.wrap_errunion_payload,
|
||||
.wrap_errunion_err,
|
||||
.slice_ptr,
|
||||
.slice_len,
|
||||
.ptr_slice_len_ptr,
|
||||
.ptr_slice_ptr_ptr,
|
||||
.struct_field_ptr_index_0,
|
||||
.struct_field_ptr_index_1,
|
||||
.struct_field_ptr_index_2,
|
||||
.struct_field_ptr_index_3,
|
||||
.array_to_slice,
|
||||
.float_to_int,
|
||||
.float_to_int_optimized,
|
||||
.int_to_float,
|
||||
.get_union_tag,
|
||||
.clz,
|
||||
.ctz,
|
||||
.popcount,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
.splat,
|
||||
.error_set_has_value,
|
||||
.addrspace_cast,
|
||||
.c_va_arg,
|
||||
.c_va_copy,
|
||||
=> {
|
||||
const ty_op = data[inst].ty_op;
|
||||
try self.verifyInst(inst, .{ ty_op.operand, .none, .none });
|
||||
},
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
.is_null_ptr,
|
||||
.is_non_null_ptr,
|
||||
.is_err,
|
||||
.is_non_err,
|
||||
.is_err_ptr,
|
||||
.is_non_err_ptr,
|
||||
.ptrtoint,
|
||||
.bool_to_int,
|
||||
.is_named_enum_value,
|
||||
.tag_name,
|
||||
.error_name,
|
||||
.sqrt,
|
||||
.sin,
|
||||
.cos,
|
||||
.tan,
|
||||
.exp,
|
||||
.exp2,
|
||||
.log,
|
||||
.log2,
|
||||
.log10,
|
||||
.fabs,
|
||||
.floor,
|
||||
.ceil,
|
||||
.round,
|
||||
.trunc_float,
|
||||
.neg,
|
||||
.neg_optimized,
|
||||
.cmp_lt_errors_len,
|
||||
.set_err_return_trace,
|
||||
.c_va_end,
|
||||
=> {
|
||||
const un_op = data[inst].un_op;
|
||||
try self.verifyInst(inst, .{ un_op, .none, .none });
|
||||
},
|
||||
.ret,
|
||||
.ret_load,
|
||||
=> {
|
||||
const un_op = data[inst].un_op;
|
||||
try self.verifyInst(inst, .{ un_op, .none, .none });
|
||||
// This instruction terminates the function, so everything should be dead
|
||||
if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
|
||||
},
|
||||
.dbg_var_ptr,
|
||||
.dbg_var_val,
|
||||
.wasm_memory_grow,
|
||||
=> {
|
||||
const pl_op = data[inst].pl_op;
|
||||
try self.verifyInst(inst, .{ pl_op.operand, .none, .none });
|
||||
},
|
||||
.prefetch => {
|
||||
const prefetch = data[inst].prefetch;
|
||||
try self.verifyInst(inst, .{ prefetch.ptr, .none, .none });
|
||||
},
|
||||
.reduce,
|
||||
.reduce_optimized,
|
||||
=> {
|
||||
const reduce = data[inst].reduce;
|
||||
try self.verifyInst(inst, .{ reduce.operand, .none, .none });
|
||||
},
|
||||
.union_init => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.init, .none, .none });
|
||||
},
|
||||
.struct_field_ptr, .struct_field_val => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.struct_operand, .none, .none });
|
||||
},
|
||||
.field_parent_ptr => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.field_ptr, .none, .none });
|
||||
},
|
||||
.atomic_load => {
|
||||
const atomic_load = data[inst].atomic_load;
|
||||
try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none });
|
||||
},
|
||||
|
||||
// binary
|
||||
.add,
|
||||
.add_optimized,
|
||||
.addwrap,
|
||||
.addwrap_optimized,
|
||||
.add_sat,
|
||||
.sub,
|
||||
.sub_optimized,
|
||||
.subwrap,
|
||||
.subwrap_optimized,
|
||||
.sub_sat,
|
||||
.mul,
|
||||
.mul_optimized,
|
||||
.mulwrap,
|
||||
.mulwrap_optimized,
|
||||
.mul_sat,
|
||||
.div_float,
|
||||
.div_float_optimized,
|
||||
.div_trunc,
|
||||
.div_trunc_optimized,
|
||||
.div_floor,
|
||||
.div_floor_optimized,
|
||||
.div_exact,
|
||||
.div_exact_optimized,
|
||||
.rem,
|
||||
.rem_optimized,
|
||||
.mod,
|
||||
.mod_optimized,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
.xor,
|
||||
.cmp_lt,
|
||||
.cmp_lt_optimized,
|
||||
.cmp_lte,
|
||||
.cmp_lte_optimized,
|
||||
.cmp_eq,
|
||||
.cmp_eq_optimized,
|
||||
.cmp_gte,
|
||||
.cmp_gte_optimized,
|
||||
.cmp_gt,
|
||||
.cmp_gt_optimized,
|
||||
.cmp_neq,
|
||||
.cmp_neq_optimized,
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
.store,
|
||||
.array_elem_val,
|
||||
.slice_elem_val,
|
||||
.ptr_elem_val,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shl_sat,
|
||||
.shr,
|
||||
.shr_exact,
|
||||
.atomic_store_unordered,
|
||||
.atomic_store_monotonic,
|
||||
.atomic_store_release,
|
||||
.atomic_store_seq_cst,
|
||||
.set_union_tag,
|
||||
.min,
|
||||
.max,
|
||||
=> {
|
||||
const bin_op = data[inst].bin_op;
|
||||
try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
},
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
.mul_with_overflow,
|
||||
.shl_with_overflow,
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
.ptr_elem_ptr,
|
||||
.slice_elem_ptr,
|
||||
.slice,
|
||||
=> {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
|
||||
},
|
||||
.shuffle => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.a, extra.b, .none });
|
||||
},
|
||||
.cmp_vector,
|
||||
.cmp_vector_optimized,
|
||||
=> {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
|
||||
},
|
||||
.atomic_rmw => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
|
||||
try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none });
|
||||
},
|
||||
|
||||
// ternary
|
||||
.select => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
|
||||
try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
|
||||
},
|
||||
.mul_add => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
|
||||
},
|
||||
.vector_store_elem => {
|
||||
const vector_store_elem = data[inst].vector_store_elem;
|
||||
const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
|
||||
try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
|
||||
},
|
||||
.memset,
|
||||
.memcpy,
|
||||
=> {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
|
||||
try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
|
||||
},
|
||||
.cmpxchg_strong,
|
||||
.cmpxchg_weak,
|
||||
=> {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
|
||||
try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
|
||||
},
|
||||
|
||||
// big tombs
|
||||
.aggregate_init => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const aggregate_ty = self.air.getRefType(ty_pl.ty);
|
||||
const len = @intCast(usize, aggregate_ty.arrayLen());
|
||||
const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
|
||||
var bt = self.liveness.iterateBigTomb(inst);
|
||||
for (elements) |element| {
|
||||
try self.verifyOperand(inst, element, bt.feed());
|
||||
}
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.call, .call_always_tail, .call_never_tail, .call_never_inline => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.Call, pl_op.payload);
|
||||
const args = @ptrCast(
|
||||
[]const Air.Inst.Ref,
|
||||
self.air.extra[extra.end..][0..extra.data.args_len],
|
||||
);
|
||||
|
||||
var bt = self.liveness.iterateBigTomb(inst);
|
||||
try self.verifyOperand(inst, pl_op.operand, bt.feed());
|
||||
for (args) |arg| {
|
||||
try self.verifyOperand(inst, arg, bt.feed());
|
||||
}
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.assembly => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Asm, ty_pl.payload);
|
||||
var extra_i = extra.end;
|
||||
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],
|
||||
);
|
||||
extra_i += inputs.len;
|
||||
|
||||
var bt = self.liveness.iterateBigTomb(inst);
|
||||
for (outputs) |output| {
|
||||
if (output != .none) {
|
||||
try self.verifyOperand(inst, output, bt.feed());
|
||||
}
|
||||
}
|
||||
for (inputs) |input| {
|
||||
try self.verifyOperand(inst, input, bt.feed());
|
||||
}
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
|
||||
// control flow
|
||||
.@"try" => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.Try, pl_op.payload);
|
||||
const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
|
||||
|
||||
const cond_br_liveness = self.liveness.getCondBr(inst);
|
||||
|
||||
try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
|
||||
|
||||
var live = try self.live.clone(self.gpa);
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(try_body);
|
||||
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = live.move();
|
||||
|
||||
for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.try_ptr => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
|
||||
const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
|
||||
|
||||
const cond_br_liveness = self.liveness.getCondBr(inst);
|
||||
|
||||
try self.verifyOperand(inst, extra.data.ptr, self.liveness.operandDies(inst, 0));
|
||||
|
||||
var live = try self.live.clone(self.gpa);
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(try_body);
|
||||
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = live.move();
|
||||
|
||||
for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.br => {
|
||||
const br = data[inst].br;
|
||||
const gop = try self.blocks.getOrPut(self.gpa, br.block_inst);
|
||||
|
||||
try self.verifyOperand(inst, br.operand, self.liveness.operandDies(inst, 0));
|
||||
if (gop.found_existing) {
|
||||
try self.verifyMatchingLiveness(br.block_inst, gop.value_ptr.*);
|
||||
} else {
|
||||
gop.value_ptr.* = try self.live.clone(self.gpa);
|
||||
}
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.block => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const block_ty = self.air.getRefType(ty_pl.ty);
|
||||
const extra = self.air.extraData(Air.Block, ty_pl.payload);
|
||||
const block_body = self.air.extra[extra.end..][0..extra.data.body_len];
|
||||
const block_liveness = self.liveness.getBlock(inst);
|
||||
|
||||
var orig_live = try self.live.clone(self.gpa);
|
||||
defer orig_live.deinit(self.gpa);
|
||||
|
||||
assert(!self.blocks.contains(inst));
|
||||
try self.verifyBody(block_body);
|
||||
|
||||
// Liveness data after the block body is garbage, but we want to
|
||||
// restore it to verify deaths
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = orig_live.move();
|
||||
|
||||
for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);
|
||||
|
||||
if (block_ty.isNoReturn()) {
|
||||
assert(!self.blocks.contains(inst));
|
||||
} else {
|
||||
var live = self.blocks.fetchRemove(inst).?.value;
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
try self.verifyMatchingLiveness(inst, live);
|
||||
}
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.loop => {
|
||||
const ty_pl = data[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Block, ty_pl.payload);
|
||||
const loop_body = self.air.extra[extra.end..][0..extra.data.body_len];
|
||||
|
||||
var live = try self.live.clone(self.gpa);
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
try self.verifyBody(loop_body);
|
||||
|
||||
// The same stuff should be alive after the loop as before it
|
||||
try self.verifyMatchingLiveness(inst, live);
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.cond_br => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const extra = self.air.extraData(Air.CondBr, pl_op.payload);
|
||||
const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
|
||||
const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
|
||||
const cond_br_liveness = self.liveness.getCondBr(inst);
|
||||
|
||||
try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
|
||||
|
||||
var live = try self.live.clone(self.gpa);
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(then_body);
|
||||
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = live.move();
|
||||
|
||||
for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(else_body);
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
.switch_br => {
|
||||
const pl_op = data[inst].pl_op;
|
||||
const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
|
||||
var extra_index = switch_br.end;
|
||||
var case_i: u32 = 0;
|
||||
const switch_br_liveness = try self.liveness.getSwitchBr(
|
||||
self.gpa,
|
||||
inst,
|
||||
switch_br.data.cases_len + 1,
|
||||
);
|
||||
defer self.gpa.free(switch_br_liveness.deaths);
|
||||
|
||||
try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
|
||||
|
||||
var live = self.live.move();
|
||||
defer live.deinit(self.gpa);
|
||||
|
||||
while (case_i < switch_br.data.cases_len) : (case_i += 1) {
|
||||
const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
|
||||
const items = @ptrCast(
|
||||
[]const Air.Inst.Ref,
|
||||
self.air.extra[case.end..][0..case.data.items_len],
|
||||
);
|
||||
const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
|
||||
extra_index = case.end + items.len + case_body.len;
|
||||
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = try live.clone(self.gpa);
|
||||
|
||||
for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(case_body);
|
||||
}
|
||||
|
||||
const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
|
||||
if (else_body.len > 0) {
|
||||
self.live.deinit(self.gpa);
|
||||
self.live = try live.clone(self.gpa);
|
||||
|
||||
for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
|
||||
try self.verifyBody(else_body);
|
||||
}
|
||||
|
||||
try self.verifyInst(inst, .{ .none, .none, .none });
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Error!void {
|
||||
try self.verifyOperand(inst, Air.indexToRef(operand), true);
|
||||
}
|
||||
|
||||
fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void {
|
||||
const operand = Air.refToIndex(op_ref) orelse return;
|
||||
switch (self.air.instructions.items(.tag)[operand]) {
|
||||
.constant, .const_ty => {},
|
||||
else => {
|
||||
if (dies) {
|
||||
if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
|
||||
} else {
|
||||
if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn verifyInst(
|
||||
self: *Verify,
|
||||
inst: Air.Inst.Index,
|
||||
operands: [Liveness.bpi - 1]Air.Inst.Ref,
|
||||
) Error!void {
|
||||
for (operands, 0..) |operand, operand_index| {
|
||||
const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
|
||||
try self.verifyOperand(inst, operand, dies);
|
||||
}
|
||||
const tag = self.air.instructions.items(.tag);
|
||||
switch (tag[inst]) {
|
||||
.constant, .const_ty => unreachable,
|
||||
else => {
|
||||
if (self.liveness.isUnused(inst)) {
|
||||
assert(!self.live.contains(inst));
|
||||
} else {
|
||||
try self.live.putNoClobber(self.gpa, inst, {});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn verifyMatchingLiveness(self: *Verify, block: Air.Inst.Index, live: LiveMap) Error!void {
|
||||
if (self.live.count() != live.count()) return invalid("%{}: different deaths across branches", .{block});
|
||||
var live_it = self.live.keyIterator();
|
||||
while (live_it.next()) |live_inst| if (!live.contains(live_inst.*)) return invalid("%{}: different deaths across branches", .{block});
|
||||
}
|
||||
|
||||
fn invalid(comptime fmt: []const u8, args: anytype) error{LivenessInvalid} {
|
||||
log.err(fmt, args);
|
||||
return error.LivenessInvalid;
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.liveness_verify);
|
||||
|
||||
const Air = @import("../Air.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const Verify = @This();
|
@ -483,6 +483,8 @@ pub const Decl = struct {
|
||||
/// and attempting semantic analysis again may succeed.
|
||||
sema_failure_retryable,
|
||||
/// There will be a corresponding ErrorMsg in Module.failed_decls.
|
||||
liveness_failure,
|
||||
/// There will be a corresponding ErrorMsg in Module.failed_decls.
|
||||
codegen_failure,
|
||||
/// There will be a corresponding ErrorMsg in Module.failed_decls.
|
||||
/// This indicates the failure was something like running out of disk space,
|
||||
@ -4129,6 +4131,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
|
||||
.file_failure,
|
||||
.sema_failure,
|
||||
.sema_failure_retryable,
|
||||
.liveness_failure,
|
||||
.codegen_failure,
|
||||
.dependency_failure,
|
||||
.codegen_failure_retryable,
|
||||
@ -4222,6 +4225,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
|
||||
.dependency_failure,
|
||||
.sema_failure,
|
||||
.sema_failure_retryable,
|
||||
.liveness_failure,
|
||||
.codegen_failure,
|
||||
.codegen_failure_retryable,
|
||||
.complete,
|
||||
@ -4247,6 +4251,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
|
||||
|
||||
.file_failure,
|
||||
.sema_failure,
|
||||
.liveness_failure,
|
||||
.codegen_failure,
|
||||
.dependency_failure,
|
||||
.sema_failure_retryable,
|
||||
@ -4306,6 +4311,33 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
|
||||
std.debug.print("# End Function AIR: {s}\n\n", .{fqn});
|
||||
}
|
||||
|
||||
if (std.debug.runtime_safety) {
|
||||
var verify = Liveness.Verify{
|
||||
.gpa = gpa,
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
};
|
||||
defer verify.deinit();
|
||||
|
||||
verify.verify() catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
|
||||
mod.failed_decls.putAssumeCapacityNoClobber(
|
||||
decl_index,
|
||||
try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(),
|
||||
"invalid liveness: {s}",
|
||||
.{@errorName(err)},
|
||||
),
|
||||
);
|
||||
decl.analysis = .liveness_failure;
|
||||
return error.AnalysisFail;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (no_bin_file and !dump_llvm_ir) return;
|
||||
|
||||
comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {
|
||||
@ -4349,6 +4381,7 @@ pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {
|
||||
.dependency_failure,
|
||||
.sema_failure,
|
||||
.sema_failure_retryable,
|
||||
.liveness_failure,
|
||||
.codegen_failure,
|
||||
.codegen_failure_retryable,
|
||||
.complete,
|
||||
|
@ -655,6 +655,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
|
||||
for (body) |inst| {
|
||||
// TODO: remove now-redundant isUnused calls from AIR handler functions
|
||||
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
@ -5000,17 +5005,11 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const loop = self.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = self.air.extra[loop.end..][0..loop.data.body_len];
|
||||
const liveness_loop = self.liveness.getLoop(inst);
|
||||
const start_index = @intCast(u32, self.mir_instructions.len);
|
||||
|
||||
try self.genBody(body);
|
||||
try self.jump(start_index);
|
||||
|
||||
try self.ensureProcessDeathCapacity(liveness_loop.deaths.len);
|
||||
for (liveness_loop.deaths) |operand| {
|
||||
self.processDeath(operand);
|
||||
}
|
||||
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
|
@ -639,6 +639,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
|
||||
for (body) |inst| {
|
||||
// TODO: remove now-redundant isUnused calls from AIR handler functions
|
||||
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
@ -4923,17 +4928,11 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const loop = self.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = self.air.extra[loop.end..][0..loop.data.body_len];
|
||||
const liveness_loop = self.liveness.getLoop(inst);
|
||||
const start_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
|
||||
|
||||
try self.genBody(body);
|
||||
try self.jump(start_index);
|
||||
|
||||
try self.ensureProcessDeathCapacity(liveness_loop.deaths.len);
|
||||
for (liveness_loop.deaths) |operand| {
|
||||
self.processDeath(operand);
|
||||
}
|
||||
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
|
@ -473,6 +473,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
|
||||
for (body) |inst| {
|
||||
// TODO: remove now-redundant isUnused calls from AIR handler functions
|
||||
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
|
@ -489,6 +489,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
|
||||
for (body) |inst| {
|
||||
// TODO: remove now-redundant isUnused calls from AIR handler functions
|
||||
if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
@ -1750,17 +1755,11 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const loop = self.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = self.air.extra[loop.end .. loop.end + loop.data.body_len];
|
||||
const liveness_loop = self.liveness.getLoop(inst);
|
||||
const start = @intCast(u32, self.mir_instructions.len);
|
||||
|
||||
try self.genBody(body);
|
||||
try self.jump(start);
|
||||
|
||||
try self.ensureProcessDeathCapacity(liveness_loop.deaths.len);
|
||||
for (liveness_loop.deaths) |operand| {
|
||||
self.processDeath(operand);
|
||||
}
|
||||
|
||||
return self.finishAirBookkeeping();
|
||||
}
|
||||
|
||||
|
@ -2009,9 +2009,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
||||
for (body) |inst| {
|
||||
if (func.liveness.isUnused(inst) and !func.air.mustLower(inst)) {
|
||||
continue;
|
||||
}
|
||||
const old_bookkeeping_value = func.air_bookkeeping;
|
||||
// TODO: Determine why we need to pre-allocate an extra 4 possible values here.
|
||||
try func.currentBranch().values.ensureUnusedCapacity(func.gpa, Liveness.bpi + 4);
|
||||
try func.currentBranch().values.ensureUnusedCapacity(func.gpa, Liveness.bpi);
|
||||
try func.genInst(inst);
|
||||
|
||||
if (builtin.mode == .Debug and func.air_bookkeeping < old_bookkeeping_value + 1) {
|
||||
@ -2185,7 +2187,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif
|
||||
}
|
||||
|
||||
const result_value = result_value: {
|
||||
if (func.liveness.isUnused(inst) or (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError())) {
|
||||
if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
|
||||
break :result_value WValue{ .none = {} };
|
||||
} else if (ret_ty.isNoReturn()) {
|
||||
try func.addTag(.@"unreachable");
|
||||
@ -2494,7 +2496,6 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
const rhs = try func.resolveInst(bin_op.rhs);
|
||||
const ty = func.air.typeOf(bin_op.lhs);
|
||||
@ -2649,7 +2650,6 @@ const FloatOp = enum {
|
||||
|
||||
fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
const operand = try func.resolveInst(un_op);
|
||||
const ty = func.air.typeOf(un_op);
|
||||
|
||||
@ -2723,7 +2723,6 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In
|
||||
|
||||
fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
const rhs = try func.resolveInst(bin_op.rhs);
|
||||
@ -3183,7 +3182,6 @@ fn airLoop(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const loop = func.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = func.air.extra[loop.end..][0..loop.data.body_len];
|
||||
const liveness_loop = func.liveness.getLoop(inst);
|
||||
|
||||
// result type of loop is always 'noreturn', meaning we can always
|
||||
// emit the wasm type 'block_empty'.
|
||||
@ -3194,11 +3192,6 @@ fn airLoop(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
try func.addLabel(.br, 0);
|
||||
try func.endBlock();
|
||||
|
||||
try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @intCast(u32, liveness_loop.deaths.len));
|
||||
for (liveness_loop.deaths) |death| {
|
||||
func.processDeath(Air.indexToRef(death));
|
||||
}
|
||||
|
||||
func.finishAir(inst, .none, &.{});
|
||||
}
|
||||
|
||||
@ -3224,9 +3217,6 @@ fn airCondBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
func.branches.appendAssumeCapacity(.{});
|
||||
try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @intCast(u32, liveness_condbr.else_deaths.len));
|
||||
for (liveness_condbr.else_deaths) |death| {
|
||||
func.processDeath(Air.indexToRef(death));
|
||||
}
|
||||
try func.genBody(else_body);
|
||||
try func.endBlock();
|
||||
var else_stack = func.branches.pop();
|
||||
@ -3235,9 +3225,6 @@ fn airCondBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
// Outer block that matches the condition
|
||||
func.branches.appendAssumeCapacity(.{});
|
||||
try func.currentBranch().values.ensureUnusedCapacity(func.gpa, @intCast(u32, liveness_condbr.then_deaths.len));
|
||||
for (liveness_condbr.then_deaths) |death| {
|
||||
func.processDeath(Air.indexToRef(death));
|
||||
}
|
||||
try func.genBody(then_body);
|
||||
var then_stack = func.branches.pop();
|
||||
defer then_stack.deinit(func.gpa);
|
||||
@ -3255,7 +3242,7 @@ fn mergeBranch(func: *CodeGen, branch: *const Branch) !void {
|
||||
const target_keys = target_slice.items(.key);
|
||||
const target_values = target_slice.items(.value);
|
||||
|
||||
try parent.values.ensureUnusedCapacity(func.gpa, branch.values.count());
|
||||
try parent.values.ensureTotalCapacity(func.gpa, parent.values.capacity() + branch.values.count());
|
||||
for (target_keys, 0..) |key, index| {
|
||||
// TODO: process deaths from branches
|
||||
parent.values.putAssumeCapacity(key, target_values[index]);
|
||||
@ -3264,7 +3251,6 @@ fn mergeBranch(func: *CodeGen, branch: *const Branch) !void {
|
||||
|
||||
fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
const rhs = try func.resolveInst(bin_op.rhs);
|
||||
@ -3381,7 +3367,6 @@ fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const operand_ty = func.air.typeOf(ty_op.operand);
|
||||
@ -3447,7 +3432,7 @@ fn airUnreachable(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
const result = if (!func.liveness.isUnused(inst)) result: {
|
||||
const result = result: {
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const wanted_ty = func.air.typeOfIndex(inst);
|
||||
const given_ty = func.air.typeOf(ty_op.operand);
|
||||
@ -3456,7 +3441,7 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
break :result try bitcast_result.toLocal(func, wanted_ty);
|
||||
}
|
||||
break :result func.reuseOperand(ty_op.operand, operand);
|
||||
} else WValue{ .none = {} };
|
||||
};
|
||||
func.finishAir(inst, result, &.{ty_op.operand});
|
||||
}
|
||||
|
||||
@ -3480,7 +3465,6 @@ fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inn
|
||||
fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.StructField, ty_pl.payload);
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{extra.data.struct_operand});
|
||||
|
||||
const struct_ptr = try func.resolveInst(extra.data.struct_operand);
|
||||
const struct_ty = func.air.typeOf(extra.data.struct_operand).childType();
|
||||
@ -3490,7 +3474,6 @@ fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
const struct_ptr = try func.resolveInst(ty_op.operand);
|
||||
const struct_ty = func.air.typeOf(ty_op.operand).childType();
|
||||
|
||||
@ -3535,7 +3518,6 @@ fn structFieldPtr(
|
||||
fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{struct_field.struct_operand});
|
||||
|
||||
const struct_ty = func.air.typeOf(struct_field.struct_operand);
|
||||
const operand = try func.resolveInst(struct_field.struct_operand);
|
||||
@ -3801,7 +3783,6 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
const operand = try func.resolveInst(un_op);
|
||||
const err_union_ty = func.air.typeOf(un_op);
|
||||
const pl_ty = err_union_ty.errorUnionPayload();
|
||||
@ -3836,7 +3817,6 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro
|
||||
|
||||
fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const op_ty = func.air.typeOf(ty_op.operand);
|
||||
@ -3859,7 +3839,6 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo
|
||||
|
||||
fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const op_ty = func.air.typeOf(ty_op.operand);
|
||||
@ -3883,7 +3862,6 @@ fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
|
||||
|
||||
fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const err_ty = func.air.typeOfIndex(inst);
|
||||
@ -3910,7 +3888,6 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void
|
||||
|
||||
fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const err_ty = func.air.getRefType(ty_op.ty);
|
||||
@ -3937,7 +3914,6 @@ fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const ty = func.air.getRefType(ty_op.ty);
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
@ -4004,7 +3980,6 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
|
||||
|
||||
fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
const operand = try func.resolveInst(un_op);
|
||||
|
||||
const op_ty = func.air.typeOf(un_op);
|
||||
@ -4049,7 +4024,7 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
const opt_ty = func.air.typeOf(ty_op.operand);
|
||||
const payload_ty = func.air.typeOfIndex(inst);
|
||||
if (func.liveness.isUnused(inst) or !payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
}
|
||||
|
||||
@ -4069,7 +4044,6 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const opt_ty = func.air.typeOf(ty_op.operand).childType();
|
||||
|
||||
@ -4114,7 +4088,6 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
|
||||
|
||||
fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
const payload_ty = func.air.typeOf(ty_op.operand);
|
||||
|
||||
const result = result: {
|
||||
@ -4153,7 +4126,6 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
const rhs = try func.resolveInst(bin_op.rhs);
|
||||
@ -4168,7 +4140,6 @@ fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const len = try func.load(operand, Type.usize, func.ptrSize());
|
||||
@ -4178,7 +4149,6 @@ fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const slice_ty = func.air.typeOf(bin_op.lhs);
|
||||
const slice = try func.resolveInst(bin_op.lhs);
|
||||
@ -4209,7 +4179,6 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const elem_ty = func.air.getRefType(ty_pl.ty).childType();
|
||||
const elem_size = elem_ty.abiSize(func.target);
|
||||
@ -4232,7 +4201,6 @@ fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airSlicePtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const ptr = try func.load(operand, Type.usize, 0);
|
||||
const result = try ptr.toLocal(func, Type.usize);
|
||||
@ -4241,7 +4209,6 @@ fn airSlicePtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const wanted_ty = func.air.getRefType(ty_op.ty);
|
||||
@ -4270,19 +4237,14 @@ fn trunc(func: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) Inner
|
||||
|
||||
fn airBoolToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
const result = if (func.liveness.isUnused(inst))
|
||||
WValue{ .none = {} }
|
||||
else result: {
|
||||
const operand = try func.resolveInst(un_op);
|
||||
break :result func.reuseOperand(un_op, operand);
|
||||
};
|
||||
const operand = try func.resolveInst(un_op);
|
||||
const result = func.reuseOperand(un_op, operand);
|
||||
|
||||
func.finishAir(inst, result, &.{un_op});
|
||||
}
|
||||
|
||||
fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const array_ty = func.air.typeOf(ty_op.operand).childType();
|
||||
@ -4305,7 +4267,6 @@ fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
const operand = try func.resolveInst(un_op);
|
||||
|
||||
const result = switch (operand) {
|
||||
@ -4318,7 +4279,6 @@ fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ptr_ty = func.air.typeOf(bin_op.lhs);
|
||||
const ptr = try func.resolveInst(bin_op.lhs);
|
||||
@ -4356,7 +4316,6 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ptr_ty = func.air.typeOf(bin_op.lhs);
|
||||
const elem_ty = func.air.getRefType(ty_pl.ty).childType();
|
||||
@ -4386,7 +4345,6 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ptr = try func.resolveInst(bin_op.lhs);
|
||||
const offset = try func.resolveInst(bin_op.rhs);
|
||||
@ -4510,7 +4468,6 @@ fn memset(func: *CodeGen, ptr: WValue, len: WValue, value: WValue) InnerError!vo
|
||||
|
||||
fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const array_ty = func.air.typeOf(bin_op.lhs);
|
||||
const array = try func.resolveInst(bin_op.lhs);
|
||||
@ -4579,7 +4536,6 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const dest_ty = func.air.typeOfIndex(inst);
|
||||
@ -4604,7 +4560,6 @@ fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const dest_ty = func.air.typeOfIndex(inst);
|
||||
@ -4719,10 +4674,6 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const child_ty = inst_ty.childType();
|
||||
const elem_size = child_ty.abiSize(func.target);
|
||||
|
||||
if (func.liveness.isUnused(inst)) {
|
||||
return func.finishAir(inst, .none, &.{ extra.a, extra.b });
|
||||
}
|
||||
|
||||
const module = func.bin_file.base.options.module.?;
|
||||
// TODO: One of them could be by ref; handle in loop
|
||||
if (isByRef(func.air.typeOf(extra.a), func.target) or isByRef(inst_ty, func.target)) {
|
||||
@ -4788,7 +4739,6 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const elements = @ptrCast([]const Air.Inst.Ref, func.air.extra[ty_pl.payload..][0..len]);
|
||||
|
||||
const result: WValue = result_value: {
|
||||
if (func.liveness.isUnused(inst)) break :result_value WValue.none;
|
||||
switch (result_ty.zigTypeTag()) {
|
||||
.Array => {
|
||||
const result = try func.allocStack(result_ty);
|
||||
@ -4894,7 +4844,6 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{extra.init});
|
||||
|
||||
const result = result: {
|
||||
const union_ty = func.air.typeOfIndex(inst);
|
||||
@ -4933,7 +4882,6 @@ fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const pl_op = func.air.instructions.items(.data)[inst].pl_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{pl_op.operand});
|
||||
|
||||
const result = try func.allocLocal(func.air.typeOfIndex(inst));
|
||||
try func.addLabel(.memory_size, pl_op.payload);
|
||||
@ -4943,7 +4891,6 @@ fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void {
|
||||
const pl_op = func.air.instructions.items(.data)[inst].pl_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{pl_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(pl_op.operand);
|
||||
const result = try func.allocLocal(func.air.typeOfIndex(inst));
|
||||
@ -5055,7 +5002,6 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const un_ty = func.air.typeOf(ty_op.operand);
|
||||
const tag_ty = func.air.typeOfIndex(inst);
|
||||
@ -5075,7 +5021,6 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const dest_ty = func.air.typeOfIndex(inst);
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
@ -5121,7 +5066,6 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!
|
||||
|
||||
fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const dest_ty = func.air.typeOfIndex(inst);
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
@ -5162,7 +5106,6 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro
|
||||
|
||||
fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const err_set_ty = func.air.typeOf(ty_op.operand).childType();
|
||||
const payload_ty = err_set_ty.errorUnionPayload();
|
||||
@ -5177,8 +5120,6 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
|
||||
);
|
||||
|
||||
const result = result: {
|
||||
if (func.liveness.isUnused(inst)) break :result WValue{ .none = {} };
|
||||
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
break :result func.reuseOperand(ty_op.operand, operand);
|
||||
}
|
||||
@ -5191,7 +5132,6 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi
|
||||
fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{extra.field_ptr});
|
||||
|
||||
const field_ptr = try func.resolveInst(extra.field_ptr);
|
||||
const parent_ty = func.air.getRefType(ty_pl.ty).childType();
|
||||
@ -5231,7 +5171,6 @@ fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
const op_ty = func.air.typeOf(ty_op.operand);
|
||||
@ -5276,7 +5215,6 @@ fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
|
||||
const operand = try func.resolveInst(un_op);
|
||||
// First retrieve the symbol index to the error name table
|
||||
@ -5318,7 +5256,6 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airPtrSliceFieldPtr(func: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
const slice_ptr = try func.resolveInst(ty_op.operand);
|
||||
const result = try func.buildPointerOffset(slice_ptr, offset, .new);
|
||||
func.finishAir(inst, result, &.{ty_op.operand});
|
||||
@ -5328,7 +5265,6 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro
|
||||
assert(op == .add or op == .sub);
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ extra.lhs, extra.rhs });
|
||||
|
||||
const lhs_op = try func.resolveInst(extra.lhs);
|
||||
const rhs_op = try func.resolveInst(extra.rhs);
|
||||
@ -5471,7 +5407,6 @@ fn addSubWithOverflowBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type,
|
||||
fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ extra.lhs, extra.rhs });
|
||||
|
||||
const lhs = try func.resolveInst(extra.lhs);
|
||||
const rhs = try func.resolveInst(extra.rhs);
|
||||
@ -5519,7 +5454,6 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ extra.lhs, extra.rhs });
|
||||
|
||||
const lhs = try func.resolveInst(extra.lhs);
|
||||
const rhs = try func.resolveInst(extra.rhs);
|
||||
@ -5605,7 +5539,6 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
if (ty.zigTypeTag() == .Vector) {
|
||||
@ -5637,8 +5570,6 @@ fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerE
|
||||
fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const pl_op = func.air.instructions.items(.data)[inst].pl_op;
|
||||
const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data;
|
||||
if (func.liveness.isUnused(inst))
|
||||
return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
if (ty.zigTypeTag() == .Vector) {
|
||||
@ -5671,7 +5602,6 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const ty = func.air.typeOf(ty_op.operand);
|
||||
const result_ty = func.air.typeOfIndex(inst);
|
||||
@ -5724,7 +5654,6 @@ fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const ty = func.air.typeOf(ty_op.operand);
|
||||
const result_ty = func.air.typeOfIndex(inst);
|
||||
@ -5892,7 +5821,6 @@ fn lowerTry(
|
||||
|
||||
fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ty_op.operand});
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
@ -5963,7 +5891,6 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
@ -5978,7 +5905,6 @@ fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
@ -6127,7 +6053,6 @@ fn signAbsValue(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue {
|
||||
fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
|
||||
assert(op == .add or op == .sub);
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
const lhs = try func.resolveInst(bin_op.lhs);
|
||||
@ -6240,7 +6165,6 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type,
|
||||
|
||||
fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const bin_op = func.air.instructions.items(.data)[inst].bin_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const ty = func.air.typeOfIndex(inst);
|
||||
const int_info = ty.intInfo(func.target);
|
||||
@ -6399,7 +6323,6 @@ fn callIntrinsic(
|
||||
|
||||
fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const un_op = func.air.instructions.items(.data)[inst].un_op;
|
||||
if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{un_op});
|
||||
const operand = try func.resolveInst(un_op);
|
||||
const enum_ty = func.air.typeOf(un_op);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -8,16 +8,16 @@ const Type = @import("type.zig").Type;
|
||||
const Air = @import("Air.zig");
|
||||
const Liveness = @import("Liveness.zig");
|
||||
|
||||
pub fn write(stream: anytype, module: *Module, air: Air, liveness: Liveness) void {
|
||||
pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) void {
|
||||
const instruction_bytes = air.instructions.len *
|
||||
// Here we don't use @sizeOf(Air.Inst.Data) because it would include
|
||||
// the debug safety tag but we want to measure release size.
|
||||
(@sizeOf(Air.Inst.Tag) + 8);
|
||||
const extra_bytes = air.extra.len * @sizeOf(u32);
|
||||
const values_bytes = air.values.len * @sizeOf(Value);
|
||||
const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);
|
||||
const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);
|
||||
const liveness_special_bytes = liveness.special.count() * 8;
|
||||
const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
|
||||
const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
|
||||
const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
|
||||
const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
|
||||
values_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
|
||||
liveness_special_bytes + tomb_bytes;
|
||||
@ -38,8 +38,8 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: Liveness) voi
|
||||
air.extra.len, fmtIntSizeBin(extra_bytes),
|
||||
air.values.len, fmtIntSizeBin(values_bytes),
|
||||
fmtIntSizeBin(tomb_bytes),
|
||||
liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
|
||||
liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
|
||||
if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
|
||||
if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
|
||||
}) catch return;
|
||||
// zig fmt: on
|
||||
|
||||
@ -61,7 +61,7 @@ pub fn writeInst(
|
||||
inst: Air.Inst.Index,
|
||||
module: *Module,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
liveness: ?Liveness,
|
||||
) void {
|
||||
var writer: Writer = .{
|
||||
.module = module,
|
||||
@ -74,11 +74,11 @@ pub fn writeInst(
|
||||
writer.writeInst(stream, inst) catch return;
|
||||
}
|
||||
|
||||
pub fn dump(module: *Module, air: Air, liveness: Liveness) void {
|
||||
pub fn dump(module: *Module, air: Air, liveness: ?Liveness) void {
|
||||
write(std.io.getStdErr().writer(), module, air, liveness);
|
||||
}
|
||||
|
||||
pub fn dumpInst(inst: Air.Inst.Index, module: *Module, air: Air, liveness: Liveness) void {
|
||||
pub fn dumpInst(inst: Air.Inst.Index, module: *Module, air: Air, liveness: ?Liveness) void {
|
||||
writeInst(std.io.getStdErr().writer(), inst, module, air, liveness);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ const Writer = struct {
|
||||
module: *Module,
|
||||
gpa: Allocator,
|
||||
air: Air,
|
||||
liveness: Liveness,
|
||||
liveness: ?Liveness,
|
||||
indent: usize,
|
||||
skip_body: bool,
|
||||
|
||||
@ -109,7 +109,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.print("%{d}{c}= {s}(", .{
|
||||
inst,
|
||||
@as(u8, if (w.liveness.isUnused(inst)) '!' else ' '),
|
||||
@as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
|
||||
@tagName(tag),
|
||||
});
|
||||
switch (tag) {
|
||||
@ -389,6 +389,10 @@ const Writer = struct {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = w.air.extra[extra.end..][0..extra.data.body_len];
|
||||
const liveness_block = if (w.liveness) |liveness|
|
||||
liveness.getBlock(inst)
|
||||
else
|
||||
Liveness.BlockSlices{ .deaths = &.{} };
|
||||
|
||||
try w.writeType(s, w.air.getRefType(ty_pl.ty));
|
||||
if (w.skip_body) return s.writeAll(", ...");
|
||||
@ -399,13 +403,16 @@ const Writer = struct {
|
||||
w.indent = old_indent;
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_block.deaths) |operand| {
|
||||
try s.print(" %{d}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.Block, ty_pl.payload);
|
||||
const body = w.air.extra[extra.end..][0..extra.data.body_len];
|
||||
const liveness_loop = w.liveness.getLoop(inst);
|
||||
|
||||
try w.writeType(s, w.air.getRefType(ty_pl.ty));
|
||||
if (w.skip_body) return s.writeAll(", ...");
|
||||
@ -413,14 +420,6 @@ const Writer = struct {
|
||||
const old_indent = w.indent;
|
||||
w.indent += 2;
|
||||
try w.writeBody(s, body);
|
||||
if (liveness_loop.deaths.len != 0) {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_loop.deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
w.indent = old_indent;
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.writeAll("}");
|
||||
@ -746,22 +745,44 @@ const Writer = struct {
|
||||
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
|
||||
const extra = w.air.extraData(Air.Try, pl_op.payload);
|
||||
const body = w.air.extra[extra.end..][0..extra.data.body_len];
|
||||
const liveness_condbr = if (w.liveness) |liveness|
|
||||
liveness.getCondBr(inst)
|
||||
else
|
||||
Liveness.CondBrSlices{ .then_deaths = &.{}, .else_deaths = &.{} };
|
||||
|
||||
try w.writeOperand(s, inst, 0, pl_op.operand);
|
||||
if (w.skip_body) return s.writeAll(", ...");
|
||||
try s.writeAll(", {\n");
|
||||
const old_indent = w.indent;
|
||||
w.indent += 2;
|
||||
|
||||
if (liveness_condbr.else_deaths.len != 0) {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
try w.writeBody(s, body);
|
||||
|
||||
w.indent = old_indent;
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
|
||||
const body = w.air.extra[extra.end..][0..extra.data.body_len];
|
||||
const liveness_condbr = if (w.liveness) |liveness|
|
||||
liveness.getCondBr(inst)
|
||||
else
|
||||
Liveness.CondBrSlices{ .then_deaths = &.{}, .else_deaths = &.{} };
|
||||
|
||||
try w.writeOperand(s, inst, 0, extra.data.ptr);
|
||||
|
||||
@ -771,10 +792,24 @@ const Writer = struct {
|
||||
try s.writeAll(", {\n");
|
||||
const old_indent = w.indent;
|
||||
w.indent += 2;
|
||||
|
||||
if (liveness_condbr.else_deaths.len != 0) {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
try w.writeBody(s, body);
|
||||
|
||||
w.indent = old_indent;
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
@ -782,7 +817,10 @@ const Writer = struct {
|
||||
const extra = w.air.extraData(Air.CondBr, pl_op.payload);
|
||||
const then_body = w.air.extra[extra.end..][0..extra.data.then_body_len];
|
||||
const else_body = w.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
|
||||
const liveness_condbr = w.liveness.getCondBr(inst);
|
||||
const liveness_condbr = if (w.liveness) |liveness|
|
||||
liveness.getCondBr(inst)
|
||||
else
|
||||
Liveness.CondBrSlices{ .then_deaths = &.{}, .else_deaths = &.{} };
|
||||
|
||||
try w.writeOperand(s, inst, 0, pl_op.operand);
|
||||
if (w.skip_body) return s.writeAll(", ...");
|
||||
@ -822,8 +860,15 @@ const Writer = struct {
|
||||
fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
|
||||
const switch_br = w.air.extraData(Air.SwitchBr, pl_op.payload);
|
||||
const liveness = w.liveness.getSwitchBr(w.gpa, inst, switch_br.data.cases_len + 1) catch
|
||||
@panic("out of memory");
|
||||
const liveness = if (w.liveness) |liveness|
|
||||
liveness.getSwitchBr(w.gpa, inst, switch_br.data.cases_len + 1) catch
|
||||
@panic("out of memory")
|
||||
else blk: {
|
||||
const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.data.cases_len + 1) catch
|
||||
@panic("out of memory");
|
||||
std.mem.set([]const Air.Inst.Index, slice, &.{});
|
||||
break :blk Liveness.SwitchBrTable{ .deaths = slice };
|
||||
};
|
||||
defer w.gpa.free(liveness.deaths);
|
||||
var extra_index: usize = switch_br.end;
|
||||
var case_i: u32 = 0;
|
||||
@ -913,13 +958,13 @@ const Writer = struct {
|
||||
operand: Air.Inst.Ref,
|
||||
) @TypeOf(s).Error!void {
|
||||
const small_tomb_bits = Liveness.bpi - 1;
|
||||
const dies = if (op_index < small_tomb_bits)
|
||||
w.liveness.operandDies(inst, @intCast(Liveness.OperandInt, op_index))
|
||||
else blk: {
|
||||
var extra_index = w.liveness.special.get(inst).?;
|
||||
const dies = if (w.liveness) |liveness| blk: {
|
||||
if (op_index < small_tomb_bits)
|
||||
break :blk liveness.operandDies(inst, @intCast(Liveness.OperandInt, op_index));
|
||||
var extra_index = liveness.special.get(inst).?;
|
||||
var tomb_op_index: usize = small_tomb_bits;
|
||||
while (true) {
|
||||
const bits = w.liveness.extra[extra_index];
|
||||
const bits = liveness.extra[extra_index];
|
||||
if (op_index < tomb_op_index + 31) {
|
||||
break :blk @truncate(u1, bits >> @intCast(u5, op_index - tomb_op_index)) != 0;
|
||||
}
|
||||
@ -927,7 +972,7 @@ const Writer = struct {
|
||||
extra_index += 1;
|
||||
tomb_op_index += 31;
|
||||
}
|
||||
};
|
||||
} else false;
|
||||
return w.writeInstRef(s, operand, dies);
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,10 @@ pub fn RegisterManager(
|
||||
return indexOfReg(tracked_registers, reg);
|
||||
}
|
||||
|
||||
pub fn regAtTrackedIndex(index: RegisterBitSet.ShiftInt) Register {
|
||||
return tracked_registers[index];
|
||||
}
|
||||
|
||||
/// Returns true when this register is not tracked
|
||||
pub fn isRegFree(self: Self, reg: Register) bool {
|
||||
const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
|
@ -274,7 +274,6 @@ test "two counters" {
|
||||
test "1-based counter and ptr to array" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var ok: usize = 0;
|
||||
|
||||
|
@ -215,3 +215,29 @@ test "copy VaList" {
|
||||
try std.testing.expectEqual(@as(c_int, 3), S.add(1, @as(c_int, 1)));
|
||||
try std.testing.expectEqual(@as(c_int, 9), S.add(2, @as(c_int, 1), @as(c_int, 2)));
|
||||
}
|
||||
|
||||
test "unused VaList arg" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn thirdArg(dummy: c_int, ...) callconv(.C) c_int {
|
||||
_ = dummy;
|
||||
|
||||
var ap = @cVaStart();
|
||||
defer @cVaEnd(&ap);
|
||||
|
||||
_ = @cVaArg(&ap, c_int);
|
||||
return @cVaArg(&ap, c_int);
|
||||
}
|
||||
};
|
||||
const x = S.thirdArg(0, @as(c_int, 1), @as(c_int, 2));
|
||||
try std.testing.expectEqual(@as(c_int, 2), x);
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
pub fn main() void {
|
||||
foo(123);
|
||||
}
|
||||
|
||||
fn foo(x: u64) void {
|
||||
if (x > 42) {
|
||||
print();
|
||||
}
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (64),
|
||||
[arg1] "{x0}" (1),
|
||||
[arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{x2}" ("Hello, World!\n".len),
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
// run
|
||||
// target=aarch64-linux
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,25 +0,0 @@
|
||||
pub fn main() void {
|
||||
foo(true);
|
||||
}
|
||||
|
||||
fn foo(x: bool) void {
|
||||
if (x) {
|
||||
print();
|
||||
}
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (64),
|
||||
[arg1] "{x0}" (1),
|
||||
[arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{x2}" ("Hello, World!\n".len),
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,31 +0,0 @@
|
||||
pub export fn _start() noreturn {
|
||||
print();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (64),
|
||||
[arg1] "{x0}" (1),
|
||||
[arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{x2}" ("Hello, World!\n".len),
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
fn exit(ret: usize) noreturn {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (93),
|
||||
[arg1] "{x0}" (ret),
|
||||
: "memory", "cc"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=aarch64-linux
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,36 +0,0 @@
|
||||
pub export fn _start() noreturn {
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (64),
|
||||
[arg1] "{x0}" (1),
|
||||
[arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{x2}" ("Hello, World!\n".len),
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
fn exit(ret: usize) noreturn {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (93),
|
||||
[arg1] "{x0}" (ret),
|
||||
: "memory", "cc"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
@ -1,21 +0,0 @@
|
||||
pub fn main() void {
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (64),
|
||||
[arg1] "{x0}" (1),
|
||||
[arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{x2}" ("Hello, World!\n".len),
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
@ -1,22 +0,0 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
const msg = @ptrToInt("Hello, World!\n");
|
||||
const len = 14;
|
||||
_ = write(1, msg, len);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
@ -1,16 +0,0 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
|
||||
const len = 104;
|
||||
_ = write(1, msg, len);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// What is up? This is a longer message that will force the data to be relocated in virtual address space.
|
||||
//
|
@ -1,18 +0,0 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
|
||||
const len = 104;
|
||||
_ = write(1, msg, len);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// What is up? This is a longer message that will force the data to be relocated in virtual address space.
|
||||
// What is up? This is a longer message that will force the data to be relocated in virtual address space.
|
||||
//
|
17
test/cases/arithmetic_operations.0.zig
Normal file
17
test/cases/arithmetic_operations.0.zig
Normal file
@ -0,0 +1,17 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
print(2, 4);
|
||||
print(1, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
const str = "123456789";
|
||||
const len = a + b;
|
||||
_ = std.os.write(1, str[0..len]) catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-linux,x86_64-macos
|
||||
//
|
||||
// 12345612345678
|
16
test/cases/arithmetic_operations.1.zig
Normal file
16
test/cases/arithmetic_operations.1.zig
Normal file
@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
print(10, 5);
|
||||
print(4, 3);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
const str = "123456789";
|
||||
const len = a - b;
|
||||
_ = std.os.write(1, str[0..len]) catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 123451
|
16
test/cases/arithmetic_operations.2.zig
Normal file
16
test/cases/arithmetic_operations.2.zig
Normal file
@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
print(8, 9);
|
||||
print(3, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
const str = "123456789";
|
||||
const len = a & b;
|
||||
_ = std.os.write(1, str[0..len]) catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 12345678123
|
16
test/cases/arithmetic_operations.3.zig
Normal file
16
test/cases/arithmetic_operations.3.zig
Normal file
@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
print(4, 2);
|
||||
print(3, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
const str = "123456789";
|
||||
const len = a | b;
|
||||
_ = std.os.write(1, str[0..len]) catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 1234561234567
|
16
test/cases/arithmetic_operations.4.zig
Normal file
16
test/cases/arithmetic_operations.4.zig
Normal file
@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
print(42, 42);
|
||||
print(3, 5);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
const str = "123456789";
|
||||
const len = a ^ b;
|
||||
_ = std.os.write(1, str[0..len]) catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 123456
|
@ -1,21 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(2, 4);
|
||||
print(1, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (a + b),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("123456789")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
||||
// 12345612345678
|
@ -1,20 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(10, 5);
|
||||
print(4, 3);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (a - b),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("123456789")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 123451
|
@ -1,20 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(8, 9);
|
||||
print(3, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (a & b),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("123456789")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 12345678123
|
@ -1,20 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(4, 2);
|
||||
print(3, 7);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (a | b),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("123456789")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 1234561234567
|
@ -1,20 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(42, 42);
|
||||
print(3, 5);
|
||||
}
|
||||
|
||||
fn print(a: u32, b: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (a ^ b),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("123456789")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// 123456
|
@ -1,21 +0,0 @@
|
||||
pub fn main() void {
|
||||
foo() catch print();
|
||||
}
|
||||
|
||||
fn foo() anyerror!void {}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{r2}" ("Hello, World!\n".len),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
@ -1,24 +0,0 @@
|
||||
pub fn main() void {
|
||||
foo() catch print();
|
||||
}
|
||||
|
||||
fn foo() anyerror!void {
|
||||
return error.Test;
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{r2}" ("Hello, World!\n".len),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,44 +0,0 @@
|
||||
const PrintFn = *const fn () void;
|
||||
|
||||
pub fn main() void {
|
||||
var printFn: PrintFn = stopSayingThat;
|
||||
var i: u32 = 0;
|
||||
while (i < 4) : (i += 1) printFn();
|
||||
|
||||
printFn = moveEveryZig;
|
||||
printFn();
|
||||
}
|
||||
|
||||
fn stopSayingThat() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n")),
|
||||
[arg3] "{r2}" ("Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n".len),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
fn moveEveryZig() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("All your codebase are belong to us\n")),
|
||||
[arg3] "{r2}" ("All your codebase are belong to us\n".len),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// All your codebase are belong to us
|
||||
//
|
@ -1,32 +0,0 @@
|
||||
pub export fn _start() noreturn {
|
||||
print();
|
||||
exit();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{r2}" (14),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
fn exit() noreturn {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (1),
|
||||
[arg1] "{r0}" (0),
|
||||
: "memory"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,37 +0,0 @@
|
||||
pub export fn _start() noreturn {
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
print();
|
||||
exit();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{r2}" (14),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
fn exit() noreturn {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (1),
|
||||
[arg1] "{r0}" (0),
|
||||
: "memory"
|
||||
);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
@ -1,22 +0,0 @@
|
||||
pub fn main() void {
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
[arg3] "{r2}" (14),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
@ -1,28 +0,0 @@
|
||||
pub fn main() void {
|
||||
print(id(14));
|
||||
}
|
||||
|
||||
fn id(x: u32) u32 {
|
||||
return x;
|
||||
}
|
||||
|
||||
// TODO: The parameters to the asm statement in print() had to
|
||||
// be in a specific order because otherwise the write to r0
|
||||
// would overwrite the len parameter which resides in r0
|
||||
fn print(len: u32) void {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg3] "{r2}" (len),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
|
||||
: "memory"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
@ -1,40 +0,0 @@
|
||||
pub fn main() void {
|
||||
printNumberHex(0x00000000);
|
||||
printNumberHex(0xaaaaaaaa);
|
||||
printNumberHex(0xdeadbeef);
|
||||
printNumberHex(0x31415926);
|
||||
}
|
||||
|
||||
fn printNumberHex(x: u32) void {
|
||||
var i: u5 = 28;
|
||||
while (true) : (i -= 4) {
|
||||
const digit = (x >> i) & 0xf;
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("0123456789abcdef") + digit),
|
||||
[arg3] "{r2}" (1),
|
||||
: "memory"
|
||||
);
|
||||
|
||||
if (i == 0) break;
|
||||
}
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (4),
|
||||
[arg1] "{r0}" (1),
|
||||
[arg2] "{r1}" (@ptrToInt("\n")),
|
||||
[arg3] "{r2}" (1),
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
// run
|
||||
// target=arm-linux
|
||||
//
|
||||
// 00000000
|
||||
// aaaaaaaa
|
||||
// deadbeef
|
||||
// 31415926
|
||||
//
|
@ -11,5 +11,5 @@ pub fn assert(ok: bool) void {
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-linux
|
||||
//
|
||||
// target=x86_64-macos,x86_64-linux
|
||||
// link_libc=true
|
20
test/cases/assert_function.18.zig
Normal file
20
test/cases/assert_function.18.zig
Normal file
@ -0,0 +1,20 @@
|
||||
const builtin = @import("builtin");
|
||||
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
for ("hello") |_| print();
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
_ = write(1, @ptrToInt("hello\n"), 6);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
//
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
var i: u32 = 0;
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
var i: u32 = 0;
|
@ -5,5 +5,5 @@ pub fn main() void {
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-linux,x86_64-macos,aarch64-linux,aarch64-macos
|
||||
// target=x86_64-linux,x86_64-macos
|
||||
//
|
||||
|
@ -6,7 +6,8 @@ pub fn main() void {
|
||||
|
||||
// error
|
||||
// output_mode=Exe
|
||||
// target=x86_64-linux
|
||||
// target=x86_64-macos,x86_64-linux
|
||||
// link_libc=true
|
||||
//
|
||||
// :4:19: error: store to comptime variable depends on runtime condition
|
||||
// :4:11: note: runtime condition here
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
comptime var len: u32 = 5;
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
comptime var i: u64 = 2;
|
23
test/cases/conditional_branches.0.zig
Normal file
23
test/cases/conditional_branches.0.zig
Normal file
@ -0,0 +1,23 @@
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
foo(123);
|
||||
}
|
||||
|
||||
fn foo(x: u64) void {
|
||||
if (x > 42) {
|
||||
print();
|
||||
}
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
const str = "Hello, World!\n";
|
||||
_ = write(1, @ptrToInt(str.ptr), ptr.len);
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-linux,x86_64-macos
|
||||
// link_libc=true
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
25
test/cases/conditional_branches.1.zig
Normal file
25
test/cases/conditional_branches.1.zig
Normal file
@ -0,0 +1,25 @@
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
foo(true);
|
||||
}
|
||||
|
||||
fn foo(x: bool) void {
|
||||
if (x) {
|
||||
print();
|
||||
print();
|
||||
} else {
|
||||
print();
|
||||
}
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
const str = "Hello, World!\n";
|
||||
_ = write(1, @ptrToInt(str.ptr), ptr.len);
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
// Hello, World!
|
||||
//
|
15
test/cases/errors.0.zig
Normal file
15
test/cases/errors.0.zig
Normal file
@ -0,0 +1,15 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
foo() catch print();
|
||||
}
|
||||
|
||||
fn foo() anyerror!void {}
|
||||
|
||||
fn print() void {
|
||||
_ = std.os.write(1, "Hello, World!\n") catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-macos
|
||||
//
|
18
test/cases/errors.1.zig
Normal file
18
test/cases/errors.1.zig
Normal file
@ -0,0 +1,18 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
foo() catch print();
|
||||
}
|
||||
|
||||
fn foo() anyerror!void {
|
||||
return error.Test;
|
||||
}
|
||||
|
||||
fn print() void {
|
||||
_ = std.os.write(1, "Hello, World!\n") catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
//
|
||||
// Hello, World!
|
||||
//
|
5
test/cases/exit.zig
Normal file
5
test/cases/exit.zig
Normal file
@ -0,0 +1,5 @@
|
||||
pub fn main() void {}
|
||||
|
||||
// run
|
||||
// target=x86_64-linux,x86_64-macos,x86_64-windows,x86_64-plan9
|
||||
//
|
30
test/cases/function_pointers.zig
Normal file
30
test/cases/function_pointers.zig
Normal file
@ -0,0 +1,30 @@
|
||||
const std = @import("std");
|
||||
|
||||
const PrintFn = *const fn () void;
|
||||
|
||||
pub fn main() void {
|
||||
var printFn: PrintFn = stopSayingThat;
|
||||
var i: u32 = 0;
|
||||
while (i < 4) : (i += 1) printFn();
|
||||
|
||||
printFn = moveEveryZig;
|
||||
printFn();
|
||||
}
|
||||
|
||||
fn stopSayingThat() void {
|
||||
_ = std.os.write(1, "Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n") catch {};
|
||||
}
|
||||
|
||||
fn moveEveryZig() void {
|
||||
_ = std.os.write(1, "All your codebase are belong to us\n") catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-macos
|
||||
//
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// All your codebase are belong to us
|
||||
//
|
@ -1,5 +1,6 @@
|
||||
// error
|
||||
// output_mode=Exe
|
||||
// target=aarch64-macos
|
||||
// target=x86_64-linux,x86_64-macos
|
||||
// link_libc=true
|
||||
//
|
||||
// :?:?: error: root struct of file 'tmp' has no member named 'main'
|
@ -1,5 +1,5 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn exit(usize) noreturn;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
extern "c" fn exit(c_int) noreturn;
|
||||
|
||||
pub export fn main() noreturn {
|
||||
print();
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
@ -1,4 +1,4 @@
|
||||
extern "c" fn write(usize, usize, usize) usize;
|
||||
extern "c" fn write(c_int, usize, usize) usize;
|
||||
|
||||
pub fn main() void {
|
||||
print();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user