| author | |
| committer | |
| log | fc402bdbbbb5be2a538f0469f3f213264e7fcc59 |
| tree | 4f3b85c10d1eef73deacfbe961c2c086ca1a65ed |
| parent | a9590f3bf863493ed9b15ad8ab0d4fa7991805a5 |
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 | 531 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{ |
| 532 | 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 | 538 | if (while_node.continue_expr) |cont_expr| { |
| 535 | const cont_expr_result = 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); | |
| 539 | _ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr); | |
| 541 | 540 | } |
| 542 | 541 | const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{ |
| 543 | 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 | 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. | |
| 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 | 156 | loop, |
| 156 | 157 | /// Ambiguously remainder division or modulus. If the computation would possibly have |
| 157 | 158 | /// a different value depending on whether the operation is remainder division or modulus, |
| ... | ... | @@ -175,8 +176,6 @@ pub const Inst = struct { |
| 175 | 176 | /// the memory location is in the stack frame, local to the scope containing the |
| 176 | 177 | /// instruction. |
| 177 | 178 | ref, |
| 178 | /// Sends control flow back to the loop block operand. | |
| 179 | repeat, | |
| 180 | 179 | /// Obtains a pointer to the return value. |
| 181 | 180 | ret_ptr, |
| 182 | 181 | /// Obtains the return type of the in-scope function. |
| ... | ... | @@ -294,7 +293,6 @@ pub const Inst = struct { |
| 294 | 293 | .compileerror => CompileError, |
| 295 | 294 | .loop => Loop, |
| 296 | 295 | .@"const" => Const, |
| 297 | .repeat => Repeat, | |
| 298 | 296 | .str => Str, |
| 299 | 297 | .int => Int, |
| 300 | 298 | .inttype => IntType, |
| ... | ... | @@ -390,7 +388,6 @@ pub const Inst = struct { |
| 390 | 388 | .breakvoid, |
| 391 | 389 | .condbr, |
| 392 | 390 | .compileerror, |
| 393 | .repeat, | |
| 394 | 391 | .@"return", |
| 395 | 392 | .returnvoid, |
| 396 | 393 | .unreach_nocheck, |
| ... | ... | @@ -587,16 +584,6 @@ pub const Inst = struct { |
| 587 | 584 | kw_args: struct {}, |
| 588 | 585 | }; |
| 589 | 586 | |
| 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 | 587 | pub const Str = struct { |
| 601 | 588 | pub const base_tag = Tag.str; |
| 602 | 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 | 61 | }, |
| 62 | 62 | .inttype => return analyzeInstIntType(mod, scope, old_inst.castTag(.inttype).?), |
| 63 | 63 | .loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?), |
| 64 | .repeat => return analyzeInstRepeat(mod, scope, old_inst.castTag(.repeat).?), | |
| 65 | 64 | .param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?), |
| 66 | 65 | .ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?), |
| 67 | 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 | 439 | return mod.addArg(b, inst.base.src, param_type, name); |
| 441 | 440 | } |
| 442 | 441 | |
| 443 | fn 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 | ||
| 447 | 442 | fn 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 | } |
| 450 | 475 | |
| 451 | 476 | fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { |