我有一个大小为 N 个字符的位掩码,它是静态已知的(即可以在编译时计算,但它不是一个常量,所以我不能把它写下来),位设置为 1 表示“想要的”位。而且我有一个相同大小的值,只有在运行时才知道。我想按顺序从该值中收集“想要的”位到新值的开头。为简单起见,让我们假设所需位数为 <= 32。
完全未优化的参考代码,希望具有正确的行为:
template<int N, const char mask[N]>
unsigned gather_bits(const char* val)
{
unsigned result = 0;
char* result_p = (char*)&result;
int pos = 0;
for (int i = 0; i < N * CHAR_BIT; i++)
{
if (mask[i/CHAR_BIT] & (1 << (i % CHAR_BIT)))
{
if (val[i/CHAR_BIT] & (1 << (i % CHAR_BIT)))
{
if (pos < sizeof(unsigned) * CHAR_BIT)
{
result_p[pos/CHAR_BIT] |= 1 << (pos % CHAR_BIT);
}
else
{
abort();
}
}
pos += 1;
}
}
return result;
}
虽然我不确定该公式是否真的允许在编译时访问掩码的内容。但在任何情况下,它都可以使用,也许一个constexpr
功能或其他东西会是一个更好的主意。我不是在这里寻找必要的 C++ 魔法(我会弄清楚),只是算法。
输入/输出示例,为清楚起见,使用 16 位值和假想二进制表示法:
mask = 0b0011011100100110
val = 0b0101000101110011
--
wanted = 0b__01_001__1__01_ // retain only those bits which are set in the mask
result = 0b0000000001001101 // bring them to the front
^ gathered bits begin here
我的问题是:
执行此操作的最高效方法是什么?(是否有任何硬件说明可以提供帮助?)
如果掩码和值都被限制为
unsigned
,所以是一个单词,而不是无界的 char 数组怎么办?然后可以用固定的、简短的指令序列来完成吗?