| author | |
| committer | |
| log | 4805b6f7acc07223a41b38e51a9a6e4f020dfdfe |
| tree | fe8d8a128c71db31972d0e097402b26a70fa471a |
| parent | 69d65ae472e725726d3c33f23c486d2c871ef8c7 |
5 files changed, 190 insertions(+), 41 deletions(-)
src/codegen/wasm/CodeGen.zig+175-28| ... | @@ -196,6 +196,9 @@ args: []WValue, | ... | @@ -196,6 +196,9 @@ args: []WValue, |
| 196 | /// When it returns a pointer to the stack, the `.local` tag will be active and must be populated | 196 | /// When it returns a pointer to the stack, the `.local` tag will be active and must be populated |
| 197 | /// before this function returns its execution to the caller. | 197 | /// before this function returns its execution to the caller. |
| 198 | return_value: WValue, | 198 | return_value: WValue, |
| 199 | /// Only populated for variadic functions. | ||
| 200 | /// Holds the hidden final parameter pointing to the varargs buffer. | ||
| 201 | varargs: WValue, | ||
| 199 | /// The size of the stack this function occupies. In the function prologue | 202 | /// The size of the stack this function occupies. In the function prologue |
| 200 | /// we will move the stack pointer by this number, forward aligned with the `stack_alignment`. | 203 | /// we will move the stack pointer by this number, forward aligned with the `stack_alignment`. |
| 201 | stack_size: u32 = 0, | 204 | stack_size: u32 = 0, |
| ... | @@ -308,7 +311,7 @@ const WValue = union(enum) { | ... | @@ -308,7 +311,7 @@ const WValue = union(enum) { |
| 308 | fn free(value: *WValue, gen: *CodeGen) void { | 311 | fn free(value: *WValue, gen: *CodeGen) void { |
| 309 | if (value.* != .local) return; | 312 | if (value.* != .local) return; |
| 310 | const local_value = value.local.value; | 313 | const local_value = value.local.value; |
| 311 | const reserved = gen.args.len + @intFromBool(gen.return_value != .none); | 314 | const reserved = gen.args.len + @intFromBool(gen.return_value != .none) + @intFromBool(gen.varargs != .none); |
| 312 | if (local_value < reserved + 2) return; // reserved locals may never be re-used. Also accounts for 2 stack locals. | 315 | if (local_value < reserved + 2) return; // reserved locals may never be re-used. Also accounts for 2 stack locals. |
| 313 | 316 | ||
| 314 | const index = local_value - reserved; | 317 | const index = local_value - reserved; |
| ... | @@ -800,6 +803,7 @@ pub fn generate( | ... | @@ -800,6 +803,7 @@ pub fn generate( |
| 800 | .func_index = func_index, | 803 | .func_index = func_index, |
| 801 | .args = cc_result.args, | 804 | .args = cc_result.args, |
| 802 | .return_value = cc_result.return_value, | 805 | .return_value = cc_result.return_value, |
| 806 | .varargs = cc_result.varargs, | ||
| 803 | .local_index = cc_result.local_index, | 807 | .local_index = cc_result.local_index, |
| 804 | .mir_instructions = .empty, | 808 | .mir_instructions = .empty, |
| 805 | .mir_extra = .empty, | 809 | .mir_extra = .empty, |
| ... | @@ -874,6 +878,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir { | ... | @@ -874,6 +878,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir { |
| 874 | const CallWValues = struct { | 878 | const CallWValues = struct { |
| 875 | args: []WValue, | 879 | args: []WValue, |
| 876 | return_value: WValue, | 880 | return_value: WValue, |
| 881 | varargs: WValue, | ||
| 877 | local_index: u32, | 882 | local_index: u32, |
| 878 | 883 | ||
| 879 | fn deinit(values: *CallWValues, gpa: Allocator) void { | 884 | fn deinit(values: *CallWValues, gpa: Allocator) void { |
| ... | @@ -895,6 +900,7 @@ fn resolveCallingConventionValues( | ... | @@ -895,6 +900,7 @@ fn resolveCallingConventionValues( |
| 895 | var result: CallWValues = .{ | 900 | var result: CallWValues = .{ |
| 896 | .args = &.{}, | 901 | .args = &.{}, |
| 897 | .return_value = .none, | 902 | .return_value = .none, |
| 903 | .varargs = .none, | ||
| 898 | .local_index = 0, | 904 | .local_index = 0, |
| 899 | }; | 905 | }; |
| 900 | if (cc == .naked) return result; | 906 | if (cc == .naked) return result; |
| ... | @@ -945,6 +951,12 @@ fn resolveCallingConventionValues( | ... | @@ -945,6 +951,12 @@ fn resolveCallingConventionValues( |
| 945 | }, | 951 | }, |
| 946 | else => unreachable, // Frontend is responsible for emitting an error earlier. | 952 | else => unreachable, // Frontend is responsible for emitting an error earlier. |
| 947 | } | 953 | } |
| 954 | |||
| 955 | if (fn_info.is_var_args) { | ||
| 956 | result.varargs = .{ .local = .{ .value = result.local_index, .references = 1 } }; | ||
| 957 | result.local_index += 1; | ||
| 958 | } | ||
| 959 | |||
| 948 | result.args = try args.toOwnedSlice(); | 960 | result.args = try args.toOwnedSlice(); |
| 949 | return result; | 961 | return result; |
| 950 | } | 962 | } |
| ... | @@ -1056,9 +1068,6 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue { | ... | @@ -1056,9 +1068,6 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue { |
| 1056 | const pt = cg.pt; | 1068 | const pt = cg.pt; |
| 1057 | const zcu = pt.zcu; | 1069 | const zcu = pt.zcu; |
| 1058 | assert(ty.hasRuntimeBits(zcu)); | 1070 | assert(ty.hasRuntimeBits(zcu)); |
| 1059 | if (cg.initial_stack_value == .none) { | ||
| 1060 | try cg.initializeStack(); | ||
| 1061 | } | ||
| 1062 | 1071 | ||
| 1063 | const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { | 1072 | const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { |
| 1064 | return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{ | 1073 | return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{ |
| ... | @@ -1067,28 +1076,29 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue { | ... | @@ -1067,28 +1076,29 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue { |
| 1067 | }; | 1076 | }; |
| 1068 | const abi_align = ty.abiAlignment(zcu); | 1077 | const abi_align = ty.abiAlignment(zcu); |
| 1069 | 1078 | ||
| 1070 | cg.stack_alignment = cg.stack_alignment.max(abi_align); | 1079 | return cg.allocStackBytes(abi_size, abi_align); |
| 1071 | |||
| 1072 | const offset: u32 = @intCast(abi_align.forward(cg.stack_size)); | ||
| 1073 | defer cg.stack_size = offset + abi_size; | ||
| 1074 | |||
| 1075 | return .{ .stack_offset = .{ .value = offset, .references = 1 } }; | ||
| 1076 | } | 1080 | } |
| 1077 | 1081 | ||
| 1078 | fn allocInt(cg: *CodeGen, int_ty: IntType) !WValue { | 1082 | fn allocInt(cg: *CodeGen, int_ty: IntType) !WValue { |
| 1079 | if (cg.initial_stack_value == .none) { | ||
| 1080 | try cg.initializeStack(); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | const abi_size = std.math.cast(u32, std.zig.target.intByteSize(cg.target, int_ty.bits)) orelse { | 1083 | const abi_size = std.math.cast(u32, std.zig.target.intByteSize(cg.target, int_ty.bits)) orelse { |
| 1084 | return cg.fail("Integer ABI size exceeds max stack size", .{}); | 1084 | return cg.fail("Integer ABI size exceeds max stack size", .{}); |
| 1085 | }; | 1085 | }; |
| 1086 | const abi_align: Alignment = .fromByteUnits(std.zig.target.intAlignment(cg.target, int_ty.bits)); | 1086 | const abi_align: Alignment = .fromByteUnits(std.zig.target.intAlignment(cg.target, int_ty.bits)); |
| 1087 | 1087 | ||
| 1088 | cg.stack_alignment = cg.stack_alignment.max(abi_align); | 1088 | return cg.allocStackBytes(abi_size, abi_align); |
| 1089 | } | ||
| 1090 | |||
| 1091 | fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue { | ||
| 1092 | assert(size > 0); | ||
| 1089 | 1093 | ||
| 1090 | const offset: u32 = @intCast(abi_align.forward(cg.stack_size)); | 1094 | if (cg.initial_stack_value == .none) { |
| 1091 | defer cg.stack_size = offset + abi_size; | 1095 | try cg.initializeStack(); |
| 1096 | } | ||
| 1097 | |||
| 1098 | cg.stack_alignment = cg.stack_alignment.max(alignment); | ||
| 1099 | |||
| 1100 | const offset: u32 = @intCast(alignment.forward(cg.stack_size)); | ||
| 1101 | defer cg.stack_size = offset + size; | ||
| 1092 | 1102 | ||
| 1093 | return .{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1103 | return .{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| 1094 | } | 1104 | } |
| ... | @@ -1841,15 +1851,16 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1841,15 +1851,16 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1841 | 1851 | ||
| 1842 | .assembly => cg.airAsm(inst), | 1852 | .assembly => cg.airAsm(inst), |
| 1843 | 1853 | ||
| 1854 | .c_va_arg => try cg.airVaArg(inst), | ||
| 1855 | .c_va_copy => try cg.airVaCopy(inst), | ||
| 1856 | .c_va_end => try cg.airVaEnd(inst), | ||
| 1857 | .c_va_start => try cg.airVaStart(inst), | ||
| 1858 | |||
| 1844 | .err_return_trace, | 1859 | .err_return_trace, |
| 1845 | .set_err_return_trace, | 1860 | .set_err_return_trace, |
| 1846 | .save_err_return_trace_index, | 1861 | .save_err_return_trace_index, |
| 1847 | .is_named_enum_value, | 1862 | .is_named_enum_value, |
| 1848 | .addrspace_cast, | 1863 | .addrspace_cast, |
| 1849 | .c_va_arg, | ||
| 1850 | .c_va_copy, | ||
| 1851 | .c_va_end, | ||
| 1852 | .c_va_start, | ||
| 1853 | => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), | 1864 | => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1854 | 1865 | ||
| 1855 | .atomic_load => cg.airAtomicLoad(inst), | 1866 | .atomic_load => cg.airAtomicLoad(inst), |
| ... | @@ -2030,19 +2041,70 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) | ... | @@ -2030,19 +2041,70 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2030 | return cg.fail("unable to lower callee to a function index", .{}); | 2041 | return cg.fail("unable to lower callee to a function index", .{}); |
| 2031 | }; | 2042 | }; |
| 2032 | 2043 | ||
| 2033 | const sret: WValue = if (first_param_sret) blk: { | 2044 | const sret: WValue = if (first_param_sret) |
| 2034 | const sret_local = try cg.allocStack(ret_ty); | 2045 | try cg.allocStack(ret_ty) |
| 2035 | try cg.lowerToStack(sret_local); | 2046 | else |
| 2036 | break :blk sret_local; | 2047 | .none; |
| 2048 | |||
| 2049 | const fixed_arg_count = fn_info.param_types.len; | ||
| 2050 | |||
| 2051 | const varargs_buf: WValue = if (fn_info.is_var_args) buf: { | ||
| 2052 | var varargs_size: u32 = 0; | ||
| 2053 | var varargs_align: Alignment = .fromByteUnits(1); | ||
| 2054 | |||
| 2055 | for (args[fixed_arg_count..]) |arg| { | ||
| 2056 | const arg_ty = cg.typeOf(arg); | ||
| 2057 | if (!arg_ty.hasRuntimeBits(zcu)) continue; | ||
| 2058 | |||
| 2059 | const arg_size = std.math.cast(u32, arg_ty.abiSize(zcu)) orelse { | ||
| 2060 | return cg.fail("argument type {f} too large for wasm varargs buffer", .{arg_ty.fmt(pt)}); | ||
| 2061 | }; | ||
| 2062 | const arg_align = arg_ty.abiAlignment(zcu); | ||
| 2063 | |||
| 2064 | varargs_align = varargs_align.max(arg_align); | ||
| 2065 | varargs_size = @intCast(arg_align.forward(varargs_size)); | ||
| 2066 | varargs_size += arg_size; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | if (varargs_size == 0) varargs_size = 1; | ||
| 2070 | |||
| 2071 | const buffer = try cg.allocStackBytes(varargs_size, varargs_align); | ||
| 2072 | |||
| 2073 | var offset: u32 = 0; | ||
| 2074 | for (args[fixed_arg_count..]) |arg| { | ||
| 2075 | const arg_ty = cg.typeOf(arg); | ||
| 2076 | if (!arg_ty.hasRuntimeBits(zcu)) continue; | ||
| 2077 | |||
| 2078 | const arg_val = try cg.resolveInst(arg); | ||
| 2079 | const arg_size = std.math.cast(u32, arg_ty.abiSize(zcu)) orelse { | ||
| 2080 | return cg.fail("argument type {f} too large for wasm varargs buffer", .{arg_ty.fmt(pt)}); | ||
| 2081 | }; | ||
| 2082 | const arg_align = arg_ty.abiAlignment(zcu); | ||
| 2083 | |||
| 2084 | offset = @intCast(arg_align.forward(offset)); | ||
| 2085 | try cg.store(buffer, arg_val, arg_ty, offset); | ||
| 2086 | offset += arg_size; | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | break :buf buffer; | ||
| 2037 | } else .none; | 2090 | } else .none; |
| 2038 | 2091 | ||
| 2039 | for (args) |arg| { | 2092 | if (first_param_sret) { |
| 2040 | const arg_val = try cg.resolveInst(arg); | 2093 | try cg.lowerToStack(sret); |
| 2094 | } | ||
| 2095 | |||
| 2096 | for (args, 0..) |arg, arg_i| { | ||
| 2097 | if (fn_info.is_var_args and arg_i >= fixed_arg_count) break; | ||
| 2041 | 2098 | ||
| 2042 | const arg_ty = cg.typeOf(arg); | 2099 | const arg_ty = cg.typeOf(arg); |
| 2043 | if (!arg_ty.hasRuntimeBits(zcu)) continue; | 2100 | if (!arg_ty.hasRuntimeBits(zcu)) continue; |
| 2044 | 2101 | ||
| 2045 | try cg.lowerArg(zcu.typeToFunc(fn_ty).?.cc, arg_ty, arg_val); | 2102 | const arg_val = try cg.resolveInst(arg); |
| 2103 | try cg.lowerArg(fn_info.cc, arg_ty, arg_val); | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | if (fn_info.is_var_args) { | ||
| 2107 | try cg.lowerToStack(varargs_buf); | ||
| 2046 | } | 2108 | } |
| 2047 | 2109 | ||
| 2048 | if (callee) |nav_index| { | 2110 | if (callee) |nav_index| { |
| ... | @@ -2097,6 +2159,91 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) | ... | @@ -2097,6 +2159,91 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2097 | return cg.finishAirResult(inst, result_value); | 2159 | return cg.finishAirResult(inst, result_value); |
| 2098 | } | 2160 | } |
| 2099 | 2161 | ||
| 2162 | fn airVaStart(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ||
| 2163 | try cg.emitWValue(cg.varargs); | ||
| 2164 | return cg.finishAir(inst, .stack, &.{}); | ||
| 2165 | } | ||
| 2166 | |||
| 2167 | fn airVaEnd(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ||
| 2168 | const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | ||
| 2169 | return cg.finishAir(inst, .none, &.{un_op}); | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | fn airVaCopy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ||
| 2173 | const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | ||
| 2174 | const operand = try cg.resolveInst(ty_op.operand); | ||
| 2175 | |||
| 2176 | const result = try cg.load(operand, .usize, 0); | ||
| 2177 | |||
| 2178 | return cg.finishAir(inst, result, &.{ty_op.operand}); | ||
| 2179 | } | ||
| 2180 | |||
| 2181 | fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ||
| 2182 | const zcu = cg.pt.zcu; | ||
| 2183 | const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | ||
| 2184 | const operand = try cg.resolveInst(ty_op.operand); | ||
| 2185 | |||
| 2186 | const ty = cg.typeOfIndex(inst); | ||
| 2187 | |||
| 2188 | if (!ty.hasRuntimeBits(zcu)) { | ||
| 2189 | return cg.finishAir(inst, .none, &.{ty_op.operand}); | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | const is_f32_va_arg = ty.toIntern() == .f32_type; | ||
| 2193 | const load_ty: Type = if (is_f32_va_arg) Type.f64 else ty; | ||
| 2194 | |||
| 2195 | const abi_size: u32 = @intCast(load_ty.abiSize(zcu)); | ||
| 2196 | const abi_align: u32 = @intCast(load_ty.abiAlignment(zcu).toByteUnits().?); | ||
| 2197 | |||
| 2198 | const arg_ptr = try cg.allocLocal(.usize); | ||
| 2199 | _ = try cg.load(operand, .usize, 0); | ||
| 2200 | |||
| 2201 | if (abi_align > 1) { | ||
| 2202 | switch (cg.ptr_size) { | ||
| 2203 | .wasm32 => { | ||
| 2204 | try cg.addImm32(abi_align - 1); | ||
| 2205 | try cg.addTag(.i32_add); | ||
| 2206 | try cg.addImm32(~(abi_align - 1)); | ||
| 2207 | try cg.addTag(.i32_and); | ||
| 2208 | }, | ||
| 2209 | .wasm64 => { | ||
| 2210 | try cg.addImm64(abi_align - 1); | ||
| 2211 | try cg.addTag(.i64_add); | ||
| 2212 | try cg.addImm64(~@as(u64, abi_align - 1)); | ||
| 2213 | try cg.addTag(.i64_and); | ||
| 2214 | }, | ||
| 2215 | } | ||
| 2216 | } | ||
| 2217 | |||
| 2218 | try cg.addLocal(.local_set, arg_ptr.local.value); | ||
| 2219 | |||
| 2220 | try cg.lowerToStack(operand); | ||
| 2221 | try cg.lowerToStack(arg_ptr); | ||
| 2222 | switch (cg.ptr_size) { | ||
| 2223 | .wasm32 => { | ||
| 2224 | try cg.addImm32(abi_size); | ||
| 2225 | try cg.addTag(.i32_add); | ||
| 2226 | }, | ||
| 2227 | .wasm64 => { | ||
| 2228 | try cg.addImm64(abi_size); | ||
| 2229 | try cg.addTag(.i64_add); | ||
| 2230 | }, | ||
| 2231 | } | ||
| 2232 | try cg.store(.stack, .stack, .usize, 0); | ||
| 2233 | |||
| 2234 | const result = if (is_f32_va_arg) result: { | ||
| 2235 | const promoted = try cg.load(arg_ptr, Type.f64, 0); | ||
| 2236 | try cg.emitWValue(promoted); | ||
| 2237 | try cg.addTag(.f32_demote_f64); | ||
| 2238 | |||
| 2239 | const result_local = try cg.allocLocal(Type.f32); | ||
| 2240 | try cg.addLocal(.local_set, result_local.local.value); | ||
| 2241 | break :result result_local; | ||
| 2242 | } else try cg.load(arg_ptr, ty, 0); | ||
| 2243 | |||
| 2244 | return cg.finishAir(inst, result, &.{ty_op.operand}); | ||
| 2245 | } | ||
| 2246 | |||
| 2100 | fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2247 | fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2101 | const value = try cg.allocStackPtr(inst); | 2248 | const value = try cg.allocStackPtr(inst); |
| 2102 | return cg.finishAir(inst, value, &.{}); | 2249 | return cg.finishAir(inst, value, &.{}); |
src/codegen/wasm/Emit.zig+1| ... | @@ -186,6 +186,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { | ... | @@ -186,6 +186,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 186 | fn_info.cc, | 186 | fn_info.cc, |
| 187 | fn_info.param_types.get(&comp.zcu.?.intern_pool), | 187 | fn_info.param_types.get(&comp.zcu.?.intern_pool), |
| 188 | .fromInterned(fn_info.return_type), | 188 | .fromInterned(fn_info.return_type), |
| 189 | fn_info.is_var_args, | ||
| 189 | target, | 190 | target, |
| 190 | ).?; | 191 | ).?; |
| 191 | if (is_obj) { | 192 | if (is_obj) { |
src/link/Wasm.zig+13-6| ... | @@ -932,7 +932,7 @@ pub const ZcuFunc = union { | ... | @@ -932,7 +932,7 @@ pub const ZcuFunc = union { |
| 932 | switch (ip.indexToKey(i.key(wasm).*)) { | 932 | switch (ip.indexToKey(i.key(wasm).*)) { |
| 933 | .func => |func| { | 933 | .func => |func| { |
| 934 | const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?; | 934 | const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?; |
| 935 | return wasm.getExistingFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?; | 935 | return wasm.getExistingFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target).?; |
| 936 | }, | 936 | }, |
| 937 | .enum_type => { | 937 | .enum_type => { |
| 938 | return i.value(wasm).tag_name.type_index; | 938 | return i.value(wasm).tag_name.type_index; |
| ... | @@ -2290,7 +2290,7 @@ pub const ZcuImportIndex = enum(u32) { | ... | @@ -2290,7 +2290,7 @@ pub const ZcuImportIndex = enum(u32) { |
| 2290 | const nav_index = index.ptr(wasm).*; | 2290 | const nav_index = index.ptr(wasm).*; |
| 2291 | const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; | 2291 | const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; |
| 2292 | const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; | 2292 | const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; |
| 2293 | return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?; | 2293 | return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target).?; |
| 2294 | } | 2294 | } |
| 2295 | 2295 | ||
| 2296 | pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) ObjectGlobal.Type { | 2296 | pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) ObjectGlobal.Type { |
| ... | @@ -3209,7 +3209,7 @@ pub fn updateFunc( | ... | @@ -3209,7 +3209,7 @@ pub fn updateFunc( |
| 3209 | for (mir.indirect_function_set.keys()) |nav| wasm.zcu_indirect_function_set.putAssumeCapacity(nav, {}); | 3209 | for (mir.indirect_function_set.keys()) |nav| wasm.zcu_indirect_function_set.putAssumeCapacity(nav, {}); |
| 3210 | for (mir.func_tys.keys()) |func_ty| { | 3210 | for (mir.func_tys.keys()) |func_ty| { |
| 3211 | const fn_info = zcu.typeToFunc(.fromInterned(func_ty)).?; | 3211 | const fn_info = zcu.typeToFunc(.fromInterned(func_ty)).?; |
| 3212 | _ = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target); | 3212 | _ = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target); |
| 3213 | } | 3213 | } |
| 3214 | wasm.error_name_table_ref_count += mir.error_name_table_ref_count; | 3214 | wasm.error_name_table_ref_count += mir.error_name_table_ref_count; |
| 3215 | // We need to populate UAV data. In theory, we can lower the UAV values while we fill `mir.uavs`. | 3215 | // We need to populate UAV data. In theory, we can lower the UAV values while we fill `mir.uavs`. |
| ... | @@ -3281,7 +3281,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index | ... | @@ -3281,7 +3281,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index |
| 3281 | wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm)); | 3281 | wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm)); |
| 3282 | // Ensure there is a corresponding function type table entry. | 3282 | // Ensure there is a corresponding function type table entry. |
| 3283 | const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; | 3283 | const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; |
| 3284 | _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target); | 3284 | _ = try internFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), fn_info.is_var_args, target); |
| 3285 | } else { | 3285 | } else { |
| 3286 | wasm.data_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm)); | 3286 | wasm.data_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm)); |
| 3287 | } | 3287 | } |
| ... | @@ -3928,9 +3928,10 @@ pub fn internFunctionType( | ... | @@ -3928,9 +3928,10 @@ pub fn internFunctionType( |
| 3928 | cc: std.lang.CallingConvention, | 3928 | cc: std.lang.CallingConvention, |
| 3929 | params: []const InternPool.Index, | 3929 | params: []const InternPool.Index, |
| 3930 | return_type: Zcu.Type, | 3930 | return_type: Zcu.Type, |
| 3931 | is_var_args: bool, | ||
| 3931 | target: *const std.Target, | 3932 | target: *const std.Target, |
| 3932 | ) Allocator.Error!FunctionType.Index { | 3933 | ) Allocator.Error!FunctionType.Index { |
| 3933 | try convertZcuFnType(wasm.base.comp, cc, params, return_type, target, &wasm.params_scratch, &wasm.returns_scratch); | 3934 | try convertZcuFnType(wasm.base.comp, cc, params, return_type, is_var_args, target, &wasm.params_scratch, &wasm.returns_scratch); |
| 3934 | return wasm.addFuncType(.{ | 3935 | return wasm.addFuncType(.{ |
| 3935 | .params = try wasm.internValtypeList(wasm.params_scratch.items), | 3936 | .params = try wasm.internValtypeList(wasm.params_scratch.items), |
| 3936 | .returns = try wasm.internValtypeList(wasm.returns_scratch.items), | 3937 | .returns = try wasm.internValtypeList(wasm.returns_scratch.items), |
| ... | @@ -3942,9 +3943,10 @@ pub fn getExistingFunctionType( | ... | @@ -3942,9 +3943,10 @@ pub fn getExistingFunctionType( |
| 3942 | cc: std.lang.CallingConvention, | 3943 | cc: std.lang.CallingConvention, |
| 3943 | params: []const InternPool.Index, | 3944 | params: []const InternPool.Index, |
| 3944 | return_type: Zcu.Type, | 3945 | return_type: Zcu.Type, |
| 3946 | is_var_args: bool, | ||
| 3945 | target: *const std.Target, | 3947 | target: *const std.Target, |
| 3946 | ) ?FunctionType.Index { | 3948 | ) ?FunctionType.Index { |
| 3947 | convertZcuFnType(wasm.base.comp, cc, params, return_type, target, &wasm.params_scratch, &wasm.returns_scratch) catch |err| switch (err) { | 3949 | convertZcuFnType(wasm.base.comp, cc, params, return_type, is_var_args, target, &wasm.params_scratch, &wasm.returns_scratch) catch |err| switch (err) { |
| 3948 | error.OutOfMemory => return null, | 3950 | error.OutOfMemory => return null, |
| 3949 | }; | 3951 | }; |
| 3950 | return wasm.getExistingFuncType(.{ | 3952 | return wasm.getExistingFuncType(.{ |
| ... | @@ -4176,6 +4178,7 @@ fn convertZcuFnType( | ... | @@ -4176,6 +4178,7 @@ fn convertZcuFnType( |
| 4176 | cc: std.lang.CallingConvention, | 4178 | cc: std.lang.CallingConvention, |
| 4177 | params: []const InternPool.Index, | 4179 | params: []const InternPool.Index, |
| 4178 | return_type: Zcu.Type, | 4180 | return_type: Zcu.Type, |
| 4181 | is_var_args: bool, | ||
| 4179 | target: *const std.Target, | 4182 | target: *const std.Target, |
| 4180 | params_buffer: *std.ArrayList(std.wasm.Valtype), | 4183 | params_buffer: *std.ArrayList(std.wasm.Valtype), |
| 4181 | returns_buffer: *std.ArrayList(std.wasm.Valtype), | 4184 | returns_buffer: *std.ArrayList(std.wasm.Valtype), |
| ... | @@ -4226,6 +4229,10 @@ fn convertZcuFnType( | ... | @@ -4226,6 +4229,10 @@ fn convertZcuFnType( |
| 4226 | else => try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)), | 4229 | else => try params_buffer.append(gpa, CodeGen.typeToValtype(param_type, zcu, target)), |
| 4227 | } | 4230 | } |
| 4228 | } | 4231 | } |
| 4232 | |||
| 4233 | if (is_var_args) { | ||
| 4234 | try params_buffer.append(gpa, .i32); | ||
| 4235 | } | ||
| 4229 | } | 4236 | } |
| 4230 | 4237 | ||
| 4231 | pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool { | 4238 | pub fn isBss(wasm: *const Wasm, optional_name: OptionalString) bool { |
src/link/Wasm/Flush.zig+1-1| ... | @@ -151,7 +151,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -151,7 +151,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 151 | const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).intTagType(zcu); | 151 | const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).intTagType(zcu); |
| 152 | gop.value_ptr.* = .{ .tag_name = .{ | 152 | gop.value_ptr.* = .{ .tag_name = .{ |
| 153 | .symbol_name = try wasm.internStringFmt("__zig_tag_name_{d}", .{data.ip_index}), | 153 | .symbol_name = try wasm.internStringFmt("__zig_tag_name_{d}", .{data.ip_index}), |
| 154 | .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .slice_const_u8_sentinel_0, target), | 154 | .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .slice_const_u8_sentinel_0, false, target), |
| 155 | .table_index = @intCast(wasm.tag_name_offs.items.len), | 155 | .table_index = @intCast(wasm.tag_name_offs.items.len), |
| 156 | } }; | 156 | } }; |
| 157 | const tag_names = ip.loadEnumType(data.ip_index).field_names; | 157 | const tag_names = ip.loadEnumType(data.ip_index).field_names; |
test/behavior/var_args.zig-6| ... | @@ -94,7 +94,6 @@ fn doNothingWithFirstArg(args: anytype) void { | ... | @@ -94,7 +94,6 @@ fn doNothingWithFirstArg(args: anytype) void { |
| 94 | test "simple variadic function" { | 94 | test "simple variadic function" { |
| 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 97 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 98 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 97 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 99 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 98 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 100 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { | 99 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { |
| ... | @@ -156,7 +155,6 @@ test "simple variadic function" { | ... | @@ -156,7 +155,6 @@ test "simple variadic function" { |
| 156 | test "coerce reference to var arg" { | 155 | test "coerce reference to var arg" { |
| 157 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 156 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 158 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 159 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 160 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 158 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 161 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 159 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 162 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { | 160 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { |
| ... | @@ -188,7 +186,6 @@ test "coerce reference to var arg" { | ... | @@ -188,7 +186,6 @@ test "coerce reference to var arg" { |
| 188 | test "variadic functions" { | 186 | test "variadic functions" { |
| 189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 187 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 188 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 191 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 192 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 189 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 193 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 190 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 194 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { | 191 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { |
| ... | @@ -241,7 +238,6 @@ test "variadic functions" { | ... | @@ -241,7 +238,6 @@ test "variadic functions" { |
| 241 | 238 | ||
| 242 | test "copy VaList" { | 239 | test "copy VaList" { |
| 243 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 240 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 244 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 245 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 241 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 246 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 242 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 247 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { | 243 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { |
| ... | @@ -276,7 +272,6 @@ test "copy VaList" { | ... | @@ -276,7 +272,6 @@ test "copy VaList" { |
| 276 | 272 | ||
| 277 | test "unused VaList arg" { | 273 | test "unused VaList arg" { |
| 278 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 274 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 279 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 280 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 275 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 281 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 276 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 282 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { | 277 | if (builtin.zig_backend == .stage2_llvm and !builtin.os.tag.isDarwin() and builtin.cpu.arch.isAARCH64()) { |
| ... | @@ -308,7 +303,6 @@ test "unused VaList arg" { | ... | @@ -308,7 +303,6 @@ test "unused VaList arg" { |
| 308 | 303 | ||
| 309 | test "floating point VaList args" { | 304 | test "floating point VaList args" { |
| 310 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 305 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 311 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 312 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 306 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 313 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 307 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 314 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/16961 | 308 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/16961 |