Skip to content

Commit

Permalink
Fix value template expansion.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Aug 26, 2024
1 parent 4b31c55 commit d804987
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 27 deletions.
23 changes: 17 additions & 6 deletions src/bc_gen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,10 @@ pub fn prepareFunc(c: *cy.Compiler, opt_group: ?rt.FuncGroupId, func: *cy.Func)
if (opt_group) |group| {
_ = try addGroupFunc(c, group, func, rtFunc);
} else {
_ = try completeFunc(c, func, rtFunc);
const id = try reserveFunc(c, func);
if (c.vm.funcSyms.buf[id].type == .null) {
completeFunc(c, id, func, rtFunc);
}
}
},
.userFunc => {
Expand Down Expand Up @@ -291,10 +294,12 @@ fn reserveFunc(c: *cy.Compiler, func: *cy.Func) !u32 {
return res.value_ptr.func.id;
}

fn completeFunc(c: *cy.Compiler, func: *cy.Func, sym: rt.FuncSymbol) !u32 {
const id = try reserveFunc(c, func);
fn completeFunc(c: *cy.Compiler, id: u32, func: *cy.Func, sym: rt.FuncSymbol) void {
log.tracev("complete func gen: {s} {}", .{func.name(), id});
if (c.vm.funcSyms.buf[id].type != .null) {
std.debug.panic("Func already completed: {s} {}", .{func.name(), id});
}
c.vm.funcSyms.buf[id] = sym;
return id;
}

fn genChunk(c: *Chunk) !void {
Expand Down Expand Up @@ -553,6 +558,11 @@ pub fn funcBlock(c: *Chunk, idx: usize, node: *ast.Node) !void {
const data = c.ir.getStmtData(idx, .funcBlock);
const func = data.func;

// Skip if marked as skip (usually for one-off compile-time functions)
if (data.skip) {
return;
}

// Skip if func has already been generated by compile-time.
const id = try reserveFunc(c.compiler, func);
if (c.vm.funcSyms.buf[id].type != .null) {
Expand All @@ -570,7 +580,7 @@ pub fn funcBlock(c: *Chunk, idx: usize, node: *ast.Node) !void {
const stackSize = c.getMaxUsedRegisters();

const rt_func = rt.FuncSymbol.initFunc(funcPc, @intCast(stackSize), func.numParams, func.funcSigId, func.reqCallTypeCheck, func.isMethod());
c.vm.funcSyms.buf[id] = rt_func;
completeFunc(c.compiler, id, func, rt_func);
try popFuncBlockCommon(c, func);
}

Expand Down Expand Up @@ -3320,7 +3330,8 @@ fn genLambda(c: *Chunk, idx: usize, cstr: Cstr, node: *ast.Node) !GenValue {

const stackSize = c.getMaxUsedRegisters();
const rt_func = rt.FuncSymbol.initFunc(funcPc, @intCast(stackSize), func.numParams, func.funcSigId, func.reqCallTypeCheck, func.isMethod());
const rt_id = try completeFunc(c.compiler, func, rt_func);
const rt_id = try reserveFunc(c.compiler, func);
completeFunc(c.compiler, rt_id, func, rt_func);

try popFuncBlockCommon(c, func);
c.patchJumpToCurPc(skipJump);
Expand Down
56 changes: 37 additions & 19 deletions src/cte.zig
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub fn expandCtFuncTemplateOnCallArgs(c: *cy.Chunk, template: *cy.sym.Template,

try pushNodeValuesCstr(c, args, template, valueStart, node);
const arg_vals = c.valueStack.items[valueStart..];
return expandCtFuncTemplate(c, template, arg_vals);
return expandValueTemplate(c, template, arg_vals);
}

pub fn expandFuncTemplateOnCallArgs(c: *cy.Chunk, template: *cy.Func, args: []const *ast.Node, node: *ast.Node) !*cy.Func {
Expand Down Expand Up @@ -252,22 +252,33 @@ fn compileFuncDeep(c: *cy.Chunk, func: *cy.Func, queued: *std.AutoHashMapUnmanag
src_chunk.buf = &c.compiler.buf;
// TODO: defer restore bc state.
try bcgen.prepareFunc(src_chunk.compiler, null, func);
try bcgen.funcBlock(src_chunk, loc, loc_n);

// Analyze IR for func deps.
var visitor = try src_chunk.ir.visitStmt(c.alloc, @intCast(loc));
defer visitor.deinit();
while (try visitor.next()) |entry| {
if (entry.is_stmt) {
continue;
}
const code = src_chunk.ir.getExprCode(entry.loc);
switch (code) {
.call_sym => {
const data = src_chunk.ir.getExprData(entry.loc, .call_sym);
try compileFuncDeep(c, data.func, queued);
},
else => {},
switch (func.type) {
.hostFunc => {
// Nop. Already setup from `prepareFunc`.
},
.userFunc => {
try bcgen.funcBlock(src_chunk, loc, loc_n);

// Analyze IR for func deps.
var visitor = try src_chunk.ir.visitStmt(c.alloc, @intCast(loc));
defer visitor.deinit();
while (try visitor.next()) |entry| {
if (entry.is_stmt) {
continue;
}
const code = src_chunk.ir.getExprCode(entry.loc);
switch (code) {
.call_sym => {
const data = src_chunk.ir.getExprData(entry.loc, .call_sym);
try compileFuncDeep(c, data.func, queued);
},
else => {},
}
}
func.data = .{ .userFunc = .{ .loc = @intCast(loc) }};
},
else => {
return error.Unexpected;
}
}
func.emitted_deps = true;
Expand All @@ -292,7 +303,7 @@ pub fn callFunc(c: *cy.Chunk, func: *cy.Func, args: []const cy.Value) !CtValue {
};
}

pub fn expandCtFuncTemplate(c: *cy.Chunk, template: *cy.sym.Template, args: []const cy.Value) !CtValue {
pub fn expandValueTemplate(c: *cy.Chunk, template: *cy.sym.Template, args: []const cy.Value) !CtValue {
// Ensure variant type.
const res = try template.variant_cache.getOrPutContext(c.alloc, args, .{ .sema = c.sema });
if (!res.found_existing) {
Expand Down Expand Up @@ -328,7 +339,14 @@ pub fn expandCtFuncTemplate(c: *cy.Chunk, template: *cy.sym.Template, args: []co

// Generate ct func. Can assume not a `@host` func.
const func = try c.createFunc(.userFunc, @ptrCast(template), @ptrCast(template.decl.child_decl), false);
defer c.vm.alloc.destroy(func);
defer {
// Remove references to the func and invalidate the sema func block.
_ = c.compiler.genSymMap.remove(@ptrCast(func));
const src_chunk = func.chunk();
const data = src_chunk.ir.getStmtDataPtr(func.data.userFunc.loc, .funcBlock);
data.skip = true;
c.vm.alloc.destroy(func);
}
const func_sig = c.sema.getFuncSig(sig);
func.funcSigId = sig;
func.retType = func_sig.getRetType();
Expand Down
8 changes: 6 additions & 2 deletions src/ir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ pub const FuncBlock = struct {

// For methods only.
parentType: cy.TypeId,

/// Mark a func block to skip generation.
/// Useful for removing temporary compile-time functions.
skip: bool = false,
};

pub const PushBlock = struct {
Expand Down Expand Up @@ -795,7 +799,7 @@ pub const Buffer = struct {
}

pub fn pushEmptyExpr(self: *Buffer, comptime code: ExprCode, alloc: std.mem.Allocator, expr_t: ExprType, node_id: *ast.Node) !u32 {
log.tracev("irPushExpr: {}", .{code});
log.tracev("irPushExpr: {} at {}", .{code, self.buf.items.len});
const start = self.buf.items.len;
try self.buf.resize(alloc, self.buf.items.len + 1 + 8 + 4 + @sizeOf(ExprData(code)));
self.buf.items[start] = @intFromEnum(code);
Expand Down Expand Up @@ -908,7 +912,7 @@ pub const Buffer = struct {
}

pub fn pushEmptyStmt2(self: *Buffer, alloc: std.mem.Allocator, comptime code: StmtCode, node: *ast.Node, comptime appendToParent_: bool) !u32 {
log.tracev("irPushStmt: {}", .{code});
log.tracev("irPushStmt: {} at {}", .{code, self.buf.items.len});
const start: u32 = @intCast(self.buf.items.len);
try self.buf.resize(alloc, self.buf.items.len + 1 + 8 + 4 + @sizeOf(StmtData(code)));
self.buf.items[start] = @intFromEnum(code);
Expand Down
5 changes: 5 additions & 0 deletions src/sym.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,11 @@ pub const Func = struct {
vtable_idx: u32,
},
template: *FuncTemplate,
userFunc: struct {
/// Currently used to invalidate the IR func block when removing temporary functions.
/// See `cte.expandValueTemplate`.
loc: u32,
},
},
variant: ?*Variant,
reqCallTypeCheck: bool,
Expand Down

0 comments on commit d804987

Please sign in to comment.