| ... | ... | @@ -113,6 +113,11 @@ type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, |
| 113 | 113 | /// `AnalUnit` multiple times. |
| 114 | 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 | 121 | const MaybeComptimeAlloc = struct { |
| 117 | 122 | /// The runtime index of the `alloc` instruction. |
| 118 | 123 | runtime_index: Value.RuntimeIndex, |
| ... | ... | @@ -5524,6 +5529,7 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 5524 | 5529 | .needed_comptime_reason = "eval branch quota must be comptime-known", |
| 5525 | 5530 | })); |
| 5526 | 5531 | sema.branch_quota = @max(sema.branch_quota, quota); |
| 5532 | sema.allow_memoize = false; |
| 5527 | 5533 | } |
| 5528 | 5534 | |
| 5529 | 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 | 6422 | } |
| 6417 | 6423 | |
| 6418 | 6424 | zcu.intern_pool.funcMaxStackAlignment(sema.func_index, alignment); |
| 6425 | sema.allow_memoize = false; |
| 6419 | 6426 | } |
| 6420 | 6427 | |
| 6421 | 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 | 6441 | .cau => return, // does nothing outside a function |
| 6435 | 6442 | }; |
| 6436 | 6443 | ip.funcSetCold(func, is_cold); |
| 6444 | sema.allow_memoize = false; |
| 6437 | 6445 | } |
| 6438 | 6446 | |
| 6439 | 6447 | fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| ... | ... | @@ -6445,6 +6453,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 6445 | 6453 | .cau => return, // does nothing outside a function |
| 6446 | 6454 | }; |
| 6447 | 6455 | ip.funcSetDisableInstrumentation(func); |
| 6456 | sema.allow_memoize = false; |
| 6448 | 6457 | } |
| 6449 | 6458 | |
| 6450 | 6459 | fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| ... | ... | @@ -7728,15 +7737,25 @@ fn analyzeCall( |
| 7728 | 7737 | // This `res2` is here instead of directly breaking from `res` due to a stage1 |
| 7729 | 7738 | // bug generating invalid LLVM IR. |
| 7730 | 7739 | const res2: Air.Inst.Ref = res2: { |
| 7731 | | if (should_memoize and is_comptime_call) { |
| 7732 | | if (zcu.intern_pool.getIfExists(.{ .memoized_call = .{ |
| 7733 | | .func = module_fn_index, |
| 7734 | | .arg_values = memoized_arg_values, |
| 7735 | | .result = .none, |
| 7736 | | } })) |memoized_call_index| { |
| 7737 | | const memoized_call = zcu.intern_pool.indexToKey(memoized_call_index).memoized_call; |
| 7738 | | break :res2 Air.internedToRef(memoized_call.result); |
| 7740 | memoize: { |
| 7741 | if (!should_memoize) break :memoize; |
| 7742 | if (!is_comptime_call) break :memoize; |
| 7743 | const memoized_call_index = ip.getIfExists(.{ |
| 7744 | .memoized_call = .{ |
| 7745 | .func = module_fn_index, |
| 7746 | .arg_values = memoized_arg_values, |
| 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 | 7761 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); |
| ... | ... | @@ -7774,6 +7793,17 @@ fn analyzeCall( |
| 7774 | 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 | 7807 | const result = result: { |
| 7778 | 7808 | sema.analyzeFnBody(&child_block, fn_info.body) catch |err| switch (err) { |
| 7779 | 7809 | error.ComptimeReturn => break :result inlining.comptime_result, |
| ... | ... | @@ -7793,11 +7823,12 @@ fn analyzeCall( |
| 7793 | 7823 | // a reference to `comptime_allocs` so is not stable across instances of `Sema`. |
| 7794 | 7824 | // TODO: check whether any external comptime memory was mutated by the |
| 7795 | 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 | 7827 | _ = try pt.intern(.{ .memoized_call = .{ |
| 7798 | 7828 | .func = module_fn_index, |
| 7799 | 7829 | .arg_values = memoized_arg_values, |
| 7800 | 7830 | .result = result_transformed, |
| 7831 | .branch_count = sema.branch_count - old_branch_count, |
| 7801 | 7832 | } }); |
| 7802 | 7833 | } |
| 7803 | 7834 | |