| ... | @@ -644,6 +644,12 @@ fn addFloat64(self: *Self, float: f64) error{OutOfMemory}!void { | ... | @@ -644,6 +644,12 @@ fn addFloat64(self: *Self, float: f64) error{OutOfMemory}!void { |
| 644 | try self.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } }); | 644 | try self.addInst(.{ .tag = .f64_const, .data = .{ .payload = extra_index } }); |
| 645 | } | 645 | } |
| 646 | | 646 | |
| | 647 | /// Inserts an instruction to load/store from/to wasm's linear memory dependent on the given `tag`. |
| | 648 | fn addMemArg(self: *Self, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOfMemory}!void { |
| | 649 | const extra_index = try self.addExtra(mem_arg); |
| | 650 | try self.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } }); |
| | 651 | } |
| | 652 | |
| 647 | /// Appends entries to `mir_extra` based on the type of `extra`. | 653 | /// Appends entries to `mir_extra` based on the type of `extra`. |
| 648 | /// Returns the index into `mir_extra` | 654 | /// Returns the index into `mir_extra` |
| 649 | fn addExtra(self: *Self, extra: anytype) error{OutOfMemory}!u32 { | 655 | fn addExtra(self: *Self, extra: anytype) error{OutOfMemory}!u32 { |
| ... | @@ -692,8 +698,9 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { | ... | @@ -692,8 +698,9 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { |
| 692 | .ErrorUnion, | 698 | .ErrorUnion, |
| 693 | .Optional, | 699 | .Optional, |
| 694 | .Fn, | 700 | .Fn, |
| | 701 | .Array, |
| 695 | => wasm.Valtype.i32, | 702 | => wasm.Valtype.i32, |
| 696 | else => self.fail("TODO - Wasm valtype for type '{}'", .{ty}), | 703 | else => self.fail("TODO - Wasm typeToValtype for type '{}'", .{ty}), |
| 697 | }; | 704 | }; |
| 698 | } | 705 | } |
| 699 | | 706 | |
| ... | @@ -756,7 +763,6 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { | ... | @@ -756,7 +763,6 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type { |
| 756 | switch (return_type.zigTypeTag()) { | 763 | switch (return_type.zigTypeTag()) { |
| 757 | .Void, .NoReturn => {}, | 764 | .Void, .NoReturn => {}, |
| 758 | .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}), | 765 | .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}), |
| 759 | .Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}), | | |
| 760 | else => try returns.append(try self.typeToValtype(return_type)), | 766 | else => try returns.append(try self.typeToValtype(return_type)), |
| 761 | } | 767 | } |
| 762 | | 768 | |
| ... | @@ -1146,6 +1152,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1146,6 +1152,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1146 | .cmp_lt => self.airCmp(inst, .lt), | 1152 | .cmp_lt => self.airCmp(inst, .lt), |
| 1147 | .cmp_neq => self.airCmp(inst, .neq), | 1153 | .cmp_neq => self.airCmp(inst, .neq), |
| 1148 | | 1154 | |
| | 1155 | .array_to_slice => self.airArrayToSlice(inst), |
| 1149 | .alloc => self.airAlloc(inst), | 1156 | .alloc => self.airAlloc(inst), |
| 1150 | .arg => self.airArg(inst), | 1157 | .arg => self.airArg(inst), |
| 1151 | .bitcast => self.airBitcast(inst), | 1158 | .bitcast => self.airBitcast(inst), |
| ... | @@ -1178,6 +1185,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1178,6 +1185,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1178 | .ret_load => self.airRetLoad(inst), | 1185 | .ret_load => self.airRetLoad(inst), |
| 1179 | .slice_len => self.airSliceLen(inst), | 1186 | .slice_len => self.airSliceLen(inst), |
| 1180 | .slice_elem_val => self.airSliceElemVal(inst), | 1187 | .slice_elem_val => self.airSliceElemVal(inst), |
| | 1188 | .slice_elem_ptr => self.airSliceElemPtr(inst), |
| 1181 | .slice_ptr => self.airSlicePtr(inst), | 1189 | .slice_ptr => self.airSlicePtr(inst), |
| 1182 | .store => self.airStore(inst), | 1190 | .store => self.airStore(inst), |
| 1183 | .struct_field_ptr => self.airStructFieldPtr(inst), | 1191 | .struct_field_ptr => self.airStructFieldPtr(inst), |
| ... | @@ -1283,6 +1291,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1283,6 +1291,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1283 | .Struct, .Pointer, .Optional, .ErrorUnion => { | 1291 | .Struct, .Pointer, .Optional, .ErrorUnion => { |
| 1284 | // single pointer can be passed directly | 1292 | // single pointer can be passed directly |
| 1285 | if (arg_ty.isSinglePointer() or arg_val != .constant) { | 1293 | if (arg_ty.isSinglePointer() or arg_val != .constant) { |
| | 1294 | if (arg_val == .none) { |
| | 1295 | // when the argument is a 0-sized value, but the function |
| | 1296 | // expects a non-zero typed value (such as a slice), we must emit an argument |
| | 1297 | // as function calls are verified with the function signature in wasm. |
| | 1298 | // In those cases we will emit a '0xaa' as address, meaning invalid memory. |
| | 1299 | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); |
| | 1300 | continue; |
| | 1301 | } |
| 1286 | try self.emitWValue(arg_val); | 1302 | try self.emitWValue(arg_val); |
| 1287 | continue; | 1303 | continue; |
| 1288 | } | 1304 | } |
| ... | @@ -1467,14 +1483,10 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1467,14 +1483,10 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1467 | }); | 1483 | }); |
| 1468 | | 1484 | |
| 1469 | // store rhs value at stack pointer's location in memory | 1485 | // store rhs value at stack pointer's location in memory |
| 1470 | const mem_arg_index = try self.addExtra(Mir.MemArg{ | 1486 | try self.addMemArg( |
| 1471 | .offset = offset, | 1487 | Mir.Inst.Tag.fromOpcode(opcode), |
| 1472 | .alignment = ty.abiAlignment(self.target), | 1488 | .{ .offset = offset, .alignment = ty.abiAlignment(self.target) }, |
| 1473 | }); | 1489 | ); |
| 1474 | try self.addInst(.{ | | |
| 1475 | .tag = Mir.Inst.Tag.fromOpcode(opcode), | | |
| 1476 | .data = .{ .payload = mem_arg_index }, | | |
| 1477 | }); | | |
| 1478 | } | 1490 | } |
| 1479 | | 1491 | |
| 1480 | fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1492 | fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -1518,14 +1530,10 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | ... | @@ -1518,14 +1530,10 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1518 | .signedness = signedness, | 1530 | .signedness = signedness, |
| 1519 | }); | 1531 | }); |
| 1520 | | 1532 | |
| 1521 | const mem_arg_index = try self.addExtra(Mir.MemArg{ | 1533 | try self.addMemArg( |
| 1522 | .offset = offset, | 1534 | Mir.Inst.Tag.fromOpcode(opcode), |
| 1523 | .alignment = ty.abiAlignment(self.target), | 1535 | .{ .offset = offset, .alignment = ty.abiAlignment(self.target) }, |
| 1524 | }); | 1536 | ); |
| 1525 | try self.addInst(.{ | | |
| 1526 | .tag = Mir.Inst.Tag.fromOpcode(opcode), | | |
| 1527 | .data = .{ .payload = mem_arg_index }, | | |
| 1528 | }); | | |
| 1529 | | 1537 | |
| 1530 | // store the result in a local | 1538 | // store the result in a local |
| 1531 | const result = try self.allocLocal(ty); | 1539 | const result = try self.allocLocal(ty); |
| ... | @@ -1713,10 +1721,10 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { | ... | @@ -1713,10 +1721,10 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { |
| 1713 | | 1721 | |
| 1714 | // When constant has value 'null', set is_null local to '1' | 1722 | // When constant has value 'null', set is_null local to '1' |
| 1715 | // and payload to '0' | 1723 | // and payload to '0' |
| 1716 | if (val.castTag(.opt_payload)) |pl| { | 1724 | if (val.castTag(.opt_payload)) |payload| { |
| 1717 | const payload_val = pl.data; | | |
| 1718 | try self.addImm32(0); | 1725 | try self.addImm32(0); |
| 1719 | try self.emitConstant(payload_val, payload_type); | 1726 | if (payload_type.hasCodeGenBits()) |
| | 1727 | try self.emitConstant(payload.data, payload_type); |
| 1720 | } else { | 1728 | } else { |
| 1721 | // set null-tag | 1729 | // set null-tag |
| 1722 | try self.addImm32(1); | 1730 | try self.addImm32(1); |
| ... | @@ -1740,6 +1748,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void { | ... | @@ -1740,6 +1748,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void { |
| 1740 | 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))), | 1748 | 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))), |
| 1741 | else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}), | 1749 | else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}), |
| 1742 | }, | 1750 | }, |
| | 1751 | .Array => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))), |
| 1743 | else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}), | 1752 | else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}), |
| 1744 | } | 1753 | } |
| 1745 | } | 1754 | } |
| ... | @@ -1953,7 +1962,14 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -1953,7 +1962,14 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1953 | | 1962 | |
| 1954 | fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1963 | fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1955 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1964 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1956 | return self.resolveInst(ty_op.operand); | 1965 | const operand = self.resolveInst(ty_op.operand); |
| | 1966 | if (operand == .constant) { |
| | 1967 | const result = try self.allocLocal(self.air.typeOfIndex(inst)); |
| | 1968 | try self.emitWValue(operand); |
| | 1969 | try self.addLabel(.local_set, result.local); |
| | 1970 | return result; |
| | 1971 | } |
| | 1972 | return operand; |
| 1957 | } | 1973 | } |
| 1958 | | 1974 | |
| 1959 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1975 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -1973,12 +1989,21 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr | ... | @@ -1973,12 +1989,21 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr |
| 1973 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1989 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1974 | const struct_ptr = self.resolveInst(ty_op.operand); | 1990 | const struct_ptr = self.resolveInst(ty_op.operand); |
| 1975 | const struct_ty = self.air.typeOf(ty_op.operand).childType(); | 1991 | const struct_ty = self.air.typeOf(ty_op.operand).childType(); |
| | 1992 | const field_ty = struct_ty.structFieldType(index); |
| 1976 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(index, self.target)) catch { | 1993 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(index, self.target)) catch { |
| 1977 | return self.fail("Field type '{}' too big to fit into stack frame", .{ | 1994 | return self.fail("Field type '{}' too big to fit into stack frame", .{ |
| 1978 | struct_ty.structFieldType(index), | 1995 | field_ty, |
| 1979 | }); | 1996 | }); |
| 1980 | }; | 1997 | }; |
| 1981 | return structFieldPtr(struct_ptr, offset); | 1998 | // field points to another struct, so retrieve that struct first |
| | 1999 | switch (struct_ptr) { |
| | 2000 | .local => return structFieldPtr(struct_ptr, offset), |
| | 2001 | .local_with_offset => |with_offset| { |
| | 2002 | const result = try self.load(struct_ptr, field_ty, with_offset.offset); |
| | 2003 | return structFieldPtr(result, offset); |
| | 2004 | }, |
| | 2005 | else => unreachable, |
| | 2006 | } |
| 1982 | } | 2007 | } |
| 1983 | | 2008 | |
| 1984 | fn structFieldPtr(struct_ptr: WValue, offset: u32) InnerError!WValue { | 2009 | fn structFieldPtr(struct_ptr: WValue, offset: u32) InnerError!WValue { |
| ... | @@ -2156,14 +2181,10 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W | ... | @@ -2156,14 +2181,10 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 2156 | | 2181 | |
| 2157 | // load the error tag value | 2182 | // load the error tag value |
| 2158 | try self.emitWValue(operand); | 2183 | try self.emitWValue(operand); |
| 2159 | const mem_arg_index = try self.addExtra(Mir.MemArg{ | 2184 | try self.addMemArg( |
| 2160 | .offset = 0, | 2185 | .i32_load16_u, |
| 2161 | .alignment = err_ty.abiAlignment(self.target), | 2186 | .{ .offset = 0, .alignment = err_ty.abiAlignment(self.target) }, |
| 2162 | }); | 2187 | ); |
| 2163 | try self.addInst(.{ | | |
| 2164 | .tag = .i32_load16_u, | | |
| 2165 | .data = .{ .payload = mem_arg_index }, | | |
| 2166 | }); | | |
| 2167 | | 2188 | |
| 2168 | // Compare the error value with '0' | 2189 | // Compare the error value with '0' |
| 2169 | try self.addImm32(0); | 2190 | try self.addImm32(0); |
| ... | @@ -2257,11 +2278,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError! | ... | @@ -2257,11 +2278,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError! |
| 2257 | | 2278 | |
| 2258 | // load the null tag value | 2279 | // load the null tag value |
| 2259 | try self.emitWValue(operand); | 2280 | try self.emitWValue(operand); |
| 2260 | const mem_arg_index = try self.addExtra(Mir.MemArg{ .offset = 0, .alignment = 1 }); | 2281 | try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 }); |
| 2261 | try self.addInst(.{ | | |
| 2262 | .tag = .i32_load8_u, | | |
| 2263 | .data = .{ .payload = mem_arg_index }, | | |
| 2264 | }); | | |
| 2265 | | 2282 | |
| 2266 | // Compare the error value with '0' | 2283 | // Compare the error value with '0' |
| 2267 | try self.addImm32(0); | 2284 | try self.addImm32(0); |
| ... | @@ -2353,6 +2370,31 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2353,6 +2370,31 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2353 | }; | 2370 | }; |
| 2354 | } | 2371 | } |
| 2355 | | 2372 | |
| | 2373 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| | 2374 | if (self.liveness.isUnused(inst)) return WValue.none; |
| | 2375 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 2376 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 2377 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| | 2378 | const elem_ty = self.air.getRefType(ty_pl.ty).childType(); |
| | 2379 | const elem_size = elem_ty.abiSize(self.target); |
| | 2380 | |
| | 2381 | const slice = self.resolveInst(bin_op.lhs); |
| | 2382 | const index = self.resolveInst(bin_op.rhs); |
| | 2383 | |
| | 2384 | const slice_ptr = try self.load(slice, slice_ty, 0); |
| | 2385 | try self.addLabel(.local_get, slice_ptr.local); |
| | 2386 | |
| | 2387 | // calculate index into slice |
| | 2388 | try self.emitWValue(index); |
| | 2389 | try self.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| | 2390 | try self.addTag(.i32_mul); |
| | 2391 | try self.addTag(.i32_add); |
| | 2392 | |
| | 2393 | const result = try self.allocLocal(Type.initTag(.i32)); |
| | 2394 | try self.addLabel(.local_set, result.local); |
| | 2395 | return result; |
| | 2396 | } |
| | 2397 | |
| 2356 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2398 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2357 | if (self.liveness.isUnused(inst)) return WValue.none; | 2399 | if (self.liveness.isUnused(inst)) return WValue.none; |
| 2358 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2400 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| ... | @@ -2424,3 +2466,8 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -2424,3 +2466,8 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2424 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2466 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2425 | return self.resolveInst(un_op); | 2467 | return self.resolveInst(un_op); |
| 2426 | } | 2468 | } |
| | 2469 | |
| | 2470 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| | 2471 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2472 | return self.resolveInst(ty_op.operand); |
| | 2473 | } |