mirror of
https://github.com/gbdev/rgbds.git
synced 2026-10-05 19:56:18 +00:00
Add POPCOUNT function (#2166)
This commit is contained in:
1 parent
ff6f1699e9
commit
d95e9260e4
13 files changed
+45
-3
No files matched your search
+17
-3
@@ -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
|
||||
|
||||
@@ -57,6 +57,7 @@ enum RPNCommand {
|
||||
RPN_LOW = 0x71,
|
||||
RPN_BITWIDTH = 0x72,
|
||||
RPN_TZCOUNT = 0x73,
|
||||
RPN_POPCOUNT = 0x74,
|
||||
|
||||
RPN_CONST = 0x80,
|
||||
RPN_SYM = 0x81
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) },
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -30,3 +30,4 @@ dw @ >>> 1
|
||||
|
||||
db BITWIDTH(@)
|
||||
db TZCOUNT(@)
|
||||
db POPCOUNT(@)
|
||||
Binary file not shown.
Reference in new issue
Block a user