authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-07 00:25:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-07 00:25:32-04:00
logd8295c188946b0f07d62420c2f08c940f70b03ac
tree96fc4b4199546dad9010ce659673e83ced997fe4
parente19f0b5d9c26f4d309df9cfc84b7e5dc04b10ed5

add @popCount intrinsic


11 files changed, 205 insertions(+), 6 deletions(-)

doc/langref.html.in+13-2
...@@ -5013,7 +5013,7 @@ comptime {...@@ -5013,7 +5013,7 @@ comptime {
5013 <p>5013 <p>
5014 If <code>x</code> is zero, <code>@clz</code> returns <code>T.bit_count</code>.5014 If <code>x</code> is zero, <code>@clz</code> returns <code>T.bit_count</code>.
5015 </p>5015 </p>
50165016 {#see_also|@ctz|@popCount#}
5017 {#header_close#}5017 {#header_close#}
5018 {#header_open|@cmpxchgStrong#}5018 {#header_open|@cmpxchgStrong#}
5019 <pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T</code></pre>5019 <pre><code class="zig">@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T</code></pre>
...@@ -5149,6 +5149,7 @@ test "main" {...@@ -5149,6 +5149,7 @@ test "main" {
5149 <p>5149 <p>
5150 If <code>x</code> is zero, <code>@ctz</code> returns <code>T.bit_count</code>.5150 If <code>x</code> is zero, <code>@ctz</code> returns <code>T.bit_count</code>.
5151 </p>5151 </p>
5152 {#see_also|@clz|@popCount#}
5152 {#header_close#}5153 {#header_close#}
5153 {#header_open|@divExact#}5154 {#header_open|@divExact#}
5154 <pre><code class="zig">@divExact(numerator: T, denominator: T) T</code></pre>5155 <pre><code class="zig">@divExact(numerator: T, denominator: T) T</code></pre>
...@@ -5631,6 +5632,16 @@ test "call foo" {...@@ -5631,6 +5632,16 @@ test "call foo" {
5631 </ul>5632 </ul>
5632 {#see_also|Root Source File#}5633 {#see_also|Root Source File#}
5633 {#header_close#}5634 {#header_close#}
5635 {#header_open|@popCount#}
5636 <pre><code class="zig">@popCount(integer: var) var</code></pre>
5637 <p>Counts the number of bits set in an integer.</p>
5638 <p>
5639 If <code>integer</code> is known at {#link|comptime#}, the return type is <code>comptime_int</code>.
5640 Otherwise, the return type is an unsigned integer with the minimum number
5641 of bits that can represent the bit count of the integer type.
5642 </p>
5643 {#see_also|@ctz|@clz#}
5644 {#header_close#}
5634 {#header_open|@ptrCast#}5645 {#header_open|@ptrCast#}
5635 <pre><code class="zig">@ptrCast(comptime DestType: type, value: var) DestType</code></pre>5646 <pre><code class="zig">@ptrCast(comptime DestType: type, value: var) DestType</code></pre>
5636 <p>5647 <p>
...@@ -7337,7 +7348,7 @@ hljs.registerLanguage("zig", function(t) {...@@ -7337,7 +7348,7 @@ hljs.registerLanguage("zig", function(t) {
7337 a = t.IR + "\\s*\\(",7348 a = t.IR + "\\s*\\(",
7338 c = {7349 c = {
7339 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",7350 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
7340 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",7351 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz popCount import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
7341 literal: "true false null undefined"7352 literal: "true false null undefined"
7342 },7353 },
7343 n = [e, t.CLCM, t.CBCM, s, r];7354 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+12
...@@ -1352,6 +1352,7 @@ enum BuiltinFnId {...@@ -1352,6 +1352,7 @@ enum BuiltinFnId {
1352 BuiltinFnIdCompileLog,1352 BuiltinFnIdCompileLog,
1353 BuiltinFnIdCtz,1353 BuiltinFnIdCtz,
1354 BuiltinFnIdClz,1354 BuiltinFnIdClz,
1355 BuiltinFnIdPopCount,
1355 BuiltinFnIdImport,1356 BuiltinFnIdImport,
1356 BuiltinFnIdCImport,1357 BuiltinFnIdCImport,
1357 BuiltinFnIdErrName,1358 BuiltinFnIdErrName,
...@@ -1477,6 +1478,7 @@ bool type_id_eql(TypeId a, TypeId b);...@@ -1477,6 +1478,7 @@ bool type_id_eql(TypeId a, TypeId b);
1477enum ZigLLVMFnId {1478enum ZigLLVMFnId {
1478 ZigLLVMFnIdCtz,1479 ZigLLVMFnIdCtz,
1479 ZigLLVMFnIdClz,1480 ZigLLVMFnIdClz,
1481 ZigLLVMFnIdPopCount,
1480 ZigLLVMFnIdOverflowArithmetic,1482 ZigLLVMFnIdOverflowArithmetic,
1481 ZigLLVMFnIdFloor,1483 ZigLLVMFnIdFloor,
1482 ZigLLVMFnIdCeil,1484 ZigLLVMFnIdCeil,
...@@ -1499,6 +1501,9 @@ struct ZigLLVMFnKey {...@@ -1499,6 +1501,9 @@ struct ZigLLVMFnKey {
1499 struct {1501 struct {
1500 uint32_t bit_count;1502 uint32_t bit_count;
1501 } clz;1503 } clz;
1504 struct {
1505 uint32_t bit_count;
1506 } pop_count;
1502 struct {1507 struct {
1503 uint32_t bit_count;1508 uint32_t bit_count;
1504 } floating;1509 } floating;
...@@ -2050,6 +2055,7 @@ enum IrInstructionId {...@@ -2050,6 +2055,7 @@ enum IrInstructionId {
2050 IrInstructionIdUnionTag,2055 IrInstructionIdUnionTag,
2051 IrInstructionIdClz,2056 IrInstructionIdClz,
2052 IrInstructionIdCtz,2057 IrInstructionIdCtz,
2058 IrInstructionIdPopCount,
2053 IrInstructionIdImport,2059 IrInstructionIdImport,
2054 IrInstructionIdCImport,2060 IrInstructionIdCImport,
2055 IrInstructionIdCInclude,2061 IrInstructionIdCInclude,
...@@ -2545,6 +2551,12 @@ struct IrInstructionClz {...@@ -2545,6 +2551,12 @@ struct IrInstructionClz {
2545 IrInstruction *value;2551 IrInstruction *value;
2546};2552};
25472553
2554struct IrInstructionPopCount {
2555 IrInstruction base;
2556
2557 IrInstruction *value;
2558};
2559
2548struct IrInstructionUnionTag {2560struct IrInstructionUnionTag {
2549 IrInstruction base;2561 IrInstruction base;
25502562
src/analyze.cpp+4
...@@ -5976,6 +5976,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {...@@ -5976,6 +5976,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
5976 return (uint32_t)(x.data.ctz.bit_count) * (uint32_t)810453934;5976 return (uint32_t)(x.data.ctz.bit_count) * (uint32_t)810453934;
5977 case ZigLLVMFnIdClz:5977 case ZigLLVMFnIdClz:
5978 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;5978 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
5979 case ZigLLVMFnIdPopCount:
5980 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049;
5979 case ZigLLVMFnIdFloor:5981 case ZigLLVMFnIdFloor:
5980 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;5982 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
5981 case ZigLLVMFnIdCeil:5983 case ZigLLVMFnIdCeil:
...@@ -5998,6 +6000,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {...@@ -5998,6 +6000,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
5998 return a.data.ctz.bit_count == b.data.ctz.bit_count;6000 return a.data.ctz.bit_count == b.data.ctz.bit_count;
5999 case ZigLLVMFnIdClz:6001 case ZigLLVMFnIdClz:
6000 return a.data.clz.bit_count == b.data.clz.bit_count;6002 return a.data.clz.bit_count == b.data.clz.bit_count;
6003 case ZigLLVMFnIdPopCount:
6004 return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
6001 case ZigLLVMFnIdFloor:6005 case ZigLLVMFnIdFloor:
6002 case ZigLLVMFnIdCeil:6006 case ZigLLVMFnIdCeil:
6003 case ZigLLVMFnIdSqrt:6007 case ZigLLVMFnIdSqrt:
src/bigint.cpp+31
...@@ -1593,6 +1593,37 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) {...@@ -1593,6 +1593,37 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base) {
1593 }1593 }
1594}1594}
15951595
1596size_t bigint_popcount_unsigned(const BigInt *bi) {
1597 assert(!bi->is_negative);
1598 if (bi->digit_count == 0)
1599 return 0;
1600
1601 size_t count = 0;
1602 size_t bit_count = bi->digit_count * 64;
1603 for (size_t i = 0; i < bit_count; i += 1) {
1604 if (bit_at_index(bi, i))
1605 count += 1;
1606 }
1607 return count;
1608}
1609
1610size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count) {
1611 if (bit_count == 0)
1612 return 0;
1613 if (bi->digit_count == 0)
1614 return 0;
1615
1616 BigInt twos_comp = {0};
1617 to_twos_complement(&twos_comp, bi, bit_count);
1618
1619 size_t count = 0;
1620 for (size_t i = 0; i < bit_count; i += 1) {
1621 if (bit_at_index(&twos_comp, i))
1622 count += 1;
1623 }
1624 return count;
1625}
1626
1596size_t bigint_ctz(const BigInt *bi, size_t bit_count) {1627size_t bigint_ctz(const BigInt *bi, size_t bit_count) {
1597 if (bit_count == 0)1628 if (bit_count == 0)
1598 return 0;1629 return 0;
src/bigint.hpp+2
...@@ -81,6 +81,8 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base);...@@ -81,6 +81,8 @@ void bigint_append_buf(Buf *buf, const BigInt *op, uint64_t base);
8181
82size_t bigint_ctz(const BigInt *bi, size_t bit_count);82size_t bigint_ctz(const BigInt *bi, size_t bit_count);
83size_t bigint_clz(const BigInt *bi, size_t bit_count);83size_t bigint_clz(const BigInt *bi, size_t bit_count);
84size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
85size_t bigint_popcount_unsigned(const BigInt *bi);
8486
85size_t bigint_bits_needed(const BigInt *op);87size_t bigint_bits_needed(const BigInt *op);
8688
src/codegen.cpp+20-1
...@@ -3426,14 +3426,22 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,...@@ -3426,14 +3426,22 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
3426static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {3426static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) {
3427 ZigLLVMFnKey key = {};3427 ZigLLVMFnKey key = {};
3428 const char *fn_name;3428 const char *fn_name;
3429 uint32_t n_args;
3429 if (fn_id == BuiltinFnIdCtz) {3430 if (fn_id == BuiltinFnIdCtz) {
3430 fn_name = "cttz";3431 fn_name = "cttz";
3432 n_args = 2;
3431 key.id = ZigLLVMFnIdCtz;3433 key.id = ZigLLVMFnIdCtz;
3432 key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;3434 key.data.ctz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3433 } else if (fn_id == BuiltinFnIdClz) {3435 } else if (fn_id == BuiltinFnIdClz) {
3434 fn_name = "ctlz";3436 fn_name = "ctlz";
3437 n_args = 2;
3435 key.id = ZigLLVMFnIdClz;3438 key.id = ZigLLVMFnIdClz;
3436 key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;3439 key.data.clz.bit_count = (uint32_t)int_type->data.integral.bit_count;
3440 } else if (fn_id == BuiltinFnIdPopCount) {
3441 fn_name = "ctpop";
3442 n_args = 1;
3443 key.id = ZigLLVMFnIdPopCount;
3444 key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
3437 } else {3445 } else {
3438 zig_unreachable();3446 zig_unreachable();
3439 }3447 }
...@@ -3448,7 +3456,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui...@@ -3448,7 +3456,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
3448 int_type->type_ref,3456 int_type->type_ref,
3449 LLVMInt1Type(),3457 LLVMInt1Type(),
3450 };3458 };
3451 LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false);3459 LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, n_args, false);
3452 LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);3460 LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
3453 assert(LLVMGetIntrinsicID(fn_val));3461 assert(LLVMGetIntrinsicID(fn_val));
34543462
...@@ -3481,6 +3489,14 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru...@@ -3481,6 +3489,14 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
3481 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);3489 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
3482}3490}
34833491
3492static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
3493 TypeTableEntry *int_type = instruction->value->value.type;
3494 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
3495 LLVMValueRef operand = ir_llvm_value(g, instruction->value);
3496 LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, &operand, 1, "");
3497 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
3498}
3499
3484static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {3500static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {
3485 LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);3501 LLVMValueRef target_value = ir_llvm_value(g, instruction->target_value);
3486 LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;3502 LLVMBasicBlockRef else_block = instruction->else_block->llvm_block;
...@@ -4831,6 +4847,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4831,6 +4847,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4831 return ir_render_clz(g, executable, (IrInstructionClz *)instruction);4847 return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
4832 case IrInstructionIdCtz:4848 case IrInstructionIdCtz:
4833 return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);4849 return ir_render_ctz(g, executable, (IrInstructionCtz *)instruction);
4850 case IrInstructionIdPopCount:
4851 return ir_render_pop_count(g, executable, (IrInstructionPopCount *)instruction);
4834 case IrInstructionIdSwitchBr:4852 case IrInstructionIdSwitchBr:
4835 return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);4853 return ir_render_switch_br(g, executable, (IrInstructionSwitchBr *)instruction);
4836 case IrInstructionIdPhi:4854 case IrInstructionIdPhi:
...@@ -6342,6 +6360,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -6342,6 +6360,7 @@ static void define_builtin_fns(CodeGen *g) {
6342 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);6360 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
6343 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);6361 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
6344 create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);6362 create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
6363 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
6345 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);6364 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
6346 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);6365 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
6347 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);6366 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
src/ir.cpp+68
...@@ -427,6 +427,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {...@@ -427,6 +427,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
427 return IrInstructionIdCtz;427 return IrInstructionIdCtz;
428}428}
429429
430static constexpr IrInstructionId ir_instruction_id(IrInstructionPopCount *) {
431 return IrInstructionIdPopCount;
432}
433
430static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {434static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {
431 return IrInstructionIdUnionTag;435 return IrInstructionIdUnionTag;
432}436}
...@@ -1725,6 +1729,15 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr...@@ -1725,6 +1729,15 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr
1725 return new_instruction;1729 return new_instruction;
1726}1730}
17271731
1732static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1733 IrInstructionPopCount *instruction = ir_build_instruction<IrInstructionPopCount>(irb, scope, source_node);
1734 instruction->value = value;
1735
1736 ir_ref_instruction(value, irb->current_basic_block);
1737
1738 return &instruction->base;
1739}
1740
1728static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,1741static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
1729 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,1742 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
1730 IrInstruction *switch_prongs_void)1743 IrInstruction *switch_prongs_void)
...@@ -3841,6 +3854,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3841,6 +3854,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
3841 IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);3854 IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
3842 return ir_lval_wrap(irb, scope, ctz, lval);3855 return ir_lval_wrap(irb, scope, ctz, lval);
3843 }3856 }
3857 case BuiltinFnIdPopCount:
3858 {
3859 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
3860 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
3861 if (arg0_value == irb->codegen->invalid_instruction)
3862 return arg0_value;
3863
3864 IrInstruction *instr = ir_build_pop_count(irb, scope, node, arg0_value);
3865 return ir_lval_wrap(irb, scope, instr, lval);
3866 }
3844 case BuiltinFnIdClz:3867 case BuiltinFnIdClz:
3845 {3868 {
3846 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);3869 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -15275,6 +15298,48 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC...@@ -15275,6 +15298,48 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
15275 }15298 }
15276}15299}
1527715300
15301static TypeTableEntry *ir_analyze_instruction_pop_count(IrAnalyze *ira, IrInstructionPopCount *instruction) {
15302 IrInstruction *value = instruction->value->other;
15303 if (type_is_invalid(value->value.type))
15304 return ira->codegen->builtin_types.entry_invalid;
15305
15306 if (value->value.type->id != TypeTableEntryIdInt && value->value.type->id != TypeTableEntryIdComptimeInt) {
15307 ir_add_error(ira, value,
15308 buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name)));
15309 return ira->codegen->builtin_types.entry_invalid;
15310 }
15311
15312 if (instr_is_comptime(value)) {
15313 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
15314 if (!val)
15315 return ira->codegen->builtin_types.entry_invalid;
15316 if (bigint_cmp_zero(&val->data.x_bigint) != CmpLT) {
15317 size_t result = bigint_popcount_unsigned(&val->data.x_bigint);
15318 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15319 bigint_init_unsigned(&out_val->data.x_bigint, result);
15320 return ira->codegen->builtin_types.entry_num_lit_int;
15321 }
15322 if (value->value.type->id == TypeTableEntryIdComptimeInt) {
15323 Buf *val_buf = buf_alloc();
15324 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
15325 ir_add_error(ira, &instruction->base,
15326 buf_sprintf("@popCount on negative %s value %s",
15327 buf_ptr(&value->value.type->name), buf_ptr(val_buf)));
15328 return ira->codegen->builtin_types.entry_invalid;
15329 }
15330 size_t result = bigint_popcount_signed(&val->data.x_bigint, value->value.type->data.integral.bit_count);
15331 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15332 bigint_init_unsigned(&out_val->data.x_bigint, result);
15333 return ira->codegen->builtin_types.entry_num_lit_int;
15334 }
15335
15336 IrInstruction *result = ir_build_pop_count(&ira->new_irb, instruction->base.scope,
15337 instruction->base.source_node, value);
15338 result->value.type = get_smallest_unsigned_int_type(ira->codegen, value->value.type->data.integral.bit_count);
15339 ir_link_new_instruction(result, &instruction->base);
15340 return result->value.type;
15341}
15342
15278static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {15343static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
15279 if (type_is_invalid(value->value.type))15344 if (type_is_invalid(value->value.type))
15280 return ira->codegen->invalid_instruction;15345 return ira->codegen->invalid_instruction;
...@@ -20534,6 +20599,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -20534,6 +20599,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
20534 return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);20599 return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
20535 case IrInstructionIdCtz:20600 case IrInstructionIdCtz:
20536 return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);20601 return ir_analyze_instruction_ctz(ira, (IrInstructionCtz *)instruction);
20602 case IrInstructionIdPopCount:
20603 return ir_analyze_instruction_pop_count(ira, (IrInstructionPopCount *)instruction);
20537 case IrInstructionIdSwitchBr:20604 case IrInstructionIdSwitchBr:
20538 return ir_analyze_instruction_switch_br(ira, (IrInstructionSwitchBr *)instruction);20605 return ir_analyze_instruction_switch_br(ira, (IrInstructionSwitchBr *)instruction);
20539 case IrInstructionIdSwitchTarget:20606 case IrInstructionIdSwitchTarget:
...@@ -20892,6 +20959,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -20892,6 +20959,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
20892 case IrInstructionIdUnwrapOptional:20959 case IrInstructionIdUnwrapOptional:
20893 case IrInstructionIdClz:20960 case IrInstructionIdClz:
20894 case IrInstructionIdCtz:20961 case IrInstructionIdCtz:
20962 case IrInstructionIdPopCount:
20895 case IrInstructionIdSwitchVar:20963 case IrInstructionIdSwitchVar:
20896 case IrInstructionIdSwitchTarget:20964 case IrInstructionIdSwitchTarget:
20897 case IrInstructionIdUnionTag:20965 case IrInstructionIdUnionTag:
src/ir_print.cpp+9
...@@ -501,6 +501,12 @@ static void ir_print_ctz(IrPrint *irp, IrInstructionCtz *instruction) {...@@ -501,6 +501,12 @@ static void ir_print_ctz(IrPrint *irp, IrInstructionCtz *instruction) {
501 fprintf(irp->f, ")");501 fprintf(irp->f, ")");
502}502}
503503
504static void ir_print_pop_count(IrPrint *irp, IrInstructionPopCount *instruction) {
505 fprintf(irp->f, "@popCount(");
506 ir_print_other_instruction(irp, instruction->value);
507 fprintf(irp->f, ")");
508}
509
504static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) {510static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) {
505 fprintf(irp->f, "switch (");511 fprintf(irp->f, "switch (");
506 ir_print_other_instruction(irp, instruction->target_value);512 ir_print_other_instruction(irp, instruction->target_value);
...@@ -1425,6 +1431,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1425,6 +1431,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1425 case IrInstructionIdCtz:1431 case IrInstructionIdCtz:
1426 ir_print_ctz(irp, (IrInstructionCtz *)instruction);1432 ir_print_ctz(irp, (IrInstructionCtz *)instruction);
1427 break;1433 break;
1434 case IrInstructionIdPopCount:
1435 ir_print_pop_count(irp, (IrInstructionPopCount *)instruction);
1436 break;
1428 case IrInstructionIdClz:1437 case IrInstructionIdClz:
1429 ir_print_clz(irp, (IrInstructionClz *)instruction);1438 ir_print_clz(irp, (IrInstructionClz *)instruction);
1430 break;1439 break;
test/behavior.zig+4-3
...@@ -8,17 +8,17 @@ comptime {...@@ -8,17 +8,17 @@ comptime {
8 _ = @import("cases/atomics.zig");8 _ = @import("cases/atomics.zig");
9 _ = @import("cases/bitcast.zig");9 _ = @import("cases/bitcast.zig");
10 _ = @import("cases/bool.zig");10 _ = @import("cases/bool.zig");
11 _ = @import("cases/bugs/1111.zig");
11 _ = @import("cases/bugs/394.zig");12 _ = @import("cases/bugs/394.zig");
12 _ = @import("cases/bugs/655.zig");13 _ = @import("cases/bugs/655.zig");
13 _ = @import("cases/bugs/656.zig");14 _ = @import("cases/bugs/656.zig");
14 _ = @import("cases/bugs/828.zig");15 _ = @import("cases/bugs/828.zig");
15 _ = @import("cases/bugs/920.zig");16 _ = @import("cases/bugs/920.zig");
16 _ = @import("cases/bugs/1111.zig");
17 _ = @import("cases/byval_arg_var.zig");17 _ = @import("cases/byval_arg_var.zig");
18 _ = @import("cases/cast.zig");18 _ = @import("cases/cast.zig");
19 _ = @import("cases/const_slice_child.zig");19 _ = @import("cases/const_slice_child.zig");
20 _ = @import("cases/coroutines.zig");
21 _ = @import("cases/coroutine_await_struct.zig");20 _ = @import("cases/coroutine_await_struct.zig");
21 _ = @import("cases/coroutines.zig");
22 _ = @import("cases/defer.zig");22 _ = @import("cases/defer.zig");
23 _ = @import("cases/enum.zig");23 _ = @import("cases/enum.zig");
24 _ = @import("cases/enum_with_members.zig");24 _ = @import("cases/enum_with_members.zig");
...@@ -36,11 +36,12 @@ comptime {...@@ -36,11 +36,12 @@ comptime {
36 _ = @import("cases/math.zig");36 _ = @import("cases/math.zig");
37 _ = @import("cases/merge_error_sets.zig");37 _ = @import("cases/merge_error_sets.zig");
38 _ = @import("cases/misc.zig");38 _ = @import("cases/misc.zig");
39 _ = @import("cases/optional.zig");
40 _ = @import("cases/namespace_depends_on_compile_var/index.zig");39 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
41 _ = @import("cases/new_stack_call.zig");40 _ = @import("cases/new_stack_call.zig");
42 _ = @import("cases/null.zig");41 _ = @import("cases/null.zig");
42 _ = @import("cases/optional.zig");
43 _ = @import("cases/pointers.zig");43 _ = @import("cases/pointers.zig");
44 _ = @import("cases/popcount.zig");
44 _ = @import("cases/pub_enum/index.zig");45 _ = @import("cases/pub_enum/index.zig");
45 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");46 _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
46 _ = @import("cases/reflection.zig");47 _ = @import("cases/reflection.zig");
test/cases/popcount.zig created+24
...@@ -0,0 +1,24 @@
1const assert = @import("std").debug.assert;
2
3test "@popCount" {
4 comptime testPopCount();
5 testPopCount();
6}
7
8fn testPopCount() void {
9 {
10 var x: u32 = 0xaa;
11 assert(@popCount(x) == 4);
12 }
13 {
14 var x: u32 = 0xaaaaaaaa;
15 assert(@popCount(x) == 16);
16 }
17 {
18 var x: i16 = -1;
19 assert(@popCount(x) == 16);
20 }
21 comptime {
22 assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
23 }
24}
test/compile_errors.zig+18
...@@ -1,6 +1,24 @@...@@ -1,6 +1,24 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "@popCount - non-integer",
6 \\export fn entry(x: f32) u32 {
7 \\ return @popCount(x);
8 \\}
9 ,
10 ".tmp_source.zig:2:22: error: expected integer type, found 'f32'",
11 );
12
13 cases.add(
14 "@popCount - negative comptime_int",
15 \\comptime {
16 \\ _ = @popCount(-1);
17 \\}
18 ,
19 ".tmp_source.zig:2:9: error: @popCount on negative comptime_int value -1",
20 );
21
4 cases.addCase(x: {22 cases.addCase(x: {
5 const tc = cases.create(23 const tc = cases.create(
6 "wrong same named struct",24 "wrong same named struct",