| author | |
| committer | |
| log | de4f3f11f735708cf9ffe4bbdbbfa693b6b07916 |
| tree | a5c68b84d6f8b9d69093bc9bafea5bf3ad112bcd |
| parent | 30db5b1fb23502de02650473ff8282b2875650a9 |
See #60216 files changed, 269 insertions(+), 21 deletions(-)
src-self-hosted/astgen.zig+158-18| ... | @@ -48,20 +48,21 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z | ... | @@ -48,20 +48,21 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z |
| 48 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { | 48 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { |
| 49 | switch (node.tag) { | 49 | switch (node.tag) { |
| 50 | .VarDecl => unreachable, // Handled in `blockExpr`. | 50 | .VarDecl => unreachable, // Handled in `blockExpr`. |
| 51 | .Assign => unreachable, // Handled in `blockExpr`. | 51 | |
| 52 | .AssignBitAnd => unreachable, // Handled in `blockExpr`. | 52 | .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), |
| 53 | .AssignBitOr => unreachable, // Handled in `blockExpr`. | 53 | .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)), |
| 54 | .AssignBitShiftLeft => unreachable, // Handled in `blockExpr`. | 54 | .AssignBitOr => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bitor)), |
| 55 | .AssignBitShiftRight => unreachable, // Handled in `blockExpr`. | 55 | .AssignBitShiftLeft => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), |
| 56 | .AssignBitXor => unreachable, // Handled in `blockExpr`. | 56 | .AssignBitShiftRight => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), |
| 57 | .AssignDiv => unreachable, // Handled in `blockExpr`. | 57 | .AssignBitXor => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), |
| 58 | .AssignSub => unreachable, // Handled in `blockExpr`. | 58 | .AssignDiv => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), |
| 59 | .AssignSubWrap => unreachable, // Handled in `blockExpr`. | 59 | .AssignSub => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), |
| 60 | .AssignMod => unreachable, // Handled in `blockExpr`. | 60 | .AssignSubWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), |
| 61 | .AssignAdd => unreachable, // Handled in `blockExpr`. | 61 | .AssignMod => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), |
| 62 | .AssignAddWrap => unreachable, // Handled in `blockExpr`. | 62 | .AssignAdd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), |
| 63 | .AssignMul => unreachable, // Handled in `blockExpr`. | 63 | .AssignAddWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), |
| 64 | .AssignMulWrap => unreachable, // Handled in `blockExpr`. | 64 | .AssignMul => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMul).?, .mul)), |
| 65 | .AssignMulWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMulWrap).?, .mulwrap)), | ||
| 65 | 66 | ||
| 66 | .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), | 67 | .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), |
| 67 | .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), | 68 | .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), |
| ... | @@ -96,6 +97,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -96,6 +97,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 96 | .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), | 97 | .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), |
| 97 | .Return => return ret(mod, scope, node.castTag(.Return).?), | 98 | .Return => return ret(mod, scope, node.castTag(.Return).?), |
| 98 | .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), | 99 | .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), |
| 100 | .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), | ||
| 99 | .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)), | 101 | .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)), |
| 100 | .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), | 102 | .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), |
| 101 | .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), | 103 | .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), |
| ... | @@ -127,10 +129,7 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block | ... | @@ -127,10 +129,7 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block |
| 127 | const var_decl_node = statement.castTag(.VarDecl).?; | 129 | const var_decl_node = statement.castTag(.VarDecl).?; |
| 128 | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); | 130 | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); |
| 129 | }, | 131 | }, |
| 130 | .Assign => { | 132 | .Assign => try assign(mod, scope, statement.castTag(.Assign).?), |
| 131 | const ass = statement.castTag(.Assign).?; | ||
| 132 | try assign(mod, scope, ass); | ||
| 133 | }, | ||
| 134 | .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bitand), | 133 | .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bitand), |
| 135 | .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bitor), | 134 | .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bitor), |
| 136 | .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), | 135 | .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), |
| ... | @@ -454,6 +453,132 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn | ... | @@ -454,6 +453,132 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn |
| 454 | return &block.base; | 453 | return &block.base; |
| 455 | } | 454 | } |
| 456 | 455 | ||
| 456 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { | ||
| 457 | if (while_node.payload) |payload| { | ||
| 458 | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{}); | ||
| 459 | } | ||
| 460 | if (while_node.@"else") |else_node| { | ||
| 461 | if (else_node.payload) |payload| { | ||
| 462 | return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{}); | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 466 | var expr_scope: Scope.GenZIR = .{ | ||
| 467 | .parent = scope, | ||
| 468 | .decl = scope.decl().?, | ||
| 469 | .arena = scope.arena(), | ||
| 470 | .instructions = .{}, | ||
| 471 | }; | ||
| 472 | defer expr_scope.instructions.deinit(mod.gpa); | ||
| 473 | |||
| 474 | var loop_scope: Scope.GenZIR = .{ | ||
| 475 | .parent = &expr_scope.base, | ||
| 476 | .decl = expr_scope.decl, | ||
| 477 | .arena = expr_scope.arena, | ||
| 478 | .instructions = .{}, | ||
| 479 | }; | ||
| 480 | defer loop_scope.instructions.deinit(mod.gpa); | ||
| 481 | |||
| 482 | var continue_scope: Scope.GenZIR = .{ | ||
| 483 | .parent = &loop_scope.base, | ||
| 484 | .decl = loop_scope.decl, | ||
| 485 | .arena = loop_scope.arena, | ||
| 486 | .instructions = .{}, | ||
| 487 | }; | ||
| 488 | defer continue_scope.instructions.deinit(mod.gpa); | ||
| 489 | |||
| 490 | const tree = scope.tree(); | ||
| 491 | const while_src = tree.token_locs[while_node.while_token].start; | ||
| 492 | const bool_type = try addZIRInstConst(mod, scope, while_src, .{ | ||
| 493 | .ty = Type.initTag(.type), | ||
| 494 | .val = Value.initTag(.bool_type), | ||
| 495 | }); | ||
| 496 | const void_type = try addZIRInstConst(mod, scope, while_src, .{ | ||
| 497 | .ty = Type.initTag(.type), | ||
| 498 | .val = Value.initTag(.void_type), | ||
| 499 | }); | ||
| 500 | const cond = try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_node.condition); | ||
| 501 | |||
| 502 | const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{ | ||
| 503 | .condition = cond, | ||
| 504 | .then_body = undefined, // populated below | ||
| 505 | .else_body = undefined, // populated below | ||
| 506 | }, .{}); | ||
| 507 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ | ||
| 508 | .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items), | ||
| 509 | }); | ||
| 510 | if (while_node.continue_expr) |cont_expr| { | ||
| 511 | const cont_expr_result = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr); | ||
| 512 | if (!cont_expr_result.tag.isNoReturn()) { | ||
| 513 | _ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat); | ||
| 514 | } | ||
| 515 | } else { | ||
| 516 | _ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat); | ||
| 517 | } | ||
| 518 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ | ||
| 519 | .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), | ||
| 520 | }); | ||
| 521 | const while_block = try addZIRInstBlock(mod, scope, while_src, .{ | ||
| 522 | .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items), | ||
| 523 | }); | ||
| 524 | var then_scope: Scope.GenZIR = .{ | ||
| 525 | .parent = &continue_scope.base, | ||
| 526 | .decl = continue_scope.decl, | ||
| 527 | .arena = continue_scope.arena, | ||
| 528 | .instructions = .{}, | ||
| 529 | }; | ||
| 530 | defer then_scope.instructions.deinit(mod.gpa); | ||
| 531 | |||
| 532 | // Most result location types can be forwarded directly; however | ||
| 533 | // if we need to write to a pointer which has an inferred type, | ||
| 534 | // proper type inference requires peer type resolution on the while's | ||
| 535 | // branches. | ||
| 536 | const branch_rl: ResultLoc = switch (rl) { | ||
| 537 | .discard, .none, .ty, .ptr, .lvalue => rl, | ||
| 538 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block }, | ||
| 539 | }; | ||
| 540 | |||
| 541 | const then_result = try expr(mod, &then_scope.base, branch_rl, while_node.body); | ||
| 542 | if (!then_result.tag.isNoReturn()) { | ||
| 543 | const then_src = tree.token_locs[while_node.body.lastToken()].start; | ||
| 544 | _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{ | ||
| 545 | .block = cond_block, | ||
| 546 | .operand = then_result, | ||
| 547 | }, .{}); | ||
| 548 | } | ||
| 549 | condbr.positionals.then_body = .{ | ||
| 550 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), | ||
| 551 | }; | ||
| 552 | |||
| 553 | var else_scope: Scope.GenZIR = .{ | ||
| 554 | .parent = &continue_scope.base, | ||
| 555 | .decl = continue_scope.decl, | ||
| 556 | .arena = continue_scope.arena, | ||
| 557 | .instructions = .{}, | ||
| 558 | }; | ||
| 559 | defer else_scope.instructions.deinit(mod.gpa); | ||
| 560 | |||
| 561 | if (while_node.@"else") |else_node| { | ||
| 562 | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); | ||
| 563 | if (!else_result.tag.isNoReturn()) { | ||
| 564 | const else_src = tree.token_locs[else_node.body.lastToken()].start; | ||
| 565 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ | ||
| 566 | .block = while_block, | ||
| 567 | .operand = else_result, | ||
| 568 | }, .{}); | ||
| 569 | } | ||
| 570 | } else { | ||
| 571 | const else_src = tree.token_locs[while_node.lastToken()].start; | ||
| 572 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ | ||
| 573 | .block = while_block, | ||
| 574 | }, .{}); | ||
| 575 | } | ||
| 576 | condbr.positionals.else_body = .{ | ||
| 577 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), | ||
| 578 | }; | ||
| 579 | return &while_block.base; | ||
| 580 | } | ||
| 581 | |||
| 457 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 582 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 458 | const tree = scope.tree(); | 583 | const tree = scope.tree(); |
| 459 | const src = tree.token_locs[cfe.ltoken].start; | 584 | const src = tree.token_locs[cfe.ltoken].start; |
| ... | @@ -1094,6 +1219,15 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr | ... | @@ -1094,6 +1219,15 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr |
| 1094 | } | 1219 | } |
| 1095 | } | 1220 | } |
| 1096 | 1221 | ||
| 1222 | fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, result: void) InnerError!*zir.Inst { | ||
| 1223 | const src = scope.tree().token_locs[node.firstToken()].start; | ||
| 1224 | const void_inst = try addZIRInstConst(mod, scope, src, .{ | ||
| 1225 | .ty = Type.initTag(.void), | ||
| 1226 | .val = Value.initTag(.void_value), | ||
| 1227 | }); | ||
| 1228 | return rlWrap(mod, scope, rl, void_inst); | ||
| 1229 | } | ||
| 1230 | |||
| 1097 | pub fn addZIRInstSpecial( | 1231 | pub fn addZIRInstSpecial( |
| 1098 | mod: *Module, | 1232 | mod: *Module, |
| 1099 | scope: *Scope, | 1233 | scope: *Scope, |
| ... | @@ -1211,3 +1345,9 @@ pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module | ... | @@ -1211,3 +1345,9 @@ pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module |
| 1211 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; | 1345 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; |
| 1212 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); | 1346 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Block, P{ .body = body }, .{}); |
| 1213 | } | 1347 | } |
| 1348 | |||
| 1349 | /// TODO The existence of this function is a workaround for a bug in stage1. | ||
| 1350 | pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop { | ||
| 1351 | const P = std.meta.fieldInfo(zir.Inst.Loop, "positionals").field_type; | ||
| 1352 | return addZIRInstSpecial(mod, scope, src, zir.Inst.Loop, P{ .body = body }, .{}); | ||
| 1353 | } |
src-self-hosted/codegen.zig+7| ... | @@ -23,6 +23,8 @@ pub const BlockData = struct { | ... | @@ -23,6 +23,8 @@ pub const BlockData = struct { |
| 23 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, | 23 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | pub const LoopData = struct { }; | ||
| 27 | |||
| 26 | pub const Reloc = union(enum) { | 28 | pub const Reloc = union(enum) { |
| 27 | /// The value is an offset into the `Function` `code` from the beginning. | 29 | /// The value is an offset into the `Function` `code` from the beginning. |
| 28 | /// To perform the reloc, write 32-bit signed little-endian integer | 30 | /// To perform the reloc, write 32-bit signed little-endian integer |
| ... | @@ -657,6 +659,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -657,6 +659,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 657 | .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?), | 659 | .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?), |
| 658 | .isnull => return self.genIsNull(inst.castTag(.isnull).?), | 660 | .isnull => return self.genIsNull(inst.castTag(.isnull).?), |
| 659 | .load => return self.genLoad(inst.castTag(.load).?), | 661 | .load => return self.genLoad(inst.castTag(.load).?), |
| 662 | .loop => return self.genLoop(inst.castTag(.loop).?), | ||
| 660 | .not => return self.genNot(inst.castTag(.not).?), | 663 | .not => return self.genNot(inst.castTag(.not).?), |
| 661 | .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?), | 664 | .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?), |
| 662 | .ref => return self.genRef(inst.castTag(.ref).?), | 665 | .ref => return self.genRef(inst.castTag(.ref).?), |
| ... | @@ -1346,6 +1349,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1346,6 +1349,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1346 | } | 1349 | } |
| 1347 | } | 1350 | } |
| 1348 | 1351 | ||
| 1352 | fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue { | ||
| 1353 | return self.fail(inst.base.src, "TODO codegen loop", .{}); | ||
| 1354 | } | ||
| 1355 | |||
| 1349 | fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue { | 1356 | fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue { |
| 1350 | if (inst.base.ty.hasCodeGenBits()) { | 1357 | if (inst.base.ty.hasCodeGenBits()) { |
| 1351 | return self.fail(inst.base.src, "TODO codegen Block with non-void type", .{}); | 1358 | return self.fail(inst.base.src, "TODO codegen Block with non-void type", .{}); |
src-self-hosted/ir.zig+19| ... | @@ -70,6 +70,7 @@ pub const Inst = struct { | ... | @@ -70,6 +70,7 @@ pub const Inst = struct { |
| 70 | isnull, | 70 | isnull, |
| 71 | /// Read a value from a pointer. | 71 | /// Read a value from a pointer. |
| 72 | load, | 72 | load, |
| 73 | loop, | ||
| 73 | ptrtoint, | 74 | ptrtoint, |
| 74 | ref, | 75 | ref, |
| 75 | ret, | 76 | ret, |
| ... | @@ -122,6 +123,7 @@ pub const Inst = struct { | ... | @@ -122,6 +123,7 @@ pub const Inst = struct { |
| 122 | .call => Call, | 123 | .call => Call, |
| 123 | .condbr => CondBr, | 124 | .condbr => CondBr, |
| 124 | .constant => Constant, | 125 | .constant => Constant, |
| 126 | .loop => Loop, | ||
| 125 | }; | 127 | }; |
| 126 | } | 128 | } |
| 127 | 129 | ||
| ... | @@ -401,6 +403,23 @@ pub const Inst = struct { | ... | @@ -401,6 +403,23 @@ pub const Inst = struct { |
| 401 | return null; | 403 | return null; |
| 402 | } | 404 | } |
| 403 | }; | 405 | }; |
| 406 | |||
| 407 | pub const Loop = struct { | ||
| 408 | pub const base_tag = Tag.loop; | ||
| 409 | |||
| 410 | base: Inst, | ||
| 411 | body: Body, | ||
| 412 | /// This memory is reserved for codegen code to do whatever it needs to here. | ||
| 413 | codegen: codegen.LoopData = .{}, | ||
| 414 | |||
| 415 | pub fn operandCount(self: *const Loop) usize { | ||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | pub fn getOperand(self: *const Loop, index: usize) ?*Inst { | ||
| 419 | return null; | ||
| 420 | } | ||
| 421 | }; | ||
| 422 | |||
| 404 | }; | 423 | }; |
| 405 | 424 | ||
| 406 | pub const Body = struct { | 425 | pub const Body = struct { |
src-self-hosted/link.zig-3| ... | @@ -1484,9 +1484,6 @@ pub const File = struct { | ... | @@ -1484,9 +1484,6 @@ pub const File = struct { |
| 1484 | assert(!self.shdr_table_dirty); | 1484 | assert(!self.shdr_table_dirty); |
| 1485 | assert(!self.shstrtab_dirty); | 1485 | assert(!self.shstrtab_dirty); |
| 1486 | assert(!self.debug_strtab_dirty); | 1486 | assert(!self.debug_strtab_dirty); |
| 1487 | assert(!self.offset_table_count_dirty); | ||
| 1488 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; | ||
| 1489 | assert(syms_sect.sh_info == self.local_symbols.items.len); | ||
| 1490 | } | 1487 | } |
| 1491 | 1488 | ||
| 1492 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { | 1489 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { |
src-self-hosted/zir.zig+75| ... | @@ -151,6 +151,8 @@ pub const Inst = struct { | ... | @@ -151,6 +151,8 @@ pub const Inst = struct { |
| 151 | isnonnull, | 151 | isnonnull, |
| 152 | /// Return a boolean true if an optional is null. `x == null` | 152 | /// Return a boolean true if an optional is null. `x == null` |
| 153 | isnull, | 153 | isnull, |
| 154 | /// A labeled block of code that loops forever. | ||
| 155 | loop, | ||
| 154 | /// Ambiguously remainder division or modulus. If the computation would possibly have | 156 | /// Ambiguously remainder division or modulus. If the computation would possibly have |
| 155 | /// a different value depending on whether the operation is remainder division or modulus, | 157 | /// a different value depending on whether the operation is remainder division or modulus, |
| 156 | /// a compile error is emitted. Otherwise the computation is performed. | 158 | /// a compile error is emitted. Otherwise the computation is performed. |
| ... | @@ -173,6 +175,8 @@ pub const Inst = struct { | ... | @@ -173,6 +175,8 @@ pub const Inst = struct { |
| 173 | /// the memory location is in the stack frame, local to the scope containing the | 175 | /// the memory location is in the stack frame, local to the scope containing the |
| 174 | /// instruction. | 176 | /// instruction. |
| 175 | ref, | 177 | ref, |
| 178 | /// Sends control flow back to the loop block operand. | ||
| 179 | repeat, | ||
| 176 | /// Obtains a pointer to the return value. | 180 | /// Obtains a pointer to the return value. |
| 177 | ret_ptr, | 181 | ret_ptr, |
| 178 | /// Obtains the return type of the in-scope function. | 182 | /// Obtains the return type of the in-scope function. |
| ... | @@ -279,7 +283,9 @@ pub const Inst = struct { | ... | @@ -279,7 +283,9 @@ pub const Inst = struct { |
| 279 | .declval_in_module => DeclValInModule, | 283 | .declval_in_module => DeclValInModule, |
| 280 | .coerce_result_block_ptr => CoerceResultBlockPtr, | 284 | .coerce_result_block_ptr => CoerceResultBlockPtr, |
| 281 | .compileerror => CompileError, | 285 | .compileerror => CompileError, |
| 286 | .loop => Loop, | ||
| 282 | .@"const" => Const, | 287 | .@"const" => Const, |
| 288 | .repeat => Repeat, | ||
| 283 | .str => Str, | 289 | .str => Str, |
| 284 | .int => Int, | 290 | .int => Int, |
| 285 | .inttype => IntType, | 291 | .inttype => IntType, |
| ... | @@ -372,10 +378,12 @@ pub const Inst = struct { | ... | @@ -372,10 +378,12 @@ pub const Inst = struct { |
| 372 | .breakvoid, | 378 | .breakvoid, |
| 373 | .condbr, | 379 | .condbr, |
| 374 | .compileerror, | 380 | .compileerror, |
| 381 | .repeat, | ||
| 375 | .@"return", | 382 | .@"return", |
| 376 | .returnvoid, | 383 | .returnvoid, |
| 377 | .unreach_nocheck, | 384 | .unreach_nocheck, |
| 378 | .@"unreachable", | 385 | .@"unreachable", |
| 386 | .loop, | ||
| 379 | => true, | 387 | => true, |
| 380 | }; | 388 | }; |
| 381 | } | 389 | } |
| ... | @@ -567,6 +575,16 @@ pub const Inst = struct { | ... | @@ -567,6 +575,16 @@ pub const Inst = struct { |
| 567 | kw_args: struct {}, | 575 | kw_args: struct {}, |
| 568 | }; | 576 | }; |
| 569 | 577 | ||
| 578 | pub const Repeat = struct { | ||
| 579 | pub const base_tag = Tag.repeat; | ||
| 580 | base: Inst, | ||
| 581 | |||
| 582 | positionals: struct { | ||
| 583 | loop: *Loop, | ||
| 584 | }, | ||
| 585 | kw_args: struct {}, | ||
| 586 | }; | ||
| 587 | |||
| 570 | pub const Str = struct { | 588 | pub const Str = struct { |
| 571 | pub const base_tag = Tag.str; | 589 | pub const base_tag = Tag.str; |
| 572 | base: Inst, | 590 | base: Inst, |
| ... | @@ -587,6 +605,16 @@ pub const Inst = struct { | ... | @@ -587,6 +605,16 @@ pub const Inst = struct { |
| 587 | kw_args: struct {}, | 605 | kw_args: struct {}, |
| 588 | }; | 606 | }; |
| 589 | 607 | ||
| 608 | pub const Loop = struct { | ||
| 609 | pub const base_tag = Tag.loop; | ||
| 610 | base: Inst, | ||
| 611 | |||
| 612 | positionals: struct { | ||
| 613 | body: Module.Body, | ||
| 614 | }, | ||
| 615 | kw_args: struct {}, | ||
| 616 | }; | ||
| 617 | |||
| 590 | pub const FieldPtr = struct { | 618 | pub const FieldPtr = struct { |
| 591 | pub const base_tag = Tag.fieldptr; | 619 | pub const base_tag = Tag.fieldptr; |
| 592 | base: Inst, | 620 | base: Inst, |
| ... | @@ -848,12 +876,14 @@ pub const Module = struct { | ... | @@ -848,12 +876,14 @@ pub const Module = struct { |
| 848 | .module = &self, | 876 | .module = &self, |
| 849 | .inst_table = InstPtrTable.init(allocator), | 877 | .inst_table = InstPtrTable.init(allocator), |
| 850 | .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator), | 878 | .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator), |
| 879 | .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator), | ||
| 851 | .arena = std.heap.ArenaAllocator.init(allocator), | 880 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 852 | .indent = 2, | 881 | .indent = 2, |
| 853 | }; | 882 | }; |
| 854 | defer write.arena.deinit(); | 883 | defer write.arena.deinit(); |
| 855 | defer write.inst_table.deinit(); | 884 | defer write.inst_table.deinit(); |
| 856 | defer write.block_table.deinit(); | 885 | defer write.block_table.deinit(); |
| 886 | defer write.loop_table.deinit(); | ||
| 857 | 887 | ||
| 858 | // First, build a map of *Inst to @ or % indexes | 888 | // First, build a map of *Inst to @ or % indexes |
| 859 | try write.inst_table.ensureCapacity(self.decls.len); | 889 | try write.inst_table.ensureCapacity(self.decls.len); |
| ... | @@ -882,6 +912,7 @@ const Writer = struct { | ... | @@ -882,6 +912,7 @@ const Writer = struct { |
| 882 | module: *const Module, | 912 | module: *const Module, |
| 883 | inst_table: InstPtrTable, | 913 | inst_table: InstPtrTable, |
| 884 | block_table: std.AutoHashMap(*Inst.Block, []const u8), | 914 | block_table: std.AutoHashMap(*Inst.Block, []const u8), |
| 915 | loop_table: std.AutoHashMap(*Inst.Loop, []const u8), | ||
| 885 | arena: std.heap.ArenaAllocator, | 916 | arena: std.heap.ArenaAllocator, |
| 886 | indent: usize, | 917 | indent: usize, |
| 887 | 918 | ||
| ... | @@ -962,6 +993,9 @@ const Writer = struct { | ... | @@ -962,6 +993,9 @@ const Writer = struct { |
| 962 | if (inst.cast(Inst.Block)) |block| { | 993 | if (inst.cast(Inst.Block)) |block| { |
| 963 | const name = try std.fmt.allocPrint(&self.arena.allocator, "label_{}", .{i}); | 994 | const name = try std.fmt.allocPrint(&self.arena.allocator, "label_{}", .{i}); |
| 964 | try self.block_table.put(block, name); | 995 | try self.block_table.put(block, name); |
| 996 | } else if (inst.cast(Inst.Loop)) |loop| { | ||
| 997 | const name = try std.fmt.allocPrint(&self.arena.allocator, "loop_{}", .{i}); | ||
| 998 | try self.loop_table.put(loop, name); | ||
| 965 | } | 999 | } |
| 966 | self.indent += 2; | 1000 | self.indent += 2; |
| 967 | try self.writeInstToStream(stream, inst); | 1001 | try self.writeInstToStream(stream, inst); |
| ... | @@ -980,6 +1014,10 @@ const Writer = struct { | ... | @@ -980,6 +1014,10 @@ const Writer = struct { |
| 980 | const name = self.block_table.get(param).?; | 1014 | const name = self.block_table.get(param).?; |
| 981 | return std.zig.renderStringLiteral(name, stream); | 1015 | return std.zig.renderStringLiteral(name, stream); |
| 982 | }, | 1016 | }, |
| 1017 | *Inst.Loop => { | ||
| 1018 | const name = self.loop_table.get(param).?; | ||
| 1019 | return std.zig.renderStringLiteral(name, stream); | ||
| 1020 | }, | ||
| 983 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), | 1021 | else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)), |
| 984 | } | 1022 | } |
| 985 | } | 1023 | } |
| ... | @@ -1016,8 +1054,10 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module | ... | @@ -1016,8 +1054,10 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module |
| 1016 | .decls = .{}, | 1054 | .decls = .{}, |
| 1017 | .unnamed_index = 0, | 1055 | .unnamed_index = 0, |
| 1018 | .block_table = std.StringHashMap(*Inst.Block).init(allocator), | 1056 | .block_table = std.StringHashMap(*Inst.Block).init(allocator), |
| 1057 | .loop_table = std.StringHashMap(*Inst.Loop).init(allocator), | ||
| 1019 | }; | 1058 | }; |
| 1020 | defer parser.block_table.deinit(); | 1059 | defer parser.block_table.deinit(); |
| 1060 | defer parser.loop_table.deinit(); | ||
| 1021 | errdefer parser.arena.deinit(); | 1061 | errdefer parser.arena.deinit(); |
| 1022 | 1062 | ||
| 1023 | parser.parseRoot() catch |err| switch (err) { | 1063 | parser.parseRoot() catch |err| switch (err) { |
| ... | @@ -1044,6 +1084,7 @@ const Parser = struct { | ... | @@ -1044,6 +1084,7 @@ const Parser = struct { |
| 1044 | error_msg: ?ErrorMsg = null, | 1084 | error_msg: ?ErrorMsg = null, |
| 1045 | unnamed_index: usize, | 1085 | unnamed_index: usize, |
| 1046 | block_table: std.StringHashMap(*Inst.Block), | 1086 | block_table: std.StringHashMap(*Inst.Block), |
| 1087 | loop_table: std.StringHashMap(*Inst.Loop), | ||
| 1047 | 1088 | ||
| 1048 | const Body = struct { | 1089 | const Body = struct { |
| 1049 | instructions: std.ArrayList(*Inst), | 1090 | instructions: std.ArrayList(*Inst), |
| ... | @@ -1255,6 +1296,8 @@ const Parser = struct { | ... | @@ -1255,6 +1296,8 @@ const Parser = struct { |
| 1255 | 1296 | ||
| 1256 | if (InstType == Inst.Block) { | 1297 | if (InstType == Inst.Block) { |
| 1257 | try self.block_table.put(inst_name, inst_specific); | 1298 | try self.block_table.put(inst_name, inst_specific); |
| 1299 | } else if (InstType == Inst.Loop) { | ||
| 1300 | try self.loop_table.put(inst_name, inst_specific); | ||
| 1258 | } | 1301 | } |
| 1259 | 1302 | ||
| 1260 | if (@hasField(InstType, "ty")) { | 1303 | if (@hasField(InstType, "ty")) { |
| ... | @@ -1366,6 +1409,10 @@ const Parser = struct { | ... | @@ -1366,6 +1409,10 @@ const Parser = struct { |
| 1366 | const name = try self.parseStringLiteral(); | 1409 | const name = try self.parseStringLiteral(); |
| 1367 | return self.block_table.get(name).?; | 1410 | return self.block_table.get(name).?; |
| 1368 | }, | 1411 | }, |
| 1412 | *Inst.Loop => { | ||
| 1413 | const name = try self.parseStringLiteral(); | ||
| 1414 | return self.loop_table.get(name).?; | ||
| 1415 | }, | ||
| 1369 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), | 1416 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), |
| 1370 | } | 1417 | } |
| 1371 | return self.fail("TODO parse parameter {}", .{@typeName(T)}); | 1418 | return self.fail("TODO parse parameter {}", .{@typeName(T)}); |
| ... | @@ -1431,8 +1478,10 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module { | ... | @@ -1431,8 +1478,10 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module { |
| 1431 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator), | 1478 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator), |
| 1432 | .indent = 0, | 1479 | .indent = 0, |
| 1433 | .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator), | 1480 | .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator), |
| 1481 | .loop_table = std.AutoHashMap(*ir.Inst.Loop, *Inst.Loop).init(allocator), | ||
| 1434 | }; | 1482 | }; |
| 1435 | defer ctx.block_table.deinit(); | 1483 | defer ctx.block_table.deinit(); |
| 1484 | defer ctx.loop_table.deinit(); | ||
| 1436 | defer ctx.decls.deinit(allocator); | 1485 | defer ctx.decls.deinit(allocator); |
| 1437 | defer ctx.names.deinit(); | 1486 | defer ctx.names.deinit(); |
| 1438 | defer ctx.primitive_table.deinit(); | 1487 | defer ctx.primitive_table.deinit(); |
| ... | @@ -1456,6 +1505,7 @@ const EmitZIR = struct { | ... | @@ -1456,6 +1505,7 @@ const EmitZIR = struct { |
| 1456 | primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl), | 1505 | primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl), |
| 1457 | indent: usize, | 1506 | indent: usize, |
| 1458 | block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block), | 1507 | block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block), |
| 1508 | loop_table: std.AutoHashMap(*ir.Inst.Loop, *Inst.Loop), | ||
| 1459 | 1509 | ||
| 1460 | fn emit(self: *EmitZIR) !void { | 1510 | fn emit(self: *EmitZIR) !void { |
| 1461 | // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced | 1511 | // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced |
| ... | @@ -1936,6 +1986,31 @@ const EmitZIR = struct { | ... | @@ -1936,6 +1986,31 @@ const EmitZIR = struct { |
| 1936 | break :blk &new_inst.base; | 1986 | break :blk &new_inst.base; |
| 1937 | }, | 1987 | }, |
| 1938 | 1988 | ||
| 1989 | .loop => blk: { | ||
| 1990 | const old_inst = inst.castTag(.loop).?; | ||
| 1991 | const new_inst = try self.arena.allocator.create(Inst.Loop); | ||
| 1992 | |||
| 1993 | try self.loop_table.put(old_inst, new_inst); | ||
| 1994 | |||
| 1995 | var loop_body = std.ArrayList(*Inst).init(self.allocator); | ||
| 1996 | defer loop_body.deinit(); | ||
| 1997 | |||
| 1998 | try self.emitBody(old_inst.body, inst_table, &loop_body); | ||
| 1999 | |||
| 2000 | new_inst.* = .{ | ||
| 2001 | .base = .{ | ||
| 2002 | .src = inst.src, | ||
| 2003 | .tag = Inst.Loop.base_tag, | ||
| 2004 | }, | ||
| 2005 | .positionals = .{ | ||
| 2006 | .body = .{ .instructions = loop_body.toOwnedSlice() }, | ||
| 2007 | }, | ||
| 2008 | .kw_args = .{}, | ||
| 2009 | }; | ||
| 2010 | |||
| 2011 | break :blk &new_inst.base; | ||
| 2012 | }, | ||
| 2013 | |||
| 1939 | .brvoid => blk: { | 2014 | .brvoid => blk: { |
| 1940 | const old_inst = inst.cast(ir.Inst.BrVoid).?; | 2015 | const old_inst = inst.cast(ir.Inst.BrVoid).?; |
| 1941 | const new_block = self.block_table.get(old_inst.block).?; | 2016 | const new_block = self.block_table.get(old_inst.block).?; |
src-self-hosted/zir_sema.zig+10| ... | @@ -60,6 +60,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -60,6 +60,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 60 | return mod.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int); | 60 | return mod.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int); |
| 61 | }, | 61 | }, |
| 62 | .inttype => return analyzeInstIntType(mod, scope, old_inst.castTag(.inttype).?), | 62 | .inttype => return analyzeInstIntType(mod, scope, old_inst.castTag(.inttype).?), |
| 63 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), | ||
| 64 | .repeat => return analyzeInstRepeat(mod, scope, old_inst.castTag(.repeat).?), | ||
| 63 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), | 65 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 64 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), | 66 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), |
| 65 | .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?), | 67 | .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?), |
| ... | @@ -424,6 +426,14 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!* | ... | @@ -424,6 +426,14 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!* |
| 424 | return mod.addArg(b, inst.base.src, param_type, name); | 426 | return mod.addArg(b, inst.base.src, param_type, name); |
| 425 | } | 427 | } |
| 426 | 428 | ||
| 429 | fn analyzeInstRepeat(mod: *Module, scope: *Scope, inst: *zir.Inst.Repeat) InnerError!*Inst { | ||
| 430 | return mod.fail(scope, inst.base.src, "TODO analyze .repeat ZIR", .{}); | ||
| 431 | } | ||
| 432 | |||
| 433 | fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst { | ||
| 434 | return mod.fail(scope, inst.base.src, "TODO analyze .loop ZIR", .{}); | ||
| 435 | } | ||
| 436 | |||
| 427 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | 437 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { |
| 428 | const parent_block = scope.cast(Scope.Block).?; | 438 | const parent_block = scope.cast(Scope.Block).?; |
| 429 | 439 |