authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-29 22:41:07+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-31 09:55:03+00:00
logd6120cf6a9a1d946f6754aa7de49c31b1fc8398e
tree400c7a774ddb39196ea9b6e09b27026ce6cfbab7
parent71bcbd59936a514843265756ae4ad03a8d656c3c
signaturelock-open Commit is signed but in an unrecognized format.

AstGen: better `block_comptime` elision


1 files changed, 74 insertions(+), 13 deletions(-)

lib/std/zig/AstGen.zig+74-13
...@@ -810,7 +810,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -810,7 +810,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
810 .negation => return negation(gz, scope, ri, node),810 .negation => return negation(gz, scope, ri, node),
811 .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap),811 .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap),
812812
813 .identifier => return identifier(gz, scope, ri, node),813 .identifier => return identifier(gz, scope, ri, node, null),
814814
815 .asm_simple,815 .asm_simple,
816 .@"asm",816 .@"asm",
...@@ -2006,19 +2006,50 @@ fn comptimeExpr2(...@@ -2006,19 +2006,50 @@ fn comptimeExpr2(
2006 const main_tokens = tree.nodes.items(.main_token);2006 const main_tokens = tree.nodes.items(.main_token);
2007 const node_tags = tree.nodes.items(.tag);2007 const node_tags = tree.nodes.items(.tag);
2008 switch (node_tags[node]) {2008 switch (node_tags[node]) {
2009 // Any identifier in `primitive_instrs` is trivially comptime. In particular, this includes
2010 // some common types, so we can elide `block_comptime` for a few common type annotations.
2011 .identifier => {2009 .identifier => {
2012 const ident_token = main_tokens[node];2010 // Many identifiers can be handled without a `block_comptime`, so `AstGen.identifier` has
2013 const ident_name_raw = tree.tokenSlice(ident_token);2011 // special handling for this case.
2014 if (primitive_instrs.get(ident_name_raw)) |zir_const_ref| {2012 return identifier(gz, scope, ri, node, .{ .src_node = src_node, .reason = reason });
2015 // No need to worry about result location here, we're not creating a comptime block!
2016 return rvalue(gz, ri, zir_const_ref, node);
2017 }
2018 },2013 },
20192014
2020 // We can also avoid the block for a few trivial AST tags which are always comptime-known.2015 // These are leaf nodes which are always comptime-known.
2021 .number_literal, .string_literal, .multiline_string_literal, .enum_literal, .error_value => {2016 .number_literal,
2017 .char_literal,
2018 .string_literal,
2019 .multiline_string_literal,
2020 .enum_literal,
2021 .error_value,
2022 .anyframe_literal,
2023 .error_set_decl,
2024 // These nodes are not leaves, but will force comptime evaluation of all sub-expressions, and
2025 // hence behave the same regardless of whether they're in a comptime scope.
2026 .error_union,
2027 .merge_error_sets,
2028 .optional_type,
2029 .anyframe_type,
2030 .ptr_type_aligned,
2031 .ptr_type_sentinel,
2032 .ptr_type,
2033 .ptr_type_bit_range,
2034 .array_type,
2035 .array_type_sentinel,
2036 .fn_proto_simple,
2037 .fn_proto_multi,
2038 .fn_proto_one,
2039 .fn_proto,
2040 .container_decl,
2041 .container_decl_trailing,
2042 .container_decl_arg,
2043 .container_decl_arg_trailing,
2044 .container_decl_two,
2045 .container_decl_two_trailing,
2046 .tagged_union,
2047 .tagged_union_trailing,
2048 .tagged_union_enum_tag,
2049 .tagged_union_enum_tag_trailing,
2050 .tagged_union_two,
2051 .tagged_union_two_trailing,
2052 => {
2022 // No need to worry about result location here, we're not creating a comptime block!2053 // No need to worry about result location here, we're not creating a comptime block!
2023 return expr(gz, scope, ri, node);2054 return expr(gz, scope, ri, node);
2024 },2055 },
...@@ -8390,11 +8421,17 @@ fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 {...@@ -8390,11 +8421,17 @@ fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 {
8390 return x;8421 return x;
8391}8422}
83928423
8424const ComptimeBlockInfo = struct {
8425 src_node: Ast.Node.Index,
8426 reason: std.zig.SimpleComptimeReason,
8427};
8428
8393fn identifier(8429fn identifier(
8394 gz: *GenZir,8430 gz: *GenZir,
8395 scope: *Scope,8431 scope: *Scope,
8396 ri: ResultInfo,8432 ri: ResultInfo,
8397 ident: Ast.Node.Index,8433 ident: Ast.Node.Index,
8434 force_comptime: ?ComptimeBlockInfo,
8398) InnerError!Zir.Inst.Ref {8435) InnerError!Zir.Inst.Ref {
8399 const astgen = gz.astgen;8436 const astgen = gz.astgen;
8400 const tree = astgen.tree;8437 const tree = astgen.tree;
...@@ -8413,6 +8450,7 @@ fn identifier(...@@ -8413,6 +8450,7 @@ fn identifier(
8413 }8450 }
84148451
8415 if (ident_name_raw.len >= 2) integer: {8452 if (ident_name_raw.len >= 2) integer: {
8453 // Keep in sync with logic in `comptimeExpr2`.
8416 const first_c = ident_name_raw[0];8454 const first_c = ident_name_raw[0];
8417 if (first_c == 'i' or first_c == 'u') {8455 if (first_c == 'i' or first_c == 'u') {
8418 const signedness: std.builtin.Signedness = switch (first_c == 'i') {8456 const signedness: std.builtin.Signedness = switch (first_c == 'i') {
...@@ -8447,8 +8485,31 @@ fn identifier(...@@ -8447,8 +8485,31 @@ fn identifier(
8447 }8485 }
8448 }8486 }
84498487
8450 // Local variables, including function parameters.8488 // Local variables, including function parameters, and container-level declarations.
8451 return localVarRef(gz, scope, ri, ident, ident_token);8489
8490 if (force_comptime) |fc| {
8491 // Mirrors the logic at the end of `comptimeExpr2`.
8492 const block_inst = try gz.makeBlockInst(.block_comptime, fc.src_node);
8493
8494 var comptime_gz = gz.makeSubBlock(scope);
8495 comptime_gz.is_comptime = true;
8496 defer comptime_gz.unstack();
8497
8498 const sub_ri: ResultInfo = .{
8499 .ctx = ri.ctx,
8500 .rl = .none, // no point providing a result type, it won't change anything
8501 };
8502 const block_result = try localVarRef(&comptime_gz, scope, sub_ri, ident, ident_token);
8503 assert(!comptime_gz.endsWithNoReturn());
8504 _ = try comptime_gz.addBreak(.break_inline, block_inst, block_result);
8505
8506 try comptime_gz.setBlockComptimeBody(block_inst, fc.reason);
8507 try gz.instructions.append(astgen.gpa, block_inst);
8508
8509 return rvalue(gz, ri, block_inst.toRef(), fc.src_node);
8510 } else {
8511 return localVarRef(gz, scope, ri, ident, ident_token);
8512 }
8452}8513}
84538514
8454fn localVarRef(8515fn localVarRef(