| ... | @@ -599,7 +599,41 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue { | ... | @@ -599,7 +599,41 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue { |
| 599 | const val = self.air.value(ref).?; | 599 | const val = self.air.value(ref).?; |
| 600 | const ty = self.air.typeOf(ref); | 600 | const ty = self.air.typeOf(ref); |
| 601 | if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} }; | 601 | if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} }; |
| 602 | const result = try self.lowerConstant(val, ty); | 602 | |
| | 603 | // When we need to pass the value by reference (such as a struct), we will |
| | 604 | // leverage `genTypedValue` to lower the constant to bytes and emit it |
| | 605 | // to the 'rodata' section. We then return the index into the section as `WValue`. |
| | 606 | // |
| | 607 | // In the other cases, we will simply lower the constant to a value that fits |
| | 608 | // into a single local (such as a pointer, integer, bool, etc). |
| | 609 | const result = if (isByRef(ty, self.target)) blk: { |
| | 610 | var value_bytes = std.ArrayList(u8).init(self.gpa); |
| | 611 | defer value_bytes.deinit(); |
| | 612 | |
| | 613 | var decl_gen: DeclGen = .{ |
| | 614 | .bin_file = self.bin_file, |
| | 615 | .decl = self.decl, |
| | 616 | .err_msg = undefined, |
| | 617 | .gpa = self.gpa, |
| | 618 | .module = self.module, |
| | 619 | .code = &value_bytes, |
| | 620 | .symbol_index = try self.bin_file.createLocalSymbol(self.decl, ty), |
| | 621 | }; |
| | 622 | const result = decl_gen.genTypedValue(ty, val, value_bytes.writer()) catch |err| { |
| | 623 | // When a codegen error occured, take ownership of the error message |
| | 624 | if (err == error.CodegenFail) { |
| | 625 | self.err_msg = decl_gen.err_msg; |
| | 626 | } |
| | 627 | return err; |
| | 628 | }; |
| | 629 | const code = switch (result) { |
| | 630 | .appended => value_bytes.items, |
| | 631 | .externally_managed => |data| data, |
| | 632 | }; |
| | 633 | try self.bin_file.updateLocalSymbolCode(self.decl, decl_gen.symbol_index, code); |
| | 634 | break :blk WValue{ .memory = decl_gen.symbol_index }; |
| | 635 | } else try self.lowerConstant(val, ty); |
| | 636 | |
| 603 | gop.value_ptr.* = result; | 637 | gop.value_ptr.* = result; |
| 604 | return result; | 638 | return result; |
| 605 | } | 639 | } |
| ... | @@ -867,15 +901,15 @@ pub const DeclGen = struct { | ... | @@ -867,15 +901,15 @@ pub const DeclGen = struct { |
| 867 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target()); | 901 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target()); |
| 868 | func_type.deinit(self.gpa); | 902 | func_type.deinit(self.gpa); |
| 869 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); | 903 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| 870 | return Result.appended; | 904 | return Result{ .appended = {} }; |
| 871 | } else { | 905 | } else { |
| 872 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | 906 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { |
| 873 | break :init_val payload.data.init; | 907 | break :init_val payload.data.init; |
| 874 | } else decl.val; | 908 | } else decl.val; |
| 875 | if (init_val.tag() != .unreachable_value) { | 909 | if (init_val.tag() != .unreachable_value) { |
| 876 | return try self.genTypedValue(decl.ty, init_val, self.code.writer()); | 910 | return self.genTypedValue(decl.ty, init_val, self.code.writer()); |
| 877 | } | 911 | } |
| 878 | return Result.appended; | 912 | return Result{ .appended = {} }; |
| 879 | } | 913 | } |
| 880 | } | 914 | } |
| 881 | | 915 | |
| ... | @@ -883,7 +917,7 @@ pub const DeclGen = struct { | ... | @@ -883,7 +917,7 @@ pub const DeclGen = struct { |
| 883 | fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result { | 917 | fn genTypedValue(self: *DeclGen, ty: Type, val: Value, writer: anytype) InnerError!Result { |
| 884 | if (val.isUndef()) { | 918 | if (val.isUndef()) { |
| 885 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); | 919 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 886 | return Result.appended; | 920 | return Result{ .appended = {} }; |
| 887 | } | 921 | } |
| 888 | switch (ty.zigTypeTag()) { | 922 | switch (ty.zigTypeTag()) { |
| 889 | .Fn => { | 923 | .Fn => { |
| ... | @@ -898,35 +932,36 @@ pub const DeclGen = struct { | ... | @@ -898,35 +932,36 @@ pub const DeclGen = struct { |
| 898 | var opt_buf: Type.Payload.ElemType = undefined; | 932 | var opt_buf: Type.Payload.ElemType = undefined; |
| 899 | const payload_type = ty.optionalChild(&opt_buf); | 933 | const payload_type = ty.optionalChild(&opt_buf); |
| 900 | const is_pl = !val.isNull(); | 934 | const is_pl = !val.isNull(); |
| | 935 | const abi_size = @intCast(usize, ty.abiSize(self.target())); |
| | 936 | const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target())); |
| 901 | | 937 | |
| 902 | if (!payload_type.hasCodeGenBits()) { | 938 | if (!payload_type.hasCodeGenBits()) { |
| 903 | try writer.writeByteNTimes(@boolToInt(is_pl), 4); | 939 | try writer.writeByteNTimes(@boolToInt(is_pl), abi_size); |
| 904 | return Result.appended; | 940 | return Result{ .appended = {} }; |
| 905 | } | 941 | } |
| 906 | | 942 | |
| 907 | if (ty.isPtrLikeOptional()) { | 943 | if (ty.isPtrLikeOptional()) { |
| 908 | if (val.castTag(.opt_payload)) |payload| { | 944 | if (val.castTag(.opt_payload)) |payload| { |
| 909 | return try self.genTypedValue(payload_type, payload.data, writer); | 945 | return self.genTypedValue(payload_type, payload.data, writer); |
| 910 | } else if (!val.isNull()) { | 946 | } else if (!val.isNull()) { |
| 911 | return try self.genTypedValue(payload_type, val, writer); | 947 | return self.genTypedValue(payload_type, val, writer); |
| 912 | } else { | 948 | } else { |
| 913 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); | 949 | try writer.writeByteNTimes(0, abi_size); |
| 914 | return Result.appended; | 950 | return Result{ .appended = {} }; |
| 915 | } | 951 | } |
| 916 | } | 952 | } |
| 917 | | 953 | |
| 918 | // `null-tag` bytes | 954 | // `null-tag` bytes |
| 919 | try writer.writeByteNTimes(@boolToInt(is_pl), 4); | 955 | try writer.writeByteNTimes(@boolToInt(is_pl), offset); |
| 920 | const pl_result = try self.genTypedValue( | 956 | switch (try self.genTypedValue( |
| 921 | payload_type, | 957 | payload_type, |
| 922 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 958 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), |
| 923 | writer, | 959 | writer, |
| 924 | ); | 960 | )) { |
| 925 | switch (pl_result) { | | |
| 926 | .appended => {}, | 961 | .appended => {}, |
| 927 | .externally_managed => |payload| try writer.writeAll(payload), | 962 | .externally_managed => |payload| try writer.writeAll(payload), |
| 928 | } | 963 | } |
| 929 | return Result.appended; | 964 | return Result{ .appended = {} }; |
| 930 | }, | 965 | }, |
| 931 | .Array => switch (val.tag()) { | 966 | .Array => switch (val.tag()) { |
| 932 | .bytes => { | 967 | .bytes => { |
| ... | @@ -942,29 +977,68 @@ pub const DeclGen = struct { | ... | @@ -942,29 +977,68 @@ pub const DeclGen = struct { |
| 942 | .externally_managed => |data| try writer.writeAll(data), | 977 | .externally_managed => |data| try writer.writeAll(data), |
| 943 | } | 978 | } |
| 944 | } | 979 | } |
| 945 | return Result.appended; | 980 | return Result{ .appended = {} }; |
| | 981 | }, |
| | 982 | .repeated => { |
| | 983 | const array = val.castTag(.repeated).?.data; |
| | 984 | const elem_ty = ty.childType(); |
| | 985 | const sentinel = ty.sentinel(); |
| | 986 | const len = ty.arrayLen(); |
| | 987 | |
| | 988 | var index: u32 = 0; |
| | 989 | while (index < len) : (index += 1) { |
| | 990 | switch (try self.genTypedValue(elem_ty, array, writer)) { |
| | 991 | .externally_managed => |data| try writer.writeAll(data), |
| | 992 | .appended => {}, |
| | 993 | } |
| | 994 | } |
| | 995 | if (sentinel) |sentinel_value| { |
| | 996 | return self.genTypedValue(elem_ty, sentinel_value, writer); |
| | 997 | } |
| | 998 | return Result{ .appended = {} }; |
| | 999 | }, |
| | 1000 | .empty_array_sentinel => { |
| | 1001 | const elem_ty = ty.childType(); |
| | 1002 | const sent_val = ty.sentinel().?; |
| | 1003 | return self.genTypedValue(elem_ty, sent_val, writer); |
| 946 | }, | 1004 | }, |
| 947 | else => return self.fail("TODO implement genTypedValue for array type value: {s}", .{@tagName(val.tag())}), | 1005 | else => unreachable, |
| 948 | }, | 1006 | }, |
| 949 | .Int => { | 1007 | .Int => { |
| 950 | const info = ty.intInfo(self.target()); | 1008 | const info = ty.intInfo(self.target()); |
| 951 | const abi_size = @intCast(usize, ty.abiSize(self.target())); | 1009 | const abi_size = @intCast(usize, ty.abiSize(self.target())); |
| 952 | // todo: Implement integer sizes larger than 64bits | 1010 | if (info.bits <= 64) { |
| 953 | if (info.bits > 64) return self.fail("TODO: Implement genTypedValue for integer bit size: {d}", .{info.bits}); | 1011 | var buf: [8]u8 = undefined; |
| 954 | var buf: [8]u8 = undefined; | 1012 | if (info.signedness == .unsigned) { |
| 955 | if (info.signedness == .unsigned) { | 1013 | std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt()); |
| 956 | std.mem.writeIntLittle(u64, &buf, val.toUnsignedInt()); | 1014 | } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt()); |
| 957 | } else std.mem.writeIntLittle(i64, &buf, val.toSignedInt()); | 1015 | try writer.writeAll(buf[0..abi_size]); |
| 958 | try writer.writeAll(buf[0..abi_size]); | 1016 | return Result{ .appended = {} }; |
| 959 | return Result.appended; | 1017 | } |
| | 1018 | var space: Value.BigIntSpace = undefined; |
| | 1019 | const bigint = val.toBigInt(&space); |
| | 1020 | const iterations = @divExact(abi_size, @sizeOf(usize)); |
| | 1021 | for (bigint.limbs) |_, index| { |
| | 1022 | const limb = bigint.limbs[bigint.limbs.len - index - 1]; |
| | 1023 | try writer.writeIntLittle(usize, limb); |
| | 1024 | } else if (bigint.limbs.len < iterations) { |
| | 1025 | // When the value is saved in less limbs than the required |
| | 1026 | // abi size, we fill the remaining parts with 0's. |
| | 1027 | var it_left = iterations - bigint.limbs.len; |
| | 1028 | while (it_left > 0) { |
| | 1029 | it_left -= 1; |
| | 1030 | try writer.writeIntLittle(usize, 0); |
| | 1031 | } |
| | 1032 | } |
| | 1033 | return Result{ .appended = {} }; |
| 960 | }, | 1034 | }, |
| 961 | .Enum => { | 1035 | .Enum => { |
| 962 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); | 1036 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 963 | return Result.appended; | 1037 | return Result{ .appended = {} }; |
| 964 | }, | 1038 | }, |
| 965 | .Bool => { | 1039 | .Bool => { |
| 966 | try writer.writeByte(@boolToInt(val.toBool())); | 1040 | try writer.writeByte(@boolToInt(val.toBool())); |
| 967 | return Result.appended; | 1041 | return Result{ .appended = {} }; |
| 968 | }, | 1042 | }, |
| 969 | .Struct => { | 1043 | .Struct => { |
| 970 | const field_vals = val.castTag(.@"struct").?.data; | 1044 | const field_vals = val.castTag(.@"struct").?.data; |
| ... | @@ -976,21 +1050,21 @@ pub const DeclGen = struct { | ... | @@ -976,21 +1050,21 @@ pub const DeclGen = struct { |
| 976 | .externally_managed => |payload| try writer.writeAll(payload), | 1050 | .externally_managed => |payload| try writer.writeAll(payload), |
| 977 | } | 1051 | } |
| 978 | } | 1052 | } |
| 979 | return Result.appended; | 1053 | return Result{ .appended = {} }; |
| 980 | }, | 1054 | }, |
| 981 | .Union => { | 1055 | .Union => { |
| 982 | // TODO: Implement Union declarations | 1056 | // TODO: Implement Union declarations |
| 983 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); | 1057 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); |
| 984 | return Result.appended; | 1058 | return Result{ .appended = {} }; |
| 985 | }, | 1059 | }, |
| 986 | .Pointer => switch (val.tag()) { | 1060 | .Pointer => switch (val.tag()) { |
| 987 | .variable => { | 1061 | .variable => { |
| 988 | const decl = val.castTag(.variable).?.data.owner_decl; | 1062 | const decl = val.castTag(.variable).?.data.owner_decl; |
| 989 | return try self.lowerDeclRef(ty, val, decl, writer); | 1063 | return self.lowerDeclRef(ty, val, decl, writer); |
| 990 | }, | 1064 | }, |
| 991 | .decl_ref => { | 1065 | .decl_ref => { |
| 992 | const decl = val.castTag(.decl_ref).?.data; | 1066 | const decl = val.castTag(.decl_ref).?.data; |
| 993 | return try self.lowerDeclRef(ty, val, decl, writer); | 1067 | return self.lowerDeclRef(ty, val, decl, writer); |
| 994 | }, | 1068 | }, |
| 995 | .slice => { | 1069 | .slice => { |
| 996 | const slice = val.castTag(.slice).?.data; | 1070 | const slice = val.castTag(.slice).?.data; |
| ... | @@ -1004,7 +1078,7 @@ pub const DeclGen = struct { | ... | @@ -1004,7 +1078,7 @@ pub const DeclGen = struct { |
| 1004 | .externally_managed => |data| try writer.writeAll(data), | 1078 | .externally_managed => |data| try writer.writeAll(data), |
| 1005 | .appended => {}, | 1079 | .appended => {}, |
| 1006 | } | 1080 | } |
| 1007 | return Result.appended; | 1081 | return Result{ .appended = {} }; |
| 1008 | }, | 1082 | }, |
| 1009 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), | 1083 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 1010 | }, | 1084 | }, |
| ... | @@ -1027,7 +1101,7 @@ pub const DeclGen = struct { | ... | @@ -1027,7 +1101,7 @@ pub const DeclGen = struct { |
| 1027 | } | 1101 | } |
| 1028 | } | 1102 | } |
| 1029 | | 1103 | |
| 1030 | return Result.appended; | 1104 | return Result{ .appended = {} }; |
| 1031 | }, | 1105 | }, |
| 1032 | .ErrorSet => { | 1106 | .ErrorSet => { |
| 1033 | switch (val.tag()) { | 1107 | switch (val.tag()) { |
| ... | @@ -1040,7 +1114,7 @@ pub const DeclGen = struct { | ... | @@ -1040,7 +1114,7 @@ pub const DeclGen = struct { |
| 1040 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); | 1114 | try writer.writeByteNTimes(0, @intCast(usize, ty.abiSize(self.target()))); |
| 1041 | }, | 1115 | }, |
| 1042 | } | 1116 | } |
| 1043 | return Result.appended; | 1117 | return Result{ .appended = {} }; |
| 1044 | }, | 1118 | }, |
| 1045 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), | 1119 | else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}), |
| 1046 | } | 1120 | } |
| ... | @@ -1058,7 +1132,7 @@ pub const DeclGen = struct { | ... | @@ -1058,7 +1132,7 @@ pub const DeclGen = struct { |
| 1058 | .base = .{ .tag = .int_u64 }, | 1132 | .base = .{ .tag = .int_u64 }, |
| 1059 | .data = val.sliceLen(), | 1133 | .data = val.sliceLen(), |
| 1060 | }; | 1134 | }; |
| 1061 | return try self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer); | 1135 | return self.genTypedValue(Type.usize, Value.initPayload(&slice_len.base), writer); |
| 1062 | } | 1136 | } |
| 1063 | | 1137 | |
| 1064 | decl.markAlive(); | 1138 | decl.markAlive(); |
| ... | @@ -1069,7 +1143,7 @@ pub const DeclGen = struct { | ... | @@ -1069,7 +1143,7 @@ pub const DeclGen = struct { |
| 1069 | decl.link.wasm.sym_index, // target symbol index | 1143 | decl.link.wasm.sym_index, // target symbol index |
| 1070 | @intCast(u32, self.code.items.len), // offset | 1144 | @intCast(u32, self.code.items.len), // offset |
| 1071 | )); | 1145 | )); |
| 1072 | return Result.appended; | 1146 | return Result{ .appended = {} }; |
| 1073 | } | 1147 | } |
| 1074 | }; | 1148 | }; |
| 1075 | | 1149 | |
| ... | @@ -1172,16 +1246,10 @@ fn allocStack(self: *Self, ty: Type) !WValue { | ... | @@ -1172,16 +1246,10 @@ fn allocStack(self: *Self, ty: Type) !WValue { |
| 1172 | assert(ty.hasCodeGenBits()); | 1246 | assert(ty.hasCodeGenBits()); |
| 1173 | | 1247 | |
| 1174 | // calculate needed stack space | 1248 | // calculate needed stack space |
| 1175 | var abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch { | 1249 | const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch { |
| 1176 | return self.fail("Given type '{}' too big to fit into stack frame", .{ty}); | 1250 | return self.fail("Given type '{}' too big to fit into stack frame", .{ty}); |
| 1177 | }; | 1251 | }; |
| 1178 | | 1252 | |
| 1179 | // We store slices as a struct with a pointer field and a length field | | |
| 1180 | // both being 'usize' size. | | |
| 1181 | if (ty.isSlice()) { | | |
| 1182 | abi_size = self.ptrSize() * 2; | | |
| 1183 | } | | |
| 1184 | | | |
| 1185 | // allocate a local using wasm's pointer size | 1253 | // allocate a local using wasm's pointer size |
| 1186 | const local = try self.allocLocal(Type.@"usize"); | 1254 | const local = try self.allocLocal(Type.@"usize"); |
| 1187 | try self.moveStack(abi_size, local.local); | 1255 | try self.moveStack(abi_size, local.local); |
| ... | @@ -1624,7 +1692,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1624,7 +1692,6 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1624 | var buf: Type.Payload.ElemType = undefined; | 1692 | var buf: Type.Payload.ElemType = undefined; |
| 1625 | const pl_ty = ty.optionalChild(&buf); | 1693 | const pl_ty = ty.optionalChild(&buf); |
| 1626 | if (!pl_ty.hasCodeGenBits()) { | 1694 | if (!pl_ty.hasCodeGenBits()) { |
| 1627 | // const null_val = try self.load(rhs, Type.initTag(.u8), 0); | | |
| 1628 | return self.store(lhs, rhs, Type.initTag(.u8), 0); | 1695 | return self.store(lhs, rhs, Type.initTag(.u8), 0); |
| 1629 | } | 1696 | } |
| 1630 | | 1697 | |
| ... | @@ -1833,61 +1900,22 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { | ... | @@ -1833,61 +1900,22 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1833 | .signed => switch (int_info.bits) { | 1900 | .signed => switch (int_info.bits) { |
| 1834 | 0...32 => return WValue{ .imm32 = @bitCast(u32, @intCast(i32, val.toSignedInt())) }, | 1901 | 0...32 => return WValue{ .imm32 = @bitCast(u32, @intCast(i32, val.toSignedInt())) }, |
| 1835 | 33...64 => return WValue{ .imm64 = @bitCast(u64, val.toSignedInt()) }, | 1902 | 33...64 => return WValue{ .imm64 = @bitCast(u64, val.toSignedInt()) }, |
| 1836 | 65...128 => {}, | 1903 | else => unreachable, |
| 1837 | else => |bits| return self.fail("Wasm todo: lowerConstant for integer with {d} bits", .{bits}), | | |
| 1838 | }, | 1904 | }, |
| 1839 | .unsigned => switch (int_info.bits) { | 1905 | .unsigned => switch (int_info.bits) { |
| 1840 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, | 1906 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1841 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt() }, | 1907 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt() }, |
| 1842 | 65...128 => {}, | 1908 | else => unreachable, |
| 1843 | else => |bits| return self.fail("Wasm TODO: lowerConstant for integer with {d} bits", .{bits}), | | |
| 1844 | }, | 1909 | }, |
| 1845 | } | 1910 | } |
| 1846 | const result = try self.allocStack(ty); | | |
| 1847 | var space: Value.BigIntSpace = undefined; | | |
| 1848 | const bigint = val.toBigInt(&space); | | |
| 1849 | if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) { | | |
| 1850 | return result; | | |
| 1851 | } | | |
| 1852 | if (@sizeOf(usize) != @sizeOf(u64)) { | | |
| 1853 | return self.fail("Wasm todo: Implement big integers for 32bit compiler", .{}); | | |
| 1854 | } | | |
| 1855 | | | |
| 1856 | for (bigint.limbs) |_, index| { | | |
| 1857 | const limb = bigint.limbs[bigint.limbs.len - index - 1]; | | |
| 1858 | try self.addLabel(.local_get, result.local); | | |
| 1859 | try self.addImm64(limb); | | |
| 1860 | try self.addMemArg(.i64_store, .{ .offset = @intCast(u32, index * 8), .alignment = 8 }); | | |
| 1861 | } | | |
| 1862 | return result; | | |
| 1863 | }, | 1911 | }, |
| 1864 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, | 1912 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 1865 | .Float => switch (ty.floatBits(self.target)) { | 1913 | .Float => switch (ty.floatBits(self.target)) { |
| 1866 | 0...32 => return WValue{ .float32 = val.toFloat(f32) }, | 1914 | 0...32 => return WValue{ .float32 = val.toFloat(f32) }, |
| 1867 | 33...64 => return WValue{ .float64 = val.toFloat(f64) }, | 1915 | 33...64 => return WValue{ .float64 = val.toFloat(f64) }, |
| 1868 | else => |bits| return self.fail("Wasm TODO: lowerConstant for floats with {d} bits", .{bits}), | 1916 | else => unreachable, |
| 1869 | }, | 1917 | }, |
| 1870 | .Pointer => switch (val.tag()) { | 1918 | .Pointer => switch (val.tag()) { |
| 1871 | .slice => { | | |
| 1872 | const result = try self.allocStack(ty); | | |
| 1873 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | | |
| 1874 | const ptr = try self.lowerConstant(val.slicePtr(), ty.slicePtrFieldType(&buf)); | | |
| 1875 | const len = val.sliceLen(); | | |
| 1876 | try self.store(result, ptr, Type.usize, 0); | | |
| 1877 | try self.addLabel(.local_get, result.local); | | |
| 1878 | switch (self.arch()) { | | |
| 1879 | .wasm32 => { | | |
| 1880 | try self.addImm32(@bitCast(i32, @intCast(u32, len))); | | |
| 1881 | try self.addMemArg(.i32_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() }); | | |
| 1882 | }, | | |
| 1883 | .wasm64 => { | | |
| 1884 | try self.addImm64(len); | | |
| 1885 | try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() }); | | |
| 1886 | }, | | |
| 1887 | else => unreachable, | | |
| 1888 | } | | |
| 1889 | return result; | | |
| 1890 | }, | | |
| 1891 | .decl_ref => { | 1919 | .decl_ref => { |
| 1892 | const decl = val.castTag(.decl_ref).?.data; | 1920 | const decl = val.castTag(.decl_ref).?.data; |
| 1893 | decl.markAlive(); | 1921 | decl.markAlive(); |
| ... | @@ -1941,120 +1969,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { | ... | @@ -1941,120 +1969,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1941 | }, | 1969 | }, |
| 1942 | .ErrorUnion => { | 1970 | .ErrorUnion => { |
| 1943 | const error_type = ty.errorUnionSet(); | 1971 | const error_type = ty.errorUnionSet(); |
| 1944 | const payload_type = ty.errorUnionPayload(); | | |
| 1945 | const is_pl = val.errorUnionIsPayload(); | 1972 | const is_pl = val.errorUnionIsPayload(); |
| 1946 | const err_val = if (!is_pl) val else Value.initTag(.zero); | 1973 | const err_val = if (!is_pl) val else Value.initTag(.zero); |
| 1947 | const error_value = try self.lowerConstant(err_val, error_type); | 1974 | return self.lowerConstant(err_val, error_type); |
| 1948 | if (!payload_type.hasCodeGenBits()) { | | |
| 1949 | return error_value; | | |
| 1950 | } | | |
| 1951 | | | |
| 1952 | const result = try self.allocStack(ty); | | |
| 1953 | try self.store(result, error_value, error_type, 0); | | |
| 1954 | const payload = try self.lowerConstant( | | |
| 1955 | if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | | |
| 1956 | payload_type, | | |
| 1957 | ); | | |
| 1958 | const pl_ptr = if (isByRef(payload_type, self.target)) | | |
| 1959 | try self.buildPointerOffset(result, error_type.abiSize(self.target), .new) | | |
| 1960 | else | | |
| 1961 | result; | | |
| 1962 | try self.store(pl_ptr, payload, payload_type, @intCast(u32, error_type.abiSize(self.target))); | | |
| 1963 | return result; | | |
| 1964 | }, | 1975 | }, |
| 1965 | .Optional => if (ty.isPtrLikeOptional()) { | 1976 | .Optional => if (ty.isPtrLikeOptional()) { |
| 1966 | var buf: Type.Payload.ElemType = undefined; | 1977 | var buf: Type.Payload.ElemType = undefined; |
| 1967 | return self.lowerConstant(val, ty.optionalChild(&buf)); | 1978 | return self.lowerConstant(val, ty.optionalChild(&buf)); |
| 1968 | } else { | 1979 | } else { |
| 1969 | var buf: Type.Payload.ElemType = undefined; | | |
| 1970 | const payload_type = ty.optionalChild(&buf); | | |
| 1971 | const is_pl = val.tag() == .opt_payload; | 1980 | const is_pl = val.tag() == .opt_payload; |
| 1972 | const null_value = WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 }; | 1981 | return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 }; |
| 1973 | if (!payload_type.hasCodeGenBits()) { | | |
| 1974 | return null_value; | | |
| 1975 | } | | |
| 1976 | | | |
| 1977 | const result = try self.allocStack(ty); | | |
| 1978 | try self.store(result, null_value, Type.initTag(.u8), 0); | | |
| 1979 | const payload = try self.lowerConstant( | | |
| 1980 | if (val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | | |
| 1981 | payload_type, | | |
| 1982 | ); | | |
| 1983 | | | |
| 1984 | const offset = @intCast(u32, ty.abiSize(self.target) - payload_type.abiSize(self.target)); | | |
| 1985 | const pl_ptr = if (self.isByRef(payload_type)) blk: { | | |
| 1986 | break :blk try self.buildPointerOffset(result, offset, .new); | | |
| 1987 | } else result; | | |
| 1988 | try self.store(pl_ptr, payload, payload_type, offset); | | |
| 1989 | return result; | | |
| 1990 | }, | | |
| 1991 | .Struct => { | | |
| 1992 | const struct_data = val.castTag(.@"struct").?; | | |
| 1993 | // in case of structs, we reserve stack space and store it there. | | |
| 1994 | const result = try self.allocStack(ty); | | |
| 1995 | | | |
| 1996 | const fields = ty.structFields(); | | |
| 1997 | const offset = try self.copyLocal(result, ty); | | |
| 1998 | for (fields.values()) |field, index| { | | |
| 1999 | const field_value = try self.lowerConstant(struct_data.data[index], field.ty); | | |
| 2000 | try self.store(offset, field_value, field.ty, 0); | | |
| 2001 | | | |
| 2002 | // this prevents us from emitting useless instructions when we reached the end of the loop | | |
| 2003 | if (index != (fields.count() - 1)) { | | |
| 2004 | _ = try self.buildPointerOffset(offset, field.ty.abiSize(self.target), .modify); | | |
| 2005 | } | | |
| 2006 | } | | |
| 2007 | return result; | | |
| 2008 | }, | | |
| 2009 | .Array => { | | |
| 2010 | const result = try self.allocStack(ty); | | |
| 2011 | if (val.castTag(.bytes)) |bytes| { | | |
| 2012 | for (bytes.data) |byte, index| { | | |
| 2013 | try self.addLabel(.local_get, result.local); | | |
| 2014 | try self.addImm32(@intCast(i32, byte)); | | |
| 2015 | try self.addMemArg(.i32_store8, .{ .offset = @intCast(u32, index), .alignment = 1 }); | | |
| 2016 | } | | |
| 2017 | } else if (val.castTag(.array)) |array| { | | |
| 2018 | const elem_ty = ty.childType(); | | |
| 2019 | const elem_size = elem_ty.abiSize(self.target); | | |
| 2020 | const offset = try self.copyLocal(result, ty); | | |
| 2021 | for (array.data) |value, index| { | | |
| 2022 | const elem_val = try self.lowerConstant(value, elem_ty); | | |
| 2023 | try self.store(offset, elem_val, elem_ty, 0); | | |
| 2024 | | | |
| 2025 | if (index != (array.data.len - 1)) { | | |
| 2026 | _ = try self.buildPointerOffset(offset, elem_size, .modify); | | |
| 2027 | } | | |
| 2028 | } | | |
| 2029 | } else if (val.castTag(.repeated)) |repeated| { | | |
| 2030 | const value = repeated.data; | | |
| 2031 | const elem_ty = ty.childType(); | | |
| 2032 | const elem_size = elem_ty.abiSize(self.target); | | |
| 2033 | const sentinel = ty.sentinel(); | | |
| 2034 | const len = ty.arrayLen(); | | |
| 2035 | const len_with_sent = len + @boolToInt(sentinel != null); | | |
| 2036 | const offset = try self.copyLocal(result, ty); | | |
| 2037 | | | |
| 2038 | var index: u32 = 0; | | |
| 2039 | while (index < len_with_sent) : (index += 1) { | | |
| 2040 | const elem_val = if (sentinel != null and index == len) | | |
| 2041 | try self.lowerConstant(sentinel.?, elem_ty) | | |
| 2042 | else | | |
| 2043 | try self.lowerConstant(value, elem_ty); | | |
| 2044 | | | |
| 2045 | try self.store(offset, elem_val, elem_ty, 0); | | |
| 2046 | | | |
| 2047 | if (index != (len_with_sent - 1)) { | | |
| 2048 | _ = try self.buildPointerOffset(offset, elem_size, .modify); | | |
| 2049 | } | | |
| 2050 | } | | |
| 2051 | } else if (val.tag() == .empty_array_sentinel) { | | |
| 2052 | const elem_ty = ty.childType(); | | |
| 2053 | const sent_val = ty.sentinel().?; | | |
| 2054 | const sentinel = try self.lowerConstant(sent_val, elem_ty); | | |
| 2055 | try self.store(result, sentinel, elem_ty, 0); | | |
| 2056 | } else unreachable; | | |
| 2057 | return result; | | |
| 2058 | }, | 1982 | }, |
| 2059 | else => |zig_type| return self.fail("Wasm TODO: LowerConstant for zigTypeTag {s}", .{zig_type}), | 1983 | else => |zig_type| return self.fail("Wasm TODO: LowerConstant for zigTypeTag {s}", .{zig_type}), |
| 2060 | } | 1984 | } |
| ... | @@ -2066,27 +1990,12 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { | ... | @@ -2066,27 +1990,12 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { |
| 2066 | .Int => switch (ty.intInfo(self.target).bits) { | 1990 | .Int => switch (ty.intInfo(self.target).bits) { |
| 2067 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, | 1991 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 2068 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, | 1992 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, |
| 2069 | else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}), | 1993 | else => unreachable, |
| 2070 | }, | 1994 | }, |
| 2071 | .Float => switch (ty.floatBits(self.target)) { | 1995 | .Float => switch (ty.floatBits(self.target)) { |
| 2072 | 0...32 => return WValue{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) }, | 1996 | 0...32 => return WValue{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) }, |
| 2073 | 33...64 => return WValue{ .float64 = @bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa)) }, | 1997 | 33...64 => return WValue{ .float64 = @bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa)) }, |
| 2074 | else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}), | 1998 | else => unreachable, |
| 2075 | }, | | |
| 2076 | .Array, .Struct => { | | |
| 2077 | const result = try self.allocStack(ty); | | |
| 2078 | const abi_size = ty.abiSize(self.target); | | |
| 2079 | var offset: u32 = 0; | | |
| 2080 | while (offset < abi_size) : (offset += 1) { | | |
| 2081 | try self.emitWValue(result); | | |
| 2082 | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); | | |
| 2083 | switch (self.arch()) { | | |
| 2084 | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2085 | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2086 | else => unreachable, | | |
| 2087 | } | | |
| 2088 | } | | |
| 2089 | return result; | | |
| 2090 | }, | 1999 | }, |
| 2091 | .Pointer => switch (self.arch()) { | 2000 | .Pointer => switch (self.arch()) { |
| 2092 | .wasm32 => return WValue{ .imm32 = 0xaaaaaaaa }, | 2001 | .wasm32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| ... | @@ -2099,42 +2008,10 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { | ... | @@ -2099,42 +2008,10 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue { |
| 2099 | if (ty.isPtrLikeOptional()) { | 2008 | if (ty.isPtrLikeOptional()) { |
| 2100 | return self.emitUndefined(pl_ty); | 2009 | return self.emitUndefined(pl_ty); |
| 2101 | } | 2010 | } |
| 2102 | if (!pl_ty.hasCodeGenBits()) { | 2011 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2103 | return self.emitUndefined(Type.initTag(.u8)); | | |
| 2104 | } | | |
| 2105 | const result = try self.allocStack(ty); | | |
| 2106 | const abi_size = ty.abiSize(self.target); | | |
| 2107 | var offset: u32 = 0; | | |
| 2108 | while (offset < abi_size) : (offset += 1) { | | |
| 2109 | try self.emitWValue(result); | | |
| 2110 | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); | | |
| 2111 | switch (self.arch()) { | | |
| 2112 | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2113 | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2114 | else => unreachable, | | |
| 2115 | } | | |
| 2116 | } | | |
| 2117 | return result; | | |
| 2118 | }, | 2012 | }, |
| 2119 | .ErrorUnion => { | 2013 | .ErrorUnion => { |
| 2120 | // const error_set = ty.errorUnionSet(); | 2014 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2121 | const pl_ty = ty.errorUnionPayload(); | | |
| 2122 | if (!pl_ty.hasCodeGenBits()) { | | |
| 2123 | return WValue{ .imm32 = 0xaaaaaaaa }; | | |
| 2124 | } | | |
| 2125 | const result = try self.allocStack(ty); | | |
| 2126 | const abi_size = ty.abiSize(self.target); | | |
| 2127 | var offset: u32 = 0; | | |
| 2128 | while (offset < abi_size) : (offset += 1) { | | |
| 2129 | try self.emitWValue(result); | | |
| 2130 | try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))); | | |
| 2131 | switch (self.arch()) { | | |
| 2132 | .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2133 | .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }), | | |
| 2134 | else => unreachable, | | |
| 2135 | } | | |
| 2136 | } | | |
| 2137 | return result; | | |
| 2138 | }, | 2015 | }, |
| 2139 | else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}), | 2016 | else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}), |
| 2140 | } | 2017 | } |