| ... | ... | @@ -1106,6 +1106,20 @@ pub const DeclGen = struct { |
| 1106 | 1106 | } |
| 1107 | 1107 | return Result{ .appended = {} }; |
| 1108 | 1108 | }, |
| 1109 | .Float => { |
| 1110 | const float_bits = ty.floatBits(self.target()); |
| 1111 | if (float_bits > 64) { |
| 1112 | return self.fail("Wasm TODO: Implement f80 and f128", .{}); |
| 1113 | } |
| 1114 | |
| 1115 | switch (float_bits) { |
| 1116 | 16, 32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))), |
| 1117 | 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))), |
| 1118 | else => unreachable, |
| 1119 | } |
| 1120 | |
| 1121 | return Result{ .appended = {} }; |
| 1122 | }, |
| 1109 | 1123 | .Enum => { |
| 1110 | 1124 | var int_buffer: Value.Payload.U64 = undefined; |
| 1111 | 1125 | const int_val = val.enumToInt(ty, &int_buffer); |
| ... | ... | @@ -1334,10 +1348,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1334 | 1348 | defer self.gpa.free(param_types); |
| 1335 | 1349 | fn_ty.fnParamTypes(param_types); |
| 1336 | 1350 | var result: CallWValues = .{ |
| 1337 | | .args = try self.gpa.alloc(WValue, param_types.len), |
| 1351 | .args = &.{}, |
| 1338 | 1352 | .return_value = .none, |
| 1339 | 1353 | }; |
| 1340 | | errdefer self.gpa.free(result.args); |
| 1354 | var args = std.ArrayList(WValue).init(self.gpa); |
| 1355 | defer args.deinit(); |
| 1356 | |
| 1341 | 1357 | const ret_ty = fn_ty.fnReturnType(); |
| 1342 | 1358 | // Check if we store the result as a pointer to the stack rather than |
| 1343 | 1359 | // by value |
| ... | ... | @@ -1350,18 +1366,18 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1350 | 1366 | switch (cc) { |
| 1351 | 1367 | .Naked => return result, |
| 1352 | 1368 | .Unspecified, .C => { |
| 1353 | | for (param_types) |ty, ty_index| { |
| 1369 | for (param_types) |ty| { |
| 1354 | 1370 | if (!ty.hasRuntimeBits()) { |
| 1355 | | result.args[ty_index] = .{ .none = {} }; |
| 1356 | 1371 | continue; |
| 1357 | 1372 | } |
| 1358 | 1373 | |
| 1359 | | result.args[ty_index] = .{ .local = self.local_index }; |
| 1374 | try args.append(.{ .local = self.local_index }); |
| 1360 | 1375 | self.local_index += 1; |
| 1361 | 1376 | } |
| 1362 | 1377 | }, |
| 1363 | 1378 | else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}), |
| 1364 | 1379 | } |
| 1380 | result.args = args.toOwnedSlice(); |
| 1365 | 1381 | return result; |
| 1366 | 1382 | } |
| 1367 | 1383 | |
| ... | ... | @@ -2060,6 +2076,26 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 2060 | 2076 | |
| 2061 | 2077 | fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2062 | 2078 | if (val.isUndefDeep()) return self.emitUndefined(ty); |
| 2079 | if (val.castTag(.decl_ref)) |decl_ref| { |
| 2080 | const decl = decl_ref.data; |
| 2081 | decl.markAlive(); |
| 2082 | const target_sym_index = decl.link.wasm.sym_index; |
| 2083 | if (ty.isSlice()) { |
| 2084 | var slice_len: Value.Payload.U64 = .{ |
| 2085 | .base = .{ .tag = .int_u64 }, |
| 2086 | .data = val.sliceLen(), |
| 2087 | }; |
| 2088 | var slice_val: Value.Payload.Slice = .{ |
| 2089 | .base = .{ .tag = .slice }, |
| 2090 | .data = .{ .ptr = val.slicePtr(), .len = Value.initPayload(&slice_len.base) }, |
| 2091 | }; |
| 2092 | return self.lowerConstant(Value.initPayload(&slice_val.base), ty); |
| 2093 | } else if (decl.ty.zigTypeTag() == .Fn) { |
| 2094 | try self.bin_file.addTableFunction(target_sym_index); |
| 2095 | return WValue{ .function_index = target_sym_index }; |
| 2096 | } else return WValue{ .memory = target_sym_index }; |
| 2097 | } |
| 2098 | |
| 2063 | 2099 | switch (ty.zigTypeTag()) { |
| 2064 | 2100 | .Int => { |
| 2065 | 2101 | const int_info = ty.intInfo(self.target); |
| ... | ... | @@ -2084,25 +2120,6 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2084 | 2120 | else => unreachable, |
| 2085 | 2121 | }, |
| 2086 | 2122 | .Pointer => switch (val.tag()) { |
| 2087 | | .decl_ref => { |
| 2088 | | const decl = val.castTag(.decl_ref).?.data; |
| 2089 | | decl.markAlive(); |
| 2090 | | const target_sym_index = decl.link.wasm.sym_index; |
| 2091 | | if (ty.isSlice()) { |
| 2092 | | var slice_len: Value.Payload.U64 = .{ |
| 2093 | | .base = .{ .tag = .int_u64 }, |
| 2094 | | .data = val.sliceLen(), |
| 2095 | | }; |
| 2096 | | var slice_val: Value.Payload.Slice = .{ |
| 2097 | | .base = .{ .tag = .slice }, |
| 2098 | | .data = .{ .ptr = val.slicePtr(), .len = Value.initPayload(&slice_len.base) }, |
| 2099 | | }; |
| 2100 | | return self.lowerConstant(Value.initPayload(&slice_val.base), ty); |
| 2101 | | } else if (decl.ty.zigTypeTag() == .Fn) { |
| 2102 | | try self.bin_file.addTableFunction(target_sym_index); |
| 2103 | | return WValue{ .function_index = target_sym_index }; |
| 2104 | | } else return WValue{ .memory = target_sym_index }; |
| 2105 | | }, |
| 2106 | 2123 | .elem_ptr => { |
| 2107 | 2124 | const elem_ptr = val.castTag(.elem_ptr).?.data; |
| 2108 | 2125 | const index = elem_ptr.index; |
| ... | ... | @@ -2114,6 +2131,27 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2114 | 2131 | .offset = @intCast(u32, offset), |
| 2115 | 2132 | } }; |
| 2116 | 2133 | }, |
| 2134 | .field_ptr => { |
| 2135 | const field_ptr = val.castTag(.field_ptr).?.data; |
| 2136 | const container = field_ptr.container_ptr; |
| 2137 | const parent_ptr = try self.lowerConstant(container, ty); |
| 2138 | |
| 2139 | const offset = switch (container.tag()) { |
| 2140 | .decl_ref => blk: { |
| 2141 | const decl_ref = container.castTag(.decl_ref).?.data; |
| 2142 | if (decl_ref.ty.castTag(.@"struct")) |_| { |
| 2143 | const offset = decl_ref.ty.structFieldOffset(field_ptr.field_index, self.target); |
| 2144 | break :blk offset; |
| 2145 | } |
| 2146 | return self.fail("Wasm TODO: field_ptr decl_ref for type '{}'", .{decl_ref.ty}); |
| 2147 | }, |
| 2148 | else => |tag| return self.fail("Wasm TODO: Implement field_ptr for value tag: '{s}'", .{tag}), |
| 2149 | }; |
| 2150 | return WValue{ .memory_offset = .{ |
| 2151 | .pointer = parent_ptr.memory, |
| 2152 | .offset = @intCast(u32, offset), |
| 2153 | } }; |
| 2154 | }, |
| 2117 | 2155 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) }, |
| 2118 | 2156 | .zero, .null_value => return WValue{ .imm32 = 0 }, |
| 2119 | 2157 | else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}), |
| ... | ... | @@ -2160,7 +2198,14 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2160 | 2198 | }, |
| 2161 | 2199 | .Optional => if (ty.isPtrLikeOptional()) { |
| 2162 | 2200 | var buf: Type.Payload.ElemType = undefined; |
| 2163 | | return self.lowerConstant(val, ty.optionalChild(&buf)); |
| 2201 | const pl_ty = ty.optionalChild(&buf); |
| 2202 | if (val.castTag(.opt_payload)) |payload| { |
| 2203 | return self.lowerConstant(payload.data, pl_ty); |
| 2204 | } else if (val.isNull()) { |
| 2205 | return WValue{ .imm32 = 0 }; |
| 2206 | } else { |
| 2207 | return self.lowerConstant(val, pl_ty); |
| 2208 | } |
| 2164 | 2209 | } else { |
| 2165 | 2210 | const is_pl = val.tag() == .opt_payload; |
| 2166 | 2211 | return WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 }; |