Pentium 及 MMX 代码的优化
调度
[第二节常规的优化方案][第四节:指令选择]
调度或配对是各代处理器都应使用的一种优化性能的方法.
下面是一个在奔腾和 P6系列处理器上, 用以提高代码速度的配对和调度表.
在某些情况下, 对特定的处理器具有达到最佳性能的变通方案.
这些变通的方法因应用程序的特性而不同. 在超标量的奔腾处理器中,
指令的顺序是使处理器达到最高性能的非常重要的因素.
对指令顺序的重新安排增加了将两条指令安排成同时运行的可能性.
与数据相关的指令应被至少一条其它指令所分开.
本书描述了你需要了解的 MMXTM 指令与整数指令配对的原则.
对下表列出的每一种情况, 都在小节中说明了与之相配的原则.
进行配对所需了解的几个规则:
- 通用配对规则:规则仅与机器状态有关, 与指定的操作码无关.
对整数和浮点同样有效. 例如, 单步指令禁止指令配对.
- 整数配对规则: 对整数指令配对的规则.
- 对 MMXTM 指令配对的规则: 由于只存在一个乘法器单元,
规则允许两个 MMXTM 指令同时执行.
- MMXTM指令与整数指令配对规则: 对一条 MMXTM
指令和一条整数指令配对的规则.
注意浮点指令不可以与 MMXTM指令配对.
关于奔腾处理器通用配对规则, 请参见
《对Intel32位处理器的优化》应用部分 AP—526(序号242816).
具有 MMXTM技术的奔腾处理器降低了一些通用配对的规则要求:
- 如果两条指令中存在一条长度大于7字节的指令, 奔腾处理器不对它们进行配对.
具有 MMXTM 技术的奔腾处理器,
不对第一条指令大于11字节或第二条指令大于7字节的指令进行配对,前缀不计算在内.
- 有前缀的指令可在 U管道配对. 前缀为0FH, 66H或67H 的指令也可在 V管道中配对.
当下列两种情况发生时不能进行配对:
- 后两条指令是不可配对指令(见下表可配对指令汇总: 并参见
《对 Intel32位处理器的优化》应用部分 AP-526,
附录 A包含了一个指令配对特性的完整列表).
通常, 大多数简单的 ALU指令是可配对的.
- 后两条指令属于寄存器争用(显式或隐式的)的一些类型.
这一规则有一些特例.在较少的情况下, 寄存器争用的指令也可配对.
这种情况在3.2.3中解释.
表 3-1:整数指令配对
在 U 管道中可配对指令 |
在 V 管道中可配对指令 |
|
mov r,r | alu r,i | push r |
mov r,r | alu r,i | push r |
mov r,m | alu m,i | push i |
mov r,m | alu m,j | push l |
mov m,r | alu eax,i | pop r |
mov m,r | alu eax,i | pop r |
mov r,i | alu m,r | nop |
mov r,i | alu m,r | jmp near |
mov m,i | alu r,m | shift/rot by l |
mov m,i | alu r,m | jcc near |
mov eax,m | inc/dec r | shift by imm |
mov eax,m | inc/dec r | oF jcc |
mov m,eax | inc/dec m | test reg, r/m |
mov m,eax | inc/dec m | call near |
alu r,r | lea r,m | test acc,imm |
alu r,r | lea r,m | nop |
| | |
test reg,r/m | cc,imm | test a |
|
不可配对指令(NP)
- 移位计数在cl的shift/rotate指令.
- 长算术指令, 如: MUL, DIV.
- 扩充指令, 如: RET, ENTER, PUSHA, MOVS, STOS, LOOPNZ.
- 某些浮点指令, 如 FSCALE, FLDCW, FST.
- 跨段(Inter-Segment)指令, 如: PUSH sreg, CALL far.
在 U或 V管道中的可配对指令(UV)
- 大多数8/32位 ALU操作, 如: ADD, INC, XOR.
- 所有的8/32位比较指令, 如: CMP, TEST.
- 所有8/32位对寄存器操作的指令, 如: PUSH reg, POP reg.
U管道中可配对指令(PU)
下列指令必须在 U管道中使用, 并可与适当的 V管道中指令配对,
这些指令不能在 V管道中执行.
- 进位和借位指令, 如: ADC, SBB.
- 有前缀的指令, 但0FH, 66H或67H前缀的指令除外(参见 2.3节)
- 用立即数移位的指令.
- 某些浮点操作, 如: FADD, FMUL, FLD.
在 V 管道配对的指令(PV)
这些指令可以在 U管道或 V管道中执行, 但只能在 V管道中配对.
由于这些指令改变了指令指针(eip), 所以如果下一个指令可能是不相邻的指令时,
不能在 U管道中配对. 即使当一个管道中的分支被预测为"未提取"时,
当前指令也不能和下一指令配对.
- 简单的控制传输指令, 如: Call near, jmp near, jcc.
包括 jcc 的短分支和 JCC近分支(具有0F 前缀)的条件分支指令.
- fxch
指令配对也受指令操作数的影响, 由于寄存器争用使下列组合不能配对,
本规则的例外情况见下节.
- 第一条指令向一个寄存器写, 而第二条指令从该寄存器中读(流相关).例如:
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 reg/imm ; push reg/imm
- push reg/imm ; call
- pop reg ; pop reg
状态代码:
注意这些特定配对由 PUSH/POP指令指定,
且只能是立即数或寄存器操作数, 不能是内存操作数.
有些配对指令可以同时安排进入管道, 但却并不能并行执行.
作为对 U管道 MMXTM 指令与 V管道整数指令配对规则的补充,
须增加下列两条规则.
- 如果两条指令都访问同一个数据高速缓存的存贮体,
则第二条( V管道)指令的申请必须等到第一条指令的申请完成.
当两个物理地址的第2至4位相同时, 发生存贮体冲突.
存贮体冲突的产生将对 V管道的指令产生一个时钟周期的额外迟延.
- 跨管道的并发执行将保持内存访问的顺序.
一条 U管道中的多时钟周期的指令将单独执行,
直到它最后的内存数据存取完成.
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 移位器单元, 两条都使用 MMXTM
移位器单元(pack,unpack和 shift类指令)的 MMXTM 指令不能配对.
移位操作既可以安排在 U管道执行, 也可以安排在 V管道执行,
但不能在同一个时钟周期内安排在两个管道内执行.
- 由于只存在一个 MMXTM乘法器单元,
所以两条都使用MMXTM乘法器单元(pmull, pmulh, pmadd类指令)
的 MMXTM 指令不能配对. 乘法操作可以安排在 U管道,
也可以安排在 V管道, 但不能在同一时钟周期内安排在两个管道内执行.
- 对内存或整数寄存器文件访问的 MMXTM 指令只能安排在U管道中.
不要将这些指令调度到 V管道中. 应使它们等待, 并安排在下一个指令对中
(且位于 U管道中).
- U管道指令的 MMXTM目的寄存器不能与 V
管道指令的源或目的寄存器匹配(相关检查).
- EMMS指令不可配对.
- 如果 CR0, TS或 CR0被设置, MMXTM 指令不能进入 V管道.
- 浮点指令不能紧跟 MMXTM指令.
- V管道的 MMXTM 指令不能访问内存或整数寄存器文件.
- U管道的整数指令是可配对的 U管道整数指令(参见表3-1)。
- V管道指令是一个可配对的整数 V管道指令(参见表3-1)。
- U管道的 MMXTM 指令不能访问内存或整数寄存器文件.
包括乘法指令在内, 全部 MMXTM 指令均可流水作业,
除乘法指令耗费3个时钟周期外, 全部指令执行时耗费一个时钟周期.
由于乘法指令执行时用三个时钟周期,
所以乘法指令后的结果只能被安排在三个时钟周期后的指令使用.
考虑这一因素, 避免在乘法指令后的两个指令对内调度一条与之相关的指令.
如(原书)2.1.1节所述, 在对寄存器写后再对寄存器存贮,
必须等待两个时钟周期来修改寄存器. 为避免管道阻塞,
存贮调度在修改寄存器的两个时间钟周期后进行.