| ... | @@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator; | ... | @@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator; |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const BigInt = std.math.big.Int; | 7 | const BigInt = std.math.big.Int; |
| 8 | const Type = @import("../type.zig").Type; | 8 | const Type = @import("../type.zig").Type; |
| | 9 | const Value = @import("../value.zig").Value; |
| | 10 | const ir = @import("../ir.zig"); |
| 9 | | 11 | |
| 10 | /// These are instructions that correspond to the ZIR text format. See `ir.Inst` for | 12 | /// 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, |
| 62 | | 64 | |
| 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 | |
| | 781 | pub 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 | |
| | 802 | const 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 | }; |