| author | |
| committer | |
| log | 717b0e827511b55375de82258f570709c07cc59d |
| tree | e546a29c60ebb9ada0188f76e1696077007e73d0 |
| parent | 26140678a5c72604f2baac3cb9d1e5f7b37b6b8d |
This gives zir_sema analysis the ability to check if the current scope
is expected to be comptime.6 files changed, 162 insertions(+), 25 deletions(-)
src-self-hosted/Module.zig+8-3| ... | @@ -725,6 +725,7 @@ pub const Scope = struct { | ... | @@ -725,6 +725,7 @@ pub const Scope = struct { |
| 725 | /// Points to the arena allocator of DeclAnalysis | 725 | /// Points to the arena allocator of DeclAnalysis |
| 726 | arena: *Allocator, | 726 | arena: *Allocator, |
| 727 | label: ?Label = null, | 727 | label: ?Label = null, |
| 728 | is_comptime: bool, | ||
| 728 | 729 | ||
| 729 | pub const Label = struct { | 730 | pub const Label = struct { |
| 730 | zir_block: *zir.Inst.Block, | 731 | zir_block: *zir.Inst.Block, |
| ... | @@ -1320,6 +1321,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1320,6 +1321,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1320 | .decl = decl, | 1321 | .decl = decl, |
| 1321 | .instructions = .{}, | 1322 | .instructions = .{}, |
| 1322 | .arena = &decl_arena.allocator, | 1323 | .arena = &decl_arena.allocator, |
| 1324 | .is_comptime = false, | ||
| 1323 | }; | 1325 | }; |
| 1324 | defer block_scope.instructions.deinit(self.gpa); | 1326 | defer block_scope.instructions.deinit(self.gpa); |
| 1325 | 1327 | ||
| ... | @@ -1457,6 +1459,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1457,6 +1459,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1457 | .decl = decl, | 1459 | .decl = decl, |
| 1458 | .instructions = .{}, | 1460 | .instructions = .{}, |
| 1459 | .arena = &decl_arena.allocator, | 1461 | .arena = &decl_arena.allocator, |
| 1462 | .is_comptime = true, | ||
| 1460 | }; | 1463 | }; |
| 1461 | defer block_scope.instructions.deinit(self.gpa); | 1464 | defer block_scope.instructions.deinit(self.gpa); |
| 1462 | 1465 | ||
| ... | @@ -1528,7 +1531,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1528,7 +1531,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1528 | defer gen_scope.instructions.deinit(self.gpa); | 1531 | defer gen_scope.instructions.deinit(self.gpa); |
| 1529 | const src = tree.token_locs[init_node.firstToken()].start; | 1532 | const src = tree.token_locs[init_node.firstToken()].start; |
| 1530 | 1533 | ||
| 1531 | // TODO comptime scope here | ||
| 1532 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); | 1534 | const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); |
| 1533 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); | 1535 | _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); |
| 1534 | 1536 | ||
| ... | @@ -1538,6 +1540,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1538,6 +1540,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1538 | .decl = decl, | 1540 | .decl = decl, |
| 1539 | .instructions = .{}, | 1541 | .instructions = .{}, |
| 1540 | .arena = &gen_scope_arena.allocator, | 1542 | .arena = &gen_scope_arena.allocator, |
| 1543 | .is_comptime = true, | ||
| 1541 | }; | 1544 | }; |
| 1542 | defer inner_block.instructions.deinit(self.gpa); | 1545 | defer inner_block.instructions.deinit(self.gpa); |
| 1543 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); | 1546 | try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); |
| ... | @@ -1628,8 +1631,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1628,8 +1631,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1628 | }; | 1631 | }; |
| 1629 | defer gen_scope.instructions.deinit(self.gpa); | 1632 | defer gen_scope.instructions.deinit(self.gpa); |
| 1630 | 1633 | ||
| 1631 | // TODO comptime scope here | 1634 | _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr); |
| 1632 | _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); | ||
| 1633 | 1635 | ||
| 1634 | var block_scope: Scope.Block = .{ | 1636 | var block_scope: Scope.Block = .{ |
| 1635 | .parent = null, | 1637 | .parent = null, |
| ... | @@ -1637,6 +1639,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1637,6 +1639,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1637 | .decl = decl, | 1639 | .decl = decl, |
| 1638 | .instructions = .{}, | 1640 | .instructions = .{}, |
| 1639 | .arena = &analysis_arena.allocator, | 1641 | .arena = &analysis_arena.allocator, |
| 1642 | .is_comptime = true, | ||
| 1640 | }; | 1643 | }; |
| 1641 | defer block_scope.instructions.deinit(self.gpa); | 1644 | defer block_scope.instructions.deinit(self.gpa); |
| 1642 | 1645 | ||
| ... | @@ -2007,6 +2010,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { | ... | @@ -2007,6 +2010,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void { |
| 2007 | .decl = decl, | 2010 | .decl = decl, |
| 2008 | .instructions = .{}, | 2011 | .instructions = .{}, |
| 2009 | .arena = &arena.allocator, | 2012 | .arena = &arena.allocator, |
| 2013 | .is_comptime = false, | ||
| 2010 | }; | 2014 | }; |
| 2011 | defer inner_block.instructions.deinit(self.gpa); | 2015 | defer inner_block.instructions.deinit(self.gpa); |
| 2012 | 2016 | ||
| ... | @@ -3432,6 +3436,7 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic | ... | @@ -3432,6 +3436,7 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic |
| 3432 | .decl = parent_block.decl, | 3436 | .decl = parent_block.decl, |
| 3433 | .instructions = .{}, | 3437 | .instructions = .{}, |
| 3434 | .arena = parent_block.arena, | 3438 | .arena = parent_block.arena, |
| 3439 | .is_comptime = parent_block.is_comptime, | ||
| 3435 | }; | 3440 | }; |
| 3436 | defer fail_block.instructions.deinit(mod.gpa); | 3441 | defer fail_block.instructions.deinit(mod.gpa); |
| 3437 | 3442 |
src-self-hosted/astgen.zig+73-16| ... | @@ -258,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -258,7 +258,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 258 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), | 258 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), |
| 259 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), | 259 | .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), |
| 260 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), | 260 | .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), |
| 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?), | 261 | .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), |
| 262 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), | 262 | .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), |
| 263 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), | 263 | .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), |
| 264 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), | 264 | .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), |
| ... | @@ -276,6 +276,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -276,6 +276,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), | 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), |
| 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), | 278 | .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), |
| 279 | .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), | ||
| 279 | 280 | ||
| 280 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), | 281 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 281 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), | 282 | .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}), |
| ... | @@ -294,11 +295,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -294,11 +295,46 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 294 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), | 295 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| 295 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), | 296 | .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), |
| 296 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), | 297 | .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}), |
| 297 | .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}), | ||
| 298 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), | 298 | .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), |
| 299 | } | 299 | } |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { | ||
| 303 | const tracy = trace(@src()); | ||
| 304 | defer tracy.end(); | ||
| 305 | |||
| 306 | return comptimeExpr(mod, scope, rl, node.expr); | ||
| 307 | } | ||
| 308 | |||
| 309 | pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | ||
| 310 | const tree = parent_scope.tree(); | ||
| 311 | const src = tree.token_locs[node.firstToken()].start; | ||
| 312 | |||
| 313 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, we can reuse the existing one. | ||
| 314 | if (node.castTag(.LabeledBlock)) |block_node| { | ||
| 315 | return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); | ||
| 316 | } | ||
| 317 | |||
| 318 | // Make a scope to collect generated instructions in the sub-expression. | ||
| 319 | var block_scope: Scope.GenZIR = .{ | ||
| 320 | .parent = parent_scope, | ||
| 321 | .decl = parent_scope.decl().?, | ||
| 322 | .arena = parent_scope.arena(), | ||
| 323 | .instructions = .{}, | ||
| 324 | }; | ||
| 325 | defer block_scope.instructions.deinit(mod.gpa); | ||
| 326 | |||
| 327 | // No need to capture the result here because block_comptime_flat implies that the final | ||
| 328 | // instruction is the block's result value. | ||
| 329 | _ = try expr(mod, &block_scope.base, rl, node); | ||
| 330 | |||
| 331 | const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ | ||
| 332 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | ||
| 333 | }); | ||
| 334 | |||
| 335 | return &block.base; | ||
| 336 | } | ||
| 337 | |||
| 302 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 338 | fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 303 | const tree = parent_scope.tree(); | 339 | const tree = parent_scope.tree(); |
| 304 | const src = tree.token_locs[node.ltoken].start; | 340 | const src = tree.token_locs[node.ltoken].start; |
| ... | @@ -360,10 +396,13 @@ fn labeledBlockExpr( | ... | @@ -360,10 +396,13 @@ fn labeledBlockExpr( |
| 360 | parent_scope: *Scope, | 396 | parent_scope: *Scope, |
| 361 | rl: ResultLoc, | 397 | rl: ResultLoc, |
| 362 | block_node: *ast.Node.LabeledBlock, | 398 | block_node: *ast.Node.LabeledBlock, |
| 399 | zir_tag: zir.Inst.Tag, | ||
| 363 | ) InnerError!*zir.Inst { | 400 | ) InnerError!*zir.Inst { |
| 364 | const tracy = trace(@src()); | 401 | const tracy = trace(@src()); |
| 365 | defer tracy.end(); | 402 | defer tracy.end(); |
| 366 | 403 | ||
| 404 | assert(zir_tag == .block or zir_tag == .block_comptime); | ||
| 405 | |||
| 367 | const tree = parent_scope.tree(); | 406 | const tree = parent_scope.tree(); |
| 368 | const src = tree.token_locs[block_node.lbrace].start; | 407 | const src = tree.token_locs[block_node.lbrace].start; |
| 369 | 408 | ||
| ... | @@ -373,7 +412,7 @@ fn labeledBlockExpr( | ... | @@ -373,7 +412,7 @@ fn labeledBlockExpr( |
| 373 | const block_inst = try gen_zir.arena.create(zir.Inst.Block); | 412 | const block_inst = try gen_zir.arena.create(zir.Inst.Block); |
| 374 | block_inst.* = .{ | 413 | block_inst.* = .{ |
| 375 | .base = .{ | 414 | .base = .{ |
| 376 | .tag = .block, | 415 | .tag = zir_tag, |
| 377 | .src = src, | 416 | .src = src, |
| 378 | }, | 417 | }, |
| 379 | .positionals = .{ | 418 | .positionals = .{ |
| ... | @@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) | ... | @@ -773,7 +812,7 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) |
| 773 | .else_body = undefined, // populated below | 812 | .else_body = undefined, // populated below |
| 774 | }, .{}); | 813 | }, .{}); |
| 775 | 814 | ||
| 776 | const block = try addZIRInstBlock(mod, scope, src, .{ | 815 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 777 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 816 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 778 | }); | 817 | }); |
| 779 | 818 | ||
| ... | @@ -946,7 +985,7 @@ fn boolBinOp( | ... | @@ -946,7 +985,7 @@ fn boolBinOp( |
| 946 | .else_body = undefined, // populated below | 985 | .else_body = undefined, // populated below |
| 947 | }, .{}); | 986 | }, .{}); |
| 948 | 987 | ||
| 949 | const block = try addZIRInstBlock(mod, scope, src, .{ | 988 | const block = try addZIRInstBlock(mod, scope, src, .block, .{ |
| 950 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 989 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 951 | }); | 990 | }); |
| 952 | 991 | ||
| ... | @@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -1095,7 +1134,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 1095 | .else_body = undefined, // populated below | 1134 | .else_body = undefined, // populated below |
| 1096 | }, .{}); | 1135 | }, .{}); |
| 1097 | 1136 | ||
| 1098 | const block = try addZIRInstBlock(mod, scope, if_src, .{ | 1137 | const block = try addZIRInstBlock(mod, scope, if_src, .block, .{ |
| 1099 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), | 1138 | .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items), |
| 1100 | }); | 1139 | }); |
| 1101 | 1140 | ||
| ... | @@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1218,7 +1257,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1218 | .then_body = undefined, // populated below | 1257 | .then_body = undefined, // populated below |
| 1219 | .else_body = undefined, // populated below | 1258 | .else_body = undefined, // populated below |
| 1220 | }, .{}); | 1259 | }, .{}); |
| 1221 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ | 1260 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .block, .{ |
| 1222 | .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), | 1261 | .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), |
| 1223 | }); | 1262 | }); |
| 1224 | // TODO avoid emitting the continue expr when there | 1263 | // TODO avoid emitting the continue expr when there |
| ... | @@ -1231,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1231,7 +1270,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1231 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ | 1270 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ |
| 1232 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | 1271 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1233 | }); | 1272 | }); |
| 1234 | const while_block = try addZIRInstBlock(mod, scope, while_src, .{ | 1273 | const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{ |
| 1235 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), | 1274 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), |
| 1236 | }); | 1275 | }); |
| 1237 | 1276 | ||
| ... | @@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1365,7 +1404,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1365 | .then_body = undefined, // populated below | 1404 | .then_body = undefined, // populated below |
| 1366 | .else_body = undefined, // populated below | 1405 | .else_body = undefined, // populated below |
| 1367 | }, .{}); | 1406 | }, .{}); |
| 1368 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ | 1407 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{ |
| 1369 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), | 1408 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), |
| 1370 | }); | 1409 | }); |
| 1371 | 1410 | ||
| ... | @@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) | ... | @@ -1382,7 +1421,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) |
| 1382 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ | 1421 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ |
| 1383 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | 1422 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| 1384 | }); | 1423 | }); |
| 1385 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ | 1424 | const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{ |
| 1386 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), | 1425 | .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items), |
| 1387 | }); | 1426 | }); |
| 1388 | 1427 | ||
| ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( | ... | @@ -2260,6 +2299,30 @@ pub fn addZIRBinOp( |
| 2260 | return &inst.base; | 2299 | return &inst.base; |
| 2261 | } | 2300 | } |
| 2262 | 2301 | ||
| 2302 | pub fn addZIRInstBlock( | ||
| 2303 | mod: *Module, | ||
| 2304 | scope: *Scope, | ||
| 2305 | src: usize, | ||
| 2306 | tag: zir.Inst.Tag, | ||
| 2307 | body: zir.Module.Body, | ||
| 2308 | ) !*zir.Inst.Block { | ||
| 2309 | const gen_zir = scope.getGenZIR(); | ||
| 2310 | try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1); | ||
| 2311 | const inst = try gen_zir.arena.create(zir.Inst.Block); | ||
| 2312 | inst.* = .{ | ||
| 2313 | .base = .{ | ||
| 2314 | .tag = tag, | ||
| 2315 | .src = src, | ||
| 2316 | }, | ||
| 2317 | .positionals = .{ | ||
| 2318 | .body = body, | ||
| 2319 | }, | ||
| 2320 | .kw_args = .{}, | ||
| 2321 | }; | ||
| 2322 | gen_zir.instructions.appendAssumeCapacity(&inst.base); | ||
| 2323 | return inst; | ||
| 2324 | } | ||
| 2325 | |||
| 2263 | pub fn addZIRInst( | 2326 | pub fn addZIRInst( |
| 2264 | mod: *Module, | 2327 | mod: *Module, |
| 2265 | scope: *Scope, | 2328 | scope: *Scope, |
| ... | @@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ | ... | @@ -2278,12 +2341,6 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ |
| 2278 | return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); | 2341 | return addZIRInst(mod, scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{}); |
| 2279 | } | 2342 | } |
| 2280 | 2343 | ||
| 2281 | /// TODO The existence of this function is a workaround for a bug in stage1. | ||
| 2282 | pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block { | ||
| 2283 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; | ||
| 2284 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | /// TODO The existence of this function is a workaround for a bug in stage1. | 2344 | /// TODO The existence of this function is a workaround for a bug in stage1. |
| 2288 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { | 2345 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { |
| 2289 | const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type; | 2346 | const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type; |
src-self-hosted/ir.zig+9-1| ... | @@ -189,7 +189,7 @@ pub const Inst = struct { | ... | @@ -189,7 +189,7 @@ pub const Inst = struct { |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator { | 191 | pub fn cmpOperator(base: *Inst) ?std.math.CompareOperator { |
| 192 | return switch (self.base.tag) { | 192 | return switch (base.tag) { |
| 193 | .cmp_lt => .lt, | 193 | .cmp_lt => .lt, |
| 194 | .cmp_lte => .lte, | 194 | .cmp_lte => .lte, |
| 195 | .cmp_eq => .eq, | 195 | .cmp_eq => .eq, |
| ... | @@ -220,6 +220,14 @@ pub const Inst = struct { | ... | @@ -220,6 +220,14 @@ pub const Inst = struct { |
| 220 | unreachable; | 220 | unreachable; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | pub fn breakBlock(base: *Inst) ?*Block { | ||
| 224 | return switch (base.tag) { | ||
| 225 | .br => base.castTag(.br).?.block, | ||
| 226 | .brvoid => base.castTag(.brvoid).?.block, | ||
| 227 | else => null, | ||
| 228 | }; | ||
| 229 | } | ||
| 230 | |||
| 223 | pub const NoOp = struct { | 231 | pub const NoOp = struct { |
| 224 | base: Inst, | 232 | base: Inst, |
| 225 | 233 |
src-self-hosted/zir.zig+16-1| ... | @@ -78,6 +78,13 @@ pub const Inst = struct { | ... | @@ -78,6 +78,13 @@ pub const Inst = struct { |
| 78 | bitor, | 78 | bitor, |
| 79 | /// A labeled block of code, which can return a value. | 79 | /// A labeled block of code, which can return a value. |
| 80 | block, | 80 | block, |
| 81 | /// A block of code, which can return a value. There are no instructions that break out of | ||
| 82 | /// this block; it is implied that the final instruction is the result. | ||
| 83 | block_flat, | ||
| 84 | /// Same as `block` but additionally makes the inner instructions execute at comptime. | ||
| 85 | block_comptime, | ||
| 86 | /// Same as `block_flat` but additionally makes the inner instructions execute at comptime. | ||
| 87 | block_comptime_flat, | ||
| 81 | /// Boolean NOT. See also `bitnot`. | 88 | /// Boolean NOT. See also `bitnot`. |
| 82 | boolnot, | 89 | boolnot, |
| 83 | /// Return a value from a `Block`. | 90 | /// Return a value from a `Block`. |
| ... | @@ -338,9 +345,14 @@ pub const Inst = struct { | ... | @@ -338,9 +345,14 @@ pub const Inst = struct { |
| 338 | .merge_error_sets, | 345 | .merge_error_sets, |
| 339 | => BinOp, | 346 | => BinOp, |
| 340 | 347 | ||
| 348 | .block, | ||
| 349 | .block_flat, | ||
| 350 | .block_comptime, | ||
| 351 | .block_comptime_flat, | ||
| 352 | => Block, | ||
| 353 | |||
| 341 | .arg => Arg, | 354 | .arg => Arg, |
| 342 | .array_type_sentinel => ArrayTypeSentinel, | 355 | .array_type_sentinel => ArrayTypeSentinel, |
| 343 | .block => Block, | ||
| 344 | .@"break" => Break, | 356 | .@"break" => Break, |
| 345 | .breakvoid => BreakVoid, | 357 | .breakvoid => BreakVoid, |
| 346 | .call => Call, | 358 | .call => Call, |
| ... | @@ -392,6 +404,9 @@ pub const Inst = struct { | ... | @@ -392,6 +404,9 @@ pub const Inst = struct { |
| 392 | .bitcast_result_ptr, | 404 | .bitcast_result_ptr, |
| 393 | .bitor, | 405 | .bitor, |
| 394 | .block, | 406 | .block, |
| 407 | .block_flat, | ||
| 408 | .block_comptime, | ||
| 409 | .block_comptime_flat, | ||
| 395 | .boolnot, | 410 | .boolnot, |
| 396 | .breakpoint, | 411 | .breakpoint, |
| 397 | .call, | 412 | .call, |
src-self-hosted/zir_sema.zig+55-3| ... | @@ -31,7 +31,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -31,7 +31,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 31 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), | 31 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 32 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), | 32 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 33 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), | 33 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?), | 34 | .block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false), |
| 35 | .block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true), | ||
| 36 | .block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false), | ||
| 37 | .block_comptime_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true), | ||
| 35 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), | 38 | .@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?), |
| 36 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), | 39 | .breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?), |
| 37 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), | 40 | .breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?), |
| ... | @@ -147,6 +150,7 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { | ... | @@ -147,6 +150,7 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { |
| 147 | } | 150 | } |
| 148 | } | 151 | } |
| 149 | 152 | ||
| 153 | /// TODO improve this to use .block_comptime_flat | ||
| 150 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { | 154 | pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { |
| 151 | try analyzeBody(mod, &block_scope.base, body); | 155 | try analyzeBody(mod, &block_scope.base, body); |
| 152 | for (block_scope.instructions.items) |inst| { | 156 | for (block_scope.instructions.items) |inst| { |
| ... | @@ -517,6 +521,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError | ... | @@ -517,6 +521,7 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 517 | .decl = parent_block.decl, | 521 | .decl = parent_block.decl, |
| 518 | .instructions = .{}, | 522 | .instructions = .{}, |
| 519 | .arena = parent_block.arena, | 523 | .arena = parent_block.arena, |
| 524 | .is_comptime = parent_block.is_comptime, | ||
| 520 | }; | 525 | }; |
| 521 | defer child_block.instructions.deinit(mod.gpa); | 526 | defer child_block.instructions.deinit(mod.gpa); |
| 522 | 527 | ||
| ... | @@ -529,7 +534,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError | ... | @@ -529,7 +534,29 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError |
| 529 | return &loop_inst.base; | 534 | return &loop_inst.base; |
| 530 | } | 535 | } |
| 531 | 536 | ||
| 532 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | 537 | fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { |
| 538 | const parent_block = scope.cast(Scope.Block).?; | ||
| 539 | |||
| 540 | var child_block: Scope.Block = .{ | ||
| 541 | .parent = parent_block, | ||
| 542 | .func = parent_block.func, | ||
| 543 | .decl = parent_block.decl, | ||
| 544 | .instructions = .{}, | ||
| 545 | .arena = parent_block.arena, | ||
| 546 | .label = null, | ||
| 547 | .is_comptime = parent_block.is_comptime or is_comptime, | ||
| 548 | }; | ||
| 549 | defer child_block.instructions.deinit(mod.gpa); | ||
| 550 | |||
| 551 | try analyzeBody(mod, &child_block.base, inst.positionals.body); | ||
| 552 | |||
| 553 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | ||
| 554 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 555 | |||
| 556 | return copied_instructions[copied_instructions.len - 1]; | ||
| 557 | } | ||
| 558 | |||
| 559 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst { | ||
| 533 | const parent_block = scope.cast(Scope.Block).?; | 560 | const parent_block = scope.cast(Scope.Block).?; |
| 534 | 561 | ||
| 535 | // Reserve space for a Block instruction so that generated Break instructions can | 562 | // Reserve space for a Block instruction so that generated Break instructions can |
| ... | @@ -557,6 +584,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr | ... | @@ -557,6 +584,7 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 557 | .results = .{}, | 584 | .results = .{}, |
| 558 | .block_inst = block_inst, | 585 | .block_inst = block_inst, |
| 559 | }), | 586 | }), |
| 587 | .is_comptime = is_comptime or parent_block.is_comptime, | ||
| 560 | }; | 588 | }; |
| 561 | const label = &child_block.label.?; | 589 | const label = &child_block.label.?; |
| 562 | 590 | ||
| ... | @@ -569,6 +597,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr | ... | @@ -569,6 +597,28 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerErr |
| 569 | assert(child_block.instructions.items.len != 0); | 597 | assert(child_block.instructions.items.len != 0); |
| 570 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn()); | 598 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn()); |
| 571 | 599 | ||
| 600 | if (label.results.items.len == 0) { | ||
| 601 | // No need for a block instruction. We can put the new instructions directly into the parent block. | ||
| 602 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items); | ||
| 603 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 604 | return copied_instructions[copied_instructions.len - 1]; | ||
| 605 | } | ||
| 606 | if (label.results.items.len == 1) { | ||
| 607 | const last_inst_index = child_block.instructions.items.len - 1; | ||
| 608 | const last_inst = child_block.instructions.items[last_inst_index]; | ||
| 609 | if (last_inst.breakBlock()) |br_block| { | ||
| 610 | if (br_block == block_inst) { | ||
| 611 | // No need for a block instruction. We can put the new instructions directly into the parent block. | ||
| 612 | // Here we omit the break instruction. | ||
| 613 | const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]); | ||
| 614 | try parent_block.instructions.appendSlice(mod.gpa, copied_instructions); | ||
| 615 | return label.results.items[0]; | ||
| 616 | } | ||
| 617 | } | ||
| 618 | } | ||
| 619 | // It should be impossible to have the number of results be > 1 in a comptime scope. | ||
| 620 | assert(!child_block.is_comptime); // We should have already got a compile error in the condbr condition. | ||
| 621 | |||
| 572 | // Need to set the type and emit the Block instruction. This allows machine code generation | 622 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 573 | // to emit a jump instruction to after the block when it encounters the break. | 623 | // to emit a jump instruction to after the block when it encounters the break. |
| 574 | try parent_block.instructions.append(mod.gpa, &block_inst.base); | 624 | try parent_block.instructions.append(mod.gpa, &block_inst.base); |
| ... | @@ -1083,7 +1133,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne | ... | @@ -1083,7 +1133,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1083 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); | 1133 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); |
| 1084 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); | 1134 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); |
| 1085 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); | 1135 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); |
| 1086 | 1136 | ||
| 1087 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { | 1137 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { |
| 1088 | .Pointer => array_ptr.ty.elemType(), | 1138 | .Pointer => array_ptr.ty.elemType(), |
| 1089 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), | 1139 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), |
| ... | @@ -1376,6 +1426,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1376,6 +1426,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1376 | .decl = parent_block.decl, | 1426 | .decl = parent_block.decl, |
| 1377 | .instructions = .{}, | 1427 | .instructions = .{}, |
| 1378 | .arena = parent_block.arena, | 1428 | .arena = parent_block.arena, |
| 1429 | .is_comptime = parent_block.is_comptime, | ||
| 1379 | }; | 1430 | }; |
| 1380 | defer true_block.instructions.deinit(mod.gpa); | 1431 | defer true_block.instructions.deinit(mod.gpa); |
| 1381 | try analyzeBody(mod, &true_block.base, inst.positionals.then_body); | 1432 | try analyzeBody(mod, &true_block.base, inst.positionals.then_body); |
| ... | @@ -1386,6 +1437,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1386,6 +1437,7 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1386 | .decl = parent_block.decl, | 1437 | .decl = parent_block.decl, |
| 1387 | .instructions = .{}, | 1438 | .instructions = .{}, |
| 1388 | .arena = parent_block.arena, | 1439 | .arena = parent_block.arena, |
| 1440 | .is_comptime = parent_block.is_comptime, | ||
| 1389 | }; | 1441 | }; |
| 1390 | defer false_block.instructions.deinit(mod.gpa); | 1442 | defer false_block.instructions.deinit(mod.gpa); |
| 1391 | try analyzeBody(mod, &false_block.base, inst.positionals.else_body); | 1443 | try analyzeBody(mod, &false_block.base, inst.positionals.else_body); |
test/stage2/test.zig+1-1| ... | @@ -274,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -274,7 +274,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | { | 276 | { |
| 277 | var case = ctx.exe("substracting numbers at runtime", linux_x64); | 277 | var case = ctx.exe("subtracting numbers at runtime", linux_x64); |
| 278 | case.addCompareOutput( | 278 | case.addCompareOutput( |
| 279 | \\export fn _start() noreturn { | 279 | \\export fn _start() noreturn { |
| 280 | \\ sub(7, 4); | 280 | \\ sub(7, 4); |