当前位置: 首页 > 知识库问答 >
问题:

x86_64-程序集-循环条件和无序

刁浩言
2023-03-14

(如果是这样的话,我会自己做的。)

我的问题是:

为了方便起见,我倾向于避免使用间接/索引寻址模式。

作为替代,我经常使用立即寻址、绝对寻址或寄存器寻址。

代码:

; %esi has the array address. Say we iterate a doubleword (4bytes) array.
; %ecx is the array elements count
(0x98767) myloop:
    ... ;do whatever with %esi
    add $4, %esi
    dec %ecx
    jnz 0x98767;

在这里,我们有一个序列化的组合(dec和jnz),它可以防止正确的乱序执行(依赖)。

有没有办法避免这种情况/打破dep?(我不是装配专家)。

共有1个答案

祝允晨
2023-03-14

在为英特尔CPU进行优化时,始终将标志设置指令放在条件跳转指令之前(如果它是下表中列出的简单指令之一),以便它们可以在解码器中宏融合到一个uop中。

对于不进行宏融合的较旧CPU来说,这样做并不会显著恶化。提前设置标志可能会将此类CPU的分支预测失误惩罚缩短1,但无序执行意味着提前移动一对指令不会产生真正的影响。请参阅通过提前计算条件来避免管道失速。为了真正有所作为,您可以在一些可以更简单地计算的东西上展开循环和/或分支,理想情况下不依赖于缓慢的输入,因此OoO exec可以在处理循环体的旧迭代时已经解决分支。i、 e.回路计数器dep链可以在主工作之前运行。

我没有基准测试,但我不认为越来越少的CPU的小缺点可以证明错过进行融合的CPU的前端吞吐量优势(解码和发布)是合理的。uop总吞吐量通常是一个瓶颈。

AMD推土机/Piledriver/蒸汽压路机可以将test/cmp与任何jcc融合,但仅限于test/cmp,而不是任何其他ALU指令。所以肯定把比较与分支放在一起。如果英特尔CPU能够在sandybridge系列上进行宏融合,那么将其他东西与分支放在一起仍然很有价值。

来自Agner Fog的微通道指南,表9.2(针对Sandybridge/Ivybridge):

First       | can pair with these  |  cannot pair with
instruction | (and the inverse)    |
---------------------------------------------
cmp         |jz, jc, jb, ja, jl, jg|   js, jp, jo
add, sub    |jz, jc, jb, ja, jl, jg|   js, jp, jo
adc, sbb    |none                  |
inc, dec    |jz, jl, jg            |   jc, jb, ja, js, jp, jo
test        | all                  |
and         | all                  |
or, xor, not, neg | none           |
shift, rotate     | none           |

Table 9.2. Instruction fusion

所以基本上,inc/dec可以与jcc宏融合,只要条件仅取决于由inc/dec修改的位。

(否则,它们不会进行宏融合,您会插入一个额外的uop来合并标志(例如,当您在写入al后读取eax时)。或者在早期的CPU上,部分标志暂停。)

Core2/Nehalem的宏融合能力更有限(仅适用于具有更有限JCC组合的CMP/TEST),Core2根本无法在64位模式下进行宏融合。

如果你还没有,也可以阅读Agner Fog的优化ASM和C指南。它们充满了基本知识。

 类似资料:
  • 条件判断 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断。 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现: age = 20 if age >= 18: print 'your age is', age print 'adult' 根据Python的缩进规则,如果if语句判断是True,就把缩进的两行print语句执行了,否则,什么

  • 3.2.1 无循环变量的DO构造 a) 一般形式 这种DO构造形式非常简单,一般形式为: [构造名:] DO 块 END DO 不带循环控制变量的DO构造控制机制为:进入DO构造体后,从DO语句下面第一句执行起顺次执行到END DO前的最后一句,再返上来从DO语句下面第一句执行起,重复执行整个DO块。如此反复执行DO块,其间如遇到EXIT语句,就停止执行DO块,退出循环,转向执行END DO下面的

  • 我一直在研究GNU的g编译器编译的汇编,它看起来像一个无限循环(g -S file.c -o的部分输出): 除了最后一条jmp指令之外,所有这些指令都是movq或计算指令,但这只是让我们回到.L3。这是以下代码的主体: 它是如何退出循环的?看起来它只是减少了i(subq$1,-8(%rbp)),并在没有比较的情况下重新启动。

  • 本章主题 ♦ - if语句 ♦ - else语句 ♦ - elif语句 ♦ -条件表达式 ♦ - while语句 ♦ - for语句 ♦ - break语句 ♦ - continue语句 ♦ - pass语句 ♦ else语句(两次述及) ♦ Iterators迭代器 ♦ -列表解析 ♦ -生成器表达式 本章的主要内容是Python的条件和循环语句以及与它们相关的部分。我们会深入探讨if、whil

  • 程序从另一个类调用一个方法,这有助于更改程序的停止条件。它平均调用该方法3-8次,并且从未达到停止条件,但是它停止了。 示例类如下: 只限于在每个当的条件为false时,use示例类的当循环才会停止。这意味着: 它应该输出它经历了多少个同时循环以及每个循环的值。最终输出a1到e1的相同值。

  • 问题内容: 嘿,我有这段代码: 它可以工作,但是我想在循环中添加一些额外的条件,例如: 我怎样才能做到这一点? 问题答案: 使用(或): 附加到元素,这将决定是否显示它。 ng- if的 文档可以在此处找到。 但是,如果只想在循环第一个或最后一个项目时执行某项操作,则也可以使用和的属性。这些已用ng- repeat记录 。可以这样使用: