emit zir skeleton
This commit is contained in:
parent
2e6ccec100
commit
993e654554
@ -86,7 +86,7 @@ pub const Inst = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const TypedValue = struct {
|
pub const TypedValue = struct {
|
||||||
ty: Type,
|
ty: Type,
|
||||||
val: Value,
|
val: Value,
|
||||||
};
|
};
|
||||||
@ -100,11 +100,13 @@ pub const Module = struct {
|
|||||||
pub const Export = struct {
|
pub const Export = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
typed_value: TypedValue,
|
typed_value: TypedValue,
|
||||||
|
src: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Fn = struct {
|
pub const Fn = struct {
|
||||||
analysis_status: enum { in_progress, failure, success },
|
analysis_status: enum { in_progress, failure, success },
|
||||||
body: []*Inst,
|
body: []*Inst,
|
||||||
|
fn_type: Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn deinit(self: *Module, allocator: *Allocator) void {
|
pub fn deinit(self: *Module, allocator: *Allocator) void {
|
||||||
@ -113,10 +115,6 @@ pub const Module = struct {
|
|||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_zir(self: Module, allocator: *Allocator) !text.Module {
|
|
||||||
return error.TodoImplementEmitToZIR;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ErrorMsg = struct {
|
pub const ErrorMsg = struct {
|
||||||
@ -141,6 +139,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
|
|||||||
defer ctx.decl_table.deinit();
|
defer ctx.decl_table.deinit();
|
||||||
defer ctx.exports.deinit();
|
defer ctx.exports.deinit();
|
||||||
defer ctx.fns.deinit();
|
defer ctx.fns.deinit();
|
||||||
|
errdefer ctx.arena.deinit();
|
||||||
|
|
||||||
ctx.analyzeRoot() catch |err| switch (err) {
|
ctx.analyzeRoot() catch |err| switch (err) {
|
||||||
error.AnalysisFail => {
|
error.AnalysisFail => {
|
||||||
@ -263,6 +262,7 @@ const Analyze = struct {
|
|||||||
try self.exports.append(.{
|
try self.exports.append(.{
|
||||||
.name = symbol_name,
|
.name = symbol_name,
|
||||||
.typed_value = typed_value,
|
.typed_value = typed_value,
|
||||||
|
.src = export_inst.base.src,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,6 +426,7 @@ const Analyze = struct {
|
|||||||
// could become invalid.
|
// could become invalid.
|
||||||
(try self.fns.addOne()).* = .{
|
(try self.fns.addOne()).* = .{
|
||||||
.analysis_status = .in_progress,
|
.analysis_status = .in_progress,
|
||||||
|
.fn_type = fn_type,
|
||||||
.body = undefined,
|
.body = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -438,10 +439,9 @@ const Analyze = struct {
|
|||||||
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
|
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fns.items[new_func.fn_index] = .{
|
const f = &self.fns.items[new_func.fn_index];
|
||||||
.analysis_status = .success,
|
f.analysis_status = .success;
|
||||||
.body = new_func.body.toOwnedSlice(),
|
f.body = new_func.body.toOwnedSlice();
|
||||||
};
|
|
||||||
|
|
||||||
const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
|
const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
|
||||||
fn_payload.* = .{ .index = new_func.fn_index };
|
fn_payload.* = .{ .index = new_func.fn_index };
|
||||||
@ -712,7 +712,7 @@ pub fn main() anyerror!void {
|
|||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var new_zir_module = try analyzed_module.emit_zir(allocator);
|
var new_zir_module = try text.emit_zir(allocator, analyzed_module);
|
||||||
defer new_zir_module.deinit(allocator);
|
defer new_zir_module.deinit(allocator);
|
||||||
|
|
||||||
new_zir_module.dump();
|
new_zir_module.dump();
|
||||||
|
@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const BigInt = std.math.big.Int;
|
const BigInt = std.math.big.Int;
|
||||||
const Type = @import("../type.zig").Type;
|
const Type = @import("../type.zig").Type;
|
||||||
|
const Value = @import("../value.zig").Value;
|
||||||
|
const ir = @import("../ir.zig");
|
||||||
|
|
||||||
/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
|
/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
|
||||||
/// in-memory, analyzed instructions with types and values.
|
/// in-memory, analyzed instructions with types and values.
|
||||||
@ -61,7 +63,7 @@ pub const Inst = struct {
|
|||||||
base: Inst,
|
base: Inst,
|
||||||
|
|
||||||
positionals: struct {
|
positionals: struct {
|
||||||
bytes: []u8,
|
bytes: []const u8,
|
||||||
},
|
},
|
||||||
kw_args: struct {},
|
kw_args: struct {},
|
||||||
};
|
};
|
||||||
@ -399,7 +401,7 @@ pub const Module = struct {
|
|||||||
try stream.writeByte('}');
|
try stream.writeByte('}');
|
||||||
},
|
},
|
||||||
bool => return stream.writeByte("01"[@boolToInt(param)]),
|
bool => return stream.writeByte("01"[@boolToInt(param)]),
|
||||||
[]u8 => return std.zig.renderStringLiteral(param, stream),
|
[]u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
|
||||||
BigInt => return stream.print("{}", .{param}),
|
BigInt => return stream.print("{}", .{param}),
|
||||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||||
}
|
}
|
||||||
@ -425,6 +427,8 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
|
|||||||
.errors = std.ArrayList(ErrorMsg).init(allocator),
|
.errors = std.ArrayList(ErrorMsg).init(allocator),
|
||||||
.global_name_map = &global_name_map,
|
.global_name_map = &global_name_map,
|
||||||
};
|
};
|
||||||
|
errdefer parser.arena.deinit();
|
||||||
|
|
||||||
parser.parseRoot() catch |err| switch (err) {
|
parser.parseRoot() catch |err| switch (err) {
|
||||||
error.ParseFailure => {
|
error.ParseFailure => {
|
||||||
assert(parser.errors.items.len != 0);
|
assert(parser.errors.items.len != 0);
|
||||||
@ -733,7 +737,7 @@ const Parser = struct {
|
|||||||
return instructions.toOwnedSlice();
|
return instructions.toOwnedSlice();
|
||||||
},
|
},
|
||||||
*Inst => return parseParameterInst(self, body_ctx),
|
*Inst => return parseParameterInst(self, body_ctx),
|
||||||
[]u8 => return self.parseStringLiteral(),
|
[]u8, []const u8 => return self.parseStringLiteral(),
|
||||||
BigInt => return self.parseIntegerLiteral(),
|
BigInt => return self.parseIntegerLiteral(),
|
||||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||||
}
|
}
|
||||||
@ -773,3 +777,201 @@ const Parser = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module {
|
||||||
|
var ctx: EmitZIR = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.decls = std.ArrayList(*Inst).init(allocator),
|
||||||
|
.decl_table = std.AutoHashMap(*ir.Inst, *Inst).init(allocator),
|
||||||
|
.arena = std.heap.ArenaAllocator.init(allocator),
|
||||||
|
.old_module = &old_module,
|
||||||
|
};
|
||||||
|
defer ctx.decls.deinit();
|
||||||
|
defer ctx.decl_table.deinit();
|
||||||
|
errdefer ctx.arena.deinit();
|
||||||
|
|
||||||
|
try ctx.emit();
|
||||||
|
|
||||||
|
return Module{
|
||||||
|
.decls = ctx.decls.toOwnedSlice(),
|
||||||
|
.arena = ctx.arena,
|
||||||
|
.errors = &[0]ErrorMsg{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmitZIR = struct {
|
||||||
|
allocator: *Allocator,
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
old_module: *const ir.Module,
|
||||||
|
decls: std.ArrayList(*Inst),
|
||||||
|
decl_table: std.AutoHashMap(*ir.Inst, *Inst),
|
||||||
|
|
||||||
|
pub fn emit(self: *EmitZIR) !void {
|
||||||
|
for (self.old_module.exports) |module_export| {
|
||||||
|
const export_value = try self.emitTypedValue(module_export.src, module_export.typed_value);
|
||||||
|
const symbol_name = try self.emitStringLiteral(module_export.src, module_export.name);
|
||||||
|
const export_inst = try self.arena.allocator.create(Inst.Export);
|
||||||
|
export_inst.* = .{
|
||||||
|
.base = .{ .src = module_export.src, .tag = Inst.Export.base_tag },
|
||||||
|
.positionals = .{
|
||||||
|
.symbol_name = symbol_name,
|
||||||
|
.value = export_value,
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
try self.decls.append(&export_inst.base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolveInst(self: *EmitZIR, inst_table: *const std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
|
||||||
|
if (inst.cast(ir.Inst.Constant)) |const_inst| {
|
||||||
|
if (self.decl_table.getValue(inst)) |decl| {
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
const new_decl = try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
|
||||||
|
try self.decl_table.putNoClobber(inst, new_decl);
|
||||||
|
return new_decl;
|
||||||
|
} else {
|
||||||
|
return inst_table.getValue(inst).?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: ir.TypedValue) Allocator.Error!*Inst {
|
||||||
|
switch (typed_value.ty.zigTypeTag()) {
|
||||||
|
.Pointer => {
|
||||||
|
const ptr_elem_type = typed_value.ty.elemType();
|
||||||
|
switch (ptr_elem_type.zigTypeTag()) {
|
||||||
|
.Array => {
|
||||||
|
// TODO more checks to make sure this can be emitted as a string literal
|
||||||
|
//const array_elem_type = ptr_elem_type.elemType();
|
||||||
|
//if (array_elem_type.eql(Type.initTag(.u8)) and
|
||||||
|
// ptr_elem_type.hasSentinel(Value.initTag(.zero)))
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
const bytes = try typed_value.val.toAllocatedBytes(&self.arena.allocator);
|
||||||
|
return self.emitStringLiteral(src, bytes);
|
||||||
|
},
|
||||||
|
else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {}", .{@tagName(t)}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Type => {
|
||||||
|
const ty = typed_value.val.toType();
|
||||||
|
return self.emitType(src, ty);
|
||||||
|
},
|
||||||
|
.Fn => {
|
||||||
|
const index = typed_value.val.cast(Value.Payload.Function).?.index;
|
||||||
|
const module_fn = self.old_module.fns[index];
|
||||||
|
|
||||||
|
var inst_table = std.AutoHashMap(*ir.Inst, *Inst).init(self.allocator);
|
||||||
|
defer inst_table.deinit();
|
||||||
|
|
||||||
|
var instructions = std.ArrayList(*Inst).init(self.allocator);
|
||||||
|
defer instructions.deinit();
|
||||||
|
|
||||||
|
for (module_fn.body) |inst| {
|
||||||
|
const new_inst = switch (inst.tag) {
|
||||||
|
.unreach => blk: {
|
||||||
|
const unreach_inst = try self.arena.allocator.create(Inst.Unreachable);
|
||||||
|
unreach_inst.* = .{
|
||||||
|
.base = .{ .src = inst.src, .tag = Inst.Unreachable.base_tag },
|
||||||
|
.positionals = .{},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
break :blk &unreach_inst.base;
|
||||||
|
},
|
||||||
|
.constant => unreachable, // excluded from function bodies
|
||||||
|
.assembly => @panic("TODO emit zir asm instruction"),
|
||||||
|
.ptrtoint => blk: {
|
||||||
|
const old_inst = inst.cast(ir.Inst.PtrToInt).?;
|
||||||
|
const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
|
||||||
|
new_inst.* = .{
|
||||||
|
.base = .{ .src = inst.src, .tag = Inst.PtrToInt.base_tag },
|
||||||
|
.positionals = .{
|
||||||
|
.ptr = try self.resolveInst(&inst_table, old_inst.args.ptr),
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
break :blk &new_inst.base;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try instructions.append(new_inst);
|
||||||
|
try inst_table.putNoClobber(inst, new_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn_type = try self.emitType(src, module_fn.fn_type);
|
||||||
|
|
||||||
|
const fn_inst = try self.arena.allocator.create(Inst.Fn);
|
||||||
|
fn_inst.* = .{
|
||||||
|
.base = .{ .src = src, .tag = Inst.Fn.base_tag },
|
||||||
|
.positionals = .{
|
||||||
|
.fn_type = fn_type,
|
||||||
|
.body = .{
|
||||||
|
.instructions = instructions.toOwnedSlice(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
try self.decls.append(&fn_inst.base);
|
||||||
|
return &fn_inst.base;
|
||||||
|
},
|
||||||
|
else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emitType(self: *EmitZIR, src: usize, ty: Type) !*Inst {
|
||||||
|
switch (ty.tag()) {
|
||||||
|
.isize => return self.emitPrimitiveType(src, .isize),
|
||||||
|
.usize => return self.emitPrimitiveType(src, .usize),
|
||||||
|
.c_short => return self.emitPrimitiveType(src, .c_short),
|
||||||
|
.c_ushort => return self.emitPrimitiveType(src, .c_ushort),
|
||||||
|
.c_int => return self.emitPrimitiveType(src, .c_int),
|
||||||
|
.c_uint => return self.emitPrimitiveType(src, .c_uint),
|
||||||
|
.c_long => return self.emitPrimitiveType(src, .c_long),
|
||||||
|
.c_ulong => return self.emitPrimitiveType(src, .c_ulong),
|
||||||
|
.c_longlong => return self.emitPrimitiveType(src, .c_longlong),
|
||||||
|
.c_ulonglong => return self.emitPrimitiveType(src, .c_ulonglong),
|
||||||
|
.c_longdouble => return self.emitPrimitiveType(src, .c_longdouble),
|
||||||
|
.c_void => return self.emitPrimitiveType(src, .c_void),
|
||||||
|
.f16 => return self.emitPrimitiveType(src, .f16),
|
||||||
|
.f32 => return self.emitPrimitiveType(src, .f32),
|
||||||
|
.f64 => return self.emitPrimitiveType(src, .f64),
|
||||||
|
.f128 => return self.emitPrimitiveType(src, .f128),
|
||||||
|
.anyerror => return self.emitPrimitiveType(src, .anyerror),
|
||||||
|
else => switch (ty.zigTypeTag()) {
|
||||||
|
.Bool => return self.emitPrimitiveType(src, .bool),
|
||||||
|
.Void => return self.emitPrimitiveType(src, .void),
|
||||||
|
.NoReturn => return self.emitPrimitiveType(src, .noreturn),
|
||||||
|
.Type => return self.emitPrimitiveType(src, .type),
|
||||||
|
.ComptimeInt => return self.emitPrimitiveType(src, .comptime_int),
|
||||||
|
.ComptimeFloat => return self.emitPrimitiveType(src, .comptime_float),
|
||||||
|
else => std.debug.panic("TODO implement emitType for {}", .{ty}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst {
|
||||||
|
const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
|
||||||
|
primitive_inst.* = .{
|
||||||
|
.base = .{ .src = src, .tag = Inst.Primitive.base_tag },
|
||||||
|
.positionals = .{
|
||||||
|
.tag = tag,
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
try self.decls.append(&primitive_inst.base);
|
||||||
|
return &primitive_inst.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
|
||||||
|
const str_inst = try self.arena.allocator.create(Inst.Str);
|
||||||
|
str_inst.* = .{
|
||||||
|
.base = .{ .src = src, .tag = Inst.Str.base_tag },
|
||||||
|
.positionals = .{
|
||||||
|
.bytes = str,
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
try self.decls.append(&str_inst.base);
|
||||||
|
return &str_inst.base;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -47,6 +47,7 @@ pub const Value = extern union {
|
|||||||
single_const_pointer_to_comptime_int_type,
|
single_const_pointer_to_comptime_int_type,
|
||||||
const_slice_u8_type,
|
const_slice_u8_type,
|
||||||
|
|
||||||
|
zero,
|
||||||
void_value,
|
void_value,
|
||||||
noreturn_value,
|
noreturn_value,
|
||||||
bool_true,
|
bool_true,
|
||||||
@ -133,6 +134,7 @@ pub const Value = extern union {
|
|||||||
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
||||||
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
|
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
|
||||||
|
|
||||||
|
.zero => return out_stream.writeAll("0"),
|
||||||
.void_value => return out_stream.writeAll("{}"),
|
.void_value => return out_stream.writeAll("{}"),
|
||||||
.noreturn_value => return out_stream.writeAll("unreachable"),
|
.noreturn_value => return out_stream.writeAll("unreachable"),
|
||||||
.bool_true => return out_stream.writeAll("true"),
|
.bool_true => return out_stream.writeAll("true"),
|
||||||
@ -195,6 +197,7 @@ pub const Value = extern union {
|
|||||||
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
||||||
.const_slice_u8_type => Type.initTag(.const_slice_u8),
|
.const_slice_u8_type => Type.initTag(.const_slice_u8),
|
||||||
|
|
||||||
|
.zero,
|
||||||
.void_value,
|
.void_value,
|
||||||
.noreturn_value,
|
.noreturn_value,
|
||||||
.bool_true,
|
.bool_true,
|
||||||
@ -252,6 +255,8 @@ pub const Value = extern union {
|
|||||||
.bytes,
|
.bytes,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
|
|
||||||
|
.zero => return true,
|
||||||
|
|
||||||
.int_u64 => switch (ty.zigTypeTag()) {
|
.int_u64 => switch (ty.zigTypeTag()) {
|
||||||
.Int => {
|
.Int => {
|
||||||
const x = self.cast(Payload.Int_u64).?.int;
|
const x = self.cast(Payload.Int_u64).?.int;
|
||||||
@ -318,6 +323,7 @@ pub const Value = extern union {
|
|||||||
.fn_naked_noreturn_no_args_type,
|
.fn_naked_noreturn_no_args_type,
|
||||||
.single_const_pointer_to_comptime_int_type,
|
.single_const_pointer_to_comptime_int_type,
|
||||||
.const_slice_u8_type,
|
.const_slice_u8_type,
|
||||||
|
.zero,
|
||||||
.void_value,
|
.void_value,
|
||||||
.noreturn_value,
|
.noreturn_value,
|
||||||
.bool_true,
|
.bool_true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user