| ... | ... | @@ -1048,7 +1048,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1048 | 1048 | |
| 1049 | 1049 | const ret_ty = fn_ty.fnReturnType(); |
| 1050 | 1050 | switch (ret_ty.zigTypeTag()) { |
| 1051 | | .ErrorUnion, .Optional => result.return_value = try self.allocLocal(Type.initTag(.i32)), |
| 1051 | .ErrorUnion, .Optional, .Pointer => result.return_value = try self.allocLocal(Type.initTag(.i32)), |
| 1052 | 1052 | .Int, .Float, .Bool, .Void, .NoReturn => {}, |
| 1053 | 1053 | else => return self.fail("TODO: Implement function return type {}", .{ret_ty}), |
| 1054 | 1054 | } |
| ... | ... | @@ -1062,6 +1062,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 1062 | 1062 | }; |
| 1063 | 1063 | |
| 1064 | 1064 | try self.moveStack(offset, result.return_value.local); |
| 1065 | |
| 1066 | // We want to make sure the return value's stack value doesn't get overwritten, |
| 1067 | // so set initial stack value to current's position instead. |
| 1068 | try self.addLabel(.global_get, 0); |
| 1069 | try self.addLabel(.local_set, self.initial_stack_value.local); |
| 1065 | 1070 | } |
| 1066 | 1071 | }, |
| 1067 | 1072 | else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}), |
| ... | ... | @@ -1076,10 +1081,6 @@ fn initializeStack(self: *Self) !void { |
| 1076 | 1081 | assert(self.initial_stack_value == .none); |
| 1077 | 1082 | // reserve space for immediate value |
| 1078 | 1083 | // get stack pointer global |
| 1079 | | // TODO: For now, we hardcode the stack pointer to index '0', |
| 1080 | | // once the linker is further implemented, we can replace this by inserting |
| 1081 | | // a relocation and have the linker resolve the correct index to the stack pointer global. |
| 1082 | | // NOTE: relocations of the type GLOBAL_INDEX_LEB are 5-bytes big |
| 1083 | 1084 | try self.addLabel(.global_get, 0); |
| 1084 | 1085 | |
| 1085 | 1086 | // Reserve a local to store the current stack pointer |
| ... | ... | @@ -1108,8 +1109,6 @@ fn restoreStackPointer(self: *Self) !void { |
| 1108 | 1109 | /// the result back into the stack pointer. |
| 1109 | 1110 | fn moveStack(self: *Self, offset: u32, local: u32) !void { |
| 1110 | 1111 | if (offset == 0) return; |
| 1111 | | // TODO: Rather than hardcode the stack pointer to position 0, |
| 1112 | | // have the linker resolve its relocation |
| 1113 | 1112 | try self.addLabel(.global_get, 0); |
| 1114 | 1113 | try self.addImm32(@bitCast(i32, offset)); |
| 1115 | 1114 | try self.addTag(.i32_sub); |
| ... | ... | @@ -1170,11 +1169,15 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1170 | 1169 | .load => self.airLoad(inst), |
| 1171 | 1170 | .loop => self.airLoop(inst), |
| 1172 | 1171 | .not => self.airNot(inst), |
| 1172 | .optional_payload => self.airOptionalPayload(inst), |
| 1173 | .optional_payload_ptr => self.airOptionalPayload(inst), |
| 1174 | .optional_payload_ptr_set => self.airOptionalPayloadPtrSet(inst), |
| 1173 | 1175 | .ret => self.airRet(inst), |
| 1174 | 1176 | .ret_ptr => self.airRetPtr(inst), |
| 1175 | 1177 | .ret_load => self.airRetLoad(inst), |
| 1176 | 1178 | .slice_len => self.airSliceLen(inst), |
| 1177 | 1179 | .slice_elem_val => self.airSliceElemVal(inst), |
| 1180 | .slice_ptr => self.airSlicePtr(inst), |
| 1178 | 1181 | .store => self.airStore(inst), |
| 1179 | 1182 | .struct_field_ptr => self.airStructFieldPtr(inst), |
| 1180 | 1183 | .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0), |
| ... | ... | @@ -1183,17 +1186,14 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1183 | 1186 | .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3), |
| 1184 | 1187 | .struct_field_val => self.airStructFieldVal(inst), |
| 1185 | 1188 | .switch_br => self.airSwitchBr(inst), |
| 1189 | .trunc => self.airTrunc(inst), |
| 1186 | 1190 | .unreach => self.airUnreachable(inst), |
| 1187 | | .wrap_optional => self.airWrapOptional(inst), |
| 1188 | 1191 | |
| 1192 | .wrap_optional => self.airWrapOptional(inst), |
| 1189 | 1193 | .unwrap_errunion_payload => self.airUnwrapErrUnionPayload(inst), |
| 1190 | 1194 | .unwrap_errunion_err => self.airUnwrapErrUnionError(inst), |
| 1191 | 1195 | .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), |
| 1192 | 1196 | .wrap_errunion_err => self.airWrapErrUnionErr(inst), |
| 1193 | | |
| 1194 | | .optional_payload => self.airOptionalPayload(inst), |
| 1195 | | .optional_payload_ptr => self.airOptionalPayload(inst), |
| 1196 | | .optional_payload_ptr_set => self.airOptionalPayloadPtrSet(inst), |
| 1197 | 1197 | else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1198 | 1198 | }; |
| 1199 | 1199 | } |
| ... | ... | @@ -1273,8 +1273,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1273 | 1273 | }; |
| 1274 | 1274 | |
| 1275 | 1275 | for (args) |arg| { |
| 1276 | | const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg)); |
| 1277 | | try self.emitWValue(arg_val); |
| 1276 | const arg_ref = @intToEnum(Air.Inst.Ref, arg); |
| 1277 | const arg_val = self.resolveInst(arg_ref); |
| 1278 | |
| 1279 | const arg_ty = self.air.typeOf(arg_ref); |
| 1280 | switch (arg_ty.zigTypeTag()) { |
| 1281 | .Struct, .Pointer, .Optional, .ErrorUnion => { |
| 1282 | // single pointer can be passed directly |
| 1283 | if (arg_ty.isSinglePointer() or arg_val != .constant) { |
| 1284 | try self.emitWValue(arg_val); |
| 1285 | continue; |
| 1286 | } |
| 1287 | const abi_size = arg_ty.abiSize(self.target); |
| 1288 | const arg_local = try self.allocLocal(Type.initTag(.i32)); |
| 1289 | try self.moveStack(@intCast(u32, abi_size), arg_local.local); |
| 1290 | try self.store(arg_local, arg_val, arg_ty, 0); |
| 1291 | try self.emitWValue(arg_local); |
| 1292 | }, |
| 1293 | else => try self.emitWValue(arg_val), |
| 1294 | } |
| 1278 | 1295 | } |
| 1279 | 1296 | |
| 1280 | 1297 | if (target) |direct| { |
| ... | ... | @@ -1296,14 +1313,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1296 | 1313 | } |
| 1297 | 1314 | |
| 1298 | 1315 | const ret_ty = fn_ty.fnReturnType(); |
| 1299 | | switch (ret_ty.zigTypeTag()) { |
| 1300 | | .Void, .NoReturn => return WValue.none, |
| 1301 | | else => { |
| 1302 | | const result_local = try self.allocLocal(ret_ty); |
| 1303 | | try self.addLabel(.local_set, result_local.local); |
| 1304 | | return result_local; |
| 1305 | | }, |
| 1306 | | } |
| 1316 | if (!ret_ty.hasCodeGenBits()) return WValue.none; |
| 1317 | |
| 1318 | const result_local = try self.allocLocal(ret_ty); |
| 1319 | try self.addLabel(.local_set, result_local.local); |
| 1320 | // if the result was allocated on the virtual stack, we must load |
| 1321 | return result_local; |
| 1307 | 1322 | } |
| 1308 | 1323 | |
| 1309 | 1324 | fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -1407,6 +1422,18 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1407 | 1422 | } |
| 1408 | 1423 | return; |
| 1409 | 1424 | }, |
| 1425 | .Pointer => { |
| 1426 | if (ty.isSlice() and rhs == .constant) { |
| 1427 | try self.emitWValue(rhs); |
| 1428 | const len_local = try self.allocLocal(Type.usize); |
| 1429 | const ptr_local = try self.allocLocal(Type.usize); |
| 1430 | try self.addLabel(.local_set, len_local.local); |
| 1431 | try self.addLabel(.local_set, ptr_local.local); |
| 1432 | try self.store(lhs, ptr_local, Type.usize, 0); |
| 1433 | try self.store(lhs, len_local, Type.usize, self.target.cpu.arch.ptrBitWidth() / 8); |
| 1434 | return; |
| 1435 | } |
| 1436 | }, |
| 1410 | 1437 | else => {}, |
| 1411 | 1438 | } |
| 1412 | 1439 | try self.emitWValue(lhs); |
| ... | ... | @@ -1598,7 +1625,11 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { |
| 1598 | 1625 | } |
| 1599 | 1626 | }, |
| 1600 | 1627 | .Pointer => { |
| 1601 | | if (val.castTag(.decl_ref)) |payload| { |
| 1628 | if (val.castTag(.slice)) |slice| { |
| 1629 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1630 | try self.emitConstant(slice.data.ptr, ty.slicePtrFieldType(&buf)); |
| 1631 | try self.emitConstant(slice.data.len, Type.usize); |
| 1632 | } else if (val.castTag(.decl_ref)) |payload| { |
| 1602 | 1633 | const decl = payload.data; |
| 1603 | 1634 | decl.alive = true; |
| 1604 | 1635 | try self.addLabel(.memory_address, decl.link.wasm.sym_index); |
| ... | ... | @@ -2258,20 +2289,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2258 | 2289 | const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8; |
| 2259 | 2290 | |
| 2260 | 2291 | return try self.load(operand, Type.usize, pointer_width); |
| 2261 | | |
| 2262 | | // // Get pointer to slice |
| 2263 | | // try self.emitWValue(operand); |
| 2264 | | // // length of slice is stored after the pointer of the slice |
| 2265 | | // const extra_index = try self.addExtra(Mir.MemArg{ |
| 2266 | | // .offset = pointer_width, |
| 2267 | | // .alignment = pointer_width, |
| 2268 | | // }); |
| 2269 | | // try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } }); |
| 2270 | | |
| 2271 | | // const result = try self.allocLocal(Type.initTag(.i32)); // pointer is always i32 |
| 2272 | | // // store slice length in local |
| 2273 | | // try self.addLabel(.local_set, result.local); |
| 2274 | | // return result; |
| 2275 | 2292 | } |
| 2276 | 2293 | |
| 2277 | 2294 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -2296,7 +2313,12 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2296 | 2313 | |
| 2297 | 2314 | const result = try self.allocLocal(elem_ty); |
| 2298 | 2315 | try self.addLabel(.local_set, result.local); |
| 2299 | | return result; |
| 2316 | return switch (elem_ty.zigTypeTag()) { |
| 2317 | // pass as pointer |
| 2318 | .Pointer, .Struct, .Optional => result, |
| 2319 | // pass by value |
| 2320 | else => try self.load(result, elem_ty, 0), |
| 2321 | }; |
| 2300 | 2322 | } |
| 2301 | 2323 | |
| 2302 | 2324 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |