diff --git a/doc/langref.html.in b/doc/langref.html.in index 0e3e32c52a..ebb81884e5 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8105,12 +8105,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 8dfc8de6f9..c45ad6806f 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1913,6 +1913,7 @@ struct ZigLLVMFnKey { } 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 37c3d58ae3..876f91a4db 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -7887,7 +7887,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) { case ZigLLVMFnIdClz: return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817; 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 67d787427f..821f37480a 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 604d2c2f90..96f4f5f1c2 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -15997,33 +15997,87 @@ static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstCl } 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