authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-11 21:23:47+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-16 11:26:32+00:00
log2e27967a81d325047e6d82f8c0722a8a654d1ac7
treec22414dd9d53298085a27932f071edcbdde2b912
parent51e96a823ce21a6b027bfdf55d94c3872a103703
signaturelock-open Commit is signed but in an unrecognized format.

AstGen: avoid emitting multiple `ret_type` instructions

This is a small optimization to generated ZIR. In any function where the return type is not a trivial Ref, we know it is almost certainly not `void` (unless the user aliased it or did something else weird to fool AstGen), and thus the return type is very likely to be required for return value RLS at some point. Thus, we can just emit one `ret_type` at the start of the function and use it throughout. This sees a very small improvement in overall ZIR bytes.

1 files changed, 22 insertions(+), 3 deletions(-)

src/AstGen.zig+22-3
......@@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
4444/// The topmost block of the current function.
4545fn_block: ?*GenZir = null,
4646fn_var_args: bool = false,
47/// The return type of the current function. This may be a trivial `Ref`, or
48/// otherwise it refers to a `ret_type` instruction.
49fn_ret_ty: Zir.Inst.Ref = .none,
4750/// Maps string table indexes to the first `@import` ZIR instruction
4851/// that uses this string as the operand.
4952imports: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, Ast.TokenIndex) = .{},
......@@ -4284,8 +4287,19 @@ fn fnDecl(
42844287 fn_gz.instructions_top = ret_gz.instructions.items.len;
42854288
42864289 const prev_fn_block = astgen.fn_block;
4290 const prev_fn_ret_ty = astgen.fn_ret_ty;
42874291 astgen.fn_block = &fn_gz;
4288 defer astgen.fn_block = prev_fn_block;
4292 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
4293 // We're essentially guaranteed to need the return type at some point,
4294 // since the return type is likely not `void` or `noreturn` so there
4295 // will probably be an explicit return requiring RLS. Fetch this
4296 // return type now so the rest of the function can use it.
4297 break :r try fn_gz.addNode(.ret_type, decl_node);
4298 } else ret_ref;
4299 defer {
4300 astgen.fn_block = prev_fn_block;
4301 astgen.fn_ret_ty = prev_fn_ret_ty;
4302 }
42894303
42904304 const prev_var_args = astgen.fn_var_args;
42914305 astgen.fn_var_args = is_var_args;
......@@ -4732,8 +4746,13 @@ fn testDecl(
47324746 defer fn_block.unstack();
47334747
47344748 const prev_fn_block = astgen.fn_block;
4749 const prev_fn_ret_ty = astgen.fn_ret_ty;
47354750 astgen.fn_block = &fn_block;
4736 defer astgen.fn_block = prev_fn_block;
4751 astgen.fn_ret_ty = .anyerror_void_error_union_type;
4752 defer {
4753 astgen.fn_block = prev_fn_block;
4754 astgen.fn_ret_ty = prev_fn_ret_ty;
4755 }
47374756
47384757 astgen.advanceSourceCursorToNode(body_node);
47394758 const lbrace_line = astgen.source_line - decl_block.decl_line;
......@@ -8038,7 +8057,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
80388057 .rl = .{ .ptr = .{ .inst = try gz.addNode(.ret_ptr, node) } },
80398058 .ctx = .@"return",
80408059 } else .{
8041 .rl = .{ .ty = try gz.addNode(.ret_type, node) },
8060 .rl = .{ .ty = astgen.fn_ret_ty },
80428061 .ctx = .@"return",
80438062 };
80448063 const prev_anon_name_strategy = gz.anon_name_strategy;