赞
踩
P1与PMMX处理器不能乱序处理。但通过下面描述的指令成对机制,它们可以同时执行两条相邻的指令。
P1与PMMX有两条流水线用于指令执行,称为U-管道及V-管道。在某些情形下,同时执行两条指令是可能的。一个在U-管道,一个在V-管道。这几乎可以使深度加倍。因此,重排指令使它们成对是有利的。
在任一管道中,以下指令是可成对的:
· MOV寄存器、内存或立即数到寄存器或内存
· PUSH寄存器或立即数,POP寄存器
· LEA,NOP
· INC,DEC,ADD,SUB,CMP,AND,OR,XOR
· 某些形式的TEST(参考手册4:指令表)。
以下指令仅在U-管道中可成对:
· ADC,SBB
· 带有立即数的SHR,SRA,SHL,SAL
· 带一个立即数的ROR,ROL,RCR,RCL
以下指令可在任一管道中执行,但仅在V-管道中可成对:
· 近程调用
· 短程及近程跳转
· 短程及近程条件跳转
所有其他整形指令仅在U-管道中执行,且不可成对。
在满足以下条件时。两条连续指令将成对:
1. 第一条指令在U-管道中可成对的,第二条指令在V-管道中可成对。
2. 第二条指令不读写第一条指令写的寄存器。例如:
;Example 4.1a. P1/PMMX pairing rules
moveax, ebx / mov ecx, eax ; Read after write, do not pair
moveax, 1 / mov eax, 2 ; Write after write, do not pair
movebx, eax / mov eax, 2 ; Write after read, pair ok
movebx, eax / mov ecx, eax ; Read after read, pair ok
movebx, eax / inc eax ; Read and write after read, pair ok
3. 在规则2中,部分寄存器被视为完整寄存器。例如:
;Example 4.1b. P1/PMMX pairing rules
moval, bl / mov ah, 0
写入同一个寄存器不同部分,不能成对。
4. 尽管有规则2与规则3,都写入标记寄存器部分的两条指令可以成对。例如:
;Example 4.1c. P1/PMMX pairing rules
shreax, 4 / inc ebx ; pair OK
5. 不管规则2,一条写入标记的指令可以与一个条件跳转成对。例如:
;Example 4.1d. P1/PMMX pairing rules
cmpeax, 2 / ja LabelBigger ; pair OK
6. 以下指令组合可以成对,而不管它们都修正栈指针的事实:
;Example 4.1e. P1/PMMX pairing rules
push+ push, push + call, pop + pop
7. 对带有前缀的指令成对存在限制。许多不实现在8086处理器上的指令有一个两字节操作码,其中第一个字节是0FH。在P1上0FH字节作为一个前缀。在PMMX及更新的处理器上,0FH字节作为操作码的部分。带有0FH前缀最常见的指令有:MOVZX,MOVSX,PUSH FS,POP FS,PUSH GS,POP GS,LFS,LGS,LSS,SETcc,BT,BTC,BTR,BTS,BSF,BSR,SHLD,SHRD及带有两个操作数且没有立即数操作数的IMUL。
在P1上,带前缀指令仅能在U-管道中执行,除了条件近程跳转。
在PMMX上,带有操作数大小或地址大小前缀的指令可以在任一管道中执行,而带有段、重复或锁前缀的指令仅能在U-管道中执行。
8. 具有位移及立即数的指令在P1上不可成对,在PMMX上仅在U-管道中可成对:
;Example 4.1f. P1/PMMX pairing rules
movdword ptr ds:[1000], 0 ; Not pairable or only in u-pipe
cmpbyte ptr [ebx+8], 1 ; Not pairable or only in u-pipe
cmpbyte ptr [ebx], 1 ; Pairable
cmpbyte ptr [ebx+8], al ; Pairable
在PMMX上,具有位移及立即数指令的另一个问题是,这样的指令可能超过7个字节,这意味着每时钟周期仅有一条指令可以被解码。
9. 这两条指令必须被预先载入及解码。在P1上这不会发生,除非第一条指令仅有一字节。
10. 对PMMX上的MMX指令,有特殊的成对规则:
· MMX shift,pack或unpack指令可以在任一管道中执行,但不能与其他MMXshift,pack或unpack指令成对。
· MMX乘法指令可以在任一管道中执行,但不能与其他MMX乘法指令成对。它们需要3个时钟周期,且以浮点指令相同的方式,最后2个周期可与后续指令重叠(参考第37页)。
· 一条访问内存或整数寄存器的MMX指令仅可以在U-管道中执行,不能与一个非-MMX指令成对。
存在情形,在一对中的两条指令不能同时执行,或时间上仅能部分重叠。不过它们仍然被视为一对,因为第一条指令在U-管道中执行,第二条在V-管道。在这个不完美对里的指令都完成前,后续指令不能开始执行。
在以下情形里,将发生不完美成对:
1. 如果第二条指令遭受了一个AGI暂停(参考第34页)。
2. 两条指令不能同时访问同一个DWORD内存。
以下例子假定ESI可被4整除:
;Example 4.2a. P1/PMMX imperfect pairing
moval, [esi] / mov bl, [esi+1]
两个操作数都在同一个DOWRD中,因此它们不能同时执行。这个对需要2个时钟周期。
;Example 4.2b. P1/PMMX perfect pairing
moval, [esi+3] / mov bl, [esi+4]
这次,两个操作数在一个DWORD边界的两边,因此,它们完美成对,仅需1个时钟周期。
3. 前面的规则被扩展到在两个地址中2-4个比特是相同的情形(缓存行冲突)。对于DWORD地址,这意味着两个地址间的差值不应该是32的倍数。
不访问内存的可成对整数指令,需要1时钟周期执行,除了误预测的跳转。至或自内存的MOV指令也需要1时钟周期,如果数据区域在缓存中且正确对齐。对复杂取址模式的使用,比如比例索引寄存器,没有速度上的惩罚。
一个读内存、执行某些计算、将结果保存进一个寄存器或标记的可成对整型指令,需要2个时钟周期(读/修改指令)。
一个读内存、执行某些计算、将结果保存回内存的可成对整型指令,需要3个时钟周期(读/修改/写指令)。
4. 如果一条读/修改/写指令与一条读/修改或读/修改/写指令成对,它们将是不完美成对。
使用的时钟周期数如下标所示:
第一条指令 | 第二条指令 | ||
| 仅MOV或寄存器 | 读/修改 | 读/修改/写 |
仅MOV或寄存器 | 1 | 2 | 3 |
读/修改 | 2 | 2 | 3 |
读/修改/写 | 3 | 4 | 5 |
表4.1. 复杂指令成对
例如:
;Example 4.3. P1/PMMX pairing complex instructions
add[mem1], eax / add ebx, [mem2] ; 4 clock cycles
addebx, [mem2] / add [mem1], eax ; 3 clock cycles
5. 当由于缓存不命中、不对齐或跳转误预测,两条成对指令都需要额外时间时,该对将需要比每条指令更多的时间,但小于两者的总和。
6. 一条后接FXCH的可成对浮点指令,如果下一条指令不是浮点指令,将形成不完美成对。
为了避免不完美成对,你必须知道哪些指令进入U-管道,哪些进入V-管道。在你的代码中往回看,查找不可成对指令、仅可在其中一个管道成对的指令,或由于上面的规则不能成对的指令,可以找到答案。
不完美成对通常可以通过重排指令来避免。例如:
;Example 4.4. P1/PMMX reorder instructions to improve pairing
L1:mov eax, [esi]
mov ebx, [esi]
inc ecx
这里两条MOV指令形成了一个不完美对,因为它们都访问相同的内存位置,结果需要3个时钟周期。你可以通过重排指令,使得INCECX与其中一个MOV指令成对,改进代码。
;Example 4.5. P1/PMMX reorder instructions to improve pairing
L2:mov eax,offset a
xor ebx, ebx
inc ebx
mov ecx, [eax]
jmp L1
INC EBX / MOV ECX,[EAX]对是不完美的,因为后者有一个AGI暂停。这个序列需要4个时钟周期。如果你插入一条NOP或其他指令,使得MOVECX, [EAX]与JMP L1成对,那么这个序列仅需要3个时钟周期。
下一个例子是16位模式,假定SP被4整除:
;Example 4.6. P1/PMMX imperfect pairing, 16 bit mode
L3:push ax
push bx
push cx
push dx
call Func
这里PUSH指令构成两个不完美对,因为每对中的操作数都进到相同的内存DWORD。PUSH BX可能可以与PUSHCX完美成对(因为它们进入一个DWORD边界的两边),但没有,因为它已经与PUSHAX成对。因此这个序列需要5个时钟周期。如果你插入一条NOP或其他指令,使得PUSHBX与PUSHCX,PUSHDX与CALLFUNC成对,那么这个序列将仅需要3个时钟周期。解决这个问题的另一个方式是确保SP不是4的倍数。知道SP是否为4的倍数,或者不在16位模式中是困难的,因此避免这个问题最好的方式是使用32位模式。
计算一条访问内存指令所需地址需要1时钟周期。通常,这个计算在之前的指令或指令对正在执行时,在流水线的一个独立阶段完成。但如果该地址依赖于在之前·时钟周期执行的一条指令的结果,计算这个地址,我们必须等待一个额外时钟周期。这称为一个AGI暂停。
;Example 4.7a. P1/PMMX AGI
addebx, 4
moveax, [ebx] ; AGI stall
在这个例子中可以去除这个暂停,通过在这两者之间插入其他一些指令,或把代码重写为:
;Example 4.7b. P1/PMMX AGI removed
moveax, [ebx+4]
addebx, 4
使用隐含使用ESP取址的指令,比如PUSH,POP,CALL与RET,如果ESP已经在前面的周期里被比如MOV,ADD或SUB这样的指令改变了,你也会得到一个AGI暂停。P1与PMMX有特殊的电路来预测一个栈操作后ESP的值,使得你不会在PUSH,POP或CALL改变了ESP后遭遇一个AGI延迟。仅在RET有加到ESP的立即数后,你会得到一个AGI暂停。例如:
;Example 4.8. P1/PMMX AGI
addesp,4 / pop esi ; AGIstall
popeax / pop esi ; nostall, pair
movesp,ebp / ret ; AGIstall
callF1 / F1: mov eax,[esp+8] ; no stall
ret/ pop eax ;no stall
ret8 / pop eax ;AGI stall
LEA指令也会遭受AGI暂停,如果它使用一个在前面时钟周期里被改变的基址或索引寄存器。例如:
;Example 4.9. P1/PMMX AGI
incesi / lea eax, [ebx+4*esi] ; AGI stall
PPro,P2与P3的内存读与LEA没有AGI暂停,但对内存写有AGI暂停。这不是非常重要,除非后续代码必须等待这个写结束。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。