Add POPCOUNT function (#2166)

This commit is contained in:
Rangi authored and GitHub committed 2026-09-27 00:17:31 +02:00
1 parent ff6f1699e9
commit d95e9260e4
13 files changed
+45 -3

No files matched your search

+17 -3
View File
@@ -42,12 +42,13 @@ static inline void unreachable_() {
// Ideally we'd use `std::bit_width`, but it has insufficient compiler support
#ifdef __GNUC__ // GCC or compatible
#define ctz __builtin_ctz
#define clz __builtin_clz
#define ctz __builtin_ctz
#define clz __builtin_clz
#define popcount __builtin_popcount
#elif defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_BitScanReverse, _BitScanForward)
#pragma intrinsic(_BitScanReverse, _BitScanForward, __popcnt)
static inline int ctz(unsigned int x) {
assume(x != 0);
@@ -63,6 +64,10 @@ static inline int clz(unsigned int x) {
return 31 - count;
}
static inline int popcount(unsigned int x) {
return __popcnt(x);
}
#else
#include <limits.h>
@@ -85,6 +90,15 @@ static inline int clz(unsigned int x) {
}
return count;
}
static inline int popcount(unsigned int x) {
int count = 0;
while (x) {
x &= x - 1;
++count;
}
return count;
}
#endif
// Macros for stringification
+1
View File
@@ -57,6 +57,7 @@ enum RPNCommand {
RPN_LOW = 0x71,
RPN_BITWIDTH = 0x72,
RPN_TZCOUNT = 0x73,
RPN_POPCOUNT = 0x74,
RPN_CONST = 0x80,
RPN_SYM = 0x81
+1
View File
@@ -23,5 +23,6 @@ int32_t op_low(int32_t value);
int32_t op_bitwidth(int32_t value);
int32_t op_tzcount(int32_t value);
int32_t op_popcount(int32_t value);
#endif // RGBDS_OP_MATH_HPP
+2
View File
@@ -436,6 +436,8 @@ equals $roman clz ( n )$, the count of leading zero bits in the binary represent
.Ar n .
.It Fn TZCOUNT n Ta Returns $roman ctz ( n )$, the count of trailing zero bits in the binary representation of
.Ar n .
.It Fn POPCOUNT n Ta Returns how many one bits are in the binary representation of
.Ar n .
.El
.EQ
delim off
+2
View File
@@ -411,6 +411,8 @@ byte.
value.
.It Li $73 Ta Cm TZCOUNT
value.
.It Li $74 Ta Cm POPCOUNT
value.
.It Li $80 Ta Integer literal; followed by the
.Cm LONG
integer.
+1
View File
@@ -173,6 +173,7 @@ static UpperMap<int> const keywords{
{"ISCONST", T_(OP_ISCONST) },
{"BITWIDTH", T_(OP_BITWIDTH) },
{"POPCOUNT", T_(OP_POPCOUNT) },
{"TZCOUNT", T_(OP_TZCOUNT) },
{"BYTELEN", T_(OP_BYTELEN) },
+4
View File
@@ -286,6 +286,7 @@
%token OP_ISCONST "ISCONST"
%token OP_LOG "LOG"
%token OP_LOW "LOW"
%token OP_POPCOUNT "POPCOUNT"
%token OP_POW "POW"
%token OP_READFILE "READFILE"
%token OP_REVCHAR "REVCHAR"
@@ -1396,6 +1397,9 @@ relocexpr_no_str:
| OP_BITWIDTH LPAREN relocexpr RPAREN {
$$.makeUnaryOp(RPN_BITWIDTH, std::move($3));
}
| OP_POPCOUNT LPAREN relocexpr RPAREN {
$$.makeUnaryOp(RPN_POPCOUNT, std::move($3));
}
| OP_TZCOUNT LPAREN relocexpr RPAREN {
$$.makeUnaryOp(RPN_TZCOUNT, std::move($3));
}
+3
View File
@@ -279,6 +279,9 @@ void Expression::makeUnaryOp(RPNCommand op, Expression &&src) {
case RPN_TZCOUNT:
data = op_tzcount(val);
break;
case RPN_POPCOUNT:
data = op_popcount(val);
break;
// LCOV_EXCL_START
default:
// `makeUnaryOp` should never be called with a non-unary operator!
+3
View File
@@ -182,6 +182,9 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
case RPN_TZCOUNT:
value = op_tzcount(popRPN(patch));
break;
case RPN_POPCOUNT:
value = op_popcount(popRPN(patch));
break;
case RPN_OR:
value = popRPN(patch) | popRPN(patch);
+4
View File
@@ -141,3 +141,7 @@ int32_t op_bitwidth(int32_t value) {
int32_t op_tzcount(int32_t value) {
return value != 0 ? ctz(static_cast<uint32_t>(value)) : 32;
}
int32_t op_popcount(int32_t value) {
return popcount(static_cast<uint32_t>(value));
}
+6
View File
@@ -9,3 +9,9 @@ assert TZCOUNT(-1) == 0
assert TZCOUNT($80000000) == 31
assert TZCOUNT(1.0) == 16
assert POPCOUNT(0) == 0
assert POPCOUNT(1) == 1
assert POPCOUNT(-1) == 32
assert POPCOUNT(%10101100) == 4
assert POPCOUNT(-%10101100) == 27
+1
View File
@@ -30,3 +30,4 @@ dw @ >>> 1
db BITWIDTH(@)
db TZCOUNT(@)
db POPCOUNT(@)
Binary file not shown.