aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/wasm/CodeGen.zig48
-rw-r--r--src/arch/wasm/Emit.zig4
-rw-r--r--src/arch/wasm/Mir.zig8
3 files changed, 59 insertions, 1 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 9cb61ca4ee..cd1aa286e1 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1316,6 +1316,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.shl_with_overflow => self.airBinOpOverflow(inst, .shl),
.mul_with_overflow => self.airBinOpOverflow(inst, .mul),
+ .clz => self.airClz(inst),
+
.cmp_eq => self.airCmp(inst, .eq),
.cmp_gte => self.airCmp(inst, .gte),
.cmp_gt => self.airCmp(inst, .gt),
@@ -1438,7 +1440,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.shl_sat,
.ret_addr,
.frame_addr,
- .clz,
.ctz,
.byte_swap,
.bit_reverse,
@@ -3932,3 +3933,48 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const mul_result = try self.binOp(lhs, rhs, ty, .mul);
return self.binOp(mul_result, addend, ty, .add);
}
+
+fn airClz(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: `@clz` 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});
+ };
+
+ try self.emitWValue(operand);
+ switch (wasm_bits) {
+ 32 => {
+ try self.addTag(.i32_clz);
+
+ if (wasm_bits != int_info.bits) {
+ const tmp = try self.allocLocal(ty);
+ try self.addLabel(.local_set, tmp.local);
+ const val: i32 = -@intCast(i32, wasm_bits - int_info.bits);
+ return self.wrapBinOp(tmp, .{ .imm32 = @bitCast(u32, val) }, ty, .add);
+ }
+ },
+ 64 => {
+ try self.addTag(.i64_clz);
+
+ if (wasm_bits != int_info.bits) {
+ const tmp = try self.allocLocal(ty);
+ try self.addLabel(.local_set, tmp.local);
+ const val: i64 = -@intCast(i64, wasm_bits - int_info.bits);
+ return self.wrapBinOp(tmp, .{ .imm64 = @bitCast(u64, val) }, ty, .add);
+ }
+ },
+ else => unreachable,
+ }
+
+ const result = try self.allocLocal(result_ty);
+ try self.addLabel(.local_set, result.local);
+ return result;
+}
diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig
index 7487b014be..6fc2dfa3b3 100644
--- a/src/arch/wasm/Emit.zig
+++ b/src/arch/wasm/Emit.zig
@@ -217,6 +217,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.i64_rem_u => try emit.emitTag(tag),
.i32_popcnt => try emit.emitTag(tag),
.i64_popcnt => try emit.emitTag(tag),
+ .i32_clz => try emit.emitTag(tag),
+ .i32_ctz => try emit.emitTag(tag),
+ .i64_clz => try emit.emitTag(tag),
+ .i64_ctz => try emit.emitTag(tag),
.extended => try emit.emitExtended(inst),
}
diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig
index 395e9bb17c..27f683cf1e 100644
--- a/src/arch/wasm/Mir.zig
+++ b/src/arch/wasm/Mir.zig
@@ -317,6 +317,10 @@ pub const Inst = struct {
/// Uses `tag`
f64_ge = 0x66,
/// Uses `tag`
+ i32_clz = 0x67,
+ /// Uses `tag`
+ i32_ctz = 0x68,
+ /// Uses `tag`
i32_popcnt = 0x69,
/// Uses `tag`
i32_add = 0x6A,
@@ -345,6 +349,10 @@ pub const Inst = struct {
/// Uses `tag`
i32_shr_u = 0x76,
/// Uses `tag`
+ i64_clz = 0x79,
+ /// Uses `tag`
+ i64_ctz = 0x7A,
+ /// Uses `tag`
i64_popcnt = 0x7B,
/// Uses `tag`
i64_add = 0x7C,