Commit 2e27967a81

mlugg <mlugg@mlugg.co.uk>
2024-02-11 22:23:47
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 parent 51e96a8
Changed files (1)
src/AstGen.zig
@@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
 /// The topmost block of the current function.
 fn_block: ?*GenZir = null,
 fn_var_args: bool = false,
+/// The return type of the current function. This may be a trivial `Ref`, or
+/// otherwise it refers to a `ret_type` instruction.
+fn_ret_ty: Zir.Inst.Ref = .none,
 /// Maps string table indexes to the first `@import` ZIR instruction
 /// that uses this string as the operand.
 imports: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, Ast.TokenIndex) = .{},
@@ -4284,8 +4287,19 @@ fn fnDecl(
         fn_gz.instructions_top = ret_gz.instructions.items.len;
 
         const prev_fn_block = astgen.fn_block;
+        const prev_fn_ret_ty = astgen.fn_ret_ty;
         astgen.fn_block = &fn_gz;
-        defer astgen.fn_block = prev_fn_block;
+        astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
+            // We're essentially guaranteed to need the return type at some point,
+            // since the return type is likely not `void` or `noreturn` so there
+            // will probably be an explicit return requiring RLS. Fetch this
+            // return type now so the rest of the function can use it.
+            break :r try fn_gz.addNode(.ret_type, decl_node);
+        } else ret_ref;
+        defer {
+            astgen.fn_block = prev_fn_block;
+            astgen.fn_ret_ty = prev_fn_ret_ty;
+        }
 
         const prev_var_args = astgen.fn_var_args;
         astgen.fn_var_args = is_var_args;
@@ -4732,8 +4746,13 @@ fn testDecl(
     defer fn_block.unstack();
 
     const prev_fn_block = astgen.fn_block;
+    const prev_fn_ret_ty = astgen.fn_ret_ty;
     astgen.fn_block = &fn_block;
-    defer astgen.fn_block = prev_fn_block;
+    astgen.fn_ret_ty = .anyerror_void_error_union_type;
+    defer {
+        astgen.fn_block = prev_fn_block;
+        astgen.fn_ret_ty = prev_fn_ret_ty;
+    }
 
     astgen.advanceSourceCursorToNode(body_node);
     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
         .rl = .{ .ptr = .{ .inst = try gz.addNode(.ret_ptr, node) } },
         .ctx = .@"return",
     } else .{
-        .rl = .{ .ty = try gz.addNode(.ret_type, node) },
+        .rl = .{ .ty = astgen.fn_ret_ty },
         .ctx = .@"return",
     };
     const prev_anon_name_strategy = gz.anon_name_strategy;