feature. See also
. The project being documented here (as the example) is the Zig library itself.
Zir.findTrackableInner
fn findTrackableInner(
zir: Zir,
gpa: Allocator,
contents: *DeclContents,
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
) Allocator.Error!void
File
Code
fn findTrackableInner(
zir: Zir,
gpa: Allocator,
contents: *DeclContents,
defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
) Allocator.Error!void {
comptime assert(Zir.inst_tracking_version == 0);
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
switch (tags[@backingInt(inst)]) {
.declaration => unreachable,
.add,
.addwrap,
.add_sat,
.add_unsafe,
.sub,
.subwrap,
.sub_sat,
.mul,
.mulwrap,
.mul_sat,
.div_exact,
.div_floor,
.div_ceil,
.div_trunc,
.mod,
.rem,
.mod_rem,
.shl,
.shl_exact,
.shl_sat,
.shr,
.shr_exact,
.param_anytype,
.param_anytype_comptime,
.array_cat,
.array_type,
.array_type_sentinel,
.reify_int,
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
.splat_op_result_ty,
.from_backing_int_arg_ty,
.indexable_ptr_len,
.anyframe_type,
.as_node,
.as_shift_operand,
.bit_and,
.bitcast,
.bit_not,
.bit_or,
.bool_not,
.bool_br_and,
.bool_br_or,
.@"break",
.break_inline,
.switch_continue,
.check_comptime_control_flow,
.builtin_call,
.cmp_lt,
.cmp_lte,
.cmp_eq,
.cmp_gte,
.cmp_gt,
.cmp_neq,
.error_set_decl,
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
.decl_ref,
.decl_val,
.load,
.div,
.elem_ptr_node,
.elem_ptr,
.elem_ptr_load,
.elem_val,
.elem_val_imm,
.ensure_result_used,
.ensure_result_non_error,
.ensure_err_union_payload_void,
.error_union_type,
.error_value,
.@"export",
.field_ptr,
.field_ptr_load,
.field_ptr_named,
.field_ptr_named_load,
.import,
.int,
.int_big,
.float,
.float128,
.int_type,
.is_non_null,
.is_non_null_ptr,
.is_non_err,
.is_non_err_ptr,
.ret_is_non_err,
.repeat,
.repeat_inline,
.for_len,
.merge_error_sets,
.ref,
.deref,
.ref_deref,
.ret_node,
.ret_load,
.ret_implicit,
.ret_err_value,
.ret_ptr,
.ret_type,
.ptr_type,
.slice_start,
.slice_end,
.slice_sentinel,
.slice_length,
.slice_sentinel_ty,
.store_node,
.store_to_inferred_ptr,
.str,
.negate,
.negate_wrap,
.typeof,
.typeof_log2_int_type,
.@"unreachable",
.xor,
.optional_type,
.optional_payload_safe,
.optional_payload_unsafe,
.optional_payload_safe_ptr,
.optional_payload_unsafe_ptr,
.err_union_payload_unsafe,
.err_union_payload_unsafe_ptr,
.err_union_code,
.err_union_code_ptr,
.enum_literal,
.decl_literal,
.decl_literal_no_coerce,
.validate_destructure,
.field_type_ref,
.opt_eu_base_ptr_init,
.coerce_ptr_elem_ty,
.validate_ref_ty,
.validate_const,
.struct_init_empty,
.struct_init_empty_result,
.struct_init_empty_ref_result,
.validate_struct_init_ty,
.validate_struct_init_result_ty,
.validate_ptr_struct_init,
.struct_init_field_type,
.struct_init_field_ptr,
.array_init_anon,
.array_init,
.array_init_ref,
.validate_array_init_ty,
.validate_array_init_result_ty,
.validate_array_init_ref_ty,
.validate_ptr_array_init,
.array_init_elem_type,
.array_init_elem_ptr,
.union_init,
.type_info,
.size_of,
.bit_size_of,
.int_from_ptr,
.compile_error,
.set_eval_branch_quota,
.int_from_enum,
.align_of,
.int_from_bool,
.embed_file,
.error_name,
.panic,
.trap,
.set_runtime_safety,
.sqrt,
.sin,
.cos,
.tan,
.exp,
.exp2,
.log,
.log2,
.log10,
.abs,
.floor,
.ceil,
.trunc,
.round,
.tag_name,
.type_name,
.frame_type,
.int_from_float,
.float_from_int,
.ptr_from_int,
.enum_from_int,
.backing_int,
.from_backing_int,
.float_cast,
.int_cast,
.ptr_cast,
.truncate,
.has_decl,
.has_field,
.clz,
.ctz,
.pop_count,
.byte_swap,
.bit_reverse,
.bit_offset_of,
.offset_of,
.splat,
.reduce,
.shuffle,
.atomic_load,
.atomic_rmw,
.atomic_store,
.mul_add,
.memcpy,
.memset,
.memmove,
.min,
.max,
.alloc,
.alloc_mut,
.alloc_comptime_mut,
.alloc_inferred,
.alloc_inferred_mut,
.alloc_inferred_comptime,
.alloc_inferred_comptime_mut,
.resolve_inferred_alloc,
.make_ptr_const,
.@"resume",
.save_err_ret_index,
.restore_err_ret_index_unconditional,
.restore_err_ret_index_fn_entry,
=> return,
.struct_init,
.struct_init_ref,
.struct_init_anon,
=> return contents.other.append(gpa, inst),
.extended => {
const extended = datas[@backingInt(inst)].extended;
switch (extended.opcode) {
.value_placeholder => unreachable,
.this,
.ret_addr,
.builtin_src,
.error_return_trace,
.frame,
.frame_address,
.alloc,
.builtin_extern,
.@"asm",
.asm_expr,
.compile_log,
.min_multi,
.max_multi,
.add_with_overflow,
.sub_with_overflow,
.mul_with_overflow,
.shl_with_overflow,
.round_op,
.wasm_memory_size,
.wasm_memory_grow,
.prefetch,
.set_float_mode,
.error_cast,
.breakpoint,
.disable_instrumentation,
.disable_intrinsics,
.select,
.int_from_error,
.error_from_int,
.reify_slice_arg_ty,
.reify_enum_value_slice_ty,
.reify_pointer_sentinel_ty,
.reify_tuple,
.reify_pointer,
.reify_fn,
.cmpxchg,
.c_va_arg,
.c_va_copy,
.c_va_end,
.c_va_start,
.ptr_cast_full,
.ptr_cast_no_dest,
.work_item_id,
.work_group_size,
.work_group_id,
.in_comptime,
.restore_err_ret_index,
.closure_get,
.field_parent_ptr,
.std_lang_value,
.branch_hint,
.inplace_arith_result_ty,
.tuple_decl,
.dbg_empty_stmt,
.astgen_error,
.float_op_result_ty,
.round_op_ty,
=> return,
.typeof_peer => {
const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);
try zir.findTrackableBody(gpa, contents, defers, body);
},
.reify_enum,
.reify_struct,
.reify_union,
.reify_spirv_type,
=> return contents.other.append(gpa, inst),
.struct_decl,
.union_decl,
.enum_decl,
.opaque_decl,
=> return contents.type_decls.append(gpa, inst),
}
},
.func,
.func_inferred,
=> {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
if (extra.data.body_len == 0) {
assert(extra.data.ret_ty.body_len < 2);
return;
}
assert(contents.func_decl == null);
contents.func_decl = inst;
var extra_index: usize = extra.end;
switch (extra.data.ret_ty.body_len) {
0 => {},
1 => extra_index += 1,
else => {
const body = zir.bodySlice(extra_index, extra.data.ret_ty.body_len);
extra_index += body.len;
try zir.findTrackableBody(gpa, contents, defers, body);
},
}
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findTrackableBody(gpa, contents, defers, body);
},
.func_fancy => {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
if (extra.data.body_len == 0) {
assert(!extra.data.bits.has_cc_body);
assert(!extra.data.bits.has_ret_ty_body);
return;
}
assert(contents.func_decl == null);
contents.func_decl = inst;
var extra_index: usize = extra.end;
if (extra.data.bits.has_cc_body) {
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_cc_ref) {
extra_index += 1;
}
if (extra.data.bits.has_ret_ty_body) {
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
try zir.findTrackableBody(gpa, contents, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_ret_ty_ref) {
extra_index += 1;
}
extra_index += @intFromBool(extra.data.bits.has_any_noalias);
const body = zir.bodySlice(extra_index, extra.data.body_len);
return zir.findTrackableBody(gpa, contents, defers, body);
},
.block,
.block_inline,
.typeof_builtin,
.loop,
=> {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.Block, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
return zir.findTrackableBody(gpa, contents, defers, body);
},
.block_comptime => {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.BlockComptime, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
return zir.findTrackableBody(gpa, contents, defers, body);
},
.condbr, .condbr_inline => {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
try zir.findTrackableBody(gpa, contents, defers, then_body);
try zir.findTrackableBody(gpa, contents, defers, else_body);
},
.@"try", .try_ptr => {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(Inst.Try, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
try zir.findTrackableBody(gpa, contents, defers, body);
},
.switch_block,
.switch_block_ref,
.switch_block_err_union,
=> {
const zir_switch = zir.getSwitchBlock(inst);
if (zir_switch.non_err_case) |non_err_case| {
try zir.findTrackableBody(gpa, contents, defers, non_err_case.body);
}
if (zir_switch.else_case) |else_case| {
try zir.findTrackableBody(gpa, contents, defers, else_case.body);
}
var extra_index = zir_switch.end;
var case_it = zir_switch.iterateCases();
while (case_it.next()) |case| {
const prong_body = zir.bodySlice(extra_index, case.prong_info.body_len);
extra_index += prong_body.len;
try zir.findTrackableBody(gpa, contents, defers, prong_body);
for (case.item_infos) |item_info| {
if (item_info.bodyLen()) |body_len| {
const item_body = zir.bodySlice(extra_index, body_len);
extra_index += item_body.len;
try zir.findTrackableBody(gpa, contents, defers, item_body);
}
}
for (case.range_infos) |range_info| {
if (range_info[0].bodyLen()) |body_len| {
const first_body = zir.bodySlice(extra_index, body_len);
extra_index += first_body.len;
try zir.findTrackableBody(gpa, contents, defers, first_body);
}
if (range_info[1].bodyLen()) |body_len| {
const last_body = zir.bodySlice(extra_index, body_len);
extra_index += last_body.len;
try zir.findTrackableBody(gpa, contents, defers, last_body);
}
}
}
},
.suspend_block => @panic("TODO iterate suspend block"),
.param, .param_comptime => {
const inst_data = datas[@backingInt(inst)].pl_tok;
const extra = zir.extraData(Inst.Param, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.type.body_len);
try zir.findTrackableBody(gpa, contents, defers, body);
},
inline .call, .field_call => |tag| {
const inst_data = datas[@backingInt(inst)].pl_node;
const extra = zir.extraData(switch (tag) {
.call => Inst.Call,
.field_call => Inst.FieldCall,
else => unreachable,
}, inst_data.payload_index);
const args_len = extra.data.flags.args_len;
if (args_len > 0) {
const first_arg_start_off = args_len;
const final_arg_end_off = zir.extra[extra.end + args_len - 1];
const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);
try zir.findTrackableBody(gpa, contents, defers, args_body);
}
},
.@"defer" => {
const inst_data = datas[@backingInt(inst)].@"defer";
const gop = try defers.getOrPut(gpa, inst_data.index);
if (!gop.found_existing) {
const body = zir.bodySlice(inst_data.index, inst_data.len);
try zir.findTrackableBody(gpa, contents, defers, body);
}
},
}
}