authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-11 19:17:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
loge21a42723b9acefd27c142bf776a8321621296b8
tree23305aa2b8f5f0593e631d0976ea83ba0fff9a63
parentc96e23632f04c7bffc2257139a19cad82fbe7223

wasm linker: implement name, module name, and type for function imports


4 files changed, 267 insertions(+), 145 deletions(-)

src/arch/wasm/CodeGen.zig+73-134
...@@ -760,7 +760,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {...@@ -760,7 +760,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
760 //760 //
761 // In the other cases, we will simply lower the constant to a value that fits761 // In the other cases, we will simply lower the constant to a value that fits
762 // into a single local (such as a pointer, integer, bool, etc).762 // into a single local (such as a pointer, integer, bool, etc).
763 const result: WValue = if (isByRef(ty, pt, cg.target))763 const result: WValue = if (isByRef(ty, zcu, cg.target))
764 .{ .uav_ref = .{ .ip_index = val.toIntern() } }764 .{ .uav_ref = .{ .ip_index = val.toIntern() } }
765 else765 else
766 try cg.lowerConstant(val, ty);766 try cg.lowerConstant(val, ty);
...@@ -953,9 +953,8 @@ fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {...@@ -953,9 +953,8 @@ fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
953 return result;953 return result;
954}954}
955955
956/// Using a given `Type`, returns the corresponding valtype for .auto callconv956/// For `std.builtin.CallingConvention.auto`.
957fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.wasm.Valtype {957pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.Valtype {
958 const zcu = pt.zcu;
959 const ip = &zcu.intern_pool;958 const ip = &zcu.intern_pool;
960 return switch (ty.zigTypeTag(zcu)) {959 return switch (ty.zigTypeTag(zcu)) {
961 .float => switch (ty.floatBits(target.*)) {960 .float => switch (ty.floatBits(target.*)) {
...@@ -973,19 +972,20 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was...@@ -973,19 +972,20 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was
973 .@"struct" => blk: {972 .@"struct" => blk: {
974 if (zcu.typeToPackedStruct(ty)) |packed_struct| {973 if (zcu.typeToPackedStruct(ty)) |packed_struct| {
975 const backing_int_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));974 const backing_int_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
976 break :blk typeToValtype(backing_int_ty, pt, target);975 break :blk typeToValtype(backing_int_ty, zcu, target);
977 } else {976 } else {
978 break :blk .i32;977 break :blk .i32;
979 }978 }
980 },979 },
981 .vector => switch (determineSimdStoreStrategy(ty, zcu, target)) {980 .vector => switch (CodeGen.determineSimdStoreStrategy(ty, zcu, target)) {
982 .direct => .v128,981 .direct => .v128,
983 .unrolled => .i32,982 .unrolled => .i32,
984 },983 },
985 .@"union" => switch (ty.containerLayout(zcu)) {984 .@"union" => switch (ty.containerLayout(zcu)) {
986 .@"packed" => blk: {985 .@"packed" => switch (ty.bitSize(zcu)) {
987 const int_ty = pt.intType(.unsigned, @as(u16, @intCast(ty.bitSize(zcu)))) catch @panic("out of memory");986 0...32 => .i32,
988 break :blk typeToValtype(int_ty, pt, target);987 33...64 => .i64,
988 else => .i32,
989 },989 },
990 else => .i32,990 else => .i32,
991 },991 },
...@@ -994,17 +994,17 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was...@@ -994,17 +994,17 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was
994}994}
995995
996/// Using a given `Type`, returns the byte representation of its wasm value type996/// Using a given `Type`, returns the byte representation of its wasm value type
997fn genValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 {997fn genValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) u8 {
998 return @intFromEnum(typeToValtype(ty, pt, target));998 return @intFromEnum(typeToValtype(ty, zcu, target));
999}999}
10001000
1001/// Using a given `Type`, returns the corresponding wasm value type1001/// Using a given `Type`, returns the corresponding wasm value type
1002/// Differently from `genValtype` this also allows `void` to create a block1002/// Differently from `genValtype` this also allows `void` to create a block
1003/// with no return type1003/// with no return type
1004fn genBlockType(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 {1004fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) u8 {
1005 return switch (ty.ip_index) {1005 return switch (ty.ip_index) {
1006 .void_type, .noreturn_type => std.wasm.block_empty,1006 .void_type, .noreturn_type => std.wasm.block_empty,
1007 else => genValtype(ty, pt, target),1007 else => genValtype(ty, zcu, target),
1008 };1008 };
1009}1009}
10101010
...@@ -1086,8 +1086,8 @@ fn getResolvedInst(cg: *CodeGen, ref: Air.Inst.Ref) *WValue {...@@ -1086,8 +1086,8 @@ fn getResolvedInst(cg: *CodeGen, ref: Air.Inst.Ref) *WValue {
1086/// Creates one locals for a given `Type`.1086/// Creates one locals for a given `Type`.
1087/// Returns a corresponding `Wvalue` with `local` as active tag1087/// Returns a corresponding `Wvalue` with `local` as active tag
1088fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {1088fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1089 const pt = cg.pt;1089 const zcu = cg.pt.zcu;
1090 const valtype = typeToValtype(ty, pt, cg.target);1090 const valtype = typeToValtype(ty, zcu, cg.target);
1091 const index_or_null = switch (valtype) {1091 const index_or_null = switch (valtype) {
1092 .i32 => cg.free_locals_i32.popOrNull(),1092 .i32 => cg.free_locals_i32.popOrNull(),
1093 .i64 => cg.free_locals_i64.popOrNull(),1093 .i64 => cg.free_locals_i64.popOrNull(),
...@@ -1106,74 +1106,13 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {...@@ -1106,74 +1106,13 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1106/// Ensures a new local will be created. This is useful when it's useful1106/// Ensures a new local will be created. This is useful when it's useful
1107/// to use a zero-initialized local.1107/// to use a zero-initialized local.
1108fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {1108fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
1109 const pt = cg.pt;1109 const zcu = cg.pt.zcu;
1110 try cg.locals.append(cg.gpa, genValtype(ty, pt, cg.target));1110 try cg.locals.append(cg.gpa, genValtype(ty, zcu, cg.target));
1111 const initial_index = cg.local_index;1111 const initial_index = cg.local_index;
1112 cg.local_index += 1;1112 cg.local_index += 1;
1113 return .{ .local = .{ .value = initial_index, .references = 1 } };1113 return .{ .local = .{ .value = initial_index, .references = 1 } };
1114}1114}
11151115
1116fn genFunctype(
1117 wasm: *link.File.Wasm,
1118 cc: std.builtin.CallingConvention,
1119 params: []const InternPool.Index,
1120 return_type: Type,
1121 pt: Zcu.PerThread,
1122 target: *const std.Target,
1123) !link.File.Wasm.FunctionType.Index {
1124 const zcu = pt.zcu;
1125 const gpa = zcu.gpa;
1126 var temp_params: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty;
1127 defer temp_params.deinit(gpa);
1128 var returns: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty;
1129 defer returns.deinit(gpa);
1130
1131 if (firstParamSRet(cc, return_type, pt, target)) {
1132 try temp_params.append(gpa, .i32); // memory address is always a 32-bit handle
1133 } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
1134 if (cc == .wasm_watc) {
1135 const res_classes = abi.classifyType(return_type, zcu);
1136 assert(res_classes[0] == .direct and res_classes[1] == .none);
1137 const scalar_type = abi.scalarType(return_type, zcu);
1138 try returns.append(gpa, typeToValtype(scalar_type, pt, target));
1139 } else {
1140 try returns.append(gpa, typeToValtype(return_type, pt, target));
1141 }
1142 } else if (return_type.isError(zcu)) {
1143 try returns.append(gpa, .i32);
1144 }
1145
1146 // param types
1147 for (params) |param_type_ip| {
1148 const param_type = Type.fromInterned(param_type_ip);
1149 if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1150
1151 switch (cc) {
1152 .wasm_watc => {
1153 const param_classes = abi.classifyType(param_type, zcu);
1154 if (param_classes[1] == .none) {
1155 if (param_classes[0] == .direct) {
1156 const scalar_type = abi.scalarType(param_type, zcu);
1157 try temp_params.append(gpa, typeToValtype(scalar_type, pt, target));
1158 } else {
1159 try temp_params.append(gpa, typeToValtype(param_type, pt, target));
1160 }
1161 } else {
1162 // i128/f128
1163 try temp_params.append(gpa, .i64);
1164 try temp_params.append(gpa, .i64);
1165 }
1166 },
1167 else => try temp_params.append(gpa, typeToValtype(param_type, pt, target)),
1168 }
1169 }
1170
1171 return wasm.addFuncType(.{
1172 .params = try wasm.internValtypeList(temp_params.items),
1173 .returns = try wasm.internValtypeList(returns.items),
1174 });
1175}
1176
1177pub const Function = extern struct {1116pub const Function = extern struct {
1178 /// Index into `Wasm.mir_instructions`.1117 /// Index into `Wasm.mir_instructions`.
1179 mir_off: u32,1118 mir_off: u32,
...@@ -1291,7 +1230,7 @@ pub fn function(...@@ -1291,7 +1230,7 @@ pub fn function(
1291 const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu);1230 const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu);
1292 const fn_info = zcu.typeToFunc(fn_ty).?;1231 const fn_info = zcu.typeToFunc(fn_ty).?;
1293 const ip = &zcu.intern_pool;1232 const ip = &zcu.intern_pool;
1294 const fn_ty_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, target);1233 const fn_ty_index = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target);
1295 const returns = fn_ty_index.ptr(wasm).returns.slice(wasm);1234 const returns = fn_ty_index.ptr(wasm).returns.slice(wasm);
1296 const any_returns = returns.len != 0;1235 const any_returns = returns.len != 0;
12971236
...@@ -1409,7 +1348,7 @@ fn resolveCallingConventionValues(...@@ -1409,7 +1348,7 @@ fn resolveCallingConventionValues(
14091348
1410 // Check if we store the result as a pointer to the stack rather than1349 // Check if we store the result as a pointer to the stack rather than
1411 // by value1350 // by value
1412 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, target)) {1351 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, target)) {
1413 // the sret arg will be passed as first argument, therefore we1352 // the sret arg will be passed as first argument, therefore we
1414 // set the `return_value` before allocating locals for regular args.1353 // set the `return_value` before allocating locals for regular args.
1415 result.return_value = .{ .local = .{ .value = result.local_index, .references = 1 } };1354 result.return_value = .{ .local = .{ .value = result.local_index, .references = 1 } };
...@@ -1443,17 +1382,17 @@ fn resolveCallingConventionValues(...@@ -1443,17 +1382,17 @@ fn resolveCallingConventionValues(
1443 return result;1382 return result;
1444}1383}
14451384
1446fn firstParamSRet(1385pub fn firstParamSRet(
1447 cc: std.builtin.CallingConvention,1386 cc: std.builtin.CallingConvention,
1448 return_type: Type,1387 return_type: Type,
1449 pt: Zcu.PerThread,1388 zcu: *const Zcu,
1450 target: *const std.Target,1389 target: *const std.Target,
1451) bool {1390) bool {
1452 switch (cc) {1391 switch (cc) {
1453 .@"inline" => unreachable,1392 .@"inline" => unreachable,
1454 .auto => return isByRef(return_type, pt, target),1393 .auto => return isByRef(return_type, zcu, target),
1455 .wasm_watc => {1394 .wasm_watc => {
1456 const ty_classes = abi.classifyType(return_type, pt.zcu);1395 const ty_classes = abi.classifyType(return_type, zcu);
1457 if (ty_classes[0] == .indirect) return true;1396 if (ty_classes[0] == .indirect) return true;
1458 if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true;1397 if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true;
1459 return false;1398 return false;
...@@ -1744,8 +1683,7 @@ fn ptrSize(cg: *const CodeGen) u16 {...@@ -1744,8 +1683,7 @@ fn ptrSize(cg: *const CodeGen) u16 {
17441683
1745/// For a given `Type`, will return true when the type will be passed1684/// For a given `Type`, will return true when the type will be passed
1746/// by reference, rather than by value1685/// by reference, rather than by value
1747fn isByRef(ty: Type, pt: Zcu.PerThread, target: *const std.Target) bool {1686fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool {
1748 const zcu = pt.zcu;
1749 const ip = &zcu.intern_pool;1687 const ip = &zcu.intern_pool;
1750 switch (ty.zigTypeTag(zcu)) {1688 switch (ty.zigTypeTag(zcu)) {
1751 .type,1689 .type,
...@@ -1778,7 +1716,7 @@ fn isByRef(ty: Type, pt: Zcu.PerThread, target: *const std.Target) bool {...@@ -1778,7 +1716,7 @@ fn isByRef(ty: Type, pt: Zcu.PerThread, target: *const std.Target) bool {
1778 },1716 },
1779 .@"struct" => {1717 .@"struct" => {
1780 if (zcu.typeToPackedStruct(ty)) |packed_struct| {1718 if (zcu.typeToPackedStruct(ty)) |packed_struct| {
1781 return isByRef(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)), pt, target);1719 return isByRef(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)), zcu, target);
1782 }1720 }
1783 return ty.hasRuntimeBitsIgnoreComptime(zcu);1721 return ty.hasRuntimeBitsIgnoreComptime(zcu);
1784 },1722 },
...@@ -1816,7 +1754,7 @@ const SimdStoreStrategy = enum {...@@ -1816,7 +1754,7 @@ const SimdStoreStrategy = enum {
1816/// This means when a given type is 128 bits and either the simd128 or relaxed-simd1754/// This means when a given type is 128 bits and either the simd128 or relaxed-simd
1817/// features are enabled, the function will return `.direct`. This would allow to store1755/// features are enabled, the function will return `.direct`. This would allow to store
1818/// it using a instruction, rather than an unrolled version.1756/// it using a instruction, rather than an unrolled version.
1819fn determineSimdStoreStrategy(ty: Type, zcu: *Zcu, target: *const std.Target) SimdStoreStrategy {1757pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy {
1820 assert(ty.zigTypeTag(zcu) == .vector);1758 assert(ty.zigTypeTag(zcu) == .vector);
1821 if (ty.bitSize(zcu) != 128) return .unrolled;1759 if (ty.bitSize(zcu) != 128) return .unrolled;
1822 const hasFeature = std.Target.wasm.featureSetHas;1760 const hasFeature = std.Target.wasm.featureSetHas;
...@@ -2144,7 +2082,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2144,7 +2082,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2144 .op = .load,2082 .op = .load,
2145 .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)),2083 .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)),
2146 .signedness = if (scalar_type.isSignedInt(zcu)) .signed else .unsigned,2084 .signedness = if (scalar_type.isSignedInt(zcu)) .signed else .unsigned,
2147 .valtype1 = typeToValtype(scalar_type, pt, cg.target),2085 .valtype1 = typeToValtype(scalar_type, zcu, cg.target),
2148 });2086 });
2149 try cg.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{2087 try cg.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
2150 .offset = operand.offset(),2088 .offset = operand.offset(),
...@@ -2177,7 +2115,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2177,7 +2115,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2177 }2115 }
21782116
2179 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;2117 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
2180 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target)) {2118 if (firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target)) {
2181 break :result cg.return_value;2119 break :result cg.return_value;
2182 }2120 }
21832121
...@@ -2199,7 +2137,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2199,7 +2137,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2199 if (ret_ty.isError(zcu)) {2137 if (ret_ty.isError(zcu)) {
2200 try cg.addImm32(0);2138 try cg.addImm32(0);
2201 }2139 }
2202 } else if (!firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target)) {2140 } else if (!firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target)) {
2203 // leave on the stack2141 // leave on the stack
2204 _ = try cg.load(operand, ret_ty, 0);2142 _ = try cg.load(operand, ret_ty, 0);
2205 }2143 }
...@@ -2227,7 +2165,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2227,7 +2165,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2227 };2165 };
2228 const ret_ty = fn_ty.fnReturnType(zcu);2166 const ret_ty = fn_ty.fnReturnType(zcu);
2229 const fn_info = zcu.typeToFunc(fn_ty).?;2167 const fn_info = zcu.typeToFunc(fn_ty).?;
2230 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), pt, cg.target);2168 const first_param_sret = firstParamSRet(fn_info.cc, Type.fromInterned(fn_info.return_type), zcu, cg.target);
22312169
2232 const callee: ?InternPool.Nav.Index = blk: {2170 const callee: ?InternPool.Nav.Index = blk: {
2233 const func_val = (try cg.air.value(pl_op.operand, pt)) orelse break :blk null;2171 const func_val = (try cg.air.value(pl_op.operand, pt)) orelse break :blk null;
...@@ -2267,7 +2205,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -2267,7 +2205,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
2267 const operand = try cg.resolveInst(pl_op.operand);2205 const operand = try cg.resolveInst(pl_op.operand);
2268 try cg.emitWValue(operand);2206 try cg.emitWValue(operand);
22692207
2270 const fn_type_index = try genFunctype(wasm, fn_info.cc, fn_info.param_types.get(ip), Type.fromInterned(fn_info.return_type), pt, cg.target);2208 const fn_type_index = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), cg.target);
2271 try cg.addLabel(.call_indirect, @intFromEnum(fn_type_index));2209 try cg.addLabel(.call_indirect, @intFromEnum(fn_type_index));
2272 }2210 }
22732211
...@@ -2328,7 +2266,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {...@@ -2328,7 +2266,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2328 // load the value, and then shift+or the rhs into the result location.2266 // load the value, and then shift+or the rhs into the result location.
2329 const int_elem_ty = try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8);2267 const int_elem_ty = try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8);
23302268
2331 if (isByRef(int_elem_ty, pt, cg.target)) {2269 if (isByRef(int_elem_ty, zcu, cg.target)) {
2332 return cg.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});2270 return cg.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{});
2333 }2271 }
23342272
...@@ -2394,7 +2332,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr...@@ -2394,7 +2332,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr
2394 const len = @as(u32, @intCast(abi_size));2332 const len = @as(u32, @intCast(abi_size));
2395 return cg.memcpy(lhs, rhs, .{ .imm32 = len });2333 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2396 },2334 },
2397 .@"struct", .array, .@"union" => if (isByRef(ty, pt, cg.target)) {2335 .@"struct", .array, .@"union" => if (isByRef(ty, zcu, cg.target)) {
2398 const len = @as(u32, @intCast(abi_size));2336 const len = @as(u32, @intCast(abi_size));
2399 return cg.memcpy(lhs, rhs, .{ .imm32 = len });2337 return cg.memcpy(lhs, rhs, .{ .imm32 = len });
2400 },2338 },
...@@ -2456,7 +2394,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr...@@ -2456,7 +2394,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr
2456 // into lhs, so we calculate that and emit that instead2394 // into lhs, so we calculate that and emit that instead
2457 try cg.lowerToStack(rhs);2395 try cg.lowerToStack(rhs);
24582396
2459 const valtype = typeToValtype(ty, pt, cg.target);2397 const valtype = typeToValtype(ty, zcu, cg.target);
2460 const opcode = buildOpcode(.{2398 const opcode = buildOpcode(.{
2461 .valtype1 = valtype,2399 .valtype1 = valtype,
2462 .width = @as(u8, @intCast(abi_size * 8)),2400 .width = @as(u8, @intCast(abi_size * 8)),
...@@ -2485,7 +2423,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2485,7 +2423,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2485 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand});2423 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand});
24862424
2487 const result = result: {2425 const result = result: {
2488 if (isByRef(ty, pt, cg.target)) {2426 if (isByRef(ty, zcu, cg.target)) {
2489 const new_local = try cg.allocStack(ty);2427 const new_local = try cg.allocStack(ty);
2490 try cg.store(new_local, operand, ty, 0);2428 try cg.store(new_local, operand, ty, 0);
2491 break :result new_local;2429 break :result new_local;
...@@ -2535,7 +2473,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue...@@ -2535,7 +2473,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue
25352473
2536 const abi_size: u8 = @intCast(ty.abiSize(zcu));2474 const abi_size: u8 = @intCast(ty.abiSize(zcu));
2537 const opcode = buildOpcode(.{2475 const opcode = buildOpcode(.{
2538 .valtype1 = typeToValtype(ty, pt, cg.target),2476 .valtype1 = typeToValtype(ty, zcu, cg.target),
2539 .width = abi_size * 8,2477 .width = abi_size * 8,
2540 .op = .load,2478 .op = .load,
2541 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,2479 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
...@@ -2632,7 +2570,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV...@@ -2632,7 +2570,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV
2632 return cg.floatOp(float_op, ty, &.{ lhs, rhs });2570 return cg.floatOp(float_op, ty, &.{ lhs, rhs });
2633 }2571 }
26342572
2635 if (isByRef(ty, pt, cg.target)) {2573 if (isByRef(ty, zcu, cg.target)) {
2636 if (ty.zigTypeTag(zcu) == .int) {2574 if (ty.zigTypeTag(zcu) == .int) {
2637 return cg.binOpBigInt(lhs, rhs, ty, op);2575 return cg.binOpBigInt(lhs, rhs, ty, op);
2638 } else {2576 } else {
...@@ -2645,7 +2583,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV...@@ -2645,7 +2583,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV
26452583
2646 const opcode: std.wasm.Opcode = buildOpcode(.{2584 const opcode: std.wasm.Opcode = buildOpcode(.{
2647 .op = op,2585 .op = op,
2648 .valtype1 = typeToValtype(ty, pt, cg.target),2586 .valtype1 = typeToValtype(ty, zcu, cg.target),
2649 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,2587 .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned,
2650 });2588 });
2651 try cg.emitWValue(lhs);2589 try cg.emitWValue(lhs);
...@@ -2949,7 +2887,7 @@ fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) Inne...@@ -2949,7 +2887,7 @@ fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) Inne
2949 for (args) |operand| {2887 for (args) |operand| {
2950 try cg.emitWValue(operand);2888 try cg.emitWValue(operand);
2951 }2889 }
2952 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, pt, cg.target) });2890 const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, zcu, cg.target) });
2953 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));2891 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2954 return .stack;2892 return .stack;
2955 }2893 }
...@@ -3174,7 +3112,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro...@@ -3174,7 +3112,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
3174fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {3112fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3175 const pt = cg.pt;3113 const pt = cg.pt;
3176 const zcu = pt.zcu;3114 const zcu = pt.zcu;
3177 assert(!isByRef(ty, pt, cg.target));3115 assert(!isByRef(ty, zcu, cg.target));
3178 const ip = &zcu.intern_pool;3116 const ip = &zcu.intern_pool;
3179 if (val.isUndefDeep(zcu)) return cg.emitUndefined(ty);3117 if (val.isUndefDeep(zcu)) return cg.emitUndefined(ty);
31803118
...@@ -3415,11 +3353,12 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3415,11 +3353,12 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
34153353
3416fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {3354fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
3417 const pt = cg.pt;3355 const pt = cg.pt;
3418 const wasm_block_ty = genBlockType(block_ty, pt, cg.target);3356 const zcu = pt.zcu;
3357 const wasm_block_ty = genBlockType(block_ty, zcu, cg.target);
34193358
3420 // if wasm_block_ty is non-empty, we create a register to store the temporary value3359 // if wasm_block_ty is non-empty, we create a register to store the temporary value
3421 const block_result: WValue = if (wasm_block_ty != std.wasm.block_empty) blk: {3360 const block_result: WValue = if (wasm_block_ty != std.wasm.block_empty) blk: {
3422 const ty: Type = if (isByRef(block_ty, pt, cg.target)) Type.u32 else block_ty;3361 const ty: Type = if (isByRef(block_ty, zcu, cg.target)) Type.u32 else block_ty;
3423 break :blk try cg.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten3362 break :blk try cg.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten
3424 } else .none;3363 } else .none;
34253364
...@@ -3544,7 +3483,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe...@@ -3544,7 +3483,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe
3544 }3483 }
3545 } else if (ty.isAnyFloat()) {3484 } else if (ty.isAnyFloat()) {
3546 return cg.cmpFloat(ty, lhs, rhs, op);3485 return cg.cmpFloat(ty, lhs, rhs, op);
3547 } else if (isByRef(ty, pt, cg.target)) {3486 } else if (isByRef(ty, zcu, cg.target)) {
3548 return cg.cmpBigInt(lhs, rhs, ty, op);3487 return cg.cmpBigInt(lhs, rhs, ty, op);
3549 }3488 }
35503489
...@@ -3562,7 +3501,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe...@@ -3562,7 +3501,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe
3562 try cg.lowerToStack(rhs);3501 try cg.lowerToStack(rhs);
35633502
3564 const opcode: std.wasm.Opcode = buildOpcode(.{3503 const opcode: std.wasm.Opcode = buildOpcode(.{
3565 .valtype1 = typeToValtype(ty, pt, cg.target),3504 .valtype1 = typeToValtype(ty, zcu, cg.target),
3566 .op = switch (op) {3505 .op = switch (op) {
3567 .lt => .lt,3506 .lt => .lt,
3568 .lte => .le,3507 .lte => .le,
...@@ -3769,7 +3708,7 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3769,7 +3708,7 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3769 break :result try cg.bitcast(wanted_ty, given_ty, operand);3708 break :result try cg.bitcast(wanted_ty, given_ty, operand);
3770 }3709 }
37713710
3772 if (isByRef(given_ty, pt, cg.target) and !isByRef(wanted_ty, pt, cg.target)) {3711 if (isByRef(given_ty, zcu, cg.target) and !isByRef(wanted_ty, zcu, cg.target)) {
3773 const loaded_memory = try cg.load(operand, wanted_ty, 0);3712 const loaded_memory = try cg.load(operand, wanted_ty, 0);
3774 if (needs_wrapping) {3713 if (needs_wrapping) {
3775 break :result try cg.wrapOperand(loaded_memory, wanted_ty);3714 break :result try cg.wrapOperand(loaded_memory, wanted_ty);
...@@ -3777,7 +3716,7 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3777,7 +3716,7 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3777 break :result loaded_memory;3716 break :result loaded_memory;
3778 }3717 }
3779 }3718 }
3780 if (!isByRef(given_ty, pt, cg.target) and isByRef(wanted_ty, pt, cg.target)) {3719 if (!isByRef(given_ty, zcu, cg.target) and isByRef(wanted_ty, zcu, cg.target)) {
3781 const stack_memory = try cg.allocStack(wanted_ty);3720 const stack_memory = try cg.allocStack(wanted_ty);
3782 try cg.store(stack_memory, operand, given_ty, 0);3721 try cg.store(stack_memory, operand, given_ty, 0);
3783 if (needs_wrapping) {3722 if (needs_wrapping) {
...@@ -3807,8 +3746,8 @@ fn bitcast(cg: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inner...@@ -3807,8 +3746,8 @@ fn bitcast(cg: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inner
38073746
3808 const opcode = buildOpcode(.{3747 const opcode = buildOpcode(.{
3809 .op = .reinterpret,3748 .op = .reinterpret,
3810 .valtype1 = typeToValtype(wanted_ty, pt, cg.target),3749 .valtype1 = typeToValtype(wanted_ty, zcu, cg.target),
3811 .valtype2 = typeToValtype(given_ty, pt, cg.target),3750 .valtype2 = typeToValtype(given_ty, zcu, cg.target),
3812 });3751 });
3813 try cg.emitWValue(operand);3752 try cg.emitWValue(operand);
3814 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));3753 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
...@@ -3930,8 +3869,8 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3930,8 +3869,8 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3930 break :result try cg.trunc(shifted_value, field_ty, backing_ty);3869 break :result try cg.trunc(shifted_value, field_ty, backing_ty);
3931 },3870 },
3932 .@"union" => result: {3871 .@"union" => result: {
3933 if (isByRef(struct_ty, pt, cg.target)) {3872 if (isByRef(struct_ty, zcu, cg.target)) {
3934 if (!isByRef(field_ty, pt, cg.target)) {3873 if (!isByRef(field_ty, zcu, cg.target)) {
3935 break :result try cg.load(operand, field_ty, 0);3874 break :result try cg.load(operand, field_ty, 0);
3936 } else {3875 } else {
3937 const new_stack_val = try cg.allocStack(field_ty);3876 const new_stack_val = try cg.allocStack(field_ty);
...@@ -3957,7 +3896,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3957,7 +3896,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3957 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse {3896 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse {
3958 return cg.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)});3897 return cg.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)});
3959 };3898 };
3960 if (isByRef(field_ty, pt, cg.target)) {3899 if (isByRef(field_ty, zcu, cg.target)) {
3961 switch (operand) {3900 switch (operand) {
3962 .stack_offset => |stack_offset| {3901 .stack_offset => |stack_offset| {
3963 break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };3902 break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
...@@ -4220,7 +4159,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -4220,7 +4159,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
4220 }4159 }
42214160
4222 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));4161 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));
4223 if (op_is_ptr or isByRef(payload_ty, pt, cg.target)) {4162 if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) {
4224 break :result try cg.buildPointerOffset(operand, pl_offset, .new);4163 break :result try cg.buildPointerOffset(operand, pl_offset, .new);
4225 }4164 }
42264165
...@@ -4446,7 +4385,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4446,7 +4385,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4446 const operand = try cg.resolveInst(ty_op.operand);4385 const operand = try cg.resolveInst(ty_op.operand);
4447 if (opt_ty.optionalReprIsPayload(zcu)) break :result cg.reuseOperand(ty_op.operand, operand);4386 if (opt_ty.optionalReprIsPayload(zcu)) break :result cg.reuseOperand(ty_op.operand, operand);
44484387
4449 if (isByRef(payload_ty, pt, cg.target)) {4388 if (isByRef(payload_ty, zcu, cg.target)) {
4450 break :result try cg.buildPointerOffset(operand, 0, .new);4389 break :result try cg.buildPointerOffset(operand, 0, .new);
4451 }4390 }
44524391
...@@ -4580,7 +4519,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4580,7 +4519,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4580 try cg.addTag(.i32_mul);4519 try cg.addTag(.i32_mul);
4581 try cg.addTag(.i32_add);4520 try cg.addTag(.i32_add);
45824521
4583 const elem_result = if (isByRef(elem_ty, pt, cg.target))4522 const elem_result = if (isByRef(elem_ty, zcu, cg.target))
4584 .stack4523 .stack
4585 else4524 else
4586 try cg.load(.stack, elem_ty, 0);4525 try cg.load(.stack, elem_ty, 0);
...@@ -4739,7 +4678,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4739,7 +4678,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4739 try cg.addTag(.i32_mul);4678 try cg.addTag(.i32_mul);
4740 try cg.addTag(.i32_add);4679 try cg.addTag(.i32_add);
47414680
4742 const elem_result = if (isByRef(elem_ty, pt, cg.target))4681 const elem_result = if (isByRef(elem_ty, zcu, cg.target))
4743 .stack4682 .stack
4744 else4683 else
4745 try cg.load(.stack, elem_ty, 0);4684 try cg.load(.stack, elem_ty, 0);
...@@ -4790,7 +4729,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -4790,7 +4729,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void {
4790 else => ptr_ty.childType(zcu),4729 else => ptr_ty.childType(zcu),
4791 };4730 };
47924731
4793 const valtype = typeToValtype(Type.usize, pt, cg.target);4732 const valtype = typeToValtype(Type.usize, zcu, cg.target);
4794 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });4733 const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul });
4795 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });4734 const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op });
47964735
...@@ -4933,7 +4872,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4933,7 +4872,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4933 const elem_ty = array_ty.childType(zcu);4872 const elem_ty = array_ty.childType(zcu);
4934 const elem_size = elem_ty.abiSize(zcu);4873 const elem_size = elem_ty.abiSize(zcu);
49354874
4936 if (isByRef(array_ty, pt, cg.target)) {4875 if (isByRef(array_ty, zcu, cg.target)) {
4937 try cg.lowerToStack(array);4876 try cg.lowerToStack(array);
4938 try cg.emitWValue(index);4877 try cg.emitWValue(index);
4939 try cg.addImm32(@intCast(elem_size));4878 try cg.addImm32(@intCast(elem_size));
...@@ -4976,7 +4915,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4976,7 +4915,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4976 }4915 }
4977 }4916 }
49784917
4979 const elem_result = if (isByRef(elem_ty, pt, cg.target))4918 const elem_result = if (isByRef(elem_ty, zcu, cg.target))
4980 .stack4919 .stack
4981 else4920 else
4982 try cg.load(.stack, elem_ty, 0);4921 try cg.load(.stack, elem_ty, 0);
...@@ -5027,8 +4966,8 @@ fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5027,8 +4966,8 @@ fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5027 try cg.emitWValue(operand);4966 try cg.emitWValue(operand);
5028 const op = buildOpcode(.{4967 const op = buildOpcode(.{
5029 .op = .trunc,4968 .op = .trunc,
5030 .valtype1 = typeToValtype(dest_ty, pt, cg.target),4969 .valtype1 = typeToValtype(dest_ty, zcu, cg.target),
5031 .valtype2 = typeToValtype(op_ty, pt, cg.target),4970 .valtype2 = typeToValtype(op_ty, zcu, cg.target),
5032 .signedness = dest_info.signedness,4971 .signedness = dest_info.signedness,
5033 });4972 });
5034 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));4973 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));
...@@ -5080,8 +5019,8 @@ fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5080,8 +5019,8 @@ fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5080 try cg.emitWValue(operand);5019 try cg.emitWValue(operand);
5081 const op = buildOpcode(.{5020 const op = buildOpcode(.{
5082 .op = .convert,5021 .op = .convert,
5083 .valtype1 = typeToValtype(dest_ty, pt, cg.target),5022 .valtype1 = typeToValtype(dest_ty, zcu, cg.target),
5084 .valtype2 = typeToValtype(op_ty, pt, cg.target),5023 .valtype2 = typeToValtype(op_ty, zcu, cg.target),
5085 .signedness = op_info.signedness,5024 .signedness = op_info.signedness,
5086 });5025 });
5087 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));5026 try cg.addTag(Mir.Inst.Tag.fromOpcode(op));
...@@ -5180,7 +5119,7 @@ fn airShuffle(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5180,7 +5119,7 @@ fn airShuffle(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5180 const elem_size = child_ty.abiSize(zcu);5119 const elem_size = child_ty.abiSize(zcu);
51815120
5182 // TODO: One of them could be by ref; handle in loop5121 // TODO: One of them could be by ref; handle in loop
5183 if (isByRef(cg.typeOf(extra.a), pt, cg.target) or isByRef(inst_ty, pt, cg.target)) {5122 if (isByRef(cg.typeOf(extra.a), zcu, cg.target) or isByRef(inst_ty, zcu, cg.target)) {
5184 const result = try cg.allocStack(inst_ty);5123 const result = try cg.allocStack(inst_ty);
51855124
5186 for (0..mask_len) |index| {5125 for (0..mask_len) |index| {
...@@ -5256,7 +5195,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5256,7 +5195,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5256 // When the element type is by reference, we must copy the entire5195 // When the element type is by reference, we must copy the entire
5257 // value. It is therefore safer to move the offset pointer and store5196 // value. It is therefore safer to move the offset pointer and store
5258 // each value individually, instead of using store offsets.5197 // each value individually, instead of using store offsets.
5259 if (isByRef(elem_ty, pt, cg.target)) {5198 if (isByRef(elem_ty, zcu, cg.target)) {
5260 // copy stack pointer into a temporary local, which is5199 // copy stack pointer into a temporary local, which is
5261 // moved for each element to store each value in the right position.5200 // moved for each element to store each value in the right position.
5262 const offset = try cg.buildPointerOffset(result, 0, .new);5201 const offset = try cg.buildPointerOffset(result, 0, .new);
...@@ -5286,7 +5225,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5286,7 +5225,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5286 },5225 },
5287 .@"struct" => switch (result_ty.containerLayout(zcu)) {5226 .@"struct" => switch (result_ty.containerLayout(zcu)) {
5288 .@"packed" => {5227 .@"packed" => {
5289 if (isByRef(result_ty, pt, cg.target)) {5228 if (isByRef(result_ty, zcu, cg.target)) {
5290 return cg.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});5229 return cg.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
5291 }5230 }
5292 const packed_struct = zcu.typeToPackedStruct(result_ty).?;5231 const packed_struct = zcu.typeToPackedStruct(result_ty).?;
...@@ -5389,15 +5328,15 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5389,15 +5328,15 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5389 if (layout.tag_size == 0) {5328 if (layout.tag_size == 0) {
5390 break :result .none;5329 break :result .none;
5391 }5330 }
5392 assert(!isByRef(union_ty, pt, cg.target));5331 assert(!isByRef(union_ty, zcu, cg.target));
5393 break :result tag_int;5332 break :result tag_int;
5394 }5333 }
53955334
5396 if (isByRef(union_ty, pt, cg.target)) {5335 if (isByRef(union_ty, zcu, cg.target)) {
5397 const result_ptr = try cg.allocStack(union_ty);5336 const result_ptr = try cg.allocStack(union_ty);
5398 const payload = try cg.resolveInst(extra.init);5337 const payload = try cg.resolveInst(extra.init);
5399 if (layout.tag_align.compare(.gte, layout.payload_align)) {5338 if (layout.tag_align.compare(.gte, layout.payload_align)) {
5400 if (isByRef(field_ty, pt, cg.target)) {5339 if (isByRef(field_ty, zcu, cg.target)) {
5401 const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new);5340 const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new);
5402 try cg.store(payload_ptr, payload, field_ty, 0);5341 try cg.store(payload_ptr, payload, field_ty, 0);
5403 } else {5342 } else {
...@@ -5478,7 +5417,7 @@ fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: st...@@ -5478,7 +5417,7 @@ fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: st
54785417
5479 _ = try cg.load(lhs, payload_ty, 0);5418 _ = try cg.load(lhs, payload_ty, 0);
5480 _ = try cg.load(rhs, payload_ty, 0);5419 _ = try cg.load(rhs, payload_ty, 0);
5481 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, pt, cg.target) });5420 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, zcu, cg.target) });
5482 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));5421 try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode));
5483 try cg.addLabel(.br_if, 0);5422 try cg.addLabel(.br_if, 0);
54845423
...@@ -6521,7 +6460,7 @@ fn lowerTry(...@@ -6521,7 +6460,7 @@ fn lowerTry(
6521 }6460 }
65226461
6523 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));6462 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
6524 if (isByRef(pl_ty, pt, cg.target)) {6463 if (isByRef(pl_ty, zcu, cg.target)) {
6525 return buildPointerOffset(cg, err_union, pl_offset, .new);6464 return buildPointerOffset(cg, err_union, pl_offset, .new);
6526 }6465 }
6527 const payload = try cg.load(err_union, pl_ty, pl_offset);6466 const payload = try cg.load(err_union, pl_ty, pl_offset);
...@@ -7100,7 +7039,7 @@ fn callIntrinsic(...@@ -7100,7 +7039,7 @@ fn callIntrinsic(
71007039
7101 // Always pass over C-ABI7040 // Always pass over C-ABI
71027041
7103 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, pt, cg.target);7042 const want_sret_param = firstParamSRet(.{ .wasm_watc = .{} }, return_type, zcu, cg.target);
7104 // if we want return as first param, we allocate a pointer to stack,7043 // if we want return as first param, we allocate a pointer to stack,
7105 // and emit it as our first argument7044 // and emit it as our first argument
7106 const sret = if (want_sret_param) blk: {7045 const sret = if (want_sret_param) blk: {
...@@ -7282,7 +7221,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7282,7 +7221,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7282 break :val ptr_val;7221 break :val ptr_val;
7283 };7222 };
72847223
7285 const result = if (isByRef(result_ty, pt, cg.target)) val: {7224 const result = if (isByRef(result_ty, zcu, cg.target)) val: {
7286 try cg.emitWValue(cmp_result);7225 try cg.emitWValue(cmp_result);
7287 try cg.addImm32(~@as(u32, 0));7226 try cg.addImm32(~@as(u32, 0));
7288 try cg.addTag(.i32_xor);7227 try cg.addTag(.i32_xor);
src/arch/wasm/abi.zig+1-1
...@@ -22,7 +22,7 @@ const direct: [2]Class = .{ .direct, .none };...@@ -22,7 +22,7 @@ const direct: [2]Class = .{ .direct, .none };
22/// Classifies a given Zig type to determine how they must be passed22/// Classifies a given Zig type to determine how they must be passed
23/// or returned as value within a wasm function.23/// or returned as value within a wasm function.
24/// When all elements result in `.none`, no value must be passed in or returned.24/// When all elements result in `.none`, no value must be passed in or returned.
25pub fn classifyType(ty: Type, zcu: *Zcu) [2]Class {25pub fn classifyType(ty: Type, zcu: *const Zcu) [2]Class {
26 const ip = &zcu.intern_pool;26 const ip = &zcu.intern_pool;
27 const target = zcu.getTarget();27 const target = zcu.getTarget();
28 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return none;28 if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return none;
src/link/Wasm.zig+186-3
...@@ -32,6 +32,7 @@ const mem = std.mem;...@@ -32,6 +32,7 @@ const mem = std.mem;
32const Air = @import("../Air.zig");32const Air = @import("../Air.zig");
33const Mir = @import("../arch/wasm/Mir.zig");33const Mir = @import("../arch/wasm/Mir.zig");
34const CodeGen = @import("../arch/wasm/CodeGen.zig");34const CodeGen = @import("../arch/wasm/CodeGen.zig");
35const abi = @import("../arch/wasm/abi.zig");
35const Compilation = @import("../Compilation.zig");36const Compilation = @import("../Compilation.zig");
36const Dwarf = @import("Dwarf.zig");37const Dwarf = @import("Dwarf.zig");
37const InternPool = @import("../InternPool.zig");38const InternPool = @import("../InternPool.zig");
...@@ -45,6 +46,7 @@ const lldMain = @import("../main.zig").lldMain;...@@ -45,6 +46,7 @@ const lldMain = @import("../main.zig").lldMain;
45const trace = @import("../tracy.zig").trace;46const trace = @import("../tracy.zig").trace;
46const wasi_libc = @import("../wasi_libc.zig");47const wasi_libc = @import("../wasi_libc.zig");
47const Value = @import("../Value.zig");48const Value = @import("../Value.zig");
49const ZcuType = @import("../Type.zig");
4850
49base: link.File,51base: link.File,
50/// Null-terminated strings, indexes have type String and string_table provides52/// Null-terminated strings, indexes have type String and string_table provides
...@@ -236,6 +238,9 @@ mir_extra: std.ArrayListUnmanaged(u32) = .empty,...@@ -236,6 +238,9 @@ mir_extra: std.ArrayListUnmanaged(u32) = .empty,
236/// All local types for all Zcu functions.238/// All local types for all Zcu functions.
237all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,239all_zcu_locals: std.ArrayListUnmanaged(u8) = .empty,
238240
241params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
242returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty,
243
239pub const UavFixup = extern struct {244pub const UavFixup = extern struct {
240 ip_index: InternPool.Index,245 ip_index: InternPool.Index,
241 /// Index into `string_bytes`.246 /// Index into `string_bytes`.
...@@ -650,8 +655,24 @@ pub const FunctionImport = extern struct {...@@ -650,8 +655,24 @@ pub const FunctionImport = extern struct {
650 pub const Index = enum(u32) {655 pub const Index = enum(u32) {
651 _,656 _,
652657
653 pub fn ptr(index: FunctionImport.Index, wasm: *const Wasm) *FunctionImport {658 pub fn key(index: Index, wasm: *const Wasm) *String {
654 return &wasm.object_function_imports.items[@intFromEnum(index)];659 return &wasm.object_function_imports.keys()[@intFromEnum(index)];
660 }
661
662 pub fn value(index: Index, wasm: *const Wasm) *FunctionImport {
663 return &wasm.object_function_imports.values()[@intFromEnum(index)];
664 }
665
666 pub fn name(index: Index, wasm: *const Wasm) String {
667 return index.key(wasm).*;
668 }
669
670 pub fn moduleName(index: Index, wasm: *const Wasm) String {
671 return index.value(wasm).module_name;
672 }
673
674 pub fn functionType(index: Index, wasm: *const Wasm) FunctionType.Index {
675 return value(index, wasm).type;
655 }676 }
656 };677 };
657};678};
...@@ -1093,9 +1114,54 @@ pub const ValtypeList = enum(u32) {...@@ -1093,9 +1114,54 @@ pub const ValtypeList = enum(u32) {
1093 }1114 }
1094};1115};
10951116
1096/// Index into `imports`.1117/// Index into `Wasm.imports`.
1097pub const ZcuImportIndex = enum(u32) {1118pub const ZcuImportIndex = enum(u32) {
1098 _,1119 _,
1120
1121 pub fn ptr(index: ZcuImportIndex, wasm: *const Wasm) *InternPool.Nav.Index {
1122 return &wasm.imports.keys()[@intFromEnum(index)];
1123 }
1124
1125 pub fn name(index: ZcuImportIndex, wasm: *const Wasm) String {
1126 const zcu = wasm.base.comp.zcu.?;
1127 const ip = &zcu.intern_pool;
1128 const nav_index = index.ptr(wasm).*;
1129 const nav = ip.getNav(nav_index);
1130 const ext = switch (ip.indexToKey(nav.status.resolved.val)) {
1131 .@"extern" => |*ext| ext,
1132 else => unreachable,
1133 };
1134 const name_slice = ext.name.toSlice(ip);
1135 return wasm.getExistingString(name_slice).?;
1136 }
1137
1138 pub fn moduleName(index: ZcuImportIndex, wasm: *const Wasm) String {
1139 const zcu = wasm.base.comp.zcu.?;
1140 const ip = &zcu.intern_pool;
1141 const nav_index = index.ptr(wasm).*;
1142 const nav = ip.getNav(nav_index);
1143 const ext = switch (ip.indexToKey(nav.status.resolved.val)) {
1144 .@"extern" => |*ext| ext,
1145 else => unreachable,
1146 };
1147 const lib_name = ext.lib_name.toSlice(ip) orelse return wasm.host_name;
1148 return wasm.getExistingString(lib_name).?;
1149 }
1150
1151 pub fn functionType(index: ZcuImportIndex, wasm: *Wasm) FunctionType.Index {
1152 const comp = wasm.base.comp;
1153 const target = &comp.root_mod.resolved_target.result;
1154 const zcu = comp.zcu.?;
1155 const ip = &zcu.intern_pool;
1156 const nav_index = index.ptr(wasm).*;
1157 const nav = ip.getNav(nav_index);
1158 const ext = switch (ip.indexToKey(nav.status.resolved.val)) {
1159 .@"extern" => |*ext| ext,
1160 else => unreachable,
1161 };
1162 const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
1163 return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;
1164 }
1099};1165};
11001166
1101/// 0. Index into `object_function_imports`.1167/// 0. Index into `object_function_imports`.
...@@ -1143,6 +1209,24 @@ pub const FunctionImportId = enum(u32) {...@@ -1143,6 +1209,24 @@ pub const FunctionImportId = enum(u32) {
1143 .zcu_import => return .zig_object_nofile, // TODO give a better source location1209 .zcu_import => return .zig_object_nofile, // TODO give a better source location
1144 }1210 }
1145 }1211 }
1212
1213 pub fn name(id: FunctionImportId, wasm: *const Wasm) String {
1214 return switch (unpack(id, wasm)) {
1215 inline .object_function_import, .zcu_import => |i| i.name(wasm),
1216 };
1217 }
1218
1219 pub fn moduleName(id: FunctionImportId, wasm: *const Wasm) String {
1220 return switch (unpack(id, wasm)) {
1221 inline .object_function_import, .zcu_import => |i| i.moduleName(wasm),
1222 };
1223 }
1224
1225 pub fn functionType(id: FunctionImportId, wasm: *Wasm) FunctionType.Index {
1226 return switch (unpack(id, wasm)) {
1227 inline .object_function_import, .zcu_import => |i| i.functionType(wasm),
1228 };
1229 }
1146};1230};
11471231
1148/// 0. Index into `object_global_imports`.1232/// 0. Index into `object_global_imports`.
...@@ -1666,6 +1750,9 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1666,6 +1750,9 @@ pub fn deinit(wasm: *Wasm) void {
1666 wasm.string_bytes.deinit(gpa);1750 wasm.string_bytes.deinit(gpa);
1667 wasm.string_table.deinit(gpa);1751 wasm.string_table.deinit(gpa);
1668 wasm.dump_argv_list.deinit(gpa);1752 wasm.dump_argv_list.deinit(gpa);
1753
1754 wasm.params_scratch.deinit(gpa);
1755 wasm.returns_scratch.deinit(gpa);
1669}1756}
16701757
1671pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {1758pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
...@@ -2599,12 +2686,51 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al...@@ -2599,12 +2686,51 @@ pub fn internValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) Al
2599 return .fromString(try internString(wasm, @ptrCast(valtype_list)));2686 return .fromString(try internString(wasm, @ptrCast(valtype_list)));
2600}2687}
26012688
2689pub fn getExistingValtypeList(wasm: *Wasm, valtype_list: []const std.wasm.Valtype) ?ValtypeList {
2690 return .fromString(getExistingString(wasm, @ptrCast(valtype_list)) orelse return null);
2691}
2692
2602pub fn addFuncType(wasm: *Wasm, ft: FunctionType) Allocator.Error!FunctionType.Index {2693pub fn addFuncType(wasm: *Wasm, ft: FunctionType) Allocator.Error!FunctionType.Index {
2603 const gpa = wasm.base.comp.gpa;2694 const gpa = wasm.base.comp.gpa;
2604 const gop = try wasm.func_types.getOrPut(gpa, ft);2695 const gop = try wasm.func_types.getOrPut(gpa, ft);
2605 return @enumFromInt(gop.index);2696 return @enumFromInt(gop.index);
2606}2697}
26072698
2699pub fn getExistingFuncType(wasm: *Wasm, ft: FunctionType) ?FunctionType.Index {
2700 const index = wasm.func_types.getIndex(ft) orelse return null;
2701 return @enumFromInt(index);
2702}
2703
2704pub fn internFunctionType(
2705 wasm: *Wasm,
2706 cc: std.builtin.CallingConvention,
2707 params: []const InternPool.Index,
2708 return_type: ZcuType,
2709 target: *const std.Target,
2710) Allocator.Error!FunctionType.Index {
2711 try convertZcuFnType(wasm, cc, params, return_type, target, &wasm.params_scratch, &wasm.returns_scratch);
2712 return wasm.addFuncType(.{
2713 .params = try wasm.internValtypeList(wasm.params_scratch.items),
2714 .returns = try wasm.internValtypeList(wasm.returns_scratch.items),
2715 });
2716}
2717
2718pub fn getExistingFunctionType(
2719 wasm: *Wasm,
2720 cc: std.builtin.CallingConvention,
2721 params: []const InternPool.Index,
2722 return_type: ZcuType,
2723 target: *const std.Target,
2724) ?FunctionType.Index {
2725 convertZcuFnType(wasm, cc, params, return_type, target, &wasm.params_scratch, &wasm.returns_scratch) catch |err| switch (err) {
2726 error.OutOfMemory => return null,
2727 };
2728 return wasm.getExistingFuncType(.{
2729 .params = wasm.getExistingValtypeList(wasm.params_scratch.items) orelse return null,
2730 .returns = wasm.getExistingValtypeList(wasm.returns_scratch.items) orelse return null,
2731 });
2732}
2733
2608pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {2734pub fn addExpr(wasm: *Wasm, bytes: []const u8) Allocator.Error!Expr {
2609 const gpa = wasm.base.comp.gpa;2735 const gpa = wasm.base.comp.gpa;
2610 // We can't use string table deduplication here since these expressions can2736 // We can't use string table deduplication here since these expressions can
...@@ -2644,3 +2770,60 @@ pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Er...@@ -2644,3 +2770,60 @@ pub fn navSymbolIndex(wasm: *Wasm, nav_index: InternPool.Nav.Index) Allocator.Er
2644 const gop = try wasm.symbol_table.getOrPut(gpa, name);2770 const gop = try wasm.symbol_table.getOrPut(gpa, name);
2645 return @enumFromInt(gop.index);2771 return @enumFromInt(gop.index);
2646}2772}
2773
2774fn convertZcuFnType(
2775 wasm: *Wasm,
2776 cc: std.builtin.CallingConvention,
2777 params: []const InternPool.Index,
2778 return_type: ZcuType,
2779 target: *const std.Target,
2780 params_buffer: *std.ArrayListUnmanaged(std.wasm.Valtype),
2781 returns_buffer: *std.ArrayListUnmanaged(std.wasm.Valtype),
2782) Allocator.Error!void {
2783 params_buffer.clearRetainingCapacity();
2784 returns_buffer.clearRetainingCapacity();
2785
2786 const comp = wasm.base.comp;
2787 const gpa = comp.gpa;
2788 const zcu = comp.zcu.?;
2789
2790 if (CodeGen.firstParamSRet(cc, return_type, zcu, target)) {
2791 try params_buffer.append(gpa, .i32); // memory address is always a 32-bit handle
2792 } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
2793 if (cc == .wasm_watc) {
2794 const res_classes = abi.classifyType(return_type, zcu);
2795 assert(res_classes[0] == .direct and res_classes[1] == .none);
2796 const scalar_type = abi.scalarType(return_type, zcu);
2797 try returns_buffer.append(gpa, CodeGen.typeToValtype(scalar_type, zcu, target));
2798 } else {
2799 try returns_buffer.append(gpa, CodeGen.typeToValtype(return_type, zcu, target));
2800 }
2801 } else if (return_type.isError(zcu)) {
2802 try returns_buffer.append(gpa, .i32);
2803 }
2804
2805 // param types
2806 for (params) |param_type_ip| {
2807 const param_type = ZcuType.fromInterned(param_type_ip);
2808 if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
2809
2810 switch (cc) {
2811 .wasm_watc => {
2812 const param_classes = abi.classifyType(param_type, zcu);
2813 if (param_classes[1] == .none) {
2814 if (param_classes[0] == .direct) {
2815 const scalar_type = abi.scalarType(param_type, zcu);
2816 try params_buffer.append(gpa, CodeGen.typeToValtype(scalar_type, zcu, target));
2817 } else {
2818 try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target));
2819 }
2820 } else {
2821 // i128/f128
2822 try params_buffer.append(gpa, .i64);
2823 try params_buffer.append(gpa, .i64);
2824 }
2825 },
2826 else => try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)),
2827 }
2828 }
2829}
src/link/Wasm/Flush.zig+7-7
...@@ -381,30 +381,30 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -381,30 +381,30 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
381381
382 // Import section382 // Import section
383 const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len +383 const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len +
384 wasm.table_imports.entries.len + wasm.memory_imports.items.len + @intFromBool(import_memory);384 wasm.table_imports.entries.len + wasm.object_memory_imports.items.len + @intFromBool(import_memory);
385385
386 if (total_imports_len > 0) {386 if (total_imports_len > 0) {
387 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);387 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
388388
389 for (wasm.function_imports.values()) |*function_import| {389 for (wasm.function_imports.values()) |*function_import| {
390 const module_name = function_import.module_name.slice(wasm);390 const module_name = function_import.moduleName(wasm).slice(wasm);
391 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));391 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
392 try binary_writer.writeAll(module_name);392 try binary_writer.writeAll(module_name);
393393
394 const name = function_import.name.slice(wasm);394 const name = function_import.name(wasm).slice(wasm);
395 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));395 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
396 try binary_writer.writeAll(name);396 try binary_writer.writeAll(name);
397397
398 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));398 try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));
399 try leb.writeUleb128(binary_writer, function_import.index);399 try leb.writeUleb128(binary_writer, @intFromEnum(function_import.functionType(wasm)));
400 }400 }
401401
402 for (wasm.table_imports.values()) |*table_import| {402 for (wasm.table_imports.values()) |*table_import| {
403 const module_name = table_import.module_name.slice(wasm);403 const module_name = table_import.moduleName(wasm).slice(wasm);
404 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));404 try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
405 try binary_writer.writeAll(module_name);405 try binary_writer.writeAll(module_name);
406406
407 const name = table_import.name.slice(wasm);407 const name = table_import.name(wasm).slice(wasm);
408 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));408 try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
409 try binary_writer.writeAll(name);409 try binary_writer.writeAll(name);
410410
...@@ -413,7 +413,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {...@@ -413,7 +413,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
413 try emitLimits(binary_writer, table_import.limits);413 try emitLimits(binary_writer, table_import.limits);
414 }414 }
415415
416 for (wasm.memory_imports.items) |*memory_import| {416 for (wasm.object_memory_imports.items) |*memory_import| {
417 try emitMemoryImport(wasm, binary_writer, memory_import);417 try emitMemoryImport(wasm, binary_writer, memory_import);
418 } else if (import_memory) {418 } else if (import_memory) {
419 try emitMemoryImport(wasm, binary_writer, &.{419 try emitMemoryImport(wasm, binary_writer, &.{