編譯原理--04 符號表、運行時存儲組織和代碼優化複習(清華大學出版社第3版)

前言

目錄
01 文法和語言、詞法分析複習
02 自頂向下、自底向上的LR分析複習
03 語法制導翻譯和中間代碼生成複習
04 符號表、運行時存儲組織和代碼優化複習

第8章 靜態語義分析和中間代碼生成(續)

符號表

符號表需要在編譯期間用到,記錄符號的具體信息。本部分只討論PL/0符號表的建立。

PL/0符號表結構

PL/0的符號表包含5個信息:

  1. NAME符號名
  2. KIND符號類型
  3. LEVEL/VAL層次/值。如果類型爲CONSTANT,存放的是常量的值;如果類型爲VARIABLEPROCEDURE,存放所屬分程序的層次,主程序的層次爲0;在主程序中定義的內容層次爲1;主程序內第一層分程序中定義的內容層次爲2,以此類推。
  4. ADR地址。如果爲簡單變量或常量,則記錄的是該量在數據區所佔單元的相對地址,用DX表示給本層局部變量分配的相對存儲位置,每說明一個變量後DX加1;如果爲過程,則存放該過程的分程序入口地址(需要返填
  5. SIZE大小。該過程局部變量的個數(需要返填

例如下面的程序:

const a = 35, b = 49;
var c, d, e;
procedure p;
    var g;

對應的符號表爲:

NAME KIND VAL/LEVEL ADD SIZE
a CONSTANT 35
b CONSTANT 49
c VARIABLE LEV DX
d VARIABLE LEV DX+1
e VARIABLE LEV DX+2
p PROCEDURE LEV p的入口地址 4
g VARIABLE LEV+1 DX

又例如下面的程序:

const a = 25;
var x, y;
procedure p;
    var z;
    begin
        ...
    end;
procedure r;
var x, s;
    procedure t;
    var v;
        begin
        ...
        end;
    begin
    ...
    end;
begin
...
end.

對應的符號表爲:

NAME KIND VAL/LEVEL ADD SIZE
a CONSTANT 25
x VARIABLE LEV DX
y VARIABLE LEV DX+1
p PROCEDURE LEV p的入口地址 3
z VARIABLE LEV+1 DX
r PROCEDURE LEV r的入口地址 4
x VARIABLE LEV+1 DX
s VARIABLE LEV+1 DX+1
t PROCEDURE LEV+1 t的入口地址 3
v VARIABLE LEV+2 DX

第9章 運行時存儲組織(暫跳)

第10章 代碼優化

優化技術簡介

常用優化技術有:

  1. 刪除多餘運算
  2. 循環不變代碼外提
  3. 強度削弱
  4. 變換循環控制條件
  5. 合併已知量
  6. 複寫傳播與刪除無用賦值

刪除多餘運算

\((1)T_1:=4*I\)
\((2)T_2:=addr(A)-4\)
\((3)T_3:=T_2[T_1]\)
\((4)T_4:=4*I\)
\((5)T_5:=addr(B)-4\)
\((6)T_6:=T_5[T_4]\)

可以看到\((4)\)式做了和\((1)\)式重複的工作,可以改寫成\(T_4:=T_1\)

循環不變代碼外提

原代碼:
塊1
\((1)P:=0\)
\((2)I:=1\)
塊2
\((3)T_1:=4*I\)
\((4)T_2:=addr(A)-4\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(3)\)

可以看到\((4)\)式在每次循環都做重複的工作,可以把它提到循環外來,記得修改跳轉:
塊1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_2:=addr(A)-4\)
塊2
\((4)T_1:=4*I\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(4)\)

強度削弱

把強度大的運算換成強度小的運算,比如用加法換乘法:
塊1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_2:=addr(A)-4\)
塊2
\((4)T_1:=4*I\)
\((5)T_3:=T_2[T_1]\)
\((6)P:=P+T_3\)
\((7)I:=I+1\)
\((8)if \;I<=20\;goto\;(4)\)

\((4)\)式經過處理,並修改跳轉:
塊1
\((1)P:=0\)
\((2)I:=1\)
\((3)T_1:=0\)
\((4)T_2:=addr(A)-4\)
塊2
\((5)T_1:=T_1+4\)
\((6)T_3:=T_2[T_1]\)
\((7)P:=P+T_3\)
\((8)I:=I+1\)
\((9)if \;I<=20\;goto\;(5)\)

變換循環控制條件

下面的代碼中,\(I\)\(T_1\)保持4倍的線性關係:
塊1
\((1)I:=1\)
\((2)T_1:=4*I\)
塊2
\((3)P:=T_2[T_1]\)
\((4)I:=I+1\)
\((5)T_1=T_1+4\)
\((6)if\;I<=20\;goto\;(3)\)

可以把循環條件\(I<=20\)改爲\(T_1<=80\),然後修改\(T_1\)的初始賦值,這樣\(I\)在整個循環都沒有被用上,可以剔除:
塊1
\((1)T_1:=4\)
塊2
\((2)P:=T_2[T_1]\)
\((3)T_1=T_1+4\)
\((4)if\;T_1<=80\;goto\;(2)\)

合併已知量

下面的代碼中,在計算\(4*I\)時,\(I\)必定爲1:
\((1)I:=1\)
\((2)T_1:=4*I\)

