如何编写将 0xFF 置于匹配通道中的 SWAR 比较?
Posted
技术标签:
【中文标题】如何编写将 0xFF 置于匹配通道中的 SWAR 比较?【英文标题】:How to write a SWAR comparison which puts 0xFF in a lane on matches? 【发布时间】:2021-08-07 20:33:19 【问题描述】:我正在尝试编写一个 SWAR 等式比较操作,在 uint64_t
上工作,假装是 uint8_t
的 8 个“通道”。根据 Hacker's Delight 和 Bit Twiddling Hacks 中的技术,我设法达到的最接近的结果如下:
uint64_t compare_eq (uint64_t x, uint64_t y)
uint64_t xored = x ^ y;
uint64_t mask = 0x7F * 0x0101010101010101ULL;
uint64_t tmp = (xored & mask) + mask;
return ~(tmp | xored | mask);
但是,这会将0x80
放入匹配的“通道”,将0x00
放入不匹配的“通道”,而我希望0xFF
放入匹配的“通道”,0x00
放入“通道” '那不是。不分支可以写吗?
【问题讨论】:
一旦你有字节宽的 MSB,(所以0x80
或 0x00
每个字节通道)右移 7 然后乘以 0xff
(255)。
@njuffa 对我来说,这看起来像是一个(体面的)答案。
@njuffa:相当于(x << 1) - (x >> 7)
,如果你不相信你的编译器会为你解决这个问题。
@NateEldredge x << 1
如果上车道是 0x80 会溢出
@phuclv:是的,但无论如何结果都是正确的(无符号溢出在 C 中定义良好)。在这种情况下,顶部通道将从 0 中减去 1,即 0xff。
【参考方案1】:
为了记录,这只是一个变体,用于计算非零字节中的高位(少一条指令)与来自 @njuffa 和 @Nate Eldredge 的 cmets(可能比 4386427 的答案更有效)。
uint64_t compare_eq (uint64_t x, uint64_t y)
uint64_t xored = x ^ y;
uint64_t mask = ((((xored >> 1) | 0x8080808080808080) - xored) & 0x8080808080808080);
return (mask << 1) - (mask >> 7);
【讨论】:
哎呀,我忘了我必须反转哪种字节映射到 0 和 0x80 的逻辑。希望现在修复。 其实不,这不是问题所在。你能举一个输入错误结果的例子吗? 好的,我现在明白了,希望真的修好了。很抱歉造成混乱:-/【参考方案2】:首先发布的代码中有一个错误(错字?):
uint64_t mask = 0x7F * 0x0101010101010101ULL;
^^
Missing 0x
一旦车道中有 0x80 或 0x00,您可以除以 0x80 并乘以 0xff。
喜欢:
uint64_t compare_eq (uint64_t x, uint64_t y)
uint64_t xored = x ^ y;
uint64_t mask = 0x7F * 0x0101010101010101ULL;
uint64_t tmp = (xored & mask) + mask;
uint64_t res = ~(tmp | xored | mask);
res = res / 0x80;
res = res * 0xff;
return res;
【讨论】:
以上是关于如何编写将 0xFF 置于匹配通道中的 SWAR 比较?的主要内容,如果未能解决你的问题,请参考以下文章
宏任务和微任务——三目算符与加号优先级——原生的js如何禁用button——0xff ^ 33 的结果是——in的用法——正则匹配网址