调度或配对是各代处理器都应使用的一种优化性能的方法. 下面是一个在奔腾和 P6系列处理器上, 用以提高代码速度的配对和调度表. 在某些情况下, 对特定的处理器具有达到最佳性能的变通方案. 这些变通的方法因应用程序的特性而不同. 在超标量的奔腾处理器中, 指令的顺序是使处理器达到最高性能的非常重要的因素.
对指令顺序的重新安排增加了将两条指令安排成同时运行的可能性. 与数据相关的指令应被至少一条其它指令所分开.
本书描述了你需要了解的 MMXTM 指令与整数指令配对的原则. 对下表列出的每一种情况, 都在小节中说明了与之相配的原则.
进行配对所需了解的几个规则:
注意浮点指令不可以与 MMXTM指令配对.
关于奔腾处理器通用配对规则, 请参见 《对Intel32位处理器的优化》应用部分 AP—526(序号242816). 具有 MMXTM技术的奔腾处理器降低了一些通用配对的规则要求:
当下列两种情况发生时不能进行配对:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
不可配对指令(NP)
在 U或 V管道中的可配对指令(UV)
U管道中可配对指令(PU)
下列指令必须在 U管道中使用, 并可与适当的 V管道中指令配对, 这些指令不能在 V管道中执行.
在 V 管道配对的指令(PV)
这些指令可以在 U管道或 V管道中执行, 但只能在 V管道中配对. 由于这些指令改变了指令指针(eip), 所以如果下一个指令可能是不相邻的指令时, 不能在 U管道中配对. 即使当一个管道中的分支被预测为"未提取"时, 当前指令也不能和下一指令配对.
指令配对也受指令操作数的影响, 由于寄存器争用使下列组合不能配对, 本规则的例外情况见下节.
mov eax, 8
mov [ebp], eax
mov eax, 8
mov eax, [ebp]
对 EFLAGS寄存器写的指令配对不受此限 (例如, 两个变换状态编码的 ALU操作), 配对后, 指令执行的状态编码为 V管道指令的状态.
注意, 两条指令中, 如果第一条读一个寄存器, 且第二条写一个已知状态(反相关), 则可以配对, 见下例:
mov eax, ebx
mov ebx, [ebp]
为了确定寄存器争用, 对一个字节或一个字寄存器的引用视同对一个完整32位寄存器的引用.因此,
mov al, 1
mov ah, 0
由于在 EAX寄存器内容上输出相关, 故不能配对.
某些特定指令不受上述"通用" 规则限制. 这些特定配对不受寄存器相关限制, 且大多数隐式地读/写 esp 寄存器或隐式地写状态码.
堆栈指针:
状态代码:
注意这些特定配对由 PUSH/POP指令指定, 且只能是立即数或寄存器操作数, 不能是内存操作数.
有些配对指令可以同时安排进入管道, 但却并不能并行执行. 作为对 U管道 MMXTM 指令与 V管道整数指令配对规则的补充, 须增加下列两条规则.
add eax, meml
add ebx, mem2 ; 1
(add) (add) ; 2 2-周期
上述指令将寄存器内容和内存单元的数值相加, 然后将结果置于寄存器中. 带内存操作数的加法将耗费两个时钟周期. 第一时钟周期从高速缓存中取数据, 第二时钟周期执行加法, 由于只有U管道指令有一个内存访问,V管道的加法可以在同一时钟周期启动.
add mem1, eax ; 1
(add) ; 2
(add)add mem2, ebx ; 3
(add) ; 4
(add) ; 5
上述指令将寄存器内容与内存单元的数值相加, 然后将结果置于内存单元中. 结果放在内存的加法, 执行时耗费三个时钟周期. 第一个时钟周期取值, 第二个时钟周期执行加法, 第三个时钟周期存贮结果. 在配对时, U管道指令的最后一时钟周期与 V管道的第一时钟周期在执行时重叠.
在已执行的指令未运行完时, 其它指令不可运行.
为了最佳地把握调度和配对的机会, 一种较好的作法是: 在耗费时钟周期数相等的情况下, 尽量安排简单指令序列代替复杂指令. 简单指令在组织时间片上占有优势. load/store 类型的代码类要求更多寄存器并将增大代码大小. 为满足这种对额外寄存器的需求, 应在寄存器分配和指令调度上进一步努力, 使仅当并行性扩大时, 额外的寄存器可被使用.
本节说明了 MMXTM指令之间的配对准则和 MMXTM 与整数指令的配对准则.
包括乘法指令在内, 全部 MMXTM 指令均可流水作业, 除乘法指令耗费3个时钟周期外, 全部指令执行时耗费一个时钟周期.
由于乘法指令执行时用三个时钟周期, 所以乘法指令后的结果只能被安排在三个时钟周期后的指令使用. 考虑这一因素, 避免在乘法指令后的两个指令对内调度一条与之相关的指令.
如(原书)2.1.1节所述, 在对寄存器写后再对寄存器存贮, 必须等待两个时钟周期来修改寄存器. 为避免管道阻塞, 存贮调度在修改寄存器的两个时间钟周期后进行.