| author | |
| committer | |
| log | 638f93ebdceb860974aae54b6f8c2c9f52157305 |
| tree | 9197ddee7f48b05a2f77ac6f46018ab0299c26ae |
| parent | aa0906e9aaaf36bc928b5502bdb34e7a0409b2c0 |
`@setEvalBranchQuota` can be called before the comptime/inline call
stack is created.
For example:
```zig
@setEvalBranchQuota(100);
comptime {
while (true) {}
}
```
Here we need to set the branch_quota before the comptime block creates a
scope for the branch_count.5 files changed, 76 insertions(+), 5 deletions(-)
src/Module.zig+21-4| ... | @@ -765,6 +765,8 @@ pub const Scope = struct { | ... | @@ -765,6 +765,8 @@ pub const Scope = struct { |
| 765 | label: ?Label = null, | 765 | label: ?Label = null, |
| 766 | inlining: ?*Inlining, | 766 | inlining: ?*Inlining, |
| 767 | is_comptime: bool, | 767 | is_comptime: bool, |
| 768 | /// Shared to sub-blocks. | ||
| 769 | branch_quota: *u32, | ||
| 768 | 770 | ||
| 769 | pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst); | 771 | pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst); |
| 770 | 772 | ||
| ... | @@ -792,8 +794,7 @@ pub const Scope = struct { | ... | @@ -792,8 +794,7 @@ pub const Scope = struct { |
| 792 | 794 | ||
| 793 | pub const Shared = struct { | 795 | pub const Shared = struct { |
| 794 | caller: ?*Fn, | 796 | caller: ?*Fn, |
| 795 | branch_count: u64, | 797 | branch_count: u32, |
| 796 | branch_quota: u64, | ||
| 797 | }; | 798 | }; |
| 798 | }; | 799 | }; |
| 799 | 800 | ||
| ... | @@ -1104,6 +1105,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1104,6 +1105,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1104 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1105 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1105 | defer inst_table.deinit(); | 1106 | defer inst_table.deinit(); |
| 1106 | 1107 | ||
| 1108 | var branch_quota: u32 = 1000; | ||
| 1109 | |||
| 1107 | var block_scope: Scope.Block = .{ | 1110 | var block_scope: Scope.Block = .{ |
| 1108 | .parent = null, | 1111 | .parent = null, |
| 1109 | .inst_table = &inst_table, | 1112 | .inst_table = &inst_table, |
| ... | @@ -1113,6 +1116,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1113,6 +1116,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1113 | .arena = &decl_arena.allocator, | 1116 | .arena = &decl_arena.allocator, |
| 1114 | .inlining = null, | 1117 | .inlining = null, |
| 1115 | .is_comptime = false, | 1118 | .is_comptime = false, |
| 1119 | .branch_quota = &branch_quota, | ||
| 1116 | }; | 1120 | }; |
| 1117 | defer block_scope.instructions.deinit(self.gpa); | 1121 | defer block_scope.instructions.deinit(self.gpa); |
| 1118 | 1122 | ||
| ... | @@ -1297,6 +1301,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1297,6 +1301,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1297 | var decl_inst_table = Scope.Block.InstTable.init(self.gpa); | 1301 | var decl_inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1298 | defer decl_inst_table.deinit(); | 1302 | defer decl_inst_table.deinit(); |
| 1299 | 1303 | ||
| 1304 | var branch_quota: u32 = 1000; | ||
| 1305 | |||
| 1300 | var block_scope: Scope.Block = .{ | 1306 | var block_scope: Scope.Block = .{ |
| 1301 | .parent = null, | 1307 | .parent = null, |
| 1302 | .inst_table = &decl_inst_table, | 1308 | .inst_table = &decl_inst_table, |
| ... | @@ -1306,6 +1312,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1306,6 +1312,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1306 | .arena = &decl_arena.allocator, | 1312 | .arena = &decl_arena.allocator, |
| 1307 | .inlining = null, | 1313 | .inlining = null, |
| 1308 | .is_comptime = true, | 1314 | .is_comptime = true, |
| 1315 | .branch_quota = &branch_quota, | ||
| 1309 | }; | 1316 | }; |
| 1310 | defer block_scope.instructions.deinit(self.gpa); | 1317 | defer block_scope.instructions.deinit(self.gpa); |
| 1311 | 1318 | ||
| ... | @@ -1367,6 +1374,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1367,6 +1374,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1367 | var var_inst_table = Scope.Block.InstTable.init(self.gpa); | 1374 | var var_inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1368 | defer var_inst_table.deinit(); | 1375 | defer var_inst_table.deinit(); |
| 1369 | 1376 | ||
| 1377 | var branch_quota_vi: u32 = 1000; | ||
| 1370 | var inner_block: Scope.Block = .{ | 1378 | var inner_block: Scope.Block = .{ |
| 1371 | .parent = null, | 1379 | .parent = null, |
| 1372 | .inst_table = &var_inst_table, | 1380 | .inst_table = &var_inst_table, |
| ... | @@ -1376,6 +1384,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1376,6 +1384,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1376 | .arena = &gen_scope_arena.allocator, | 1384 | .arena = &gen_scope_arena.allocator, |
| 1377 | .inlining = null, | 1385 | .inlining = null, |
| 1378 | .is_comptime = true, | 1386 | .is_comptime = true, |
| 1387 | .branch_quota = &branch_quota_vi, | ||
| 1379 | }; | 1388 | }; |
| 1380 | defer inner_block.instructions.deinit(self.gpa); | 1389 | defer inner_block.instructions.deinit(self.gpa); |
| 1381 | try zir_sema.analyzeBody(self, &inner_block, .{ | 1390 | try zir_sema.analyzeBody(self, &inner_block, .{ |
| ... | @@ -1494,6 +1503,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1494,6 +1503,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1494 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1503 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1495 | defer inst_table.deinit(); | 1504 | defer inst_table.deinit(); |
| 1496 | 1505 | ||
| 1506 | var branch_quota: u32 = 1000; | ||
| 1507 | |||
| 1497 | var block_scope: Scope.Block = .{ | 1508 | var block_scope: Scope.Block = .{ |
| 1498 | .parent = null, | 1509 | .parent = null, |
| 1499 | .inst_table = &inst_table, | 1510 | .inst_table = &inst_table, |
| ... | @@ -1503,6 +1514,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1503,6 +1514,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1503 | .arena = &analysis_arena.allocator, | 1514 | .arena = &analysis_arena.allocator, |
| 1504 | .inlining = null, | 1515 | .inlining = null, |
| 1505 | .is_comptime = true, | 1516 | .is_comptime = true, |
| 1517 | .branch_quota = &branch_quota, | ||
| 1506 | }; | 1518 | }; |
| 1507 | defer block_scope.instructions.deinit(self.gpa); | 1519 | defer block_scope.instructions.deinit(self.gpa); |
| 1508 | 1520 | ||
| ... | @@ -1875,6 +1887,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -1875,6 +1887,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 1875 | defer decl.typed_value.most_recent.arena.?.* = arena.state; | 1887 | defer decl.typed_value.most_recent.arena.?.* = arena.state; |
| 1876 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1888 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1877 | defer inst_table.deinit(); | 1889 | defer inst_table.deinit(); |
| 1890 | var branch_quota: u32 = 1000; | ||
| 1891 | |||
| 1878 | var inner_block: Scope.Block = .{ | 1892 | var inner_block: Scope.Block = .{ |
| 1879 | .parent = null, | 1893 | .parent = null, |
| 1880 | .inst_table = &inst_table, | 1894 | .inst_table = &inst_table, |
| ... | @@ -1884,6 +1898,7 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -1884,6 +1898,7 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 1884 | .arena = &arena.allocator, | 1898 | .arena = &arena.allocator, |
| 1885 | .inlining = null, | 1899 | .inlining = null, |
| 1886 | .is_comptime = false, | 1900 | .is_comptime = false, |
| 1901 | .branch_quota = &branch_quota, | ||
| 1887 | }; | 1902 | }; |
| 1888 | defer inner_block.instructions.deinit(self.gpa); | 1903 | defer inner_block.instructions.deinit(self.gpa); |
| 1889 | 1904 | ||
| ... | @@ -3466,7 +3481,9 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic | ... | @@ -3466,7 +3481,9 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3466 | .arena = parent_block.arena, | 3481 | .arena = parent_block.arena, |
| 3467 | .inlining = parent_block.inlining, | 3482 | .inlining = parent_block.inlining, |
| 3468 | .is_comptime = parent_block.is_comptime, | 3483 | .is_comptime = parent_block.is_comptime, |
| 3484 | .branch_quota = parent_block.branch_quota, | ||
| 3469 | }; | 3485 | }; |
| 3486 | |||
| 3470 | defer fail_block.instructions.deinit(mod.gpa); | 3487 | defer fail_block.instructions.deinit(mod.gpa); |
| 3471 | 3488 | ||
| 3472 | _ = try mod.safetyPanic(&fail_block, ok.src, panic_id); | 3489 | _ = try mod.safetyPanic(&fail_block, ok.src, panic_id); |
| ... | @@ -3532,10 +3549,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) | ... | @@ -3532,10 +3549,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) |
| 3532 | pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { | 3549 | pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { |
| 3533 | const shared = block.inlining.?.shared; | 3550 | const shared = block.inlining.?.shared; |
| 3534 | shared.branch_count += 1; | 3551 | shared.branch_count += 1; |
| 3535 | if (shared.branch_count > shared.branch_quota) { | 3552 | if (shared.branch_count > block.branch_quota.*) { |
| 3536 | // TODO show the "called from here" stack | 3553 | // TODO show the "called from here" stack |
| 3537 | return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{ | 3554 | return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{ |
| 3538 | shared.branch_quota, | 3555 | block.branch_quota.*, |
| 3539 | }); | 3556 | }); |
| 3540 | } | 3557 | } |
| 3541 | } | 3558 | } |
src/astgen.zig+15| ... | @@ -2317,6 +2317,19 @@ fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerE | ... | @@ -2317,6 +2317,19 @@ fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerE |
| 2317 | return addZIRUnOp(mod, scope, src, .compileerror, target); | 2317 | return addZIRUnOp(mod, scope, src, .compileerror, target); |
| 2318 | } | 2318 | } |
| 2319 | 2319 | ||
| 2320 | fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | ||
| 2321 | try ensureBuiltinParamCount(mod, scope, call, 1); | ||
| 2322 | const tree = scope.tree(); | ||
| 2323 | const src = tree.token_locs[call.builtin_token].start; | ||
| 2324 | const params = call.params(); | ||
| 2325 | const target = try expr(mod, scope, .none, params[0]); | ||
| 2326 | const u32_type = try addZIRInstConst(mod, scope, src, .{ | ||
| 2327 | .ty = Type.initTag(.type), | ||
| 2328 | .val = Value.initTag(.u32_type), | ||
| 2329 | }); | ||
| 2330 | return addZIRUnOp(mod, scope, src, .setevalbranchquota, try rlWrap(mod, scope, .{ .ty = u32_type }, target)); | ||
| 2331 | } | ||
| 2332 | |||
| 2320 | fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { | 2333 | fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 2321 | const tree = scope.tree(); | 2334 | const tree = scope.tree(); |
| 2322 | const arena = scope.arena(); | 2335 | const arena = scope.arena(); |
| ... | @@ -2362,6 +2375,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built | ... | @@ -2362,6 +2375,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built |
| 2362 | return rlWrap(mod, scope, rl, try import(mod, scope, call)); | 2375 | return rlWrap(mod, scope, rl, try import(mod, scope, call)); |
| 2363 | } else if (mem.eql(u8, builtin_name, "@compileError")) { | 2376 | } else if (mem.eql(u8, builtin_name, "@compileError")) { |
| 2364 | return compileError(mod, scope, call); | 2377 | return compileError(mod, scope, call); |
| 2378 | } else if (mem.eql(u8, builtin_name, "@setEvalBranchQuota")) { | ||
| 2379 | return setEvalBranchQuota(mod, scope, call); | ||
| 2365 | } else { | 2380 | } else { |
| 2366 | return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name}); | 2381 | return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name}); |
| 2367 | } | 2382 | } |
src/zir.zig+4| ... | @@ -127,6 +127,8 @@ pub const Inst = struct { | ... | @@ -127,6 +127,8 @@ pub const Inst = struct { |
| 127 | coerce_to_ptr_elem, | 127 | coerce_to_ptr_elem, |
| 128 | /// Emit an error message and fail compilation. | 128 | /// Emit an error message and fail compilation. |
| 129 | compileerror, | 129 | compileerror, |
| 130 | /// Changes the maximum number of backwards branches that compile-time code execution can use before giving up and making a compile error. | ||
| 131 | setevalbranchquota, | ||
| 130 | /// Conditional branch. Splits control flow based on a boolean condition value. | 132 | /// Conditional branch. Splits control flow based on a boolean condition value. |
| 131 | condbr, | 133 | condbr, |
| 132 | /// Special case, has no textual representation. | 134 | /// Special case, has no textual representation. |
| ... | @@ -347,6 +349,7 @@ pub const Inst = struct { | ... | @@ -347,6 +349,7 @@ pub const Inst = struct { |
| 347 | .anyframe_type, | 349 | .anyframe_type, |
| 348 | .bitnot, | 350 | .bitnot, |
| 349 | .import, | 351 | .import, |
| 352 | .setevalbranchquota, | ||
| 350 | => UnOp, | 353 | => UnOp, |
| 351 | 354 | ||
| 352 | .add, | 355 | .add, |
| ... | @@ -535,6 +538,7 @@ pub const Inst = struct { | ... | @@ -535,6 +538,7 @@ pub const Inst = struct { |
| 535 | .switch_range, | 538 | .switch_range, |
| 536 | .typeof_peer, | 539 | .typeof_peer, |
| 537 | .resolve_inferred_alloc, | 540 | .resolve_inferred_alloc, |
| 541 | .setevalbranchquota, | ||
| 538 | => false, | 542 | => false, |
| 539 | 543 | ||
| 540 | .@"break", | 544 | .@"break", |
src/zir_sema.zig+21-1| ... | @@ -81,6 +81,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -81,6 +81,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 81 | .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), | 81 | .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), |
| 82 | .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), | 82 | .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), |
| 83 | .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), | 83 | .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), |
| 84 | .setevalbranchquota => return analyzeInstSetEvalBranchQuota(mod, scope, old_inst.castTag(.setevalbranchquota).?), | ||
| 84 | .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), | 85 | .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), |
| 85 | .int => { | 86 | .int => { |
| 86 | const big_int = old_inst.castTag(.int).?.positionals.int; | 87 | const big_int = old_inst.castTag(.int).?.positionals.int; |
| ... | @@ -486,6 +487,18 @@ fn analyzeInstStoreToInferredPtr( | ... | @@ -486,6 +487,18 @@ fn analyzeInstStoreToInferredPtr( |
| 486 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); | 487 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); |
| 487 | } | 488 | } |
| 488 | 489 | ||
| 490 | fn analyzeInstSetEvalBranchQuota( | ||
| 491 | mod: *Module, | ||
| 492 | scope: *Scope, | ||
| 493 | inst: *zir.Inst.UnOp, | ||
| 494 | ) InnerError!*Inst { | ||
| 495 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | ||
| 496 | const quota = @truncate(u32, try resolveInt(mod, scope, inst.positionals.operand, Type.initTag(.u32))); | ||
| 497 | if (b.branch_quota.* < quota) | ||
| 498 | b.branch_quota.* = quota; | ||
| 499 | return mod.constVoid(scope, inst.base.src); | ||
| 500 | } | ||
| 501 | |||
| 489 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 502 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 490 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | 503 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); |
| 491 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | 504 | const value = try resolveInst(mod, scope, inst.positionals.rhs); |
| ... | @@ -594,6 +607,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError | ... | @@ -594,6 +607,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 594 | .arena = parent_block.arena, | 607 | .arena = parent_block.arena, |
| 595 | .inlining = parent_block.inlining, | 608 | .inlining = parent_block.inlining, |
| 596 | .is_comptime = parent_block.is_comptime, | 609 | .is_comptime = parent_block.is_comptime, |
| 610 | .branch_quota = parent_block.branch_quota, | ||
| 597 | }; | 611 | }; |
| 598 | defer child_block.instructions.deinit(mod.gpa); | 612 | defer child_block.instructions.deinit(mod.gpa); |
| 599 | 613 | ||
| ... | @@ -619,6 +633,7 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c | ... | @@ -619,6 +633,7 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c |
| 619 | .label = null, | 633 | .label = null, |
| 620 | .inlining = parent_block.inlining, | 634 | .inlining = parent_block.inlining, |
| 621 | .is_comptime = parent_block.is_comptime or is_comptime, | 635 | .is_comptime = parent_block.is_comptime or is_comptime, |
| 636 | .branch_quota = parent_block.branch_quota, | ||
| 622 | }; | 637 | }; |
| 623 | defer child_block.instructions.deinit(mod.gpa); | 638 | defer child_block.instructions.deinit(mod.gpa); |
| 624 | 639 | ||
| ... | @@ -666,6 +681,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt | ... | @@ -666,6 +681,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt |
| 666 | }), | 681 | }), |
| 667 | .inlining = parent_block.inlining, | 682 | .inlining = parent_block.inlining, |
| 668 | .is_comptime = is_comptime or parent_block.is_comptime, | 683 | .is_comptime = is_comptime or parent_block.is_comptime, |
| 684 | .branch_quota = parent_block.branch_quota, | ||
| 669 | }; | 685 | }; |
| 670 | const merges = &child_block.label.?.merges; | 686 | const merges = &child_block.label.?.merges; |
| 671 | 687 | ||
| ... | @@ -867,7 +883,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError | ... | @@ -867,7 +883,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError |
| 867 | // Otherwise we pass on the shared data from the parent scope. | 883 | // Otherwise we pass on the shared data from the parent scope. |
| 868 | var shared_inlining = Scope.Block.Inlining.Shared{ | 884 | var shared_inlining = Scope.Block.Inlining.Shared{ |
| 869 | .branch_count = 0, | 885 | .branch_count = 0, |
| 870 | .branch_quota = 1000, | ||
| 871 | .caller = b.func, | 886 | .caller = b.func, |
| 872 | }; | 887 | }; |
| 873 | // This one is shared among sub-blocks within the same callee, but not | 888 | // This one is shared among sub-blocks within the same callee, but not |
| ... | @@ -896,7 +911,9 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError | ... | @@ -896,7 +911,9 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError |
| 896 | .label = null, | 911 | .label = null, |
| 897 | .inlining = &inlining, | 912 | .inlining = &inlining, |
| 898 | .is_comptime = is_comptime_call, | 913 | .is_comptime = is_comptime_call, |
| 914 | .branch_quota = b.branch_quota, | ||
| 899 | }; | 915 | }; |
| 916 | |||
| 900 | const merges = &child_block.inlining.?.merges; | 917 | const merges = &child_block.inlining.?.merges; |
| 901 | 918 | ||
| 902 | defer child_block.instructions.deinit(mod.gpa); | 919 | defer child_block.instructions.deinit(mod.gpa); |
| ... | @@ -1417,6 +1434,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In | ... | @@ -1417,6 +1434,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In |
| 1417 | .arena = parent_block.arena, | 1434 | .arena = parent_block.arena, |
| 1418 | .inlining = parent_block.inlining, | 1435 | .inlining = parent_block.inlining, |
| 1419 | .is_comptime = parent_block.is_comptime, | 1436 | .is_comptime = parent_block.is_comptime, |
| 1437 | .branch_quota = parent_block.branch_quota, | ||
| 1420 | }; | 1438 | }; |
| 1421 | defer case_block.instructions.deinit(mod.gpa); | 1439 | defer case_block.instructions.deinit(mod.gpa); |
| 1422 | 1440 | ||
| ... | @@ -1960,6 +1978,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1960,6 +1978,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1960 | .arena = parent_block.arena, | 1978 | .arena = parent_block.arena, |
| 1961 | .inlining = parent_block.inlining, | 1979 | .inlining = parent_block.inlining, |
| 1962 | .is_comptime = parent_block.is_comptime, | 1980 | .is_comptime = parent_block.is_comptime, |
| 1981 | .branch_quota = parent_block.branch_quota, | ||
| 1963 | }; | 1982 | }; |
| 1964 | defer true_block.instructions.deinit(mod.gpa); | 1983 | defer true_block.instructions.deinit(mod.gpa); |
| 1965 | try analyzeBody(mod, &true_block, inst.positionals.then_body); | 1984 | try analyzeBody(mod, &true_block, inst.positionals.then_body); |
| ... | @@ -1973,6 +1992,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1973,6 +1992,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1973 | .arena = parent_block.arena, | 1992 | .arena = parent_block.arena, |
| 1974 | .inlining = parent_block.inlining, | 1993 | .inlining = parent_block.inlining, |
| 1975 | .is_comptime = parent_block.is_comptime, | 1994 | .is_comptime = parent_block.is_comptime, |
| 1995 | .branch_quota = parent_block.branch_quota, | ||
| 1976 | }; | 1996 | }; |
| 1977 | defer false_block.instructions.deinit(mod.gpa); | 1997 | defer false_block.instructions.deinit(mod.gpa); |
| 1978 | try analyzeBody(mod, &false_block, inst.positionals.else_body); | 1998 | try analyzeBody(mod, &false_block, inst.positionals.else_body); |
test/stage2/cbe.zig+15| ... | @@ -67,7 +67,22 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -67,7 +67,22 @@ pub fn addCases(ctx: *TestContext) !void { |
| 67 | \\} | 67 | \\} |
| 68 | , ""); | 68 | , ""); |
| 69 | } | 69 | } |
| 70 | { | ||
| 71 | var case = ctx.exeFromCompiledC("@setEvalBranchQuota", .{}); | ||
| 70 | 72 | ||
| 73 | case.addCompareOutput( | ||
| 74 | \\export fn main() i32 { | ||
| 75 | \\ @setEvalBranchQuota(1001); | ||
| 76 | \\ const y = rec(1001); | ||
| 77 | \\ return y - 1; | ||
| 78 | \\} | ||
| 79 | \\ | ||
| 80 | \\inline fn rec(n: usize) usize { | ||
| 81 | \\ if (n <= 1) return n; | ||
| 82 | \\ return rec(n - 1); | ||
| 83 | \\} | ||
| 84 | , ""); | ||
| 85 | } | ||
| 71 | ctx.c("empty start function", linux_x64, | 86 | ctx.c("empty start function", linux_x64, |
| 72 | \\export fn _start() noreturn { | 87 | \\export fn _start() noreturn { |
| 73 | \\ unreachable; | 88 | \\ unreachable; |