authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-13 11:03:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-13 20:32:32-07:00
logfc402bdbbbb5be2a538f0469f3f213264e7fcc59
tree4f3b85c10d1eef73deacfbe961c2c086ca1a65ed
parenta9590f3bf863493ed9b15ad8ab0d4fa7991805a5

stage2: zir_sema for loops

Also remove the "repeat" instruction and make it implied to be at the end of a Loop body.

3 files changed, 38 insertions(+), 27 deletions(-)

src-self-hosted/astgen.zig+5-6
...@@ -531,13 +531,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -531,13 +531,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
531 const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{531 const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{
532 .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items),532 .instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items),
533 });533 });
534 // TODO avoid emitting the continue expr when there
535 // are no jumps to it. This happens when the last statement of a while body is noreturn
536 // and there are no `continue` statements.
537 // The "repeat" at the end of a loop body is implied.
534 if (while_node.continue_expr) |cont_expr| {538 if (while_node.continue_expr) |cont_expr| {
535 const cont_expr_result = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);539 _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);
536 if (!cont_expr_result.tag.isNoReturn()) {
537 _ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat);
538 }
539 } else {
540 _ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat);
541 }540 }
542 const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{541 const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{
543 .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),542 .instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),
src-self-hosted/zir.zig+2-15
...@@ -151,7 +151,8 @@ pub const Inst = struct {...@@ -151,7 +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.154 /// A labeled block of code that loops forever. At the end of the body it is implied
155 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
155 loop,156 loop,
156 /// Ambiguously remainder division or modulus. If the computation would possibly have157 /// Ambiguously remainder division or modulus. If the computation would possibly have
157 /// a different value depending on whether the operation is remainder division or modulus,158 /// a different value depending on whether the operation is remainder division or modulus,
...@@ -175,8 +176,6 @@ pub const Inst = struct {...@@ -175,8 +176,6 @@ pub const Inst = struct {
175 /// the memory location is in the stack frame, local to the scope containing the176 /// the memory location is in the stack frame, local to the scope containing the
176 /// instruction.177 /// instruction.
177 ref,178 ref,
178 /// Sends control flow back to the loop block operand.
179 repeat,
180 /// Obtains a pointer to the return value.179 /// Obtains a pointer to the return value.
181 ret_ptr,180 ret_ptr,
182 /// Obtains the return type of the in-scope function.181 /// Obtains the return type of the in-scope function.
...@@ -294,7 +293,6 @@ pub const Inst = struct {...@@ -294,7 +293,6 @@ pub const Inst = struct {
294 .compileerror => CompileError,293 .compileerror => CompileError,
295 .loop => Loop,294 .loop => Loop,
296 .@"const" => Const,295 .@"const" => Const,
297 .repeat => Repeat,
298 .str => Str,296 .str => Str,
299 .int => Int,297 .int => Int,
300 .inttype => IntType,298 .inttype => IntType,
...@@ -390,7 +388,6 @@ pub const Inst = struct {...@@ -390,7 +388,6 @@ pub const Inst = struct {
390 .breakvoid,388 .breakvoid,
391 .condbr,389 .condbr,
392 .compileerror,390 .compileerror,
393 .repeat,
394 .@"return",391 .@"return",
395 .returnvoid,392 .returnvoid,
396 .unreach_nocheck,393 .unreach_nocheck,
...@@ -587,16 +584,6 @@ pub const Inst = struct {...@@ -587,16 +584,6 @@ pub const Inst = struct {
587 kw_args: struct {},584 kw_args: struct {},
588 };585 };
589586
590 pub const Repeat = struct {
591 pub const base_tag = Tag.repeat;
592 base: Inst,
593
594 positionals: struct {
595 loop: *Loop,
596 },
597 kw_args: struct {},
598 };
599
600 pub const Str = struct {587 pub const Str = struct {
601 pub const base_tag = Tag.str;588 pub const base_tag = Tag.str;
602 base: Inst,589 base: Inst,
src-self-hosted/zir_sema.zig+31-6
...@@ -61,7 +61,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -61,7 +61,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
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).?),63 .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?),
64 .repeat => return analyzeInstRepeat(mod, scope, old_inst.castTag(.repeat).?),
65 .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?),64 .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?),
66 .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?),65 .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?),
67 .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?),66 .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?),
...@@ -440,12 +439,38 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*...@@ -440,12 +439,38 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*
440 return mod.addArg(b, inst.base.src, param_type, name);439 return mod.addArg(b, inst.base.src, param_type, name);
441}440}
442441
443fn analyzeInstRepeat(mod: *Module, scope: *Scope, inst: *zir.Inst.Repeat) InnerError!*Inst {
444 return mod.fail(scope, inst.base.src, "TODO analyze .repeat ZIR", .{});
445}
446
447fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {442fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
448 return mod.fail(scope, inst.base.src, "TODO analyze .loop ZIR", .{});443 const parent_block = scope.cast(Scope.Block).?;
444
445 // Reserve space for a Loop instruction so that generated Break instructions can
446 // point to it, even if it doesn't end up getting used because the code ends up being
447 // comptime evaluated.
448 const loop_inst = try parent_block.arena.create(Inst.Loop);
449 loop_inst.* = .{
450 .base = .{
451 .tag = Inst.Loop.base_tag,
452 .ty = Type.initTag(.noreturn),
453 .src = inst.base.src,
454 },
455 .body = undefined,
456 };
457
458 var child_block: Scope.Block = .{
459 .parent = parent_block,
460 .func = parent_block.func,
461 .decl = parent_block.decl,
462 .instructions = .{},
463 .arena = parent_block.arena,
464 };
465 defer child_block.instructions.deinit(mod.gpa);
466
467 try analyzeBody(mod, &child_block.base, inst.positionals.body);
468
469 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
470
471 try parent_block.instructions.append(mod.gpa, &loop_inst.base);
472 loop_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
473 return &loop_inst.base;
449}474}
450475
451fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {476fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {