authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 17:56:11+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 21:54:01+02:00
log2c40b37f79b1b40b5f22e13131064bcab2191f64
treee6cec6c137fde02857b8ced426a4e725641ae707
parentbd27fe2bf58d72dd0cdef73dd4040f2747215b78

wasm: Implement `@ctz` for bitsize <= 64

Implements the `ctz` AIR instruction for integers with bitsize <= 64. When the bitsize of the integer does not match the bitsize of a wasm type, we first XOR the value with the value of (1<<bitsize) to set the right bits and ensure we will only count the trailing zeroes of the integer with the correct bitsize.

1 files changed, 42 insertions(+), 1 deletions(-)

src/arch/wasm/CodeGen.zig+42-1
...@@ -1317,6 +1317,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1317,6 +1317,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1317 .mul_with_overflow => self.airBinOpOverflow(inst, .mul),1317 .mul_with_overflow => self.airBinOpOverflow(inst, .mul),
13181318
1319 .clz => self.airClz(inst),1319 .clz => self.airClz(inst),
1320 .ctz => self.airCtz(inst),
13201321
1321 .cmp_eq => self.airCmp(inst, .eq),1322 .cmp_eq => self.airCmp(inst, .eq),
1322 .cmp_gte => self.airCmp(inst, .gte),1323 .cmp_gte => self.airCmp(inst, .gte),
...@@ -1440,7 +1441,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1440,7 +1441,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1440 .shl_sat,1441 .shl_sat,
1441 .ret_addr,1442 .ret_addr,
1442 .frame_addr,1443 .frame_addr,
1443 .ctz,
1444 .byte_swap,1444 .byte_swap,
1445 .bit_reverse,1445 .bit_reverse,
1446 .is_err_ptr,1446 .is_err_ptr,
...@@ -3978,3 +3978,44 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3978,3 +3978,44 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3978 try self.addLabel(.local_set, result.local);3978 try self.addLabel(.local_set, result.local);
3979 return result;3979 return result;
3980}3980}
3981
3982fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3983 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3984 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3985 const ty = self.air.typeOf(ty_op.operand);
3986 const result_ty = self.air.typeOfIndex(inst);
3987
3988 if (ty.zigTypeTag() == .Vector) {
3989 return self.fail("TODO: `@ctz` for vectors", .{});
3990 }
3991
3992 const operand = try self.resolveInst(ty_op.operand);
3993 const int_info = ty.intInfo(self.target);
3994 const wasm_bits = toWasmBits(int_info.bits) orelse {
3995 return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
3996 };
3997
3998 switch (wasm_bits) {
3999 32 => {
4000 if (wasm_bits != int_info.bits) {
4001 const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);
4002 const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
4003 try self.emitWValue(bin_op);
4004 } else try self.emitWValue(operand);
4005 try self.addTag(.i32_ctz);
4006 },
4007 64 => {
4008 if (wasm_bits != int_info.bits) {
4009 const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);
4010 const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
4011 try self.emitWValue(bin_op);
4012 } else try self.emitWValue(operand);
4013 try self.addTag(.i64_ctz);
4014 },
4015 else => unreachable,
4016 }
4017
4018 const result = try self.allocLocal(result_ty);
4019 try self.addLabel(.local_set, result.local);
4020 return result;
4021}