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 {...@@ -1371,6 +1371,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1371 .aggregate_init => self.airAggregateInit(inst),1371 .aggregate_init => self.airAggregateInit(inst),
1372 .union_init => self.airUnionInit(inst),1372 .union_init => self.airUnionInit(inst),
1373 .prefetch => self.airPrefetch(inst),1373 .prefetch => self.airPrefetch(inst),
1374 .popcount => self.airPopcount(inst),
13741375
1375 .slice => self.airSlice(inst),1376 .slice => self.airSlice(inst),
1376 .slice_len => self.airSliceLen(inst),1377 .slice_len => self.airSliceLen(inst),
...@@ -1419,7 +1420,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1419,7 +1420,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1419 .frame_addr,1420 .frame_addr,
1420 .clz,1421 .clz,
1421 .ctz,1422 .ctz,
1422 .popcount,
1423 .byte_swap,1423 .byte_swap,
1424 .bit_reverse,1424 .bit_reverse,
1425 .is_err_ptr,1425 .is_err_ptr,
...@@ -3565,3 +3565,49 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3565,3 +3565,49 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3565 try self.memcpy(dst, src, len);3565 try self.memcpy(dst, src, len);
3566 return WValue{ .none = {} };3566 return WValue{ .none = {} };
3567}3567}
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 {...@@ -207,6 +207,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
207 .i32_rem_u => try emit.emitTag(tag),207 .i32_rem_u => try emit.emitTag(tag),
208 .i64_rem_s => try emit.emitTag(tag),208 .i64_rem_s => try emit.emitTag(tag),
209 .i64_rem_u => try emit.emitTag(tag),209 .i64_rem_u => try emit.emitTag(tag),
210 .i32_popcnt => try emit.emitTag(tag),
211 .i64_popcnt => try emit.emitTag(tag),
210212
211 .extended => try emit.emitExtended(inst),213 .extended => try emit.emitExtended(inst),
212 }214 }
src/arch/wasm/Mir.zig+4
...@@ -317,6 +317,8 @@ pub const Inst = struct {...@@ -317,6 +317,8 @@ pub const Inst = struct {
317 /// Uses `tag`317 /// Uses `tag`
318 f64_ge = 0x66,318 f64_ge = 0x66,
319 /// Uses `tag`319 /// Uses `tag`
320 i32_popcnt = 0x69,
321 /// Uses `tag`
320 i32_add = 0x6A,322 i32_add = 0x6A,
321 /// Uses `tag`323 /// Uses `tag`
322 i32_sub = 0x6B,324 i32_sub = 0x6B,
...@@ -343,6 +345,8 @@ pub const Inst = struct {...@@ -343,6 +345,8 @@ pub const Inst = struct {
343 /// Uses `tag`345 /// Uses `tag`
344 i32_shr_u = 0x76,346 i32_shr_u = 0x76,
345 /// Uses `tag`347 /// Uses `tag`
348 i64_popcnt = 0x7B,
349 /// Uses `tag`
346 i64_add = 0x7C,350 i64_add = 0x7C,
347 /// Uses `tag`351 /// Uses `tag`
348 i64_sub = 0x7D,352 i64_sub = 0x7D,
test/behavior/popcount.zig+19-8
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
55
6test "@popCount integers" {6test "@popCount integers" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -13,6 +12,25 @@ test "@popCount integers" {...@@ -13,6 +12,25 @@ test "@popCount integers" {
13 try testPopCountIntegers();12 try testPopCountIntegers();
14}13}
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
16fn testPopCountIntegers() !void {34fn testPopCountIntegers() !void {
17 {35 {
18 var x: u32 = 0xffffffff;36 var x: u32 = 0xffffffff;
...@@ -42,16 +60,9 @@ fn testPopCountIntegers() !void {...@@ -42,16 +60,9 @@ fn testPopCountIntegers() !void {
42 var x: i8 = -120;60 var x: i8 = -120;
43 try expect(@popCount(i8, x) == 2);61 try expect(@popCount(i8, x) == 2);
44 }62 }
45 {
46 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
47 try expect(@popCount(u128, x) == 24);
48 }
49 comptime {63 comptime {
50 try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);64 try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);
51 }65 }
52 comptime {
53 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
54 }
55}66}
5667
57test "@popCount vectors" {68test "@popCount vectors" {