feat: code generation for diverts, wip
This commit is contained in:
parent
ee26be6254
commit
20292bcc6a
5 changed files with 699 additions and 149 deletions
98
src/Sema.zig
98
src/Sema.zig
|
|
@ -19,9 +19,9 @@ const InnerError = error{
|
|||
};
|
||||
|
||||
const Ref = union(enum) {
|
||||
none,
|
||||
bool_true,
|
||||
bool_false,
|
||||
none,
|
||||
index: u32,
|
||||
constant: u32,
|
||||
global: u32,
|
||||
|
|
@ -64,11 +64,11 @@ fn addGlobal(sema: *Sema, name: Ir.NullTerminatedString) !Ref {
|
|||
fn getGlobal(sema: *Sema, name: Ir.NullTerminatedString) !Ref {
|
||||
const interned = try sema.getConstant(.{ .string = name });
|
||||
for (sema.ir.globals) |global| {
|
||||
if (name == global.name) {
|
||||
if (global.name == name) {
|
||||
return .{ .global = interned.constant };
|
||||
}
|
||||
}
|
||||
return sema.fail("unknown global variable");
|
||||
return fail(sema, "unknown global variable");
|
||||
}
|
||||
|
||||
fn irInteger(sema: *Sema, inst: Ir.Inst.Index) InnerError!Ref {
|
||||
|
|
@ -352,9 +352,7 @@ fn irDeclKnot(
|
|||
.sema = sema,
|
||||
.knot = &knot,
|
||||
};
|
||||
defer chunk.fixups.deinit(gpa);
|
||||
defer chunk.labels.deinit(gpa);
|
||||
defer chunk.inst_map.deinit(gpa);
|
||||
defer chunk.deinit(gpa);
|
||||
|
||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||
try blockBodyInner(sema, &chunk, body);
|
||||
|
|
@ -374,6 +372,63 @@ fn irDeclaration(sema: *Sema, parent_chunk: ?*Chunk, inst: Ir.Inst.Index) !void
|
|||
}
|
||||
}
|
||||
|
||||
fn irCall(_: *Sema, _: *Chunk, _: Ir.Inst.Index) !Ref {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn irDivert(
|
||||
sema: *Sema,
|
||||
chunk: *Chunk,
|
||||
inst: Ir.Inst.Index,
|
||||
comptime kind: enum { direct, field },
|
||||
) !void {
|
||||
const ExtraType = switch (kind) {
|
||||
.direct => Ir.Inst.Call,
|
||||
.field => Ir.Inst.FieldCall,
|
||||
};
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(ExtraType, data.payload_index);
|
||||
const args_len = extra.data.args_len;
|
||||
const body = sema.ir.extra[extra.end..];
|
||||
|
||||
const callee = switch (kind) {
|
||||
.direct => chunk.resolveInst(extra.data.callee),
|
||||
.field => chunk.resolveInst(extra.data.obj_ptr),
|
||||
};
|
||||
_ = try chunk.doLoad(callee);
|
||||
|
||||
var arg_start: u32 = args_len;
|
||||
var i: u32 = 0;
|
||||
while (i < args_len) : (i += 1) {
|
||||
const arg_end = sema.ir.extra[extra.end + i];
|
||||
defer arg_start = arg_end;
|
||||
const arg_body = body[arg_start..arg_end];
|
||||
try blockBodyInner(sema, chunk, @ptrCast(arg_body));
|
||||
// FIXME: hack
|
||||
{
|
||||
const last_inst: Ir.Inst.Index = @enumFromInt(arg_body[arg_body.len - 1]);
|
||||
const val = chunk.resolveInst(last_inst.toRef());
|
||||
_ = try chunk.doLoad(val);
|
||||
}
|
||||
}
|
||||
_ = try chunk.addConstOp(.divert, @intCast(args_len));
|
||||
}
|
||||
|
||||
fn irFieldPtr(_: *Sema, _: *Chunk, _: Ir.Inst.Index) !Ref {
|
||||
return .none;
|
||||
}
|
||||
|
||||
// TODO: Check for duplicate parameters.
|
||||
fn irParam(_: *Sema, chunk: *Chunk, _: Ir.Inst.Index) !Ref {
|
||||
//const data = sema.ir.instructions[@intFromEnum(inst)].data.string;
|
||||
const local_index = chunk.knot.stack_size;
|
||||
// TODO: Add constraints on how many temporaries we can have.
|
||||
// max(u8) or max(u16) are most likey appropriate.
|
||||
chunk.knot.arity += 1;
|
||||
chunk.knot.stack_size += 1;
|
||||
return .{ .local = local_index };
|
||||
}
|
||||
|
||||
fn blockBodyInner(sema: *Sema, chunk: *Chunk, body: []const Ir.Inst.Index) InnerError!void {
|
||||
const gpa = sema.gpa;
|
||||
|
||||
|
|
@ -433,6 +488,18 @@ fn blockBodyInner(sema: *Sema, chunk: *Chunk, body: []const Ir.Inst.Index) Inner
|
|||
continue;
|
||||
},
|
||||
.implicit_ret => try irImplicitRet(sema, chunk, inst),
|
||||
.call => try irCall(sema, chunk, inst),
|
||||
.divert => {
|
||||
try irDivert(sema, chunk, inst, .direct);
|
||||
continue;
|
||||
},
|
||||
.field_call => try irCall(sema, chunk, inst),
|
||||
.field_divert => {
|
||||
try irDivert(sema, chunk, inst, .field);
|
||||
continue;
|
||||
},
|
||||
.field_ptr => try irFieldPtr(sema, chunk, inst),
|
||||
.param => try irParam(sema, chunk, inst),
|
||||
};
|
||||
try chunk.inst_map.put(gpa, inst, ref);
|
||||
}
|
||||
|
|
@ -473,6 +540,12 @@ const Chunk = struct {
|
|||
code_offset: u32,
|
||||
};
|
||||
|
||||
fn deinit(chunk: *Chunk, gpa: std.mem.Allocator) void {
|
||||
chunk.fixups.deinit(gpa);
|
||||
chunk.labels.deinit(gpa);
|
||||
chunk.inst_map.deinit(gpa);
|
||||
}
|
||||
|
||||
fn addByteOp(chunk: *Chunk, op: Story.Opcode) error{OutOfMemory}!Ref {
|
||||
const gpa = chunk.sema.gpa;
|
||||
const bytecode = &chunk.knot.bytecode;
|
||||
|
|
@ -627,13 +700,13 @@ pub const CompiledStory = struct {
|
|||
pub fn buildRuntime(
|
||||
self: *CompiledStory,
|
||||
gpa: std.mem.Allocator,
|
||||
ir: Ir,
|
||||
ir: *Ir,
|
||||
story: *Story,
|
||||
) !void {
|
||||
const globals_len = self.globals.len + self.knots.len;
|
||||
const constants_pool = &story.constants_pool;
|
||||
try constants_pool.ensureUnusedCapacity(gpa, self.constants.len);
|
||||
try story.paths.ensureUnusedCapacity(gpa, self.knots.len);
|
||||
try story.globals.ensureUnusedCapacity(gpa, @intCast(self.globals.len));
|
||||
try story.globals.ensureUnusedCapacity(gpa, @intCast(globals_len));
|
||||
|
||||
for (self.constants) |constant| {
|
||||
switch (constant) {
|
||||
|
|
@ -656,15 +729,18 @@ pub const CompiledStory = struct {
|
|||
story.globals.putAssumeCapacity(name_bytes, null);
|
||||
}
|
||||
for (self.knots) |*knot| {
|
||||
const knot_name = ir.nullTerminatedString(knot.name);
|
||||
const runtime_chunk: *Object.ContentPath = try .create(story, .{
|
||||
.name = try .create(story, ir.nullTerminatedString(knot.name)),
|
||||
.name = try .create(story, knot_name),
|
||||
.arity = @intCast(knot.arity),
|
||||
.locals_count = @intCast(knot.stack_size - knot.arity),
|
||||
.const_pool = try knot.constants.toOwnedSlice(gpa),
|
||||
.bytes = try knot.bytecode.toOwnedSlice(gpa),
|
||||
});
|
||||
story.paths.appendAssumeCapacity(&runtime_chunk.base);
|
||||
story.globals.putAssumeCapacity(knot_name, &runtime_chunk.base);
|
||||
}
|
||||
story.string_bytes = ir.string_bytes;
|
||||
ir.string_bytes = &.{};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue