authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-03 21:44:24+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-04 19:22:08+01:00
logb7fe958f44160af17ef19e8e71f1bfb6930f190a
tree259b8b4602e8d1a4240a83e1102b93ed464464c7
parent52fb0446698c81272ac5224df81b8f965628575e
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Implement slice as return type and argument


1 files changed, 60 insertions(+), 38 deletions(-)

src/arch/wasm/CodeGen.zig+60-38
...@@ -1048,7 +1048,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1048,7 +1048,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
10481048
1049 const ret_ty = fn_ty.fnReturnType();1049 const ret_ty = fn_ty.fnReturnType();
1050 switch (ret_ty.zigTypeTag()) {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 .Int, .Float, .Bool, .Void, .NoReturn => {},1052 .Int, .Float, .Bool, .Void, .NoReturn => {},
1053 else => return self.fail("TODO: Implement function return type {}", .{ret_ty}),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,6 +1062,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1062 };1062 };
10631063
1064 try self.moveStack(offset, result.return_value.local);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 else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}),1072 else => return self.fail("TODO implement function parameters for cc '{}' on wasm", .{cc}),
...@@ -1076,10 +1081,6 @@ fn initializeStack(self: *Self) !void {...@@ -1076,10 +1081,6 @@ fn initializeStack(self: *Self) !void {
1076 assert(self.initial_stack_value == .none);1081 assert(self.initial_stack_value == .none);
1077 // reserve space for immediate value1082 // reserve space for immediate value
1078 // get stack pointer global1083 // 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 try self.addLabel(.global_get, 0);1084 try self.addLabel(.global_get, 0);
10841085
1085 // Reserve a local to store the current stack pointer1086 // Reserve a local to store the current stack pointer
...@@ -1108,8 +1109,6 @@ fn restoreStackPointer(self: *Self) !void {...@@ -1108,8 +1109,6 @@ fn restoreStackPointer(self: *Self) !void {
1108/// the result back into the stack pointer.1109/// the result back into the stack pointer.
1109fn moveStack(self: *Self, offset: u32, local: u32) !void {1110fn moveStack(self: *Self, offset: u32, local: u32) !void {
1110 if (offset == 0) return;1111 if (offset == 0) return;
1111 // TODO: Rather than hardcode the stack pointer to position 0,
1112 // have the linker resolve its relocation
1113 try self.addLabel(.global_get, 0);1112 try self.addLabel(.global_get, 0);
1114 try self.addImm32(@bitCast(i32, offset));1113 try self.addImm32(@bitCast(i32, offset));
1115 try self.addTag(.i32_sub);1114 try self.addTag(.i32_sub);
...@@ -1170,11 +1169,15 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1170,11 +1169,15 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1170 .load => self.airLoad(inst),1169 .load => self.airLoad(inst),
1171 .loop => self.airLoop(inst),1170 .loop => self.airLoop(inst),
1172 .not => self.airNot(inst),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 .ret => self.airRet(inst),1175 .ret => self.airRet(inst),
1174 .ret_ptr => self.airRetPtr(inst),1176 .ret_ptr => self.airRetPtr(inst),
1175 .ret_load => self.airRetLoad(inst),1177 .ret_load => self.airRetLoad(inst),
1176 .slice_len => self.airSliceLen(inst),1178 .slice_len => self.airSliceLen(inst),
1177 .slice_elem_val => self.airSliceElemVal(inst),1179 .slice_elem_val => self.airSliceElemVal(inst),
1180 .slice_ptr => self.airSlicePtr(inst),
1178 .store => self.airStore(inst),1181 .store => self.airStore(inst),
1179 .struct_field_ptr => self.airStructFieldPtr(inst),1182 .struct_field_ptr => self.airStructFieldPtr(inst),
1180 .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),1183 .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),
...@@ -1183,17 +1186,14 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1183,17 +1186,14 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1183 .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),1186 .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),
1184 .struct_field_val => self.airStructFieldVal(inst),1187 .struct_field_val => self.airStructFieldVal(inst),
1185 .switch_br => self.airSwitchBr(inst),1188 .switch_br => self.airSwitchBr(inst),
1189 .trunc => self.airTrunc(inst),
1186 .unreach => self.airUnreachable(inst),1190 .unreach => self.airUnreachable(inst),
1187 .wrap_optional => self.airWrapOptional(inst),
11881191
1192 .wrap_optional => self.airWrapOptional(inst),
1189 .unwrap_errunion_payload => self.airUnwrapErrUnionPayload(inst),1193 .unwrap_errunion_payload => self.airUnwrapErrUnionPayload(inst),
1190 .unwrap_errunion_err => self.airUnwrapErrUnionError(inst),1194 .unwrap_errunion_err => self.airUnwrapErrUnionError(inst),
1191 .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),1195 .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),
1192 .wrap_errunion_err => self.airWrapErrUnionErr(inst),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 else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),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,8 +1273,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1273 };1273 };
12741274
1275 for (args) |arg| {1275 for (args) |arg| {
1276 const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg));1276 const arg_ref = @intToEnum(Air.Inst.Ref, arg);
1277 try self.emitWValue(arg_val);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 }
12791296
1280 if (target) |direct| {1297 if (target) |direct| {
...@@ -1296,14 +1313,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1296,14 +1313,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1296 }1313 }
12971314
1298 const ret_ty = fn_ty.fnReturnType();1315 const ret_ty = fn_ty.fnReturnType();
1299 switch (ret_ty.zigTypeTag()) {1316 if (!ret_ty.hasCodeGenBits()) return WValue.none;
1300 .Void, .NoReturn => return WValue.none,1317
1301 else => {1318 const result_local = try self.allocLocal(ret_ty);
1302 const result_local = try self.allocLocal(ret_ty);1319 try self.addLabel(.local_set, result_local.local);
1303 try self.addLabel(.local_set, result_local.local);1320 // if the result was allocated on the virtual stack, we must load
1304 return result_local;1321 return result_local;
1305 },
1306 }
1307}1322}
13081323
1309fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1324fn 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,6 +1422,18 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1407 }1422 }
1408 return;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 else => {},1437 else => {},
1411 }1438 }
1412 try self.emitWValue(lhs);1439 try self.emitWValue(lhs);
...@@ -1598,7 +1625,11 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -1598,7 +1625,11 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1598 }1625 }
1599 },1626 },
1600 .Pointer => {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 const decl = payload.data;1633 const decl = payload.data;
1603 decl.alive = true;1634 decl.alive = true;
1604 try self.addLabel(.memory_address, decl.link.wasm.sym_index);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,20 +2289,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2258 const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8;2289 const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8;
22592290
2260 return try self.load(operand, Type.usize, pointer_width);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}
22762293
2277fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2294fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2296,7 +2313,12 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2296,7 +2313,12 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22962313
2297 const result = try self.allocLocal(elem_ty);2314 const result = try self.allocLocal(elem_ty);
2298 try self.addLabel(.local_set, result.local);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}
23012323
2302fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2324fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {