authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 19:17:34+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 22:29:36+01:00
logb9fe6a93ff51ecb5ce770c78f463c38a0620de49
treea155cb583568eb2136dfb8fd42ff40b9c41245f1
parent1fe1e4d29207de8c972fcc1b61266fbaddb07d63
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Re-use genTypedValue for constants

When a constant will be passed by reference, such as a struct, we will call into genTypedValue to lower the constant to bytes and store them into the `rodata` section. We will then return the address of this constant as a `WValue`. This change means we will have all constants lowered during compilation time, and no longer have to sacrifice runtime to lower them onto the stack.

2 files changed, 122 insertions(+), 244 deletions(-)

src/arch/wasm/CodeGen.zig+121-244
......@@ -599,7 +599,41 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
599599 const val = self.air.value(ref).?;
600600 const ty = self.air.typeOf(ref);
601601 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
603637 gop.value_ptr.* = result;
604638 return result;
605639}
......@@ -867,15 +901,15 @@ pub const DeclGen = struct {
867901 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
868902 func_type.deinit(self.gpa);
869903 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
870 return Result.appended;
904 return Result{ .appended = {} };
871905 } else {
872906 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
873907 break :init_val payload.data.init;
874908 } else decl.val;
875909 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());
877911 }
878 return Result.appended;
912 return Result{ .appended = {} };
879913 }
880914 }
881915
......@@ -883,7 +917,7 @@ pub const DeclGen = struct {
883917 fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result {
884918 if (val.isUndef()) {
885919 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
886 return Result.appended;
920 return Result{ .appended = {} };
887921 }
888922 switch (ty.zigTypeTag()) {
889923 .Fn => {
......@@ -898,35 +932,36 @@ pub const DeclGen = struct {
898932 var opt_buf: Type.Payload.ElemType = undefined;
899933 const payload_type = ty.optionalChild(&opt_buf);
900934 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()));
901937
902938 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 = {} };
905941 }
906942
907943 if (ty.isPtrLikeOptional()) {
908944 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);
910946 } else if (!val.isNull()) {
911 return try self.genTypedValue(payload_type, val, writer);
947 return self.genTypedValue(payload_type, val, writer);
912948 } 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 = {} };
915951 }
916952 }
917953
918954 // `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(
921957 payload_type,
922958 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
923959 writer,
924 );
925 switch (pl_result) {
960 )) {
926961 .appended => {},
927962 .externally_managed => |payload| try writer.writeAll(payload),
928963 }
929 return Result.appended;
964 return Result{ .appended = {} };
930965 },
931966 .Array => switch (val.tag()) {
932967 .bytes => {
......@@ -942,29 +977,68 @@ pub const DeclGen = struct {
942977 .externally_managed => |data| try writer.writeAll(data),
943978 }
944979 }
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);
9461004 },
947 else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}),
1005 else => unreachable,
9481006 },
9491007 .Int => {
9501008 const info = ty.intInfo(self.target());
9511009 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 = {} };
9601034 },
9611035 .Enum => {
9621036 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
963 return Result.appended;
1037 return Result{ .appended = {} };
9641038 },
9651039 .Bool => {
9661040 try writer.writeByte(@boolToInt(val.toBool()));
967 return Result.appended;
1041 return Result{ .appended = {} };
9681042 },
9691043 .Struct => {
9701044 const field_vals = val.castTag(.@"struct").?.data;
......@@ -976,21 +1050,21 @@ pub const DeclGen = struct {
9761050 .externally_managed => |payload| try writer.writeAll(payload),
9771051 }
9781052 }
979 return Result.appended;
1053 return Result{ .appended = {} };
9801054 },
9811055 .Union => {
9821056 // TODO: Implement Union declarations
9831057 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));
984 return Result.appended;
1058 return Result{ .appended = {} };
9851059 },
9861060 .Pointer => switch (val.tag()) {
9871061 .variable => {
9881062 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);
9901064 },
9911065 .decl_ref => {
9921066 const decl = val.castTag(.decl_ref).?.data;
993 return try self.lowerDeclRef(ty, val, decl, writer);
1067 return self.lowerDeclRef(ty, val, decl, writer);
9941068 },
9951069 .slice => {
9961070 const slice = val.castTag(.slice).?.data;
......@@ -1004,7 +1078,7 @@ pub const DeclGen = struct {
10041078 .externally_managed => |data| try writer.writeAll(data),
10051079 .appended => {},
10061080 }
1007 return Result.appended;
1081 return Result{ .appended = {} };
10081082 },
10091083 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
10101084 },
......@@ -1027,7 +1101,7 @@ pub const DeclGen = struct {
10271101 }
10281102 }
10291103
1030 return Result.appended;
1104 return Result{ .appended = {} };
10311105 },
10321106 .ErrorSet => {
10331107 switch (val.tag()) {
......@@ -1040,7 +1114,7 @@ pub const DeclGen = struct {
10401114 try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target())));
10411115 },
10421116 }
1043 return Result.appended;
1117 return Result{ .appended = {} };
10441118 },
10451119 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
10461120 }
......@@ -1058,7 +1132,7 @@ pub const DeclGen = struct {
10581132 .base = .{ .tag = .int_u64 },
10591133 .data = val.sliceLen(),
10601134 };
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);
10621136 }
10631137
10641138 decl.markAlive();
......@@ -1069,7 +1143,7 @@ pub const DeclGen = struct {
10691143 decl.link.wasm.sym_index, // target symbol index
10701144 @intCast(u32, self.code.items.len), // offset
10711145 ));
1072 return Result.appended;
1146 return Result{ .appended = {} };
10731147 }
10741148};
10751149
......@@ -1172,16 +1246,10 @@ fn allocStack(self: *Self, ty: Type) !WValue {
11721246 assert(ty.hasCodeGenBits());
11731247
11741248 // 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 {
11761250 return self.fail("Given type '{}' too big to fit into stack frame", .{ty});
11771251 };
11781252
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
11851253 // allocate a local using wasm's pointer size
11861254 const local = try self.allocLocal(Type.@"usize");
11871255 try self.moveStack(abi_size, local.local);
......@@ -1624,7 +1692,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
16241692 var buf: Type.Payload.ElemType = undefined;
16251693 const pl_ty = ty.optionalChild(&buf);
16261694 if (!pl_ty.hasCodeGenBits()) {
1627 // const null_val = try self.load(rhs, Type.initTag(.u8), 0);
16281695 return self.store(lhs, rhs, Type.initTag(.u8), 0);
16291696 }
16301697
......@@ -1833,61 +1900,22 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
18331900 .signed => switch (int_info.bits) {
18341901 0...32 => return WValue{ .imm32 = @bitCast(u32, @intCast(i32, val.toSignedInt())) },
18351902 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,
18381904 },
18391905 .unsigned => switch (int_info.bits) {
18401906 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
18411907 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,
18441909 },
18451910 }
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;
18631911 },
18641912 .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
18651913 .Float => switch (ty.floatBits(self.target)) {
18661914 0...32 => return WValue{ .float32 = val.toFloat(f32) },
18671915 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,
18691917 },
18701918 .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 },
18911919 .decl_ref => {
18921920 const decl = val.castTag(.decl_ref).?.data;
18931921 decl.markAlive();
......@@ -1941,120 +1969,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19411969 },
19421970 .ErrorUnion => {
19431971 const error_type = ty.errorUnionSet();
1944 const payload_type = ty.errorUnionPayload();
19451972 const is_pl = val.errorUnionIsPayload();
19461973 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);
19641975 },
19651976 .Optional => if (ty.isPtrLikeOptional()) {
19661977 var buf: Type.Payload.ElemType = undefined;
19671978 return self.lowerConstant(val, ty.optionalChild(&buf));
19681979 } else {
1969 var buf: Type.Payload.ElemType = undefined;
1970 const payload_type = ty.optionalChild(&buf);
19711980 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 };
20581982 },
20591983 else => |zig_type| return self.fail("Wasm TODO: LowerConstant for zigTypeTag {s}", .{zig_type}),
20601984 }
......@@ -2066,27 +1990,12 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
20661990 .Int => switch (ty.intInfo(self.target).bits) {
20671991 0...32 => return WValue{ .imm32 = 0xaaaaaaaa },
20681992 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
2069 else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),
1993 else => unreachable,
20701994 },
20711995 .Float => switch (ty.floatBits(self.target)) {
20721996 0...32 => return WValue{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) },
20731997 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,
20901999 },
20912000 .Pointer => switch (self.arch()) {
20922001 .wasm32 => return WValue{ .imm32 = 0xaaaaaaaa },
......@@ -2099,42 +2008,10 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
20992008 if (ty.isPtrLikeOptional()) {
21002009 return self.emitUndefined(pl_ty);
21012010 }
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 };
21182012 },
21192013 .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 };
21382015 },
21392016 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}),
21402017 }
src/link/Wasm.zig+1
......@@ -323,6 +323,7 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
323323
324324 var atom = Atom.empty;
325325 atom.alignment = ty.abiAlignment(self.base.options.target);
326 try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
326327
327328 if (self.symbols_free_list.popOrNull()) |index| {
328329 atom.sym_index = index;