| author | |
| committer | |
| log | d8295c188946b0f07d62420c2f08c940f70b03ac |
| tree | 96fc4b4199546dad9010ce659673e83ced997fe4 |
| parent | e19f0b5d9c26f4d309df9cfc84b7e5dc04b10ed5 |
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> |
| 5016 | 5016 | {#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); |
| 1477 | enum ZigLLVMFnId { | 1478 | enum 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 | }; |
| 2547 | 2553 | ||
| 2554 | struct IrInstructionPopCount { | ||
| 2555 | IrInstruction base; | ||
| 2556 | |||
| 2557 | IrInstruction *value; | ||
| 2558 | }; | ||
| 2559 | |||
| 2548 | struct IrInstructionUnionTag { | 2560 | struct IrInstructionUnionTag { |
| 2549 | IrInstruction base; | 2561 | IrInstruction base; |
| 2550 | 2562 |
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 | } |
| 1595 | 1595 | ||
| 1596 | size_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 | |||
| 1610 | size_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 | |||
| 1596 | size_t bigint_ctz(const BigInt *bi, size_t bit_count) { | 1627 | size_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); |
| 81 | 81 | ||
| 82 | size_t bigint_ctz(const BigInt *bi, size_t bit_count); | 82 | size_t bigint_ctz(const BigInt *bi, size_t bit_count); |
| 83 | size_t bigint_clz(const BigInt *bi, size_t bit_count); | 83 | size_t bigint_clz(const BigInt *bi, size_t bit_count); |
| 84 | size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count); | ||
| 85 | size_t bigint_popcount_unsigned(const BigInt *bi); | ||
| 84 | 86 | ||
| 85 | size_t bigint_bits_needed(const BigInt *op); | 87 | size_t bigint_bits_needed(const BigInt *op); |
| 86 | 88 |
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, |
| 3426 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) { | 3426 | static 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)); |
| 3454 | 3462 | ||
| ... | @@ -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 | } |
| 3483 | 3491 | ||
| 3492 | static 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 | |||
| 3484 | static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) { | 3500 | static 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 | } |
| 429 | 429 | ||
| 430 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPopCount *) { | ||
| 431 | return IrInstructionIdPopCount; | ||
| 432 | } | ||
| 433 | |||
| 430 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) { | 434 | static 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 | } |
| 1727 | 1731 | ||
| 1732 | static 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 | |||
| 1728 | static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value, | 1741 | static 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 | } |
| 15277 | 15300 | ||
| 15301 | static 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 | |||
| 15278 | static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) { | 15343 | static 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 | } |
| 503 | 503 | ||
| 504 | static 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 | |||
| 504 | static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction) { | 510 | static 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 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | test "@popCount" { | ||
| 4 | comptime testPopCount(); | ||
| 5 | testPopCount(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn 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 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub 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", |