延迟槽有什么意义?

Jam*_*mes 19 assembly mips pipelining

因此,根据我对延迟槽的理解,它们在调用分支指令时发生,并且分支之后的下一条指令也从内存加载.这有什么意义?在分支被采取的情况下,你不希望分支后的代码不运行吗?是否节省时间,以防分支机构没有被采取?

我正在查看管道图,看起来分支后的指令正在进行中..

old*_*mer 23

目前大多数处理器都使用流水线.H&P书中的想法和问题随处可见.在那些原始着作的时候,我会假设实际的硬件与管道的特定概念相匹配.获取,解码,执行,回写.

基本上,管道是装配线,在生产线上有四个主要阶段,因此您最多只能同时处理四个指令.这混淆了执行指令需要多少时钟的概念,它需要多个时钟,但如果你有一些/多个并行执行,那么"平均"可以接近或超过每个时钟一个.

虽然装配线失败,但是当你采取分支时.必须抛出提取和解码阶段中的指令,并且必须再次开始填充,因此您需要几个时钟来获取,解码,然后再执行.分支阴影或延迟槽的想法是恢复其中一个时钟.如果声明分支之后的指令总是被执行,那么当执行分支时,解码槽中的指令也会被执行,取指槽中的指令被丢弃,你有一个时间空洞而不是两个.因此,不是执行,清空,清空,执行,执行,而是在管道的执行阶段执行,执行,清空,执行,执行.... 该分支的痛苦减少了50%,整体平均执行速度提高了等等.

ARM没有延迟槽,但是通过声明程序计数器是前面的两条指令,它也给出了管道的错觉.任何依赖于程序计数器(pc相对寻址)的操作必须使用前面两条指令的pc计算偏移量,对于ARM指令,这对于原始拇指4字节是8字节,当你添加thumb2指令时它会变得混乱.

这些是学术界之外的幻想,管道更深,有很多技巧等,以便遗留代码继续工作,和/或不必重新定义指令如何适用于每个架构的变化(想象一下mips rev x,1个延迟槽,2个延迟槽,如果条件a则转3个槽,如果条件b则转2个槽,如果条件c则转1个槽)处理器继续执行分支后的第一个指令,并丢弃另一个在重新填充管道之后打了十几打.管道的实际深度通常不会与公众分享.

我看到有关这是一个RISC的评论,它可能已经开始,但CISC处理器使用相同的精确技巧,只是给出传统指令集的错觉,有时CISC处理器只不过是一个RISC或VLIW核心用于模拟传统CISC指令集(微编码)的包装器.

观看它制作的节目.可视化装配线,该行中的每个步骤都有一个任务.如果生产线中的一个步骤用尽了蓝色的产品,并且要制作蓝色和黄色的产品,那么您需要蓝色的产品.你不能再换一个新的蓝色星期,因为有人搞砸了.因此,您必须停止生产线,将耗材更改为每个阶段,并将红色和绿色产品暂时生产,这通常可以在不倾倒生产线的情况下正确分阶段进行.这就像一个分支,在装配线深处的某个地方发生的事情,导致线必须改变,转储线.延迟槽是一种恢复一个产品必须在生产线中丢弃的方法.在生产线停止之前,N + 1产品不再出现,而是在每次生产运行中出现N + 1产品.代码的执行就像生产运行的爆发一样,在命中分支到另一个短执行路径之前,你经常得到短的,有时很长的线性执行路径,分支另一个短的执行路径......

  • 请停止破坏您的内容; 这是毫无意义的,因为无论如何它将恢复到原来的状态.它实现的唯一目标是让你从网站退出这么不那么有尊严. (7认同)

Oli*_*rth 12

在分支被采取的情况下,你不希望分支后的代码不运行吗?

但现在已经太晚了.CPU管道的整个目的是您希望在每个周期完成一条指令.实现这一目标的唯一方法是每个周期获取一条指令.因此,在CPU注意到必须采取分支之前,分支指令之后的代码已经被提取并且正在进行中.

这有什么意义?

无关紧要.它不是一个功能,它只是这种管道设计的工件.

  • @James:当然,我们可以在那里放一个`nop`(事实上有些编译器会这样做).但这是次优的,因为它变成了浪费的循环.因此编译器通常会寻找在延迟槽中放置一些有用的东西的方法. (6认同)
  • @James:绝对.它们是RISC风格管道的工件,通常很痛苦.但鉴于它们不可避免地存在于这些体系结构中,编译器和狡猾的汇编程序员可能会利用它们. (3认同)
  • 因此,如果分支后的指令将值增加 1 并且分支采取后的指令减少 1,那么它无论如何都会增加它,然后在假设采取分支的情况下减少? (2认同)
  • @James:我怀疑这取决于具体的架构,以及它如何实现断点的细节. (2认同)
  • 还有一个问题。我们不能只放置一些虚拟指令来解决延迟时隙吗? (2认同)

Car*_*rum 7

即使指令出现在分支之后的程序中,它实际上也会在分支被执行之前运行.查看有关延迟槽分支危险的维基百科页面.


Dig*_*oss 6

RISC架构的想法是简化解码并优化流水线以提高速度.CPU尝试通过流水线操作重叠指令执行,因此一次执行多条指令.

延迟时隙的要点特别是执行已经通过管道的一部分的指令,并且现在处于一个否则必须被丢弃的槽中.

优化器可以在分支目标处获取第一条指令并将其移至延迟槽,使其"免费"执行.

该功能并未成为主流,主要是因为世界标准化了现有的ISA 1设计,即x86和x86-64,但也出于另一个原因.

晶体管数量的二次爆炸使非常复杂的解码器成为可能.无论如何,当架构上可见的ISA被转换为微操作时,像延迟槽这样的小黑客变得不重要.


1. ISA:指令集架构


Aki*_*nen 5

在流水线实施的教科书示例中,CPU 提取解码执行回写。这些阶段均在不同的时钟周期内发生,因此实际上,每条指令均在4个周期内完成。但是,当第一个操作码即将被解码时,下一个操作码将从内存中加载。当CPU完全占用时,有4个不同指令的一部分同时处理,并且CPU 的吞吐量是每个时钟周期一个指令。

在机器代码中时,有一个序列:

      sub r0, #1
      bne loop
      xxx
Run Code Online (Sandbox Code Playgroud)

处理器可以从的写回阶段sub r0, #1到的执行阶段反馈信息bne loop,但是同时xxx已经在获取阶段。为了简化展开管线的必要性,CPU设计人员选择使用延迟槽。在获取延迟时隙中的指令之后,获取单元具有分支目标的正确地址。优化的编译器很少需要在延迟槽中放入NOP,而是在其中插入两个可能的分支目标都必需的指令。