窥孔优化初探

窥孔优化,顾名思义,是一种很局部的优化方式,编译器仅仅在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点,通过一些认为可能带来性能提升的转换规则,或者通过整体的分析,通过指令转换,提升代码性能


写在前面:缘起

初次见识到这个名词是在一个慵懒的午后,我百无聊赖的翻阅着各大论坛、博客的形形色色的文章、见解,突然一个词映入眼帘:窥孔优化——因为比较在意,而且本来对程序的性能就比较关心,于是就百度了下(引言部分就是出自百度百科)

请允许我把百度百科的关于窥孔优化的介绍在此简要说明下

百度百科的意思,这个窥孔,你可以认为是一个滑动窗口,编译器在实施窥孔优化时,就仅仅分析这个窗口内的指令;每次转换之后,可能还会暴露相邻窗口之间的某些优化机会,所以可以多次调用窥孔优化,尽可能提升性能

读完这段文字对窥孔优化要有一个大致的印象:不妨想象下医院取药的那个小窗口,我觉得比较形象

顺便一提窥孔这个词翻译过来貌似是『peehole』,pee是小便的意思,hole是洞洞的意思——乍一看还有点那个 :-P


窥孔优化之原理初探

首先明确,窥孔优化是一种局部的优化(窥孔嘛……)

局部怎么理解呢:一种很局部的优化方式,编译器仅仅在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点

窥孔优化式基于汇编代码的

窥孔优化可以在四个方面寻找优化机会:1)删除冗余指令,包括冗余的load和store指令以及死代码(不会执行的代码);2)控制流优化;3)强度削弱;4)利用特有指令

1)删除冗余指令和死代码

sh $0,6($sp)
sh $0, 4($sp)
sh $0, 2($sp)
sh $0, 0($sp)
ldc1 $f1, 0($sp)

替换为

xor $f1,$f1,$f1

这样便减少了5次内存访问

另外,有些代码可能用于不会被执行到,这样在窥孔优化阶段,如果发现这样的代码,就可以直接删除;典型的方式是优化双跳转,即第一条跳转指令的目的地址还是一条跳转指令时,可以删除后一条跳转指令,并修改第一条跳转指令的目标地址(另对于不可能进入的分支也可以使用这种方式删除),即变双跳转甚至多跳转为一条条转指令

2)控制流优化

看到控制流就想到了jmp为代表的跳转指令

中间代码生成阶段,很可能经常产生一些跳转到跳转指令,跳转到分支跳转、分支跳转到跳转之类的指令,都可以在窥孔优化中想办法解决掉,当然你也可以在中间代码中优化它们

一些分支被删除后,可能还存在一些不会被到达的标号(label),也可以顺便删除之,这样就会提升基本块的大小,增加优化机会

3)强度削弱

什么叫强度削弱?举个例子就秒懂

x = x + 0
y = y * 1

上面的代码中,x和y加0、乘以1的行为是完全可以避免的(其实这也可以分类到第一点,即删除不必要的冗余代码——知识点之间都是互通的嘛)

再举一例

p = p / 2
q = q * 2

完全可以用代价较小的位运算代替代价较大的乘除运算

p >>= 1
q <<= 1

这些例子都是靠平时积累的,类似的还有x^2之类的指数运算可以削弱为x*x的乘法运算,浮点数除以常数的运算可以转换为浮点数乘以常数的倒数等

4)利用特有指令

要知道软件是依赖于硬件运作的,不同的CPU提供略有不同的指令集

比如DSP芯片中可能有复杂的数字信号处理指令,龙芯中有乘加指令以及一些向量扩展指令;还有一些CPU可能提供自增、自减、取绝对值指令;这些都能在窥孔优化中生成,以提升程序的运行性能

好了,以上就是本人对于窥孔优化的初步认识,也算是从感性层面上理解了什么是窥孔优化,这个词以后可能还会遇到,到时候再做深究

猜你喜欢

转载自blog.csdn.net/abc_12366/article/details/80397828