相关疑难解决方法(0)

为什么使用 MOV 指令将 XOR 交换优化为普通交换?

在围绕Compiler Explorer进行测试时,我尝试了以下无溢出函数来计算 2 个无符号 32 位整数的平均值:

uint32_t average_1(uint32_t a, uint32_t b)
{
    if(a < b){
        a ^= b;
        b ^= a;
        a ^= b;
    }
    return b + (a - b) / 2;
}
Run Code Online (Sandbox Code Playgroud)

被编译成这样:(与激活的-O1, -O2,-O3优化相同)

average_1:
        cmp     edi, esi
        jnb     .L2
        mov     eax, edi
        mov     edi, esi
        mov     esi, eax
.L2:
        sub     edi, esi
        shr     edi
        lea     eax, [rdi+rsi]
        ret
Run Code Online (Sandbox Code Playgroud)

其中代码的交换部分经过优化,可以使用mov具有 1 个附加寄存器的指令。

我已经阅读了这些问题:

人们为什么不使用异或交换?
通过 mov、xor 交换变量的成本

并得到:

  • 使用 XOR …

c optimization gcc swap x86-64

8
推荐指数
1
解决办法
843
查看次数

RISCV无分支编码

在英特尔 AVX 上,存在无分支代码的可能性。您可以计算这两种情况,并根据条件混合结果,而不是针对 case0 或 case1 进行分支。

AVX 使用vblendps指令以 8 种方式实现浮动。

您还可以使用 x86 指令CMOVcc以标量方式(无需向量)执行此操作,该指令有条件地执行移动操作。

注意:ARM 有CSEL,NEON 有VBSL

RISCV64 可以做这样的标量移动吗,这样你就不必分支

a = c ? x : y;
Run Code Online (Sandbox Code Playgroud)

据我了解,RISCV 实现是有序的,因此在不需要分支时它比 x86 更有好处。(后者至少可以围绕一些指令进行洗牌,甚至可以推测性地分支以隐藏延迟。)

我能找到的最接近 riscv 的无分支操作是SLT(设置小于),但设置为 1 或 0,然后需要乘法?将 SLT 设置为 -1 或 0 不是更有用,这样我们就可以进行 AND 运算吗?

更新

做时:

int foo(int a, int b, int x, int y)
{
    return a < b ? x : y;
}
Run Code Online (Sandbox Code Playgroud)

我尝试了使用 SLT 的穷人版本的无分支。我不确定我是否完全正确,通过使用位掩码作为 0 - 条件(0|1),我想出了:

branchless: …
Run Code Online (Sandbox Code Playgroud)

assembly cpu-architecture riscv conditional-move branchless

7
推荐指数
2
解决办法
1657
查看次数