mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
wasm: Implement @popCount
This commit is contained in:
parent
7141356838
commit
be579d4797
@ -1371,6 +1371,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
.aggregate_init => self.airAggregateInit(inst),
|
||||
.union_init => self.airUnionInit(inst),
|
||||
.prefetch => self.airPrefetch(inst),
|
||||
.popcount => self.airPopcount(inst),
|
||||
|
||||
.slice => self.airSlice(inst),
|
||||
.slice_len => self.airSliceLen(inst),
|
||||
@ -1419,7 +1420,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
.frame_addr,
|
||||
.clz,
|
||||
.ctz,
|
||||
.popcount,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
.is_err_ptr,
|
||||
@ -3565,3 +3565,49 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
try self.memcpy(dst, src, len);
|
||||
return WValue{ .none = {} };
|
||||
}
|
||||
|
||||
fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const op_ty = self.air.typeOf(ty_op.operand);
|
||||
|
||||
if (op_ty.zigTypeTag() == .Vector) {
|
||||
return self.fail("TODO: Implement @popCount for vectors", .{});
|
||||
}
|
||||
|
||||
const int_info = op_ty.intInfo(self.target);
|
||||
const bits = int_info.bits;
|
||||
const wasm_bits = toWasmBits(bits) orelse {
|
||||
return self.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits});
|
||||
};
|
||||
|
||||
try self.emitWValue(operand);
|
||||
|
||||
// for signed integers we first mask the signedness bit
|
||||
if (int_info.signedness == .signed and wasm_bits != bits) {
|
||||
switch (wasm_bits) {
|
||||
32 => {
|
||||
const mask = (@as(u32, 1) << @intCast(u5, bits)) - 1;
|
||||
try self.addImm32(@bitCast(i32, mask));
|
||||
try self.addTag(.i32_and);
|
||||
},
|
||||
64 => {
|
||||
const mask = (@as(u64, 1) << @intCast(u6, bits)) - 1;
|
||||
try self.addImm64(mask);
|
||||
try self.addTag(.i64_and);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
switch (wasm_bits) {
|
||||
32 => try self.addTag(.i32_popcnt),
|
||||
64 => try self.addTag(.i64_popcnt),
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
const result = try self.allocLocal(op_ty);
|
||||
try self.addLabel(.local_set, result.local);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -207,6 +207,8 @@ pub fn emitMir(emit: *Emit) InnerError!void {
|
||||
.i32_rem_u => try emit.emitTag(tag),
|
||||
.i64_rem_s => try emit.emitTag(tag),
|
||||
.i64_rem_u => try emit.emitTag(tag),
|
||||
.i32_popcnt => try emit.emitTag(tag),
|
||||
.i64_popcnt => try emit.emitTag(tag),
|
||||
|
||||
.extended => try emit.emitExtended(inst),
|
||||
}
|
||||
|
||||
@ -317,6 +317,8 @@ pub const Inst = struct {
|
||||
/// Uses `tag`
|
||||
f64_ge = 0x66,
|
||||
/// Uses `tag`
|
||||
i32_popcnt = 0x69,
|
||||
/// Uses `tag`
|
||||
i32_add = 0x6A,
|
||||
/// Uses `tag`
|
||||
i32_sub = 0x6B,
|
||||
@ -343,6 +345,8 @@ pub const Inst = struct {
|
||||
/// Uses `tag`
|
||||
i32_shr_u = 0x76,
|
||||
/// Uses `tag`
|
||||
i64_popcnt = 0x7B,
|
||||
/// Uses `tag`
|
||||
i64_add = 0x7C,
|
||||
/// Uses `tag`
|
||||
i64_sub = 0x7D,
|
||||
|
||||
@ -4,7 +4,6 @@ const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
test "@popCount integers" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
@ -13,6 +12,25 @@ test "@popCount integers" {
|
||||
try testPopCountIntegers();
|
||||
}
|
||||
|
||||
test "@popCount 128bit integer" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
comptime {
|
||||
try expect(@popCount(u128, @as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
|
||||
try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
|
||||
}
|
||||
|
||||
{
|
||||
var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
|
||||
try expect(@popCount(u128, x) == 24);
|
||||
}
|
||||
|
||||
try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
|
||||
}
|
||||
|
||||
fn testPopCountIntegers() !void {
|
||||
{
|
||||
var x: u32 = 0xffffffff;
|
||||
@ -42,16 +60,9 @@ fn testPopCountIntegers() !void {
|
||||
var x: i8 = -120;
|
||||
try expect(@popCount(i8, x) == 2);
|
||||
}
|
||||
{
|
||||
var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
|
||||
try expect(@popCount(u128, x) == 24);
|
||||
}
|
||||
comptime {
|
||||
try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);
|
||||
}
|
||||
comptime {
|
||||
try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
|
||||
}
|
||||
}
|
||||
|
||||
test "@popCount vectors" {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user