ir
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -109,6 +109,8 @@ pub const Op = union(enum) {
|
||||
cmp_le: BinOp,
|
||||
cmp_gt: BinOp,
|
||||
cmp_ge: BinOp,
|
||||
str_eq: BinOp, // string/slice equality via memcmp
|
||||
str_ne: BinOp, // string/slice inequality via memcmp
|
||||
|
||||
// ── Logical ─────────────────────────────────────────────────────
|
||||
bool_and: BinOp, // short-circuit &&
|
||||
@@ -192,6 +194,7 @@ pub const Op = union(enum) {
|
||||
// ── Globals ─────────────────────────────────────────────────────
|
||||
global_get: GlobalId,
|
||||
global_set: GlobalSet,
|
||||
func_ref: FuncId, // reference to a function (for function pointers)
|
||||
|
||||
// ── Block params (SSA phi alternative) ──────────────────────────
|
||||
block_param: BlockParam,
|
||||
|
||||
@@ -318,6 +318,20 @@ pub const Interpreter = struct {
|
||||
.cmp_le => |b| return .{ .value = .{ .boolean = try self.evalCmp(frame, b, .le) } },
|
||||
.cmp_gt => |b| return .{ .value = .{ .boolean = try self.evalCmp(frame, b, .gt) } },
|
||||
.cmp_ge => |b| return .{ .value = .{ .boolean = try self.evalCmp(frame, b, .ge) } },
|
||||
.str_eq => |b| {
|
||||
const lhs = frame.getRef(b.lhs);
|
||||
const rhs = frame.getRef(b.rhs);
|
||||
const ls = if (lhs == .string) lhs.string else "";
|
||||
const rs = if (rhs == .string) rhs.string else "";
|
||||
return .{ .value = .{ .boolean = std.mem.eql(u8, ls, rs) } };
|
||||
},
|
||||
.str_ne => |b| {
|
||||
const lhs = frame.getRef(b.lhs);
|
||||
const rhs = frame.getRef(b.rhs);
|
||||
const ls = if (lhs == .string) lhs.string else "";
|
||||
const rs = if (rhs == .string) rhs.string else "";
|
||||
return .{ .value = .{ .boolean = !std.mem.eql(u8, ls, rs) } };
|
||||
},
|
||||
|
||||
// ── Logical ─────────────────────────────────────────
|
||||
.bool_and => |b| {
|
||||
@@ -824,6 +838,9 @@ pub const Interpreter = struct {
|
||||
const val = try self.getGlobal(gid);
|
||||
return .{ .value = val };
|
||||
},
|
||||
.func_ref => |fid| {
|
||||
return .{ .value = .{ .func_ref = fid } };
|
||||
},
|
||||
.global_set => |gs| {
|
||||
const val = frame.getRef(gs.value);
|
||||
self.global_values.put(gs.global.index(), val) catch {};
|
||||
|
||||
4792
src/ir/lower.zig
4792
src/ir/lower.zig
File diff suppressed because it is too large
Load Diff
@@ -219,7 +219,7 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
/// Emit an instruction with no meaningful result (terminators, stores).
|
||||
fn emitVoid(self: *Builder, op: Op, ty: TypeId) void {
|
||||
pub fn emitVoid(self: *Builder, op: Op, ty: TypeId) void {
|
||||
const block = self.currentBlock();
|
||||
self.inst_counter += 1;
|
||||
block.insts.append(self.module.alloc, .{ .op = op, .ty = ty }) catch unreachable;
|
||||
|
||||
@@ -167,6 +167,8 @@ fn printInst(instruction: *const Inst, ref_idx: u32, tt: *const TypeTable, write
|
||||
.cmp_le => |b| try writer.print("cmp_le %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
.cmp_gt => |b| try writer.print("cmp_gt %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
.cmp_ge => |b| try writer.print("cmp_ge %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
.str_eq => |b| try writer.print("str_eq %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
.str_ne => |b| try writer.print("str_ne %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
|
||||
// ── Logical ─────────────────────────────────────────────
|
||||
.bool_and => |b| try writer.print("bool_and %{d}, %{d} : ", .{ b.lhs.index(), b.rhs.index() }),
|
||||
@@ -359,6 +361,7 @@ fn printInst(instruction: *const Inst, ref_idx: u32, tt: *const TypeTable, write
|
||||
|
||||
// ── Globals ─────────────────────────────────────────────
|
||||
.global_get => |gid| try writer.print("global_get @{d} : ", .{gid.index()}),
|
||||
.func_ref => |fid| try writer.print("func_ref @{d} : ", .{@intFromEnum(fid)}),
|
||||
.global_set => |gs| {
|
||||
try writer.print("global_set @{d}, %{d}\n", .{ gs.global.index(), gs.value.index() });
|
||||
return;
|
||||
|
||||
@@ -17,6 +17,7 @@ pub fn resolveAstType(node: ?*const Node, table: *TypeTable) TypeId {
|
||||
const n = node orelse return .s64; // no annotation → default
|
||||
return switch (n.data) {
|
||||
.type_expr => |te| resolveTypeName(te.name, table),
|
||||
.identifier => |id| resolveTypeName(id.name, table),
|
||||
.array_type_expr => |at| resolveArrayType(&at, table),
|
||||
.slice_type_expr => |st| resolveSliceType(&st, table),
|
||||
.pointer_type_expr => |pt| resolvePointerType(&pt, table),
|
||||
@@ -31,7 +32,10 @@ pub fn resolveAstType(node: ?*const Node, table: *TypeTable) TypeId {
|
||||
.enum_decl => |ed| resolveInlineEnum(&ed, table),
|
||||
.struct_decl => |sd| resolveInlineStruct(&sd, table),
|
||||
.union_decl => |ud| resolveInlineUnion(&ud, table),
|
||||
else => .s64, // fallback for unknown nodes
|
||||
else => {
|
||||
std.debug.print("type_bridge: unhandled node type {s}\n", .{@tagName(n.data)});
|
||||
return .s64;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,6 +154,19 @@ fn resolveTypeName(name: []const u8, table: *TypeTable) TypeId {
|
||||
// Try primitive first
|
||||
if (resolveTypePrimitive(name)) |id| return id;
|
||||
|
||||
// Arbitrary bit-width integers: s1-s64, u1-u64
|
||||
if (name.len >= 2 and (name[0] == 's' or name[0] == 'u')) {
|
||||
if (std.fmt.parseInt(u8, name[1..], 10)) |width| {
|
||||
if (width >= 1 and width <= 64) {
|
||||
if (name[0] == 's') {
|
||||
return table.intern(.{ .signed = width });
|
||||
} else {
|
||||
return table.intern(.{ .unsigned = width });
|
||||
}
|
||||
}
|
||||
} else |_| {}
|
||||
}
|
||||
|
||||
// Sentinel-terminated slice: [:0]u8 → string
|
||||
if (name.len >= 5 and name[0] == '[' and name[1] == ':') {
|
||||
if (std.mem.indexOfScalar(u8, name, ']')) |close| {
|
||||
@@ -181,6 +198,8 @@ fn resolveTypeName(name: []const u8, table: *TypeTable) TypeId {
|
||||
|
||||
// Assume it's a named struct/enum/union type
|
||||
const name_id = table.internString(name);
|
||||
// Check if already registered (e.g., as a union from enum_decl)
|
||||
if (table.findByName(name_id)) |existing| return existing;
|
||||
return table.intern(.{ .@"struct" = .{ .name = name_id, .fields = &.{} } });
|
||||
}
|
||||
|
||||
@@ -201,7 +220,7 @@ pub fn resolveTypePrimitive(name: []const u8) ?TypeId {
|
||||
if (std.mem.eql(u8, name, "string")) return .string;
|
||||
if (std.mem.eql(u8, name, "void")) return .void;
|
||||
if (std.mem.eql(u8, name, "Any")) return .any;
|
||||
if (std.mem.eql(u8, name, "Type")) return .s64; // Type tags are runtime integers
|
||||
if (std.mem.eql(u8, name, "Type")) return .any; // Type-as-value: boxed string
|
||||
if (std.mem.eql(u8, name, "noreturn")) return .noreturn;
|
||||
return null;
|
||||
}
|
||||
@@ -276,8 +295,10 @@ fn resolveTupleType(tt: *const ast.TupleTypeExpr, table: *TypeTable) TypeId {
|
||||
}
|
||||
|
||||
fn resolveParameterizedType(pt: *const ast.ParameterizedTypeExpr, table: *TypeTable) TypeId {
|
||||
// Strip module prefix (e.g. "std.Vector" → "Vector")
|
||||
const base_name = if (std.mem.lastIndexOfScalar(u8, pt.name, '.')) |dot| pt.name[dot + 1 ..] else pt.name;
|
||||
// Vector(N, T) is a built-in parameterized type
|
||||
if (std.mem.eql(u8, pt.name, "Vector")) {
|
||||
if (std.mem.eql(u8, base_name, "Vector")) {
|
||||
if (pt.args.len == 2) {
|
||||
const length: u32 = switch (pt.args[0].data) {
|
||||
.int_literal => |lit| @intCast(@as(u64, @bitCast(lit.value))),
|
||||
@@ -306,10 +327,41 @@ fn resolveInlineEnum(ed: *const ast.EnumDecl, table: *TypeTable) TypeId {
|
||||
if (has_payloads) {
|
||||
var fields = std.ArrayList(TypeInfo.StructInfo.Field).empty;
|
||||
for (ed.variant_names, 0..) |vn, i| {
|
||||
const field_ty = if (i < ed.variant_types.len)
|
||||
(if (ed.variant_types[i]) |vt| resolveAstType(vt, table) else .void)
|
||||
else
|
||||
.void;
|
||||
var field_ty: TypeId = .void;
|
||||
if (i < ed.variant_types.len) {
|
||||
if (ed.variant_types[i]) |vt| {
|
||||
// For inline structs (__anon), rename to EnumName.variant_name
|
||||
if (vt.data == .struct_decl) {
|
||||
const sd = &vt.data.struct_decl;
|
||||
if (std.mem.eql(u8, sd.name, "__anon")) {
|
||||
const qualified = std.fmt.allocPrint(alloc, "{s}.{s}", .{ ed.name, vn }) catch "__anon";
|
||||
const qname_id = table.internString(qualified);
|
||||
if (table.findByName(qname_id)) |existing| {
|
||||
field_ty = existing;
|
||||
} else {
|
||||
var sfields = std.ArrayList(TypeInfo.StructInfo.Field).empty;
|
||||
for (sd.field_names, sd.field_types) |fname, ftype_node| {
|
||||
const fty = resolveAstType(ftype_node, table);
|
||||
sfields.append(alloc, .{
|
||||
.name = table.internString(fname),
|
||||
.ty = fty,
|
||||
}) catch unreachable;
|
||||
}
|
||||
const sinfo: TypeInfo = .{ .@"struct" = .{
|
||||
.name = qname_id,
|
||||
.fields = sfields.items,
|
||||
} };
|
||||
field_ty = table.intern(sinfo);
|
||||
table.update(field_ty, sinfo);
|
||||
}
|
||||
} else {
|
||||
field_ty = resolveAstType(vt, table);
|
||||
}
|
||||
} else {
|
||||
field_ty = resolveAstType(vt, table);
|
||||
}
|
||||
}
|
||||
}
|
||||
fields.append(alloc, .{
|
||||
.name = table.internString(vn),
|
||||
.ty = field_ty,
|
||||
@@ -330,9 +382,43 @@ fn resolveInlineEnum(ed: *const ast.EnumDecl, table: *TypeTable) TypeId {
|
||||
for (ed.variant_names) |vn| {
|
||||
variants.append(alloc, table.internString(vn)) catch unreachable;
|
||||
}
|
||||
// Build explicit values for flags (power-of-2) or custom values
|
||||
var explicit_vals: ?[]const i64 = null;
|
||||
if (ed.is_flags) {
|
||||
var vals = std.ArrayList(i64).empty;
|
||||
for (ed.variant_names, 0..) |_, i| {
|
||||
if (i < ed.variant_values.len) {
|
||||
if (ed.variant_values[i]) |vv| {
|
||||
if (vv.data == .int_literal) {
|
||||
vals.append(alloc, vv.data.int_literal.value) catch unreachable;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Auto power-of-2: 1, 2, 4, 8, ...
|
||||
vals.append(alloc, @as(i64, 1) << @intCast(i)) catch unreachable;
|
||||
}
|
||||
explicit_vals = vals.items;
|
||||
} else if (ed.variant_values.len > 0) {
|
||||
var vals = std.ArrayList(i64).empty;
|
||||
for (0..ed.variant_names.len) |i| {
|
||||
if (i < ed.variant_values.len) {
|
||||
if (ed.variant_values[i]) |vv| {
|
||||
if (vv.data == .int_literal) {
|
||||
vals.append(alloc, vv.data.int_literal.value) catch unreachable;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
vals.append(alloc, @intCast(i)) catch unreachable;
|
||||
}
|
||||
explicit_vals = vals.items;
|
||||
}
|
||||
const info: TypeInfo = .{ .@"enum" = .{
|
||||
.name = name_id,
|
||||
.variants = variants.items,
|
||||
.is_flags = ed.is_flags,
|
||||
.explicit_values = explicit_vals,
|
||||
} };
|
||||
const id = table.intern(info);
|
||||
table.update(id, info);
|
||||
|
||||
@@ -82,6 +82,8 @@ pub const TypeInfo = union(enum) {
|
||||
pub const EnumInfo = struct {
|
||||
name: StringId,
|
||||
variants: []const StringId,
|
||||
is_flags: bool = false,
|
||||
explicit_values: ?[]const i64 = null, // for flags (power-of-2) or custom values
|
||||
};
|
||||
|
||||
pub const UnionInfo = struct {
|
||||
@@ -350,11 +352,27 @@ pub const TypeTable = struct {
|
||||
.array => |arr| arr.length * self.sizeOf(arr.element),
|
||||
.vector => |vec| vec.length * self.sizeOf(vec.element),
|
||||
.any => 16, // {type_tag, data_ptr}
|
||||
.@"struct", .@"union", .@"enum", .tuple, .protocol => {
|
||||
// Sizes of composite types depend on layout — return 0 as placeholder.
|
||||
// Real size computation needs struct layout info from codegen/sema.
|
||||
return 0;
|
||||
.@"struct" => |s| {
|
||||
var total: u32 = 0;
|
||||
for (s.fields) |f| total += @max(self.sizeOf(f.ty), 8);
|
||||
return if (total == 0) 8 else total;
|
||||
},
|
||||
.@"union" => |u| {
|
||||
// Size of union = tag + max(field sizes)
|
||||
var max_field: u32 = 0;
|
||||
for (u.fields) |f| {
|
||||
const sz = self.sizeOf(f.ty);
|
||||
if (sz > max_field) max_field = sz;
|
||||
}
|
||||
return 8 + @max(max_field, 8);
|
||||
},
|
||||
.@"enum" => 8, // plain enums are just integer tags
|
||||
.tuple => |t| {
|
||||
var total: u32 = 0;
|
||||
for (t.fields) |f| total += @max(self.sizeOf(f), 8);
|
||||
return if (total == 0) 8 else total;
|
||||
},
|
||||
.protocol => 16, // {ctx, vtable}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user