authorgravatar for auguste.rame@gmail.comAuguste Rame <auguste.rame@gmail.com> 2021-07-25 20:35:55-04:00
committergravatar for auguste.rame@gmail.comAuguste Rame <auguste.rame@gmail.com> 2021-07-25 20:35:55-04:00
logecca829bcbfdcb03bfcefa56f530b180d5c61653
tree3a948e1e290a8a96f9d90e8119a1bd5f7001483f
parent653c851e6233a105cb151602517d0222b1128ea7

Add vector support for @popCount


6 files changed, 96 insertions(+), 15 deletions(-)

doc/langref.html.in+5-3
......@@ -8105,12 +8105,14 @@ test "@wasmMemoryGrow" {
81058105 {#header_close#}
81068106
81078107 {#header_open|@popCount#}
8108 <pre>{#syntax#}@popCount(comptime T: type, integer: T){#endsyntax#}</pre>
8108 <pre>{#syntax#}@popCount(comptime T: type, operand: T){#endsyntax#}</pre>
8109 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>
8110 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
81098111 <p>Counts the number of bits set in an integer.</p>
81108112 <p>
8111 If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#},
8113 If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer,
81128114 the return type is {#syntax#}comptime_int{#endsyntax#}.
8113 Otherwise, the return type is an unsigned integer with the minimum number
8115 Otherwise, the return type is an unsigned integer or vector of unsigned integers with the minimum number
81148116 of bits that can represent the bit count of the integer type.
81158117 </p>
81168118 {#see_also|@ctz|@clz#}
src/stage1/all_types.hpp+1
......@@ -1913,6 +1913,7 @@ struct ZigLLVMFnKey {
19131913 } clz;
19141914 struct {
19151915 uint32_t bit_count;
1916 uint32_t vector_len; // 0 means not a vector
19161917 } pop_count;
19171918 struct {
19181919 BuiltinFnId op;
src/stage1/analyze.cpp+2-1
......@@ -7887,7 +7887,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) {
78877887 case ZigLLVMFnIdClz:
78887888 return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817;
78897889 case ZigLLVMFnIdPopCount:
7890 return (uint32_t)(x->data.clz.bit_count) * (uint32_t)101195049;
7890 return (uint32_t)(x->data.pop_count.bit_count) * (uint32_t)101195049 +
7891 (uint32_t)(x->data.pop_count.vector_len) * (((uint32_t)x->id << 5) + 1025);
78917892 case ZigLLVMFnIdFloatOp:
78927893 return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) +
78937894 (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025) +
src/stage1/codegen.cpp+1
......@@ -5053,6 +5053,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFn
50535053 n_args = 1;
50545054 key.id = ZigLLVMFnIdPopCount;
50555055 key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
5056 key.data.pop_count.vector_len = vector_len;
50565057 } else if (fn_id == BuiltinFnIdBswap) {
50575058 fn_name = "bswap";
50585059 n_args = 1;
src/stage1/ir.cpp+60-6
......@@ -15997,33 +15997,87 @@ static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstCl
1599715997}
1599815998
1599915999static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1ZirInstPopCount *instruction) {
16000 Error err;
16001
1600016002 ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child);
1600116003 if (type_is_invalid(int_type))
1600216004 return ira->codegen->invalid_inst_gen;
1600316005
16004 Stage1AirInst *op = ir_implicit_cast(ira, instruction->op->child, int_type);
16006 Stage1AirInst *uncasted_op = instruction->op->child;
16007 if (type_is_invalid(uncasted_op->value->type))
16008 return ira->codegen->invalid_inst_gen;
16009
16010 uint32_t vector_len = UINT32_MAX; // means not a vector
16011 if (uncasted_op->value->type->id == ZigTypeIdArray) {
16012 bool can_be_vec_elem;
16013 if ((err = is_valid_vector_elem_type(ira->codegen, uncasted_op->value->type->data.array.child_type,
16014 &can_be_vec_elem)))
16015 {
16016 return ira->codegen->invalid_inst_gen;
16017 }
16018 if (can_be_vec_elem) {
16019 vector_len = uncasted_op->value->type->data.array.len;
16020 }
16021 } else if (uncasted_op->value->type->id == ZigTypeIdVector) {
16022 vector_len = uncasted_op->value->type->data.vector.len;
16023 }
16024
16025 bool is_vector = (vector_len != UINT32_MAX);
16026 ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type;
16027
16028 Stage1AirInst *op = ir_implicit_cast(ira, uncasted_op, op_type);
1600516029 if (type_is_invalid(op->value->type))
1600616030 return ira->codegen->invalid_inst_gen;
1600716031
1600816032 if (int_type->data.integral.bit_count == 0)
1600916033 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, 0);
1601016034
16035 ZigType *smallest_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
16036
1601116037 if (instr_is_comptime(op)) {
1601216038 ZigValue *val = ir_resolve_const(ira, op, UndefOk);
1601316039 if (val == nullptr)
1601416040 return ira->codegen->invalid_inst_gen;
1601516041 if (val->special == ConstValSpecialUndef)
1601616042 return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int);
16043
16044 if (is_vector) {
16045 ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type);
16046 Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type);
16047 expand_undef_array(ira->codegen, val);
16048 result->value->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(smallest_vec_type->data.vector.len);
16049 for (unsigned i = 0; i < smallest_vec_type->data.vector.len; i += 1) {
16050 ZigValue *op_elem_val = &val->data.x_array.data.s_none.elements[i];
16051 if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node,
16052 op_elem_val, UndefOk)))
16053 {
16054 return ira->codegen->invalid_inst_gen;
16055 }
16056 ZigValue *result_elem_val = &result->value->data.x_array.data.s_none.elements[i];
16057 result_elem_val->type = smallest_type;
16058 result_elem_val->special = op_elem_val->special;
16059 if (op_elem_val->special == ConstValSpecialUndef)
16060 continue;
1601716061
16018 if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) {
16019 size_t result = bigint_popcount_unsigned(&val->data.x_bigint);
16062 if (bigint_cmp_zero(&op_elem_val->data.x_bigint) != CmpLT) {
16063 size_t value = bigint_popcount_unsigned(&op_elem_val->data.x_bigint);
16064 bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value);
16065 }
16066 size_t value = bigint_popcount_signed(&op_elem_val->data.x_bigint, int_type->data.integral.bit_count);
16067 bigint_init_unsigned(&result->value->data.x_array.data.s_none.elements[i].data.x_bigint, value);
16068 }
16069 return result;
16070 } else {
16071 if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) {
16072 size_t result = bigint_popcount_unsigned(&val->data.x_bigint);
16073 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result);
16074 }
16075 size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count);
1602016076 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result);
1602116077 }
16022 size_t result = bigint_popcount_signed(&val->data.x_bigint, int_type->data.integral.bit_count);
16023 return ir_const_unsigned(ira, instruction->base.scope, instruction->base.source_node, result);
1602416078 }
1602516079
16026 ZigType *return_type = get_smallest_unsigned_int_type(ira->codegen, int_type->data.integral.bit_count);
16080 ZigType *return_type = is_vector ? get_vector_type(ira->codegen, vector_len, smallest_type) : smallest_type;
1602716081 return ir_build_pop_count_gen(ira, instruction->base.scope, instruction->base.source_node, return_type, op);
1602816082}
1602916083
test/behavior/popcount.zig+27-5
......@@ -1,11 +1,14 @@
1const expect = @import("std").testing.expect;
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4const Vector = std.meta.Vector;
25
3test "@popCount" {
4 comptime try testPopCount();
5 try testPopCount();
6test "@popCount integers" {
7 comptime try testPopCountIntegers();
8 try testPopCountIntegers();
69}
710
8fn testPopCount() !void {
11fn testPopCountIntegers() !void {
912 {
1013 var x: u32 = 0xffffffff;
1114 try expect(@popCount(u32, x) == 32);
......@@ -41,3 +44,22 @@ fn testPopCount() !void {
4144 try expect(@popCount(i128, 0b11111111000110001100010000100001000011000011100101010001) == 24);
4245 }
4346}
47
48test "@popCount vectors" {
49 // https://github.com/ziglang/zig/issues/3317
50 if (std.Target.current.cpu.arch == .mipsel or std.Target.current.cpu.arch == .mips) return error.SkipZigTest;
51
52 comptime try testPopCountVectors();
53 try testPopCountVectors();
54}
55
56fn testPopCountVectors() !void {
57 {
58 var x: Vector(8, u32) = [1]u32{0xffffffff} ** 8;
59 try expectEqual([1]u6{32} ** 8, @as([8]u6, @popCount(u32, x)));
60 }
61 {
62 var x: Vector(8, i16) = [1]i16{-1} ** 8;
63 try expectEqual([1]u5{16} ** 8, @as([8]u5, @popCount(i16, x)));
64 }
65}