代码生成:
中间表示形式+符号表 -> 指令选择,寄存器分配和指派,指令排序
8.2.1 1) x = 1
LD r, #1
ST x, r
3)x = a+1
LD r, a
ADD r, #1
ST a, r
5)x = b*c
LD R1, b
MUL R1, c
ST x, R1
8.2.2 1)x=a[i] y=b[j] a[i]=y b[j]=x
LD R0 i
MUL R0, 4
LD R1 a(R0)
LD R0 j
MUL R0, 4
LD R2 b(R0)
ST a[i] R2
ST b[j] R1
2) x=a[i] y=b[i] z=x*y
LD R0 i
MUL R0, 4
LD R1 a(R0)
MUL R1 b(R0)
ST z R1
8.2.3 y=*q q=q+4 *p=y p=p+4
LD R1 q
LD R2 0(R1)
ADD R1 #4
ST q R1
LD R1 p
ST 0(R1) R2
ADD R1 #4
ST p R1
8.2.4
LD R1, x
LD R2, y
SUB R1-R2
BLTZ R1, M // M为L1生成第一条指令位置
8.2.5
LD R1, s
ST R1, 0
LD R2, i
ST R1, 0
LD R3, n
L1: CMP R2, R3
JG L2
ADD R1, R2
ADD R2, #1
GOTO L1
L2:
8.2.6 1) 2+2+1+2
8.3.1 没有理解题中return什么意思,下面没有考虑return。假设这是main中一段代码
100: LD SP, #600
108: ACTION1
128: ADD SP, SP, #msize
136: ST 0(SP), #152
144: BR 300
152: SUB SP, SP #msize
160: ADD SP, SP #msize
168: ST 0(SP), #184
176: BR 400
184: SUB SP, SP #msize
192: ADD SP, SP #msize
200: ST 0(SP), #216
208: BR 500
216: SUB SP, SP #msize
300: ACTION
320: BR *0(SP)
400: ACTION
420: BR *0(SP)
500: ACTION
520: BR *0(SP)
8.3.2与8.3.3 8.3中没有类似这样的例子,栈式分配的话重要的是地址的确定,可以将这些语句当作函数中第一条语句生成代码
8.4.1 一个二重循环一个三重循环,二重循环三地址语句类似于图8-7上半部分,流图类似于图8-9B1-B4,循环包括例8.9中1和3,下面练习一下三重循环
1)
1 i = 0
2 j = 0
3 k = 0
4 t1 = n*i
5 t2 = t1 + j
6 t3 = t1 + k
7 t4 = n*k
8 t5 = t4 + j
9 t6 = a[t3] * b[t5]
10 c[t2] = c[t2] + t6
11 k = k + 1
12 if(k<n) goto 4
13 j = j + 1
14 if(j<n) goto 3
15 i = i + 1
16 if(i<n) goto 2
2)三重循环流图:
B1 1
B2 2
B3 3
B4 4-12
B5 13-14
B6 15-16
3)循环有3个:B4自身,B3B4B5,B2B3B4B5B6
8.4.2 类似,略
8.5.1
a1
+(e) *(d,b)
a0 b0 c0
8.5.2
1)只有a活跃,则第一行可以优化掉
2)abc活跃,则同样第一行d=b*c可以优化掉
8.5.3 B6 原理类似8.5.1,略
8.5.4 B3 原理类似8.5.1,略
8.5.5
1) a[i]=b a设置为不活跃,b设置为活跃,影响所有对数组a的引用
2) a=b[i] a设置为不活跃,b设置为活跃,影响所有对数组b的引用
3) a=*b a设置为不活跃,b设置为活跃,从后往前扫描过程中,所有对b的引用都是活跃的
4) *a=b a设置为不活跃,b设置为活跃,从后往前扫描过程中,所有对a的引用都是不活跃的
8.5.6 在这儿画树太麻烦了
1)p可以指向任何地方,则*p=...使得构造出来全部节点都被杀死每一步构造结果为:
a[i] = b
[]=
i0 b0
*p=c 节点[]=、i0、b0被杀死
[]= *= p
i0(k) b0(k) c0(k)
d=a[j]
=[](d)
a0 j0
[]= *= p
i0(k) b0(k) c0(k)
e=*p
=[](d)
a0 j0 =* e
[]= *= p
i0(k) b0(k) c0(k)
*p = a[i] 转为:t=a[i] *p=t
t=a[i]
=[](t) =[](d)
t0 a0 j0 =* e
[]= *= p
i0(k) b0(k) c0(k)
*p=t 上面所有节点都被杀死
2)p可以指向b或d,则*p=...使得构造出来以b或d为变量的节点杀死
8.5.7 e=*p -> e=c
8.5.8
t0 = a+c
t1 = t0+e
y= t0+t1
t2 = y+b
t3 = y+d
x = t3+f
x=a+b*c | a[i][j]=b[i][k]+c[k][j] | ||
8.6.1 | t0=b*c x=a+t0 |
t0=i*10 t1=t0+k t2=b[t1] t3=k*10 t4=t3+j t5=c[t4] t6=t0+j t7=t2+t5 a[t6]=t7 |
|
8.6.2 | ... | ||
8.6.3 | LD R1, b LD R2, c MUL R1, R1, R2 LD R2, a ADD R1, R1, R2 |
// load b[i][k] LD R1, i MUL R1, R1, 10 LD R2, k ADD R3, R1, R2 LD R4, pb ADD R4, R4, R3 //load c[k][j] MUL R2, R2, 10 LD R3, j ADD R2, R2, R3 LD R5, pc ADD R5, R5, R2 // add ADD R6, 0(R4), 0(R5) ADD R1, R1, R3 LD R2, pc ADD R2, R2, R1 ST 0(R2), R6 |
|
8.6.4 | .. | L | |
8.6.5 | .. |
R1 | R2 | R3 | i | j | k | pa | pb | pc | ||
LD R1, i | i | i,R1 | j | k | pa | pb | pc | |||
MUL R1, R1, 10 | t0 | i | ||||||||
LD R2, k | k | k,R2 | ||||||||
ADD R3, R1, R2 | t1 | |||||||||
LD R1, pb | pb | pb,R1 | ||||||||
ADD R1, R1, R3 | t2 | k | t1 | i | j | k,R2 | pa | pb | pc | |
MUL R2, R2, 10 | t3 | k | ||||||||
LD R3,j | j | j,R3 | ||||||||
ADD R2, R2, R3 | t4 | |||||||||
LD R3, pc | pc | j | pc,R3 | |||||||
ADD R3, R2, R3 | t2 | t4 | t5 | i | j | k | pa | pb | pc | |
ADD R1, R1, R3 | t7 | |||||||||
LD R2, i | i | i,R1 | ||||||||
MUL R2, R2, 10 | t0 | i | ||||||||
LD R3, j | j | j,R3 | ||||||||
ADD R2, R2, R3 | t6 | |||||||||
LD R3, pa | pa | j | pa,R3 | |||||||
ADD R2, R2, R3 | t7 | a[i][j] | ||||||||
ST R2, R1 |
8.6.5 只有2个寄存器需要将值保存到栈中或临时变量中,原理类似,只是数据来回倒腾多点
略
例8.17计算式8.1:
use(x,B) | live(x,B) | |
a/4 | B2,B3 | B1 |
b/5 | B1 | B3,B4 |
c/3 | B1,B3,B4 | -- |
d/6 | B1,B2,B3,B4 | B1 |
e/4 | B1,B3 |
书中只介绍了算法没有例子,只能靠自己了,8.8.4中举例有误,考虑的两个节点应该是a和d,不是a和b
8.8.1 只考虑B1
a=b+c | LD R0, b LD R1, c ADD R2, R0, R1 ST a R2 |
b,c活跃 |
d=d-b | LD R3, d SUB R3, R3, R0 ST d, R3 |
d,b活跃 |
e=a+f | LD R4, f ADD R5 R2, R4 ST e, R5 |
a,f活跃,e不活跃 |
k=6,边包括:
d-a, d-f
a-f, a-d, a-b
a -- d
| \ |
b f
a,b,d各一种颜色,b可以跟f一种颜色
8.8.2 保存全局变量的寄存器可以不覆盖?
例8.25
t4 t1 t3 base=1 k=3
t3 e t2 base=2, k=2 m=1
t2 c d LD R3, d; LD R2, c; ADD R3, R2, R3
LD R2, e
MUL R3, R2, R3
t2 a b base=1 k=2
LD R2, b
LD R1, a
SUB R2, R1, R2
ADD R3, R2, R3
8.10.1 1)a/(b+c)-d*(e+f)
t5=t2-t4
t4=d*t3
t3=e+f
t2=a/t1
t1=b+c
t5(3)
t2(2) t4(2)
a1 t1(2) d1 t3(2)
b1 c1 e1 f1
2)a+b*(c*(d+e))
t4=a+t3
t3=b*t2
t2=c*t1
t1=d+e
t4(2)
a1 t3(2)
b1 t2(2)
c1 t1(2)
d1 e1
3)(-a+*p)*((b-*q)/(-c+*r))
t10 = t3*t9
t9=t5/t8
t8=t6+t7
t7=*r
t6=-c
t5=b-t4
t4=*q
t3=t1+t2
t2=*p
t1=-a
t10(3)
t3(2) t9(3)
t1(1) t2(1) t5(2) t8(2)
- a1 * p1 b1 t4(1) t6(1) t7(1)
* q1 - c1 * r1
8.10.2 对2),类似例8.25,对例1)和3)类似例8.27
8.10.3 类似例8.25
8.10.4 对于一个节点,假设有n个子节点,n<=2类似8.10.1中描述,如果n>=2,假设每个子节点标号为a1< a2 < ... < an,
计算节点标号值A方法如下:
初始化 A=an, k=n, x=0
for(i=n; i>1; --i)
if(ai-a(i-1))>0)
x+=(ai-a(i-1));
else if(x>0)
x--;
else
A++;
解释如下:
假设子节点从左到右标号升序排列,则从右到左检查,如果象邻两个子节点标号相同,则需要增加一个寄存器存储中间结果,
否则,如果这两个相邻子节点标号相差为1,则无需增加寄存器
否则,如果这两个相邻子节点标号相差>1,则不仅无需增加寄存器,还可以空余(差值-1)个寄存器在检查扫描过程中使用
8.10.5 可以采用8.10.4的方法
8.10.6
如果两个子节点标号相同的情况,节点标号等于子节点标号
如果两个子节点标号不同,节点标号等于左子节点标号
8.10.7 在加载值的时候保证符合要求即可(*和/的两个变量在相邻寄存器中)
例8.28代价向量说明,只说明-/(3,2,2),其余略
1个寄存器保存到内存 | 1个寄存器保存到寄存器 | 2个寄存器保存到寄存器 | |
abcde(0,1,1) | 0:保存到内存中 | 1个寄存器保存到寄存器 | 2个寄存器保存到寄存器 |
-/(3,2,2) | LD R0 a SUB R0 b ST a R0 |
LD R0 a SUB R0 b |
LD R0 a SUB R0 b |
*(5,5,4) | |||
+(8,8,7) |
8.11.1
1) Ca(0, 1, 1)
2) Mx(0, 1, 1)
3) =(3, 2, 2)
4) =(1, 1, 1)
5) ind(3, 2, 2)
6) +(4, 2, 2)
7) +(2, 1, 1)
8) +(2, 1, 1)