stage2: zir_sema for loops
Also remove the "repeat" instruction and make it implied to be at the end of a Loop body.master
parent
a9590f3bf8
commit
fc402bdbbb
|
@ -531,13 +531,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
|
|||
const cond_block = try addZIRInstBlock(mod, &loop_scope.base, while_src, .{
|
||||
.instructions = try loop_scope.arena.dupe(*zir.Inst, continue_scope.instructions.items),
|
||||
});
|
||||
// TODO avoid emitting the continue expr when there
|
||||
// are no jumps to it. This happens when the last statement of a while body is noreturn
|
||||
// and there are no `continue` statements.
|
||||
// The "repeat" at the end of a loop body is implied.
|
||||
if (while_node.continue_expr) |cont_expr| {
|
||||
const cont_expr_result = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);
|
||||
if (!cont_expr_result.tag.isNoReturn()) {
|
||||
_ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat);
|
||||
}
|
||||
} else {
|
||||
_ = try addZIRNoOp(mod, &loop_scope.base, while_src, .repeat);
|
||||
_ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);
|
||||
}
|
||||
const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{
|
||||
.instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),
|
||||
|
|
|
@ -151,7 +151,8 @@ pub const Inst = struct {
|
|||
isnonnull,
|
||||
/// Return a boolean true if an optional is null. `x == null`
|
||||
isnull,
|
||||
/// A labeled block of code that loops forever.
|
||||
/// A labeled block of code that loops forever. At the end of the body it is implied
|
||||
/// to repeat; no explicit "repeat" instruction terminates loop bodies.
|
||||
loop,
|
||||
/// Ambiguously remainder division or modulus. If the computation would possibly have
|
||||
/// a different value depending on whether the operation is remainder division or modulus,
|
||||
|
@ -175,8 +176,6 @@ pub const Inst = struct {
|
|||
/// the memory location is in the stack frame, local to the scope containing the
|
||||
/// instruction.
|
||||
ref,
|
||||
/// Sends control flow back to the loop block operand.
|
||||
repeat,
|
||||
/// Obtains a pointer to the return value.
|
||||
ret_ptr,
|
||||
/// Obtains the return type of the in-scope function.
|
||||
|
@ -294,7 +293,6 @@ pub const Inst = struct {
|
|||
.compileerror => CompileError,
|
||||
.loop => Loop,
|
||||
.@"const" => Const,
|
||||
.repeat => Repeat,
|
||||
.str => Str,
|
||||
.int => Int,
|
||||
.inttype => IntType,
|
||||
|
@ -390,7 +388,6 @@ pub const Inst = struct {
|
|||
.breakvoid,
|
||||
.condbr,
|
||||
.compileerror,
|
||||
.repeat,
|
||||
.@"return",
|
||||
.returnvoid,
|
||||
.unreach_nocheck,
|
||||
|
@ -587,16 +584,6 @@ pub const Inst = struct {
|
|||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const Repeat = struct {
|
||||
pub const base_tag = Tag.repeat;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
loop: *Loop,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const Str = struct {
|
||||
pub const base_tag = Tag.str;
|
||||
base: Inst,
|
||||
|
|
|
@ -61,7 +61,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
|||
},
|
||||
.inttype => return analyzeInstIntType(mod, scope, old_inst.castTag(.inttype).?),
|
||||
.loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?),
|
||||
.repeat => return analyzeInstRepeat(mod, scope, old_inst.castTag(.repeat).?),
|
||||
.param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?),
|
||||
.ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?),
|
||||
.fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?),
|
||||
|
@ -440,12 +439,38 @@ fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*
|
|||
return mod.addArg(b, inst.base.src, param_type, name);
|
||||
}
|
||||
|
||||
fn analyzeInstRepeat(mod: *Module, scope: *Scope, inst: *zir.Inst.Repeat) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO analyze .repeat ZIR", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO analyze .loop ZIR", .{});
|
||||
const parent_block = scope.cast(Scope.Block).?;
|
||||
|
||||
// Reserve space for a Loop instruction so that generated Break instructions can
|
||||
// point to it, even if it doesn't end up getting used because the code ends up being
|
||||
// comptime evaluated.
|
||||
const loop_inst = try parent_block.arena.create(Inst.Loop);
|
||||
loop_inst.* = .{
|
||||
.base = .{
|
||||
.tag = Inst.Loop.base_tag,
|
||||
.ty = Type.initTag(.noreturn),
|
||||
.src = inst.base.src,
|
||||
},
|
||||
.body = undefined,
|
||||
};
|
||||
|
||||
var child_block: Scope.Block = .{
|
||||
.parent = parent_block,
|
||||
.func = parent_block.func,
|
||||
.decl = parent_block.decl,
|
||||
.instructions = .{},
|
||||
.arena = parent_block.arena,
|
||||
};
|
||||
defer child_block.instructions.deinit(mod.gpa);
|
||||
|
||||
try analyzeBody(mod, &child_block.base, inst.positionals.body);
|
||||
|
||||
// Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
|
||||
|
||||
try parent_block.instructions.append(mod.gpa, &loop_inst.base);
|
||||
loop_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
|
||||
return &loop_inst.base;
|
||||
}
|
||||
|
||||
fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
|
||||
|
|
Loading…
Reference in New Issue