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.
This commit is contained in:
Luuk de Gram 2022-04-02 17:56:11 +02:00
parent bd27fe2bf5
commit 2c40b37f79

View File

@ -1317,6 +1317,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.mul_with_overflow => self.airBinOpOverflow(inst, .mul),
.clz => self.airClz(inst),
.ctz => self.airCtz(inst),
.cmp_eq => self.airCmp(inst, .eq),
.cmp_gte => self.airCmp(inst, .gte),
@ -1440,7 +1441,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.shl_sat,
.ret_addr,
.frame_addr,
.ctz,
.byte_swap,
.bit_reverse,
.is_err_ptr,
@ -3978,3 +3978,44 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
try self.addLabel(.local_set, result.local);
return result;
}
fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const ty = self.air.typeOf(ty_op.operand);
const result_ty = self.air.typeOfIndex(inst);
if (ty.zigTypeTag() == .Vector) {
return self.fail("TODO: `@ctz` for vectors", .{});
}
const operand = try self.resolveInst(ty_op.operand);
const int_info = ty.intInfo(self.target);
const wasm_bits = toWasmBits(int_info.bits) orelse {
return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
};
switch (wasm_bits) {
32 => {
if (wasm_bits != int_info.bits) {
const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);
const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
try self.emitWValue(bin_op);
} else try self.emitWValue(operand);
try self.addTag(.i32_ctz);
},
64 => {
if (wasm_bits != int_info.bits) {
const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);
const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
try self.emitWValue(bin_op);
} else try self.emitWValue(operand);
try self.addTag(.i64_ctz);
},
else => unreachable,
}
const result = try self.allocLocal(result_ty);
try self.addLabel(.local_set, result.local);
return result;
}