C编译器剖析_5.2.2 中间代码生成及优化_再论符号symbol与公共子表达式

本文深入探讨C编译器如何处理公共子表达式,通过图示和实例解释了如何利用中间代码优化重复计算,避免冗余操作。在编译过程中,通过valueDef和valueUse结构体跟踪变量状态,以确定何时可以重用计算结果。同时,介绍了生成中间代码时针对函数调用和条件表达式的特殊处理,以及在优化阶段如何修改中间代码以提高效率。
摘要由CSDN通过智能技术生成

5.2.2    再论符号symbol与公共子表达式

    在介绍算术表达式的翻译前,让我们简单重温一下第2.5节中的“图2.5.4 公共子表达式”及“图2.5.5 valueDef和valueUse”。为阅读方便,我们再次给出这两张图,更详细的说明请参见第2.5节。对于图2.5.4第2行的a+b,我们会由第7行的中间代码来对a+b进行求值,其结果存于临时变量t1中,之后在第3行中再次遇到表达式a+b时,a和b的值并没有发生变化,我们可在第9行直接把t1赋给变量d。由于我们在第4行对a进行赋值,导致t1中保存的值不再有效,所以我们需要重新进行计算第5行的a+b。我们用形如第7行的“t1:a+b;”来表示临时变量t1由a和b相加产生,这与编译原理相关教材中使用“t1 = a+b;”的式子略微有所区别。


图2.5.4  公共子表达式

     对公共子表达式进行重用的思路并不难理解,第2.5节的图2.5.5主要是用于说明要实现这样的想法,我们需要定义出相应的数据结构。图2.5.5中的struct  valueDef结构体用来描述一个公共子表达式“t1:a+b”,其中临时变量t1、变量a和变量b各用一个struct  variableSymbol符号对象来刻画。在变量a发生变化时,为了能让公共子表达式a+b失效,我们需要在a中记录“a在哪些公共子表达式中被使用”,图2.5.4中定义的结构体struct  valueUse就用于此目的。由于变量a可在多个公共子表达式中被使用,因此我们需要一条由若干个struct  valueUse对象构成的链表来记录这些表达式,其链首就存于图2.5.5的结构体对象struct   variableSymbol的uses域中。当a发生变化时,我们要沿着uses域所指向的链表,使链表上的各个公共子表达式失效。当然,变量b中也有类似的结构,当变量b发生变化时,我们也要做类似的处理。


图2.5.5  valueDef和valueUse

    图2.5.4第7行使用“t1:a+b”的一个原因是,这隐含着UCC编译器只对t1进行唯一的一次赋值(单赋值)。但对于C语句“b = a > 3? 50:60;”来说,与其对应的中间代码如下所示,我们可以发现临时变量t0会被赋值两次。为了与单赋值的情况有所区别,此处我们用MOV指令“t0 = 50”,其中用的是赋值号’=’,而非冒号’:’。在生成中间代码后,我们在进行优化时,可把以下对t0进行赋值的语句改为对b进行赋值。但由于UCC编译器的优化只在一个基本块内进行,而此处的t0显然出现在多个基本块中,这就需要我们在生成中间代码时做一些特殊处理,以便优化时可对“t0=50;”指令做修改。产生这样困境的原因在于UCC编译器在翻译表达式“a > 3? 50:60”时,并没有考虑其所处的上下文,而总是将条件表达式的结果先存放到一个临时变量中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值