6.3.3. 特殊的预取类型:猜测

一个现代处理器的 OoO 执行能力允许在不与彼此冲突的情况下搬移指令。举例来说(这次使用 IA-64 为例):

st8        [r4] = 12
add        r5 = r6, r7;;
st8        [r18] = r5

这段程序序列将 12 储存至由暂存器 r4 指定的地址、将 r6r7 暂存器的内容相加、并将它储存在暂存器 r5 中。最后,它将总和储存至由暂存器 r18 指定的地址。这里的重点在于,加法指令能够在第一个 st8 指令之前 –– 或者同时 –– 执行,因为并没有资料的依赖关系。但假如必须载入其中一个加数会怎么样呢?

st8        [r4] = 12
ld8        r6 = [r8];;
add        r5 = r6, r7;;
st8        [r18] = r5

额外的 ld8 指令将值载入到由 r8 指令的地址。在这个载入指令与接下来的 add 指令之间有个明确的资料依赖关系(这便是指令后面的 ;; 的理由,感谢提问)。这里的关键在于,新的 ld8 指令 –– 不若 add 指令 –– 无法被移到第一个 st8 前面。处理器无法在指令解码的期间足够快速地决定储存与载入是否冲突 –– 即,r4r8 是否可能有相同的值。假如它们有相同的值,st8 指令会决定载入到 r6 的值。更糟的是,在载入错失cache的情况下,ld8 可能也会随之带来漫长的等待时间。IA 64 架构针对这种情况支援猜测式载入(speculative load):

ld8.a      r6 = [r8];;
[... other instructions ...]
st8        [r4] = 12
ld8.c.clr  r6 = [r8];;
add        r5 = r6, r7;;
st8        [r18] = r5

新的 ld8.ald8.c.clr 指令是一对的,并取代前一段程序序列的 ld8 指令。ld8.a 为猜测式载入。这个值无法被直接使用,但处理器能开始运作。这时,当到达 ld8.c.clr 指令的时候,这个内容可能已经被载入(假定这个间隔中有足够数量的指令)。这个指令的引数(argument)必须与 ld8.a 指令相符。若是前面的 st8 指令没有覆写这个值(即 r4r8 相同译注),就什么也不必做。猜测式载入做它的工作,而载入的等待时间被隐藏。若是载入与储存冲突,ld8.c.clr 会重新从memory载入值,而我们最终会得到一个正常的 ld8 指令的语义。

猜测式载入(仍?)没有被广泛使用。但如同这个例子所显示的,它是个非常简单而有效的隐藏等待时间的方法。预取基本上是等同的东西,并且对有著少量暂存器的处理器而言,猜测式载入可能没多大意义。猜测式载入有直接将值载入到暂存器中,而不载入到可能会被再次逐出的cache行(举例来说,当执行绪被移出排程〔deschedule〕的时候)这个(有时很大的)优点。如果能够使用猜测的话,应该要使用它。

译注. r4r8 相同指的是「值会被覆写的情况」。

results matching ""

    No results matching ""