| author | |
| committer | |
| log | ef2fa67ef018a4a49124a40e60941149efd34553 |
| tree | 5c5c538cf0b1d79e6626637ea5b3192e7cdec868 |
| parent | aa0906e9aaaf36bc928b5502bdb34e7a0409b2c0 |
| parent | 7e64dc42215c93a2d1d6b7fa4f5e07b885788a7d |
closes #76825 files changed, 97 insertions(+), 5 deletions(-)
src/Module.zig+23-4| ... | @@ -23,6 +23,8 @@ const trace = @import("tracy.zig").trace; | ... | @@ -23,6 +23,8 @@ const trace = @import("tracy.zig").trace; |
| 23 | const astgen = @import("astgen.zig"); | 23 | const astgen = @import("astgen.zig"); |
| 24 | const zir_sema = @import("zir_sema.zig"); | 24 | const zir_sema = @import("zir_sema.zig"); |
| 25 | 25 | ||
| 26 | const default_eval_branch_quota = 1000; | ||
| 27 | |||
| 26 | /// General-purpose allocator. Used for both temporary and long-term storage. | 28 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 27 | gpa: *Allocator, | 29 | gpa: *Allocator, |
| 28 | comp: *Compilation, | 30 | comp: *Compilation, |
| ... | @@ -765,6 +767,8 @@ pub const Scope = struct { | ... | @@ -765,6 +767,8 @@ pub const Scope = struct { |
| 765 | label: ?Label = null, | 767 | label: ?Label = null, |
| 766 | inlining: ?*Inlining, | 768 | inlining: ?*Inlining, |
| 767 | is_comptime: bool, | 769 | is_comptime: bool, |
| 770 | /// Shared to sub-blocks. | ||
| 771 | branch_quota: *u32, | ||
| 768 | 772 | ||
| 769 | pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst); | 773 | pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst); |
| 770 | 774 | ||
| ... | @@ -792,8 +796,7 @@ pub const Scope = struct { | ... | @@ -792,8 +796,7 @@ pub const Scope = struct { |
| 792 | 796 | ||
| 793 | pub const Shared = struct { | 797 | pub const Shared = struct { |
| 794 | caller: ?*Fn, | 798 | caller: ?*Fn, |
| 795 | branch_count: u64, | 799 | branch_count: u32, |
| 796 | branch_quota: u64, | ||
| 797 | }; | 800 | }; |
| 798 | }; | 801 | }; |
| 799 | 802 | ||
| ... | @@ -1104,6 +1107,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1104,6 +1107,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1104 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1107 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1105 | defer inst_table.deinit(); | 1108 | defer inst_table.deinit(); |
| 1106 | 1109 | ||
| 1110 | var branch_quota: u32 = default_eval_branch_quota; | ||
| 1111 | |||
| 1107 | var block_scope: Scope.Block = .{ | 1112 | var block_scope: Scope.Block = .{ |
| 1108 | .parent = null, | 1113 | .parent = null, |
| 1109 | .inst_table = &inst_table, | 1114 | .inst_table = &inst_table, |
| ... | @@ -1113,6 +1118,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1113,6 +1118,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1113 | .arena = &decl_arena.allocator, | 1118 | .arena = &decl_arena.allocator, |
| 1114 | .inlining = null, | 1119 | .inlining = null, |
| 1115 | .is_comptime = false, | 1120 | .is_comptime = false, |
| 1121 | .branch_quota = &branch_quota, | ||
| 1116 | }; | 1122 | }; |
| 1117 | defer block_scope.instructions.deinit(self.gpa); | 1123 | defer block_scope.instructions.deinit(self.gpa); |
| 1118 | 1124 | ||
| ... | @@ -1297,6 +1303,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1297,6 +1303,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1297 | var decl_inst_table = Scope.Block.InstTable.init(self.gpa); | 1303 | var decl_inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1298 | defer decl_inst_table.deinit(); | 1304 | defer decl_inst_table.deinit(); |
| 1299 | 1305 | ||
| 1306 | var branch_quota: u32 = default_eval_branch_quota; | ||
| 1307 | |||
| 1300 | var block_scope: Scope.Block = .{ | 1308 | var block_scope: Scope.Block = .{ |
| 1301 | .parent = null, | 1309 | .parent = null, |
| 1302 | .inst_table = &decl_inst_table, | 1310 | .inst_table = &decl_inst_table, |
| ... | @@ -1306,6 +1314,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1306,6 +1314,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1306 | .arena = &decl_arena.allocator, | 1314 | .arena = &decl_arena.allocator, |
| 1307 | .inlining = null, | 1315 | .inlining = null, |
| 1308 | .is_comptime = true, | 1316 | .is_comptime = true, |
| 1317 | .branch_quota = &branch_quota, | ||
| 1309 | }; | 1318 | }; |
| 1310 | defer block_scope.instructions.deinit(self.gpa); | 1319 | defer block_scope.instructions.deinit(self.gpa); |
| 1311 | 1320 | ||
| ... | @@ -1367,6 +1376,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1367,6 +1376,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1367 | var var_inst_table = Scope.Block.InstTable.init(self.gpa); | 1376 | var var_inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1368 | defer var_inst_table.deinit(); | 1377 | defer var_inst_table.deinit(); |
| 1369 | 1378 | ||
| 1379 | var branch_quota_vi: u32 = default_eval_branch_quota; | ||
| 1370 | var inner_block: Scope.Block = .{ | 1380 | var inner_block: Scope.Block = .{ |
| 1371 | .parent = null, | 1381 | .parent = null, |
| 1372 | .inst_table = &var_inst_table, | 1382 | .inst_table = &var_inst_table, |
| ... | @@ -1376,6 +1386,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1376,6 +1386,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1376 | .arena = &gen_scope_arena.allocator, | 1386 | .arena = &gen_scope_arena.allocator, |
| 1377 | .inlining = null, | 1387 | .inlining = null, |
| 1378 | .is_comptime = true, | 1388 | .is_comptime = true, |
| 1389 | .branch_quota = &branch_quota_vi, | ||
| 1379 | }; | 1390 | }; |
| 1380 | defer inner_block.instructions.deinit(self.gpa); | 1391 | defer inner_block.instructions.deinit(self.gpa); |
| 1381 | try zir_sema.analyzeBody(self, &inner_block, .{ | 1392 | try zir_sema.analyzeBody(self, &inner_block, .{ |
| ... | @@ -1494,6 +1505,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1494,6 +1505,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1494 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1505 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1495 | defer inst_table.deinit(); | 1506 | defer inst_table.deinit(); |
| 1496 | 1507 | ||
| 1508 | var branch_quota: u32 = default_eval_branch_quota; | ||
| 1509 | |||
| 1497 | var block_scope: Scope.Block = .{ | 1510 | var block_scope: Scope.Block = .{ |
| 1498 | .parent = null, | 1511 | .parent = null, |
| 1499 | .inst_table = &inst_table, | 1512 | .inst_table = &inst_table, |
| ... | @@ -1503,6 +1516,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1503,6 +1516,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1503 | .arena = &analysis_arena.allocator, | 1516 | .arena = &analysis_arena.allocator, |
| 1504 | .inlining = null, | 1517 | .inlining = null, |
| 1505 | .is_comptime = true, | 1518 | .is_comptime = true, |
| 1519 | .branch_quota = &branch_quota, | ||
| 1506 | }; | 1520 | }; |
| 1507 | defer block_scope.instructions.deinit(self.gpa); | 1521 | defer block_scope.instructions.deinit(self.gpa); |
| 1508 | 1522 | ||
| ... | @@ -1875,6 +1889,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -1875,6 +1889,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 1875 | defer decl.typed_value.most_recent.arena.?.* = arena.state; | 1889 | defer decl.typed_value.most_recent.arena.?.* = arena.state; |
| 1876 | var inst_table = Scope.Block.InstTable.init(self.gpa); | 1890 | var inst_table = Scope.Block.InstTable.init(self.gpa); |
| 1877 | defer inst_table.deinit(); | 1891 | defer inst_table.deinit(); |
| 1892 | var branch_quota: u32 = default_eval_branch_quota; | ||
| 1893 | |||
| 1878 | var inner_block: Scope.Block = .{ | 1894 | var inner_block: Scope.Block = .{ |
| 1879 | .parent = null, | 1895 | .parent = null, |
| 1880 | .inst_table = &inst_table, | 1896 | .inst_table = &inst_table, |
| ... | @@ -1884,6 +1900,7 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -1884,6 +1900,7 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 1884 | .arena = &arena.allocator, | 1900 | .arena = &arena.allocator, |
| 1885 | .inlining = null, | 1901 | .inlining = null, |
| 1886 | .is_comptime = false, | 1902 | .is_comptime = false, |
| 1903 | .branch_quota = &branch_quota, | ||
| 1887 | }; | 1904 | }; |
| 1888 | defer inner_block.instructions.deinit(self.gpa); | 1905 | defer inner_block.instructions.deinit(self.gpa); |
| 1889 | 1906 | ||
| ... | @@ -3466,7 +3483,9 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic | ... | @@ -3466,7 +3483,9 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3466 | .arena = parent_block.arena, | 3483 | .arena = parent_block.arena, |
| 3467 | .inlining = parent_block.inlining, | 3484 | .inlining = parent_block.inlining, |
| 3468 | .is_comptime = parent_block.is_comptime, | 3485 | .is_comptime = parent_block.is_comptime, |
| 3486 | .branch_quota = parent_block.branch_quota, | ||
| 3469 | }; | 3487 | }; |
| 3488 | |||
| 3470 | defer fail_block.instructions.deinit(mod.gpa); | 3489 | defer fail_block.instructions.deinit(mod.gpa); |
| 3471 | 3490 | ||
| 3472 | _ = try mod.safetyPanic(&fail_block, ok.src, panic_id); | 3491 | _ = try mod.safetyPanic(&fail_block, ok.src, panic_id); |
| ... | @@ -3532,10 +3551,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) | ... | @@ -3532,10 +3551,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) |
| 3532 | pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { | 3551 | pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void { |
| 3533 | const shared = block.inlining.?.shared; | 3552 | const shared = block.inlining.?.shared; |
| 3534 | shared.branch_count += 1; | 3553 | shared.branch_count += 1; |
| 3535 | if (shared.branch_count > shared.branch_quota) { | 3554 | if (shared.branch_count > block.branch_quota.*) { |
| 3536 | // TODO show the "called from here" stack | 3555 | // TODO show the "called from here" stack |
| 3537 | return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{ | 3556 | return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{ |
| 3538 | shared.branch_quota, | 3557 | block.branch_quota.*, |
| 3539 | }); | 3558 | }); |
| 3540 | } | 3559 | } |
| 3541 | } | 3560 | } |
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 u32_type = try addZIRInstConst(mod, scope, src, .{ | ||
| 2326 | .ty = Type.initTag(.type), | ||
| 2327 | .val = Value.initTag(.u32_type), | ||
| 2328 | }); | ||
| 2329 | const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]); | ||
| 2330 | return addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota); | ||
| 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+5| ... | @@ -127,6 +127,9 @@ pub const Inst = struct { | ... | @@ -127,6 +127,9 @@ 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 | ||
| 131 | /// code execution can use before giving up and making a compile error. | ||
| 132 | set_eval_branch_quota, | ||
| 130 | /// Conditional branch. Splits control flow based on a boolean condition value. | 133 | /// Conditional branch. Splits control flow based on a boolean condition value. |
| 131 | condbr, | 134 | condbr, |
| 132 | /// Special case, has no textual representation. | 135 | /// Special case, has no textual representation. |
| ... | @@ -347,6 +350,7 @@ pub const Inst = struct { | ... | @@ -347,6 +350,7 @@ pub const Inst = struct { |
| 347 | .anyframe_type, | 350 | .anyframe_type, |
| 348 | .bitnot, | 351 | .bitnot, |
| 349 | .import, | 352 | .import, |
| 353 | .set_eval_branch_quota, | ||
| 350 | => UnOp, | 354 | => UnOp, |
| 351 | 355 | ||
| 352 | .add, | 356 | .add, |
| ... | @@ -535,6 +539,7 @@ pub const Inst = struct { | ... | @@ -535,6 +539,7 @@ pub const Inst = struct { |
| 535 | .switch_range, | 539 | .switch_range, |
| 536 | .typeof_peer, | 540 | .typeof_peer, |
| 537 | .resolve_inferred_alloc, | 541 | .resolve_inferred_alloc, |
| 542 | .set_eval_branch_quota, | ||
| 538 | => false, | 543 | => false, |
| 539 | 544 | ||
| 540 | .@"break", | 545 | .@"break", |
src/zir_sema.zig+39-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 | .set_eval_branch_quota => return analyzeInstSetEvalBranchQuota(mod, scope, old_inst.castTag(.set_eval_branch_quota).?), | ||
| 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; |
| ... | @@ -280,6 +281,24 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { | ... | @@ -280,6 +281,24 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { |
| 280 | return val.toType(scope.arena()); | 281 | return val.toType(scope.arena()); |
| 281 | } | 282 | } |
| 282 | 283 | ||
| 284 | /// Appropriate to call when the coercion has already been done by result | ||
| 285 | /// location semantics. Asserts the value fits in the provided `Int` type. | ||
| 286 | /// Only supports `Int` types 64 bits or less. | ||
| 287 | fn resolveAlreadyCoercedInt( | ||
| 288 | mod: *Module, | ||
| 289 | scope: *Scope, | ||
| 290 | old_inst: *zir.Inst, | ||
| 291 | comptime Int: type, | ||
| 292 | ) !Int { | ||
| 293 | comptime assert(@typeInfo(Int).Int.bits <= 64); | ||
| 294 | const new_inst = try resolveInst(mod, scope, old_inst); | ||
| 295 | const val = try mod.resolveConstValue(scope, new_inst); | ||
| 296 | switch (@typeInfo(Int).Int.signedness) { | ||
| 297 | .signed => return @intCast(Int, val.toSignedInt()), | ||
| 298 | .unsigned => return @intCast(Int, val.toUnsignedInt()), | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 283 | fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { | 302 | fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { |
| 284 | const new_inst = try resolveInst(mod, scope, old_inst); | 303 | const new_inst = try resolveInst(mod, scope, old_inst); |
| 285 | const coerced = try mod.coerce(scope, dest_type, new_inst); | 304 | const coerced = try mod.coerce(scope, dest_type, new_inst); |
| ... | @@ -486,6 +505,18 @@ fn analyzeInstStoreToInferredPtr( | ... | @@ -486,6 +505,18 @@ fn analyzeInstStoreToInferredPtr( |
| 486 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); | 505 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); |
| 487 | } | 506 | } |
| 488 | 507 | ||
| 508 | fn analyzeInstSetEvalBranchQuota( | ||
| 509 | mod: *Module, | ||
| 510 | scope: *Scope, | ||
| 511 | inst: *zir.Inst.UnOp, | ||
| 512 | ) InnerError!*Inst { | ||
| 513 | const b = try mod.requireFunctionBlock(scope, inst.base.src); | ||
| 514 | const quota = try resolveAlreadyCoercedInt(mod, scope, inst.positionals.operand, u32); | ||
| 515 | if (b.branch_quota.* < quota) | ||
| 516 | b.branch_quota.* = quota; | ||
| 517 | return mod.constVoid(scope, inst.base.src); | ||
| 518 | } | ||
| 519 | |||
| 489 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 520 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
| 490 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | 521 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); |
| 491 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | 522 | const value = try resolveInst(mod, scope, inst.positionals.rhs); |
| ... | @@ -594,6 +625,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError | ... | @@ -594,6 +625,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 594 | .arena = parent_block.arena, | 625 | .arena = parent_block.arena, |
| 595 | .inlining = parent_block.inlining, | 626 | .inlining = parent_block.inlining, |
| 596 | .is_comptime = parent_block.is_comptime, | 627 | .is_comptime = parent_block.is_comptime, |
| 628 | .branch_quota = parent_block.branch_quota, | ||
| 597 | }; | 629 | }; |
| 598 | defer child_block.instructions.deinit(mod.gpa); | 630 | defer child_block.instructions.deinit(mod.gpa); |
| 599 | 631 | ||
| ... | @@ -619,6 +651,7 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c | ... | @@ -619,6 +651,7 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c |
| 619 | .label = null, | 651 | .label = null, |
| 620 | .inlining = parent_block.inlining, | 652 | .inlining = parent_block.inlining, |
| 621 | .is_comptime = parent_block.is_comptime or is_comptime, | 653 | .is_comptime = parent_block.is_comptime or is_comptime, |
| 654 | .branch_quota = parent_block.branch_quota, | ||
| 622 | }; | 655 | }; |
| 623 | defer child_block.instructions.deinit(mod.gpa); | 656 | defer child_block.instructions.deinit(mod.gpa); |
| 624 | 657 | ||
| ... | @@ -666,6 +699,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt | ... | @@ -666,6 +699,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt |
| 666 | }), | 699 | }), |
| 667 | .inlining = parent_block.inlining, | 700 | .inlining = parent_block.inlining, |
| 668 | .is_comptime = is_comptime or parent_block.is_comptime, | 701 | .is_comptime = is_comptime or parent_block.is_comptime, |
| 702 | .branch_quota = parent_block.branch_quota, | ||
| 669 | }; | 703 | }; |
| 670 | const merges = &child_block.label.?.merges; | 704 | const merges = &child_block.label.?.merges; |
| 671 | 705 | ||
| ... | @@ -867,7 +901,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError | ... | @@ -867,7 +901,6 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError |
| 867 | // Otherwise we pass on the shared data from the parent scope. | 901 | // Otherwise we pass on the shared data from the parent scope. |
| 868 | var shared_inlining = Scope.Block.Inlining.Shared{ | 902 | var shared_inlining = Scope.Block.Inlining.Shared{ |
| 869 | .branch_count = 0, | 903 | .branch_count = 0, |
| 870 | .branch_quota = 1000, | ||
| 871 | .caller = b.func, | 904 | .caller = b.func, |
| 872 | }; | 905 | }; |
| 873 | // This one is shared among sub-blocks within the same callee, but not | 906 | // This one is shared among sub-blocks within the same callee, but not |
| ... | @@ -896,7 +929,9 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError | ... | @@ -896,7 +929,9 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError |
| 896 | .label = null, | 929 | .label = null, |
| 897 | .inlining = &inlining, | 930 | .inlining = &inlining, |
| 898 | .is_comptime = is_comptime_call, | 931 | .is_comptime = is_comptime_call, |
| 932 | .branch_quota = b.branch_quota, | ||
| 899 | }; | 933 | }; |
| 934 | |||
| 900 | const merges = &child_block.inlining.?.merges; | 935 | const merges = &child_block.inlining.?.merges; |
| 901 | 936 | ||
| 902 | defer child_block.instructions.deinit(mod.gpa); | 937 | defer child_block.instructions.deinit(mod.gpa); |
| ... | @@ -1417,6 +1452,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In | ... | @@ -1417,6 +1452,7 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In |
| 1417 | .arena = parent_block.arena, | 1452 | .arena = parent_block.arena, |
| 1418 | .inlining = parent_block.inlining, | 1453 | .inlining = parent_block.inlining, |
| 1419 | .is_comptime = parent_block.is_comptime, | 1454 | .is_comptime = parent_block.is_comptime, |
| 1455 | .branch_quota = parent_block.branch_quota, | ||
| 1420 | }; | 1456 | }; |
| 1421 | defer case_block.instructions.deinit(mod.gpa); | 1457 | defer case_block.instructions.deinit(mod.gpa); |
| 1422 | 1458 | ||
| ... | @@ -1960,6 +1996,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1960,6 +1996,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1960 | .arena = parent_block.arena, | 1996 | .arena = parent_block.arena, |
| 1961 | .inlining = parent_block.inlining, | 1997 | .inlining = parent_block.inlining, |
| 1962 | .is_comptime = parent_block.is_comptime, | 1998 | .is_comptime = parent_block.is_comptime, |
| 1999 | .branch_quota = parent_block.branch_quota, | ||
| 1963 | }; | 2000 | }; |
| 1964 | defer true_block.instructions.deinit(mod.gpa); | 2001 | defer true_block.instructions.deinit(mod.gpa); |
| 1965 | try analyzeBody(mod, &true_block, inst.positionals.then_body); | 2002 | try analyzeBody(mod, &true_block, inst.positionals.then_body); |
| ... | @@ -1973,6 +2010,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1973,6 +2010,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1973 | .arena = parent_block.arena, | 2010 | .arena = parent_block.arena, |
| 1974 | .inlining = parent_block.inlining, | 2011 | .inlining = parent_block.inlining, |
| 1975 | .is_comptime = parent_block.is_comptime, | 2012 | .is_comptime = parent_block.is_comptime, |
| 2013 | .branch_quota = parent_block.branch_quota, | ||
| 1976 | }; | 2014 | }; |
| 1977 | defer false_block.instructions.deinit(mod.gpa); | 2015 | defer false_block.instructions.deinit(mod.gpa); |
| 1978 | try analyzeBody(mod, &false_block, inst.positionals.else_body); | 2016 | 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; |