理论教育 编译器设计之路:代数简化的实现

编译器设计之路:代数简化的实现

时间:2023-11-04 理论教育 版权反馈
【摘要】:从算法实现上来说,代数简化是一种代价极小的优化算法,甚至不需要数据流分析的支持。事实上,试图运用代数简化解决一切运算化简的问题是徒劳的。另外,还应该注意一些特定的代数性质,例如运算的交换律、结合律等。其中,交换律是最常见的代数性质。程序7-15 IRSimplify.cpp第3~10行:主要用于初始化Num2Bit映射表。主要是考虑到log函数的结果是浮点数,而细小误差可能会导致非常严重的错误。

编译器设计之路:代数简化的实现

算法实现上来说,代数简化是一种代价极小的优化算法,甚至不需要数据流分析的支持。设计代数简化算法时,有个问题需要注意,就是不要把代数简化过于神化了。事实上,试图运用代数简化解决一切运算化简的问题是徒劳的。这种想法不但会大大增加算法设计的难度,而且也会影响算法执行的效率。这里,Neo Pascal只实现了一个简单的算法框架,并不力求解决那些复杂的运算化简问题。

另外,还应该注意一些特定的代数性质,例如运算的交换律、结合律等。其中,交换律是最常见的代数性质。在很多情况下,如果交换律处理得不好,就会使源代码变得极其冗长。当然,要解决这类问题的方法是非常简单的,笔者将在源代码分析中详述。

程序7-15 IRSimplify.cpp

第3~10行:主要用于初始化Num2Bit映射表。这个表描述的就是乘、除运算中特定常量与相应移位运算的位数之间的关系。例如,n*8=n shl 3,就可以将<8,3>存入Num2Bit备用。有读者可能有疑问,为什么不直接使用log函数计算呢?主要是考虑到log函数的结果是浮点数,而细小误差可能会导致非常严重的错误。

第12行:遍历IR列表。

第14行:获取当前IR。

第16~21行:获取处理方案。

第24~32行:如果运算是满足交换律的,则将IR中常量操作数统一置于操作数2中。这样做可以避免编写许多不必要的判断及处理。当然,这项工作也可以在生成IR时完成。理论上讲,操作数1、操作数2都是常量的IR是不存在的,应该已经被常量折叠优化了。

第35~42行:依据等式i+O=i,将IR转换为赋值形式。这里,不必考虑O+i=i的情况,因为在第24~32行中已经进行了操作数交换。以下满足交换律的等式的处理方法类似。

第46~53行:依据等式i-O=i,将IR转换为赋值形式。

第59~66行:依据等式i*l=i、i div l=i、i mod l=i,将IR转换为赋值形式。(www.daowen.com)

第71~84行:将乘以、除以一个常量2“的IR转换为移位IR。

第89~96行:依据等式i shl O=i、i shr O=i,将IR转换为赋值形式。

第100~108行:依据等式i or i-i,将IR转换为赋值形式。

第109~116行:依据等式i or false=i,将IR转换为赋值形式。

第117~125行:依据等式i or true=true,将IR转换为赋值形式。

第129~137行:依据等式i and i=i,将IR转换为赋值形式。

第138~145行:依据等式i and true=i,将IR转换为赋值形式。

第146~164行:依据等式i and false=false,将IR转换为赋值形式。

关于代数简化的实现,就讨论至此。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