| ... | ... | @@ -760,7 +760,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 760 | 760 | // |
| 761 | 761 | // In the other cases, we will simply lower the constant to a value that fits |
| 762 | 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 | 764 | .{ .uav_ref = .{ .ip_index = val.toIntern() } } |
| 765 | 765 | else |
| 766 | 766 | try cg.lowerConstant(val, ty); |
| ... | ... | @@ -953,9 +953,8 @@ fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 { |
| 953 | 953 | return result; |
| 954 | 954 | } |
| 955 | 955 | |
| 956 | | /// Using a given `Type`, returns the corresponding valtype for .auto callconv |
| 957 | | fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.wasm.Valtype { |
| 958 | | const zcu = pt.zcu; |
| 956 | /// For `std.builtin.CallingConvention.auto`. |
| 957 | pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.Valtype { |
| 959 | 958 | const ip = &zcu.intern_pool; |
| 960 | 959 | return switch (ty.zigTypeTag(zcu)) { |
| 961 | 960 | .float => switch (ty.floatBits(target.*)) { |
| ... | ... | @@ -973,19 +972,20 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was |
| 973 | 972 | .@"struct" => blk: { |
| 974 | 973 | if (zcu.typeToPackedStruct(ty)) |packed_struct| { |
| 975 | 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 | 976 | } else { |
| 978 | 977 | break :blk .i32; |
| 979 | 978 | } |
| 980 | 979 | }, |
| 981 | | .vector => switch (determineSimdStoreStrategy(ty, zcu, target)) { |
| 980 | .vector => switch (CodeGen.determineSimdStoreStrategy(ty, zcu, target)) { |
| 982 | 981 | .direct => .v128, |
| 983 | 982 | .unrolled => .i32, |
| 984 | 983 | }, |
| 985 | 984 | .@"union" => switch (ty.containerLayout(zcu)) { |
| 986 | | .@"packed" => blk: { |
| 987 | | const int_ty = pt.intType(.unsigned, @as(u16, @intCast(ty.bitSize(zcu)))) catch @panic("out of memory"); |
| 988 | | break :blk typeToValtype(int_ty, pt, target); |
| 985 | .@"packed" => switch (ty.bitSize(zcu)) { |
| 986 | 0...32 => .i32, |
| 987 | 33...64 => .i64, |
| 988 | else => .i32, |
| 989 | 989 | }, |
| 990 | 990 | else => .i32, |
| 991 | 991 | }, |
| ... | ... | @@ -994,17 +994,17 @@ fn typeToValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) std.was |
| 994 | 994 | } |
| 995 | 995 | |
| 996 | 996 | /// Using a given `Type`, returns the byte representation of its wasm value type |
| 997 | | fn genValtype(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 { |
| 998 | | return @intFromEnum(typeToValtype(ty, pt, target)); |
| 997 | fn genValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) u8 { |
| 998 | return @intFromEnum(typeToValtype(ty, zcu, target)); |
| 999 | 999 | } |
| 1000 | 1000 | |
| 1001 | 1001 | /// Using a given `Type`, returns the corresponding wasm value type |
| 1002 | 1002 | /// Differently from `genValtype` this also allows `void` to create a block |
| 1003 | 1003 | /// with no return type |
| 1004 | | fn genBlockType(ty: Type, pt: Zcu.PerThread, target: *const std.Target) u8 { |
| 1004 | fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) u8 { |
| 1005 | 1005 | return switch (ty.ip_index) { |
| 1006 | 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 | } |
| 1010 | 1010 | |
| ... | ... | @@ -1086,8 +1086,8 @@ fn getResolvedInst(cg: *CodeGen, ref: Air.Inst.Ref) *WValue { |
| 1086 | 1086 | /// Creates one locals for a given `Type`. |
| 1087 | 1087 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 1088 | 1088 | fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { |
| 1089 | | const pt = cg.pt; |
| 1090 | | const valtype = typeToValtype(ty, pt, cg.target); |
| 1089 | const zcu = cg.pt.zcu; |
| 1090 | const valtype = typeToValtype(ty, zcu, cg.target); |
| 1091 | 1091 | const index_or_null = switch (valtype) { |
| 1092 | 1092 | .i32 => cg.free_locals_i32.popOrNull(), |
| 1093 | 1093 | .i64 => cg.free_locals_i64.popOrNull(), |
| ... | ... | @@ -1106,74 +1106,13 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { |
| 1106 | 1106 | /// Ensures a new local will be created. This is useful when it's useful |
| 1107 | 1107 | /// to use a zero-initialized local. |
| 1108 | 1108 | fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { |
| 1109 | | const pt = cg.pt; |
| 1110 | | try cg.locals.append(cg.gpa, genValtype(ty, pt, cg.target)); |
| 1109 | const zcu = cg.pt.zcu; |
| 1110 | try cg.locals.append(cg.gpa, genValtype(ty, zcu, cg.target)); |
| 1111 | 1111 | const initial_index = cg.local_index; |
| 1112 | 1112 | cg.local_index += 1; |
| 1113 | 1113 | return .{ .local = .{ .value = initial_index, .references = 1 } }; |
| 1114 | 1114 | } |
| 1115 | 1115 | |
| 1116 | | fn 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 | | |
| 1177 | 1116 | pub const Function = extern struct { |
| 1178 | 1117 | /// Index into `Wasm.mir_instructions`. |
| 1179 | 1118 | mir_off: u32, |
| ... | ... | @@ -1291,7 +1230,7 @@ pub fn function( |
| 1291 | 1230 | const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu); |
| 1292 | 1231 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 1293 | 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 | 1234 | const returns = fn_ty_index.ptr(wasm).returns.slice(wasm); |
| 1296 | 1235 | const any_returns = returns.len != 0; |
| 1297 | 1236 | |
| ... | ... | @@ -1409,7 +1348,7 @@ fn resolveCallingConventionValues( |
| 1409 | 1348 | |
| 1410 | 1349 | // Check if we store the result as a pointer to the stack rather than |
| 1411 | 1350 | // 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 | 1352 | // the sret arg will be passed as first argument, therefore we |
| 1414 | 1353 | // set the `return_value` before allocating locals for regular args. |
| 1415 | 1354 | result.return_value = .{ .local = .{ .value = result.local_index, .references = 1 } }; |
| ... | ... | @@ -1443,17 +1382,17 @@ fn resolveCallingConventionValues( |
| 1443 | 1382 | return result; |
| 1444 | 1383 | } |
| 1445 | 1384 | |
| 1446 | | fn firstParamSRet( |
| 1385 | pub fn firstParamSRet( |
| 1447 | 1386 | cc: std.builtin.CallingConvention, |
| 1448 | 1387 | return_type: Type, |
| 1449 | | pt: Zcu.PerThread, |
| 1388 | zcu: *const Zcu, |
| 1450 | 1389 | target: *const std.Target, |
| 1451 | 1390 | ) bool { |
| 1452 | 1391 | switch (cc) { |
| 1453 | 1392 | .@"inline" => unreachable, |
| 1454 | | .auto => return isByRef(return_type, pt, target), |
| 1393 | .auto => return isByRef(return_type, zcu, target), |
| 1455 | 1394 | .wasm_watc => { |
| 1456 | | const ty_classes = abi.classifyType(return_type, pt.zcu); |
| 1395 | const ty_classes = abi.classifyType(return_type, zcu); |
| 1457 | 1396 | if (ty_classes[0] == .indirect) return true; |
| 1458 | 1397 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; |
| 1459 | 1398 | return false; |
| ... | ... | @@ -1744,8 +1683,7 @@ fn ptrSize(cg: *const CodeGen) u16 { |
| 1744 | 1683 | |
| 1745 | 1684 | /// For a given `Type`, will return true when the type will be passed |
| 1746 | 1685 | /// by reference, rather than by value |
| 1747 | | fn isByRef(ty: Type, pt: Zcu.PerThread, target: *const std.Target) bool { |
| 1748 | | const zcu = pt.zcu; |
| 1686 | fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool { |
| 1749 | 1687 | const ip = &zcu.intern_pool; |
| 1750 | 1688 | switch (ty.zigTypeTag(zcu)) { |
| 1751 | 1689 | .type, |
| ... | ... | @@ -1778,7 +1716,7 @@ fn isByRef(ty: Type, pt: Zcu.PerThread, target: *const std.Target) bool { |
| 1778 | 1716 | }, |
| 1779 | 1717 | .@"struct" => { |
| 1780 | 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 | 1721 | return ty.hasRuntimeBitsIgnoreComptime(zcu); |
| 1784 | 1722 | }, |
| ... | ... | @@ -1816,7 +1754,7 @@ const SimdStoreStrategy = enum { |
| 1816 | 1754 | /// This means when a given type is 128 bits and either the simd128 or relaxed-simd |
| 1817 | 1755 | /// features are enabled, the function will return `.direct`. This would allow to store |
| 1818 | 1756 | /// it using a instruction, rather than an unrolled version. |
| 1819 | | fn determineSimdStoreStrategy(ty: Type, zcu: *Zcu, target: *const std.Target) SimdStoreStrategy { |
| 1757 | pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy { |
| 1820 | 1758 | assert(ty.zigTypeTag(zcu) == .vector); |
| 1821 | 1759 | if (ty.bitSize(zcu) != 128) return .unrolled; |
| 1822 | 1760 | const hasFeature = std.Target.wasm.featureSetHas; |
| ... | ... | @@ -2144,7 +2082,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2144 | 2082 | .op = .load, |
| 2145 | 2083 | .width = @as(u8, @intCast(scalar_type.abiSize(zcu) * 8)), |
| 2146 | 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 | 2087 | try cg.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2150 | 2088 | .offset = operand.offset(), |
| ... | ... | @@ -2177,7 +2115,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2177 | 2115 | } |
| 2178 | 2116 | |
| 2179 | 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 | 2119 | break :result cg.return_value; |
| 2182 | 2120 | } |
| 2183 | 2121 | |
| ... | ... | @@ -2199,7 +2137,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2199 | 2137 | if (ret_ty.isError(zcu)) { |
| 2200 | 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 | 2141 | // leave on the stack |
| 2204 | 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 | 2165 | }; |
| 2228 | 2166 | const ret_ty = fn_ty.fnReturnType(zcu); |
| 2229 | 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); |
| 2231 | 2169 | |
| 2232 | 2170 | const callee: ?InternPool.Nav.Index = blk: { |
| 2233 | 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 | 2205 | const operand = try cg.resolveInst(pl_op.operand); |
| 2268 | 2206 | try cg.emitWValue(operand); |
| 2269 | 2207 | |
| 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 | 2209 | try cg.addLabel(.call_indirect, @intFromEnum(fn_type_index)); |
| 2272 | 2210 | } |
| 2273 | 2211 | |
| ... | ... | @@ -2328,7 +2266,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 2328 | 2266 | // load the value, and then shift+or the rhs into the result location. |
| 2329 | 2267 | const int_elem_ty = try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8); |
| 2330 | 2268 | |
| 2331 | | if (isByRef(int_elem_ty, pt, cg.target)) { |
| 2269 | if (isByRef(int_elem_ty, zcu, cg.target)) { |
| 2332 | 2270 | return cg.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{}); |
| 2333 | 2271 | } |
| 2334 | 2272 | |
| ... | ... | @@ -2394,7 +2332,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr |
| 2394 | 2332 | const len = @as(u32, @intCast(abi_size)); |
| 2395 | 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 | 2336 | const len = @as(u32, @intCast(abi_size)); |
| 2399 | 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 | 2394 | // into lhs, so we calculate that and emit that instead |
| 2457 | 2395 | try cg.lowerToStack(rhs); |
| 2458 | 2396 | |
| 2459 | | const valtype = typeToValtype(ty, pt, cg.target); |
| 2397 | const valtype = typeToValtype(ty, zcu, cg.target); |
| 2460 | 2398 | const opcode = buildOpcode(.{ |
| 2461 | 2399 | .valtype1 = valtype, |
| 2462 | 2400 | .width = @as(u8, @intCast(abi_size * 8)), |
| ... | ... | @@ -2485,7 +2423,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2485 | 2423 | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand}); |
| 2486 | 2424 | |
| 2487 | 2425 | const result = result: { |
| 2488 | | if (isByRef(ty, pt, cg.target)) { |
| 2426 | if (isByRef(ty, zcu, cg.target)) { |
| 2489 | 2427 | const new_local = try cg.allocStack(ty); |
| 2490 | 2428 | try cg.store(new_local, operand, ty, 0); |
| 2491 | 2429 | break :result new_local; |
| ... | ... | @@ -2535,7 +2473,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue |
| 2535 | 2473 | |
| 2536 | 2474 | const abi_size: u8 = @intCast(ty.abiSize(zcu)); |
| 2537 | 2475 | const opcode = buildOpcode(.{ |
| 2538 | | .valtype1 = typeToValtype(ty, pt, cg.target), |
| 2476 | .valtype1 = typeToValtype(ty, zcu, cg.target), |
| 2539 | 2477 | .width = abi_size * 8, |
| 2540 | 2478 | .op = .load, |
| 2541 | 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 | 2570 | return cg.floatOp(float_op, ty, &.{ lhs, rhs }); |
| 2633 | 2571 | } |
| 2634 | 2572 | |
| 2635 | | if (isByRef(ty, pt, cg.target)) { |
| 2573 | if (isByRef(ty, zcu, cg.target)) { |
| 2636 | 2574 | if (ty.zigTypeTag(zcu) == .int) { |
| 2637 | 2575 | return cg.binOpBigInt(lhs, rhs, ty, op); |
| 2638 | 2576 | } else { |
| ... | ... | @@ -2645,7 +2583,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV |
| 2645 | 2583 | |
| 2646 | 2584 | const opcode: std.wasm.Opcode = buildOpcode(.{ |
| 2647 | 2585 | .op = op, |
| 2648 | | .valtype1 = typeToValtype(ty, pt, cg.target), |
| 2586 | .valtype1 = typeToValtype(ty, zcu, cg.target), |
| 2649 | 2587 | .signedness = if (ty.isSignedInt(zcu)) .signed else .unsigned, |
| 2650 | 2588 | }); |
| 2651 | 2589 | try cg.emitWValue(lhs); |
| ... | ... | @@ -2949,7 +2887,7 @@ fn floatOp(cg: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) Inne |
| 2949 | 2887 | for (args) |operand| { |
| 2950 | 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 | 2891 | try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2954 | 2892 | return .stack; |
| 2955 | 2893 | } |
| ... | ... | @@ -3174,7 +3112,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro |
| 3174 | 3112 | fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3175 | 3113 | const pt = cg.pt; |
| 3176 | 3114 | const zcu = pt.zcu; |
| 3177 | | assert(!isByRef(ty, pt, cg.target)); |
| 3115 | assert(!isByRef(ty, zcu, cg.target)); |
| 3178 | 3116 | const ip = &zcu.intern_pool; |
| 3179 | 3117 | if (val.isUndefDeep(zcu)) return cg.emitUndefined(ty); |
| 3180 | 3118 | |
| ... | ... | @@ -3415,11 +3353,12 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3415 | 3353 | |
| 3416 | 3354 | fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void { |
| 3417 | 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); |
| 3419 | 3358 | |
| 3420 | 3359 | // if wasm_block_ty is non-empty, we create a register to store the temporary value |
| 3421 | 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 | 3362 | break :blk try cg.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten |
| 3424 | 3363 | } else .none; |
| 3425 | 3364 | |
| ... | ... | @@ -3544,7 +3483,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe |
| 3544 | 3483 | } |
| 3545 | 3484 | } else if (ty.isAnyFloat()) { |
| 3546 | 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 | 3487 | return cg.cmpBigInt(lhs, rhs, ty, op); |
| 3549 | 3488 | } |
| 3550 | 3489 | |
| ... | ... | @@ -3562,7 +3501,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe |
| 3562 | 3501 | try cg.lowerToStack(rhs); |
| 3563 | 3502 | |
| 3564 | 3503 | const opcode: std.wasm.Opcode = buildOpcode(.{ |
| 3565 | | .valtype1 = typeToValtype(ty, pt, cg.target), |
| 3504 | .valtype1 = typeToValtype(ty, zcu, cg.target), |
| 3566 | 3505 | .op = switch (op) { |
| 3567 | 3506 | .lt => .lt, |
| 3568 | 3507 | .lte => .le, |
| ... | ... | @@ -3769,7 +3708,7 @@ fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3769 | 3708 | break :result try cg.bitcast(wanted_ty, given_ty, operand); |
| 3770 | 3709 | } |
| 3771 | 3710 | |
| 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 | 3712 | const loaded_memory = try cg.load(operand, wanted_ty, 0); |
| 3774 | 3713 | if (needs_wrapping) { |
| 3775 | 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 | 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 | 3720 | const stack_memory = try cg.allocStack(wanted_ty); |
| 3782 | 3721 | try cg.store(stack_memory, operand, given_ty, 0); |
| 3783 | 3722 | if (needs_wrapping) { |
| ... | ... | @@ -3807,8 +3746,8 @@ fn bitcast(cg: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inner |
| 3807 | 3746 | |
| 3808 | 3747 | const opcode = buildOpcode(.{ |
| 3809 | 3748 | .op = .reinterpret, |
| 3810 | | .valtype1 = typeToValtype(wanted_ty, pt, cg.target), |
| 3811 | | .valtype2 = typeToValtype(given_ty, pt, cg.target), |
| 3749 | .valtype1 = typeToValtype(wanted_ty, zcu, cg.target), |
| 3750 | .valtype2 = typeToValtype(given_ty, zcu, cg.target), |
| 3812 | 3751 | }); |
| 3813 | 3752 | try cg.emitWValue(operand); |
| 3814 | 3753 | try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| ... | ... | @@ -3930,8 +3869,8 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3930 | 3869 | break :result try cg.trunc(shifted_value, field_ty, backing_ty); |
| 3931 | 3870 | }, |
| 3932 | 3871 | .@"union" => result: { |
| 3933 | | if (isByRef(struct_ty, pt, cg.target)) { |
| 3934 | | if (!isByRef(field_ty, pt, cg.target)) { |
| 3872 | if (isByRef(struct_ty, zcu, cg.target)) { |
| 3873 | if (!isByRef(field_ty, zcu, cg.target)) { |
| 3935 | 3874 | break :result try cg.load(operand, field_ty, 0); |
| 3936 | 3875 | } else { |
| 3937 | 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 | 3896 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse { |
| 3958 | 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 | 3900 | switch (operand) { |
| 3962 | 3901 | .stack_offset => |stack_offset| { |
| 3963 | 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 | 4159 | } |
| 4221 | 4160 | |
| 4222 | 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 | 4163 | break :result try cg.buildPointerOffset(operand, pl_offset, .new); |
| 4225 | 4164 | } |
| 4226 | 4165 | |
| ... | ... | @@ -4446,7 +4385,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4446 | 4385 | const operand = try cg.resolveInst(ty_op.operand); |
| 4447 | 4386 | if (opt_ty.optionalReprIsPayload(zcu)) break :result cg.reuseOperand(ty_op.operand, operand); |
| 4448 | 4387 | |
| 4449 | | if (isByRef(payload_ty, pt, cg.target)) { |
| 4388 | if (isByRef(payload_ty, zcu, cg.target)) { |
| 4450 | 4389 | break :result try cg.buildPointerOffset(operand, 0, .new); |
| 4451 | 4390 | } |
| 4452 | 4391 | |
| ... | ... | @@ -4580,7 +4519,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4580 | 4519 | try cg.addTag(.i32_mul); |
| 4581 | 4520 | try cg.addTag(.i32_add); |
| 4582 | 4521 | |
| 4583 | | const elem_result = if (isByRef(elem_ty, pt, cg.target)) |
| 4522 | const elem_result = if (isByRef(elem_ty, zcu, cg.target)) |
| 4584 | 4523 | .stack |
| 4585 | 4524 | else |
| 4586 | 4525 | try cg.load(.stack, elem_ty, 0); |
| ... | ... | @@ -4739,7 +4678,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4739 | 4678 | try cg.addTag(.i32_mul); |
| 4740 | 4679 | try cg.addTag(.i32_add); |
| 4741 | 4680 | |
| 4742 | | const elem_result = if (isByRef(elem_ty, pt, cg.target)) |
| 4681 | const elem_result = if (isByRef(elem_ty, zcu, cg.target)) |
| 4743 | 4682 | .stack |
| 4744 | 4683 | else |
| 4745 | 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 | 4729 | else => ptr_ty.childType(zcu), |
| 4791 | 4730 | }; |
| 4792 | 4731 | |
| 4793 | | const valtype = typeToValtype(Type.usize, pt, cg.target); |
| 4732 | const valtype = typeToValtype(Type.usize, zcu, cg.target); |
| 4794 | 4733 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); |
| 4795 | 4734 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); |
| 4796 | 4735 | |
| ... | ... | @@ -4933,7 +4872,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4933 | 4872 | const elem_ty = array_ty.childType(zcu); |
| 4934 | 4873 | const elem_size = elem_ty.abiSize(zcu); |
| 4935 | 4874 | |
| 4936 | | if (isByRef(array_ty, pt, cg.target)) { |
| 4875 | if (isByRef(array_ty, zcu, cg.target)) { |
| 4937 | 4876 | try cg.lowerToStack(array); |
| 4938 | 4877 | try cg.emitWValue(index); |
| 4939 | 4878 | try cg.addImm32(@intCast(elem_size)); |
| ... | ... | @@ -4976,7 +4915,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4976 | 4915 | } |
| 4977 | 4916 | } |
| 4978 | 4917 | |
| 4979 | | const elem_result = if (isByRef(elem_ty, pt, cg.target)) |
| 4918 | const elem_result = if (isByRef(elem_ty, zcu, cg.target)) |
| 4980 | 4919 | .stack |
| 4981 | 4920 | else |
| 4982 | 4921 | try cg.load(.stack, elem_ty, 0); |
| ... | ... | @@ -5027,8 +4966,8 @@ fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5027 | 4966 | try cg.emitWValue(operand); |
| 5028 | 4967 | const op = buildOpcode(.{ |
| 5029 | 4968 | .op = .trunc, |
| 5030 | | .valtype1 = typeToValtype(dest_ty, pt, cg.target), |
| 5031 | | .valtype2 = typeToValtype(op_ty, pt, cg.target), |
| 4969 | .valtype1 = typeToValtype(dest_ty, zcu, cg.target), |
| 4970 | .valtype2 = typeToValtype(op_ty, zcu, cg.target), |
| 5032 | 4971 | .signedness = dest_info.signedness, |
| 5033 | 4972 | }); |
| 5034 | 4973 | try cg.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| ... | ... | @@ -5080,8 +5019,8 @@ fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5080 | 5019 | try cg.emitWValue(operand); |
| 5081 | 5020 | const op = buildOpcode(.{ |
| 5082 | 5021 | .op = .convert, |
| 5083 | | .valtype1 = typeToValtype(dest_ty, pt, cg.target), |
| 5084 | | .valtype2 = typeToValtype(op_ty, pt, cg.target), |
| 5022 | .valtype1 = typeToValtype(dest_ty, zcu, cg.target), |
| 5023 | .valtype2 = typeToValtype(op_ty, zcu, cg.target), |
| 5085 | 5024 | .signedness = op_info.signedness, |
| 5086 | 5025 | }); |
| 5087 | 5026 | try cg.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| ... | ... | @@ -5180,7 +5119,7 @@ fn airShuffle(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5180 | 5119 | const elem_size = child_ty.abiSize(zcu); |
| 5181 | 5120 | |
| 5182 | 5121 | // 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 | 5123 | const result = try cg.allocStack(inst_ty); |
| 5185 | 5124 | |
| 5186 | 5125 | for (0..mask_len) |index| { |
| ... | ... | @@ -5256,7 +5195,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5256 | 5195 | // When the element type is by reference, we must copy the entire |
| 5257 | 5196 | // value. It is therefore safer to move the offset pointer and store |
| 5258 | 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 | 5199 | // copy stack pointer into a temporary local, which is |
| 5261 | 5200 | // moved for each element to store each value in the right position. |
| 5262 | 5201 | const offset = try cg.buildPointerOffset(result, 0, .new); |
| ... | ... | @@ -5286,7 +5225,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5286 | 5225 | }, |
| 5287 | 5226 | .@"struct" => switch (result_ty.containerLayout(zcu)) { |
| 5288 | 5227 | .@"packed" => { |
| 5289 | | if (isByRef(result_ty, pt, cg.target)) { |
| 5228 | if (isByRef(result_ty, zcu, cg.target)) { |
| 5290 | 5229 | return cg.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 5291 | 5230 | } |
| 5292 | 5231 | const packed_struct = zcu.typeToPackedStruct(result_ty).?; |
| ... | ... | @@ -5389,15 +5328,15 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5389 | 5328 | if (layout.tag_size == 0) { |
| 5390 | 5329 | break :result .none; |
| 5391 | 5330 | } |
| 5392 | | assert(!isByRef(union_ty, pt, cg.target)); |
| 5331 | assert(!isByRef(union_ty, zcu, cg.target)); |
| 5393 | 5332 | break :result tag_int; |
| 5394 | 5333 | } |
| 5395 | 5334 | |
| 5396 | | if (isByRef(union_ty, pt, cg.target)) { |
| 5335 | if (isByRef(union_ty, zcu, cg.target)) { |
| 5397 | 5336 | const result_ptr = try cg.allocStack(union_ty); |
| 5398 | 5337 | const payload = try cg.resolveInst(extra.init); |
| 5399 | 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 | 5340 | const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5402 | 5341 | try cg.store(payload_ptr, payload, field_ty, 0); |
| 5403 | 5342 | } else { |
| ... | ... | @@ -5478,7 +5417,7 @@ fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: st |
| 5478 | 5417 | |
| 5479 | 5418 | _ = try cg.load(lhs, payload_ty, 0); |
| 5480 | 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 | 5421 | try cg.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 5483 | 5422 | try cg.addLabel(.br_if, 0); |
| 5484 | 5423 | |
| ... | ... | @@ -6521,7 +6460,7 @@ fn lowerTry( |
| 6521 | 6460 | } |
| 6522 | 6461 | |
| 6523 | 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 | 6464 | return buildPointerOffset(cg, err_union, pl_offset, .new); |
| 6526 | 6465 | } |
| 6527 | 6466 | const payload = try cg.load(err_union, pl_ty, pl_offset); |
| ... | ... | @@ -7100,7 +7039,7 @@ fn callIntrinsic( |
| 7100 | 7039 | |
| 7101 | 7040 | // Always pass over C-ABI |
| 7102 | 7041 | |
| 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 | 7043 | // if we want return as first param, we allocate a pointer to stack, |
| 7105 | 7044 | // and emit it as our first argument |
| 7106 | 7045 | const sret = if (want_sret_param) blk: { |
| ... | ... | @@ -7282,7 +7221,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7282 | 7221 | break :val ptr_val; |
| 7283 | 7222 | }; |
| 7284 | 7223 | |
| 7285 | | const result = if (isByRef(result_ty, pt, cg.target)) val: { |
| 7224 | const result = if (isByRef(result_ty, zcu, cg.target)) val: { |
| 7286 | 7225 | try cg.emitWValue(cmp_result); |
| 7287 | 7226 | try cg.addImm32(~@as(u32, 0)); |
| 7288 | 7227 | try cg.addTag(.i32_xor); |