标签: swar

并行地将 64 位整数中的压缩 8 位整数减去 1,SWAR 没有硬件 SIMD

如果我有一个 64 位整数,我将其解释为一个包含 8 个元素的压缩 8 位整数数组。我需要1在处理溢出时从每个压缩整数中减去常量,而一个元素的结果不会影响另一个元素的结果。

我现在有这个代码并且它可以工作,但我需要一个解决方案来并行地减去每个打包的 8 位整数并且不进行内存访问。在 x86 上,我可以使用类似的 SIMD 指令psubb并行减去打包的 8 位整数,但我正在编码的平台不支持 SIMD 指令。(在这种情况下为 RISC-V)。

因此,我正在尝试执行SWAR(寄存器内的 SIMD)以手动取消 a 的字节之间的进位传播uint64_t,执行与此等效的操作:

uint64_t sub(uint64_t arg) {
    uint8_t* packed = (uint8_t*) &arg;

    for (size_t i = 0; i < sizeof(uint64_t); ++i) {
        packed[i] -= 1;
    }

    return arg;
}
Run Code Online (Sandbox Code Playgroud)

我认为你可以用按位运算符来做到这一点,但我不确定。我正在寻找一种不使用 SIMD 指令的解决方案。我正在寻找一个非常便携的 C 或 C++ 解决方案,或者只是它背后的理论,这样我就可以实现我自己的解决方案。

c c++ bit-manipulation simd swar

79
推荐指数
5
解决办法
5017
查看次数

最小/最大寄存器内 SIMD 版本

假设我有两个uint16_t[4]数组,a并且b. 这些数组中的每个整数都在 [0, 16383] 范围内,因此未设置第 14 和 15 位。a[i]然后我有一些代码来查找每个b[i]之间的最小值和最大值i

uint16_t min[4], max[4];
for (int i = 0; i < 4; i++) {
    if (a[i] < b[i]) {
        min[i] = a[i];
        max[i] = b[i];
    } else {
        min[i] = b[i];
        max[i] = a[i];
    }
}
Run Code Online (Sandbox Code Playgroud)

假设由于某种原因我不能/不会使用 SIMD,但我仍然想在 64 位平台上尽可能快地计算它。因此,一个自然的解决方案是在 64 位寄存器上使用 SIMD 寄存器内 (SWAR) 范例,在单次迭代中计算这 4 个值,而不是使用 16 位算术进行超过 4 次迭代。

可以使用哪些位操作技巧来使用 SWAR 范例来实现(最小或最大)或理想情况下这两种操作,以便生成的代码比上面的循环更快?我的目标架构是 ARMv8,因此请随意使用任何有助于减少指令数量的 ARMv8 指令。

C、汇编或 C+ …

c assembly bit-manipulation arm64 swar

12
推荐指数
1
解决办法
409
查看次数

按段比较 64 位整数

我有两个 64 位整数xy. 每个代表5个无符号短整数:前10位代表第一个整数,接下来的13位代表第二个整数,接下来的16位代表第三个整数,接下来的14位代表第四个整数,其余位代表第 5 个整数。

x0x1x2x3x4是构成5个短整型x。设y0y1y2y3y4是构成5个短整型y。我需要知道是否x0 < y0AND x1 < y1AND x2 < y2AND x3 < y3AND x4 < y4

我认为最简单的解决方案是转移:

bool allLess(std::size_t x, std::size_t y)
{
  if(x >= y) return 0;
  int shift[] = {10, 13, 16, 14};
  for(int i = 0; i < …
Run Code Online (Sandbox Code Playgroud)

c++ bit-manipulation swar

5
推荐指数
1
解决办法
262
查看次数

如何实现 SWAR 无符号小于?

我试图使用s 的uint64_t8 个车道uint8_t;我的目标是实现逐车道小于。如果相应车道 in的值小于该车道 in 的值,则此操作,给定xy,应0xFF在车道内产生结果,否则。逐车道小于或等于也可以。xy0x00

根据我所看到的,我猜我需要一个车道差异或零操作(定义为doz(x, y) = if (x < y) then 0 else (x - y)),然后使用它来构建一个选择掩码。但是,我见过的所有车道减法方法都是有符号的,我不确定如何使用它们来完成此类任务。

有没有办法做到这一点,使用差异或零或其他方式?

c bit-manipulation swar

5
推荐指数
3
解决办法
213
查看次数

两个压缩有符号整数相乘

Stockfish 国际象棋引擎需要存储残局得分和中局得分以进行评估。

它将它们打包成一个 ,而不是单独存储它们int。中局得分存储在低 16 位中。如果中局得分为正,则残局得分存储在高 16 位中;如果中局得分为负,则减一。

这样做的优点是可以并行地对两个数字进行运算(加法、减法、求反和乘法)。

这是代码:

/// Score enum stores a middlegame and an endgame value in a single integer (enum).
/// The least significant 16 bits are used to store the middlegame value and the
/// upper 16 bits are used to store the endgame value. We have to take care to
/// avoid left-shifting a signed int to avoid undefined behavior.
enum Score : int { SCORE_ZERO };

constexpr Score make_score(int mg, …
Run Code Online (Sandbox Code Playgroud)

c++ bit-manipulation swar stockfish

5
推荐指数
1
解决办法
434
查看次数

一个寄存器可以同时保存多个值吗?

对于 64 位 x86 寄存器,如果一个值的大小足够小以至于多个指令可以放入一个寄存器中,是否可以在同一寄存器中一次保存多个值?例如,将两个 32 位整数装入一个寄存器。如果可能的话,这会是一件坏事吗?我一直在阅读寄存器,并且对这个概念很陌生。

assembly x86-64 simd cpu-registers swar

3
推荐指数
1
解决办法
2284
查看次数

为每个 int8_t 元素添加两个具有饱和度的向量(uint64_t 类型)

我最近面临一个给定的问题:

\n
\n

向量中有8个元素,每个元素都用int8_t表示。

\n

在 x86_64 中实现一个算法,将两个向量(uint64_t 类型)相加。

\n

添加元素时应考虑饱和算术。

\n

例如:

\n

80 + 60 = 127

\n

(\xe2\x88\x9240) + (\xe2\x88\x92100) = \xe2\x88\x92128

\n
\n

最大的挑战是施加的限制:

\n
    \n
  • 除ret外无条件指令;没有跳跃、cmove、set 等。
  • \n
  • 该解不能长于 48 条指令(存在短于 37 条指令的解)
  • \n
\n

我想不出任何符合这些限制的解决方案。\n有人能给我一些提示吗?欢迎使用 C 语言的示例。

\n

我只能使用“标准”、传输、算术、逻辑指令和标准寄存器:

\n
    \n
  • mov cbw/cwde/cdqe cwd/cdq/cqo movzx movsx
  • \n
  • 添加 sub imul mul idiv div inc dec neg
  • \n
  • 和或异或非 sar sarx shr shrx shl shlx ror rol
  • \n
  • 雷雷
  • \n
\n

assembly bit-manipulation x86-64 saturation-arithmetic swar

0
推荐指数
1
解决办法
270
查看次数