authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-15 22:49:12+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 20:01:23+01:00
log38253a680d8a53723667eca2c1f9a56b183dea8c
tree5b7f64fc4426e9b88ffb183f7744d1dbb71c214a
parent7c6981e0c0f2412c49457a900e5a6a4db96be2e8
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Refactor emitConstant to lower to `WValue`


1 files changed, 148 insertions(+), 133 deletions(-)

src/arch/wasm/CodeGen.zig+148-133
...@@ -27,8 +27,22 @@ const WValue = union(enum) {...@@ -27,8 +27,22 @@ const WValue = union(enum) {
27 none: void,27 none: void,
28 /// Index of the local variable28 /// Index of the local variable
29 local: u32,29 local: u32,
30 /// Holds a memoized typed value30 /// Represents the index of a local that contains a pointer to its stack position
31 constant: TypedValue,31 stack: u32,
32 /// An immediate 32bit value
33 imm32: u32,
34 /// An immediate 64bit value
35 imm64: u64,
36 /// A constant 32bit float value
37 float32: f32,
38 /// A constant 64bit float value
39 float64: f64,
40 /// A value that represents a pointer to the data section
41 memory: u64,
42 /// Represents a function pointer
43 /// In wasm function pointers are indexes into a function table,
44 /// rather than an address in the data section.
45 function_index: u32,
32 /// Used for types that contains of multiple areas within46 /// Used for types that contains of multiple areas within
33 /// a memory region in the stack.47 /// a memory region in the stack.
34 /// The local represents the position in the stack,48 /// The local represents the position in the stack,
...@@ -588,24 +602,14 @@ fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {...@@ -588,24 +602,14 @@ fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {
588/// Resolves the `WValue` for the given instruction `inst`602/// Resolves the `WValue` for the given instruction `inst`
589/// When the given instruction has a `Value`, it returns a constant instead603/// When the given instruction has a `Value`, it returns a constant instead
590fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {604fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {
591 const inst_index = Air.refToIndex(ref) orelse {605 const gop = try self.values.getOrPut(self.gpa, ref);
592 const tv = Air.Inst.Ref.typed_value_map[@enumToInt(ref)];606 if (gop.found_existing) return gop.value_ptr.*;
593 if (!tv.ty.hasCodeGenBits()) {
594 return WValue.none;
595 }
596 return WValue{ .constant = tv };
597 };
598607
599 const inst_type = self.air.typeOfIndex(inst_index);608 // when we did not find an existing instruction, it
600 // It's allowed to have 0-bit integers609 // means we must generate it from a constant.
601 if (!inst_type.hasCodeGenBits() and !inst_type.isInt()) return WValue{ .none = {} };610 const val = self.air.value(ref).?;
602611 const ty = self.air.typeOf(ref);
603 if (self.air.instructions.items(.tag)[inst_index] == .constant) {612 return self.lowerConstant(val, ty);
604 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
605 return WValue{ .constant = .{ .ty = inst_type, .val = self.air.values[ty_pl.payload] } };
606 }
607
608 return self.values.get(inst_index).?; // Instruction does not dominate all uses!
609}613}
610614
611/// Appends a MIR instruction and returns its index within the list of instructions615/// Appends a MIR instruction and returns its index within the list of instructions
...@@ -730,7 +734,12 @@ fn emitWValue(self: *Self, val: WValue) InnerError!void {...@@ -730,7 +734,12 @@ fn emitWValue(self: *Self, val: WValue) InnerError!void {
730 .none => {}, // no-op734 .none => {}, // no-op
731 .local_with_offset => |with_off| try self.addLabel(.local_get, with_off.local),735 .local_with_offset => |with_off| try self.addLabel(.local_get, with_off.local),
732 .local => |idx| try self.addLabel(.local_get, idx),736 .local => |idx| try self.addLabel(.local_get, idx),
733 .constant => |tv| try self.emitConstant(tv.val, tv.ty), // Creates a new constant on the stack737 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
738 .imm64 => |val| try self.addImm64(val),
739 .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
740 .float64 => |val| try self.addFloat64(val),
741 .memory => |ptr| try self.addLabel(.memory_address, ptr), // write sybol address and generate relocation
742 .function_index => |index| try self.addLabel(.function_index, index), // write function index and generate relocation
734 }743 }
735}744}
736745
...@@ -929,7 +938,8 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -929,7 +938,8 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
929 return Result.appended;938 return Result.appended;
930 },939 },
931 .Enum => {940 .Enum => {
932 try self.emitConstant(val, ty);941 const size = @intCast(usize, ty.abiSize(self.target));
942 try self.code.appendNTimes(0xaa, size);
933 return Result.appended;943 return Result.appended;
934 },944 },
935 .Bool => {945 .Bool => {
...@@ -1207,6 +1217,10 @@ fn ptrSize(self: *const Self) u16 {...@@ -1207,6 +1217,10 @@ fn ptrSize(self: *const Self) u16 {
1207 return @divExact(self.target.cpu.arch.ptrBitWidth(), 8);1217 return @divExact(self.target.cpu.arch.ptrBitWidth(), 8);
1208}1218}
12091219
1220fn arch(self: *const Self) std.Target.Cpu.Arch {
1221 return self.target.cpu.arch;
1222}
1223
1210/// For a given `Type`, will return true when the type will be passed1224/// For a given `Type`, will return true when the type will be passed
1211/// by reference, rather than by value.1225/// by reference, rather than by value.
1212fn isByRef(self: Self, ty: Type) bool {1226fn isByRef(self: Self, ty: Type) bool {
...@@ -1699,13 +1713,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1699,13 +1713,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1699 }1713 }
1700 },1714 },
1701 .Struct, .Array => {1715 .Struct, .Array => {
1702 const final_rhs = if (rhs == .constant) blk: {1716 return try self.memCopy(ty, lhs, rhs);
1703 const tmp = try self.allocLocal(Type.usize);
1704 try self.emitWValue(rhs);
1705 try self.addLabel(.local_set, tmp.local);
1706 break :blk tmp;
1707 } else rhs;
1708 return try self.memCopy(ty, lhs, final_rhs);
1709 },1717 },
1710 .Pointer => {1718 .Pointer => {
1711 if (ty.isSlice() and rhs == .constant) {1719 if (ty.isSlice() and rhs == .constant) {
...@@ -1748,11 +1756,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1748,11 +1756,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1748 }1756 }
1749 },1757 },
1750 .Int => if (ty.intInfo(self.target).bits > 64) {1758 .Int => if (ty.intInfo(self.target).bits > 64) {
1751 if (rhs == .constant) {
1752 try self.emitWValue(rhs);
1753 try self.addLabel(.local_set, lhs.local);
1754 return;
1755 }
1756 return try self.memCopy(ty, lhs, rhs);1759 return try self.memCopy(ty, lhs, rhs);
1757 },1760 },
1758 else => {},1761 else => {},
...@@ -1933,7 +1936,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -1933,7 +1936,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1933 return bin_local;1936 return bin_local;
1934}1937}
19351938
1936fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {1939fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
1937 if (val.isUndefDeep()) return self.emitUndefined(ty);1940 if (val.isUndefDeep()) return self.emitUndefined(ty);
1938 switch (ty.zigTypeTag()) {1941 switch (ty.zigTypeTag()) {
1939 .Int => {1942 .Int => {
...@@ -1941,16 +1944,16 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -1941,16 +1944,16 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1941 // write constant1944 // write constant
1942 switch (int_info.signedness) {1945 switch (int_info.signedness) {
1943 .signed => switch (int_info.bits) {1946 .signed => switch (int_info.bits) {
1944 0...32 => return try self.addImm32(@intCast(i32, val.toSignedInt())),1947 0...32 => return WValue{ .imm32 = @bitCast(u32, @intCast(i32, val.toSignedInt())) },
1945 33...64 => return try self.addImm64(@bitCast(u64, val.toSignedInt())),1948 33...64 => return WValue{ .imm64 = @bitCast(u64, val.toSignedInt()) },
1946 65...128 => {},1949 65...128 => {},
1947 else => |bits| return self.fail("Wasm todo: emitConstant for integer with {d} bits", .{bits}),1950 else => |bits| return self.fail("Wasm todo: lowerConstant for integer with {d} bits", .{bits}),
1948 },1951 },
1949 .unsigned => switch (int_info.bits) {1952 .unsigned => switch (int_info.bits) {
1950 0...32 => return try self.addImm32(@bitCast(i32, @intCast(u32, val.toUnsignedInt()))),1953 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
1951 33...64 => return try self.addImm64(val.toUnsignedInt()),1954 33...64 => return WValue{ .imm64 = val.toUnsignedInt() },
1952 65...128 => {},1955 65...128 => {},
1953 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),1956 else => |bits| return self.fail("Wasm TODO: lowerConstant for integer with {d} bits", .{bits}),
1954 },1957 },
1955 }1958 }
1956 const result = try self.allocStack(ty);1959 const result = try self.allocStack(ty);
...@@ -1970,53 +1973,58 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -1970,53 +1973,58 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1970 try self.addImm64(limb);1973 try self.addImm64(limb);
1971 try self.addMemArg(.i64_store, .{ .offset = @intCast(u32, index * 8), .alignment = 8 });1974 try self.addMemArg(.i64_store, .{ .offset = @intCast(u32, index * 8), .alignment = 8 });
1972 }1975 }
1973 try self.addLabel(.local_get, result.local);1976 return result;
1974 },1977 },
1975 .Bool => try self.addImm32(@intCast(i32, val.toSignedInt())),1978 .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
1976 .Float => {1979 .Float => switch (ty.floatBits(self.target)) {
1977 // write constant1980 0...32 => return WValue{ .float32 = val.toFloat(f32) },
1978 switch (ty.floatBits(self.target)) {1981 33...64 => return WValue{ .float64 = val.toFloat(f64) },
1979 0...32 => try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val.toFloat(f32) } }),1982 else => |bits| return self.fail("Wasm TODO: emitConstant for floats with {d} bits", .{bits}),
1980 64 => try self.addFloat64(val.toFloat(f64)),
1981 else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
1982 }
1983 },1983 },
1984 .Pointer => {1984 .Pointer => switch (val) {
1985 if (val.castTag(.slice)) |slice| {1985 .slice => {
1986 const result = try self.allocStack(ty);
1986 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1987 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1987 try self.emitConstant(slice.data.ptr, ty.slicePtrFieldType(&buf));1988 const ptr = try self.lowerConstant(val.slicePtr(), ty.slicePtrFieldType(&buf));
1988 try self.emitConstant(slice.data.len, Type.usize);1989 const len = val.sliceLen();
1989 } else if (val.castTag(.decl_ref)) |payload| {1990 try self.store(result, ptr, Type.usize, 0);
1990 const decl = payload.data;1991 try self.addLabel(.local_get, result.local);
1992 switch (self.arch()) {
1993 .wasm32 => {
1994 try self.addImm32(@bitCast(i32, @intCast(u32, len)));
1995 try self.addMemArg(.i32_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() });
1996 },
1997 .wasm64 => {
1998 try self.addImm64(len);
1999 try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() });
2000 },
2001 }
2002 return result;
2003 },
2004 .decl_ref => {
2005 const decl = val.castTag(.decl_ref).?.data;
1991 decl.markAlive();2006 decl.markAlive();
1992 // Function pointers use a table index, rather than a memory address2007 const target_sym_index = decl.link.wasm.sym_index;
1993 if (decl.ty.zigTypeTag() == .Fn) {2008 if (decl.ty.zigTypeTag() == .Fn) {
1994 const target_sym_index = decl.link.wasm.sym_index;
1995 try self.bin_file.addTableFunction(target_sym_index);2009 try self.bin_file.addTableFunction(target_sym_index);
1996 try self.addLabel(.function_index, target_sym_index);2010 return WValue{ .function_index = target_sym_index };
1997 } else {2011 } else return WValue{ .memory = target_sym_index };
1998 try self.addLabel(.memory_address, decl.link.wasm.sym_index);2012 },
1999 }2013 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
2000 } else if (val.castTag(.int_u64)) |int_ptr| {2014 .zero, .null_value => return WValue{ .imm32 = 0 },
2001 try self.addImm32(@bitCast(i32, @intCast(u32, int_ptr.data)));2015 else => return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}),
2002 } else if (val.tag() == .zero or val.tag() == .null_value) {2016 },
2003 try self.addImm32(0);
2004 } else if (val.tag() == .one) {
2005 try self.addImm32(1);
2006 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
2007 },
2008 .Void => {},
2009 .Enum => {2017 .Enum => {
2010 if (val.castTag(.enum_field_index)) |field_index| {2018 if (val.castTag(.enum_field_index)) |field_index| {
2011 switch (ty.tag()) {2019 switch (ty.tag()) {
2012 .enum_simple => try self.addImm32(@bitCast(i32, field_index.data)),2020 .enum_simple => return WValue{ .imm32 = field_index.data },
2013 .enum_full, .enum_nonexhaustive => {2021 .enum_full, .enum_nonexhaustive => {
2014 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;2022 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
2015 if (enum_full.values.count() != 0) {2023 if (enum_full.values.count() != 0) {
2016 const tag_val = enum_full.values.keys()[field_index.data];2024 const tag_val = enum_full.values.keys()[field_index.data];
2017 try self.emitConstant(tag_val, enum_full.tag_ty);2025 return self.lowerConstant(tag_val, enum_full.tag_ty);
2018 } else {2026 } else {
2019 try self.addImm32(@bitCast(i32, field_index.data));2027 return WValue{ .imm32 = field_index.data };
2020 }2028 }
2021 },2029 },
2022 else => unreachable,2030 else => unreachable,
...@@ -2024,55 +2032,61 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -2024,55 +2032,61 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
2024 } else {2032 } else {
2025 var int_tag_buffer: Type.Payload.Bits = undefined;2033 var int_tag_buffer: Type.Payload.Bits = undefined;
2026 const int_tag_ty = ty.intTagType(&int_tag_buffer);2034 const int_tag_ty = ty.intTagType(&int_tag_buffer);
2027 try self.emitConstant(val, int_tag_ty);2035 return self.lowerConstant(val, int_tag_ty);
2028 }2036 }
2029 },2037 },
2030 .ErrorSet => {2038 .ErrorSet => {
2031 const error_index = self.global_error_set.get(val.getError().?).?;2039 const error_index = self.global_error_set.get(val.getError().?).?;
2032 try self.addImm32(@bitCast(i32, error_index));2040 return WValue{ .imm32 = error_index };
2033 },2041 },
2034 .ErrorUnion => {2042 .ErrorUnion => {
2035 const error_type = ty.errorUnionSet();2043 const error_type = ty.errorUnionSet();
2036 const payload_type = ty.errorUnionPayload();2044 const payload_type = ty.errorUnionPayload();
2037 if (val.castTag(.eu_payload)) |pl| {2045 const is_pl = val.errorUnionIsPayload();
2038 const payload_val = pl.data;2046 const err_val = if (!is_pl) val else Value.initTag(.zero);
2039 // no error, so write a '0' const2047 const error_value = try self.lowerConstant(err_val, error_type);
2040 try self.addImm32(0);2048 if (!payload_type.hasCodeGenBits()) {
20412049 return error_value;
2042 if (payload_type.hasCodeGenBits()) {
2043 // after the error code, we emit the payload
2044 try self.emitConstant(payload_val, payload_type);
2045 }
2046 } else {
2047 // write the error val
2048 try self.emitConstant(val, error_type);
2049
2050 if (payload_type.hasCodeGenBits()) {
2051 // no payload, so write a '0' const
2052 try self.addImm32(0);
2053 }
2054 }2050 }
2055 },2051
2056 .Optional => {2052 const result = try self.allocStack(ty);
2053 try self.store(result, error_value, error_type, 0);
2054 const payload = try lowerConstant(
2055 if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
2056 payload_type,
2057 );
2058 const pl_ptr = if (self.isByRef(payload_type)) try self.buildPointerOffset(
2059 result,
2060 error_type.abiSize(self.target),
2061 .new,
2062 ) else result;
2063 try self.store(pl_ptr, payload, payload_type, 0);
2064 return result;
2065 },
2066 .Optional => if (ty.isPtrLikeOptional()) {
2067 return self.lowerConstant(val, payload_type);
2068 } else {
2057 var buf: Type.Payload.ElemType = undefined;2069 var buf: Type.Payload.ElemType = undefined;
2058 const payload_type = ty.optionalChild(&buf);2070 const payload_type = ty.optionalChild(&buf);
2059 if (ty.isPtrLikeOptional()) {2071 const is_pl = val.tag() == .opt_payload;
2060 try self.emitConstant(val, payload_type);2072 const null_value = WValue{ .imm32 = if (is_pl) @as(u32, 0) else 1 };
2061 return;2073 if (!payload_type.hasCodeGenBits()) {
2074 return null_value;
2062 }2075 }
20632076
2064 // When constant has value 'null', set is_null local to '1'2077 const result = try self.allocStack(ty);
2065 // and payload to '0'2078 try self.store(result, null_value, Type.initTag(.u8), 0);
2066 if (val.castTag(.opt_payload)) |payload| {2079 const payload = try self.lowerConstant(
2067 try self.addImm32(1);2080 if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
2068 if (payload_type.hasCodeGenBits())2081 payload_type,
2069 try self.emitConstant(payload.data, payload_type);2082 );
2070 } else {2083
2071 // set null-tag2084 const pl_ptr = if (self.isByRef(payload_type)) blk: {
2072 try self.addImm32(0);2085 const offset = ty.abiSize(self.target) - payload_type.abiSize();
2073 // null-tag is set, so write a '0' const2086 break :blk try self.buildPointerOffset(result, offset, .new);
2074 try self.addImm32(0);2087 } else result;
2075 }2088 try self.store(pl_ptr, payload, payload_type, 0);
2089 return result;
2076 },2090 },
2077 .Struct => {2091 .Struct => {
2078 const struct_data = val.castTag(.@"struct").?;2092 const struct_data = val.castTag(.@"struct").?;
...@@ -2083,16 +2097,15 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -2083,16 +2097,15 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
2083 const offset = try self.copyLocal(result, ty);2097 const offset = try self.copyLocal(result, ty);
2084 for (fields.values()) |field, index| {2098 for (fields.values()) |field, index| {
2085 const tmp = try self.allocLocal(field.ty);2099 const tmp = try self.allocLocal(field.ty);
2086 try self.emitConstant(struct_data.data[index], field.ty);2100 const field_value = try self.lowerConstant(struct_data.data[index], field.ty);
2087 try self.addLabel(.local_set, tmp.local);2101 try self.store(offset, field_value, field.ty, 0);
2088 try self.store(offset, tmp, field.ty, 0);
20892102
2090 // this prevents us from emitting useless instructions when we reached the end of the loop2103 // this prevents us from emitting useless instructions when we reached the end of the loop
2091 if (index != (fields.count() - 1)) {2104 if (index != (fields.count() - 1)) {
2092 _ = try self.buildPointerOffset(offset, field.ty.abiSize(self.target), .modify);2105 _ = try self.buildPointerOffset(offset, field.ty.abiSize(self.target), .modify);
2093 }2106 }
2094 }2107 }
2095 try self.addLabel(.local_get, result.local);2108 return result;
2096 },2109 },
2097 .Array => {2110 .Array => {
2098 const result = try self.allocStack(ty);2111 const result = try self.allocStack(ty);
...@@ -2108,7 +2121,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -2108,7 +2121,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
2108 const tmp = try self.allocLocal(elem_ty);2121 const tmp = try self.allocLocal(elem_ty);
2109 const offset = try self.copyLocal(result, ty);2122 const offset = try self.copyLocal(result, ty);
2110 for (array.data) |value, index| {2123 for (array.data) |value, index| {
2111 try self.emitConstant(value, elem_ty);2124 try self.lowerConstant(value, elem_ty);
2112 try self.addLabel(.local_set, tmp.local);2125 try self.addLabel(.local_set, tmp.local);
2113 try self.store(offset, tmp, elem_ty, 0);2126 try self.store(offset, tmp, elem_ty, 0);
21142127
...@@ -2129,9 +2142,9 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -2129,9 +2142,9 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
2129 var index: u32 = 0;2142 var index: u32 = 0;
2130 while (index < len_with_sent) : (index += 1) {2143 while (index < len_with_sent) : (index += 1) {
2131 if (sentinel != null and index == len) {2144 if (sentinel != null and index == len) {
2132 try self.emitConstant(sentinel.?, elem_ty);2145 try self.lowerConstant(sentinel.?, elem_ty);
2133 } else {2146 } else {
2134 try self.emitConstant(value, elem_ty);2147 try self.lowerConstant(value, elem_ty);
2135 }2148 }
2136 try self.addLabel(.local_set, tmp.local);2149 try self.addLabel(.local_set, tmp.local);
2137 try self.store(offset, tmp, elem_ty, 0);2150 try self.store(offset, tmp, elem_ty, 0);
...@@ -2144,26 +2157,26 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -2144,26 +2157,26 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
2144 const elem_ty = ty.childType();2157 const elem_ty = ty.childType();
2145 const sent_val = ty.sentinel().?;2158 const sent_val = ty.sentinel().?;
2146 const tmp = try self.allocLocal(elem_ty);2159 const tmp = try self.allocLocal(elem_ty);
2147 try self.emitConstant(sent_val, elem_ty);2160 try self.lowerConstant(sent_val, elem_ty);
2148 try self.addLabel(.local_set, tmp.local);2161 try self.addLabel(.local_set, tmp.local);
2149 try self.store(result, tmp, elem_ty, 0);2162 try self.store(result, tmp, elem_ty, 0);
2150 } else unreachable;2163 } else unreachable;
2151 try self.addLabel(.local_get, result.local);2164 return result;
2152 },2165 },
2153 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),2166 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
2154 }2167 }
2155}2168}
21562169
2157fn emitUndefined(self: *Self, ty: Type) InnerError!void {2170fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
2158 switch (ty.zigTypeTag()) {2171 switch (ty.zigTypeTag()) {
2159 .Int => switch (ty.intInfo(self.target).bits) {2172 .Int => switch (ty.intInfo(self.target).bits) {
2160 0...32 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),2173 0...32 => return WValue{ .imm32 = 0xaaaaaaaa },
2161 33...64 => try self.addImm64(0xaaaaaaaaaaaaaaaa),2174 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
2162 else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),2175 else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),
2163 },2176 },
2164 .Float => switch (ty.floatBits(self.target)) {2177 .Float => switch (ty.floatBits(self.target)) {
2165 0...32 => try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) } }),2178 0...32 => return WValue{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) },
2166 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),2179 33...64 => return WValue{ .float64 = @bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa)) },
2167 else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),2180 else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),
2168 },2181 },
2169 .Array, .Struct => {2182 .Array, .Struct => {
...@@ -2172,18 +2185,18 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {...@@ -2172,18 +2185,18 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {
2172 var offset: u32 = 0;2185 var offset: u32 = 0;
2173 while (offset < abi_size) : (offset += 1) {2186 while (offset < abi_size) : (offset += 1) {
2174 try self.emitWValue(result);2187 try self.emitWValue(result);
2175 try self.addImm32(0xaa);2188 try self.addImm32(0xaaaaaaaa);
2176 switch (self.ptrSize()) {2189 switch (self.arch()) {
2177 4 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),2190 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
2178 8 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),2191 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
2179 else => unreachable,2192 else => unreachable,
2180 }2193 }
2181 }2194 }
2182 try self.addLabel(.local_get, result.local);2195 return result;
2183 },2196 },
2184 .Pointer => switch (self.ptrSize()) {2197 .Pointer => switch (self.arch()) {
2185 4 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),2198 .wasm32 => return WValue{ .imm32 = 0xaaaaaaaa },
2186 8 => try self.addImm64(0xaaaaaaaaaaaaaaaa),2199 .wasm64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
2187 else => unreachable,2200 else => unreachable,
2188 },2201 },
2189 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),2202 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
...@@ -2595,7 +2608,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2595,7 +2608,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2595 // for single value prong we can emit a simple if2608 // for single value prong we can emit a simple if
2596 if (case.values.len == 1) {2609 if (case.values.len == 1) {
2597 try self.emitWValue(target);2610 try self.emitWValue(target);
2598 try self.emitConstant(case.values[0].value, target_ty);2611 const val = try self.lowerConstant(case.values[0].value, target_ty);
2612 try self.emitWValue(val);
2599 const opcode = buildOpcode(.{2613 const opcode = buildOpcode(.{
2600 .valtype1 = try self.typeToValtype(target_ty),2614 .valtype1 = try self.typeToValtype(target_ty),
2601 .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition.2615 .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition.
...@@ -2608,7 +2622,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2608,7 +2622,8 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2608 try self.startBlock(.block, blocktype);2622 try self.startBlock(.block, blocktype);
2609 for (case.values) |value| {2623 for (case.values) |value| {
2610 try self.emitWValue(target);2624 try self.emitWValue(target);
2611 try self.emitConstant(value.value, target_ty);2625 const val = try self.lowerConstant(value.value, target_ty);
2626 try self.emitWValue(val);
2612 const opcode = buildOpcode(.{2627 const opcode = buildOpcode(.{
2613 .valtype1 = try self.typeToValtype(target_ty),2628 .valtype1 = try self.typeToValtype(target_ty),
2614 .op = .eq,2629 .op = .eq,