首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RISCV无分支编码

RISCV无分支编码
EN

Stack Overflow用户
提问于 2022-05-22 19:27:58
回答 1查看 339关注 0票数 4

在Intel AVX上,有可能出现无分支代码。而不是对case0或case1进行分支,您可以计算这两种情况,并根据条件混合结果。

AVX使用喷雾器指令实现浮点的8种方式。

您也可以使用x86指令CMOVcc (有条件地执行移动操作),以标量方式完成这一操作,而不需要使用向量。

注: ARM有CSEL,NEON有VBSL

RISCV64是否可以像这样做标量移动,这样您就不必为

代码语言:javascript
复制
a = c ? x : y;

据我所知,RISCV实现是有序的,因此当不需要分支时,它将比x86受益更多。(后者至少可以左右一些指令,甚至可以推测地分支以隐藏延迟。)

对riscv最接近的w.r.t无分支操作是SLT (Set小于),但它设置为1或0,然后需要乘法吗?将SLT设置为-1或0不是更有用吗?这样我们就可以这样做了?

更新

在做时:

代码语言:javascript
复制
int foo(int a, int b, int x, int y)
{
    return a < b ? x : y;
}

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

代码语言:javascript
复制
branchless:
    SLT t0,a0,a1
    SUB t0,zero,t0
    NOT t1,t0
    AND t0,a2,t0
    AND t1,a3,t1
    OR  a0,t0,t1
    RET
    .size   branchless, .-branchless

作为以下的无分支版本:

代码语言:javascript
复制
branched:
    BGE a0,a1,.L2
    MV  a3,a2
.L2:
    MV  a0,a3
    RET
    .size   branched, .-branched

我想知道我是否对此使用了太多的说明,但我测量到的分支版本比随机数据上的非分支版本稍微快一些,但没有太多。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-22 22:48:12

提议的RISC扩展B包括cmov (有4个操作数:3个输入和一个单独的目的地!)

我认为David ( MIPS和RISC-V的主要架构师之一)真的不喜欢cmov (以及SSE/AVX这样的短向量SIMD ),并认为CPU应该专门处理“吊床”分支(如果他们想要这样做的话,就可以跳过一条指令)。差不多吧。因此,这似乎是一个哲学纯洁的例子,妨碍了包括有用的指令。(AArch64是一种更加实用的设计,在高性能实现的关键方面仍然是RISC。)

如果没有任何其他的3输入指令,并且/或可能希望将指令限制在最多2个输入。这意味着如果标量管道严格遵循这一限制,它只需要2个寄存器读取端口,而不是3个。(这也意味着,当你必须处理进位和执行相同的加法运算时,扩展精度的数学对于大于2个寄存器的数字来说是相当痛苦的。)

你可以像你说的那样模仿cmov和/ANDnot/OR,但这需要相当多的指令,而且通常不值得,除非可能是在宽而深的无序机器上,因为分支机构丢失的工作量要大得多。(mask = (c == 0) - 1;,您可以使用sltiu / add reg,reg, -1将0转换为-1,将1转换为0。)

在哪种微体系结构从CMOV中获益更多的问题上,你可以向后看,尽管无论哪种方式都有潜在的好处。一台有序机器已经不得不在一个条件分支等待条件来解决问题,而一台处理控制依赖与数据依赖的无序机器则有很大的不同。正如在gcc优化标志-O3使代码比-O2慢中所讨论的,通过cmov的数据依赖可以创建一个循环携带的依赖链,这是高度可预测分支的一个更大的瓶颈。

有一些无序的执行RISC-V设计,甚至有些是开源的.例如,Erik链接了伯克利故障机(BOOM)

分机B:他们把他们遗漏的所有有趣的指令放在那里

RISC-V扩展B方案有一个有条件的移动,还有标量min/max、popcount、前导/尾随零计数、位字段插入/提取、两寄存器移位以及一系列更深奥的内容。https://five-embeddev.com/riscv-bitmanip/draft/bext.html#conditional-move-cmov

从建议的指令列表来看,令人惊讶的是,在基准RISC-V中遗漏了什么,就像窄整数的符号扩展(目前需要slli/srai),如果调用约定或加载指令还没有保证的话,以及大多数ISAs所拥有的流行计数和前导/尾随零计数之类的标准内容。

哥德波特使用cmovminsext.b显示clang12.0。在那个经典版本中,-O3 -Wall -menable-experimental-extensions -march=rv32gcb0p93是实现这一目标的神奇咒语。扩展B0.93由字符串的b0p93部分启用。(扩展B还没有完成,我也不知道clang14.0需要什么版本;它的错误消息没有帮助,只是普通的-march=rv32gcb没有让编译器真正使用cmov。)

代码语言:javascript
复制
//  -march=rv32gcb0p93 includes extension b 0.93 (0p93)

int sel(int x, int y, int c){
    return c ? x : y;
}
# extension B  clang
        cmov    a0, a2, a0, a1
        ret

# baseline gcc11.3  (clang and GCC12 waste several mv instructions)
        bne     a2,zero,.L2
        mv      a0,a1
.L2:
        ret
代码语言:javascript
复制
int min(int x, int y, int c){
    return (x<y) ? x : y;
}
# extension B  clang
        min     a0, a0, a1
        ret

# baseline gcc
        ble     a0,a1,.L5
        mv      a0,a1
.L5:
        ret
代码语言:javascript
复制
int sext(int c){
    return (signed char)c;
}
# extension B  clang
        sext.b  a0, a0
        ret

# baseline gcc
        slli    a0,a0,24
        srai    a0,a0,24
        ret
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72340698

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档