authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-12 21:13:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-12 21:13:16-07:00
logde4f3f11f735708cf9ffe4bbdbbfa693b6b07916
treea5c68b84d6f8b9d69093bc9bafea5bf3ad112bcd
parent30db5b1fb23502de02650473ff8282b2875650a9

stage2: astgen for while loops

See #6021

6 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
48pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {48pub 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)),
6566
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}
456455
456fn 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
457fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {582fn 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}
10961221
1222fn 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
1097pub fn addZIRInstSpecial(1231pub 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.
1350pub 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};
2525
26pub const LoopData = struct { };
27
26pub const Reloc = union(enum) {28pub 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 integer30 /// 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 }
13481351
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 }
127129
...@@ -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};
405424
406pub const Body = struct {425pub 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 }
14911488
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 have156 /// 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 the175 /// 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 };
569577
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 };
589607
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();
857887
858 // First, build a map of *Inst to @ or % indexes888 // 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,
887918
...@@ -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();
10221062
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),
10471088
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 {
12551296
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 }
12591302
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),
14591509
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 introduced1511 // 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 },
19381988
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}
426428
429fn 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
433fn 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
427fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {437fn 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).?;
429439