authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-02 22:33:36+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2021-12-04 19:22:08+01:00
log52fb0446698c81272ac5224df81b8f965628575e
tree2f6d18b9b14408d42d72dbb9bb6e6784f2a48dc2
parent96a4692f94e202f80ca89a7fb237eb99b6352260
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Implement trunc, fix sliceLen and write undefined


3 files changed, 121 insertions(+), 13 deletions(-)

src/arch/wasm/CodeGen.zig+106-13
......@@ -551,7 +551,7 @@ mir_extra: std.ArrayListUnmanaged(u32) = .{},
551551initial_stack_value: WValue = .none,
552552/// Arguments of this function declaration
553553/// This will be set after `resolveCallingConventionValues`
554args: []WValue = undefined,
554args: []WValue = &.{},
555555/// This will only be `.none` if the function returns void, or returns an immediate.
556556/// When it returns a pointer to the stack, the `.local` tag will be active and must be populated
557557/// before this function returns its execution to the caller.
......@@ -1117,6 +1117,13 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
11171117 try self.addLabel(.global_set, 0);
11181118}
11191119
1120/// From given zig bitsize, returns the wasm bitsize
1121fn toWasmIntBits(bits: u16) ?u16 {
1122 return for ([_]u16{ 32, 64 }) |wasm_bits| {
1123 if (bits <= wasm_bits) return wasm_bits;
1124 } else null;
1125}
1126
11201127fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
11211128 const air_tags = self.air.instructions.items(.tag);
11221129 return switch (air_tags[inst]) {
......@@ -1563,6 +1570,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
15631570}
15641571
15651572fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1573 if (val.isUndefDeep()) return self.emitUndefined(ty);
15661574 switch (ty.zigTypeTag()) {
15671575 .Int => {
15681576 const int_info = ty.intInfo(self.target);
......@@ -1668,6 +1676,22 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
16681676 }
16691677}
16701678
1679fn emitUndefined(self: *Self, ty: Type) InnerError!void {
1680 switch (ty.zigTypeTag()) {
1681 .Int => switch (ty.intInfo(self.target).bits) {
1682 0...32 => try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa))),
1683 33...64 => try self.addImm64(0xaaaaaaaaaaaaaaaa),
1684 else => |bits| return self.fail("Wasm TODO: emitUndefined for integer bitsize: {d}", .{bits}),
1685 },
1686 .Float => switch (ty.floatBits(self.target)) {
1687 0...32 => try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = @bitCast(f32, @as(u32, 0xaaaaaaaa)) } }),
1688 33...64 => try self.addFloat64(@bitCast(f64, @as(u64, 0xaaaaaaaaaaaaaaaa))),
1689 else => |bits| return self.fail("Wasm TODO: emitUndefined for float bitsize: {d}", .{bits}),
1690 },
1691 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
1692 }
1693}
1694
16711695/// Returns a `Value` as a signed 32 bit value.
16721696/// It's illegal to provide a value with a type that cannot be represented
16731697/// as an integer value.
......@@ -2233,19 +2257,21 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22332257 const operand = self.resolveInst(ty_op.operand);
22342258 const pointer_width = self.target.cpu.arch.ptrBitWidth() / 8;
22352259
2236 // Get pointer to slice
2237 try self.emitWValue(operand);
2238 // length of slice is stored after the pointer of the slice
2239 const extra_index = try self.addExtra(Mir.MemArg{
2240 .offset = pointer_width,
2241 .alignment = pointer_width,
2242 });
2243 try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } });
2260 return try self.load(operand, Type.usize, pointer_width);
22442261
2245 const result = try self.allocLocal(Type.initTag(.i32)); // pointer is always i32
2246 // store slice length in local
2247 try self.addLabel(.local_set, result.local);
2248 return result;
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;
22492275}
22502276
22512277fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -2272,3 +2298,70 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22722298 try self.addLabel(.local_set, result.local);
22732299 return result;
22742300}
2301
2302fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2303 if (self.liveness.isUnused(inst)) return WValue.none;
2304 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2305 const operand = self.resolveInst(ty_op.operand);
2306 return try self.load(operand, Type.usize, 0);
2307}
2308
2309fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2310 if (self.liveness.isUnused(inst)) return WValue.none;
2311 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2312 const operand = self.resolveInst(ty_op.operand);
2313 const op_ty = self.air.typeOf(ty_op.operand);
2314 const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);
2315 const wanted_bits = int_info.bits;
2316 const result = try self.allocLocal(self.air.getRefType(ty_op.ty));
2317 const op_bits = op_ty.intInfo(self.target).bits;
2318
2319 const wasm_bits = toWasmIntBits(wanted_bits) orelse
2320 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{wanted_bits});
2321
2322 // Use wasm's instruction to wrap from 64bit to 32bit integer when possible
2323 if (op_bits == 64 and wanted_bits == 32) {
2324 try self.emitWValue(operand);
2325 try self.addTag(.i32_wrap_i64);
2326 try self.addLabel(.local_set, result.local);
2327 return result;
2328 }
2329
2330 // Any other truncation must be done manually
2331 if (int_info.signedness == .unsigned) {
2332 const mask = (@as(u65, 1) << @intCast(u7, wanted_bits)) - 1;
2333 try self.emitWValue(operand);
2334 switch (wasm_bits) {
2335 32 => {
2336 try self.addImm32(@bitCast(i32, @intCast(u32, mask)));
2337 try self.addTag(.i32_and);
2338 },
2339 64 => {
2340 try self.addImm64(@intCast(u64, mask));
2341 try self.addTag(.i64_and);
2342 },
2343 else => unreachable,
2344 }
2345 } else {
2346 const shift_bits = wasm_bits - wanted_bits;
2347 try self.emitWValue(operand);
2348 switch (wasm_bits) {
2349 32 => {
2350 try self.addImm32(@bitCast(i16, shift_bits));
2351 try self.addTag(.i32_shl);
2352 try self.addImm32(@bitCast(i16, shift_bits));
2353 try self.addTag(.i32_shr_s);
2354 },
2355 64 => {
2356 try self.addImm64(shift_bits);
2357 try self.addTag(.i64_shl);
2358 try self.addImm64(shift_bits);
2359 try self.addTag(.i64_shr_s);
2360 },
2361 else => unreachable,
2362 }
2363 }
2364
2365 try self.addLabel(.local_set, result.local);
2366 return result;
2367}
src/arch/wasm/Emit.zig+5
......@@ -147,6 +147,11 @@ pub fn emitMir(emit: *Emit) InnerError!void {
147147 .i64_div_s => try emit.emitTag(tag),
148148 .i64_div_u => try emit.emitTag(tag),
149149 .i64_and => try emit.emitTag(tag),
150 .i64_or => try emit.emitTag(tag),
151 .i64_xor => try emit.emitTag(tag),
152 .i64_shl => try emit.emitTag(tag),
153 .i64_shr_s => try emit.emitTag(tag),
154 .i64_shr_u => try emit.emitTag(tag),
150155 .i32_wrap_i64 => try emit.emitTag(tag),
151156 .i64_extend_i32_s => try emit.emitTag(tag),
152157 .i64_extend_i32_u => try emit.emitTag(tag),
src/arch/wasm/Mir.zig+10
......@@ -348,6 +348,16 @@ pub const Inst = struct {
348348 /// Uses `tag`
349349 i64_and = 0x83,
350350 /// Uses `tag`
351 i64_or = 0x84,
352 /// Uses `tag`
353 i64_xor = 0x85,
354 /// Uses `tag`
355 i64_shl = 0x86,
356 /// Uses `tag`
357 i64_shr_s = 0x87,
358 /// Uses `tag`
359 i64_shr_u = 0x88,
360 /// Uses `tag`
351361 i32_wrap_i64 = 0xA7,
352362 /// Uses `tag`
353363 i64_extend_i32_s = 0xAC,