| 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 | 48 | pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { |
| 49 | 49 | switch (node.tag) { |
| 50 | 50 | .VarDecl => unreachable, // Handled in `blockExpr`. |
| 51 | .Assign => unreachable, // Handled in `blockExpr`. | |
| 52 | .AssignBitAnd => unreachable, // Handled in `blockExpr`. | |
| 53 | .AssignBitOr => unreachable, // Handled in `blockExpr`. | |
| 54 | .AssignBitShiftLeft => unreachable, // Handled in `blockExpr`. | |
| 55 | .AssignBitShiftRight => unreachable, // Handled in `blockExpr`. | |
| 56 | .AssignBitXor => unreachable, // Handled in `blockExpr`. | |
| 57 | .AssignDiv => unreachable, // Handled in `blockExpr`. | |
| 58 | .AssignSub => unreachable, // Handled in `blockExpr`. | |
| 59 | .AssignSubWrap => unreachable, // Handled in `blockExpr`. | |
| 60 | .AssignMod => unreachable, // Handled in `blockExpr`. | |
| 61 | .AssignAdd => unreachable, // Handled in `blockExpr`. | |
| 62 | .AssignAddWrap => unreachable, // Handled in `blockExpr`. | |
| 63 | .AssignMul => unreachable, // Handled in `blockExpr`. | |
| 64 | .AssignMulWrap => unreachable, // Handled in `blockExpr`. | |
| 51 | ||
| 52 | .Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), | |
| 53 | .AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)), | |
| 54 | .AssignBitOr => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bitor)), | |
| 55 | .AssignBitShiftLeft => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), | |
| 56 | .AssignBitShiftRight => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), | |
| 57 | .AssignBitXor => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), | |
| 58 | .AssignDiv => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), | |
| 59 | .AssignSub => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), | |
| 60 | .AssignSubWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), | |
| 61 | .AssignMod => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), | |
| 62 | .AssignAdd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), | |
| 63 | .AssignAddWrap => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), | |
| 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 | 67 | .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), |
| 67 | 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 | 97 | .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), |
| 97 | 98 | .Return => return ret(mod, scope, node.castTag(.Return).?), |
| 98 | 99 | .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), |
| 100 | .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), | |
| 99 | 101 | .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)), |
| 100 | 102 | .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), |
| 101 | 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 | 129 | const var_decl_node = statement.castTag(.VarDecl).?; |
| 128 | 130 | scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); |
| 129 | 131 | }, |
| 130 | .Assign => { | |
| 131 | const ass = statement.castTag(.Assign).?; | |
| 132 | try assign(mod, scope, ass); | |
| 133 | }, | |
| 132 | .Assign => try assign(mod, scope, statement.castTag(.Assign).?), | |
| 134 | 133 | .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bitand), |
| 135 | 134 | .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bitor), |
| 136 | 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 | 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 | 582 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 458 | 583 | const tree = scope.tree(); |
| 459 | 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 | 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 | 1231 | pub fn addZIRInstSpecial( |
| 1098 | 1232 | mod: *Module, |
| 1099 | 1233 | scope: *Scope, |
| ... | ... | @@ -1211,3 +1345,9 @@ pub fn addZIRInstBlock(mod: *Module, scope: *Scope, src: usize, body: zir.Module |
| 1211 | 1345 | const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type; |
| 1212 | 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 | 23 | relocs: std.ArrayListUnmanaged(Reloc) = .{}, |
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | pub const LoopData = struct { }; | |
| 27 | ||
| 26 | 28 | pub const Reloc = union(enum) { |
| 27 | 29 | /// The value is an offset into the `Function` `code` from the beginning. |
| 28 | 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 | 659 | .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?), |
| 658 | 660 | .isnull => return self.genIsNull(inst.castTag(.isnull).?), |
| 659 | 661 | .load => return self.genLoad(inst.castTag(.load).?), |
| 662 | .loop => return self.genLoop(inst.castTag(.loop).?), | |
| 660 | 663 | .not => return self.genNot(inst.castTag(.not).?), |
| 661 | 664 | .ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?), |
| 662 | 665 | .ref => return self.genRef(inst.castTag(.ref).?), |
| ... | ... | @@ -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 | 1356 | fn genBlock(self: *Self, inst: *ir.Inst.Block) !MCValue { |
| 1350 | 1357 | if (inst.base.ty.hasCodeGenBits()) { |
| 1351 | 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 | 70 | isnull, |
| 71 | 71 | /// Read a value from a pointer. |
| 72 | 72 | load, |
| 73 | loop, | |
| 73 | 74 | ptrtoint, |
| 74 | 75 | ref, |
| 75 | 76 | ret, |
| ... | ... | @@ -122,6 +123,7 @@ pub const Inst = struct { |
| 122 | 123 | .call => Call, |
| 123 | 124 | .condbr => CondBr, |
| 124 | 125 | .constant => Constant, |
| 126 | .loop => Loop, | |
| 125 | 127 | }; |
| 126 | 128 | } |
| 127 | 129 | |
| ... | ... | @@ -401,6 +403,23 @@ pub const Inst = struct { |
| 401 | 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 | 425 | pub const Body = struct { |
src-self-hosted/link.zig-3| ... | ... | @@ -1484,9 +1484,6 @@ pub const File = struct { |
| 1484 | 1484 | assert(!self.shdr_table_dirty); |
| 1485 | 1485 | assert(!self.shstrtab_dirty); |
| 1486 | 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 | 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 | 151 | isnonnull, |
| 152 | 152 | /// Return a boolean true if an optional is null. `x == null` |
| 153 | 153 | isnull, |
| 154 | /// A labeled block of code that loops forever. | |
| 155 | loop, | |
| 154 | 156 | /// Ambiguously remainder division or modulus. If the computation would possibly have |
| 155 | 157 | /// a different value depending on whether the operation is remainder division or modulus, |
| 156 | 158 | /// a compile error is emitted. Otherwise the computation is performed. |
| ... | ... | @@ -173,6 +175,8 @@ pub const Inst = struct { |
| 173 | 175 | /// the memory location is in the stack frame, local to the scope containing the |
| 174 | 176 | /// instruction. |
| 175 | 177 | ref, |
| 178 | /// Sends control flow back to the loop block operand. | |
| 179 | repeat, | |
| 176 | 180 | /// Obtains a pointer to the return value. |
| 177 | 181 | ret_ptr, |
| 178 | 182 | /// Obtains the return type of the in-scope function. |
| ... | ... | @@ -279,7 +283,9 @@ pub const Inst = struct { |
| 279 | 283 | .declval_in_module => DeclValInModule, |
| 280 | 284 | .coerce_result_block_ptr => CoerceResultBlockPtr, |
| 281 | 285 | .compileerror => CompileError, |
| 286 | .loop => Loop, | |
| 282 | 287 | .@"const" => Const, |
| 288 | .repeat => Repeat, | |
| 283 | 289 | .str => Str, |
| 284 | 290 | .int => Int, |
| 285 | 291 | .inttype => IntType, |
| ... | ... | @@ -372,10 +378,12 @@ pub const Inst = struct { |
| 372 | 378 | .breakvoid, |
| 373 | 379 | .condbr, |
| 374 | 380 | .compileerror, |
| 381 | .repeat, | |
| 375 | 382 | .@"return", |
| 376 | 383 | .returnvoid, |
| 377 | 384 | .unreach_nocheck, |
| 378 | 385 | .@"unreachable", |
| 386 | .loop, | |
| 379 | 387 | => true, |
| 380 | 388 | }; |
| 381 | 389 | } |
| ... | ... | @@ -567,6 +575,16 @@ pub const Inst = struct { |
| 567 | 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 | 588 | pub const Str = struct { |
| 571 | 589 | pub const base_tag = Tag.str; |
| 572 | 590 | base: Inst, |
| ... | ... | @@ -587,6 +605,16 @@ pub const Inst = struct { |
| 587 | 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 | 618 | pub const FieldPtr = struct { |
| 591 | 619 | pub const base_tag = Tag.fieldptr; |
| 592 | 620 | base: Inst, |
| ... | ... | @@ -848,12 +876,14 @@ pub const Module = struct { |
| 848 | 876 | .module = &self, |
| 849 | 877 | .inst_table = InstPtrTable.init(allocator), |
| 850 | 878 | .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator), |
| 879 | .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator), | |
| 851 | 880 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 852 | 881 | .indent = 2, |
| 853 | 882 | }; |
| 854 | 883 | defer write.arena.deinit(); |
| 855 | 884 | defer write.inst_table.deinit(); |
| 856 | 885 | defer write.block_table.deinit(); |
| 886 | defer write.loop_table.deinit(); | |
| 857 | 887 | |
| 858 | 888 | // First, build a map of *Inst to @ or % indexes |
| 859 | 889 | try write.inst_table.ensureCapacity(self.decls.len); |
| ... | ... | @@ -882,6 +912,7 @@ const Writer = struct { |
| 882 | 912 | module: *const Module, |
| 883 | 913 | inst_table: InstPtrTable, |
| 884 | 914 | block_table: std.AutoHashMap(*Inst.Block, []const u8), |
| 915 | loop_table: std.AutoHashMap(*Inst.Loop, []const u8), | |
| 885 | 916 | arena: std.heap.ArenaAllocator, |
| 886 | 917 | indent: usize, |
| 887 | 918 | |
| ... | ... | @@ -962,6 +993,9 @@ const Writer = struct { |
| 962 | 993 | if (inst.cast(Inst.Block)) |block| { |
| 963 | 994 | const name = try std.fmt.allocPrint(&self.arena.allocator, "label_{}", .{i}); |
| 964 | 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 | 1000 | self.indent += 2; |
| 967 | 1001 | try self.writeInstToStream(stream, inst); |
| ... | ... | @@ -980,6 +1014,10 @@ const Writer = struct { |
| 980 | 1014 | const name = self.block_table.get(param).?; |
| 981 | 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 | 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 | 1054 | .decls = .{}, |
| 1017 | 1055 | .unnamed_index = 0, |
| 1018 | 1056 | .block_table = std.StringHashMap(*Inst.Block).init(allocator), |
| 1057 | .loop_table = std.StringHashMap(*Inst.Loop).init(allocator), | |
| 1019 | 1058 | }; |
| 1020 | 1059 | defer parser.block_table.deinit(); |
| 1060 | defer parser.loop_table.deinit(); | |
| 1021 | 1061 | errdefer parser.arena.deinit(); |
| 1022 | 1062 | |
| 1023 | 1063 | parser.parseRoot() catch |err| switch (err) { |
| ... | ... | @@ -1044,6 +1084,7 @@ const Parser = struct { |
| 1044 | 1084 | error_msg: ?ErrorMsg = null, |
| 1045 | 1085 | unnamed_index: usize, |
| 1046 | 1086 | block_table: std.StringHashMap(*Inst.Block), |
| 1087 | loop_table: std.StringHashMap(*Inst.Loop), | |
| 1047 | 1088 | |
| 1048 | 1089 | const Body = struct { |
| 1049 | 1090 | instructions: std.ArrayList(*Inst), |
| ... | ... | @@ -1255,6 +1296,8 @@ const Parser = struct { |
| 1255 | 1296 | |
| 1256 | 1297 | if (InstType == Inst.Block) { |
| 1257 | 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 | 1303 | if (@hasField(InstType, "ty")) { |
| ... | ... | @@ -1366,6 +1409,10 @@ const Parser = struct { |
| 1366 | 1409 | const name = try self.parseStringLiteral(); |
| 1367 | 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 | 1416 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), |
| 1370 | 1417 | } |
| 1371 | 1418 | return self.fail("TODO parse parameter {}", .{@typeName(T)}); |
| ... | ... | @@ -1431,8 +1478,10 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module { |
| 1431 | 1478 | .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator), |
| 1432 | 1479 | .indent = 0, |
| 1433 | 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 | 1483 | defer ctx.block_table.deinit(); |
| 1484 | defer ctx.loop_table.deinit(); | |
| 1436 | 1485 | defer ctx.decls.deinit(allocator); |
| 1437 | 1486 | defer ctx.names.deinit(); |
| 1438 | 1487 | defer ctx.primitive_table.deinit(); |
| ... | ... | @@ -1456,6 +1505,7 @@ const EmitZIR = struct { |
| 1456 | 1505 | primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl), |
| 1457 | 1506 | indent: usize, |
| 1458 | 1507 | block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block), |
| 1508 | loop_table: std.AutoHashMap(*ir.Inst.Loop, *Inst.Loop), | |
| 1459 | 1509 | |
| 1460 | 1510 | fn emit(self: *EmitZIR) !void { |
| 1461 | 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 | 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 | 2014 | .brvoid => blk: { |
| 1940 | 2015 | const old_inst = inst.cast(ir.Inst.BrVoid).?; |
| 1941 | 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 | 60 | return mod.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int); |
| 61 | 61 | }, |
| 62 | 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 | 65 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 64 | 66 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), |
| 65 | 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 | 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 | 437 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { |
| 428 | 438 | const parent_block = scope.cast(Scope.Block).?; |
| 429 | 439 |