在英特尔 AVX 上,存在无分支代码的可能性。您可以计算这两种情况,并根据条件混合结果,而不是针对 case0 或 case1 进行分支。
AVX 使用vblendps指令以 8 种方式实现浮动。
您还可以使用 x86 指令CMOVcc以标量方式(无需向量)执行此操作,该指令有条件地执行移动操作。
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) 对于 64 位寄存器,有CMOV cc A, B指令,仅在满足条件时B写入:Acc
; Do rax <- rdx iff rcx == 0
test rcx, rcx
cmove rax, rdx
Run Code Online (Sandbox Code Playgroud)
但是,我找不到任何与 AVX 等效的东西。我仍然想根据 的值移动RFLAGS,只是使用更大的操作数:
; Do ymm1 <- ymm2 iff rcx == 0
test rcx, rcx
cmove ymm1, ymm2 (invalid)
Run Code Online (Sandbox Code Playgroud)
有 AVX 等效项吗cmov?如果没有,我怎样才能以无分支的方式实现这个操作?
众所周知,我们可以使用 CMOV 指令来编写无分支代码,但我想知道我是否正在编写等效的指令x = cond ? 1 : 2,我应该更喜欢
CMOVE rax, 1 #1a
CMOVNE rax, 2 #1b
Run Code Online (Sandbox Code Playgroud)
或者
MOV rax, 1 #2a
CMOVNE rax, 2 #2b
Run Code Online (Sandbox Code Playgroud)
理论上,第一个可以几乎并行执行,而第二个由于数据依赖性而速度较慢。但我不确定现实情况如何。
我注意到条件移动指令的可扩展性比普通的mov. 例如,它不支持立即数,也不支持寄存器的低字节。
出于好奇,为什么该Cmov命令比一般mov命令的限制性要大得多?例如,为什么两者不允许这样的事情:
mov $2, %rbx # allowed
cmovcc $1, %rbx # I suppose setcc %bl could be used for the '1' immediate case
Run Code Online (Sandbox Code Playgroud)
附带说明一下,我注意到在使用 Compiler Explorer 时, 的使用量比和cmovcc少得多。通常是这种情况吗?如果是,为什么它的使用频率低于其他条件句?jmpccsetcc