authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-21 05:28:24+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-21 05:28:24+01:00
log61919fe63d1eb7134a3c85fe0a4cf279744de3e9
treead8a93f55ed7c4cff101789aedea0b5cc930d0f6
parent16d74809d44d6bb8db1a32923ef8db43d956e24d
parenta99ad52b362d966f772f29ad14ae1714218bc033
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21135 from mlugg/incremental

incremental: more progress

18 files changed, 297 insertions(+), 132 deletions(-)

lib/compiler/aro/aro/Builtins/Builtin.zig+1-1
...@@ -5165,7 +5165,7 @@ const dafsa = [_]Node{...@@ -5165,7 +5165,7 @@ const dafsa = [_]Node{
5165 .{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },5165 .{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },
5166};5166};
5167pub const data = blk: {5167pub const data = blk: {
5168 @setEvalBranchQuota(3986);5168 @setEvalBranchQuota(30_000);
5169 break :blk [_]@This(){5169 break :blk [_]@This(){
5170 // _Block_object_assign5170 // _Block_object_assign
5171 .{ .tag = @enumFromInt(0), .properties = .{ .param_str = "vv*vC*iC", .header = .blocks, .attributes = .{ .lib_function_without_prefix = true } } },5171 .{ .tag = @enumFromInt(0), .properties = .{ .param_str = "vv*vC*iC", .header = .blocks, .attributes = .{ .lib_function_without_prefix = true } } },
lib/compiler/aro/aro/Parser.zig+2
...@@ -4802,6 +4802,7 @@ const CallExpr = union(enum) {...@@ -4802,6 +4802,7 @@ const CallExpr = union(enum) {
4802 }4802 }
48034803
4804 fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {4804 fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {
4805 @setEvalBranchQuota(2000);
4805 return switch (self) {4806 return switch (self) {
4806 .standard => true,4807 .standard => true,
4807 .builtin => |builtin| switch (builtin.tag) {4808 .builtin => |builtin| switch (builtin.tag) {
...@@ -4902,6 +4903,7 @@ const CallExpr = union(enum) {...@@ -4902,6 +4903,7 @@ const CallExpr = union(enum) {
4902 }4903 }
49034904
4904 fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {4905 fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {
4906 @setEvalBranchQuota(6000);
4905 return switch (self) {4907 return switch (self) {
4906 .standard => callable_ty.returnType(),4908 .standard => callable_ty.returnType(),
4907 .builtin => |builtin| switch (builtin.tag) {4909 .builtin => |builtin| switch (builtin.tag) {
lib/std/crypto/aes/soft.zig+2
...@@ -629,6 +629,8 @@ fn generateSbox(invert: bool) [256]u8 {...@@ -629,6 +629,8 @@ fn generateSbox(invert: bool) [256]u8 {
629629
630// Generate lookup tables.630// Generate lookup tables.
631fn generateTable(invert: bool) [4][256]u32 {631fn generateTable(invert: bool) [4][256]u32 {
632 @setEvalBranchQuota(50000);
633
632 var table: [4][256]u32 = undefined;634 var table: [4][256]u32 = undefined;
633635
634 for (generateSbox(invert), 0..) |value, index| {636 for (generateSbox(invert), 0..) |value, index| {
lib/std/crypto/blake2.zig+2-2
...@@ -786,7 +786,7 @@ test "blake2b384 streaming" {...@@ -786,7 +786,7 @@ test "blake2b384 streaming" {
786786
787test "comptime blake2b384" {787test "comptime blake2b384" {
788 comptime {788 comptime {
789 @setEvalBranchQuota(10000);789 @setEvalBranchQuota(20000);
790 var block = [_]u8{0} ** Blake2b384.block_length;790 var block = [_]u8{0} ** Blake2b384.block_length;
791 var out: [Blake2b384.digest_length]u8 = undefined;791 var out: [Blake2b384.digest_length]u8 = undefined;
792792
...@@ -878,7 +878,7 @@ test "blake2b512 keyed" {...@@ -878,7 +878,7 @@ test "blake2b512 keyed" {
878878
879test "comptime blake2b512" {879test "comptime blake2b512" {
880 comptime {880 comptime {
881 @setEvalBranchQuota(10000);881 @setEvalBranchQuota(12000);
882 var block = [_]u8{0} ** Blake2b512.block_length;882 var block = [_]u8{0} ** Blake2b512.block_length;
883 var out: [Blake2b512.digest_length]u8 = undefined;883 var out: [Blake2b512.digest_length]u8 = undefined;
884884
lib/std/crypto/pcurves/p384.zig+1-1
...@@ -393,7 +393,7 @@ pub const P384 = struct {...@@ -393,7 +393,7 @@ pub const P384 = struct {
393 }393 }
394394
395 const basePointPc = pc: {395 const basePointPc = pc: {
396 @setEvalBranchQuota(50000);396 @setEvalBranchQuota(70000);
397 break :pc precompute(P384.basePoint, 15);397 break :pc precompute(P384.basePoint, 15);
398 };398 };
399399
lib/std/enums.zig+1-1
...@@ -6,7 +6,7 @@ const testing = std.testing;...@@ -6,7 +6,7 @@ const testing = std.testing;
6const EnumField = std.builtin.Type.EnumField;6const EnumField = std.builtin.Type.EnumField;
77
8/// Increment this value when adding APIs that add single backwards branches.8/// Increment this value when adding APIs that add single backwards branches.
9const eval_branch_quota_cushion = 5;9const eval_branch_quota_cushion = 10;
1010
11/// Returns a struct with a field matching each unique named enum element.11/// Returns a struct with a field matching each unique named enum element.
12/// If the enum is extern and has multiple names for the same value, only12/// If the enum is extern and has multiple names for the same value, only
lib/std/hash/xxhash.zig+1-1
...@@ -890,7 +890,7 @@ test "xxhash32 smhasher" {...@@ -890,7 +890,7 @@ test "xxhash32 smhasher" {
890 }890 }
891 };891 };
892 try Test.do();892 try Test.do();
893 @setEvalBranchQuota(75000);893 @setEvalBranchQuota(85000);
894 comptime try Test.do();894 comptime try Test.do();
895}895}
896896
lib/std/math.zig+8-16
...@@ -749,31 +749,23 @@ test rotl {...@@ -749,31 +749,23 @@ test rotl {
749 try testing.expect(rotl(@Vector(1, u32), @Vector(1, u32){1 << 31}, @as(isize, -1))[0] == @as(u32, 1) << 30);749 try testing.expect(rotl(@Vector(1, u32), @Vector(1, u32){1 << 31}, @as(isize, -1))[0] == @as(u32, 1) << 30);
750}750}
751751
752/// Returns an unsigned int type that can hold the number of bits in T752/// Returns an unsigned int type that can hold the number of bits in T - 1.
753/// - 1. Suitable for 0-based bit indices of T.753/// Suitable for 0-based bit indices of T.
754pub fn Log2Int(comptime T: type) type {754pub fn Log2Int(comptime T: type) type {
755 // comptime ceil log2755 // comptime ceil log2
756 if (T == comptime_int) return comptime_int;756 if (T == comptime_int) return comptime_int;
757 comptime var count = 0;757 const bits: u16 = @typeInfo(T).Int.bits;
758 comptime var s = @typeInfo(T).Int.bits - 1;758 const log2_bits = 16 - @clz(bits - 1);
759 inline while (s != 0) : (s >>= 1) {759 return std.meta.Int(.unsigned, log2_bits);
760 count += 1;
761 }
762
763 return std.meta.Int(.unsigned, count);
764}760}
765761
766/// Returns an unsigned int type that can hold the number of bits in T.762/// Returns an unsigned int type that can hold the number of bits in T.
767pub fn Log2IntCeil(comptime T: type) type {763pub fn Log2IntCeil(comptime T: type) type {
768 // comptime ceil log2764 // comptime ceil log2
769 if (T == comptime_int) return comptime_int;765 if (T == comptime_int) return comptime_int;
770 comptime var count = 0;766 const bits: u16 = @typeInfo(T).Int.bits;
771 comptime var s = @typeInfo(T).Int.bits;767 const log2_bits = 16 - @clz(bits);
772 inline while (s != 0) : (s >>= 1) {768 return std.meta.Int(.unsigned, log2_bits);
773 count += 1;
774 }
775
776 return std.meta.Int(.unsigned, count);
777}769}
778770
779/// Returns the smallest integer type that can hold both from and to.771/// Returns the smallest integer type that can hold both from and to.
lib/std/math/hypot.zig+1
...@@ -114,6 +114,7 @@ test "hypot.precise" {...@@ -114,6 +114,7 @@ test "hypot.precise" {
114}114}
115115
116test "hypot.special" {116test "hypot.special" {
117 @setEvalBranchQuota(2000);
117 inline for (.{ f16, f32, f64, f128 }) |T| {118 inline for (.{ f16, f32, f64, f128 }) |T| {
118 try expect(math.isNan(hypot(nan(T), 0.0)));119 try expect(math.isNan(hypot(nan(T), 0.0)));
119 try expect(math.isNan(hypot(0.0, nan(T))));120 try expect(math.isNan(hypot(0.0, nan(T))));
lib/std/math/nextafter.zig+1-1
...@@ -144,7 +144,7 @@ test "int" {...@@ -144,7 +144,7 @@ test "int" {
144}144}
145145
146test "float" {146test "float" {
147 @setEvalBranchQuota(3000);147 @setEvalBranchQuota(4000);
148148
149 // normal -> normal149 // normal -> normal
150 try expect(nextAfter(f16, 0x1.234p0, 2.0) == 0x1.238p0);150 try expect(nextAfter(f16, 0x1.234p0, 2.0) == 0x1.238p0);
lib/std/unicode.zig+1
...@@ -535,6 +535,7 @@ fn testUtf16CountCodepoints() !void {...@@ -535,6 +535,7 @@ fn testUtf16CountCodepoints() !void {
535}535}
536536
537test "utf16 count codepoints" {537test "utf16 count codepoints" {
538 @setEvalBranchQuota(2000);
538 try testUtf16CountCodepoints();539 try testUtf16CountCodepoints();
539 try comptime testUtf16CountCodepoints();540 try comptime testUtf16CountCodepoints();
540}541}
lib/std/zig/AstGen.zig+107-30
...@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},...@@ -66,6 +66,10 @@ scratch: std.ArrayListUnmanaged(u32) = .{},
66/// of ZIR.66/// of ZIR.
67/// The key is the ref operand; the value is the ref instruction.67/// The key is the ref operand; the value is the ref instruction.
68ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},68ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
69/// Any information which should trigger invalidation of incremental compilation
70/// data should be used to update this hasher. The result is the final source
71/// hash of the enclosing declaration/etc.
72src_hasher: std.zig.SrcHasher,
6973
70const InnerError = error{ OutOfMemory, AnalysisFail };74const InnerError = error{ OutOfMemory, AnalysisFail };
7175
...@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -137,6 +141,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
137 .arena = arena.allocator(),141 .arena = arena.allocator(),
138 .tree = &tree,142 .tree = &tree,
139 .nodes_need_rl = &nodes_need_rl,143 .nodes_need_rl = &nodes_need_rl,
144 .src_hasher = undefined, // `structDeclInner` for the root struct will set this
140 };145 };
141 defer astgen.deinit(gpa);146 defer astgen.deinit(gpa);
142147
...@@ -1422,6 +1427,8 @@ fn fnProtoExpr(...@@ -1422,6 +1427,8 @@ fn fnProtoExpr(
1422 .is_extern = false,1427 .is_extern = false,
1423 .is_noinline = false,1428 .is_noinline = false,
1424 .noalias_bits = noalias_bits,1429 .noalias_bits = noalias_bits,
1430
1431 .proto_hash = undefined, // ignored for `body_gz == null`
1425 });1432 });
14261433
1427 _ = try block_scope.addBreak(.break_inline, block_inst, result);1434 _ = try block_scope.addBreak(.break_inline, block_inst, result);
...@@ -4007,6 +4014,13 @@ fn fnDecl(...@@ -4007,6 +4014,13 @@ fn fnDecl(
4007 const tree = astgen.tree;4014 const tree = astgen.tree;
4008 const token_tags = tree.tokens.items(.tag);4015 const token_tags = tree.tokens.items(.tag);
40094016
4017 const old_hasher = astgen.src_hasher;
4018 defer astgen.src_hasher = old_hasher;
4019 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4020 // We don't add the full source yet, because we also need the prototype hash!
4021 // The source slice is added towards the *end* of this function.
4022 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4023
4010 // missing function name already happened in scanDecls()4024 // missing function name already happened in scanDecls()
4011 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;4025 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
40124026
...@@ -4300,11 +4314,21 @@ fn fnDecl(...@@ -4300,11 +4314,21 @@ fn fnDecl(
4300 .is_extern = true,4314 .is_extern = true,
4301 .is_noinline = is_noinline,4315 .is_noinline = is_noinline,
4302 .noalias_bits = noalias_bits,4316 .noalias_bits = noalias_bits,
4317 .proto_hash = undefined, // ignored for `body_gz == null`
4303 });4318 });
4304 } else func: {4319 } else func: {
4305 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz4320 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz
4306 fn_gz.instructions_top = ret_gz.instructions.items.len;4321 fn_gz.instructions_top = ret_gz.instructions.items.len;
43074322
4323 // Construct the prototype hash.
4324 // Leave `astgen.src_hasher` unmodified; this will be used for hashing
4325 // the *whole* function declaration, including its body.
4326 var proto_hasher = astgen.src_hasher;
4327 const proto_node = tree.nodes.items(.data)[decl_node].lhs;
4328 proto_hasher.update(tree.getNodeSource(proto_node));
4329 var proto_hash: std.zig.SrcHash = undefined;
4330 proto_hasher.final(&proto_hash);
4331
4308 const prev_fn_block = astgen.fn_block;4332 const prev_fn_block = astgen.fn_block;
4309 const prev_fn_ret_ty = astgen.fn_ret_ty;4333 const prev_fn_ret_ty = astgen.fn_ret_ty;
4310 defer {4334 defer {
...@@ -4362,16 +4386,22 @@ fn fnDecl(...@@ -4362,16 +4386,22 @@ fn fnDecl(
4362 .is_extern = false,4386 .is_extern = false,
4363 .is_noinline = is_noinline,4387 .is_noinline = is_noinline,
4364 .noalias_bits = noalias_bits,4388 .noalias_bits = noalias_bits,
4389 .proto_hash = proto_hash,
4365 });4390 });
4366 };4391 };
43674392
4393 // *Now* we can incorporate the full source code into the hasher.
4394 astgen.src_hasher.update(tree.getNodeSource(decl_node));
4395
4368 // We add this at the end so that its instruction index marks the end range4396 // We add this at the end so that its instruction index marks the end range
4369 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.4397 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4370 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);4398 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
43714399
4400 var hash: std.zig.SrcHash = undefined;
4401 astgen.src_hasher.final(&hash);
4372 try setDeclaration(4402 try setDeclaration(
4373 decl_inst,4403 decl_inst,
4374 std.zig.hashSrc(tree.getNodeSource(decl_node)),4404 hash,
4375 .{ .named = fn_name_token },4405 .{ .named = fn_name_token },
4376 decl_gz.decl_line,4406 decl_gz.decl_line,
4377 is_pub,4407 is_pub,
...@@ -4395,6 +4425,12 @@ fn globalVarDecl(...@@ -4395,6 +4425,12 @@ fn globalVarDecl(
4395 const tree = astgen.tree;4425 const tree = astgen.tree;
4396 const token_tags = tree.tokens.items(.tag);4426 const token_tags = tree.tokens.items(.tag);
43974427
4428 const old_hasher = astgen.src_hasher;
4429 defer astgen.src_hasher = old_hasher;
4430 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4431 astgen.src_hasher.update(tree.getNodeSource(node));
4432 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4433
4398 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;4434 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
4399 // We do this at the beginning so that the instruction index marks the range start4435 // We do this at the beginning so that the instruction index marks the range start
4400 // of the top level declaration.4436 // of the top level declaration.
...@@ -4534,9 +4570,11 @@ fn globalVarDecl(...@@ -4534,9 +4570,11 @@ fn globalVarDecl(
4534 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);4570 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4535 }4571 }
45364572
4573 var hash: std.zig.SrcHash = undefined;
4574 astgen.src_hasher.final(&hash);
4537 try setDeclaration(4575 try setDeclaration(
4538 decl_inst,4576 decl_inst,
4539 std.zig.hashSrc(tree.getNodeSource(node)),4577 hash,
4540 .{ .named = name_token },4578 .{ .named = name_token },
4541 block_scope.decl_line,4579 block_scope.decl_line,
4542 is_pub,4580 is_pub,
...@@ -4562,6 +4600,12 @@ fn comptimeDecl(...@@ -4562,6 +4600,12 @@ fn comptimeDecl(
4562 const node_datas = tree.nodes.items(.data);4600 const node_datas = tree.nodes.items(.data);
4563 const body_node = node_datas[node].lhs;4601 const body_node = node_datas[node].lhs;
45644602
4603 const old_hasher = astgen.src_hasher;
4604 defer astgen.src_hasher = old_hasher;
4605 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4606 astgen.src_hasher.update(tree.getNodeSource(node));
4607 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4608
4565 // Up top so the ZIR instruction index marks the start range of this4609 // Up top so the ZIR instruction index marks the start range of this
4566 // top-level declaration.4610 // top-level declaration.
4567 const decl_inst = try gz.makeDeclaration(node);4611 const decl_inst = try gz.makeDeclaration(node);
...@@ -4584,9 +4628,11 @@ fn comptimeDecl(...@@ -4584,9 +4628,11 @@ fn comptimeDecl(
4584 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);4628 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
4585 }4629 }
45864630
4631 var hash: std.zig.SrcHash = undefined;
4632 astgen.src_hasher.final(&hash);
4587 try setDeclaration(4633 try setDeclaration(
4588 decl_inst,4634 decl_inst,
4589 std.zig.hashSrc(tree.getNodeSource(node)),4635 hash,
4590 .@"comptime",4636 .@"comptime",
4591 decl_block.decl_line,4637 decl_block.decl_line,
4592 false,4638 false,
...@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(...@@ -4607,6 +4653,12 @@ fn usingnamespaceDecl(
4607 const tree = astgen.tree;4653 const tree = astgen.tree;
4608 const node_datas = tree.nodes.items(.data);4654 const node_datas = tree.nodes.items(.data);
46094655
4656 const old_hasher = astgen.src_hasher;
4657 defer astgen.src_hasher = old_hasher;
4658 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4659 astgen.src_hasher.update(tree.getNodeSource(node));
4660 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4661
4610 const type_expr = node_datas[node].lhs;4662 const type_expr = node_datas[node].lhs;
4611 const is_pub = blk: {4663 const is_pub = blk: {
4612 const main_tokens = tree.nodes.items(.main_token);4664 const main_tokens = tree.nodes.items(.main_token);
...@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(...@@ -4634,9 +4686,11 @@ fn usingnamespaceDecl(
4634 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);4686 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4635 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);4687 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
46364688
4689 var hash: std.zig.SrcHash = undefined;
4690 astgen.src_hasher.final(&hash);
4637 try setDeclaration(4691 try setDeclaration(
4638 decl_inst,4692 decl_inst,
4639 std.zig.hashSrc(tree.getNodeSource(node)),4693 hash,
4640 .@"usingnamespace",4694 .@"usingnamespace",
4641 decl_block.decl_line,4695 decl_block.decl_line,
4642 is_pub,4696 is_pub,
...@@ -4658,6 +4712,12 @@ fn testDecl(...@@ -4658,6 +4712,12 @@ fn testDecl(
4658 const node_datas = tree.nodes.items(.data);4712 const node_datas = tree.nodes.items(.data);
4659 const body_node = node_datas[node].rhs;4713 const body_node = node_datas[node].rhs;
46604714
4715 const old_hasher = astgen.src_hasher;
4716 defer astgen.src_hasher = old_hasher;
4717 astgen.src_hasher = std.zig.SrcHasher.init(.{});
4718 astgen.src_hasher.update(tree.getNodeSource(node));
4719 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
4720
4661 // Up top so the ZIR instruction index marks the start range of this4721 // Up top so the ZIR instruction index marks the start range of this
4662 // top-level declaration.4722 // top-level declaration.
4663 const decl_inst = try gz.makeDeclaration(node);4723 const decl_inst = try gz.makeDeclaration(node);
...@@ -4819,13 +4879,18 @@ fn testDecl(...@@ -4819,13 +4879,18 @@ fn testDecl(
4819 .is_extern = false,4879 .is_extern = false,
4820 .is_noinline = false,4880 .is_noinline = false,
4821 .noalias_bits = 0,4881 .noalias_bits = 0,
4882
4883 // Tests don't have a prototype that needs hashing
4884 .proto_hash = .{0} ** 16,
4822 });4885 });
48234886
4824 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);4887 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
48254888
4889 var hash: std.zig.SrcHash = undefined;
4890 astgen.src_hasher.final(&hash);
4826 try setDeclaration(4891 try setDeclaration(
4827 decl_inst,4892 decl_inst,
4828 std.zig.hashSrc(tree.getNodeSource(node)),4893 hash,
4829 test_name,4894 test_name,
4830 decl_block.decl_line,4895 decl_block.decl_line,
4831 false,4896 false,
...@@ -4983,10 +5048,12 @@ fn structDeclInner(...@@ -4983,10 +5048,12 @@ fn structDeclInner(
4983 }5048 }
4984 };5049 };
49855050
4986 var fields_hasher = std.zig.SrcHasher.init(.{});5051 const old_hasher = astgen.src_hasher;
4987 fields_hasher.update(@tagName(layout));5052 defer astgen.src_hasher = old_hasher;
5053 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5054 astgen.src_hasher.update(@tagName(layout));
4988 if (backing_int_node != 0) {5055 if (backing_int_node != 0) {
4989 fields_hasher.update(tree.getNodeSource(backing_int_node));5056 astgen.src_hasher.update(tree.getNodeSource(backing_int_node));
4990 }5057 }
49915058
4992 var sfba = std.heap.stackFallback(256, astgen.arena);5059 var sfba = std.heap.stackFallback(256, astgen.arena);
...@@ -5009,7 +5076,7 @@ fn structDeclInner(...@@ -5009,7 +5076,7 @@ fn structDeclInner(
5009 .field => |field| field,5076 .field => |field| field,
5010 };5077 };
50115078
5012 fields_hasher.update(tree.getNodeSource(member_node));5079 astgen.src_hasher.update(tree.getNodeSource(member_node));
50135080
5014 if (!is_tuple) {5081 if (!is_tuple) {
5015 const field_name = try astgen.identAsString(member.ast.main_token);5082 const field_name = try astgen.identAsString(member.ast.main_token);
...@@ -5139,7 +5206,7 @@ fn structDeclInner(...@@ -5139,7 +5206,7 @@ fn structDeclInner(
5139 }5206 }
51405207
5141 var fields_hash: std.zig.SrcHash = undefined;5208 var fields_hash: std.zig.SrcHash = undefined;
5142 fields_hasher.final(&fields_hash);5209 astgen.src_hasher.final(&fields_hash);
51435210
5144 try gz.setStruct(decl_inst, .{5211 try gz.setStruct(decl_inst, .{
5145 .src_node = node,5212 .src_node = node,
...@@ -5240,11 +5307,13 @@ fn unionDeclInner(...@@ -5240,11 +5307,13 @@ fn unionDeclInner(
5240 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);5307 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
5241 defer wip_members.deinit();5308 defer wip_members.deinit();
52425309
5243 var fields_hasher = std.zig.SrcHasher.init(.{});5310 const old_hasher = astgen.src_hasher;
5244 fields_hasher.update(@tagName(layout));5311 defer astgen.src_hasher = old_hasher;
5245 fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)});5312 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5313 astgen.src_hasher.update(@tagName(layout));
5314 astgen.src_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
5246 if (arg_node != 0) {5315 if (arg_node != 0) {
5247 fields_hasher.update(astgen.tree.getNodeSource(arg_node));5316 astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
5248 }5317 }
52495318
5250 var sfba = std.heap.stackFallback(256, astgen.arena);5319 var sfba = std.heap.stackFallback(256, astgen.arena);
...@@ -5261,7 +5330,7 @@ fn unionDeclInner(...@@ -5261,7 +5330,7 @@ fn unionDeclInner(
5261 .decl => continue,5330 .decl => continue,
5262 .field => |field| field,5331 .field => |field| field,
5263 };5332 };
5264 fields_hasher.update(astgen.tree.getNodeSource(member_node));5333 astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
5265 member.convertToNonTupleLike(astgen.tree.nodes);5334 member.convertToNonTupleLike(astgen.tree.nodes);
5266 if (member.ast.tuple_like) {5335 if (member.ast.tuple_like) {
5267 return astgen.failTok(member.ast.main_token, "union field missing name", .{});5336 return astgen.failTok(member.ast.main_token, "union field missing name", .{});
...@@ -5364,7 +5433,7 @@ fn unionDeclInner(...@@ -5364,7 +5433,7 @@ fn unionDeclInner(
5364 }5433 }
53655434
5366 var fields_hash: std.zig.SrcHash = undefined;5435 var fields_hash: std.zig.SrcHash = undefined;
5367 fields_hasher.final(&fields_hash);5436 astgen.src_hasher.final(&fields_hash);
53685437
5369 if (!block_scope.isEmpty()) {5438 if (!block_scope.isEmpty()) {
5370 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);5439 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
...@@ -5578,11 +5647,13 @@ fn containerDecl(...@@ -5578,11 +5647,13 @@ fn containerDecl(
5578 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);5647 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
5579 defer wip_members.deinit();5648 defer wip_members.deinit();
55805649
5581 var fields_hasher = std.zig.SrcHasher.init(.{});5650 const old_hasher = astgen.src_hasher;
5651 defer astgen.src_hasher = old_hasher;
5652 astgen.src_hasher = std.zig.SrcHasher.init(.{});
5582 if (container_decl.ast.arg != 0) {5653 if (container_decl.ast.arg != 0) {
5583 fields_hasher.update(tree.getNodeSource(container_decl.ast.arg));5654 astgen.src_hasher.update(tree.getNodeSource(container_decl.ast.arg));
5584 }5655 }
5585 fields_hasher.update(&.{@intFromBool(nonexhaustive)});5656 astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)});
55865657
5587 var sfba = std.heap.stackFallback(256, astgen.arena);5658 var sfba = std.heap.stackFallback(256, astgen.arena);
5588 const sfba_allocator = sfba.get();5659 const sfba_allocator = sfba.get();
...@@ -5596,7 +5667,7 @@ fn containerDecl(...@@ -5596,7 +5667,7 @@ fn containerDecl(
5596 for (container_decl.ast.members) |member_node| {5667 for (container_decl.ast.members) |member_node| {
5597 if (member_node == counts.nonexhaustive_node)5668 if (member_node == counts.nonexhaustive_node)
5598 continue;5669 continue;
5599 fields_hasher.update(tree.getNodeSource(member_node));5670 astgen.src_hasher.update(tree.getNodeSource(member_node));
5600 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5671 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5601 .decl => continue,5672 .decl => continue,
5602 .field => |field| field,5673 .field => |field| field,
...@@ -5676,7 +5747,7 @@ fn containerDecl(...@@ -5676,7 +5747,7 @@ fn containerDecl(
5676 }5747 }
56775748
5678 var fields_hash: std.zig.SrcHash = undefined;5749 var fields_hash: std.zig.SrcHash = undefined;
5679 fields_hasher.final(&fields_hash);5750 astgen.src_hasher.final(&fields_hash);
56805751
5681 const body = block_scope.instructionsSlice();5752 const body = block_scope.instructionsSlice();
5682 const body_len = astgen.countBodyLenAfterFixups(body);5753 const body_len = astgen.countBodyLenAfterFixups(body);
...@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(...@@ -8478,6 +8549,10 @@ fn tunnelThroughClosure(
8478 });8549 });
8479 }8550 }
84808551
8552 // Incorporate the capture index into the source hash, so that changes in
8553 // the order of captures cause suitable re-analysis.
8554 astgen.src_hasher.update(std.mem.asBytes(&cur_capture_index));
8555
8481 // Add an instruction to get the value from the closure.8556 // Add an instruction to get the value from the closure.
8482 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);8557 return gz.addExtendedNodeSmall(.closure_get, inner_ref_node, cur_capture_index);
8483}8558}
...@@ -9306,6 +9381,13 @@ fn builtinCall(...@@ -9306,6 +9381,13 @@ fn builtinCall(
9306 },9381 },
93079382
9308 .src => {9383 .src => {
9384 // Incorporate the source location into the source hash, so that
9385 // changes in the source location of `@src()` result in re-analysis.
9386 astgen.src_hasher.update(
9387 std.mem.asBytes(&astgen.source_line) ++
9388 std.mem.asBytes(&astgen.source_column),
9389 );
9390
9309 const token_starts = tree.tokens.items(.start);9391 const token_starts = tree.tokens.items(.start);
9310 const node_start = token_starts[tree.firstToken(node)];9392 const node_start = token_starts[tree.firstToken(node)];
9311 astgen.advanceSourceCursor(node_start);9393 astgen.advanceSourceCursor(node_start);
...@@ -12122,6 +12204,9 @@ const GenZir = struct {...@@ -12122,6 +12204,9 @@ const GenZir = struct {
12122 is_test: bool,12204 is_test: bool,
12123 is_extern: bool,12205 is_extern: bool,
12124 is_noinline: bool,12206 is_noinline: bool,
12207
12208 /// Ignored if `body_gz == null`.
12209 proto_hash: std.zig.SrcHash,
12125 }) !Zir.Inst.Ref {12210 }) !Zir.Inst.Ref {
12126 assert(args.src_node != 0);12211 assert(args.src_node != 0);
12127 const astgen = gz.astgen;12212 const astgen = gz.astgen;
...@@ -12150,15 +12235,7 @@ const GenZir = struct {...@@ -12150,15 +12235,7 @@ const GenZir = struct {
1215012235
12151 const columns = args.lbrace_column | (rbrace_column << 16);12236 const columns = args.lbrace_column | (rbrace_column << 16);
1215212237
12153 const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {12238 const proto_hash_arr: [4]u32 = @bitCast(args.proto_hash);
12154 .fn_decl => sig_hash: {
12155 const proto_node = node_datas[fn_decl].lhs;
12156 break :sig_hash std.zig.hashSrc(tree.getNodeSource(proto_node));
12157 },
12158 .test_decl => std.zig.hashSrc(""), // tests don't have a prototype
12159 else => unreachable,
12160 };
12161 const proto_hash_arr: [4]u32 = @bitCast(proto_hash);
1216212239
12163 src_locs_and_hash_buffer = .{12240 src_locs_and_hash_buffer = .{
12164 args.lbrace_line,12241 args.lbrace_line,
src/InternPool.zig+4
...@@ -2391,6 +2391,7 @@ pub const Key = union(enum) {...@@ -2391,6 +2391,7 @@ pub const Key = union(enum) {
2391 func: Index,2391 func: Index,
2392 arg_values: []const Index,2392 arg_values: []const Index,
2393 result: Index,2393 result: Index,
2394 branch_count: u32,
2394 };2395 };
23952396
2396 pub fn hash32(key: Key, ip: *const InternPool) u32 {2397 pub fn hash32(key: Key, ip: *const InternPool) u32 {
...@@ -6157,6 +6158,7 @@ pub const MemoizedCall = struct {...@@ -6157,6 +6158,7 @@ pub const MemoizedCall = struct {
6157 func: Index,6158 func: Index,
6158 args_len: u32,6159 args_len: u32,
6159 result: Index,6160 result: Index,
6161 branch_count: u32,
6160};6162};
61616163
6162pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {6164pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
...@@ -6785,6 +6787,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6785,6 +6787,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6785 .func = extra.data.func,6787 .func = extra.data.func,
6786 .arg_values = @ptrCast(extra_list.view().items(.@"0")[extra.end..][0..extra.data.args_len]),6788 .arg_values = @ptrCast(extra_list.view().items(.@"0")[extra.end..][0..extra.data.args_len]),
6787 .result = extra.data.result,6789 .result = extra.data.result,
6790 .branch_count = extra.data.branch_count,
6788 } };6791 } };
6789 },6792 },
6790 };6793 };
...@@ -7955,6 +7958,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -7955,6 +7958,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
7955 .func = memoized_call.func,7958 .func = memoized_call.func,
7956 .args_len = @intCast(memoized_call.arg_values.len),7959 .args_len = @intCast(memoized_call.arg_values.len),
7957 .result = memoized_call.result,7960 .result = memoized_call.result,
7961 .branch_count = memoized_call.branch_count,
7958 }),7962 }),
7959 });7963 });
7960 extra.appendSliceAssumeCapacity(.{@ptrCast(memoized_call.arg_values)});7964 extra.appendSliceAssumeCapacity(.{@ptrCast(memoized_call.arg_values)});
src/Sema.zig+110-78
...@@ -113,6 +113,11 @@ type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},...@@ -113,6 +113,11 @@ type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
113/// `AnalUnit` multiple times.113/// `AnalUnit` multiple times.
114dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{},114dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{},
115115
116/// Whether memoization of this call is permitted. Operations with side effects global
117/// to the `Sema`, such as `@setEvalBranchQuota`, set this to `false`. It is observed
118/// by `analyzeCall`.
119allow_memoize: bool = true,
120
116const MaybeComptimeAlloc = struct {121const MaybeComptimeAlloc = struct {
117 /// The runtime index of the `alloc` instruction.122 /// The runtime index of the `alloc` instruction.
118 runtime_index: Value.RuntimeIndex,123 runtime_index: Value.RuntimeIndex,
...@@ -5524,6 +5529,7 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -5524,6 +5529,7 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
5524 .needed_comptime_reason = "eval branch quota must be comptime-known",5529 .needed_comptime_reason = "eval branch quota must be comptime-known",
5525 }));5530 }));
5526 sema.branch_quota = @max(sema.branch_quota, quota);5531 sema.branch_quota = @max(sema.branch_quota, quota);
5532 sema.allow_memoize = false;
5527}5533}
55285534
5529fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5535fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
...@@ -6416,6 +6422,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst...@@ -6416,6 +6422,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
6416 }6422 }
64176423
6418 zcu.intern_pool.funcMaxStackAlignment(sema.func_index, alignment);6424 zcu.intern_pool.funcMaxStackAlignment(sema.func_index, alignment);
6425 sema.allow_memoize = false;
6419}6426}
64206427
6421fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {6428fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
...@@ -6434,6 +6441,7 @@ fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)...@@ -6434,6 +6441,7 @@ fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
6434 .cau => return, // does nothing outside a function6441 .cau => return, // does nothing outside a function
6435 };6442 };
6436 ip.funcSetCold(func, is_cold);6443 ip.funcSetCold(func, is_cold);
6444 sema.allow_memoize = false;
6437}6445}
64386446
6439fn zirDisableInstrumentation(sema: *Sema) CompileError!void {6447fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
...@@ -6445,6 +6453,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {...@@ -6445,6 +6453,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
6445 .cau => return, // does nothing outside a function6453 .cau => return, // does nothing outside a function
6446 };6454 };
6447 ip.funcSetDisableInstrumentation(func);6455 ip.funcSetDisableInstrumentation(func);
6456 sema.allow_memoize = false;
6448}6457}
64496458
6450fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {6459fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
...@@ -7589,6 +7598,9 @@ fn analyzeCall(...@@ -7589,6 +7598,9 @@ fn analyzeCall(
75897598
7590 const module_fn = zcu.funcInfo(module_fn_index);7599 const module_fn = zcu.funcInfo(module_fn_index);
75917600
7601 // The call site definitely depends on the function's signature.
7602 try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst });
7603
7592 // This is not a function instance, so the function's `Nav` has a7604 // This is not a function instance, so the function's `Nav` has a
7593 // `Cau` -- we don't need to check `generic_owner`.7605 // `Cau` -- we don't need to check `generic_owner`.
7594 const fn_nav = ip.getNav(module_fn.owner_nav);7606 const fn_nav = ip.getNav(module_fn.owner_nav);
...@@ -7725,101 +7737,121 @@ fn analyzeCall(...@@ -7725,101 +7737,121 @@ fn analyzeCall(
7725 } }));7737 } }));
7726 }7738 }
77277739
7728 // This `res2` is here instead of directly breaking from `res` due to a stage17740 memoize: {
7729 // bug generating invalid LLVM IR.7741 if (!should_memoize) break :memoize;
7730 const res2: Air.Inst.Ref = res2: {7742 if (!is_comptime_call) break :memoize;
7731 if (should_memoize and is_comptime_call) {7743 const memoized_call_index = ip.getIfExists(.{
7732 if (zcu.intern_pool.getIfExists(.{ .memoized_call = .{7744 .memoized_call = .{
7733 .func = module_fn_index,7745 .func = module_fn_index,
7734 .arg_values = memoized_arg_values,7746 .arg_values = memoized_arg_values,
7735 .result = .none,7747 .result = undefined, // ignored by hash+eql
7736 } })) |memoized_call_index| {7748 .branch_count = undefined, // ignored by hash+eql
7737 const memoized_call = zcu.intern_pool.indexToKey(memoized_call_index).memoized_call;7749 },
7738 break :res2 Air.internedToRef(memoized_call.result);7750 }) orelse break :memoize;
7739 }7751 const memoized_call = ip.indexToKey(memoized_call_index).memoized_call;
7752 if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) {
7753 // Let the call play out se we get the correct source location for the
7754 // "evaluation exceeded X backwards branches" error.
7755 break :memoize;
7740 }7756 }
7757 sema.branch_count += memoized_call.branch_count;
7758 break :res Air.internedToRef(memoized_call.result);
7759 }
77417760
7742 new_fn_info.return_type = sema.fn_ret_ty.toIntern();7761 // Since we're doing an inline call, we depend on the source code of the whole
7743 if (!is_comptime_call and !block.is_typeof) {7762 // function declaration.
7744 const zir_tags = sema.code.instructions.items(.tag);7763 try sema.declareDependency(.{ .src_hash = fn_cau.zir_index });
7745 for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
7746 .param, .param_comptime => {
7747 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok;
7748 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
7749 const param_name = sema.code.nullTerminatedString(extra.data.name);
7750 const inst = sema.inst_map.get(param).?;
77517764
7752 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);7765 new_fn_info.return_type = sema.fn_ret_ty.toIntern();
7753 },7766 if (!is_comptime_call and !block.is_typeof) {
7754 .param_anytype, .param_anytype_comptime => {7767 const zir_tags = sema.code.instructions.items(.tag);
7755 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;7768 for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) {
7756 const param_name = inst_data.get(sema.code);7769 .param, .param_comptime => {
7757 const inst = sema.inst_map.get(param).?;7770 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].pl_tok;
7771 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
7772 const param_name = sema.code.nullTerminatedString(extra.data.name);
7773 const inst = sema.inst_map.get(param).?;
7774
7775 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
7776 },
7777 .param_anytype, .param_anytype_comptime => {
7778 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok;
7779 const param_name = inst_data.get(sema.code);
7780 const inst = sema.inst_map.get(param).?;
77587781
7759 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);7782 try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name);
7760 },7783 },
7761 else => continue,7784 else => continue,
7762 };7785 };
7763 }7786 }
77647787
7765 if (is_comptime_call and ensure_result_used) {7788 if (is_comptime_call and ensure_result_used) {
7766 try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src);7789 try sema.ensureResultUsed(block, sema.fn_ret_ty, call_src);
7767 }7790 }
77687791
7769 if (is_comptime_call or block.is_typeof) {7792 if (is_comptime_call or block.is_typeof) {
7770 // Save the error trace as our first action in the function7793 // Save the error trace as our first action in the function
7771 // to match the behavior of runtime function calls.7794 // to match the behavior of runtime function calls.
7772 const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);7795 const error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block);
7773 sema.error_return_trace_index_on_fn_entry = error_return_trace_index;7796 sema.error_return_trace_index_on_fn_entry = error_return_trace_index;
7774 child_block.error_return_trace_index = error_return_trace_index;7797 child_block.error_return_trace_index = error_return_trace_index;
7775 }7798 }
77767799
7777 const result = result: {7800 // We temporarily set `allow_memoize` to `true` to track this comptime call.
7778 sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) {7801 // It is restored after this call finishes analysis, so that a caller may
7779 error.ComptimeReturn => break :result inlining.comptime_result,7802 // know whether an in-progress call (containing this call) may be memoized.
7780 else => |e| return e,7803 const old_allow_memoize = sema.allow_memoize;
7781 };7804 defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize;
7782 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);7805 sema.allow_memoize = true;
7806
7807 // Store the current eval branch count so we can find out how many eval branches
7808 // the comptime call caused.
7809 const old_branch_count = sema.branch_count;
7810
7811 const result = result: {
7812 sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) {
7813 error.ComptimeReturn => break :result inlining.comptime_result,
7814 else => |e| return e,
7783 };7815 };
7816 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, merges, need_debug_scope);
7817 };
77847818
7785 if (is_comptime_call) {7819 if (is_comptime_call) {
7786 const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined);7820 const result_val = try sema.resolveConstValue(block, LazySrcLoc.unneeded, result, undefined);
7787 const result_interned = result_val.toIntern();7821 const result_interned = result_val.toIntern();
7788
7789 // Transform ad-hoc inferred error set types into concrete error sets.
7790 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
7791
7792 // If the result can mutate comptime vars, we must not memoize it, as it contains
7793 // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
7794 // TODO: check whether any external comptime memory was mutated by the
7795 // comptime function call. If so, then do not memoize the call here.
7796 if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) {
7797 _ = try pt.intern(.{ .memoized_call = .{
7798 .func = module_fn_index,
7799 .arg_values = memoized_arg_values,
7800 .result = result_transformed,
7801 } });
7802 }
78037822
7804 break :res2 Air.internedToRef(result_transformed);7823 // Transform ad-hoc inferred error set types into concrete error sets.
7805 }7824 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_interned);
78067825
7807 if (try sema.resolveValue(result)) |result_val| {7826 // If the result can mutate comptime vars, we must not memoize it, as it contains
7808 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());7827 // a reference to `comptime_allocs` so is not stable across instances of `Sema`.
7809 break :res2 Air.internedToRef(result_transformed);7828 // TODO: check whether any external comptime memory was mutated by the
7829 // comptime function call. If so, then do not memoize the call here.
7830 if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) {
7831 _ = try pt.intern(.{ .memoized_call = .{
7832 .func = module_fn_index,
7833 .arg_values = memoized_arg_values,
7834 .result = result_transformed,
7835 .branch_count = sema.branch_count - old_branch_count,
7836 } });
7810 }7837 }
78117838
7812 const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());7839 break :res Air.internedToRef(result_transformed);
7813 if (new_ty != .none) {7840 }
7814 // TODO: mutate in place the previous instruction if possible
7815 // rather than adding a bitcast instruction.
7816 break :res2 try block.addBitCast(Type.fromInterned(new_ty), result);
7817 }
78187841
7819 break :res2 result;7842 if (try sema.resolveValue(result)) |result_val| {
7820 };7843 const result_transformed = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
7844 break :res Air.internedToRef(result_transformed);
7845 }
7846
7847 const new_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result).toIntern());
7848 if (new_ty != .none) {
7849 // TODO: mutate in place the previous instruction if possible
7850 // rather than adding a bitcast instruction.
7851 break :res try block.addBitCast(Type.fromInterned(new_ty), result);
7852 }
78217853
7822 break :res res2;7854 break :res result;
7823 } else res: {7855 } else res: {
7824 assert(!func_ty_info.is_generic);7856 assert(!func_ty_info.is_generic);
78257857
src/register_manager.zig+2
...@@ -93,6 +93,8 @@ pub fn RegisterManager(...@@ -93,6 +93,8 @@ pub fn RegisterManager(
93 comptime set: []const Register,93 comptime set: []const Register,
94 reg: Register,94 reg: Register,
95 ) ?std.math.IntFittingRange(0, set.len - 1) {95 ) ?std.math.IntFittingRange(0, set.len - 1) {
96 @setEvalBranchQuota(3000);
97
96 const Id = @TypeOf(reg.id());98 const Id = @TypeOf(reg.id());
97 comptime var min_id: Id = std.math.maxInt(Id);99 comptime var min_id: Id = std.math.maxInt(Id);
98 comptime var max_id: Id = std.math.minInt(Id);100 comptime var max_id: Id = std.math.minInt(Id);
test/incremental/delete_comptime_decls+1-1
...@@ -31,7 +31,7 @@ pub fn main() void {}...@@ -31,7 +31,7 @@ pub fn main() void {}
31comptime {31comptime {
32 const x: [*c]u8 = null;32 const x: [*c]u8 = null;
33 var runtime_len: usize = undefined;33 var runtime_len: usize = undefined;
34 runtime_len = 0;34 runtime_len = 0;
35 const y = x[0..runtime_len];35 const y = x[0..runtime_len];
36 _ = y;36 _ = y;
37}37}
test/incremental/modify_inline_fn created+23
...@@ -0,0 +1,23 @@
1#target=x86_64-linux
2#update=initial version
3#file=main.zig
4const std = @import("std");
5pub fn main() !void {
6 const str = getStr();
7 try std.io.getStdOut().writeAll(str);
8}
9inline fn getStr() []const u8 {
10 return "foo\n";
11}
12#expect_stdout="foo\n"
13#update=change the string
14#file=main.zig
15const std = @import("std");
16pub fn main() !void {
17 const str = getStr();
18 try std.io.getStdOut().writeAll(str);
19}
20inline fn getStr() []const u8 {
21 return "bar\n";
22}
23#expect_stdout="bar\n"
test/incremental/move_src created+29
...@@ -0,0 +1,29 @@
1#target=x86_64-linux
2#update=initial version
3#file=main.zig
4const std = @import("std");
5pub fn main() !void {
6 try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
7}
8fn foo() u32 {
9 return @src().line;
10}
11fn bar() u32 {
12 return 123;
13}
14#expect_stdout="6 123\n"
15
16#update=add newline
17#file=main.zig
18const std = @import("std");
19pub fn main() !void {
20 try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
21}
22
23fn foo() u32 {
24 return @src().line;
25}
26fn bar() u32 {
27 return 123;
28}
29#expect_stdout="7 123\n"