Skip to content

Commit

Permalink
Support inferring static var type. Reimplement static var dependencies.
Browse files Browse the repository at this point in the history
  • Loading branch information
fubark committed Aug 28, 2024
1 parent eb077ae commit 9c98ad7
Show file tree
Hide file tree
Showing 18 changed files with 278 additions and 242 deletions.
4 changes: 2 additions & 2 deletions docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ func foo():
```
The `.` prefix is used to reference the current module's namespace.

Unlike local variables, static variables do not currently infer the type from the right hand side so a specific type must be specified or it will default to the `any` type:
A type specifier can be provided after the variable name, otherwise, it's inferred from the initializer:
```cy
var .my_map Map = Map{}
var .my_map any = Map{}
```

Since static variables are initialized outside of a fiber's execution flow, they can not reference any local variables:
Expand Down
54 changes: 39 additions & 15 deletions src/bc_gen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ fn genStmt(c: *Chunk, idx: u32) anyerror!void {
.forRangeStmt => try forRangeStmt(c, idx, node),
.funcBlock => try funcBlock(c, idx, node),
.ifStmt => try genIfStmt(c, idx, node),
.init_var_sym => try initVarSym(c, idx, node),
.loopStmt => try loopStmt(c, idx, node),
.mainBlock => try mainBlock(c, idx, node),
.block => try genBlock(c, idx, node),
Expand All @@ -374,7 +375,7 @@ fn genStmt(c: *Chunk, idx: u32) anyerror!void {
.setLocal => try irSetLocal(c, idx, node),
.set_field => try setField(c, idx, node),
.set_deref => try genSetDeref(c, idx, node),
.setVarSym => try setVarSym(c, idx, node),
.set_var_sym => try setVarSym(c, idx, node),
.switchStmt => try genSwitchStmt(c, idx, node),
.tryStmt => try genTryStmt(c, idx, node),
.verbose => try verbose(c, idx, node),
Expand Down Expand Up @@ -1944,7 +1945,7 @@ fn genVarSym(c: *Chunk, idx: usize, cstr: Cstr, node: *ast.Node) !GenValue {

const varId = c.compiler.genSymMap.get(data.sym).?.varSym.id;

const inst = try bc.selectForNoErrNoDepInst(c, cstr, ret_t, true, node);
const inst = try bc.selectForNoErrNoDepInst(c, cstr, ret_t, false, node);
if (inst.requiresPreRelease) {
try pushRelease(c, inst.dst, node);
}
Expand All @@ -1953,12 +1954,15 @@ fn genVarSym(c: *Chunk, idx: usize, cstr: Cstr, node: *ast.Node) !GenValue {
const pc = c.buf.len();
try c.buf.pushOp3(.staticVar, 0, 0, inst.dst);
c.buf.setOpArgU16(pc + 1, @intCast(varId));

if (inst.own_dst) {
try initSlot(c, inst.dst, true, node);
}

return finishNoErrNoDepInst(c, inst, true);
const boxed = !c.sema.isUnboxedType(ret_t);
if (boxed) {
try c.pushCode(.retain, &.{ inst.dst }, node);
}
return finishNoErrNoDepInst(c, inst, boxed);
}

fn genFuncPtr(c: *Chunk, idx: usize, cstr: Cstr, node: *ast.Node) !GenValue {
Expand Down Expand Up @@ -2091,13 +2095,25 @@ fn reserveFuncSlots(c: *Chunk, maxIrLocals: u8, numParamCopies: u8, params: []al
nextReg += numParamCopies;
}

fn setVarSym(c: *Chunk, idx: usize, node: *ast.Node) !void {
fn initVarSym(c: *Chunk, idx: usize, node: *ast.Node) !void {
_ = node;
const data = c.ir.getStmtData(idx, .setVarSym).generic;
const varSym = c.ir.getExprData(data.left, .varSym);
const data = c.ir.getStmtData(idx, .init_var_sym);

const id = c.compiler.genSymMap.get(varSym.sym).?.varSym.id;
_ = try genExpr(c, data.right, Cstr.toVarSym(id));
const ir_save = c.ir;
defer c.ir = ir_save;

c.ir = data.src_ir;
const id = c.compiler.genSymMap.get(data.sym).?.varSym.id;
_ = try genExpr(c, data.expr, Cstr.toVarSym(id, false));
}

fn setVarSym(c: *Chunk, idx: usize, node: *ast.Node) !void {
_ = node;
const data = c.ir.getStmtData(idx, .set_var_sym);
const id = c.compiler.genSymMap.get(data.sym).?.varSym.id;
const expr_t = c.ir.getExprType(data.expr).id;
const boxed = !c.sema.isUnboxedType(expr_t);
_ = try genExpr(c, data.expr, Cstr.toVarSym(id, boxed));
}

fn declareLocalInit(c: *Chunk, idx: u32, node: *ast.Node) !SlotId {
Expand Down Expand Up @@ -2673,13 +2689,15 @@ fn genToExactDesc(c: *Chunk, src: GenValue, dst: Cstr, node: *ast.Node, extraIdx
},
.varSym => {
const src_s = getSlot(c, src.reg);
if (src_s.boxed and src_s.type == .local) {
const from_boxed_local = src_s.boxed and src_s.type == .local;
const retain_to_dst = !src_s.boxed_retains and dst.data.varSym.retain;
if (from_boxed_local or retain_to_dst) {
try c.pushCode(.retain, &.{ src.reg }, node);
}

const pc = c.buf.len();
try c.pushCodeExt(.setStaticVar, &.{ 0, 0, src.reg }, node, extraIdx);
c.buf.setOpArgU16(pc + 1, @intCast(dst.data.varSym));
try c.pushCodeExt(.setStaticVar, &.{ 0, 0, src.reg, @intFromBool(src_s.boxed) }, node, extraIdx);
c.buf.setOpArgU16(pc + 1, @intCast(dst.data.varSym.id));

// Ownership was moved from temp.
try consumeTempValue(c, src, node);
Expand Down Expand Up @@ -4207,7 +4225,10 @@ pub const Cstr = struct {
releaseDst: bool,
},
// Runtime id.
varSym: u32,
varSym: struct {
id: u32,
retain: bool,
},
liftedLocal: struct {
reg: SlotId,
/// This shouldn't change after initialization.
Expand Down Expand Up @@ -4251,9 +4272,12 @@ pub const Cstr = struct {
}}};
}

pub fn toVarSym(id: u32) Cstr {
pub fn toVarSym(id: u32, retain: bool) Cstr {
return .{ .type = .varSym, .data = .{
.varSym = id
.varSym = .{
.id = id,
.retain = retain,
},
}};
}

Expand Down
5 changes: 3 additions & 2 deletions src/bytecode.zig
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,8 @@ pub fn dumpInst(vm: *cy.VM, pcOffset: u32, code: OpCode, pc: [*]const Inst, opts
.setStaticVar => {
const symId = @as(*const align(1) u16, @ptrCast(pc + 1)).*;
const src = pc[3].val;
len += try fmt.printCount(w, "vars[{}] = %{}", &.{v(symId), v(src)});
const release = pc[4].val == 1;
len += try fmt.printCount(w, "vars[{}] = %{}, release={}", &.{v(symId), v(src), v(release)});
},
.catch_op => {
const endOffset = @as(*const align(1) u16, @ptrCast(pc + 1)).*;
Expand Down Expand Up @@ -1019,7 +1020,6 @@ pub fn getInstLenAt(pc: [*]const Inst) u8 {
.constOp,
.constRetain,
.staticVar,
.setStaticVar,
.setField,
.jumpCond,
.compare,
Expand All @@ -1034,6 +1034,7 @@ pub fn getInstLenAt(pc: [*]const Inst) u8 {
const numExprs = pc[2].val;
return 4 + numExprs + 1;
},
.setStaticVar,
.func_union,
.typeCheck,
.field,
Expand Down
2 changes: 1 addition & 1 deletion src/cgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ pub fn gen(self: *cy.Compiler) !cy.compiler.AotCompileResult {
for (self.chunks.items, 0..) |chunk, i| {
chunks[i] = .{
.alloc = self.alloc,
.ir = chunk.ir,
.ir = chunk.own_ir,
.encoder = chunk.encoder,
.out = .{},
.outw = undefined,
Expand Down
55 changes: 12 additions & 43 deletions src/chunk.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub const Chunk = struct {
curNode: ?*ast.Node,

///
/// Sema pass
/// Sema pass.
///
semaProcs: std.ArrayListUnmanaged(sema.Proc),
semaBlocks: std.ArrayListUnmanaged(sema.Block),
Expand All @@ -66,7 +66,9 @@ pub const Chunk = struct {

valueStack: std.ArrayListUnmanaged(cy.Value),

ir: cy.ir.Buffer,
/// IR buffer can be swapped in, this will go away when migrating to `Worker`.
ir: *cy.ir.Buffer,
own_ir: cy.ir.Buffer,

/// Maps a IR local to a VM local.
genIrLocalMapStack: std.ArrayListUnmanaged(u8),
Expand All @@ -80,23 +82,12 @@ pub const Chunk = struct {
/// The slots in the front are reserved for the call convention and params.
slot_stack: std.ArrayListUnmanaged(bc.Slot),

/// Record other chunks that this chunk's static initializer depends on.
symInitChunkDeps: std.AutoHashMapUnmanaged(*cy.Chunk, void),

/// Local vars.
varStack: std.ArrayListUnmanaged(sema.LocalVar),
varShadowStack: std.ArrayListUnmanaged(cy.sema.VarShadow),
preLoopVarSaveStack: std.ArrayListUnmanaged(cy.sema.PreLoopVarSave),
assignedVarStack: std.ArrayListUnmanaged(sema.LocalVarId),

/// Which sema sym var is currently being analyzed for an assignment initializer.
curInitingSym: ?*cy.Sym,
curInitingSymDeps: std.AutoHashMapUnmanaged(*cy.Sym, void),

/// Currently used to store lists of static var dependencies.
symInitDeps: std.ArrayListUnmanaged(SymInitDep),
symInitInfos: std.AutoHashMapUnmanaged(*cy.Sym, SymInitInfo),

/// Main sema block id.
mainSemaProcId: sema.ProcId,

Expand Down Expand Up @@ -173,8 +164,6 @@ pub const Chunk = struct {
curHostVarIdx: u32,

hasStaticInit: bool,
initializerVisiting: bool,
initializerVisited: bool,

encoder: cy.ast.Encoder,

Expand Down Expand Up @@ -223,7 +212,8 @@ pub const Chunk = struct {
.preLoopVarSaveStack = .{},
.typeStack = .{},
.valueStack = .{},
.ir = cy.ir.Buffer.init(),
.ir = undefined,
.own_ir = cy.ir.Buffer.init(),
.slot_stack = .{},
.genIrLocalMapStack = .{},
.dataStack = .{},
Expand All @@ -237,11 +227,6 @@ pub const Chunk = struct {
.jitBuf = undefined,
.x64Enc = undefined,
.curNode = null,
.symInitDeps = .{},
.symInitInfos = .{},
.curInitingSym = null,
.curInitingSymDeps = .{},
.symInitChunkDeps = .{},
.tempBufU8 = .{},
.srcOwned = true,
.mainSemaProcId = cy.NullId,
Expand All @@ -258,8 +243,6 @@ pub const Chunk = struct {
.typeDeps = .{},
.typeDepsMap = .{},
.hasStaticInit = false,
.initializerVisited = false,
.initializerVisiting = false,
.encoder = undefined,
.nextUnnamedId = 1,
.indent = 0,
Expand All @@ -271,6 +254,7 @@ pub const Chunk = struct {
.host_types = .{},
.host_funcs = .{},
};
self.ir = &self.own_ir;
try self.parser.init(c.alloc);

if (cy.hasJIT) {
Expand Down Expand Up @@ -312,13 +296,9 @@ pub const Chunk = struct {
self.unwind_stack.deinit(self.alloc);
self.capVarDescs.deinit(self.alloc);

self.symInitDeps.deinit(self.alloc);
self.symInitInfos.deinit(self.alloc);
self.curInitingSymDeps.deinit(self.alloc);

self.typeStack.deinit(self.alloc);
self.valueStack.deinit(self.alloc);
self.ir.deinit(self.alloc);
self.own_ir.deinit(self.alloc);
self.dataStack.deinit(self.alloc);
self.dataU8Stack.deinit(self.alloc);
self.listDataStack.deinit(self.alloc);
Expand Down Expand Up @@ -416,7 +396,7 @@ pub const Chunk = struct {
}

pub inline fn isInStaticInitializer(self: *Chunk) bool {
return self.curInitingSym != null;
return self.compiler.svar_init_stack.items.len > 0;
}

pub inline fn semaBlockDepth(self: *Chunk) u32 {
Expand Down Expand Up @@ -691,16 +671,19 @@ pub const Chunk = struct {

/// An instruction that can fail (can throw or panic).
pub fn pushFCode(c: *Chunk, code: cy.OpCode, args: []const u8, node: *ast.Node) !void {
log.tracev("pushFCode: {s} {}", .{@tagName(code), c.buf.ops.items.len});
try c.pushFailableDebugSym(node);
try c.buf.pushOpSliceExt(code, args, null);
}

pub fn pushCode(c: *Chunk, code: cy.OpCode, args: []const u8, node: *ast.Node) !void {
log.tracev("pushCode: {s} {}", .{@tagName(code), c.buf.ops.items.len});
try c.pushOptionalDebugSym(node);
try c.buf.pushOpSliceExt(code, args, null);
}

pub fn pushCodeExt(c: *Chunk, code: cy.OpCode, args: []const u8, node: *ast.Node, desc: ?u32) !void {
log.tracev("pushCode: {s} {}", .{@tagName(code), c.buf.ops.items.len});
try c.pushOptionalDebugSym(node);
try c.buf.pushOpSliceExt(code, args, desc);
}
Expand Down Expand Up @@ -742,20 +725,6 @@ const ReservedTempLocal = struct {

const LocalId = u8;

pub const SymInitInfo = struct {
depStart: u32,
depEnd: u32,
irStart: u32,
irEnd: u32,
visiting: bool = false,
visited: bool = false,
};

const SymInitDep = struct {
sym: *cy.Sym,
refNodeId: *ast.Node,
};

pub const LLVM_Func = struct {
typeRef: llvm.TypeRef,
funcRef: llvm.ValueRef,
Expand Down
Loading

0 comments on commit 9c98ad7

Please sign in to comment.