| 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,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), | ||
| 1374 | 1375 | ||
| 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 | |||
| 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,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), | ||
| 210 | 212 | ||
| 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; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | ||
| 6 | test "@popCount integers" { | 6 | test "@popCount integers" { |
| 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 8 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 9 | 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 | } |
| 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 | fn testPopCountIntegers() !void { | 34 | fn 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 | } |
| 56 | 67 | ||
| 57 | test "@popCount vectors" { | 68 | test "@popCount vectors" { |