authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-22 00:04:52-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-22 00:04:52-04:00
log993e6545546b499e8052a0020cc10e399c235c11
treeffdf9ff4234aa667d55829061349a23288d14968
parent2e6ccec1007199d651bf89216c4af53f80c5c15a

emit zir skeleton


3 files changed, 221 insertions(+), 13 deletions(-)

src-self-hosted/ir.zig+10-10
...@@ -86,7 +86,7 @@ pub const Inst = struct {...@@ -86,7 +86,7 @@ pub const Inst = struct {
86 };86 };
87};87};
8888
89const TypedValue = struct {89pub const TypedValue = struct {
90 ty: Type,90 ty: Type,
91 val: Value,91 val: Value,
92};92};
...@@ -100,11 +100,13 @@ pub const Module = struct {...@@ -100,11 +100,13 @@ pub const Module = struct {
100 pub const Export = struct {100 pub const Export = struct {
101 name: []const u8,101 name: []const u8,
102 typed_value: TypedValue,102 typed_value: TypedValue,
103 src: usize,
103 };104 };
104105
105 pub const Fn = struct {106 pub const Fn = struct {
106 analysis_status: enum { in_progress, failure, success },107 analysis_status: enum { in_progress, failure, success },
107 body: []*Inst,108 body: []*Inst,
109 fn_type: Type,
108 };110 };
109111
110 pub fn deinit(self: *Module, allocator: *Allocator) void {112 pub fn deinit(self: *Module, allocator: *Allocator) void {
...@@ -113,10 +115,6 @@ pub const Module = struct {...@@ -113,10 +115,6 @@ pub const Module = struct {
113 self.arena.deinit();115 self.arena.deinit();
114 self.* = undefined;116 self.* = undefined;
115 }117 }
116
117 pub fn emit_zir(self: Module, allocator: *Allocator) !text.Module {
118 return error.TodoImplementEmitToZIR;
119 }
120};118};
121119
122pub const ErrorMsg = struct {120pub const ErrorMsg = struct {
...@@ -141,6 +139,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {...@@ -141,6 +139,7 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
141 defer ctx.decl_table.deinit();139 defer ctx.decl_table.deinit();
142 defer ctx.exports.deinit();140 defer ctx.exports.deinit();
143 defer ctx.fns.deinit();141 defer ctx.fns.deinit();
142 errdefer ctx.arena.deinit();
144143
145 ctx.analyzeRoot() catch |err| switch (err) {144 ctx.analyzeRoot() catch |err| switch (err) {
146 error.AnalysisFail => {145 error.AnalysisFail => {
...@@ -263,6 +262,7 @@ const Analyze = struct {...@@ -263,6 +262,7 @@ const Analyze = struct {
263 try self.exports.append(.{262 try self.exports.append(.{
264 .name = symbol_name,263 .name = symbol_name,
265 .typed_value = typed_value,264 .typed_value = typed_value,
265 .src = export_inst.base.src,
266 });266 });
267 }267 }
268268
...@@ -426,6 +426,7 @@ const Analyze = struct {...@@ -426,6 +426,7 @@ const Analyze = struct {
426 // could become invalid.426 // could become invalid.
427 (try self.fns.addOne()).* = .{427 (try self.fns.addOne()).* = .{
428 .analysis_status = .in_progress,428 .analysis_status = .in_progress,
429 .fn_type = fn_type,
429 .body = undefined,430 .body = undefined,
430 };431 };
431432
...@@ -438,10 +439,9 @@ const Analyze = struct {...@@ -438,10 +439,9 @@ const Analyze = struct {
438 try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });439 try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
439 }440 }
440441
441 self.fns.items[new_func.fn_index] = .{442 const f = &self.fns.items[new_func.fn_index];
442 .analysis_status = .success,443 f.analysis_status = .success;
443 .body = new_func.body.toOwnedSlice(),444 f.body = new_func.body.toOwnedSlice();
444 };
445445
446 const fn_payload = try self.arena.allocator.create(Value.Payload.Function);446 const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
447 fn_payload.* = .{ .index = new_func.fn_index };447 fn_payload.* = .{ .index = new_func.fn_index };
...@@ -712,7 +712,7 @@ pub fn main() anyerror!void {...@@ -712,7 +712,7 @@ pub fn main() anyerror!void {
712 std.process.exit(1);712 std.process.exit(1);
713 }713 }
714714
715 var new_zir_module = try analyzed_module.emit_zir(allocator);715 var new_zir_module = try text.emit_zir(allocator, analyzed_module);
716 defer new_zir_module.deinit(allocator);716 defer new_zir_module.deinit(allocator);
717717
718 new_zir_module.dump();718 new_zir_module.dump();
src-self-hosted/ir/text.zig+205-3
...@@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator;...@@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const BigInt = std.math.big.Int;7const BigInt = std.math.big.Int;
8const Type = @import("../type.zig").Type;8const Type = @import("../type.zig").Type;
9const Value = @import("../value.zig").Value;
10const ir = @import("../ir.zig");
911
10/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for12/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
11/// in-memory, analyzed instructions with types and values.13/// in-memory, analyzed instructions with types and values.
...@@ -61,7 +63,7 @@ pub const Inst = struct {...@@ -61,7 +63,7 @@ pub const Inst = struct {
61 base: Inst,63 base: Inst,
6264
63 positionals: struct {65 positionals: struct {
64 bytes: []u8,66 bytes: []const u8,
65 },67 },
66 kw_args: struct {},68 kw_args: struct {},
67 };69 };
...@@ -399,7 +401,7 @@ pub const Module = struct {...@@ -399,7 +401,7 @@ pub const Module = struct {
399 try stream.writeByte('}');401 try stream.writeByte('}');
400 },402 },
401 bool => return stream.writeByte("01"[@boolToInt(param)]),403 bool => return stream.writeByte("01"[@boolToInt(param)]),
402 []u8 => return std.zig.renderStringLiteral(param, stream),404 []u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
403 BigInt => return stream.print("{}", .{param}),405 BigInt => return stream.print("{}", .{param}),
404 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),406 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
405 }407 }
...@@ -425,6 +427,8 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -425,6 +427,8 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
425 .errors = std.ArrayList(ErrorMsg).init(allocator),427 .errors = std.ArrayList(ErrorMsg).init(allocator),
426 .global_name_map = &global_name_map,428 .global_name_map = &global_name_map,
427 };429 };
430 errdefer parser.arena.deinit();
431
428 parser.parseRoot() catch |err| switch (err) {432 parser.parseRoot() catch |err| switch (err) {
429 error.ParseFailure => {433 error.ParseFailure => {
430 assert(parser.errors.items.len != 0);434 assert(parser.errors.items.len != 0);
...@@ -733,7 +737,7 @@ const Parser = struct {...@@ -733,7 +737,7 @@ const Parser = struct {
733 return instructions.toOwnedSlice();737 return instructions.toOwnedSlice();
734 },738 },
735 *Inst => return parseParameterInst(self, body_ctx),739 *Inst => return parseParameterInst(self, body_ctx),
736 []u8 => return self.parseStringLiteral(),740 []u8, []const u8 => return self.parseStringLiteral(),
737 BigInt => return self.parseIntegerLiteral(),741 BigInt => return self.parseIntegerLiteral(),
738 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),742 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
739 }743 }
...@@ -773,3 +777,201 @@ const Parser = struct {...@@ -773,3 +777,201 @@ const Parser = struct {
773 }777 }
774 }778 }
775};779};
780
781pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module {
782 var ctx: EmitZIR = .{
783 .allocator = allocator,
784 .decls = std.ArrayList(*Inst).init(allocator),
785 .decl_table = std.AutoHashMap(*ir.Inst, *Inst).init(allocator),
786 .arena = std.heap.ArenaAllocator.init(allocator),
787 .old_module = &old_module,
788 };
789 defer ctx.decls.deinit();
790 defer ctx.decl_table.deinit();
791 errdefer ctx.arena.deinit();
792
793 try ctx.emit();
794
795 return Module{
796 .decls = ctx.decls.toOwnedSlice(),
797 .arena = ctx.arena,
798 .errors = &[0]ErrorMsg{},
799 };
800}
801
802const EmitZIR = struct {
803 allocator: *Allocator,
804 arena: std.heap.ArenaAllocator,
805 old_module: *const ir.Module,
806 decls: std.ArrayList(*Inst),
807 decl_table: std.AutoHashMap(*ir.Inst, *Inst),
808
809 pub fn emit(self: *EmitZIR) !void {
810 for (self.old_module.exports) |module_export| {
811 const export_value = try self.emitTypedValue(module_export.src, module_export.typed_value);
812 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.name);
813 const export_inst = try self.arena.allocator.create(Inst.Export);
814 export_inst.* = .{
815 .base = .{ .src = module_export.src, .tag = Inst.Export.base_tag },
816 .positionals = .{
817 .symbol_name = symbol_name,
818 .value = export_value,
819 },
820 .kw_args = .{},
821 };
822 try self.decls.append(&export_inst.base);
823 }
824 }
825
826 pub fn resolveInst(self: *EmitZIR, inst_table: *const std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
827 if (inst.cast(ir.Inst.Constant)) |const_inst| {
828 if (self.decl_table.getValue(inst)) |decl| {
829 return decl;
830 }
831 const new_decl = try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
832 try self.decl_table.putNoClobber(inst, new_decl);
833 return new_decl;
834 } else {
835 return inst_table.getValue(inst).?;
836 }
837 }
838
839 pub fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: ir.TypedValue) Allocator.Error!*Inst {
840 switch (typed_value.ty.zigTypeTag()) {
841 .Pointer => {
842 const ptr_elem_type = typed_value.ty.elemType();
843 switch (ptr_elem_type.zigTypeTag()) {
844 .Array => {
845 // TODO more checks to make sure this can be emitted as a string literal
846 //const array_elem_type = ptr_elem_type.elemType();
847 //if (array_elem_type.eql(Type.initTag(.u8)) and
848 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))
849 //{
850 //}
851 const bytes = try typed_value.val.toAllocatedBytes(&self.arena.allocator);
852 return self.emitStringLiteral(src, bytes);
853 },
854 else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {}", .{@tagName(t)}),
855 }
856 },
857 .Type => {
858 const ty = typed_value.val.toType();
859 return self.emitType(src, ty);
860 },
861 .Fn => {
862 const index = typed_value.val.cast(Value.Payload.Function).?.index;
863 const module_fn = self.old_module.fns[index];
864
865 var inst_table = std.AutoHashMap(*ir.Inst, *Inst).init(self.allocator);
866 defer inst_table.deinit();
867
868 var instructions = std.ArrayList(*Inst).init(self.allocator);
869 defer instructions.deinit();
870
871 for (module_fn.body) |inst| {
872 const new_inst = switch (inst.tag) {
873 .unreach => blk: {
874 const unreach_inst = try self.arena.allocator.create(Inst.Unreachable);
875 unreach_inst.* = .{
876 .base = .{ .src = inst.src, .tag = Inst.Unreachable.base_tag },
877 .positionals = .{},
878 .kw_args = .{},
879 };
880 break :blk &unreach_inst.base;
881 },
882 .constant => unreachable, // excluded from function bodies
883 .assembly => @panic("TODO emit zir asm instruction"),
884 .ptrtoint => blk: {
885 const old_inst = inst.cast(ir.Inst.PtrToInt).?;
886 const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
887 new_inst.* = .{
888 .base = .{ .src = inst.src, .tag = Inst.PtrToInt.base_tag },
889 .positionals = .{
890 .ptr = try self.resolveInst(&inst_table, old_inst.args.ptr),
891 },
892 .kw_args = .{},
893 };
894 break :blk &new_inst.base;
895 },
896 };
897 try instructions.append(new_inst);
898 try inst_table.putNoClobber(inst, new_inst);
899 }
900
901 const fn_type = try self.emitType(src, module_fn.fn_type);
902
903 const fn_inst = try self.arena.allocator.create(Inst.Fn);
904 fn_inst.* = .{
905 .base = .{ .src = src, .tag = Inst.Fn.base_tag },
906 .positionals = .{
907 .fn_type = fn_type,
908 .body = .{
909 .instructions = instructions.toOwnedSlice(),
910 },
911 },
912 .kw_args = .{},
913 };
914 try self.decls.append(&fn_inst.base);
915 return &fn_inst.base;
916 },
917 else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
918 }
919 }
920
921 pub fn emitType(self: *EmitZIR, src: usize, ty: Type) !*Inst {
922 switch (ty.tag()) {
923 .isize => return self.emitPrimitiveType(src, .isize),
924 .usize => return self.emitPrimitiveType(src, .usize),
925 .c_short => return self.emitPrimitiveType(src, .c_short),
926 .c_ushort => return self.emitPrimitiveType(src, .c_ushort),
927 .c_int => return self.emitPrimitiveType(src, .c_int),
928 .c_uint => return self.emitPrimitiveType(src, .c_uint),
929 .c_long => return self.emitPrimitiveType(src, .c_long),
930 .c_ulong => return self.emitPrimitiveType(src, .c_ulong),
931 .c_longlong => return self.emitPrimitiveType(src, .c_longlong),
932 .c_ulonglong => return self.emitPrimitiveType(src, .c_ulonglong),
933 .c_longdouble => return self.emitPrimitiveType(src, .c_longdouble),
934 .c_void => return self.emitPrimitiveType(src, .c_void),
935 .f16 => return self.emitPrimitiveType(src, .f16),
936 .f32 => return self.emitPrimitiveType(src, .f32),
937 .f64 => return self.emitPrimitiveType(src, .f64),
938 .f128 => return self.emitPrimitiveType(src, .f128),
939 .anyerror => return self.emitPrimitiveType(src, .anyerror),
940 else => switch (ty.zigTypeTag()) {
941 .Bool => return self.emitPrimitiveType(src, .bool),
942 .Void => return self.emitPrimitiveType(src, .void),
943 .NoReturn => return self.emitPrimitiveType(src, .noreturn),
944 .Type => return self.emitPrimitiveType(src, .type),
945 .ComptimeInt => return self.emitPrimitiveType(src, .comptime_int),
946 .ComptimeFloat => return self.emitPrimitiveType(src, .comptime_float),
947 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
948 },
949 }
950 }
951
952 pub fn emitPrimitiveType(self: *EmitZIR, src: usize, tag: Inst.Primitive.BuiltinType) !*Inst {
953 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
954 primitive_inst.* = .{
955 .base = .{ .src = src, .tag = Inst.Primitive.base_tag },
956 .positionals = .{
957 .tag = tag,
958 },
959 .kw_args = .{},
960 };
961 try self.decls.append(&primitive_inst.base);
962 return &primitive_inst.base;
963 }
964
965 pub fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
966 const str_inst = try self.arena.allocator.create(Inst.Str);
967 str_inst.* = .{
968 .base = .{ .src = src, .tag = Inst.Str.base_tag },
969 .positionals = .{
970 .bytes = str,
971 },
972 .kw_args = .{},
973 };
974 try self.decls.append(&str_inst.base);
975 return &str_inst.base;
976 }
977};
src-self-hosted/value.zig+6
...@@ -47,6 +47,7 @@ pub const Value = extern union {...@@ -47,6 +47,7 @@ pub const Value = extern union {
47 single_const_pointer_to_comptime_int_type,47 single_const_pointer_to_comptime_int_type,
48 const_slice_u8_type,48 const_slice_u8_type,
4949
50 zero,
50 void_value,51 void_value,
51 noreturn_value,52 noreturn_value,
52 bool_true,53 bool_true,
...@@ -133,6 +134,7 @@ pub const Value = extern union {...@@ -133,6 +134,7 @@ pub const Value = extern union {
133 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),134 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
134 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),135 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
135136
137 .zero => return out_stream.writeAll("0"),
136 .void_value => return out_stream.writeAll("{}"),138 .void_value => return out_stream.writeAll("{}"),
137 .noreturn_value => return out_stream.writeAll("unreachable"),139 .noreturn_value => return out_stream.writeAll("unreachable"),
138 .bool_true => return out_stream.writeAll("true"),140 .bool_true => return out_stream.writeAll("true"),
...@@ -195,6 +197,7 @@ pub const Value = extern union {...@@ -195,6 +197,7 @@ pub const Value = extern union {
195 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),197 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
196 .const_slice_u8_type => Type.initTag(.const_slice_u8),198 .const_slice_u8_type => Type.initTag(.const_slice_u8),
197199
200 .zero,
198 .void_value,201 .void_value,
199 .noreturn_value,202 .noreturn_value,
200 .bool_true,203 .bool_true,
...@@ -252,6 +255,8 @@ pub const Value = extern union {...@@ -252,6 +255,8 @@ pub const Value = extern union {
252 .bytes,255 .bytes,
253 => unreachable,256 => unreachable,
254257
258 .zero => return true,
259
255 .int_u64 => switch (ty.zigTypeTag()) {260 .int_u64 => switch (ty.zigTypeTag()) {
256 .Int => {261 .Int => {
257 const x = self.cast(Payload.Int_u64).?.int;262 const x = self.cast(Payload.Int_u64).?.int;
...@@ -318,6 +323,7 @@ pub const Value = extern union {...@@ -318,6 +323,7 @@ pub const Value = extern union {
318 .fn_naked_noreturn_no_args_type,323 .fn_naked_noreturn_no_args_type,
319 .single_const_pointer_to_comptime_int_type,324 .single_const_pointer_to_comptime_int_type,
320 .const_slice_u8_type,325 .const_slice_u8_type,
326 .zero,
321 .void_value,327 .void_value,
322 .noreturn_value,328 .noreturn_value,
323 .bool_true,329 .bool_true,