| ... | @@ -542,10 +542,9 @@ locals: std.ArrayListUnmanaged(u8), | ... | @@ -542,10 +542,9 @@ locals: std.ArrayListUnmanaged(u8), |
| 542 | target: std.Target, | 542 | target: std.Target, |
| 543 | /// Represents the wasm binary file that is being linked. | 543 | /// Represents the wasm binary file that is being linked. |
| 544 | bin_file: *link.File.Wasm, | 544 | bin_file: *link.File.Wasm, |
| 545 | /// Table with the global error set. Consists of every error found in | 545 | /// Reference to the Module that this decl is part of. |
| 546 | /// the compiled code. Each error name maps to a `Module.ErrorInt` which is emitted | 546 | /// Used to find the error value. |
| 547 | /// during codegen to determine the error value. | 547 | module: *Module, |
| 548 | global_error_set: std.StringHashMapUnmanaged(Module.ErrorInt), | | |
| 549 | /// List of MIR Instructions | 548 | /// List of MIR Instructions |
| 550 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 549 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 551 | /// Contains extra data for MIR | 550 | /// Contains extra data for MIR |
| ... | @@ -581,7 +580,7 @@ pub fn deinit(self: *Self) void { | ... | @@ -581,7 +580,7 @@ pub fn deinit(self: *Self) void { |
| 581 | self.* = undefined; | 580 | self.* = undefined; |
| 582 | } | 581 | } |
| 583 | | 582 | |
| 584 | /// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig | 583 | /// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig |
| 585 | fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError { | 584 | fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError { |
| 586 | const src: LazySrcLoc = .{ .node_offset = 0 }; | 585 | const src: LazySrcLoc = .{ .node_offset = 0 }; |
| 587 | const src_loc = src.toSrcLoc(self.decl); | 586 | const src_loc = src.toSrcLoc(self.decl); |
| ... | @@ -674,50 +673,41 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) error{OutOfMemory}!u32 { | ... | @@ -674,50 +673,41 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) error{OutOfMemory}!u32 { |
| 674 | return result; | 673 | return result; |
| 675 | } | 674 | } |
| 676 | | 675 | |
| 677 | /// Using a given `Type`, returns the corresponding wasm Valtype | 676 | /// Using a given `Type`, returns the corresponding type |
| 678 | fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { | 677 | fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { |
| 679 | return switch (ty.zigTypeTag()) { | 678 | return switch (ty.zigTypeTag()) { |
| 680 | .Float => blk: { | 679 | .Float => blk: { |
| 681 | const bits = ty.floatBits(self.target); | 680 | const bits = ty.floatBits(target); |
| 682 | if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32; | 681 | if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32; |
| 683 | if (bits == 64) break :blk wasm.Valtype.f64; | 682 | if (bits == 64) break :blk wasm.Valtype.f64; |
| 684 | return self.fail("Float bit size not supported by wasm: '{d}'", .{bits}); | 683 | return wasm.Valtype.i32; // represented as pointer to stack |
| 685 | }, | 684 | }, |
| 686 | .Int => blk: { | 685 | .Int => blk: { |
| 687 | const info = ty.intInfo(self.target); | 686 | const info = ty.intInfo(target); |
| 688 | if (info.bits <= 32) break :blk wasm.Valtype.i32; | 687 | if (info.bits <= 32) break :blk wasm.Valtype.i32; |
| 689 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; | 688 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; |
| 690 | break :blk wasm.Valtype.i32; // represented as pointer to stack | 689 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 691 | }, | 690 | }, |
| 692 | .Enum => switch (ty.tag()) { | 691 | .Enum => switch (ty.tag()) { |
| 693 | .enum_simple => wasm.Valtype.i32, | 692 | .enum_simple => wasm.Valtype.i32, |
| 694 | else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty), | 693 | else => typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty, target), |
| 695 | }, | 694 | }, |
| 696 | .Bool, | 695 | else => wasm.Valtype.i32, // all represented as reference/immediate |
| 697 | .Pointer, | | |
| 698 | .ErrorSet, | | |
| 699 | .Struct, | | |
| 700 | .ErrorUnion, | | |
| 701 | .Optional, | | |
| 702 | .Fn, | | |
| 703 | .Array, | | |
| 704 | => wasm.Valtype.i32, | | |
| 705 | else => self.fail("TODO - Wasm typeToValtype for type '{}'", .{ty}), | | |
| 706 | }; | 696 | }; |
| 707 | } | 697 | } |
| 708 | | 698 | |
| 709 | /// Using a given `Type`, returns the byte representation of its wasm value type | 699 | /// Using a given `Type`, returns the byte representation of its wasm value type |
| 710 | fn genValtype(self: *Self, ty: Type) InnerError!u8 { | 700 | fn genValtype(ty: Type, target: std.Target) u8 { |
| 711 | return wasm.valtype(try self.typeToValtype(ty)); | 701 | return wasm.valtype(typeToValtype(ty, target)); |
| 712 | } | 702 | } |
| 713 | | 703 | |
| 714 | /// Using a given `Type`, returns the corresponding wasm value type | 704 | /// Using a given `Type`, returns the corresponding wasm value type |
| 715 | /// Differently from `genValtype` this also allows `void` to create a block | 705 | /// Differently from `genValtype` this also allows `void` to create a block |
| 716 | /// with no return type | 706 | /// with no return type |
| 717 | fn genBlockType(self: *Self, ty: Type) InnerError!u8 { | 707 | fn genBlockType(ty: Type, target: std.Target) u8 { |
| 718 | return switch (ty.tag()) { | 708 | return switch (ty.tag()) { |
| 719 | .void, .noreturn => wasm.block_empty, | 709 | .void, .noreturn => wasm.block_empty, |
| 720 | else => self.genValtype(ty), | 710 | else => genValtype(ty, target), |
| 721 | }; | 711 | }; |
| 722 | } | 712 | } |
| 723 | | 713 | |
| ... | @@ -739,7 +729,7 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { | ... | @@ -739,7 +729,7 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void { |
| 739 | /// Returns a corresponding `Wvalue` with `local` as active tag | 729 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 740 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | 730 | fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| 741 | const initial_index = self.local_index; | 731 | const initial_index = self.local_index; |
| 742 | const valtype = try self.genValtype(ty); | 732 | const valtype = genValtype(ty, self.target); |
| 743 | try self.locals.append(self.gpa, valtype); | 733 | try self.locals.append(self.gpa, valtype); |
| 744 | self.local_index += 1; | 734 | self.local_index += 1; |
| 745 | return WValue{ .local = initial_index }; | 735 | return WValue{ .local = initial_index }; |
| ... | @@ -747,33 +737,33 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { | ... | @@ -747,33 +737,33 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { |
| 747 | | 737 | |
| 748 | /// Generates a `wasm.Type` from a given function type. | 738 | /// Generates a `wasm.Type` from a given function type. |
| 749 | /// Memory is owned by the caller. | 739 | /// Memory is owned by the caller. |
| 750 | fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { | 740 | fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type { |
| 751 | var params = std.ArrayList(wasm.Valtype).init(self.gpa); | 741 | var params = std.ArrayList(wasm.Valtype).init(gpa); |
| 752 | defer params.deinit(); | 742 | defer params.deinit(); |
| 753 | var returns = std.ArrayList(wasm.Valtype).init(self.gpa); | 743 | var returns = std.ArrayList(wasm.Valtype).init(gpa); |
| 754 | defer returns.deinit(); | 744 | defer returns.deinit(); |
| 755 | const return_type = fn_ty.fnReturnType(); | 745 | const return_type = fn_ty.fnReturnType(); |
| 756 | | 746 | |
| 757 | const want_sret = self.isByRef(return_type); | 747 | const want_sret = isByRef(return_type, target); |
| 758 | | 748 | |
| 759 | if (want_sret) { | 749 | if (want_sret) { |
| 760 | try params.append(try self.typeToValtype(Type.usize)); | 750 | try params.append(typeToValtype(return_type, target)); |
| 761 | } | 751 | } |
| 762 | | 752 | |
| 763 | // param types | 753 | // param types |
| 764 | if (fn_ty.fnParamLen() != 0) { | 754 | if (fn_ty.fnParamLen() != 0) { |
| 765 | const fn_params = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 755 | const fn_params = try gpa.alloc(Type, fn_ty.fnParamLen()); |
| 766 | defer self.gpa.free(fn_params); | 756 | defer gpa.free(fn_params); |
| 767 | fn_ty.fnParamTypes(fn_params); | 757 | fn_ty.fnParamTypes(fn_params); |
| 768 | for (fn_params) |param_type| { | 758 | for (fn_params) |param_type| { |
| 769 | if (!param_type.hasCodeGenBits()) continue; | 759 | if (!param_type.hasCodeGenBits()) continue; |
| 770 | try params.append(try self.typeToValtype(param_type)); | 760 | try params.append(typeToValtype(param_type, target)); |
| 771 | } | 761 | } |
| 772 | } | 762 | } |
| 773 | | 763 | |
| 774 | // return type | 764 | // return type |
| 775 | if (!want_sret and return_type.hasCodeGenBits()) { | 765 | if (!want_sret and return_type.hasCodeGenBits()) { |
| 776 | try returns.append(try self.typeToValtype(return_type)); | 766 | try returns.append(typeToValtype(return_type, target)); |
| 777 | } | 767 | } |
| 778 | | 768 | |
| 779 | return wasm.Type{ | 769 | return wasm.Type{ |
| ... | @@ -782,8 +772,8 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { | ... | @@ -782,8 +772,8 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { |
| 782 | }; | 772 | }; |
| 783 | } | 773 | } |
| 784 | | 774 | |
| 785 | pub fn genFunc(self: *Self) InnerError!Result { | 775 | pub fn genFunc(self: *Self) InnerError!void { |
| 786 | var func_type = try self.genFunctype(self.decl.ty); | 776 | var func_type = try genFunctype(self.gpa, self.decl.ty, self.target); |
| 787 | defer func_type.deinit(self.gpa); | 777 | defer func_type.deinit(self.gpa); |
| 788 | self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 778 | self.decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 789 | | 779 | |
| ... | @@ -828,240 +818,260 @@ pub fn genFunc(self: *Self) InnerError!Result { | ... | @@ -828,240 +818,260 @@ pub fn genFunc(self: *Self) InnerError!Result { |
| 828 | }, | 818 | }, |
| 829 | else => |e| return e, | 819 | else => |e| return e, |
| 830 | }; | 820 | }; |
| 831 | | | |
| 832 | // codegen data has been appended to `code` | | |
| 833 | return Result.appended; | | |
| 834 | } | 821 | } |
| 835 | | 822 | |
| 836 | pub fn genDecl(self: *Self) InnerError!Result { | 823 | pub const DeclGen = struct { |
| 837 | const decl = self.decl; | 824 | /// The decl we are generating code for. |
| 838 | assert(decl.has_tv); | 825 | decl: *Decl, |
| 839 | | 826 | /// The symbol we're generating code for. |
| 840 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); | 827 | /// This can either be the symbol of the Decl itself, |
| 841 | | 828 | /// or one of its locals. |
| 842 | if (decl.val.castTag(.function)) |func_payload| { | 829 | symbol_index: u32, |
| 843 | _ = func_payload; | 830 | gpa: Allocator, |
| 844 | return self.fail("TODO wasm backend genDecl function pointer", .{}); | 831 | /// A reference to the linker, that will process the decl's |
| 845 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { | 832 | /// code and create any relocations it deems neccesary. |
| 846 | const ext_decl = extern_fn.data; | 833 | bin_file: *link.File.Wasm, |
| 847 | var func_type = try self.genFunctype(ext_decl.ty); | 834 | /// This will be set when `InnerError` has been returned. |
| 848 | func_type.deinit(self.gpa); | 835 | /// In any other case, this will be 'undefined'. |
| 849 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 836 | err_msg: *Module.ErrorMsg, |
| 850 | return Result.appended; | 837 | /// Reference to the Module that is being compiled. |
| 851 | } else { | 838 | /// Used to find the error value of an error. |
| 852 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | 839 | module: *Module, |
| 853 | break :init_val payload.data.init; | 840 | /// The list of bytes that have been generated so far, |
| 854 | } else decl.val; | 841 | /// can be used to calculate the offset into a section. |
| 855 | if (init_val.tag() != .unreachable_value) { | 842 | code: *std.ArrayList(u8), |
| 856 | return try self.genTypedValue(decl.ty, init_val); | 843 | |
| | 844 | /// Sets `err_msg` on `DeclGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig |
| | 845 | fn fail(self: *DeclGen, comptime fmt: []const u8, args: anytype) InnerError { |
| | 846 | const src: LazySrcLoc = .{ .node_offset = 0 }; |
| | 847 | const src_loc = src.toSrcLoc(self.decl); |
| | 848 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args); |
| | 849 | return error.CodegenFail; |
| | 850 | } |
| | 851 | |
| | 852 | fn target(self: *const DeclGen) std.Target { |
| | 853 | return self.bin_file.base.options.target; |
| | 854 | } |
| | 855 | |
| | 856 | pub fn genDecl(self: *DeclGen) InnerError!Result { |
| | 857 | const decl = self.decl; |
| | 858 | assert(decl.has_tv); |
| | 859 | |
| | 860 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val }); |
| | 861 | |
| | 862 | if (decl.val.castTag(.function)) |func_payload| { |
| | 863 | _ = func_payload; |
| | 864 | return self.fail("TODO wasm backend genDecl function pointer", .{}); |
| | 865 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| | 866 | const ext_decl = extern_fn.data; |
| | 867 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target()); |
| | 868 | func_type.deinit(self.gpa); |
| | 869 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| | 870 | return Result.appended; |
| | 871 | } else { |
| | 872 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| | 873 | break :init_val payload.data.init; |
| | 874 | } else decl.val; |
| | 875 | if (init_val.tag() != .unreachable_value) { |
| | 876 | return try self.genTypedValue(decl.ty, init_val, self.code.writer()); |
| | 877 | } |
| | 878 | return Result.appended; |
| 857 | } | 879 | } |
| 858 | return Result.appended; | | |
| 859 | } | 880 | } |
| 860 | } | | |
| 861 | | 881 | |
| 862 | /// Generates the wasm bytecode for the declaration belonging to `Context` | 882 | /// Generates the wasm bytecode for the declaration belonging to `Context` |
| 863 | fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result { | 883 | fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result { |
| 864 | if (val.isUndef()) { | 884 | if (val.isUndef()) { |
| 865 | try self.code.appendNTimes(0xaa, @intCast(usize, ty.abiSize(self.target))); | 885 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 866 | return Result.appended; | 886 | return Result.appended; |
| 867 | } | 887 | } |
| 868 | switch (ty.zigTypeTag()) { | 888 | switch (ty.zigTypeTag()) { |
| 869 | .Fn => { | 889 | .Fn => { |
| 870 | const fn_decl = switch (val.tag()) { | 890 | const fn_decl = switch (val.tag()) { |
| 871 | .extern_fn => val.castTag(.extern_fn).?.data, | 891 | .extern_fn => val.castTag(.extern_fn).?.data, |
| 872 | .function => val.castTag(.function).?.data.owner_decl, | 892 | .function => val.castTag(.function).?.data.owner_decl, |
| 873 | else => unreachable, | 893 | else => unreachable, |
| 874 | }; | 894 | }; |
| 875 | return try self.lowerDeclRef(ty, val, fn_decl); | 895 | return try self.lowerDeclRef(ty, val, fn_decl, writer); |
| 876 | }, | 896 | }, |
| 877 | .Optional => { | 897 | .Optional => { |
| 878 | var opt_buf: Type.Payload.ElemType = undefined; | 898 | var opt_buf: Type.Payload.ElemType = undefined; |
| 879 | const payload_type = ty.optionalChild(&opt_buf); | 899 | const payload_type = ty.optionalChild(&opt_buf); |
| 880 | if (ty.isPtrLikeOptional()) { | 900 | const is_pl = !val.isNull(); |
| 881 | if (val.castTag(.opt_payload)) |payload| { | 901 | |
| 882 | return try self.genTypedValue(payload_type, payload.data); | 902 | if (!payload_type.hasCodeGenBits()) { |
| 883 | } else if (!val.isNull()) { | 903 | try writer.writeByteNTimes(@boolToInt(is_pl), 4); |
| 884 | return try self.genTypedValue(payload_type, val); | | |
| 885 | } else { | | |
| 886 | try self.code.appendNTimes(0, @intCast(usize, ty.abiSize(self.target))); | | |
| 887 | return Result.appended; | 904 | return Result.appended; |
| 888 | } | 905 | } |
| 889 | } | 906 | |
| 890 | // `null-tag` byte | 907 | if (ty.isPtrLikeOptional()) { |
| 891 | try self.code.appendNTimes(@boolToInt(!val.isNull()), 4); | 908 | if (val.castTag(.opt_payload)) |payload| { |
| 892 | const pl_result = try self.genTypedValue( | 909 | return try self.genTypedValue(payload_type, payload.data, writer); |
| 893 | payload_type, | 910 | } else if (!val.isNull()) { |
| 894 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 911 | return try self.genTypedValue(payload_type, val, writer); |
| 895 | ); | 912 | } else { |
| 896 | switch (pl_result) { | 913 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); |
| 897 | .appended => {}, | 914 | return Result.appended; |
| 898 | .externally_managed => |payload| try self.code.appendSlice(payload), | 915 | } |
| 899 | } | 916 | } |
| 900 | return Result.appended; | 917 | |
| 901 | }, | 918 | // `null-tag` bytes |
| 902 | .Array => switch (val.tag()) { | 919 | try writer.writeByteNTimes(@boolToInt(is_pl), 4); |
| 903 | .bytes => { | 920 | const pl_result = try self.genTypedValue( |
| 904 | const payload = val.castTag(.bytes).?; | 921 | payload_type, |
| 905 | return Result{ .externally_managed = payload.data }; | 922 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| | 923 | writer, |
| | 924 | ); |
| | 925 | switch (pl_result) { |
| | 926 | .appended => {}, |
| | 927 | .externally_managed => |payload| try writer.writeAll(payload), |
| | 928 | } |
| | 929 | return Result.appended; |
| 906 | }, | 930 | }, |
| 907 | .array => { | 931 | .Array => switch (val.tag()) { |
| 908 | const elem_vals = val.castTag(.array).?.data; | 932 | .bytes => { |
| 909 | const elem_ty = ty.childType(); | 933 | const payload = val.castTag(.bytes).?; |
| 910 | for (elem_vals) |elem_val| { | 934 | return Result{ .externally_managed = payload.data }; |
| 911 | switch (try self.genTypedValue(elem_ty, elem_val)) { | 935 | }, |
| | 936 | .array => { |
| | 937 | const elem_vals = val.castTag(.array).?.data; |
| | 938 | const elem_ty = ty.childType(); |
| | 939 | for (elem_vals) |elem_val| { |
| | 940 | switch (try self.genTypedValue(elem_ty, elem_val, writer)) { |
| | 941 | .appended => {}, |
| | 942 | .externally_managed => |data| try writer.writeAll(data), |
| | 943 | } |
| | 944 | } |
| | 945 | return Result.appended; |
| | 946 | }, |
| | 947 | else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}), |
| | 948 | }, |
| | 949 | .Int => { |
| | 950 | const info = ty.intInfo(self.target()); |
| | 951 | const abi_size = @intCast(usize, ty.abiSize(self.target())); |
| | 952 | // todo: Implement integer sizes larger than 64bits |
| | 953 | if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits}); |
| | 954 | var buf: [8]u8 = undefined; |
| | 955 | if (info.signedness == .unsigned) { |
| | 956 | std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt()); |
| | 957 | } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt()); |
| | 958 | try writer.writeAll(buf[0..abi_size]); |
| | 959 | return Result.appended; |
| | 960 | }, |
| | 961 | .Enum => { |
| | 962 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| | 963 | return Result.appended; |
| | 964 | }, |
| | 965 | .Bool => { |
| | 966 | try writer.writeByte(@boolToInt(val.toBool())); |
| | 967 | return Result.appended; |
| | 968 | }, |
| | 969 | .Struct => { |
| | 970 | const field_vals = val.castTag(.@"struct").?.data; |
| | 971 | for (field_vals) |field_val, index| { |
| | 972 | const field_ty = ty.structFieldType(index); |
| | 973 | if (!field_ty.hasCodeGenBits()) continue; |
| | 974 | switch (try self.genTypedValue(field_ty, field_val, writer)) { |
| 912 | .appended => {}, | 975 | .appended => {}, |
| 913 | .externally_managed => |data| try self.code.appendSlice(data), | 976 | .externally_managed => |payload| try writer.writeAll(payload), |
| 914 | } | 977 | } |
| 915 | } | 978 | } |
| 916 | return Result.appended; | 979 | return Result.appended; |
| 917 | }, | 980 | }, |
| 918 | else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}), | 981 | .Union => { |
| 919 | }, | 982 | // TODO: Implement Union declarations |
| 920 | .Int => { | 983 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 921 | const info = ty.intInfo(self.target); | 984 | return Result.appended; |
| 922 | const abi_size = @intCast(usize, ty.abiSize(self.target)); | | |
| 923 | // todo: Implement integer sizes larger than 64bits | | |
| 924 | if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits}); | | |
| 925 | var buf: [8]u8 = undefined; | | |
| 926 | if (info.signedness == .unsigned) { | | |
| 927 | std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt()); | | |
| 928 | } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt()); | | |
| 929 | try self.code.appendSlice(buf[0..abi_size]); | | |
| 930 | return Result.appended; | | |
| 931 | }, | | |
| 932 | .Enum => { | | |
| 933 | const size = @intCast(usize, ty.abiSize(self.target)); | | |
| 934 | try self.code.appendNTimes(0xaa, size); | | |
| 935 | return Result.appended; | | |
| 936 | }, | | |
| 937 | .Bool => { | | |
| 938 | const int_byte: u8 = @boolToInt(val.toBool()); | | |
| 939 | try self.code.append(int_byte); | | |
| 940 | return Result.appended; | | |
| 941 | }, | | |
| 942 | .Struct => { | | |
| 943 | const field_vals = val.castTag(.@"struct").?.data; | | |
| 944 | for (field_vals) |field_val, index| { | | |
| 945 | const field_ty = ty.structFieldType(index); | | |
| 946 | if (!field_ty.hasCodeGenBits()) continue; | | |
| 947 | switch (try self.genTypedValue(field_ty, field_val)) { | | |
| 948 | .appended => {}, | | |
| 949 | .externally_managed => |payload| try self.code.appendSlice(payload), | | |
| 950 | } | | |
| 951 | } | | |
| 952 | return Result.appended; | | |
| 953 | }, | | |
| 954 | .Union => { | | |
| 955 | // TODO: Implement Union declarations | | |
| 956 | const abi_size = @intCast(usize, ty.abiSize(self.target)); | | |
| 957 | try self.code.appendNTimes(0xaa, abi_size); | | |
| 958 | return Result.appended; | | |
| 959 | }, | | |
| 960 | .Pointer => switch (val.tag()) { | | |
| 961 | .variable => { | | |
| 962 | const decl = val.castTag(.variable).?.data.owner_decl; | | |
| 963 | return try self.lowerDeclRef(ty, val, decl); | | |
| 964 | }, | 985 | }, |
| 965 | .decl_ref => { | 986 | .Pointer => switch (val.tag()) { |
| 966 | const decl = val.castTag(.decl_ref).?.data; | 987 | .variable => { |
| 967 | return try self.lowerDeclRef(ty, val, decl); | 988 | const decl = val.castTag(.variable).?.data.owner_decl; |
| | 989 | return try self.lowerDeclRef(ty, val, decl, writer); |
| | 990 | }, |
| | 991 | .decl_ref => { |
| | 992 | const decl = val.castTag(.decl_ref).?.data; |
| | 993 | return try self.lowerDeclRef(ty, val, decl, writer); |
| | 994 | }, |
| | 995 | .slice => { |
| | 996 | const slice = val.castTag(.slice).?.data; |
| | 997 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| | 998 | const ptr_ty = ty.slicePtrFieldType(&buf); |
| | 999 | switch (try self.genTypedValue(ptr_ty, slice.ptr, writer)) { |
| | 1000 | .externally_managed => |data| try writer.writeAll(data), |
| | 1001 | .appended => {}, |
| | 1002 | } |
| | 1003 | switch (try self.genTypedValue(Type.usize, slice.len, writer)) { |
| | 1004 | .externally_managed => |data| try writer.writeAll(data), |
| | 1005 | .appended => {}, |
| | 1006 | } |
| | 1007 | return Result.appended; |
| | 1008 | }, |
| | 1009 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 968 | }, | 1010 | }, |
| 969 | .slice => { | 1011 | .ErrorUnion => { |
| 970 | const slice = val.castTag(.slice).?.data; | 1012 | const error_ty = ty.errorUnionSet(); |
| 971 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1013 | const payload_ty = ty.errorUnionPayload(); |
| 972 | const ptr_ty = ty.slicePtrFieldType(&buf); | 1014 | const is_pl = val.errorUnionIsPayload(); |
| 973 | switch (try self.genTypedValue(ptr_ty, slice.ptr)) { | 1015 | |
| 974 | .externally_managed => |data| try self.code.appendSlice(data), | 1016 | const err_val = if (!is_pl) val else Value.initTag(.zero); |
| | 1017 | switch (try self.genTypedValue(error_ty, err_val, writer)) { |
| | 1018 | .externally_managed => |data| try writer.writeAll(data), |
| 975 | .appended => {}, | 1019 | .appended => {}, |
| 976 | } | 1020 | } |
| 977 | switch (try self.genTypedValue(Type.usize, slice.len)) { | 1021 | |
| 978 | .externally_managed => |data| try self.code.appendSlice(data), | 1022 | if (payload_ty.hasCodeGenBits()) { |
| 979 | .appended => {}, | 1023 | const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); |
| | 1024 | switch (try self.genTypedValue(payload_ty, pl_val, writer)) { |
| | 1025 | .externally_managed => |data| try writer.writeAll(data), |
| | 1026 | .appended => {}, |
| | 1027 | } |
| 980 | } | 1028 | } |
| | 1029 | |
| 981 | return Result.appended; | 1030 | return Result.appended; |
| 982 | }, | 1031 | }, |
| 983 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), | 1032 | .ErrorSet => { |
| 984 | }, | 1033 | switch (val.tag()) { |
| 985 | .ErrorUnion => { | 1034 | .@"error" => { |
| 986 | const error_ty = ty.errorUnionSet(); | 1035 | const name = val.castTag(.@"error").?.data.name; |
| 987 | const payload_ty = ty.errorUnionPayload(); | 1036 | const kv = try self.module.getErrorValue(name); |
| 988 | const is_pl = val.errorUnionIsPayload(); | 1037 | try writer.writeIntLittle(u32, kv.value); |
| 989 | | 1038 | }, |
| 990 | const err_val = if (!is_pl) val else Value.initTag(.zero); | 1039 | else => { |
| 991 | switch (try self.genTypedValue(error_ty, err_val)) { | 1040 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); |
| 992 | .externally_managed => |data| try self.code.appendSlice(data), | 1041 | }, |
| 993 | .appended => {}, | | |
| 994 | } | | |
| 995 | | | |
| 996 | if (payload_ty.hasCodeGenBits()) { | | |
| 997 | const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); | | |
| 998 | switch (try self.genTypedValue(payload_ty, pl_val)) { | | |
| 999 | .externally_managed => |data| try self.code.appendSlice(data), | | |
| 1000 | .appended => {}, | | |
| 1001 | } | 1042 | } |
| 1002 | } | 1043 | return Result.appended; |
| 1003 | | 1044 | }, |
| 1004 | return Result.appended; | 1045 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), |
| 1005 | }, | 1046 | } |
| 1006 | .ErrorSet => { | | |
| 1007 | switch (val.tag()) { | | |
| 1008 | .@"error" => { | | |
| 1009 | const name = val.castTag(.@"error").?.data.name; | | |
| 1010 | const value = self.global_error_set.get(name).?; | | |
| 1011 | try self.code.writer().writeIntLittle(u32, value); | | |
| 1012 | }, | | |
| 1013 | else => { | | |
| 1014 | const abi_size = @intCast(usize, ty.abiSize(self.target)); | | |
| 1015 | try self.code.appendNTimes(0, abi_size); | | |
| 1016 | }, | | |
| 1017 | } | | |
| 1018 | return Result.appended; | | |
| 1019 | }, | | |
| 1020 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), | | |
| 1021 | } | 1047 | } |
| 1022 | } | | |
| 1023 | | 1048 | |
| 1024 | fn lowerDeclRef(self: *Self, ty: Type, val: Value, decl: *Module.Decl) InnerError!Result { | 1049 | fn lowerDeclRef(self: *DeclGen, ty: Type, val: Value, decl: *Module.Decl, writer: anytype) InnerError!Result { |
| 1025 | if (ty.isSlice()) { | 1050 | if (ty.isSlice()) { |
| 1026 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1051 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1027 | const slice_ty = ty.slicePtrFieldType(&buf); | 1052 | const slice_ty = ty.slicePtrFieldType(&buf); |
| 1028 | switch (try self.genTypedValue(slice_ty, val)) { | 1053 | switch (try self.genTypedValue(slice_ty, val, writer)) { |
| 1029 | .appended => {}, | 1054 | .appended => {}, |
| 1030 | .externally_managed => |payload| try self.code.appendSlice(payload), | 1055 | .externally_managed => |payload| try writer.writeAll(payload), |
| | 1056 | } |
| | 1057 | var slice_len: Value.Payload.U64 = .{ |
| | 1058 | .base = .{ .tag = .int_u64 }, |
| | 1059 | .data = val.sliceLen(), |
| | 1060 | }; |
| | 1061 | return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer); |
| 1031 | } | 1062 | } |
| 1032 | var slice_len: Value.Payload.U64 = .{ | | |
| 1033 | .base = .{ .tag = .int_u64 }, | | |
| 1034 | .data = val.sliceLen(), | | |
| 1035 | }; | | |
| 1036 | return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base)); | | |
| 1037 | } | | |
| 1038 | | | |
| 1039 | const offset = @intCast(u32, self.code.items.len); | | |
| 1040 | const atom = &self.decl.link.wasm; | | |
| 1041 | const target_sym_index = decl.link.wasm.sym_index; | | |
| 1042 | decl.markAlive(); | | |
| 1043 | if (decl.ty.zigTypeTag() == .Fn) { | | |
| 1044 | // We found a function pointer, so add it to our table, | | |
| 1045 | // as function pointers are not allowed to be stored inside the data section, | | |
| 1046 | // but rather in a function table which are called by index | | |
| 1047 | try self.bin_file.addTableFunction(target_sym_index); | | |
| 1048 | try atom.relocs.append(self.gpa, .{ | | |
| 1049 | .index = target_sym_index, | | |
| 1050 | .offset = offset, | | |
| 1051 | .relocation_type = .R_WASM_TABLE_INDEX_I32, | | |
| 1052 | }); | | |
| 1053 | } else { | | |
| 1054 | try atom.relocs.append(self.gpa, .{ | | |
| 1055 | .index = target_sym_index, | | |
| 1056 | .offset = offset, | | |
| 1057 | .relocation_type = .R_WASM_MEMORY_ADDR_I32, | | |
| 1058 | }); | | |
| 1059 | } | | |
| 1060 | const ptr_width = @intCast(usize, self.target.cpu.arch.ptrBitWidth() / 8); | | |
| 1061 | try self.code.appendNTimes(0xaa, ptr_width); | | |
| 1062 | | 1063 | |
| 1063 | return Result.appended; | 1064 | decl.markAlive(); |
| 1064 | } | 1065 | try writer.writeIntLittle(u32, try self.bin_file.getDeclVAddr( |
| | 1066 | self.decl, // The decl containing the source symbol index |
| | 1067 | decl.ty, // type we generate the address of |
| | 1068 | self.symbol_index, // source symbol index |
| | 1069 | decl.link.wasm.sym_index, // target symbol index |
| | 1070 | @intCast(u32, self.code.items.len), // offset |
| | 1071 | )); |
| | 1072 | return Result.appended; |
| | 1073 | } |
| | 1074 | }; |
| 1065 | | 1075 | |
| 1066 | const CallWValues = struct { | 1076 | const CallWValues = struct { |
| 1067 | args: []WValue, | 1077 | args: []WValue, |
| ... | @@ -1086,7 +1096,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu | ... | @@ -1086,7 +1096,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1086 | const ret_ty = fn_ty.fnReturnType(); | 1096 | const ret_ty = fn_ty.fnReturnType(); |
| 1087 | // Check if we store the result as a pointer to the stack rather than | 1097 | // Check if we store the result as a pointer to the stack rather than |
| 1088 | // by value | 1098 | // by value |
| 1089 | if (self.isByRef(ret_ty)) { | 1099 | if (isByRef(ret_ty, self.target)) { |
| 1090 | // the sret arg will be passed as first argument, therefore we | 1100 | // the sret arg will be passed as first argument, therefore we |
| 1091 | // set the `return_value` before allocating locals for regular args. | 1101 | // set the `return_value` before allocating locals for regular args. |
| 1092 | result.return_value = .{ .local = self.local_index }; | 1102 | result.return_value = .{ .local = self.local_index }; |
| ... | @@ -1213,8 +1223,8 @@ fn arch(self: *const Self) std.Target.Cpu.Arch { | ... | @@ -1213,8 +1223,8 @@ fn arch(self: *const Self) std.Target.Cpu.Arch { |
| 1213 | } | 1223 | } |
| 1214 | | 1224 | |
| 1215 | /// For a given `Type`, will return true when the type will be passed | 1225 | /// For a given `Type`, will return true when the type will be passed |
| 1216 | /// by reference, rather than by value. | 1226 | /// by reference, rather than by value |
| 1217 | fn isByRef(self: Self, ty: Type) bool { | 1227 | fn isByRef(ty: Type, target: std.Target) bool { |
| 1218 | switch (ty.zigTypeTag()) { | 1228 | switch (ty.zigTypeTag()) { |
| 1219 | .Type, | 1229 | .Type, |
| 1220 | .ComptimeInt, | 1230 | .ComptimeInt, |
| ... | @@ -1242,7 +1252,7 @@ fn isByRef(self: Self, ty: Type) bool { | ... | @@ -1242,7 +1252,7 @@ fn isByRef(self: Self, ty: Type) bool { |
| 1242 | .Frame, | 1252 | .Frame, |
| 1243 | .Union, | 1253 | .Union, |
| 1244 | => return ty.hasCodeGenBits(), | 1254 | => return ty.hasCodeGenBits(), |
| 1245 | .Int => return if (ty.intInfo(self.target).bits > 64) true else false, | 1255 | .Int => return if (ty.intInfo(target).bits > 64) true else false, |
| 1246 | .ErrorUnion => { | 1256 | .ErrorUnion => { |
| 1247 | const has_tag = ty.errorUnionSet().hasCodeGenBits(); | 1257 | const has_tag = ty.errorUnionSet().hasCodeGenBits(); |
| 1248 | const has_pl = ty.errorUnionPayload().hasCodeGenBits(); | 1258 | const has_pl = ty.errorUnionPayload().hasCodeGenBits(); |
| ... | @@ -1470,7 +1480,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1470,7 +1480,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1470 | const child_type = self.air.typeOfIndex(inst).childType(); | 1480 | const child_type = self.air.typeOfIndex(inst).childType(); |
| 1471 | if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} }; | 1481 | if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} }; |
| 1472 | | 1482 | |
| 1473 | if (self.isByRef(child_type)) { | 1483 | if (isByRef(child_type, self.target)) { |
| 1474 | return self.return_value; | 1484 | return self.return_value; |
| 1475 | } | 1485 | } |
| 1476 | | 1486 | |
| ... | @@ -1487,7 +1497,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1487,7 +1497,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1487 | const ret_ty = self.air.typeOf(un_op).childType(); | 1497 | const ret_ty = self.air.typeOf(un_op).childType(); |
| 1488 | if (!ret_ty.hasCodeGenBits()) return WValue.none; | 1498 | if (!ret_ty.hasCodeGenBits()) return WValue.none; |
| 1489 | | 1499 | |
| 1490 | if (!self.isByRef(ret_ty)) { | 1500 | if (!isByRef(ret_ty, self.target)) { |
| 1491 | const result = try self.load(operand, ret_ty, 0); | 1501 | const result = try self.load(operand, ret_ty, 0); |
| 1492 | try self.emitWValue(result); | 1502 | try self.emitWValue(result); |
| 1493 | } | 1503 | } |
| ... | @@ -1509,7 +1519,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1509,7 +1519,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1509 | else => unreachable, | 1519 | else => unreachable, |
| 1510 | }; | 1520 | }; |
| 1511 | const ret_ty = fn_ty.fnReturnType(); | 1521 | const ret_ty = fn_ty.fnReturnType(); |
| 1512 | const first_param_sret = self.isByRef(ret_ty); | 1522 | const first_param_sret = isByRef(ret_ty, self.target); |
| 1513 | | 1523 | |
| 1514 | const target: ?*Decl = blk: { | 1524 | const target: ?*Decl = blk: { |
| 1515 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; | 1525 | const func_val = self.air.value(pl_op.operand) orelse break :blk null; |
| ... | @@ -1546,7 +1556,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1546,7 +1556,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1546 | const operand = try self.resolveInst(pl_op.operand); | 1556 | const operand = try self.resolveInst(pl_op.operand); |
| 1547 | try self.emitWValue(operand); | 1557 | try self.emitWValue(operand); |
| 1548 | | 1558 | |
| 1549 | var fn_type = try self.genFunctype(fn_ty); | 1559 | var fn_type = try genFunctype(self.gpa, fn_ty, self.target); |
| 1550 | defer fn_type.deinit(self.gpa); | 1560 | defer fn_type.deinit(self.gpa); |
| 1551 | | 1561 | |
| 1552 | const fn_type_index = try self.bin_file.putOrGetFuncType(fn_type); | 1562 | const fn_type_index = try self.bin_file.putOrGetFuncType(fn_type); |
| ... | @@ -1642,7 +1652,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1642,7 +1652,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1642 | } | 1652 | } |
| 1643 | try self.emitWValue(lhs); | 1653 | try self.emitWValue(lhs); |
| 1644 | try self.emitWValue(rhs); | 1654 | try self.emitWValue(rhs); |
| 1645 | const valtype = try self.typeToValtype(ty); | 1655 | const valtype = typeToValtype(ty, self.target); |
| 1646 | // check if we should pass by pointer or value based on ABI size | 1656 | // check if we should pass by pointer or value based on ABI size |
| 1647 | // TODO: Implement a way to get ABI values from a given type, | 1657 | // TODO: Implement a way to get ABI values from a given type, |
| 1648 | // that is portable across the backend, rather than copying logic. | 1658 | // that is portable across the backend, rather than copying logic. |
| ... | @@ -1675,7 +1685,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1675,7 +1685,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1675 | | 1685 | |
| 1676 | if (!ty.hasCodeGenBits()) return WValue{ .none = {} }; | 1686 | if (!ty.hasCodeGenBits()) return WValue{ .none = {} }; |
| 1677 | | 1687 | |
| 1678 | if (self.isByRef(ty)) { | 1688 | if (isByRef(ty, self.target)) { |
| 1679 | const new_local = try self.allocStack(ty); | 1689 | const new_local = try self.allocStack(ty); |
| 1680 | try self.store(new_local, operand, ty, 0); | 1690 | try self.store(new_local, operand, ty, 0); |
| 1681 | return new_local; | 1691 | return new_local; |
| ... | @@ -1712,7 +1722,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | ... | @@ -1712,7 +1722,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1712 | }; | 1722 | }; |
| 1713 | | 1723 | |
| 1714 | const opcode = buildOpcode(.{ | 1724 | const opcode = buildOpcode(.{ |
| 1715 | .valtype1 = try self.typeToValtype(ty), | 1725 | .valtype1 = typeToValtype(ty, self.target), |
| 1716 | .width = abi_size * 8, // use bitsize instead of byte size | 1726 | .width = abi_size * 8, // use bitsize instead of byte size |
| 1717 | .op = .load, | 1727 | .op = .load, |
| 1718 | .signedness = signedness, | 1728 | .signedness = signedness, |
| ... | @@ -1743,7 +1753,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -1743,7 +1753,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 1743 | const rhs = try self.resolveInst(bin_op.rhs); | 1753 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1744 | const operand_ty = self.air.typeOfIndex(inst); | 1754 | const operand_ty = self.air.typeOfIndex(inst); |
| 1745 | | 1755 | |
| 1746 | if (self.isByRef(operand_ty)) { | 1756 | if (isByRef(operand_ty, self.target)) { |
| 1747 | return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty}); | 1757 | return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty}); |
| 1748 | } | 1758 | } |
| 1749 | | 1759 | |
| ... | @@ -1753,7 +1763,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -1753,7 +1763,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 1753 | const bin_ty = self.air.typeOf(bin_op.lhs); | 1763 | const bin_ty = self.air.typeOf(bin_op.lhs); |
| 1754 | const opcode: wasm.Opcode = buildOpcode(.{ | 1764 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 1755 | .op = op, | 1765 | .op = op, |
| 1756 | .valtype1 = try self.typeToValtype(bin_ty), | 1766 | .valtype1 = typeToValtype(bin_ty, self.target), |
| 1757 | .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned, | 1767 | .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned, |
| 1758 | }); | 1768 | }); |
| 1759 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 1769 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| ... | @@ -1775,7 +1785,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -1775,7 +1785,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 1775 | const bin_ty = self.air.typeOf(bin_op.lhs); | 1785 | const bin_ty = self.air.typeOf(bin_op.lhs); |
| 1776 | const opcode: wasm.Opcode = buildOpcode(.{ | 1786 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 1777 | .op = op, | 1787 | .op = op, |
| 1778 | .valtype1 = try self.typeToValtype(bin_ty), | 1788 | .valtype1 = typeToValtype(bin_ty, self.target), |
| 1779 | .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned, | 1789 | .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned, |
| 1780 | }); | 1790 | }); |
| 1781 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 1791 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| ... | @@ -1924,8 +1934,8 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { | ... | @@ -1924,8 +1934,8 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1924 | }, | 1934 | }, |
| 1925 | .ErrorSet => switch (val.tag()) { | 1935 | .ErrorSet => switch (val.tag()) { |
| 1926 | .@"error" => { | 1936 | .@"error" => { |
| 1927 | const error_index = self.global_error_set.get(val.getError().?).?; | 1937 | const kv = try self.module.getErrorValue(val.getError().?); |
| 1928 | return WValue{ .imm32 = error_index }; | 1938 | return WValue{ .imm32 = kv.value }; |
| 1929 | }, | 1939 | }, |
| 1930 | else => return WValue{ .imm32 = 0 }, | 1940 | else => return WValue{ .imm32 = 0 }, |
| 1931 | }, | 1941 | }, |
| ... | @@ -1945,7 +1955,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { | ... | @@ -1945,7 +1955,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1945 | if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | 1955 | if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1946 | payload_type, | 1956 | payload_type, |
| 1947 | ); | 1957 | ); |
| 1948 | const pl_ptr = if (self.isByRef(payload_type)) | 1958 | const pl_ptr = if (isByRef(payload_type, self.target)) |
| 1949 | try self.buildPointerOffset(result, error_type.abiSize(self.target), .new) | 1959 | try self.buildPointerOffset(result, error_type.abiSize(self.target), .new) |
| 1950 | else | 1960 | else |
| 1951 | result; | 1961 | result; |
| ... | @@ -2159,8 +2169,8 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { | ... | @@ -2159,8 +2169,8 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { |
| 2159 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())), | 2169 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt())), |
| 2160 | }, | 2170 | }, |
| 2161 | .ErrorSet => { | 2171 | .ErrorSet => { |
| 2162 | const error_index = self.global_error_set.get(val.getError().?).?; | 2172 | const kv = self.module.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function |
| 2163 | return @bitCast(i32, error_index); | 2173 | return @bitCast(i32, kv.value); |
| 2164 | }, | 2174 | }, |
| 2165 | else => unreachable, // Programmer called this function for an illegal type | 2175 | else => unreachable, // Programmer called this function for an illegal type |
| 2166 | } | 2176 | } |
| ... | @@ -2168,7 +2178,7 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { | ... | @@ -2168,7 +2178,7 @@ fn valueAsI32(self: Self, val: Value, ty: Type) i32 { |
| 2168 | | 2178 | |
| 2169 | fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2179 | fn airBlock(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2170 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2180 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2171 | const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty)); | 2181 | const block_ty = genBlockType(self.air.getRefType(ty_pl.ty), self.target); |
| 2172 | const extra = self.air.extraData(Air.Block, ty_pl.payload); | 2182 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 2173 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 2183 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 2174 | | 2184 | |
| ... | @@ -2265,7 +2275,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2265,7 +2275,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2265 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs | 2275 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 2266 | return self.cmpOptionals(lhs, rhs, operand_ty, op); | 2276 | return self.cmpOptionals(lhs, rhs, operand_ty, op); |
| 2267 | } | 2277 | } |
| 2268 | } else if (self.isByRef(operand_ty)) { | 2278 | } else if (isByRef(operand_ty, self.target)) { |
| 2269 | return self.cmpBigInt(lhs, rhs, operand_ty, op); | 2279 | return self.cmpBigInt(lhs, rhs, operand_ty, op); |
| 2270 | } | 2280 | } |
| 2271 | | 2281 | |
| ... | @@ -2280,7 +2290,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner | ... | @@ -2280,7 +2290,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner |
| 2280 | break :blk operand_ty.intInfo(self.target).signedness; | 2290 | break :blk operand_ty.intInfo(self.target).signedness; |
| 2281 | }; | 2291 | }; |
| 2282 | const opcode: wasm.Opcode = buildOpcode(.{ | 2292 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 2283 | .valtype1 = try self.typeToValtype(operand_ty), | 2293 | .valtype1 = typeToValtype(operand_ty, self.target), |
| 2284 | .op = switch (op) { | 2294 | .op = switch (op) { |
| 2285 | .lt => .lt, | 2295 | .lt => .lt, |
| 2286 | .lte => .le, | 2296 | .lte => .le, |
| ... | @@ -2353,13 +2363,6 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2353,13 +2363,6 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2353 | fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2363 | fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2354 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2364 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2355 | const operand = try self.resolveInst(ty_op.operand); | 2365 | const operand = try self.resolveInst(ty_op.operand); |
| 2356 | // if (operand == .constant) { | | |
| 2357 | // std.debug.print("Let's take a look at this!!!!!!\n--------------------\n", .{}); | | |
| 2358 | // const result = try self.allocLocal(self.air.typeOfIndex(inst)); | | |
| 2359 | // try self.emitWValue(operand); | | |
| 2360 | // try self.addLabel(.local_set, result.local); | | |
| 2361 | // return result; | | |
| 2362 | // } | | |
| 2363 | return operand; | 2366 | return operand; |
| 2364 | } | 2367 | } |
| 2365 | | 2368 | |
| ... | @@ -2407,7 +2410,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2407,7 +2410,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2407 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); | 2410 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); |
| 2408 | }; | 2411 | }; |
| 2409 | | 2412 | |
| 2410 | if (self.isByRef(field_ty)) { | 2413 | if (isByRef(field_ty, self.target)) { |
| 2411 | return self.buildPointerOffset(operand, offset, .new); | 2414 | return self.buildPointerOffset(operand, offset, .new); |
| 2412 | } | 2415 | } |
| 2413 | | 2416 | |
| ... | @@ -2527,7 +2530,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2527,7 +2530,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2527 | const val = try self.lowerConstant(case.values[0].value, target_ty); | 2530 | const val = try self.lowerConstant(case.values[0].value, target_ty); |
| 2528 | try self.emitWValue(val); | 2531 | try self.emitWValue(val); |
| 2529 | const opcode = buildOpcode(.{ | 2532 | const opcode = buildOpcode(.{ |
| 2530 | .valtype1 = try self.typeToValtype(target_ty), | 2533 | .valtype1 = typeToValtype(target_ty, self.target), |
| 2531 | .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition. | 2534 | .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition. |
| 2532 | .signedness = signedness, | 2535 | .signedness = signedness, |
| 2533 | }); | 2536 | }); |
| ... | @@ -2541,7 +2544,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2541,7 +2544,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2541 | const val = try self.lowerConstant(value.value, target_ty); | 2544 | const val = try self.lowerConstant(value.value, target_ty); |
| 2542 | try self.emitWValue(val); | 2545 | try self.emitWValue(val); |
| 2543 | const opcode = buildOpcode(.{ | 2546 | const opcode = buildOpcode(.{ |
| 2544 | .valtype1 = try self.typeToValtype(target_ty), | 2547 | .valtype1 = typeToValtype(target_ty, self.target), |
| 2545 | .op = .eq, | 2548 | .op = .eq, |
| 2546 | .signedness = signedness, | 2549 | .signedness = signedness, |
| 2547 | }); | 2550 | }); |
| ... | @@ -2596,7 +2599,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue | ... | @@ -2596,7 +2599,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue |
| 2596 | const payload_ty = err_ty.errorUnionPayload(); | 2599 | const payload_ty = err_ty.errorUnionPayload(); |
| 2597 | if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} }; | 2600 | if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} }; |
| 2598 | const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target)); | 2601 | const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target)); |
| 2599 | if (self.isByRef(payload_ty)) { | 2602 | if (isByRef(payload_ty, self.target)) { |
| 2600 | return self.buildPointerOffset(operand, offset, .new); | 2603 | return self.buildPointerOffset(operand, offset, .new); |
| 2601 | } | 2604 | } |
| 2602 | return try self.load(operand, payload_ty, offset); | 2605 | return try self.load(operand, payload_ty, offset); |
| ... | @@ -2725,7 +2728,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2725,7 +2728,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2725 | | 2728 | |
| 2726 | const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target); | 2729 | const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target); |
| 2727 | | 2730 | |
| 2728 | if (self.isByRef(payload_ty)) { | 2731 | if (isByRef(payload_ty, self.target)) { |
| 2729 | return self.buildPointerOffset(operand, offset, .new); | 2732 | return self.buildPointerOffset(operand, offset, .new); |
| 2730 | } | 2733 | } |
| 2731 | | 2734 | |
| ... | @@ -2856,7 +2859,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2856,7 +2859,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2856 | const result = try self.allocLocal(elem_ty); | 2859 | const result = try self.allocLocal(elem_ty); |
| 2857 | try self.addLabel(.local_set, result.local); | 2860 | try self.addLabel(.local_set, result.local); |
| 2858 | | 2861 | |
| 2859 | if (self.isByRef(elem_ty)) { | 2862 | if (isByRef(elem_ty, self.target)) { |
| 2860 | return result; | 2863 | return result; |
| 2861 | } | 2864 | } |
| 2862 | return try self.load(result, elem_ty, 0); | 2865 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3017,7 +3020,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3017,7 +3020,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3017 | | 3020 | |
| 3018 | const result = try self.allocLocal(elem_ty); | 3021 | const result = try self.allocLocal(elem_ty); |
| 3019 | try self.addLabel(.local_set, result.local); | 3022 | try self.addLabel(.local_set, result.local); |
| 3020 | if (self.isByRef(elem_ty)) { | 3023 | if (isByRef(elem_ty, self.target)) { |
| 3021 | return result; | 3024 | return result; |
| 3022 | } | 3025 | } |
| 3023 | return try self.load(result, elem_ty, 0); | 3026 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3064,7 +3067,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -3064,7 +3067,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 3064 | else => ptr_ty.childType(), | 3067 | else => ptr_ty.childType(), |
| 3065 | }; | 3068 | }; |
| 3066 | | 3069 | |
| 3067 | const valtype = try self.typeToValtype(Type.usize); | 3070 | const valtype = typeToValtype(Type.usize, self.target); |
| 3068 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); | 3071 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); |
| 3069 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); | 3072 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); |
| 3070 | | 3073 | |
| ... | @@ -3167,7 +3170,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3167,7 +3170,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3167 | const result = try self.allocLocal(elem_ty); | 3170 | const result = try self.allocLocal(elem_ty); |
| 3168 | try self.addLabel(.local_set, result.local); | 3171 | try self.addLabel(.local_set, result.local); |
| 3169 | | 3172 | |
| 3170 | if (self.isByRef(elem_ty)) { | 3173 | if (isByRef(elem_ty, self.target)) { |
| 3171 | return result; | 3174 | return result; |
| 3172 | } | 3175 | } |
| 3173 | return try self.load(result, elem_ty, 0); | 3176 | return try self.load(result, elem_ty, 0); |
| ... | @@ -3184,8 +3187,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3184,8 +3187,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3184 | try self.emitWValue(operand); | 3187 | try self.emitWValue(operand); |
| 3185 | const op = buildOpcode(.{ | 3188 | const op = buildOpcode(.{ |
| 3186 | .op = .trunc, | 3189 | .op = .trunc, |
| 3187 | .valtype1 = try self.typeToValtype(dest_ty), | 3190 | .valtype1 = typeToValtype(dest_ty, self.target), |
| 3188 | .valtype2 = try self.typeToValtype(op_ty), | 3191 | .valtype2 = typeToValtype(op_ty, self.target), |
| 3189 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, | 3192 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, |
| 3190 | }); | 3193 | }); |
| 3191 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); | 3194 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| ... | @@ -3249,7 +3252,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -3249,7 +3252,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 3249 | | 3252 | |
| 3250 | try self.emitWValue(lhs_pl); | 3253 | try self.emitWValue(lhs_pl); |
| 3251 | try self.emitWValue(rhs_pl); | 3254 | try self.emitWValue(rhs_pl); |
| 3252 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = try self.typeToValtype(payload_ty) }); | 3255 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) }); |
| 3253 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 3256 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 3254 | try self.addLabel(.br_if, 0); | 3257 | try self.addLabel(.br_if, 0); |
| 3255 | | 3258 | |