对C语义的for循环的基本代码生成模式

20 篇文章 0 订阅
6 篇文章 0 订阅
之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案,然后聊起C语言的for循环的代码生成有几种常见的模式。顺道跟大家分享讨论一下。

C语言的for循环大家应该都很熟悉了,C系语言大都有一样或几乎一样的语法结构:一个循环初始化,一个循环条件,一个循环再初始化,然后一个循环体。通常循环初始化在最前面,再初始化的逻辑直接黏在循环体后面,能有变化的就是循环条件的代码生成到什么位置。

举个例子,
for (int i = 0; i < 100; i++) {
foo();
}

把它翻译为龙书第8章所用的三地址指令,可以用许多不同的模式翻译,这里举三种例子:
(注释里标出了基本块的标号、前导基本块、后继基本块,以及基本块的内容等信息。应该很直观吧?)

第一种:循环条件放前面,循环末尾用无条件跳转回到开头:
(1)  i = 0

// B1 <- { B0, B2 }, -> { B2, B3 }: loop condition
(2) if i >= 100 goto (6) // note: inverted condition

// B2 <- B1, -> B1: loop body
(3) call foo()
(4) i = i + 1
(5) goto (2)

// B3 <- B1: after loop
(6) ...[/code]

[img]http://dl2.iteye.com/upload/attachment/0090/3395/9e7377b8-60c6-3d21-a352-9daa673d21e5.png[/img]


第二种:循环条件放后面,在进入循环的地方先无条件跳转到位于循环末尾的条件:
[code="">// B0 -> B2: loop initialize
(1) i = 0
(2) goto (5)

// B1 <- B2, -> B2: loop body
(3) call foo()
(4) i = i + 1

// B2 <- { B0, B1 }, -> { B1, B3 }: loop condition
(5) if i < 100 goto (3)

// B3 <- B2: after loop
(6) ...


[img]http://dl2.iteye.com/upload/attachment/0090/3397/43047d5d-6ab8-39dc-840c-1a1b32ac29b1.png[/img]


第三种:在进入循环的地方先判断是否跳过循环,然后循环条件放在末尾:
(1)  i = 0
(2) if i >= 100 goto (6) // note: inverted condition

// B1 <- { B0, B2 }, -> B2: loop body
(3) call foo()
(4) i = i + 1

// B2 <- B1, -> { B1, B3 }: loop condition
(5) if i < 100 goto (3)

// B3 <- { B0, B2 }: after loop
(6) ...[/code]

[img]http://dl2.iteye.com/upload/attachment/0090/3401/bdfa834b-b820-3caf-9b2d-1452441ff6c4.png[/img]

顺带一提,这个具体例子中循环条件是拿循环变量与一个编译时常量比较,所以这个版本的代码的(2)可以非常轻易的通过条件常量传播消除掉,等价变换为:
[code="">// B0 -> B1: loop initialize
(1) i = 0

// B1 <- { B0, B2 }, -> B2: loop body
(2) call foo()
(3) i = i + 1

// B2 <- B1, -> { B1, B3 }: loop condition
(4) if i < 100 goto (2)

// B3 <- { B0, B2 }: after loop
(5) ...


[img]http://dl2.iteye.com/upload/attachment/0090/3403/63c0ec5f-1c36-3ef6-b876-c647d1847e57.png[/img]

而前两种模式没那么容易消除其中的指令。


有兴趣的同学可以来讨论下这几种模式的异同点 :lol:
注意三地址指令的条数,基本块的个数与划分,基本块之间控制流边的总个数,代码的静态与动态的情况的关系,等等。

当然这不是啥新问题,早就有很多论文讨论过了。
例如说某篇1978年的小论文⋯名字就先不说了免得剧透。有兴趣的同学自己思考喔。

========================================

下面补充些在实际生活种能看到的例子。

1. [url=http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.2]Java虚拟机规范,Java SE 7版,3.2小节[/url]
这里举了几个Java的for循环翻译为字节码的范例,都符合上面说的“第二种”模式。
例如把这样的代码:
void spin() {
int i;
for (i = 0; i < 100; i++) {
; // Loop body is empty
}
}

翻译为:
0:   iconst_0       // Push int constant 0
1: istore_1 // Store into local variable 1 (i=0)
2: goto 8 // First time through don't increment
5: iinc 1, 1 // Increment local variable 1 by 1 (i++)
8: iload_1 // Push local variable 1 (i)
9: bipush 100 // Push int constant 100
11: if_icmplt 5 // Compare and loop if less than (i < 100)
14: return // Return void when done

Eclipse Compiler for Java (ecj)就采取了这种模式。但Oracle JDK6里自带的javac实际用的代码生成策略却是前面说的“第一种”,将上面的例子编译为:
0:	iconst_0
1: istore_1
2: iload_1
3: bipush 100
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return

好玩吧呵呵厚⋯
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Compiler Construction Experiment 1 Implementing a Scanner for TINY+ You are to write a lexical analyzer/scanner for the language TINY+. Goals 1The input of the scanner is a source code file and the output of the scanner is a stream of tokens. 2Your scanner should go for longest possible match i.e. a string ‘:=’ is to be identified as ‘ass-symbol’ rather than ‘:’ and ‘=’. 3Token is represented as (Kind, Value). We use the following symbols to denote different kinds of tokens KEY denotes reserved words SYM denotes special symbols ID denotes identifiers NUM denotes numeric constants STR denotes string constants 4Check lexical errors: giving meaning error messages and the lines where errors occur. The kinds of lexical errors are: Illegal character, that is, scanner may recognize a character that is not in the alphabet of TINY+, such as $ is an illegal character The right bracket of a STRING is lost, such as ' scanner The right delimiter of a comment is lost, such as: {this is an example Requirements 1Write your program in C or C++ 2This experiment must be finished in 4 periods. You will submit a report and the source code Example output for some TINY+ programs Test1 or and int bool char while do if then else end repeat until read write , ; := + - * / ( ) = a2c 123 'EFG' The scanner should give the outputs: (KEY, or) (KEY, and) (KEY, int) (KEY, bool) (KEY, char) (KEY, while) (KEY, do) (KEY, if) (KEY, then) (KEY, else) (KEY, end) (KEY, repeat) (KEY, until) (KEY, read) (KEY, write) (SYM, ,) (SYM, ;) (SYM, :=) (SYM, +) (SYM, -) (SYM, *) (SYM, /) (SYM, ( ) (SYM, )) (SYM, ) (SYM, =) (ID, a2c) (NUM, 123) (STR, EFG) Test2 {this is an example} int A,B; bool C1, C2, C3; char D; D:= 'scanner'; while A<=B do A:=A*2 end The scanner should give the outputs: (KEY, int) (ID, A) (SYM, ,) (ID, B) (SYM, ;) (KEY, bool) (ID, C1) (SYM, ,) (ID, C2) (SYM, ,) (ID, C3) (SYM, ;) (KEY, char) (ID, D) (SYM, ;) (ID, D) (SYM, :=) (STR, scanner) (SYM, ;) (KEY, while) (ID, A) (SYM, <=) (ID, B) (KEY, do) (ID, A) (SYM, :=) (ID, A) (SYM, *) (NUM, 2) (KEY, end)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值