如何编写将 0xFF 放在匹配通道中的 SWAR 比较?
How to write a SWAR comparison which puts 0xFF in a lane on matches?
我正在尝试编写一个 SWAR 比较相等操作,在 uint64_t
上假装是 uint8_t
的 8 'lanes'。根据 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
放入匹配的 'lanes' 中,将 0x00
放入不匹配的 'lanes' 中,而我希望 0xFF
中的 'lanes' 匹配,0x00
in 'lanes' 不匹配。可以不用分支写吗?
首先,发布的代码中存在错误(打字错误?):
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;
}
郑重声明,这只是计算非零字节高位的一种变体(少了一条指令)以及来自@njuffa 和@Nate Eldredge 的评论(可能比 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);
}
我正在尝试编写一个 SWAR 比较相等操作,在 uint64_t
上假装是 uint8_t
的 8 'lanes'。根据 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
放入匹配的 'lanes' 中,将 0x00
放入不匹配的 'lanes' 中,而我希望 0xFF
中的 'lanes' 匹配,0x00
in 'lanes' 不匹配。可以不用分支写吗?
首先,发布的代码中存在错误(打字错误?):
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;
}
郑重声明,这只是计算非零字节高位的一种变体(少了一条指令)以及来自@njuffa 和@Nate Eldredge 的评论(可能比 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);
}