aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-04-02 17:56:11 +0200
committerLuuk de Gram <luuk@degram.dev>2022-04-02 21:54:01 +0200
commit2c40b37f79b1b40b5f22e13131064bcab2191f64 (patch)
treee6cec6c137fde02857b8ced426a4e725641ae707 /src
parentbd27fe2bf58d72dd0cdef73dd4040f2747215b78 (diff)
downloadzig-2c40b37f79b1b40b5f22e13131064bcab2191f64.tar.gz
zig-2c40b37f79b1b40b5f22e13131064bcab2191f64.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/arch/wasm/CodeGen.zig43
1 files changed, 42 insertions, 1 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index cd1aa286e1..f52506c393 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -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;
+}