authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-21 22:03:25+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-21 22:01:34-04:00
logbe579d479753153e78e55b17cb8fd2d55004145b
treef1b36abf4da8bbba446f287bf53f9ec6c0095468
parent71413568389850e821df0784166d840de4d8f96e

wasm: Implement @popCount


4 files changed, 72 insertions(+), 9 deletions(-)

src/arch/wasm/CodeGen.zig+47-1
......@@ -1371,6 +1371,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
13711371 .aggregate_init => self.airAggregateInit(inst),
13721372 .union_init => self.airUnionInit(inst),
13731373 .prefetch => self.airPrefetch(inst),
1374 .popcount => self.airPopcount(inst),
13741375
13751376 .slice => self.airSlice(inst),
13761377 .slice_len => self.airSliceLen(inst),
......@@ -1419,7 +1420,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14191420 .frame_addr,
14201421 .clz,
14211422 .ctz,
1422 .popcount,
14231423 .byte_swap,
14241424 .bit_reverse,
14251425 .is_err_ptr,
......@@ -3565,3 +3565,49 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
35653565 try self.memcpy(dst, src, len);
35663566 return WValue{ .none = {} };
35673567}
3568
3569fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3570 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3571 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3572 const operand = try self.resolveInst(ty_op.operand);
3573 const op_ty = self.air.typeOf(ty_op.operand);
3574
3575 if (op_ty.zigTypeTag() == .Vector) {
3576 return self.fail("TODO: Implement @popCount for vectors", .{});
3577 }
3578
3579 const int_info = op_ty.intInfo(self.target);
3580 const bits = int_info.bits;
3581 const wasm_bits = toWasmBits(bits) orelse {
3582 return self.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits});
3583 };
3584
3585 try self.emitWValue(operand);
3586
3587 // for signed integers we first mask the signedness bit
3588 if (int_info.signedness == .signed and wasm_bits != bits) {
3589 switch (wasm_bits) {
3590 32 => {
3591 const mask = (@as(u32, 1) << @intCast(u5, bits)) - 1;
3592 try self.addImm32(@bitCast(i32, mask));
3593 try self.addTag(.i32_and);
3594 },
3595 64 => {
3596 const mask = (@as(u64, 1) << @intCast(u6, bits)) - 1;
3597 try self.addImm64(mask);
3598 try self.addTag(.i64_and);
3599 },
3600 else => unreachable,
3601 }
3602 }
3603
3604 switch (wasm_bits) {
3605 32 => try self.addTag(.i32_popcnt),
3606 64 => try self.addTag(.i64_popcnt),
3607 else => unreachable,
3608 }
3609
3610 const result = try self.allocLocal(op_ty);
3611 try self.addLabel(.local_set, result.local);
3612 return result;
3613}
src/arch/wasm/Emit.zig+2
......@@ -207,6 +207,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
207207 .i32_rem_u => try emit.emitTag(tag),
208208 .i64_rem_s => try emit.emitTag(tag),
209209 .i64_rem_u => try emit.emitTag(tag),
210 .i32_popcnt => try emit.emitTag(tag),
211 .i64_popcnt => try emit.emitTag(tag),
210212
211213 .extended => try emit.emitExtended(inst),
212214 }
src/arch/wasm/Mir.zig+4
......@@ -317,6 +317,8 @@ pub const Inst = struct {
317317 /// Uses `tag`
318318 f64_ge = 0x66,
319319 /// Uses `tag`
320 i32_popcnt = 0x69,
321 /// Uses `tag`
320322 i32_add = 0x6A,
321323 /// Uses `tag`
322324 i32_sub = 0x6B,
......@@ -343,6 +345,8 @@ pub const Inst = struct {
343345 /// Uses `tag`
344346 i32_shr_u = 0x76,
345347 /// Uses `tag`
348 i64_popcnt = 0x7B,
349 /// Uses `tag`
346350 i64_add = 0x7C,
347351 /// Uses `tag`
348352 i64_sub = 0x7D,
test/behavior/popcount.zig+19-8
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
55
66test "@popCount integers" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -13,6 +12,25 @@ test "@popCount integers" {
1312 try testPopCountIntegers();
1413}
1514
15test "@popCount 128bit integer" {
16 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20
21 comptime {
22 try expect(@popCount(u128, @as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
23 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
24 }
25
26 {
27 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
28 try expect(@popCount(u128, x) == 24);
29 }
30
31 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
32}
33
1634fn testPopCountIntegers() !void {
1735 {
1836 var x: u32 = 0xffffffff;
......@@ -42,16 +60,9 @@ fn testPopCountIntegers() !void {
4260 var x: i8 = -120;
4361 try expect(@popCount(i8, x) == 2);
4462 }
45 {
46 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
47 try expect(@popCount(u128, x) == 24);
48 }
4963 comptime {
5064 try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);
5165 }
52 comptime {
53 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
54 }
5566}
5667
5768test "@popCount vectors" {