| ... | @@ -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 variable | 28 | /// Index of the local variable |
| 29 | local: u32, | 29 | local: u32, |
| 30 | /// Holds a memoized typed value | 30 | /// 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 within | 46 | /// 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 instead | 603 | /// When the given instruction has a `Value`, it returns a constant instead |
| 590 | fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue { | 604 | fn 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 | }; | | |
| 598 | | 607 | |
| 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 integers | 609 | // 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).?; |
| 602 | | 611 | 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 | } |
| 610 | | 614 | |
| 611 | /// Appends a MIR instruction and returns its index within the list of instructions | 615 | /// 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-op | 734 | .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 stack | 737 | .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 | } |
| 736 | | 745 | |
| ... | @@ -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 | } |
| 1209 | | 1219 | |
| | 1220 | fn 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 passed | 1224 | /// 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. |
| 1212 | fn isByRef(self: Self, ty: Type) bool { | 1226 | fn 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 | } |
| 1935 | | 1938 | |
| 1936 | fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { | 1939 | fn 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 constant | 1944 | // 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 constant | 1980 | 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 address | 2007 | 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' const | 2047 | const error_value = try self.lowerConstant(err_val, error_type); |
| 2040 | try self.addImm32(0); | 2048 | if (!payload_type.hasCodeGenBits()) { |
| 2041 | | 2049 | 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 | } |
| 2063 | | 2076 | |
| 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-tag | 2084 | 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' const | 2086 | 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); | | |
| 2089 | | 2102 | |
| 2090 | // this prevents us from emitting useless instructions when we reached the end of the loop | 2103 | // 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); |
| 2114 | | 2127 | |
| ... | @@ -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 | } |
| 2156 | | 2169 | |
| 2157 | fn emitUndefined(self: *Self, ty: Type) InnerError!void { | 2170 | fn 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 if | 2608 | // 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, |