| ... | ... | @@ -599,7 +599,41 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue { |
| 599 | 599 | const val = self.air.value(ref).?; |
| 600 | 600 | const ty = self.air.typeOf(ref); |
| 601 | 601 | if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} }; |
| 602 | | const result = try self.lowerConstant(val, ty); |
| 602 | |
| 603 | // When we need to pass the value by reference (such as a struct), we will |
| 604 | // leverage `genTypedValue` to lower the constant to bytes and emit it |
| 605 | // to the 'rodata' section. We then return the index into the section as `WValue`. |
| 606 | // |
| 607 | // In the other cases, we will simply lower the constant to a value that fits |
| 608 | // into a single local (such as a pointer, integer, bool, etc). |
| 609 | const result = if (isByRef(ty, self.target)) blk: { |
| 610 | var value_bytes = std.ArrayList(u8).init(self.gpa); |
| 611 | defer value_bytes.deinit(); |
| 612 | |
| 613 | var decl_gen: DeclGen = .{ |
| 614 | .bin_file = self.bin_file, |
| 615 | .decl = self.decl, |
| 616 | .err_msg = undefined, |
| 617 | .gpa = self.gpa, |
| 618 | .module = self.module, |
| 619 | .code = &value_bytes, |
| 620 | .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty), |
| 621 | }; |
| 622 | const result = decl_gen.genTypedValue(ty, val, value_bytes.writer()) catch |err| { |
| 623 | // When a codegen error occured, take ownership of the error message |
| 624 | if (err == error.CodegenFail) { |
| 625 | self.err_msg = decl_gen.err_msg; |
| 626 | } |
| 627 | return err; |
| 628 | }; |
| 629 | const code = switch (result) { |
| 630 | .appended => value_bytes.items, |
| 631 | .externally_managed => |data| data, |
| 632 | }; |
| 633 | try self.bin_file.updateLocalSymbolCode(self.decl, decl_gen.symbol_index, code); |
| 634 | break :blk WValue{ .memory = decl_gen.symbol_index }; |
| 635 | } else try self.lowerConstant(val, ty); |
| 636 | |
| 603 | 637 | gop.value_ptr.* = result; |
| 604 | 638 | return result; |
| 605 | 639 | } |
| ... | ... | @@ -867,15 +901,15 @@ pub const DeclGen = struct { |
| 867 | 901 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target()); |
| 868 | 902 | func_type.deinit(self.gpa); |
| 869 | 903 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 870 | | return Result.appended; |
| 904 | return Result{ .appended = {} }; |
| 871 | 905 | } else { |
| 872 | 906 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| 873 | 907 | break :init_val payload.data.init; |
| 874 | 908 | } else decl.val; |
| 875 | 909 | if (init_val.tag() != .unreachable_value) { |
| 876 | | return try self.genTypedValue(decl.ty, init_val, self.code.writer()); |
| 910 | return self.genTypedValue(decl.ty, init_val, self.code.writer()); |
| 877 | 911 | } |
| 878 | | return Result.appended; |
| 912 | return Result{ .appended = {} }; |
| 879 | 913 | } |
| 880 | 914 | } |
| 881 | 915 | |
| ... | ... | @@ -883,7 +917,7 @@ pub const DeclGen = struct { |
| 883 | 917 | fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result { |
| 884 | 918 | if (val.isUndef()) { |
| 885 | 919 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 886 | | return Result.appended; |
| 920 | return Result{ .appended = {} }; |
| 887 | 921 | } |
| 888 | 922 | switch (ty.zigTypeTag()) { |
| 889 | 923 | .Fn => { |
| ... | ... | @@ -898,35 +932,36 @@ pub const DeclGen = struct { |
| 898 | 932 | var opt_buf: Type.Payload.ElemType = undefined; |
| 899 | 933 | const payload_type = ty.optionalChild(&opt_buf); |
| 900 | 934 | const is_pl = !val.isNull(); |
| 935 | const abi_size = @intCast(usize, ty.abiSize(self.target())); |
| 936 | const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target())); |
| 901 | 937 | |
| 902 | 938 | if (!payload_type.hasCodeGenBits()) { |
| 903 | | try writer.writeByteNTimes(@boolToInt(is_pl), 4); |
| 904 | | return Result.appended; |
| 939 | try writer.writeByteNTimes(@boolToInt(is_pl), abi_size); |
| 940 | return Result{ .appended = {} }; |
| 905 | 941 | } |
| 906 | 942 | |
| 907 | 943 | if (ty.isPtrLikeOptional()) { |
| 908 | 944 | if (val.castTag(.opt_payload)) |payload| { |
| 909 | | return try self.genTypedValue(payload_type, payload.data, writer); |
| 945 | return self.genTypedValue(payload_type, payload.data, writer); |
| 910 | 946 | } else if (!val.isNull()) { |
| 911 | | return try self.genTypedValue(payload_type, val, writer); |
| 947 | return self.genTypedValue(payload_type, val, writer); |
| 912 | 948 | } else { |
| 913 | | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); |
| 914 | | return Result.appended; |
| 949 | try writer.writeByteNTimes(0, abi_size); |
| 950 | return Result{ .appended = {} }; |
| 915 | 951 | } |
| 916 | 952 | } |
| 917 | 953 | |
| 918 | 954 | // `null-tag` bytes |
| 919 | | try writer.writeByteNTimes(@boolToInt(is_pl), 4); |
| 920 | | const pl_result = try self.genTypedValue( |
| 955 | try writer.writeByteNTimes(@boolToInt(is_pl), offset); |
| 956 | switch (try self.genTypedValue( |
| 921 | 957 | payload_type, |
| 922 | 958 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 923 | 959 | writer, |
| 924 | | ); |
| 925 | | switch (pl_result) { |
| 960 | )) { |
| 926 | 961 | .appended => {}, |
| 927 | 962 | .externally_managed => |payload| try writer.writeAll(payload), |
| 928 | 963 | } |
| 929 | | return Result.appended; |
| 964 | return Result{ .appended = {} }; |
| 930 | 965 | }, |
| 931 | 966 | .Array => switch (val.tag()) { |
| 932 | 967 | .bytes => { |
| ... | ... | @@ -942,29 +977,68 @@ pub const DeclGen = struct { |
| 942 | 977 | .externally_managed => |data| try writer.writeAll(data), |
| 943 | 978 | } |
| 944 | 979 | } |
| 945 | | return Result.appended; |
| 980 | return Result{ .appended = {} }; |
| 981 | }, |
| 982 | .repeated => { |
| 983 | const array = val.castTag(.repeated).?.data; |
| 984 | const elem_ty = ty.childType(); |
| 985 | const sentinel = ty.sentinel(); |
| 986 | const len = ty.arrayLen(); |
| 987 | |
| 988 | var index: u32 = 0; |
| 989 | while (index < len) : (index += 1) { |
| 990 | switch (try self.genTypedValue(elem_ty, array, writer)) { |
| 991 | .externally_managed => |data| try writer.writeAll(data), |
| 992 | .appended => {}, |
| 993 | } |
| 994 | } |
| 995 | if (sentinel) |sentinel_value| { |
| 996 | return self.genTypedValue(elem_ty, sentinel_value, writer); |
| 997 | } |
| 998 | return Result{ .appended = {} }; |
| 999 | }, |
| 1000 | .empty_array_sentinel => { |
| 1001 | const elem_ty = ty.childType(); |
| 1002 | const sent_val = ty.sentinel().?; |
| 1003 | return self.genTypedValue(elem_ty, sent_val, writer); |
| 946 | 1004 | }, |
| 947 | | else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}), |
| 1005 | else => unreachable, |
| 948 | 1006 | }, |
| 949 | 1007 | .Int => { |
| 950 | 1008 | const info = ty.intInfo(self.target()); |
| 951 | 1009 | 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; |
| 1010 | if (info.bits <= 64) { |
| 1011 | var buf: [8]u8 = undefined; |
| 1012 | if (info.signedness == .unsigned) { |
| 1013 | std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt()); |
| 1014 | } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt()); |
| 1015 | try writer.writeAll(buf[0..abi_size]); |
| 1016 | return Result{ .appended = {} }; |
| 1017 | } |
| 1018 | var space: Value.BigIntSpace = undefined; |
| 1019 | const bigint = val.toBigInt(&space); |
| 1020 | const iterations = @divExact(abi_size, @sizeOf(usize)); |
| 1021 | for (bigint.limbs) |_, index| { |
| 1022 | const limb = bigint.limbs[bigint.limbs.len - index - 1]; |
| 1023 | try writer.writeIntLittle(usize, limb); |
| 1024 | } else if (bigint.limbs.len < iterations) { |
| 1025 | // When the value is saved in less limbs than the required |
| 1026 | // abi size, we fill the remaining parts with 0's. |
| 1027 | var it_left = iterations - bigint.limbs.len; |
| 1028 | while (it_left > 0) { |
| 1029 | it_left -= 1; |
| 1030 | try writer.writeIntLittle(usize, 0); |
| 1031 | } |
| 1032 | } |
| 1033 | return Result{ .appended = {} }; |
| 960 | 1034 | }, |
| 961 | 1035 | .Enum => { |
| 962 | 1036 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 963 | | return Result.appended; |
| 1037 | return Result{ .appended = {} }; |
| 964 | 1038 | }, |
| 965 | 1039 | .Bool => { |
| 966 | 1040 | try writer.writeByte(@boolToInt(val.toBool())); |
| 967 | | return Result.appended; |
| 1041 | return Result{ .appended = {} }; |
| 968 | 1042 | }, |
| 969 | 1043 | .Struct => { |
| 970 | 1044 | const field_vals = val.castTag(.@"struct").?.data; |
| ... | ... | @@ -976,21 +1050,21 @@ pub const DeclGen = struct { |
| 976 | 1050 | .externally_managed => |payload| try writer.writeAll(payload), |
| 977 | 1051 | } |
| 978 | 1052 | } |
| 979 | | return Result.appended; |
| 1053 | return Result{ .appended = {} }; |
| 980 | 1054 | }, |
| 981 | 1055 | .Union => { |
| 982 | 1056 | // TODO: Implement Union declarations |
| 983 | 1057 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 984 | | return Result.appended; |
| 1058 | return Result{ .appended = {} }; |
| 985 | 1059 | }, |
| 986 | 1060 | .Pointer => switch (val.tag()) { |
| 987 | 1061 | .variable => { |
| 988 | 1062 | const decl = val.castTag(.variable).?.data.owner_decl; |
| 989 | | return try self.lowerDeclRef(ty, val, decl, writer); |
| 1063 | return self.lowerDeclRef(ty, val, decl, writer); |
| 990 | 1064 | }, |
| 991 | 1065 | .decl_ref => { |
| 992 | 1066 | const decl = val.castTag(.decl_ref).?.data; |
| 993 | | return try self.lowerDeclRef(ty, val, decl, writer); |
| 1067 | return self.lowerDeclRef(ty, val, decl, writer); |
| 994 | 1068 | }, |
| 995 | 1069 | .slice => { |
| 996 | 1070 | const slice = val.castTag(.slice).?.data; |
| ... | ... | @@ -1004,7 +1078,7 @@ pub const DeclGen = struct { |
| 1004 | 1078 | .externally_managed => |data| try writer.writeAll(data), |
| 1005 | 1079 | .appended => {}, |
| 1006 | 1080 | } |
| 1007 | | return Result.appended; |
| 1081 | return Result{ .appended = {} }; |
| 1008 | 1082 | }, |
| 1009 | 1083 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 1010 | 1084 | }, |
| ... | ... | @@ -1027,7 +1101,7 @@ pub const DeclGen = struct { |
| 1027 | 1101 | } |
| 1028 | 1102 | } |
| 1029 | 1103 | |
| 1030 | | return Result.appended; |
| 1104 | return Result{ .appended = {} }; |
| 1031 | 1105 | }, |
| 1032 | 1106 | .ErrorSet => { |
| 1033 | 1107 | switch (val.tag()) { |
| ... | ... | @@ -1040,7 +1114,7 @@ pub const DeclGen = struct { |
| 1040 | 1114 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); |
| 1041 | 1115 | }, |
| 1042 | 1116 | } |
| 1043 | | return Result.appended; |
| 1117 | return Result{ .appended = {} }; |
| 1044 | 1118 | }, |
| 1045 | 1119 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), |
| 1046 | 1120 | } |
| ... | ... | @@ -1058,7 +1132,7 @@ pub const DeclGen = struct { |
| 1058 | 1132 | .base = .{ .tag = .int_u64 }, |
| 1059 | 1133 | .data = val.sliceLen(), |
| 1060 | 1134 | }; |
| 1061 | | return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer); |
| 1135 | return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer); |
| 1062 | 1136 | } |
| 1063 | 1137 | |
| 1064 | 1138 | decl.markAlive(); |
| ... | ... | @@ -1069,7 +1143,7 @@ pub const DeclGen = struct { |
| 1069 | 1143 | decl.link.wasm.sym_index, // target symbol index |
| 1070 | 1144 | @intCast(u32, self.code.items.len), // offset |
| 1071 | 1145 | )); |
| 1072 | | return Result.appended; |
| 1146 | return Result{ .appended = {} }; |
| 1073 | 1147 | } |
| 1074 | 1148 | }; |
| 1075 | 1149 | |
| ... | ... | @@ -1172,16 +1246,10 @@ fn allocStack(self: *Self, ty: Type) !WValue { |
| 1172 | 1246 | assert(ty.hasCodeGenBits()); |
| 1173 | 1247 | |
| 1174 | 1248 | // calculate needed stack space |
| 1175 | | var abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch { |
| 1249 | const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch { |
| 1176 | 1250 | return self.fail("Given type '{}' too big to fit into stack frame", .{ty}); |
| 1177 | 1251 | }; |
| 1178 | 1252 | |
| 1179 | | // We store slices as a struct with a pointer field and a length field |
| 1180 | | // both being 'usize' size. |
| 1181 | | if (ty.isSlice()) { |
| 1182 | | abi_size = self.ptrSize() * 2; |
| 1183 | | } |
| 1184 | | |
| 1185 | 1253 | // allocate a local using wasm's pointer size |
| 1186 | 1254 | const local = try self.allocLocal(Type.@"usize"); |
| 1187 | 1255 | try self.moveStack(abi_size, local.local); |
| ... | ... | @@ -1624,7 +1692,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1624 | 1692 | var buf: Type.Payload.ElemType = undefined; |
| 1625 | 1693 | const pl_ty = ty.optionalChild(&buf); |
| 1626 | 1694 | if (!pl_ty.hasCodeGenBits()) { |
| 1627 | | // const null_val = try self.load(rhs, Type.initTag(.u8), 0); |
| 1628 | 1695 | return self.store(lhs, rhs, Type.initTag(.u8), 0); |
| 1629 | 1696 | } |
| 1630 | 1697 | |
| ... | ... | @@ -1833,61 +1900,22 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1833 | 1900 | .signed => switch (int_info.bits) { |
| 1834 | 1901 | 0...32 => return WValue{ .imm32 = @bitCast(u32, @intCast(i32, val.toSignedInt())) }, |
| 1835 | 1902 | 33...64 => return WValue{ .imm64 = @bitCast(u64, val.toSignedInt()) }, |
| 1836 | | 65...128 => {}, |
| 1837 | | else => |bits| return self.fail("Wasm todo: lowerConstant for integer with {d} bits", .{bits}), |
| 1903 | else => unreachable, |
| 1838 | 1904 | }, |
| 1839 | 1905 | .unsigned => switch (int_info.bits) { |
| 1840 | 1906 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1841 | 1907 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt() }, |
| 1842 | | 65...128 => {}, |
| 1843 | | else => |bits| return self.fail("Wasm TODO: lowerConstant for integer with {d} bits", .{bits}), |
| 1908 | else => unreachable, |
| 1844 | 1909 | }, |
| 1845 | 1910 | } |
| 1846 | | const result = try self.allocStack(ty); |
| 1847 | | var space: Value.BigIntSpace = undefined; |
| 1848 | | const bigint = val.toBigInt(&space); |
| 1849 | | if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) { |
| 1850 | | return result; |
| 1851 | | } |
| 1852 | | if (@sizeOf(usize) != @sizeOf(u64)) { |
| 1853 | | return self.fail("Wasm todo: Implement big integers for 32bit compiler", .{}); |
| 1854 | | } |
| 1855 | | |
| 1856 | | for (bigint.limbs) |_, index| { |
| 1857 | | const limb = bigint.limbs[bigint.limbs.len - index - 1]; |
| 1858 | | try self.addLabel(.local_get, result.local); |
| 1859 | | try self.addImm64(limb); |
| 1860 | | try self.addMemArg(.i64_store, .{ .offset = @intCast(u32, index * 8), .alignment = 8 }); |
| 1861 | | } |
| 1862 | | return result; |
| 1863 | 1911 | }, |
| 1864 | 1912 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1865 | 1913 | .Float => switch (ty.floatBits(self.target)) { |
| 1866 | 1914 | 0...32 => return WValue{ .float32 = val.toFloat(f32) }, |
| 1867 | 1915 | 33...64 => return WValue{ .float64 = val.toFloat(f64) }, |
| 1868 | | else => |bits| return self.fail("Wasm TODO: lowerConstant for floats with {d} bits", .{bits}), |
| 1916 | else => unreachable, |
| 1869 | 1917 | }, |
| 1870 | 1918 | .Pointer => switch (val.tag()) { |
| 1871 | | .slice => { |
| 1872 | | const result = try self.allocStack(ty); |
| 1873 | | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1874 | | const ptr = try self.lowerConstant(val.slicePtr(), ty.slicePtrFieldType(&buf)); |
| 1875 | | const len = val.sliceLen(); |
| 1876 | | try self.store(result, ptr, Type.usize, 0); |
| 1877 | | try self.addLabel(.local_get, result.local); |
| 1878 | | switch (self.arch()) { |
| 1879 | | .wasm32 => { |
| 1880 | | try self.addImm32(@bitCast(i32, @intCast(u32, len))); |
| 1881 | | try self.addMemArg(.i32_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() }); |
| 1882 | | }, |
| 1883 | | .wasm64 => { |
| 1884 | | try self.addImm64(len); |
| 1885 | | try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() }); |
| 1886 | | }, |
| 1887 | | else => unreachable, |
| 1888 | | } |
| 1889 | | return result; |
| 1890 | | }, |
| 1891 | 1919 | .decl_ref => { |
| 1892 | 1920 | const decl = val.castTag(.decl_ref).?.data; |
| 1893 | 1921 | decl.markAlive(); |
| ... | ... | @@ -1941,120 +1969,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1941 | 1969 | }, |
| 1942 | 1970 | .ErrorUnion => { |
| 1943 | 1971 | const error_type = ty.errorUnionSet(); |
| 1944 | | const payload_type = ty.errorUnionPayload(); |
| 1945 | 1972 | const is_pl = val.errorUnionIsPayload(); |
| 1946 | 1973 | const err_val = if (!is_pl) val else Value.initTag(.zero); |
| 1947 | | const error_value = try self.lowerConstant(err_val, error_type); |
| 1948 | | if (!payload_type.hasCodeGenBits()) { |
| 1949 | | return error_value; |
| 1950 | | } |
| 1951 | | |
| 1952 | | const result = try self.allocStack(ty); |
| 1953 | | try self.store(result, error_value, error_type, 0); |
| 1954 | | const payload = try self.lowerConstant( |
| 1955 | | if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1956 | | payload_type, |
| 1957 | | ); |
| 1958 | | const pl_ptr = if (isByRef(payload_type, self.target)) |
| 1959 | | try self.buildPointerOffset(result, error_type.abiSize(self.target), .new) |
| 1960 | | else |
| 1961 | | result; |
| 1962 | | try self.store(pl_ptr, payload, payload_type, @intCast(u32, error_type.abiSize(self.target))); |
| 1963 | | return result; |
| 1974 | return self.lowerConstant(err_val, error_type); |
| 1964 | 1975 | }, |
| 1965 | 1976 | .Optional => if (ty.isPtrLikeOptional()) { |
| 1966 | 1977 | var buf: Type.Payload.ElemType = undefined; |
| 1967 | 1978 | return self.lowerConstant(val, ty.optionalChild(&buf)); |
| 1968 | 1979 | } else { |
| 1969 | | var buf: Type.Payload.ElemType = undefined; |
| 1970 | | const payload_type = ty.optionalChild(&buf); |
| 1971 | 1980 | const is_pl = val.tag() == .opt_payload; |
| 1972 | | const null_value = WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 }; |
| 1973 | | if (!payload_type.hasCodeGenBits()) { |
| 1974 | | return null_value; |
| 1975 | | } |
| 1976 | | |
| 1977 | | const result = try self.allocStack(ty); |
| 1978 | | try self.store(result, null_value, Type.initTag(.u8), 0); |
| 1979 | | const payload = try self.lowerConstant( |
| 1980 | | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 1981 | | payload_type, |
| 1982 | | ); |
| 1983 | | |
| 1984 | | const offset = @intCast(u32, ty.abiSize(self.target) - payload_type.abiSize(self.target)); |
| 1985 | | const pl_ptr = if (self.isByRef(payload_type)) blk: { |
| 1986 | | break :blk try self.buildPointerOffset(result, offset, .new); |
| 1987 | | } else result; |
| 1988 | | try self.store(pl_ptr, payload, payload_type, offset); |
| 1989 | | return result; |
| 1990 | | }, |
| 1991 | | .Struct => { |
| 1992 | | const struct_data = val.castTag(.@"struct").?; |
| 1993 | | // in case of structs, we reserve stack space and store it there. |
| 1994 | | const result = try self.allocStack(ty); |
| 1995 | | |
| 1996 | | const fields = ty.structFields(); |
| 1997 | | const offset = try self.copyLocal(result, ty); |
| 1998 | | for (fields.values()) |field, index| { |
| 1999 | | const field_value = try self.lowerConstant(struct_data.data[index], field.ty); |
| 2000 | | try self.store(offset, field_value, field.ty, 0); |
| 2001 | | |
| 2002 | | // this prevents us from emitting useless instructions when we reached the end of the loop |
| 2003 | | if (index != (fields.count() - 1)) { |
| 2004 | | _ = try self.buildPointerOffset(offset, field.ty.abiSize(self.target), .modify); |
| 2005 | | } |
| 2006 | | } |
| 2007 | | return result; |
| 2008 | | }, |
| 2009 | | .Array => { |
| 2010 | | const result = try self.allocStack(ty); |
| 2011 | | if (val.castTag(.bytes)) |bytes| { |
| 2012 | | for (bytes.data) |byte, index| { |
| 2013 | | try self.addLabel(.local_get, result.local); |
| 2014 | | try self.addImm32(@intCast(i32, byte)); |
| 2015 | | try self.addMemArg(.i32_store8, .{ .offset = @intCast(u32, index), .alignment = 1 }); |
| 2016 | | } |
| 2017 | | } else if (val.castTag(.array)) |array| { |
| 2018 | | const elem_ty = ty.childType(); |
| 2019 | | const elem_size = elem_ty.abiSize(self.target); |
| 2020 | | const offset = try self.copyLocal(result, ty); |
| 2021 | | for (array.data) |value, index| { |
| 2022 | | const elem_val = try self.lowerConstant(value, elem_ty); |
| 2023 | | try self.store(offset, elem_val, elem_ty, 0); |
| 2024 | | |
| 2025 | | if (index != (array.data.len - 1)) { |
| 2026 | | _ = try self.buildPointerOffset(offset, elem_size, .modify); |
| 2027 | | } |
| 2028 | | } |
| 2029 | | } else if (val.castTag(.repeated)) |repeated| { |
| 2030 | | const value = repeated.data; |
| 2031 | | const elem_ty = ty.childType(); |
| 2032 | | const elem_size = elem_ty.abiSize(self.target); |
| 2033 | | const sentinel = ty.sentinel(); |
| 2034 | | const len = ty.arrayLen(); |
| 2035 | | const len_with_sent = len + @boolToInt(sentinel != null); |
| 2036 | | const offset = try self.copyLocal(result, ty); |
| 2037 | | |
| 2038 | | var index: u32 = 0; |
| 2039 | | while (index < len_with_sent) : (index += 1) { |
| 2040 | | const elem_val = if (sentinel != null and index == len) |
| 2041 | | try self.lowerConstant(sentinel.?, elem_ty) |
| 2042 | | else |
| 2043 | | try self.lowerConstant(value, elem_ty); |
| 2044 | | |
| 2045 | | try self.store(offset, elem_val, elem_ty, 0); |
| 2046 | | |
| 2047 | | if (index != (len_with_sent - 1)) { |
| 2048 | | _ = try self.buildPointerOffset(offset, elem_size, .modify); |
| 2049 | | } |
| 2050 | | } |
| 2051 | | } else if (val.tag() == .empty_array_sentinel) { |
| 2052 | | const elem_ty = ty.childType(); |
| 2053 | | const sent_val = ty.sentinel().?; |
| 2054 | | const sentinel = try self.lowerConstant(sent_val, elem_ty); |
| 2055 | | try self.store(result, sentinel, elem_ty, 0); |
| 2056 | | } else unreachable; |
| 2057 | | return result; |
| 1981 | return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 }; |
| 2058 | 1982 | }, |
| 2059 | 1983 | else => |zig_type| return self.fail("Wasm TODO: LowerConstant for zigTypeTag {s}", .{zig_type}), |
| 2060 | 1984 | } |
| ... | ... | @@ -2066,27 +1990,12 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { |
| 2066 | 1990 | .Int => switch (ty.intInfo(self.target).bits) { |
| 2067 | 1991 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 2068 | 1992 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, |
| 2069 | | else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}), |
| 1993 | else => unreachable, |
| 2070 | 1994 | }, |
| 2071 | 1995 | .Float => switch (ty.floatBits(self.target)) { |
| 2072 | 1996 | 0...32 => return WValue{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) }, |
| 2073 | 1997 | 33...64 => return WValue{ .float64 = @bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa)) }, |
| 2074 | | else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}), |
| 2075 | | }, |
| 2076 | | .Array, .Struct => { |
| 2077 | | const result = try self.allocStack(ty); |
| 2078 | | const abi_size = ty.abiSize(self.target); |
| 2079 | | var offset: u32 = 0; |
| 2080 | | while (offset < abi_size) : (offset += 1) { |
| 2081 | | try self.emitWValue(result); |
| 2082 | | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); |
| 2083 | | switch (self.arch()) { |
| 2084 | | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), |
| 2085 | | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), |
| 2086 | | else => unreachable, |
| 2087 | | } |
| 2088 | | } |
| 2089 | | return result; |
| 1998 | else => unreachable, |
| 2090 | 1999 | }, |
| 2091 | 2000 | .Pointer => switch (self.arch()) { |
| 2092 | 2001 | .wasm32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| ... | ... | @@ -2099,42 +2008,10 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { |
| 2099 | 2008 | if (ty.isPtrLikeOptional()) { |
| 2100 | 2009 | return self.emitUndefined(pl_ty); |
| 2101 | 2010 | } |
| 2102 | | if (!pl_ty.hasCodeGenBits()) { |
| 2103 | | return self.emitUndefined(Type.initTag(.u8)); |
| 2104 | | } |
| 2105 | | const result = try self.allocStack(ty); |
| 2106 | | const abi_size = ty.abiSize(self.target); |
| 2107 | | var offset: u32 = 0; |
| 2108 | | while (offset < abi_size) : (offset += 1) { |
| 2109 | | try self.emitWValue(result); |
| 2110 | | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); |
| 2111 | | switch (self.arch()) { |
| 2112 | | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), |
| 2113 | | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), |
| 2114 | | else => unreachable, |
| 2115 | | } |
| 2116 | | } |
| 2117 | | return result; |
| 2011 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2118 | 2012 | }, |
| 2119 | 2013 | .ErrorUnion => { |
| 2120 | | // const error_set = ty.errorUnionSet(); |
| 2121 | | const pl_ty = ty.errorUnionPayload(); |
| 2122 | | if (!pl_ty.hasCodeGenBits()) { |
| 2123 | | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2124 | | } |
| 2125 | | const result = try self.allocStack(ty); |
| 2126 | | const abi_size = ty.abiSize(self.target); |
| 2127 | | var offset: u32 = 0; |
| 2128 | | while (offset < abi_size) : (offset += 1) { |
| 2129 | | try self.emitWValue(result); |
| 2130 | | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); |
| 2131 | | switch (self.arch()) { |
| 2132 | | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), |
| 2133 | | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), |
| 2134 | | else => unreachable, |
| 2135 | | } |
| 2136 | | } |
| 2137 | | return result; |
| 2014 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2138 | 2015 | }, |
| 2139 | 2016 | else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}), |
| 2140 | 2017 | } |