| ... | @@ -973,6 +973,41 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result { | ... | @@ -973,6 +973,41 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result { |
| 973 | }, | 973 | }, |
| 974 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), | 974 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 975 | }, | 975 | }, |
| | 976 | .ErrorUnion => { |
| | 977 | const error_ty = ty.errorUnionSet(); |
| | 978 | const payload_ty = ty.errorUnionPayload(); |
| | 979 | const is_pl = val.errorUnionIsPayload(); |
| | 980 | |
| | 981 | const err_val = if (!is_pl) val else Value.initTag(.zero); |
| | 982 | switch (try self.genTypedValue(error_ty, err_val)) { |
| | 983 | .externally_managed => |data| try self.code.appendSlice(data), |
| | 984 | .appended => {}, |
| | 985 | } |
| | 986 | |
| | 987 | if (payload_ty.hasCodeGenBits()) { |
| | 988 | const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); |
| | 989 | switch (try self.genTypedValue(payload_ty, pl_val)) { |
| | 990 | .externally_managed => |data| try self.code.appendSlice(data), |
| | 991 | .appended => {}, |
| | 992 | } |
| | 993 | } |
| | 994 | |
| | 995 | return Result.appended; |
| | 996 | }, |
| | 997 | .ErrorSet => { |
| | 998 | switch (val.tag()) { |
| | 999 | .@"error" => { |
| | 1000 | const name = val.castTag(.@"error").?.data.name; |
| | 1001 | const value = self.global_error_set.get(name).?; |
| | 1002 | try self.code.writer().writeIntLittle(u32, value); |
| | 1003 | }, |
| | 1004 | else => { |
| | 1005 | const abi_size = @intCast(usize, ty.abiSize(self.target)); |
| | 1006 | try self.code.appendNTimes(0, abi_size); |
| | 1007 | }, |
| | 1008 | } |
| | 1009 | return Result.appended; |
| | 1010 | }, |
| 976 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), | 1011 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), |
| 977 | } | 1012 | } |
| 978 | } | 1013 | } |
| ... | @@ -1149,6 +1184,26 @@ fn toWasmIntBits(bits: u16) ?u16 { | ... | @@ -1149,6 +1184,26 @@ fn toWasmIntBits(bits: u16) ?u16 { |
| 1149 | } else null; | 1184 | } else null; |
| 1150 | } | 1185 | } |
| 1151 | | 1186 | |
| | 1187 | /// Performs a copy of bytes for a given type. Copying all bytes |
| | 1188 | /// from rhs to lhs. |
| | 1189 | /// Asserts `lhs` and `rhs` have their active tag set to `local` |
| | 1190 | /// |
| | 1191 | /// TODO: Perform feature detection and when bulk_memory is available, |
| | 1192 | /// use wasm's mem.copy instruction. |
| | 1193 | fn memCopy(self: *Self, ty: Type, lhs: WValue, rhs: WValue) !void { |
| | 1194 | const abi_size = ty.abiSize(self.target); |
| | 1195 | var offset: u32 = 0; |
| | 1196 | while (offset < abi_size) : (offset += 1) { |
| | 1197 | // get lhs' address to store the result |
| | 1198 | try self.addLabel(.local_get, lhs.local); |
| | 1199 | // load byte from rhs' adress |
| | 1200 | try self.addLabel(.local_get, rhs.local); |
| | 1201 | try self.addMemArg(.i32_load8_u, .{ .offset = offset, .alignment = 1 }); |
| | 1202 | // store the result in lhs (we already have its address on the stack) |
| | 1203 | try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }); |
| | 1204 | } |
| | 1205 | } |
| | 1206 | |
| 1152 | fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | 1207 | fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1153 | const air_tags = self.air.instructions.items(.tag); | 1208 | const air_tags = self.air.instructions.items(.tag); |
| 1154 | return switch (air_tags[inst]) { | 1209 | return switch (air_tags[inst]) { |
| ... | @@ -1482,20 +1537,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1482,20 +1537,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1482 | } | 1537 | } |
| 1483 | }, | 1538 | }, |
| 1484 | .Struct => { | 1539 | .Struct => { |
| 1485 | // we are copying a struct with its fields. | 1540 | if (rhs == .constant) { |
| 1486 | // Replace this with a wasm memcpy instruction once we support that feature. | 1541 | try self.emitWValue(rhs); |
| 1487 | const fields_len = ty.structFieldCount(); | 1542 | try self.addLabel(.local_set, lhs.local); |
| 1488 | var index: usize = 0; | 1543 | return; |
| 1489 | while (index < fields_len) : (index += 1) { | | |
| 1490 | const field_ty = ty.structFieldType(index); | | |
| 1491 | if (!field_ty.hasCodeGenBits()) continue; | | |
| 1492 | const field_offset = std.math.cast(u32, ty.structFieldOffset(index, self.target)) catch { | | |
| 1493 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); | | |
| 1494 | }; | | |
| 1495 | const field_local = try self.load(rhs, field_ty, field_offset); | | |
| 1496 | try self.store(lhs, field_local, field_ty, field_offset); | | |
| 1497 | } | 1544 | } |
| 1498 | return; | 1545 | return try self.memCopy(ty, lhs, rhs); |
| 1499 | }, | 1546 | }, |
| 1500 | .Pointer => { | 1547 | .Pointer => { |
| 1501 | if (ty.isSlice() and rhs == .constant) { | 1548 | if (ty.isSlice() and rhs == .constant) { |
| ... | @@ -2086,19 +2133,20 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr | ... | @@ -2086,19 +2133,20 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr |
| 2086 | field_ty, | 2133 | field_ty, |
| 2087 | }); | 2134 | }); |
| 2088 | }; | 2135 | }; |
| 2089 | // field points to another struct, so retrieve that struct first | 2136 | return structFieldPtr(struct_ptr, offset); |
| 2090 | switch (struct_ptr) { | | |
| 2091 | .local => return structFieldPtr(struct_ptr, offset), | | |
| 2092 | .local_with_offset => |with_offset| { | | |
| 2093 | const result = try self.load(struct_ptr, field_ty, with_offset.offset); | | |
| 2094 | return structFieldPtr(result, offset); | | |
| 2095 | }, | | |
| 2096 | else => unreachable, | | |
| 2097 | } | | |
| 2098 | } | 2137 | } |
| 2099 | | 2138 | |
| 2100 | fn structFieldPtr(struct_ptr: WValue, offset: u32) InnerError!WValue { | 2139 | fn structFieldPtr(struct_ptr: WValue, offset: u32) InnerError!WValue { |
| 2101 | return WValue{ .local_with_offset = .{ .local = struct_ptr.local, .offset = offset } }; | 2140 | var final_offset = offset; |
| | 2141 | const local = switch (struct_ptr) { |
| | 2142 | .local => |local| local, |
| | 2143 | .local_with_offset => |with_offset| blk: { |
| | 2144 | final_offset += with_offset.offset; |
| | 2145 | break :blk with_offset.local; |
| | 2146 | }, |
| | 2147 | else => unreachable, |
| | 2148 | }; |
| | 2149 | return WValue{ .local_with_offset = .{ .local = local, .offset = final_offset } }; |
| 2102 | } | 2150 | } |
| 2103 | | 2151 | |
| 2104 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2152 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -2114,7 +2162,19 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2114,7 +2162,19 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2114 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch { | 2162 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch { |
| 2115 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); | 2163 | return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty}); |
| 2116 | }; | 2164 | }; |
| 2117 | return try self.load(operand, field_ty, offset); | 2165 | |
| | 2166 | // TODO: Replace this check with some 'isByRef' function to de-duplicate logic |
| | 2167 | if (field_ty.zigTypeTag() == .Struct) { |
| | 2168 | return WValue{ .local_with_offset = .{ |
| | 2169 | .local = operand.local, |
| | 2170 | .offset = offset, |
| | 2171 | } }; |
| | 2172 | } |
| | 2173 | |
| | 2174 | switch (operand) { |
| | 2175 | .local_with_offset => |with_offset| return try self.load(operand, field_ty, offset + with_offset.offset), |
| | 2176 | else => return try self.load(operand, field_ty, offset), |
| | 2177 | } |
| 2118 | } | 2178 | } |
| 2119 | | 2179 | |
| 2120 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2180 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |