authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-03 23:48:44+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-04 17:51:49+01:00
log5c21a45cf0a22f68ac15f7db8829186ff1808a84
treef015dca4d245f43f657fb6b9a0974566ddba4e37
parentc888485f854111ba20bb35255c6e82c99af31a03
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Implement 'slice' instruction

Emitting undefined ptr's also has been implemented. This means we now pass the void.zig behavior tests.

1 files changed, 31 insertions(+), 11 deletions(-)

src/arch/wasm/CodeGen.zig+31-11
...@@ -1088,19 +1088,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1088,19 +1088,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1088 }1088 }
10891089
1090 const ret_ty = fn_ty.fnReturnType();1090 const ret_ty = fn_ty.fnReturnType();
1091 if (isByRef(ret_ty)) {
1092 result.return_value = try self.allocLocal(Type.initTag(.i32));
1093 }
1094
1095 // Check if we store the result as a pointer to the stack rather than1091 // Check if we store the result as a pointer to the stack rather than
1096 // by value1092 // by value
1097 if (result.return_value != .none) {1093 if (isByRef(ret_ty)) {
1098 if (self.initial_stack_value == .none) try self.initializeStack();1094 if (self.initial_stack_value == .none) try self.initializeStack();
1099 const offset = std.math.cast(u32, ret_ty.abiSize(self.target)) catch {1095 result.return_value = try self.allocStack(ret_ty);
1100 return self.fail("Return type '{}' too big for stack frame", .{ret_ty});
1101 };
1102
1103 try self.moveStack(offset, result.return_value.local);
11041096
1105 // We want to make sure the return value's stack value doesn't get overwritten,1097 // We want to make sure the return value's stack value doesn't get overwritten,
1106 // so set initial stack value to current's position instead.1098 // so set initial stack value to current's position instead.
...@@ -1165,10 +1157,16 @@ fn allocStack(self: *Self, ty: Type) !WValue {...@@ -1165,10 +1157,16 @@ fn allocStack(self: *Self, ty: Type) !WValue {
1165 assert(ty.hasCodeGenBits());1157 assert(ty.hasCodeGenBits());
11661158
1167 // calculate needed stack space1159 // calculate needed stack space
1168 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {1160 var abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {
1169 return self.fail("Given type '{}' too big to fit into stack frame", .{ty});1161 return self.fail("Given type '{}' too big to fit into stack frame", .{ty});
1170 };1162 };
11711163
1164 // We store slices as a struct with a pointer field and a length field
1165 // both being 'usize' size.
1166 if (ty.isSlice()) {
1167 abi_size = self.ptrSize() * 2;
1168 }
1169
1172 // allocate a local using wasm's pointer size1170 // allocate a local using wasm's pointer size
1173 const local = try self.allocLocal(Type.@"usize");1171 const local = try self.allocLocal(Type.@"usize");
1174 try self.moveStack(abi_size, local.local);1172 try self.moveStack(abi_size, local.local);
...@@ -1337,6 +1335,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1337,6 +1335,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1337 .ret => self.airRet(inst),1335 .ret => self.airRet(inst),
1338 .ret_ptr => self.airRetPtr(inst),1336 .ret_ptr => self.airRetPtr(inst),
1339 .ret_load => self.airRetLoad(inst),1337 .ret_load => self.airRetLoad(inst),
1338 .slice => self.airSlice(inst),
1340 .slice_len => self.airSliceLen(inst),1339 .slice_len => self.airSliceLen(inst),
1341 .slice_elem_val => self.airSliceElemVal(inst),1340 .slice_elem_val => self.airSliceElemVal(inst),
1342 .slice_elem_ptr => self.airSliceElemPtr(inst),1341 .slice_elem_ptr => self.airSliceElemPtr(inst),
...@@ -1994,6 +1993,11 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {...@@ -1994,6 +1993,11 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!void {
1994 const result = try self.allocStack(ty);1993 const result = try self.allocStack(ty);
1995 try self.addLabel(.local_get, result.local);1994 try self.addLabel(.local_get, result.local);
1996 },1995 },
1996 .Pointer => switch (self.ptrSize()) {
1997 4 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),
1998 8 => try self.addImm64(0xaaaaaaaaaaaaaaaa),
1999 else => unreachable,
2000 },
1997 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),2001 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
1998 }2002 }
1999}2003}
...@@ -2673,6 +2677,22 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2673,6 +2677,22 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2673 return result;2677 return result;
2674}2678}
26752679
2680fn airSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2681 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2682
2683 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2684 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2685 const lhs = self.resolveInst(bin_op.lhs);
2686 const rhs = self.resolveInst(bin_op.rhs);
2687 const slice_ty = self.air.typeOfIndex(inst);
2688
2689 const slice = try self.allocStack(slice_ty);
2690 try self.store(slice, lhs, Type.usize, 0);
2691 try self.store(slice, rhs, Type.usize, self.ptrSize());
2692
2693 return slice;
2694}
2695
2676fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2696fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2677 if (self.liveness.isUnused(inst)) return WValue.none;2697 if (self.liveness.isUnused(inst)) return WValue.none;
26782698