Pentium 及 MMX 代码的优化

调度

[第二节常规的优化方案][第四节:指令选择]


   调度或配对是各代处理器都应使用的一种优化性能的方法. 下面是一个在奔腾和 P6系列处理器上, 用以提高代码速度的配对和调度表. 在某些情况下, 对特定的处理器具有达到最佳性能的变通方案. 这些变通的方法因应用程序的特性而不同. 在超标量的奔腾处理器中, 指令的顺序是使处理器达到最高性能的非常重要的因素.

  对指令顺序的重新安排增加了将两条指令安排成同时运行的可能性. 与数据相关的指令应被至少一条其它指令所分开.

  本书描述了你需要了解的 MMXTM 指令与整数指令配对的原则. 对下表列出的每一种情况, 都在小节中说明了与之相配的原则.

  进行配对所需了解的几个规则:

  注意浮点指令不可以与 MMXTM指令配对.

3.1 通用配对规则

  关于奔腾处理器通用配对规则, 请参见 《对Intel32位处理器的优化》应用部分 AP—526(序号242816). 具有 MMXTM技术的奔腾处理器降低了一些通用配对的规则要求:

3.2 整数配对规则

  当下列两种情况发生时不能进行配对:

  1. 后两条指令是不可配对指令(见下表可配对指令汇总: 并参见 《对 Intel32位处理器的优化》应用部分 AP-526, 附录 A包含了一个指令配对特性的完整列表). 通常, 大多数简单的 ALU指令是可配对的.
  2. 后两条指令属于寄存器争用(显式或隐式的)的一些类型. 这一规则有一些特例.在较少的情况下, 寄存器争用的指令也可配对. 这种情况在3.2.3中解释.
表 3-1:整数指令配对
在 U 管道中可配对指令 在 V 管道中可配对指令
mov r,ralu r,ipush r mov r,ralu r,ipush r
mov r,malu m,ipush i mov r,malu m,jpush l
mov m,ralu eax,ipop r mov m,ralu eax,ipop r
mov r,ialu m,rnop mov r,ialu m,rjmp near
mov m,ialu r,mshift/rot by l mov m,ialu r,mjcc near
mov eax,minc/dec rshift by imm mov eax,minc/dec roF jcc
mov m,eaxinc/dec mtest reg, r/m mov m,eaxinc/dec mcall near
alu r,rlea r,mtest acc,imm alu r,rlea r,mnop
    test reg,r/mcc,immtest a

3.2.1 配对指令集

  不可配对指令(NP)

  在 U或 V管道中的可配对指令(UV)

  U管道中可配对指令(PU)

  下列指令必须在 U管道中使用, 并可与适当的 V管道中指令配对, 这些指令不能在 V管道中执行.

  在 V 管道配对的指令(PV)

  这些指令可以在 U管道或 V管道中执行, 但只能在 V管道中配对. 由于这些指令改变了指令指针(eip), 所以如果下一个指令可能是不相邻的指令时, 不能在 U管道中配对. 即使当一个管道中的分支被预测为"未提取"时, 当前指令也不能和下一指令配对.

3.2.2由于寄存器相关而不能配对的指令

  指令配对也受指令操作数的影响, 由于寄存器争用使下列组合不能配对, 本规则的例外情况见下节.

  1. 第一条指令向一个寄存器写, 而第二条指令从该寄存器中读(流相关).例如:
    
        mov  eax, 8
        mov  [ebp], eax
    
  2. 两条指令均写向同一寄存器(输出相关), 如下例:
    
        mov  eax, 8
        mov  eax, [ebp]
    

  对 EFLAGS寄存器写的指令配对不受此限 (例如, 两个变换状态编码的 ALU操作), 配对后, 指令执行的状态编码为 V管道指令的状态.

  注意, 两条指令中, 如果第一条读一个寄存器, 且第二条写一个已知状态(反相关), 则可以配对, 见下例:


    mov  eax, ebx
    mov  ebx, [ebp]

  为了确定寄存器争用, 对一个字节或一个字寄存器的引用视同对一个完整32位寄存器的引用.因此,


    mov  al, 1
    mov  ah, 0

  由于在 EAX寄存器内容上输出相关, 故不能配对.

3.2.3 特定配对

  某些特定指令不受上述"通用" 规则限制. 这些特定配对不受寄存器相关限制, 且大多数隐式地读/写 esp 寄存器或隐式地写状态码.

  堆栈指针:

  状态代码:

  注意这些特定配对由 PUSH/POP指令指定, 且只能是立即数或寄存器操作数, 不能是内存操作数.

3.2.4 配对执行的限制

  有些配对指令可以同时安排进入管道, 但却并不能并行执行. 作为对 U管道 MMXTM 指令与 V管道整数指令配对规则的补充, 须增加下列两条规则.

  1. 如果两条指令都访问同一个数据高速缓存的存贮体, 则第二条( V管道)指令的申请必须等到第一条指令的申请完成. 当两个物理地址的第2至4位相同时, 发生存贮体冲突. 存贮体冲突的产生将对 V管道的指令产生一个时钟周期的额外迟延.
  2. 跨管道的并发执行将保持内存访问的顺序. 一条 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 类型的代码类要求更多寄存器并将增大代码大小. 为满足这种对额外寄存器的需求, 应在寄存器分配和指令调度上进一步努力, 使仅当并行性扩大时, 额外的寄存器可被使用.

3.3 MMXTM指令配对准则

  本节说明了 MMXTM指令之间的配对准则和 MMXTM 与整数指令的配对准则.

3.3.1 两个 MMXTM 指令的配对

3.3.2 U管道的整数指令与V管道中的MMXTM指令配对

3.3.3 U管道的MMXTM指令与V管道中的整数指令配对

调度规则

  包括乘法指令在内, 全部 MMXTM 指令均可流水作业, 除乘法指令耗费3个时钟周期外, 全部指令执行时耗费一个时钟周期.

  由于乘法指令执行时用三个时钟周期, 所以乘法指令后的结果只能被安排在三个时钟周期后的指令使用. 考虑这一因素, 避免在乘法指令后的两个指令对内调度一条与之相关的指令.

  如(原书)2.1.1节所述, 在对寄存器写后再对寄存器存贮, 必须等待两个时钟周期来修改寄存器. 为避免管道阻塞, 存贮调度在修改寄存器的两个时间钟周期后进行.


云风工作室 制作