fix: call frame handling, logical short circuiting
This commit is contained in:
parent
5c133e5fa2
commit
236acc7d60
8 changed files with 301 additions and 159 deletions
80
src/Sema.zig
80
src/Sema.zig
|
|
@ -14,6 +14,7 @@ module: *compile.Module,
|
|||
ir: Ir,
|
||||
inst_map: std.AutoHashMapUnmanaged(Ir.Inst.Index, ValueInfo) = .empty,
|
||||
errors: *std.ArrayListUnmanaged(Module.Error),
|
||||
comptime_break_inst: Ir.Inst.Index = undefined,
|
||||
|
||||
const InnerError = error{
|
||||
OutOfMemory,
|
||||
|
|
@ -160,6 +161,10 @@ pub const Builder = struct {
|
|||
constants_map: std.AutoHashMapUnmanaged(InternPool.Index, u8) = .empty,
|
||||
labels: std.ArrayListUnmanaged(Label) = .empty,
|
||||
fixups: std.ArrayListUnmanaged(Fixup) = .empty,
|
||||
knot_tag: enum {
|
||||
knot,
|
||||
function,
|
||||
},
|
||||
|
||||
const Label = struct {
|
||||
code_offset: usize,
|
||||
|
|
@ -495,35 +500,50 @@ fn irBinaryOp(
|
|||
return .stack;
|
||||
}
|
||||
|
||||
fn analyzeInlineBody(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
body: []const Ir.Inst.Index,
|
||||
) !ValueInfo {
|
||||
if (sema.analyzeBodyInner(builder, body, true)) |_| {} else |err| switch (err) {
|
||||
error.ComptimeBreak => {},
|
||||
else => |e| return e,
|
||||
}
|
||||
const break_inst = sema.ir.instructions[@intFromEnum(sema.comptime_break_inst)];
|
||||
const extra = sema.ir.extraData(Ir.Inst.Break, break_inst.data.payload.extra_index).data;
|
||||
return sema.resolveInst(extra.operand);
|
||||
}
|
||||
|
||||
fn irLogicalOp(
|
||||
sema: *Sema,
|
||||
builder: *Builder,
|
||||
inst: Ir.Inst.Index,
|
||||
logical_or: bool,
|
||||
is_logical_or: bool,
|
||||
) InnerError!ValueInfo {
|
||||
const ip = &sema.module.intern_pool;
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.bin;
|
||||
const lhs = sema.resolveInst(data.lhs);
|
||||
const rhs = sema.resolveInst(data.rhs);
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.BoolBr, data.extra_index);
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
const lhs = sema.resolveInst(extra.data.lhs);
|
||||
|
||||
if (sema.resolveValue(lhs)) |lhs_info| {
|
||||
const lhs_value = lhs_info.unwrap(ip);
|
||||
if (sema.resolveValue(rhs)) |_| {
|
||||
return if (logical_or)
|
||||
if (lhs_value.isTruthy()) lhs else rhs
|
||||
else if (!lhs_value.isTruthy()) lhs else rhs;
|
||||
if (is_logical_or and lhs_value.bool) {
|
||||
const value = ip.getOrPutBool(true);
|
||||
return .{ .value = value };
|
||||
} else if (!is_logical_or and !lhs_value.bool) {
|
||||
const value = ip.getOrPutBool(false);
|
||||
return .{ .value = value };
|
||||
}
|
||||
|
||||
if (logical_or and lhs_value.isTruthy()) return lhs;
|
||||
if (!logical_or and !lhs_value.isTruthy()) return lhs;
|
||||
try builder.ensureLoad(rhs);
|
||||
return .none;
|
||||
return try sema.analyzeInlineBody(builder, body);
|
||||
}
|
||||
|
||||
const else_label = try builder.addLabel();
|
||||
try builder.ensureLoad(lhs);
|
||||
try builder.addFixup(if (logical_or) .jmp_t else .jmp_f, else_label);
|
||||
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);
|
||||
try builder.ensureLoad(rhs);
|
||||
builder.setLabel(else_label);
|
||||
return .none;
|
||||
|
|
@ -768,15 +788,25 @@ fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
|||
|
||||
fn irRet(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.un;
|
||||
if (data.lhs.toIndexAllowNone()) |index| {
|
||||
const value = sema.inst_map.get(index).?;
|
||||
if (value != .none) try builder.ensureLoad(value);
|
||||
const lhs = sema.resolveInst(data.lhs);
|
||||
if (lhs != .none) {
|
||||
try builder.ensureLoad(lhs);
|
||||
} else {
|
||||
try builder.addByteOp(.stream_glue);
|
||||
}
|
||||
try builder.addByteOp(.ret);
|
||||
}
|
||||
|
||||
fn irImplicitRet(_: *Sema, builder: *Builder, _: Ir.Inst.Index) InnerError!void {
|
||||
try builder.addByteOp(.exit);
|
||||
switch (builder.knot_tag) {
|
||||
.knot => {
|
||||
try builder.addByteOp(.exit);
|
||||
},
|
||||
.function => {
|
||||
try builder.addByteOp(.stream_glue);
|
||||
try builder.addByteOp(.ret);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn irCall(
|
||||
|
|
@ -823,7 +853,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 analyzeBodyInner(sema, builder, @ptrCast(arg_body), false);
|
||||
const arg_value = try sema.analyzeInlineBody(builder, @ptrCast(arg_body));
|
||||
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
||||
}
|
||||
try builder.addConstOp(.call, @intCast(args_len));
|
||||
|
|
@ -986,8 +1016,8 @@ fn analyzeBodyInner(
|
|||
.mod => try irBinaryOp(sema, builder, inst, .mod),
|
||||
.neg => try irUnaryOp(sema, builder, inst, .neg),
|
||||
.not => try irUnaryOp(sema, builder, inst, .not),
|
||||
.bool_and => try irLogicalOp(sema, builder, inst, false),
|
||||
.bool_or => try irLogicalOp(sema, builder, inst, true),
|
||||
.bool_br_and => try irLogicalOp(sema, builder, inst, false),
|
||||
.bool_br_or => try irLogicalOp(sema, builder, 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),
|
||||
|
|
@ -1008,7 +1038,10 @@ fn analyzeBodyInner(
|
|||
try irBreak(sema, inst);
|
||||
continue;
|
||||
},
|
||||
.break_inline => try irBreakInline(sema, inst),
|
||||
.break_inline => {
|
||||
sema.comptime_break_inst = inst;
|
||||
return error.ComptimeBreak;
|
||||
},
|
||||
.block => {
|
||||
try irBlock(sema, builder, inst);
|
||||
continue;
|
||||
|
|
@ -1233,7 +1266,7 @@ fn resolveGlobalDecl(
|
|||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
|
||||
entry.resolution = .in_progress;
|
||||
const val = try sema.analyzeBodyInner(builder, body, true);
|
||||
const val = try sema.analyzeInlineBody(builder, body);
|
||||
entry.resolution = .{ .resolved = val };
|
||||
return val;
|
||||
},
|
||||
|
|
@ -1260,6 +1293,7 @@ pub fn scanTopLevelDecls(
|
|||
.sema = sema,
|
||||
.code = undefined,
|
||||
.namespace = namespace,
|
||||
.knot_tag = .knot,
|
||||
};
|
||||
defer builder.deinit(gpa);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue