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