diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-04-02 17:56:11 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-04-02 21:54:01 +0200 |
| commit | 2c40b37f79b1b40b5f22e13131064bcab2191f64 (patch) | |
| tree | e6cec6c137fde02857b8ced426a4e725641ae707 /src | |
| parent | bd27fe2bf58d72dd0cdef73dd4040f2747215b78 (diff) | |
| download | zig-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.zig | 43 |
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; +} |
