因此,根据我对延迟槽的理解,它们发生在调用分支指令并且分支之后的下一条指令也从内存中加载时。这有什么意义?您不希望分支之后的代码在分支被占用的情况下不会运行吗?如果分支没有被占用,是否可以节省时间?
我正在看一个流水线图,似乎分支后的指令无论如何都在执行..
因此,根据我对延迟槽的理解,它们发生在调用分支指令并且分支之后的下一条指令也从内存中加载时。这有什么意义?您不希望分支之后的代码在分支被占用的情况下不会运行吗?如果分支没有被占用,是否可以节省时间?
我正在看一个流水线图,似乎分支后的指令无论如何都在执行..
如今,大多数处理器都使用管道。H&P 书中的想法和问题无处不在。在撰写这些原始著作时,我会假设实际的硬件与管道的特定概念相匹配。获取、解码、执行、写回。
基本上,流水线是一条流水线,其中有四个主要阶段,因此您最多可以同时处理四个指令。这混淆了执行一条指令需要多少个时钟的概念,它需要多个时钟,但如果你有一些/许多并行执行,那么“平均值”可以接近或超过每个时钟一个。
当您在流水线失败时选择分支时。获取和解码阶段的指令必须扔掉,你必须重新开始填充,所以你需要花费几个时钟来获取、解码,然后返回执行。分支阴影或延迟槽的想法是恢复其中一个时钟。如果您声明始终执行分支之后的指令,那么当执行分支时,解码槽中的指令也会被执行,取指槽中的指令将被丢弃,并且您有一个时间洞而不是两个时间洞。因此,在管道的执行阶段,您现在可以执行、执行、清空、执行、执行...,而不是执行、空、空、执行、执行。分支的痛苦减少了 50%,你的整体平均执行速度提高了,等等。
ARM 没有延迟槽,但它也给出了流水线的错觉,通过声明程序计数器提前两条指令。任何依赖于程序计数器(pc 相对寻址)的操作都必须使用提前两条指令的 pc 计算偏移量,对于 ARM 指令,原始 thumb 4 字节为 8 字节,当您添加 thumb2 指令时,它会变得混乱。
在这一点上,这些都是学术界之外的幻想,管道更深,有很多技巧,等等,以便遗留代码继续工作,和/或不必重新定义指令如何为每个架构更改工作(想象 mips rev x, 1 个延迟槽,rev y 2 个延迟槽,rev z 如果条件 a 则为 3 个槽,如果条件 b 为 2 个槽,如果条件 c 为 1 个槽)处理器继续执行分支后的第一条指令,并丢弃其他少数或十几个,因为它重新填充管道。管道的实际深度通常不会与公众分享。
我看到一个评论说这是一个 RISC 的东西,它可能从那里开始,但是 CISC 处理器使用相同的技巧,只是给人一种遗留指令集的错觉,有时 CISC 处理器只不过是一个 RISC 或 VLIW 核心用于模拟传统 CISC 指令集(微编码)的包装器。
观看它的制作方式。可视化一条流水线,流水线中的每一步都有一个任务。如果生产线中的一步用完了蓝色的东西怎么办,而要制造蓝色和黄色的产品,您需要蓝色的东西。因为有人搞砸了,你不能再过一周得到新的蓝色什么。所以你必须停止生产线,改变每个阶段的供应,并制作一段时间的红色和绿色产品,这通常可以在不倾倒生产线的情况下正确分阶段进行。这就像在装配线深处某处的分支发生的事情,导致生产线不得不改变,转储生产线。延迟槽是一种将一个产品从必须在生产线中丢弃的情况中恢复的方法。不是在生产线停止前推出 N 个产品,而是每次生产运行 N+1 个产品。
您不希望分支之后的代码在分支被占用的情况下不会运行吗?
但已经太晚了。CPU 流水线的全部目的是您希望在每个周期完成一条指令。实现这一目标的唯一方法是每个周期获取一条指令。因此,在 CPU 注意到必须执行分支之前,已经获取了分支指令之后的代码并且正在运行中。
这有什么意义?
无关紧要。这不是一个特性,它只是这种管道设计的产物。
RISC 架构的理念是简化解码并优化流水线以提高速度。CPU 尝试通过流水线来重叠指令执行,因此同时执行了几条指令。
延迟槽的重点是执行一条指令,该指令已经通过部分管道,现在位于一个槽中,否则只能被丢弃。
优化器可以在分支目标处获取第一条指令并将其移动到延迟槽,使其“免费”执行。
该功能没有成为主流,主要是因为世界标准化了现有的 ISA 1设计,即 x86 和 x86-64,但也有另一个原因。
晶体管数量的二次爆炸使得非常复杂的解码器成为可能。无论如何,当架构上可见的 ISA 被转换为微操作时,像延迟槽这样的小技巧就变得不重要了。
在流水线实现的教科书示例中,CPU获取、解码、执行和写回. 这些阶段都发生在不同的时钟周期中,因此实际上每条指令在 4 个周期内完成。然而,当第一个操作码即将被解码时,下一个操作码会从内存中加载。当 CPU 完全占用时,有 4 条不同指令的一部分同时处理,CPU 的吞吐量为每个时钟周期一条指令。
当机器码中有一个序列时:
sub r0, #1
bne loop
xxx
处理器可以从write back stage ofsub r0, #1
到execute stage of反馈信息bne loop
,但同时 xxx 已经在 stage fetch中。为了简化展开流水线的必要性,CPU 设计人员选择使用延迟槽。延迟槽中的指令被取出后,取出单元具有正确的分支目标地址。优化编译器很少需要在延迟槽中放置 NOP,但会在其中插入两个可能的分支目标都需要的指令。