因此可以直接在編譯期間算出它的值是4:
\((1)I:=1\)
\((2)T_1:=4\)

複寫傳播和刪除無用賦值

看下面的代碼:
塊1
\((1)T_1:=4\)
\((2)I:=1\)
塊2
\((3)T_2:=T_1\)
\(...\)
\((7)T_3:=T_4[T_2]\)
\((8)T_1:=T_1+T_3\)
\((9)I:=I+1\)
\((10)if\;T_1<=80\;goto\;(3)\)

四元式\((3)\)\(T_1\)的值寫入\(T_2\)中,但\(T_2\)\(T_1\)的值在\((3)\)\((7)\)之間沒有發生改變,故將\((7)\)改爲\(T_3:=T_4[T_1]\)

此時\((3)\)式沒有被引用,屬於無用賦值,可以刪掉。

然後,\((2)\),\((9)\)\(I\)賦值,但也只是自我引用,其餘地方沒有需要用到\(I\),屬於無用賦值,故可以刪掉。

最終變爲:
塊1
\((1)T_1:=4\)
塊2
\(...\)
\((5)T_3:=T_4[T_1]\)
\((6)T_1:=T_1+T_3\)
\((7)if\;T_1<=80\;goto\;(2)\)

基本塊、流圖和循環

基本塊

一個基本塊內部是順序執行的,故內部不能有任何停止、分支、跳轉。

基本塊的劃分:

  1. 條件轉移語句或者無條件轉移語句和下一句語句之間要劃分開
  2. 跳轉的目標語句要和上一句語句之間劃分開

例如:
\((1)\quad pi:=3.14\)
\((2)\quad ar:=0.0\)
\((3)\quad n:=16\)
\((4)\quad r:=1\)
\((5)\quad if\;n<=1\;goto\;(9)\)
\((6)\quad r:=r*n\)
\((7)\quad n:=n-1\)
\((8)\quad goto\;(5)\)
\((9)\quad ar:=2*pi\)
\((10)\quad ar:=ar*r\)
\((11)\quad print\;ar\)

經過劃分後:
B1
\((1)\quad pi:=3.14\)
\((2)\quad ar:=0.0\)
\((3)\quad n:=16\)
\((4)\quad r:=1\)
/////////////////////////////////////////////////
B2
\((5)\quad if\;n<=1\;goto\;(9)\)
/////////////////////////////////////////////////
B3
\((6)\quad r:=r*n\)
\((7)\quad n:=n-1\)
\((8)\quad goto\;(5)\)
/////////////////////////////////////////////////
B4
\((9)\quad ar:=2*pi\)
\((10)\quad ar:=ar*r\)
\((11)\quad print\;ar\)

流圖

流圖 是在已經劃分基本塊的基礎上,構造一個有向圖。

  1. 兩個相鄰基本塊如果上面的沒有跳轉,可以直接和下面的相連
  2. 如果當前基本塊最後存在無條件跳轉,直接和跳轉的目標基本塊相連
  3. 如果當前基本塊存在最後有條件跳轉,需要先和下面相鄰的基本塊相連,然後和跳轉的目標基本塊相連

上面的基本塊集合爲\(\{B1,B2,B3,B4\}\),可以用有向邊集合\(\{B1\rightarrow B2, B2\rightarrow B3, B3\rightarrow B2, B2\rightarrow B4\}\),這裏不畫圖。

循環

支配結點,指的是對任意兩個結點m和n來說,如果從流圖的首結點出發,到達n的任一通路都要經過m,則稱m是n的支配結點,記爲\(m\;DOM\;n\)

下圖是某個程序的流圖,其結點即程序中的基本塊

所有結點的支配結點集D(n):
\(D(1)=\{1\}\)
\(D(2)=\{1,2\}\)
\(D(3)=\{1,2,3\}\)
\(D(4)=\{1,2,4\}\)
\(D(5)=\{1,2,4,5\}\)
\(D(6)=\{1,2,4,6\}\)
\(D(7)=\{1,2,4,7\}\)

該圖的有向邊集合爲:\(\{1\rightarrow 2, 2\rightarrow 3, 2\rightarrow 4, 3\rightarrow 4, 4\rightarrow 2, 4\rightarrow 5, 4\rightarrow 6, 5\rightarrow 7, 6\rightarrow 6, 6\rightarrow 7, 7\rightarrow 4\}\)

回邊指的是存在一條邊\(A\rightarrow B\),使得\(B\in D(A)\)。故上圖的回邊有\(4\rightarrow 2, 6\rightarrow 6,7\rightarrow4\)

一個循環由其中的一條回邊\(A\rightarrow B\)對應的兩個結點\(B,A\),以及有通路到達\(A\)而不經過\(B\)的所有結點組成,並且保證\(B\)是該循環的唯一入口結點。

如包含回邊\((6\rightarrow 6)\)的循環爲\(\{6\}\)
包含回邊\((7\rightarrow 4)\)的循環爲\(\{4,5,6,7\}\)
包含回邊\((4\rightarrow 2)\)的循環爲\(\{2,3,4,5,6,7\}\)

這一章可能的考點

  1. 劃分基本表、畫出流圖、求支配集、找回邊、找循環
  2. 代碼局部優化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章