| ... | ... | @@ -973,6 +973,41 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result { |
| 973 | 973 | }, |
| 974 | 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 | 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 | 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 | 1207 | fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1153 | 1208 | const air_tags = self.air.instructions.items(.tag); |
| 1154 | 1209 | return switch (air_tags[inst]) { |
| ... | ... | @@ -1482,20 +1537,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1482 | 1537 | } |
| 1483 | 1538 | }, |
| 1484 | 1539 | .Struct => { |
| 1485 | | // we are copying a struct with its fields. |
| 1486 | | // Replace this with a wasm memcpy instruction once we support that feature. |
| 1487 | | const fields_len = ty.structFieldCount(); |
| 1488 | | var index: usize = 0; |
| 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); |
| 1540 | if (rhs == .constant) { |
| 1541 | try self.emitWValue(rhs); |
| 1542 | try self.addLabel(.local_set, lhs.local); |
| 1543 | return; |
| 1497 | 1544 | } |
| 1498 | | return; |
| 1545 | return try self.memCopy(ty, lhs, rhs); |
| 1499 | 1546 | }, |
| 1500 | 1547 | .Pointer => { |
| 1501 | 1548 | if (ty.isSlice() and rhs == .constant) { |
| ... | ... | @@ -2086,19 +2133,20 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr |
| 2086 | 2133 | field_ty, |
| 2087 | 2134 | }); |
| 2088 | 2135 | }; |
| 2089 | | // field points to another struct, so retrieve that struct first |
| 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 | | } |
| 2136 | return structFieldPtr(struct_ptr, offset); |
| 2098 | 2137 | } |
| 2099 | 2138 | |
| 2100 | 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 | 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 | 2162 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch { |
| 2115 | 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 | 2180 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |