自编教材分享:第六章—程序编写优化(五)



语句级优化
删除冗余语句
在开发和修改程序时可能遗留有死代码,死代码是指程序在一个完整的执行过程该段代码并没有得到任何的运行,也可能是一些声明了但没有用到的变量,此时可以将其删除,避免程序在运行中进行不相关的运算行为,减少运行的时间。
优化前代码:
优化后代码:
代数变换
程序员在编写程序时可能忽略了代数表达式也可以进一步优化,达到简化计算缩短运行时间的目的。此代码中的计算语句可以进行简化,原计算语句中含有乘法、加法和除法三种运算,而简化后仅剩乘法运算。
优化前代码:
优化后代码:
去除相关性
标量扩展
语句中依赖关系的存在非常不利于进行语序调整、向量化等优化方法的开展,且由于编译器优化的局限性,需要优化人员在编写程序时尽量消除依赖关系。
标量扩展是将循环中的标量引用用编译器生成的临时数组引用替换,可以有效地消除一些由内存单元的重用而导致的依赖。
优化前代码:
优化后代码:
标量重命名
此循环中语句S1到S4之间存在真依赖,S1到S3之间存在输出依赖,这些语句间的依赖都是由于标量T引起的,此时可以通过引入两个不同的变量代替现有的变量T来消除依赖。
优化前代码:
优化后代码:
数组重命名
数组的存储单元有时被重用会导致不必要的反依赖和输出依赖,此时可以使用数组重命名的方法来消除。
优化前代码:
优化后代码:
数组重命名需要增加和数组大小成比例的额外内存空间,因此数组重命名的安全性和有利性都比标量重命名复杂,这种代价可能会严重影响到程序的性能,因此在实施数组重命名时应该更加谨慎。
公共子表达式优化
当程序中表达式含有两个或者更多的相同子表达式,仅需要计算一次子表达式的值即可
优化前代码:
优化后代码:
分支语句优化
合并判断条件
当程序中的分支判断条件是复杂表达式,优化人员可以将其进行优化
优化前代码:
优化后代码:
生成选择指令
一些平台支持选择指令,选择指令是一个三目运算指令,在某些情况下可以将分支指令用选择指令进行替换,达到提升效率的目的。
优化前代码:
优化后代码:
运用条件编译
由于宏条件在编译时就已经确定,编译器可直接忽略不成立的分支,所以条件编译是在编译时判断。而普通分支判别是在运行时判断,故编译后的代码要长,效率也不如条件编译。
优化前代码:
优化后代码:
移除分支语句
如果在程序设计时,编程人员能够将各分支路径的计算结果放到一张表中,并将分支条件转化为表中值对应的索引,那么就可以将分支跳转转化为访问表中元素,这是查表法移除分支的主要思想。
优化前代码:
优化后代码:
平衡分支判断
C语言中的switch运算符是程序员经常使用的一种语法,包含大量的分支,在一些程序中switch运算符可以含有数千个设置值,若直接实现这种需求的话,所得到的逻辑树会特别高,以下面switch分支语句为例。
下图为分支语句对应的判断逻辑树,该代码所对应的优化逻辑树的高度为6,当a的值为10时需要6次判断,可以通过平衡判断分支的方法对分支语句进行优化,优化后逻辑判断树如右图所示,当a的值为10时需要4次判断,即平均仅需要4次比较操作就能完成判断。

