Pentium 及 MMX 代码的优化Word下载.docx
- 文档编号:22027061
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:24
- 大小:36.84KB
Pentium 及 MMX 代码的优化Word下载.docx
《Pentium 及 MMX 代码的优化Word下载.docx》由会员分享,可在线阅读,更多相关《Pentium 及 MMX 代码的优化Word下载.docx(24页珍藏版)》请在冰豆网上搜索。
o动态执行(P6系列)处理器中的部分寄存器阻塞
o有关分支预测的信息
▪动态分支预测
▪在动态执行(P6系列)处理器上的静态预测
3.调度
o通用配对规则
o整数配对规则
▪配对指令集
▪由于寄存器相关而不能配对的指令
▪特定配对
▪配对执行的限制
oMMXTM指令配对准则
▪两个MMXTM指令的配对
▪U管道的整数指令与V管道中的MMXTM指令配对
▪U管道的MMXTM指令与V管道中的整数指令配对
▪调度规则
4.指令选择
o使用访问内存的指令
o指令长度
5.高速缓存优化
o线读入顺序(命令)
o在高速缓存线中的数据对齐
▪优化方法1:
布尔
▪优化方法2:
写前检查
6.内存优化
o对部分内部访问
o增加内存填充和视频填充的带宽
▪内存填充
▪视频填充
规则列表及建议
[序][第二节:
常规的优化方案]
下述规则将帮助快速地开发出高效的MMXTM代码,并且这些代码可以在具有MMXTM技术的所有的处理器上运行.以下给出一张规则和建议的列表.
1.1规则
∙使用当前的编译器可以产生一个优化的应用程序.这将帮助你从一开始能产生好的代码.
∙避免部分寄存器的阻塞.参见第2.4节.
∙注意分支预测算法(参见2.5节).这是动态执行(P6-系列)处理器最为重要的优化方法.由于提高了分支预测能力,你的代码将耗费很少的周期来读取指令.
∙对代码进行调度,使其达到最大的配对可能.参见第3节。
∙确定所有的数据都已对齐.
∙安排好代码,使其未命中的高速缓存指令最少,并优化预取.参见第5节.
∙不要混用MMXTM指令和浮点指令.
∙避免使用除前缀为0F以外的操作码.参见第2.3节。
∙对同一个内存区域,避免在大数据量存贮数据后进行小数据量读取,或小数据量存贮后进行大数据量的读取.对于同一个内存区域,读取和存贮数据应使用同样大小的数据量;
并且地址要对齐.参见第6.1节.
∙在任何时候,都要尽可能地使用OP,REG和MEM格式.这些格式可以帮助你减少占用寄存器,减少循环,避免产生不必要的读取操作.参见第4.1节。
EMMS必须放在MMXTM指令的尾部.
∙优化高速缓存中的数据的带宽,以符合MMXTM寄存器的大小.参见第6节.
1.2建议
∙调整代码,一般情况下不使用向前条件分支,通常使用向后的条件分支.
∙按16字节边界条件对齐频繁执行的分支目标.
∙将循环展开来调度指令.
∙使用软件方式来安排流水线以调度迟延和功能单元.
∙必须成对使用CALL和RET(return)指令.
∙避免使用自修改代码.
∙避免把数据放在代码段.
∙尽可能快地计算出存贮地址.
∙应避免使用包含三个或三个以上微操作代码或指令长度超过7个字节的指令.如果可能,使用只有一个微操作的指令.
∙不要使用两个8位读取指令来进行16位的读取。
∙在调用被调用保存(callee—save)过程前,先清除部分寄存器的内容.
∙解决阻塞条件,如存贮地址,尽可能地避免可能引起阻塞的读取.
∙一般情况下,一个可以直接由处理器支持的N-字节的数据(8位的字节,16值的字,32位的双字,32位、64位及80位浮点数)应该对齐在下一个最高的2的乘方边界处,避免未对齐的数据.
o按任意边界对齐8位数据.
o在已对齐的4一字节字数据内对齐16位数据
o以4的任意倍数为边界,对齐32位数据.
o以8的任意倍数为边界,对齐64位数据.
o以128位为边界(即16字节的倍数),对齐80位数据。
常规的优化方案
[第一节规则列表及建议][第三节:
调度]
本节概括了Intel体系结构的重要的常规优化技术.
2.1寻址方式
在奔腾处理器上,当一个寄存器被用作基地址元素时,如果该寄存器是前一个指令的目的寄存器(假设所有的指令都已在预取队列中),将耗费一个附加的时钟周期.例如:
addesi,eax;
esi是目的寄存器
moveax,[esi];
esi是基地址,增耗费1个时钟
因为奔腾处理器有两条整数流水线,如果一个寄存器是前一时钟内任意指令的目的寄存器,这个用于计算有效地址(在任一管道)的基地址或索引元素的寄存器,将耗费一个额外的时钟周期.这种效应称为地址生成互锁(AGI).为了避免AGI,指令间应安排其它指令,并产生至少一个时钟周期的间隔来分隔这些指令.
新增的MMXTM寄存器不能当作索引寄存器或基地址使用,所以AGI不适用于MMXTM寄存器为目的寄存器的情况.
在AGI情况下,动态执行(P6-系列)处理器不产生额外迟延.
注意一些具有隐含寄存器读/写的指令,那些通过ESP(PUSH,POP,RET,CALL)而具有隐含的地址生成的指令,也会产生AGI附加迟延,如下例:
subesp,24
;
一个时钟周期的阻塞
pushebx
movesp,ebp
popebp
PUSH和POP也对ESP进行隐含的写操作,但是如果下一条指令是通过E3P寻址时,将不产生AGI.奔腾处理器通过PUSH和POP指令中的ESP"
重命名"
来避免入AGI的额外迟延,如下例:
pushedi;
无阻塞
movebx,[esp]
在具有MMXTM技术的奔腾处理器上,包含立即数和偏移量的指令可在U管道中进行配对.如果有必要使用常数,那么使用立即数通常比把常数读取到寄存器更有效.但是如果同一个立即数被多次引用,应把常数先取到一个寄存器,然后多次使用这个寄存器,这种方法将更快一些,如下例所示:
movresult,555;
555是一个立即数,result是偏移量
movwordptr[esp+4],1;
1是立即数,4是偏移量
由于MMXTM指令是双字节操作码(0x0F操作码映射),任何一个使用基地址或使用具有4字节位移的索引寻址来访问内存的指令,其指令长度为8字节.超过7字节的指令一次只能部分译码,应尽量避免使用(见4.2节).人们经常通过将立即数值加到基地址或索引寄存器的方法来减少这种指令的长度,因此要除去立即数部分.
在Intel486TM处理器中,当一个部分寄存器被写后,紧接着立即使用全部寄存器时,将产生一个附加的时钟周期.奔腾处理器在这方面无此后果,这种情况称之为部分阻塞条件,下例为奔腾处理器的例子.
moval,0;
1
mov[ebp],eax;
2-在奔腾处理器上无迟延
下列为Intel486处理器对应的例子.
moval,0;
2一个附加时钟周期
3
动态执行(P6-系列)处理器具有与Intel486处理器一样的阻塞类型,甚至耗费更高.在对部分寄存器写操作结束前,读操作一直被阻塞.这样的耗费可能多于一个时钟周期.
为达到最佳的性能,应避免在对部分寄存器(如AL,AH,AX)写操作后,使用包含这个部分寄存器的大寄存器.这条规则将防止动态执行处理器上的部分条件阻塞,并适用于所有大小寄存器对:
ALAHAXEAX
BLBHBXEBX
CLCHCXECX
DLDHDXEDX
SPESP
BPEBP
SIESI
DIEDI
有关部分寄存器阻塞的其它内容,请见第2.4节。
2.2对齐
本节提供了有关奔腾和动态执行(P6-系列)处理器在代码和数据对齐方面的信息.
2.2.1代码
奔腾和动态执行(P6-系列)处理器有一个32字节的高速缓存线.由于预取缓冲区按16字节的边界提取,代码的对齐对预取缓冲区的效率有直接影响.
为使Intel体系结构系列处理器达到最佳性能,推荐如下方法:
∙循环的人口标号应按下一个0MODl6对齐,当它与边界的距离小于8字节时.
∙跟在条件转移后的标号不应被对齐.
∙在无条件转移或函数调用后的标号应按下一个0MODl6对齐,当它与边界的距离小于8字节时.
2.2.2数据
在奔腾处理器上,对一个在高速缓存或总线上的未对齐数据进行访问,至少多耗费3个时钟周期.在动态执行(P6-系列)处理器上,对一个跨高速缓存线的末对齐数据进行访问,将耗费9-12个时钟周期.Intel推荐对数据按下述边界对齐,使全部处理器达以最佳执行性能.
2字节数据
一个2字节的对象应完全包含在按4字节对齐的字内.(即,它的二进制地址应为XXXX00,XXXX01,XXXXl0,而不能是XXXX11).
4字节数据
4字节对象应按4字节边界对齐.
8字节数据
一个8字节数据(64位,如双精度实数据类型,全部MMXTM成组寄存器值)应按8字节边界对齐.
2.3有前缀的操作码
在奔腾处理器上,一个指令的前缀能够延缓语法分析并禁止指令配对.
下表强调了FIFO中的指令前缀的影响.
∙前缀为0F指令无附加迟延.
∙前缀为66h,67h指令将花费一个时钟检测前缀,一个时钟计算指令长度和一个时钟进入FIFO(总共3个时钟).它必须是第一条进入FIFO的指令,且另一条指令可与它一起被压入FIFO.
∙具有其它前缀(非0F,66H,67H)的指令需要另一个附加时钟检测每一前缀.这些被压入FIFO的指令只能作为第一条指令.具有两个前缀的指令需用三个周期进入FIFO(两个时钟周期处理前缀,一个时钟周期处理指令).另一个指令可以和第一条指令在同一时钟周期内一起压入FIFO.
仅当FIFO保持两个以下人口时,才存在对性能的影响.只要译码器(D1阶段)有两条指令来译码,就没有额外开销.如果以每个时钟周期两条指令的频率,将FIFO中的指令撤出,FIF0就可迅速变空.所以,如果恰好位于一条有前缀的指令前的一些指令造成了性能损失(如,由高速缓存失误造成的阻塞引起不能配对、未对齐等等),则造成有前缀的指令的性能损失可能被掩起来.
在动态执行(P6-系列)处理器中,长度上超过7字节的指令将降低每时钟周期内译码指令数(见1.2节),前缀给指令增加了一到二个字节,可能使译码器受到限制.
建议在任何时候都尽可能地不使用有前缀的指令,或将它们安排在因其它原因造成阻塞的指令后面.
有关有前缀指令的配对详情,参见第3节。
2.4动态执行(P6-系列)处理器中的部分寄存器阻塞
在动态执行(P6-系列)处理器中,当16或8位寄存器(如AL,AH,AX)被写后立即执行一个32位寄存器(如EAX)读操作,那么读操作被阻塞直到写结束(最少7个时钟周期).考虑下面的例子,第一条指令移动数值8到AX寄存器,接下来的指令访问大寄存器EAX,这个代码导致一个部分寄存器阻塞.
MOVAX,8←─┐
ADDECX,EAX←─┘发生在访问EAX寄存器的部分阻塞
对于全部8位和16位或32位寄存器时同样如此.
小寄存器
AL
AH
AX
BL
BH
BX
CL
CH
CX
DL
DH
DX
大寄存器
EAX
EBX
ECX
EDX
奔腾处理器不存在这种附加迟延.
由于P6系列的处理器可以按乱序执行代码.因此,这种相邻的指令不会产生阻塞.下例中也包含了一个部分阻塞.
MOVAL,8←─┐
MOVEDX,0X40│
MOVEDI,new-value│
ADDEDX,EAX←─┘发生在访问EAX寄存器的部分阻塞
另外,任何跟在被阻塞的微操作后的微操作,也将等待被阻塞的微操作通过管道后,才能获得执行的时钟周期.通常为了避免阻塞,在对16位或8位小寄存器(AL)写操作后,不要对包含它的大寄存器进行读操作.
为了使代码能够简便地应用于不同类型的处理器,在动态执行处理器中也存在读写小寄存器和大寄存器的特殊情况.下例的特殊情况中使用了XOR和SUB指令.
xoreax,eax
movbal,mem8
useeax←无部分阻塞
movwal,meml6
subax,ax
subeax,eax
xorah,ah
通常,在实现这些指令序列时,总是在对寄存器写操作前,先对大寄存器清零.在这种特殊情况中,由XOR和SUB实现清零功能,且对EAX、EBX、ECX、EDX、EBP、ESP、EDI和ESI均有效.
2.5有关分支预测的信息
对动态执行(P6-系列)的处理器来说,分支优化是最重要的优化方案.这些优化方案也同样有益于奔腾处理器.
2.5.1动态分支预测
下列三个因素对动态分支预测是很重要的:
1.如果指令地址不在BTB中,预测结果为无分支的继续运行(失败).
2.预测到的分支有一个时钟周期的迟延.
3.BTB存贮了有关分支预测历史的4位数据.
第一个因素建议将分支跟在将被执行的代码后面.决不要将数据跟在分支后面.
为避免因提取分支而产生一个时钟周期的迟延,可简单地在这些分支之间加入一些额外工作.这个迟延限定了循环的最小耗费为两个时钟周期.如果你的小循环不超过两个时钟周期,就将它展开.
分支预测器能够正确地对常规的分文模式进行预测.比如,它可以正确地预测出一个分支在循环中仅在每一奇次迭代时发生,而在每一偶次迭代中不发生.
2.5.2在动态执行(P6-系列)处理器上的静态预测
在动态执行处理器中,对那些在BTB中没有历史数据的分支将使用静态预测算法进行预测.静态预测算法如下:
∙预测无条件转移分支.
∙预测向后的条件分支,本规则对循环适用.
∙预测向前的条件分支.
静态预测的额外开销为6个时钟周期.无预测或错误预测的额外开销大于12个时钟周期.下面的图表显示了静态预测的算法.
向前条件分支未发生(fallthrough)
if<条件> {
...↓
}无条件分支
for<条件>{ JMP
...↓───→
}
JMP
向后条件分支发生
loop{
↑
└─}<条件>
下例说明了静态预测算法的基本规则.
A.Begin:
MOVEAX,mem32
ANDEAX,EBX
IMULEAX,EDX
SHLDEAX,7
JCBegin
在这个例子中,在第一次通过时,向后分支不在BTB中,因此BTB未进行预测.但是静态预测器将预测到这个分支,所以不产生预测失误.
B.MOVEAX,mem32
Begin:
CallConvert
本代码段的第一个分支指令(JCBegin)是一个向前条件分支.第一次通过时,它不在BTB中,但静态预测器将预测到该分支.
第一次通过时BTB发现CallConvert指令,但在BTB中没有进行预测.但静态预测算法能预测并提取一个该调用,这对一个无条件分支来说是正确的结果.
这些例子中,条件分支只有两种情况:
提取的和未提取的.间接分支,如开关语句,可计算的GOTO或通过指针的调用,都可跳到一个特定的地址单元上.如果分支有一个偏离的目标地址(即分支90%都转向同一地址),那么BTB将在大多数情况能够精确预测到.但是如果目标地址是不可预测的,性能将迅速下降,用可预测的条件分支替换间接分支可以改善性能.
调度
[第二节常规的优化方案][第四节:
指令选择]
调度或配对是各代处理器都应使用的一种优化性能的方法.下面是一个在奔腾和P6系列处理器上,用以提高代码速度的配对和调度表.在某些情况下,对特定的处理器具有达到最佳性能的变通方案.这些变通的方法因应用程序的特性而不同.在超标量的奔腾处理器中,指令的顺序是使处理器达到最高性能的非常重要的因素.
对指令顺序的重新安排增加了将两条指令安排成同时运行的可能性.与数据相关的指令应被至少一条其它指令所分开.
本书描述了你需要了解的MMXTM指令与整数指令配对的原则.对下表列出的每一种情况,都在小节中说明了与之相配的原则.
进行配对所需了解的几个规则:
∙通用配对规则:
规则仅与机器状态有关,与指定的操作码无关.对整数和浮点同样有效.例如,单步指令禁止指令配对.
∙整数配对规则:
对整数指令配对的规则.
∙对MMXTM指令配对的规则:
由于只存在一个乘法器单元,规则允许两个MMXTM指令同时执行.
∙MMXTM指令与整数指令配对规则:
对一条MMXTM指令和一条整数指令配对的规则.
注意浮点指令不可以与MMXTM指令配对.
3.1通用配对规则
关于奔腾处理器通用配对规则,请参见《对Intel32位处理器的优化》应用部分AP—526(序号242816).具有MMXTM技术的奔腾处理器降低了一些通用配对的规则要求:
∙如果两条指令中存在一条长度大于7字节的指令,奔腾处理器不对它们进行配对.具有MMXTM技术的奔腾处理器,不对第一条指令大于11字节或第二条指令大于7字节的指令进行配对,前缀不计算在内.
∙有前缀的指令可在U管道配对.前缀为0FH,66H或67H的指令也可在V管道中配对.
3.2整数配对规则
当下列两种情况发生时不能进行配对:
1.后两条指令是不可配对指令(见下表可配对指令汇总:
并参见《对Intel32位处理器的优化》应用部分AP-526,附录A包含了一个指令配对特性的完整列表).通常,大多数简单的ALU指令是可配对的.
2.后两条指令属于寄存器争用(显式或隐式的)的一些类型.这一规则有一些特例.在较少的情况下,寄存器争用的指令也可配对.这种情况在3.2.3中解释.
表3-1:
整数指令配对
在U管道中可配对指令
在V管道中可配对指令
movr,r
alur,i
pushr
movr,m
alum,i
pushi
alum,j
pushl
movm,r
alueax,i
popr
movr,i
alum,r
nop
jmpnear
movm,i
alur,m
shift/rotbyl
jccnear
moveax,m
inc/decr
shiftbyimm
oFjcc
movm,eax
inc/decm
testreg,r/m
callnear
alur,r
lear,m
testacc,imm
testreg,r/m
cc,imm
testa
3.2.1配对指令集
不可配对指令(NP)
∙移位计数在cl的shift/rotate指令.
∙长算术指令,如:
MUL,DIV.
∙扩充指令,如:
RET,ENTER,PUSHA,MOVS,STOS,LOOPNZ.
∙某些浮点指令,如FSCALE,FLDCW,FST.
∙跨段(Inter-Segment)指令,如:
PUSHsreg,CALLfar.
在U或V管道中的可配对指令(UV)
∙大多数8/32位ALU操作,如:
ADD,INC,XOR.
∙所有的8/32位比较指令,如:
CMP,TEST.
∙所有8/32位对寄存器操作的指令,如:
PUSHreg,POPreg.
U管道中可配对指令(PU)
下列指令必须在U管道中使用,并可与适当的V管道中指令配对,这些指令不能在V管道中执行.
∙进位和借位指令,如:
ADC,SBB.
∙有前缀的指令,但0FH,66H或67H前缀的指令除外(参见2.3节)
∙用立即数移位的指令.
∙某些浮点操作,如:
FA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Pentium MMX 代码的优化 代码 优化