| ... | @@ -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. |
| 114 | dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{}, | 114 | dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .{}, |
| 115 | | 115 | |
| | 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`. |
| | 119 | allow_memoize: bool = true, |
| | 120 | |
| 116 | const MaybeComptimeAlloc = struct { | 121 | const 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 | } |
| 5528 | | 5534 | |
| 5529 | fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 5535 | fn 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 | } |
| 6417 | | 6423 | |
| 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 | } |
| 6420 | | 6427 | |
| 6421 | fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { | 6428 | fn 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 function | 6441 | .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 | } |
| 6438 | | 6446 | |
| 6439 | fn zirDisableInstrumentation(sema: *Sema) CompileError!void { | 6447 | fn 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 function | 6453 | .cau => return, // does nothing outside a function |
| 6446 | }; | 6454 | }; |
| 6447 | ip.funcSetDisableInstrumentation(func); | 6455 | ip.funcSetDisableInstrumentation(func); |
| | 6456 | sema.allow_memoize = false; |
| 6448 | } | 6457 | } |
| 6449 | | 6458 | |
| 6450 | fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { | 6459 | fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| ... | @@ -7728,15 +7737,25 @@ fn analyzeCall( | ... | @@ -7728,15 +7737,25 @@ fn analyzeCall( |
| 7728 | // This `res2` is here instead of directly breaking from `res` due to a stage1 | 7737 | // This `res2` is here instead of directly breaking from `res` due to a stage1 |
| 7729 | // bug generating invalid LLVM IR. | 7738 | // bug generating invalid LLVM IR. |
| 7730 | const res2: Air.Inst.Ref = res2: { | 7739 | const res2: Air.Inst.Ref = res2: { |
| 7731 | if (should_memoize and is_comptime_call) { | 7740 | memoize: { |
| 7732 | if (zcu.intern_pool.getIfExists(.{ .memoized_call = .{ | 7741 | if (!should_memoize) break :memoize; |
| 7733 | .func = module_fn_index, | 7742 | if (!is_comptime_call) break :memoize; |
| 7734 | .arg_values = memoized_arg_values, | 7743 | const memoized_call_index = ip.getIfExists(.{ |
| 7735 | .result = .none, | 7744 | .memoized_call = .{ |
| 7736 | } })) |memoized_call_index| { | 7745 | .func = module_fn_index, |
| 7737 | const memoized_call = zcu.intern_pool.indexToKey(memoized_call_index).memoized_call; | 7746 | .arg_values = memoized_arg_values, |
| 7738 | break :res2 Air.internedToRef(memoized_call.result); | 7747 | .result = undefined, // ignored by hash+eql |
| | 7748 | .branch_count = undefined, // ignored by hash+eql |
| | 7749 | }, |
| | 7750 | }) orelse break :memoize; |
| | 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; |
| 7739 | } | 7756 | } |
| | 7757 | sema.branch_count += memoized_call.branch_count; |
| | 7758 | break :res2 Air.internedToRef(memoized_call.result); |
| 7740 | } | 7759 | } |
| 7741 | | 7760 | |
| 7742 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); | 7761 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); |
| ... | @@ -7774,6 +7793,17 @@ fn analyzeCall( | ... | @@ -7774,6 +7793,17 @@ fn analyzeCall( |
| 7774 | child_block.error_return_trace_index = error_return_trace_index; | 7793 | child_block.error_return_trace_index = error_return_trace_index; |
| 7775 | } | 7794 | } |
| 7776 | | 7795 | |
| | 7796 | // We temporarily set `allow_memoize` to `true` to track this comptime call. |
| | 7797 | // It is restored after this call finishes analysis, so that a caller may |
| | 7798 | // know whether an in-progress call (containing this call) may be memoized. |
| | 7799 | const old_allow_memoize = sema.allow_memoize; |
| | 7800 | defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize; |
| | 7801 | sema.allow_memoize = true; |
| | 7802 | |
| | 7803 | // Store the current eval branch count so we can find out how many eval branches |
| | 7804 | // the comptime call caused. |
| | 7805 | const old_branch_count = sema.branch_count; |
| | 7806 | |
| 7777 | const result = result: { | 7807 | const result = result: { |
| 7778 | sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { | 7808 | sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { |
| 7779 | error.ComptimeReturn => break :result inlining.comptime_result, | 7809 | error.ComptimeReturn => break :result inlining.comptime_result, |
| ... | @@ -7793,11 +7823,12 @@ fn analyzeCall( | ... | @@ -7793,11 +7823,12 @@ fn analyzeCall( |
| 7793 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. | 7823 | // 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 | 7824 | // TODO: check whether any external comptime memory was mutated by the |
| 7795 | // comptime function call. If so, then do not memoize the call here. | 7825 | // comptime function call. If so, then do not memoize the call here. |
| 7796 | if (should_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) { | 7826 | if (should_memoize and sema.allow_memoize and !Value.fromInterned(result_interned).canMutateComptimeVarState(zcu)) { |
| 7797 | _ = try pt.intern(.{ .memoized_call = .{ | 7827 | _ = try pt.intern(.{ .memoized_call = .{ |
| 7798 | .func = module_fn_index, | 7828 | .func = module_fn_index, |
| 7799 | .arg_values = memoized_arg_values, | 7829 | .arg_values = memoized_arg_values, |
| 7800 | .result = result_transformed, | 7830 | .result = result_transformed, |
| | 7831 | .branch_count = sema.branch_count - old_branch_count, |
| 7801 | } }); | 7832 | } }); |
| 7802 | } | 7833 | } |
| 7803 | | 7834 | |