| ... | ... | @@ -6,6 +6,8 @@ const Allocator = std.mem.Allocator; |
| 6 | 6 | const assert = std.debug.assert; |
| 7 | 7 | const BigInt = std.math.big.Int; |
| 8 | 8 | const Type = @import("../type.zig").Type; |
| 9 | const Value = @import("../value.zig").Value; |
| 10 | const ir = @import("../ir.zig"); |
| 9 | 11 | |
| 10 | 12 | /// These are instructions that correspond to the ZIR text format. See `ir.Inst` for |
| 11 | 13 | /// in-memory, analyzed instructions with types and values. |
| ... | ... | @@ -61,7 +63,7 @@ pub const Inst = struct { |
| 61 | 63 | base: Inst, |
| 62 | 64 | |
| 63 | 65 | positionals: struct { |
| 64 | | bytes: []u8, |
| 66 | bytes: []const u8, |
| 65 | 67 | }, |
| 66 | 68 | kw_args: struct {}, |
| 67 | 69 | }; |
| ... | ... | @@ -399,7 +401,7 @@ pub const Module = struct { |
| 399 | 401 | try stream.writeByte('}'); |
| 400 | 402 | }, |
| 401 | 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 | 405 | BigInt => return stream.print("{}", .{param}), |
| 404 | 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 | 427 | .errors = std.ArrayList(ErrorMsg).init(allocator), |
| 426 | 428 | .global_name_map = &global_name_map, |
| 427 | 429 | }; |
| 430 | errdefer parser.arena.deinit(); |
| 431 | |
| 428 | 432 | parser.parseRoot() catch |err| switch (err) { |
| 429 | 433 | error.ParseFailure => { |
| 430 | 434 | assert(parser.errors.items.len != 0); |
| ... | ... | @@ -733,7 +737,7 @@ const Parser = struct { |
| 733 | 737 | return instructions.toOwnedSlice(); |
| 734 | 738 | }, |
| 735 | 739 | *Inst => return parseParameterInst(self, body_ctx), |
| 736 | | []u8 => return self.parseStringLiteral(), |
| 740 | []u8, []const u8 => return self.parseStringLiteral(), |
| 737 | 741 | BigInt => return self.parseIntegerLiteral(), |
| 738 | 742 | else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)), |
| 739 | 743 | } |
| ... | ... | @@ -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 | }; |