diff --git a/doc/langref.html.in b/doc/langref.html.in index 0e3e32c52a2c..9e98bb011411 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7366,18 +7366,20 @@ pub const CallOptions = struct { {#header_close#} {#header_open|@clz#} -
{#syntax#}@clz(comptime T: type, integer: T){#endsyntax#}
+
{#syntax#}@clz(comptime T: type, operand: T){#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type.

+

{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.

- This function counts the number of most-significant (leading in a big-Endian sense) zeroes in {#syntax#}integer{#endsyntax#}. + This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.

- If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, + If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer, the return type is {#syntax#}comptime_int{#endsyntax#}. - Otherwise, the return type is an unsigned integer with the minimum number + Otherwise, the return type is an unsigned integer or vector of unsigned integers with the minimum number of bits that can represent the bit count of the integer type.

- If {#syntax#}integer{#endsyntax#} is zero, {#syntax#}@clz{#endsyntax#} returns the bit width + If {#syntax#}operand{#endsyntax#} is zero, {#syntax#}@clz{#endsyntax#} returns the bit width of integer type {#syntax#}T{#endsyntax#}.

{#see_also|@ctz|@popCount#} @@ -7509,18 +7511,20 @@ test "main" { {#header_close#} {#header_open|@ctz#} -
{#syntax#}@ctz(comptime T: type, integer: T){#endsyntax#}
+
{#syntax#}@ctz(comptime T: type, operand: T){#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type.

+

{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.

- This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in {#syntax#}integer{#endsyntax#}. + This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.

- If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, + If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer, the return type is {#syntax#}comptime_int{#endsyntax#}. - Otherwise, the return type is an unsigned integer with the minimum number + Otherwise, the return type is an unsigned integer or vector of unsigned integers with the minimum number of bits that can represent the bit count of the integer type.

- If {#syntax#}integer{#endsyntax#} is zero, {#syntax#}@ctz{#endsyntax#} returns + If {#syntax#}operand{#endsyntax#} is zero, {#syntax#}@ctz{#endsyntax#} returns the bit width of integer type {#syntax#}T{#endsyntax#}.

{#see_also|@clz|@popCount#} @@ -8105,12 +8109,14 @@ test "@wasmMemoryGrow" { {#header_close#} {#header_open|@popCount#} -
{#syntax#}@popCount(comptime T: type, integer: T){#endsyntax#}
+
{#syntax#}@popCount(comptime T: type, operand: T){#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type.

+

{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.

Counts the number of bits set in an integer.

- If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, + If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer, the return type is {#syntax#}comptime_int{#endsyntax#}. - Otherwise, the return type is an unsigned integer with the minimum number + Otherwise, the return type is an unsigned integer or vector of unsigned integers with the minimum number of bits that can represent the bit count of the integer type.

{#see_also|@ctz|@clz#} diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 8dfc8de6f9f3..ee06c15cf0c3 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1907,12 +1907,15 @@ struct ZigLLVMFnKey { union { struct { uint32_t bit_count; + uint32_t vector_len; // 0 means not a vector } ctz; struct { uint32_t bit_count; + uint32_t vector_len; // 0 means not a vector } clz; struct { uint32_t bit_count; + uint32_t vector_len; // 0 means not a vector } pop_count; struct { BuiltinFnId op; diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 37c3d58ae31f..501e43373df4 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -7883,11 +7883,14 @@ bool type_id_eql(TypeId const *a, TypeId const *b) { uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) { switch (x->id) { case ZigLLVMFnIdCtz: - return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934; + return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934 + + (uint32_t)(x->data.ctz.vector_len) * (((uint32_t)x->id << 5) + 1025); case ZigLLVMFnIdClz: - return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817; + return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817 + + (uint32_t)(x->data.clz.vector_len) * (((uint32_t)x->id << 5) + 1025); case ZigLLVMFnIdPopCount: - return (uint32_t)(x->data.clz.bit_count) * (uint32_t)101195049; + return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 + + (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025); case ZigLLVMFnIdFloatOp: return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025) + diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 67d787427fc2..821f37480af4 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -5053,6 +5053,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFn n_args = 1; key.id = ZigLLVMFnIdPopCount; key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; + key.data.pop_count.vector_len = vector_len; } else if (fn_id == BuiltinFnIdBswap) { fn_name = "bswap"; n_args = 1; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 604d2c2f9085..a6d1ff30075f 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -15945,85 +15945,239 @@ static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, } static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) { + Error err; + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; - Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type); + Stage1AirInst *uncasted_op = instruction->op->child; + if (type_is_invalid(uncasted_op->value->type)) + return ira->codegen->invalid_inst_gen; + + uint32_t vector_len = UINT32_MAX; // means not a vector + if (uncasted_op->value->type->id == ZigTypeIdArray) { + bool can_be_vec_elem; + if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, + &can_be_vec_elem))) + { + return ira->codegen->invalid_inst_gen; + } + if (can_be_vec_elem) { + vector_len = uncasted_op->value->type->data.array.len; + } + } else if (uncasted_op->value->type->id == ZigTypeIdVector) { + vector_len = uncasted_op->value->type->data.vector.len; + } + + bool is_vector = (vector_len != UINT32_MAX); + ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; + + Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); if (type_is_invalid(op->value->type)) return ira->codegen->invalid_inst_gen; if (int_type->data.integral.bit_count == 0) return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); + ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + if (instr_is_comptime(op)) { ZigValue *val = ir_resolve_const(ira, op, UndefOk); if (val == nullptr) return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); + + if (is_vector) { + ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); + Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); + expand_undef_array(ira->codegen, val); + result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); + for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { + ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, + op_elem_val, UndefOk))) + { + return ira->codegen->invalid_inst_gen; + } + ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; + result_elem_val->type = smallest_type; + result_elem_val->special = op_elem_val->special; + if (op_elem_val->special == ConstValSpecialUndef) + continue; + size_t value = bigint_ctz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); + bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); + } + return result; + } else { + size_t result_usize = bigint_ctz(&op->value->data.x_bigint, int_type->data.integral.bit_count); + return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); + } } - ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; return ir_build_ctz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); } static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) { + Error err; + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; - Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type); + Stage1AirInst *uncasted_op = instruction->op->child; + if (type_is_invalid(uncasted_op->value->type)) + return ira->codegen->invalid_inst_gen; + + uint32_t vector_len = UINT32_MAX; // means not a vector + if (uncasted_op->value->type->id == ZigTypeIdArray) { + bool can_be_vec_elem; + if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, + &can_be_vec_elem))) + { + return ira->codegen->invalid_inst_gen; + } + if (can_be_vec_elem) { + vector_len = uncasted_op->value->type->data.array.len; + } + } else if (uncasted_op->value->type->id == ZigTypeIdVector) { + vector_len = uncasted_op->value->type->data.vector.len; + } + + bool is_vector = (vector_len != UINT32_MAX); + ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; + + Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); if (type_is_invalid(op->value->type)) return ira->codegen->invalid_inst_gen; if (int_type->data.integral.bit_count == 0) return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); + ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + if (instr_is_comptime(op)) { ZigValue *val = ir_resolve_const(ira, op, UndefOk); if (val == nullptr) return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); + + if (is_vector) { + ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); + Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); + expand_undef_array(ira->codegen, val); + result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); + for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { + ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, + op_elem_val, UndefOk))) + { + return ira->codegen->invalid_inst_gen; + } + ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; + result_elem_val->type = smallest_type; + result_elem_val->special = op_elem_val->special; + if (op_elem_val->special == ConstValSpecialUndef) + continue; + size_t value = bigint_clz(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); + bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); + } + return result; + } else { + size_t result_usize = bigint_clz(&op->value->data.x_bigint, int_type->data.integral.bit_count); + return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result_usize); + } } - ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; return ir_build_clz_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); } static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1ZirInstPopCount *instruction) { + Error err; + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; - Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type); + Stage1AirInst *uncasted_op = instruction->op->child; + if (type_is_invalid(uncasted_op->value->type)) + return ira->codegen->invalid_inst_gen; + + uint32_t vector_len = UINT32_MAX; // means not a vector + if (uncasted_op->value->type->id == ZigTypeIdArray) { + bool can_be_vec_elem; + if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type, + &can_be_vec_elem))) + { + return ira->codegen->invalid_inst_gen; + } + if (can_be_vec_elem) { + vector_len = uncasted_op->value->type->data.array.len; + } + } else if (uncasted_op->value->type->id == ZigTypeIdVector) { + vector_len = uncasted_op->value->type->data.vector.len; + } + + bool is_vector = (vector_len != UINT32_MAX); + ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; + + Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type); if (type_is_invalid(op->value->type)) return ira->codegen->invalid_inst_gen; if (int_type->data.integral.bit_count == 0) return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0); + ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + if (instr_is_comptime(op)) { ZigValue *val = ir_resolve_const(ira, op, UndefOk); if (val == nullptr) return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); + + if (is_vector) { + ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); + Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); + expand_undef_array(ira->codegen, val); + result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(smallest_vec_type->data.vector.len); + for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) { + ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, + op_elem_val, UndefOk))) + { + return ira->codegen->invalid_inst_gen; + } + ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i]; + result_elem_val->type = smallest_type; + result_elem_val->special = op_elem_val->special; + if (op_elem_val->special == ConstValSpecialUndef) + continue; - if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) { - size_t result = bigint_popcount_unsigned(&val->data.x_bigint); + if (bigint_cmp_zero(&op_elem_val->data.x_bigint) != CmpLT) { + size_t value = bigint_popcount_unsigned(&op_elem_val->data.x_bigint); + bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); + } + size_t value = bigint_popcount_signed(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count); + bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value); + } + return result; + } else { + if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) { + size_t result = bigint_popcount_unsigned(&val->data.x_bigint); + return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); + } + size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count); return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); } - size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count); - return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result); } - ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count); + ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type; return ir_build_pop_count_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 5c746816e248..7a5c31f67a09 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -123,16 +123,27 @@ test "@clz" { } fn testClz() !void { - try expect(clz(u8, 0b10001010) == 0); - try expect(clz(u8, 0b00001010) == 4); - try expect(clz(u8, 0b00011010) == 3); - try expect(clz(u8, 0b00000000) == 8); - try expect(clz(u128, 0xffffffffffffffff) == 64); - try expect(clz(u128, 0x10000000000000000) == 63); + try expect(@clz(u8, 0b10001010) == 0); + try expect(@clz(u8, 0b00001010) == 4); + try expect(@clz(u8, 0b00011010) == 3); + try expect(@clz(u8, 0b00000000) == 8); + try expect(@clz(u128, 0xffffffffffffffff) == 64); + try expect(@clz(u128, 0x10000000000000000) == 63); } -fn clz(comptime T: type, x: T) usize { - return @clz(T, x); +test "@clz vectors" { + try testClzVectors(); + comptime try testClzVectors(); +} + +fn testClzVectors() !void { + @setEvalBranchQuota(10_000); + try expectEqual(@clz(u8, @splat(64, @as(u8, 0b10001010))), @splat(64, @as(u4, 0))); + try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00001010))), @splat(64, @as(u4, 4))); + try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00011010))), @splat(64, @as(u4, 3))); + try expectEqual(@clz(u8, @splat(64, @as(u8, 0b00000000))), @splat(64, @as(u4, 8))); + try expectEqual(@clz(u128, @splat(64, @as(u128, 0xffffffffffffffff))), @splat(64, @as(u8, 64))); + try expectEqual(@clz(u128, @splat(64, @as(u128, 0x10000000000000000))), @splat(64, @as(u8, 63))); } test "@ctz" { @@ -141,14 +152,23 @@ test "@ctz" { } fn testCtz() !void { - try expect(ctz(u8, 0b10100000) == 5); - try expect(ctz(u8, 0b10001010) == 1); - try expect(ctz(u8, 0b00000000) == 8); - try expect(ctz(u16, 0b00000000) == 16); + try expect(@ctz(u8, 0b10100000) == 5); + try expect(@ctz(u8, 0b10001010) == 1); + try expect(@ctz(u8, 0b00000000) == 8); + try expect(@ctz(u16, 0b00000000) == 16); +} + +test "@ctz vectors" { + try testClzVectors(); + comptime try testClzVectors(); } -fn ctz(comptime T: type, x: T) usize { - return @ctz(T, x); +fn testCtzVectors() !void { + @setEvalBranchQuota(10_000); + try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b10100000))), @splat(64, @as(u4, 5))); + try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b10001010))), @splat(64, @as(u4, 1))); + try expectEqual(@ctz(u8, @splat(64, @as(u8, 0b00000000))), @splat(64, @as(u4, 8))); + try expectEqual(@ctz(u16, @splat(64, @as(u16, 0b00000000))), @splat(64, @as(u5, 16))); } test "assignment operators" { diff --git a/test/behavior/popcount.zig b/test/behavior/popcount.zig index 99a1849d80b8..0a2352340dac 100644 --- a/test/behavior/popcount.zig +++ b/test/behavior/popcount.zig @@ -1,11 +1,14 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const Vector = std.meta.Vector; -test "@popCount" { - comptime try testPopCount(); - try testPopCount(); +test "@popCount integers" { + comptime try testPopCountIntegers(); + try testPopCountIntegers(); } -fn testPopCount() !void { +fn testPopCountIntegers() !void { { var x: u32 = 0xffffffff; try expect(@popCount(u32, x) == 32); @@ -41,3 +44,22 @@ fn testPopCount() !void { try expect(@popCount(i128, 0b11111111000110001100010000100001000011000011100101010001) == 24); } } + +test "@popCount vectors" { + // https://github.com/ziglang/zig/issues/3317 + if (std.Target.current.cpu.arch == .mipsel or std.Target.current.cpu.arch == .mips) return error.SkipZigTest; + + comptime try testPopCountVectors(); + try testPopCountVectors(); +} + +fn testPopCountVectors() !void { + { + var x: Vector(8, u32) = [1]u32{0xffffffff} ** 8; + try expectEqual([1]u6{32} ** 8, @as([8]u6, @popCount(u32, x))); + } + { + var x: Vector(8, i16) = [1]i16{-1} ** 8; + try expectEqual([1]u5{16} ** 8, @as([8]u5, @popCount(i16, x))); + } +}