authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 17:34:24+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-04-02 21:54:01+02:00
logbd27fe2bf58d72dd0cdef73dd4040f2747215b78
tree1eb058d93436940069ae6bf578207b3c1b1d7f67
parent5ba03369ee11b6b57dcad99ab7ed8ce3b08c7456

wasm: Implement `@clz`

Implements the `clz` AIR instruction for integers with bitsize <= 64. When the bitsize of the integer is not the same as wasm's bitsize, we substract the difference in bits as those will always be 0 for the integer, but should not be counted towards the end result. We also wrap the result to ensure it fits in the result type as documented in the language reference.

3 files changed, 59 insertions(+), 1 deletions(-)

src/arch/wasm/CodeGen.zig+47-1
......@@ -1316,6 +1316,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
13161316 .shl_with_overflow => self.airBinOpOverflow(inst, .shl),
13171317 .mul_with_overflow => self.airBinOpOverflow(inst, .mul),
13181318
1319 .clz => self.airClz(inst),
1320
13191321 .cmp_eq => self.airCmp(inst, .eq),
13201322 .cmp_gte => self.airCmp(inst, .gte),
13211323 .cmp_gt => self.airCmp(inst, .gt),
......@@ -1438,7 +1440,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14381440 .shl_sat,
14391441 .ret_addr,
14401442 .frame_addr,
1441 .clz,
14421443 .ctz,
14431444 .byte_swap,
14441445 .bit_reverse,
......@@ -3932,3 +3933,48 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
39323933 const mul_result = try self.binOp(lhs, rhs, ty, .mul);
39333934 return self.binOp(mul_result, addend, ty, .add);
39343935}
3936
3937fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3938 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3939 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3940 const ty = self.air.typeOf(ty_op.operand);
3941 const result_ty = self.air.typeOfIndex(inst);
3942 if (ty.zigTypeTag() == .Vector) {
3943 return self.fail("TODO: `@clz` for vectors", .{});
3944 }
3945
3946 const operand = try self.resolveInst(ty_op.operand);
3947 const int_info = ty.intInfo(self.target);
3948 const wasm_bits = toWasmBits(int_info.bits) orelse {
3949 return self.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits});
3950 };
3951
3952 try self.emitWValue(operand);
3953 switch (wasm_bits) {
3954 32 => {
3955 try self.addTag(.i32_clz);
3956
3957 if (wasm_bits != int_info.bits) {
3958 const tmp = try self.allocLocal(ty);
3959 try self.addLabel(.local_set, tmp.local);
3960 const val: i32 = -@intCast(i32, wasm_bits - int_info.bits);
3961 return self.wrapBinOp(tmp, .{ .imm32 = @bitCast(u32, val) }, ty, .add);
3962 }
3963 },
3964 64 => {
3965 try self.addTag(.i64_clz);
3966
3967 if (wasm_bits != int_info.bits) {
3968 const tmp = try self.allocLocal(ty);
3969 try self.addLabel(.local_set, tmp.local);
3970 const val: i64 = -@intCast(i64, wasm_bits - int_info.bits);
3971 return self.wrapBinOp(tmp, .{ .imm64 = @bitCast(u64, val) }, ty, .add);
3972 }
3973 },
3974 else => unreachable,
3975 }
3976
3977 const result = try self.allocLocal(result_ty);
3978 try self.addLabel(.local_set, result.local);
3979 return result;
3980}
src/arch/wasm/Emit.zig+4
......@@ -217,6 +217,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {
217217 .i64_rem_u => try emit.emitTag(tag),
218218 .i32_popcnt => try emit.emitTag(tag),
219219 .i64_popcnt => try emit.emitTag(tag),
220 .i32_clz => try emit.emitTag(tag),
221 .i32_ctz => try emit.emitTag(tag),
222 .i64_clz => try emit.emitTag(tag),
223 .i64_ctz => try emit.emitTag(tag),
220224
221225 .extended => try emit.emitExtended(inst),
222226 }
src/arch/wasm/Mir.zig+8
......@@ -317,6 +317,10 @@ pub const Inst = struct {
317317 /// Uses `tag`
318318 f64_ge = 0x66,
319319 /// Uses `tag`
320 i32_clz = 0x67,
321 /// Uses `tag`
322 i32_ctz = 0x68,
323 /// Uses `tag`
320324 i32_popcnt = 0x69,
321325 /// Uses `tag`
322326 i32_add = 0x6A,
......@@ -345,6 +349,10 @@ pub const Inst = struct {
345349 /// Uses `tag`
346350 i32_shr_u = 0x76,
347351 /// Uses `tag`
352 i64_clz = 0x79,
353 /// Uses `tag`
354 i64_ctz = 0x7A,
355 /// Uses `tag`
348356 i64_popcnt = 0x7B,
349357 /// Uses `tag`
350358 i64_add = 0x7C,