fix: content inconsistencies in the vm
This commit is contained in:
parent
236acc7d60
commit
ecd6017673
6 changed files with 259 additions and 115 deletions
206
src/Sema.zig
206
src/Sema.zig
|
|
@ -154,6 +154,12 @@ pub fn deinit(sema: *Sema) void {
|
|||
sema.* = undefined;
|
||||
}
|
||||
|
||||
pub const Block = struct {
|
||||
parent_block: ?*Block,
|
||||
block_inst: Ir.Inst.Index,
|
||||
exit_label: usize,
|
||||
};
|
||||
|
||||
pub const Builder = struct {
|
||||
sema: *Sema,
|
||||
namespace: *Module.Namespace,
|
||||
|
|
@ -503,9 +509,12 @@ fn irBinaryOp(
|
|||
fn analyzeInlineBody(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
body: []const Ir.Inst.Index,
|
||||
) !ValueInfo {
|
||||
if (sema.analyzeBodyInner(builder, body, true)) |_| {} else |err| switch (err) {
|
||||
if (sema.analyzeBodyInner(builder, block, body, true)) |_| {
|
||||
// TODO: Do something.
|
||||
} else |err| switch (err) {
|
||||
error.ComptimeBreak => {},
|
||||
else => |e| return e,
|
||||
}
|
||||
|
|
@ -517,6 +526,7 @@ fn analyzeInlineBody(
|
|||
fn irLogicalOp(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
parent_block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
is_logical_or: bool,
|
||||
) InnerError!ValueInfo {
|
||||
|
|
@ -535,7 +545,14 @@ fn irLogicalOp(
|
|||
const value = ip.getOrPutBool(false);
|
||||
return .{ .value = value };
|
||||
}
|
||||
return try sema.analyzeInlineBody(builder, body);
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = parent_block,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
|
||||
return sema.analyzeInlineBody(builder, &block, body);
|
||||
}
|
||||
|
||||
const else_label = try builder.addLabel();
|
||||
|
|
@ -543,7 +560,13 @@ fn irLogicalOp(
|
|||
try builder.addFixup(if (is_logical_or) .jmp_t else .jmp_f, else_label);
|
||||
try builder.addByteOp(.pop);
|
||||
|
||||
const rhs = try sema.analyzeInlineBody(builder, body);
|
||||
var block: Block = .{
|
||||
.parent_block = parent_block,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
|
||||
const rhs = try sema.analyzeInlineBody(builder, &block, body);
|
||||
try builder.ensureLoad(rhs);
|
||||
builder.setLabel(else_label);
|
||||
return .none;
|
||||
|
|
@ -552,6 +575,7 @@ fn irLogicalOp(
|
|||
fn irDeclRef(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
inline_block: bool,
|
||||
) InnerError!ValueInfo {
|
||||
|
|
@ -562,7 +586,7 @@ fn irDeclRef(
|
|||
if (inline_block) {
|
||||
switch (ident.tag) {
|
||||
.knot, .stitch, .function => unreachable,
|
||||
.var_const => return sema.resolveGlobalDecl(builder, ip_index, src_loc),
|
||||
.var_const => return sema.resolveGlobalDecl(builder, block, ip_index, src_loc),
|
||||
.var_mut => return sema.fail(
|
||||
src_loc,
|
||||
"global variable assignments cannot refer to other variables",
|
||||
|
|
@ -621,7 +645,12 @@ fn irLoad(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!ValueI
|
|||
return .stack;
|
||||
}
|
||||
|
||||
fn irCondBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
||||
fn irCondBr(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
) InnerError!ValueInfo {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.CondBr, data.extra_index);
|
||||
const then_body = sema.ir.bodySlice(extra.end, extra.data.then_body_len);
|
||||
|
|
@ -633,36 +662,44 @@ fn irCondBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!Valu
|
|||
|
||||
try builder.addFixup(.jmp_f, else_label);
|
||||
try builder.addByteOp(.pop);
|
||||
_ = try analyzeBodyInner(sema, builder, then_body, false);
|
||||
|
||||
_ = try analyzeBodyInner(sema, builder, block, then_body, false);
|
||||
|
||||
try builder.addFixup(.jmp, end_label);
|
||||
builder.setLabel(else_label);
|
||||
try builder.addByteOp(.pop);
|
||||
|
||||
_ = try analyzeBodyInner(sema, builder, else_body, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, else_body, false);
|
||||
builder.setLabel(end_label);
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn irBreak(sema: *Sema, inst: Ir.Inst.Index) InnerError!void {
|
||||
_ = sema;
|
||||
_ = inst;
|
||||
}
|
||||
|
||||
fn irBreakInline(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.bin;
|
||||
const rvalue_inst = sema.resolveInst(data.rhs);
|
||||
return rvalue_inst;
|
||||
}
|
||||
|
||||
fn irBlock(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||
fn irBlock(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
parent_block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
) InnerError!void {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.Block, data.extra_index);
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = parent_block,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
|
||||
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||
builder.setLabel(block.exit_label);
|
||||
}
|
||||
|
||||
fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||
fn irSwitchBlock(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
parent_block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
) InnerError!void {
|
||||
const gpa = sema.gpa;
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.SwitchBr, data.extra_index);
|
||||
|
|
@ -675,7 +712,12 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
const condition = sema.resolveInst(extra.data.operand);
|
||||
if (condition != .none) try builder.ensureLoad(condition);
|
||||
|
||||
const exit_label = try builder.addLabel();
|
||||
var switch_block: Block = .{
|
||||
.parent_block = parent_block,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
|
||||
const cmp_var = builder.addStackSlot();
|
||||
try builder.addConstOp(.store, cmp_var);
|
||||
|
||||
|
|
@ -701,8 +743,8 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
|
||||
builder.setLabel(label_index);
|
||||
try builder.addByteOp(.pop);
|
||||
_ = try analyzeBodyInner(sema, builder, case_body, false);
|
||||
try builder.addFixup(.jmp, exit_label);
|
||||
_ = try analyzeBodyInner(sema, builder, &switch_block, case_body, false);
|
||||
try builder.addFixup(.jmp, switch_block.exit_label);
|
||||
}
|
||||
|
||||
const else_body = sema.ir.bodySlice(
|
||||
|
|
@ -711,8 +753,34 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
);
|
||||
|
||||
builder.setLabel(else_label);
|
||||
_ = try analyzeBodyInner(sema, builder, else_body, false);
|
||||
builder.setLabel(exit_label);
|
||||
_ = try analyzeBodyInner(sema, builder, &switch_block, else_body, false);
|
||||
builder.setLabel(switch_block.exit_label);
|
||||
}
|
||||
|
||||
fn irBreak(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
parent_block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
) InnerError!void {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.Break, data.extra_index).data;
|
||||
const target = extra.block_inst;
|
||||
|
||||
var current_block: ?*Block = parent_block;
|
||||
while (current_block) |block| : (current_block = block.parent_block) {
|
||||
if (block.block_inst == target) {
|
||||
try builder.addFixup(.jmp, block.exit_label);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return error.InvalidBreakTarget;
|
||||
}
|
||||
|
||||
fn irBreakInline(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.bin;
|
||||
const rvalue_inst = sema.resolveInst(data.rhs);
|
||||
return rvalue_inst;
|
||||
}
|
||||
|
||||
fn irContentPush(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||
|
|
@ -723,7 +791,12 @@ fn irContentPush(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError
|
|||
try builder.addByteOp(.stream_push);
|
||||
}
|
||||
|
||||
fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||
fn irChoiceBr(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
) InnerError!void {
|
||||
const gpa = sema.gpa;
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const choice_extra = sema.ir.extraData(Ir.Inst.ChoiceBr, data.extra_index);
|
||||
|
|
@ -748,8 +821,8 @@ fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
branch_labels.appendAssumeCapacity(case_label);
|
||||
|
||||
try builder.addByteOp(.stream_mark);
|
||||
_ = try analyzeBodyInner(sema, builder, lhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, mhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, lhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, mhs_slice, false);
|
||||
try builder.addFixupAbsolute(.br_push, case_label);
|
||||
}
|
||||
|
||||
|
|
@ -779,10 +852,10 @@ fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
|
||||
builder.setLabel(label);
|
||||
|
||||
_ = try analyzeBodyInner(sema, builder, lhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, rhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, lhs_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, rhs_slice, false);
|
||||
try builder.addByteOp(.stream_line);
|
||||
_ = try analyzeBodyInner(sema, builder, body_slice, false);
|
||||
_ = try analyzeBodyInner(sema, builder, block, body_slice, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -804,6 +877,7 @@ fn irImplicitRet(_: *Sema, builder: *Builder, _: Ir.Inst.Index) InnerError!void
|
|||
},
|
||||
.function => {
|
||||
try builder.addByteOp(.stream_glue);
|
||||
try builder.addByteOp(.nil);
|
||||
try builder.addByteOp(.ret);
|
||||
},
|
||||
}
|
||||
|
|
@ -812,6 +886,7 @@ fn irImplicitRet(_: *Sema, builder: *Builder, _: Ir.Inst.Index) InnerError!void
|
|||
fn irCall(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
comptime kind: enum { direct, field },
|
||||
) !ValueInfo {
|
||||
|
|
@ -853,7 +928,7 @@ fn irCall(
|
|||
const arg_end = sema.ir.extra[extra.end + i];
|
||||
defer arg_start = arg_end;
|
||||
const arg_body = body[arg_start..arg_end];
|
||||
const arg_value = try sema.analyzeInlineBody(builder, @ptrCast(arg_body));
|
||||
const arg_value = try sema.analyzeInlineBody(builder, block, @ptrCast(arg_body));
|
||||
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
||||
}
|
||||
try builder.addConstOp(.call, @intCast(args_len));
|
||||
|
|
@ -863,6 +938,7 @@ fn irCall(
|
|||
fn irDivert(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
inst: Ir.Inst.Index,
|
||||
comptime kind: enum { direct, field },
|
||||
) !void {
|
||||
|
|
@ -874,6 +950,7 @@ fn irDivert(
|
|||
const extra = sema.ir.extraData(ExtraType, data.extra_index);
|
||||
const body = sema.ir.extra[extra.end..];
|
||||
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
|
||||
|
||||
switch (kind) {
|
||||
.direct => {
|
||||
const callee = sema.resolveInst(extra.data.callee);
|
||||
|
|
@ -904,7 +981,7 @@ fn irDivert(
|
|||
const arg_end = sema.ir.extra[extra.end + i];
|
||||
defer arg_start = arg_end;
|
||||
const arg_body = body[arg_start..arg_end];
|
||||
const arg_value = try analyzeBodyInner(sema, builder, @ptrCast(arg_body), false);
|
||||
const arg_value = try analyzeBodyInner(sema, builder, block, @ptrCast(arg_body), false);
|
||||
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
||||
}
|
||||
try builder.addConstOp(.divert, @intCast(args_len));
|
||||
|
|
@ -987,6 +1064,7 @@ fn analyzeDivertTarget(
|
|||
fn analyzeBodyInner(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
body: []const Ir.Inst.Index,
|
||||
inline_block: bool,
|
||||
) InnerError!ValueInfo {
|
||||
|
|
@ -1016,15 +1094,15 @@ fn analyzeBodyInner(
|
|||
.mod => try irBinaryOp(sema, builder, inst, .mod),
|
||||
.neg => try irUnaryOp(sema, builder, inst, .neg),
|
||||
.not => try irUnaryOp(sema, builder, inst, .not),
|
||||
.bool_br_and => try irLogicalOp(sema, builder, inst, false),
|
||||
.bool_br_or => try irLogicalOp(sema, builder, inst, true),
|
||||
.bool_br_and => try irLogicalOp(sema, builder, block, inst, false),
|
||||
.bool_br_or => try irLogicalOp(sema, builder, block, inst, true),
|
||||
.cmp_eq => try irBinaryOp(sema, builder, inst, .cmp_eq),
|
||||
.cmp_neq => try irBinaryOp(sema, builder, inst, .cmp_neq),
|
||||
.cmp_lt => try irBinaryOp(sema, builder, inst, .cmp_lt),
|
||||
.cmp_lte => try irBinaryOp(sema, builder, inst, .cmp_lte),
|
||||
.cmp_gt => try irBinaryOp(sema, builder, inst, .cmp_gt),
|
||||
.cmp_gte => try irBinaryOp(sema, builder, inst, .cmp_gte),
|
||||
.decl_ref => try irDeclRef(sema, builder, inst, inline_block),
|
||||
.decl_ref => try irDeclRef(sema, builder, block, inst, inline_block),
|
||||
.ret => {
|
||||
try irRet(sema, builder, inst);
|
||||
continue;
|
||||
|
|
@ -1033,9 +1111,9 @@ fn analyzeBodyInner(
|
|||
try irImplicitRet(sema, builder, inst);
|
||||
continue;
|
||||
},
|
||||
.condbr => try irCondBr(sema, builder, inst),
|
||||
.condbr => try irCondBr(sema, builder, block, inst),
|
||||
.@"break" => {
|
||||
try irBreak(sema, inst);
|
||||
try irBreak(sema, builder, block, inst);
|
||||
continue;
|
||||
},
|
||||
.break_inline => {
|
||||
|
|
@ -1043,7 +1121,7 @@ fn analyzeBodyInner(
|
|||
return error.ComptimeBreak;
|
||||
},
|
||||
.block => {
|
||||
try irBlock(sema, builder, inst);
|
||||
try irBlock(sema, builder, block, inst);
|
||||
continue;
|
||||
},
|
||||
.content_push => {
|
||||
|
|
@ -1059,21 +1137,21 @@ fn analyzeBodyInner(
|
|||
continue;
|
||||
},
|
||||
.choice_br => {
|
||||
try irChoiceBr(sema, builder, inst);
|
||||
try irChoiceBr(sema, builder, block, inst);
|
||||
continue;
|
||||
},
|
||||
.switch_br => {
|
||||
try irSwitchBr(sema, builder, inst);
|
||||
try irSwitchBlock(sema, builder, block, inst);
|
||||
continue;
|
||||
},
|
||||
.call => try irCall(sema, builder, inst, .direct),
|
||||
.field_call => try irCall(sema, builder, inst, .field),
|
||||
.call => try irCall(sema, builder, block, inst, .direct),
|
||||
.field_call => try irCall(sema, builder, block, inst, .field),
|
||||
.divert => {
|
||||
try irDivert(sema, builder, inst, .direct);
|
||||
try irDivert(sema, builder, block, inst, .direct);
|
||||
continue;
|
||||
},
|
||||
.field_divert => {
|
||||
try irDivert(sema, builder, inst, .field);
|
||||
try irDivert(sema, builder, block, inst, .field);
|
||||
continue;
|
||||
},
|
||||
.field_ptr => try irFieldPtr(sema, builder, inst),
|
||||
|
|
@ -1095,7 +1173,13 @@ pub fn analyzeStitch(
|
|||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.Stitch, data.extra_index);
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = null,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||
}
|
||||
|
||||
// TODO: No diverts allowed.
|
||||
|
|
@ -1107,7 +1191,13 @@ pub fn analyzeFunction(
|
|||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.Function, data.extra_index);
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = null,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||
}
|
||||
|
||||
// TODO: No return allowed.
|
||||
|
|
@ -1119,7 +1209,13 @@ pub fn analyzeKnot(
|
|||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.Knot, data.extra_index);
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = null,
|
||||
.exit_label = try builder.addLabel(),
|
||||
.block_inst = inst,
|
||||
};
|
||||
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||
}
|
||||
|
||||
fn analyzeNestedDecl(
|
||||
|
|
@ -1255,6 +1351,7 @@ fn scanTopLevelDecl(
|
|||
fn resolveGlobalDecl(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
block: *Block,
|
||||
decl_name: InternPool.Index,
|
||||
src_loc: SrcLoc,
|
||||
) InnerError!ValueInfo {
|
||||
|
|
@ -1266,7 +1363,7 @@ fn resolveGlobalDecl(
|
|||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
|
||||
entry.resolution = .in_progress;
|
||||
const val = try sema.analyzeInlineBody(builder, body);
|
||||
const val = try sema.analyzeInlineBody(builder, block, body);
|
||||
entry.resolution = .{ .resolved = val };
|
||||
return val;
|
||||
},
|
||||
|
|
@ -1301,11 +1398,18 @@ pub fn scanTopLevelDecls(
|
|||
while (iter.next()) |entry| {
|
||||
const key = entry.key_ptr.*;
|
||||
const value = entry.value_ptr.*;
|
||||
|
||||
var block: Block = .{
|
||||
.parent_block = null,
|
||||
.block_inst = @enumFromInt(0),
|
||||
.exit_label = 0,
|
||||
};
|
||||
|
||||
switch (value.tag) {
|
||||
.var_mut, .var_const => {
|
||||
// TODO: Set a proper source offset for this.
|
||||
const src_loc: SrcLoc = .{ .src_offset = 0 };
|
||||
const result = try sema.resolveGlobalDecl(&builder, key, src_loc);
|
||||
const result = try sema.resolveGlobalDecl(&builder, &block, key, src_loc);
|
||||
const initial_value = sema.resolveValue(result).?;
|
||||
try sema.module.globals.append(gpa, .{
|
||||
.key = key,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue