周知cpu為方便亂序執(zhí)行,內(nèi)部會(huì)使用重命名寄存器技術(shù)消除數(shù)據(jù)依賴(war和waw)。編譯器在如下場(chǎng)景也會(huì)用到重命名
1. 不可達(dá)代碼是指無論輸入什么都不會(huì)執(zhí)行的代碼,對(duì)過程而言,即是從入口基本塊到不了(沒有路徑可達(dá))的那些基本塊;死代碼是指可達(dá)但計(jì)算了后面任何可執(zhí)行路徑都不會(huì)使用其計(jì)算結(jié)果的代碼,比如死變量和死指令
2. 不可達(dá)代碼的識(shí)別本質(zhì)是有向圖的可達(dá)性判定與傳遞閉包計(jì)算問題,一般用DFS法處理。先找到從入口基本塊不可達(dá)的基本塊,再刪除(同時(shí)改變其前驅(qū)和后繼基本塊的指向),直到找不到為止。死代碼的識(shí)別可用活躍分析或必要指令標(biāo)記法,對(duì)于活躍分析,刪除基本塊出口不活躍的變量定值,以及它所使用不活躍操作數(shù)的定值;對(duì)于標(biāo)記法,從必要指令出發(fā),根據(jù)def-use鏈和use-def鏈,不斷標(biāo)記對(duì)其操作數(shù)有貢獻(xiàn)的指令,最后刪除沒被標(biāo)記的那些指令
3. 不可達(dá)代碼和死代碼可能來源于程序員,更可能源于編譯器的其它一些優(yōu)化產(chǎn)生,刪除優(yōu)化它們能顯著減小代碼體積,對(duì)執(zhí)行速度有間接的影響,因?yàn)榭赡芨纳浦噶罡咚倬弻拥睦寐?/div>
1. 目的是識(shí)別循環(huán)中那種在每個(gè)迭代都產(chǎn)生相同值的計(jì)算,并將它們移到循環(huán)之外。注意,如果一個(gè)計(jì)算出現(xiàn)在嵌套循環(huán)內(nèi),對(duì)外循環(huán)的特定迭代而言,內(nèi)循環(huán)的每個(gè)迭代都產(chǎn)生相同的值,但外循環(huán)的不同迭代產(chǎn)生不同的值,那么這種計(jì)算將移到內(nèi)循環(huán)外,而非外循環(huán)外
2. 識(shí)別循環(huán)不變量可以基于數(shù)據(jù)流分析求得的use-def鏈,一條指令是循環(huán)不變的,當(dāng)它的每個(gè)操作數(shù)滿足以下條件之一
a)該操作數(shù)是常數(shù)
b)該操作數(shù)的所有到達(dá)定值在循環(huán)之外。因?yàn)槿粲幸粋€(gè)在循環(huán)內(nèi),則該指令就可能是循環(huán)變化的,除非那個(gè)定值是循環(huán)不變量
c)該操作數(shù)只存在一個(gè)為循環(huán)不變量的到達(dá)定值,且該指令之前沒有對(duì)其左部變量(若有)的使用。因?yàn)槿粲卸鄠€(gè)這樣的定值,則該指令就可能是循環(huán)變化的,除非多個(gè)定值結(jié)果都一樣;因?yàn)槿羟懊嬗袑?duì)其左部變量的使用,則該指令的賦值就殺死了左部變量的初值,這樣外提后左部變量第一次迭代就會(huì)使用錯(cuò)誤的定值
3. 由于以上條件沒考慮到控制流分析,不能保證循環(huán)不變量在每個(gè)迭代中執(zhí)行,以及循環(huán)不變量之左部變量的所有使用都是相同的值。因此為了保證外提后的代碼行為正確,還需要滿足條件:循環(huán)不變量所在基本塊必須是循環(huán)中所有使用了其左部變量的基本塊和所有出口基本塊的必經(jīng)結(jié)點(diǎn)。當(dāng)外提循環(huán)不變量后,考慮到循環(huán)有可能執(zhí)行0次即一開始就不滿足循環(huán)進(jìn)入條件,可以用是否進(jìn)入循環(huán)的測(cè)試條件來保護(hù)前置塊,即識(shí)別終止條件是否一開始就為false,來保護(hù)它。這種方法總是安全的,但增加了代碼體積。不過若終止條件恒為true或false,則常數(shù)傳播分析會(huì)刪除這個(gè)冗余測(cè)試,如果為false,那么還會(huì)刪除前置塊
葉調(diào)用優(yōu)化與收縮包裝
1. 葉調(diào)用優(yōu)化適用于被調(diào)者是不調(diào)用任何過程的過程之場(chǎng)景,這種過程叫葉過程
2. 有幾種可能的優(yōu)化
a)如果過程的實(shí)現(xiàn)使用display數(shù)組來尋址非局部變量,那么葉過程可避免在起始代碼序列中更新display數(shù)組
b)如果葉過程內(nèi)不使用由被調(diào)者保存的寄存器(寄存器分配器應(yīng)設(shè)法優(yōu)先使用由調(diào)用者保存的寄存器),那么可避免起始代碼序列中保存代碼和收尾代碼序列中恢復(fù)代碼。很小的葉過程很可能不使用到被調(diào)者保存的寄存器,只使用部分調(diào)用者保存的寄存器的葉過程,那么調(diào)用者也可以避免一部分寄存器保存與恢復(fù)代碼
c)如果調(diào)用者有很多次調(diào)用葉過程,而且兩者代碼同時(shí)可見,那么葉過程不必自己分配棧幀,由調(diào)用者一次性分配好
3. 收縮包裝是葉調(diào)用優(yōu)化的一種推廣,目的是盡可能去掉過程起始代碼序列和收尾代碼序列中實(shí)際沒用的寄存器保存恢復(fù)代碼。可以先用數(shù)據(jù)流分析來計(jì)算每個(gè)基本塊的保存寄存器集合(基本塊入口可預(yù)見但其前驅(qū)不可預(yù)見且入口不可達(dá)的那些寄存器)與恢復(fù)寄存器集合(基本塊出口可達(dá)但其后繼不可達(dá)且出口不可預(yù)見的那些寄存器),再在保存寄存器集合非空的基本塊入口處插入save指令(插入點(diǎn)已是最早的合適的位置),恢復(fù)寄存器集合非空的基本塊出口處插入restore指令(插入點(diǎn)已是最晚的合適的位置)
尾調(diào)用優(yōu)化與尾遞歸刪除
1. 尾調(diào)用優(yōu)化的條件是兩個(gè)(不同)過程編譯時(shí)同時(shí)可見,比如處于同一編譯單元,或調(diào)用者有足夠多的、使得優(yōu)化可能發(fā)生的關(guān)于被調(diào)用者的信息
2. 尾調(diào)用優(yōu)化的實(shí)現(xiàn),因?yàn)楸徽{(diào)者返回后代碼序列到調(diào)用者收尾代碼序列之間不存在有用計(jì)算,所以原來標(biāo)準(zhǔn)鏈接處理要保存的那些寄存器不可能活躍,首先要裁剪調(diào)用前代碼序列即不保存由調(diào)用者保存的寄存器和不壓棧返回地址,以及裁剪被調(diào)過程的起始代碼序列即不保存由被調(diào)者保存的寄存器和不分配新棧幀(借用調(diào)用者的棧幀,若被調(diào)者的棧幀比調(diào)用者的大,則需按兩者之差擴(kuò)展棧幀),然后轉(zhuǎn)移到被調(diào)者裁剪過的起始代碼序列,最后修改被調(diào)過程的收尾代碼序列:正確釋放棧幀,比如用幀指針賦給棧指針,使之直接返回到調(diào)用者的調(diào)用者(比如o調(diào)用p,p調(diào)用q,q是尾調(diào)用,那么優(yōu)化后q實(shí)際返回到o)。綜上可得,尾調(diào)用優(yōu)化減免了壓棧返回地址與保存寄存器的開銷
3. 尾遞歸刪除是尾調(diào)用優(yōu)化的一種特例,由于調(diào)用者和被調(diào)者是同一過程,因此不存在擴(kuò)展棧幀和額外釋放棧幀,只須改變參數(shù)及跳轉(zhuǎn)到過程入口處即可
1. 數(shù)學(xué)基礎(chǔ):兩者的共同點(diǎn)是都基于數(shù)據(jù)流值的半格和對(duì)組合運(yùn)算封閉的傳遞函數(shù),不同點(diǎn)是區(qū)域分析算法還要求傳遞函數(shù)是一個(gè)半格,不僅支持組合運(yùn)算,而且支持交匯運(yùn)算和閉包運(yùn)算,交匯運(yùn)算用于把有相同后繼的不同執(zhí)行路徑組合起來,閉包運(yùn)算用于環(huán)上(比如循環(huán))執(zhí)行零到多次的效果
2. 流程:迭代算法由初始化和循環(huán)求不動(dòng)解組成,以前向數(shù)據(jù)流為例,其中初始化包括初始化入口基本塊的out集合為合適值,其它基本塊的out集合為半格的頂元素;循環(huán)求不動(dòng)解遍歷除入口外(因?yàn)槿肟诘膐ut不會(huì)變)的每個(gè)基本塊,計(jì)算其out集合,直至所有基本塊的out不再改變。區(qū)域分析算法由計(jì)算層次區(qū)域序列、構(gòu)造區(qū)域傳遞函數(shù)和計(jì)算各區(qū)域入口值組成,計(jì)算層次區(qū)域序列自底向上,基本塊為葉子區(qū)域,自然循環(huán)分為循環(huán)體區(qū)域和循環(huán)區(qū)域,都是內(nèi)部區(qū)域,不是自然循環(huán)的整個(gè)流圖為根區(qū)域;區(qū)域傳遞函數(shù)有2個(gè),一是R區(qū)域入口到其直接子區(qū)域S的入口的數(shù)據(jù)流值傳遞,記作Fin(R,S),另一是R區(qū)域入口到其直接子區(qū)域出口基本塊B(可能有多個(gè))出口處的數(shù)據(jù)流值傳遞,記作Fout(R,B),區(qū)域傳遞函數(shù)的計(jì)算自底向上,對(duì)于葉子區(qū)域,F(xiàn)in是恒等函數(shù),F(xiàn)out和迭代算法的傳遞函數(shù)一樣,取決于具體數(shù)據(jù)流問題;對(duì)于更大的區(qū)域(非葉子區(qū)域),遍歷每個(gè)子區(qū)域,F(xiàn)in由所有Fout(R,B)交匯而成,B為S在R中的前驅(qū),若R為循環(huán)區(qū)域,則再求Fout的閉包,遍歷S的每個(gè)出口基本塊B,F(xiàn)out由Fout(S,B)和Fin(R,S)組合而成。計(jì)算各區(qū)域入口值自頂向下,根區(qū)域的In值等于流圖入口的In值,其它區(qū)域S的In值等于Fin(R,S),R為父區(qū)域,所有Fin在前一環(huán)節(jié)已構(gòu)造好
3. 結(jié)果:對(duì)同一數(shù)據(jù)流問題比如到達(dá)定值,兩種算法求得的數(shù)據(jù)流值是一樣的。為什么區(qū)域分析算法是正確的?因?yàn)樗鼘?shí)際是按照程序控制流來構(gòu)造傳遞函數(shù)的,包含了所有可能執(zhí)行路徑數(shù)據(jù)流值傳遞的效果,這相當(dāng)于迭代算法求不動(dòng)解的過程,所以最后只要一個(gè)流圖的入口值,就能算出各區(qū)域的入口值。為什么迭代算法是收斂的?因?yàn)榘敫袷菃握{(diào)的且高度有窮。收斂速度取決于遍歷基本塊的順序,如果按基本塊深度優(yōu)先排序(逆后序)遍歷,那么迭代輪數(shù)不超過流圖的深度(各條無環(huán)路徑后退邊的最大數(shù))加2
4. 區(qū)別:迭代算法用于可歸約流圖和不可歸約流圖,區(qū)域分析算法僅能用于可歸約流圖
1. 作為指令高速緩層優(yōu)化的一種重要技術(shù),它根據(jù)CFG流圖邊的執(zhí)行頻率將頻繁執(zhí)行的基本塊排列在一起,并布局那些基本塊在下降分支路徑,而不在一起的也就是很少執(zhí)行的基本塊布局在轉(zhuǎn)移分支路徑。這樣做一來可以使取到I-cache中的指令實(shí)際被執(zhí)行的比例較高,二來對(duì)于某些體系結(jié)構(gòu)上轉(zhuǎn)移和下降路徑延遲不等的分支指令,可以降低跳轉(zhuǎn)延遲
2. 實(shí)現(xiàn)過程內(nèi)代碼置放有以下幾個(gè)環(huán)節(jié):
a)獲取剖析數(shù)據(jù):編譯器可以先在基本塊出口處插入代碼以統(tǒng)計(jì)到其后繼基本塊的執(zhí)行次數(shù),作為CFG流圖邊的權(quán)重,然后編譯生成可執(zhí)行文件,輸入代表性數(shù)據(jù)運(yùn)行它,結(jié)果輸出一個(gè)數(shù)據(jù)文件,用于第二次編譯,這次編譯實(shí)施過程內(nèi)代碼置放優(yōu)化
b)以鏈的形式構(gòu)建熱路徑:熱路徑是CFG路徑的一個(gè)集合,其中包括頻繁執(zhí)行的那些邊,每條路徑是一個(gè)或多個(gè)基本塊按邊的方向構(gòu)成的鏈,每個(gè)鏈關(guān)聯(lián)一個(gè)優(yōu)先級(jí),用于布局代碼的先后順序。初始時(shí),每個(gè)基本塊構(gòu)成一個(gè)只有它本身的鏈,其優(yōu)先級(jí)為CFG流圖邊的數(shù)量或者更大值;接下來,在CFG中按權(quán)重降序遍歷每條邊<x,y>(x不等于y),若x是某個(gè)鏈a的尾結(jié)點(diǎn)且y是某鏈b的頭結(jié)點(diǎn),則把b合并到a后面,更新a的優(yōu)先級(jí)為a原來優(yōu)先級(jí)、b優(yōu)先級(jí)、P三者的最小值,同時(shí)遞增P,其中P為鏈合并操作的計(jì)數(shù)器,用于決定鏈的相對(duì)次序由低到高排列,初值為0。當(dāng)遍歷結(jié)束時(shí),所有熱路徑構(gòu)建完成
c)進(jìn)行代碼布局:經(jīng)過前一環(huán)節(jié),就得到了鏈的集合。首先從鏈集合找出含有入口基本塊的鏈t,將t加入工作表WL;然后從WL移出一個(gè)優(yōu)先級(jí)最低的鏈c,按序(構(gòu)建鏈時(shí)加入基本塊的順序)遍歷c的每個(gè)基本塊x,把x放在過程可執(zhí)行代碼體的末端,對(duì)于邊<x,y>,將包含y的鏈t加入WL(若t不在WL中),重復(fù)該過程直至WL為空
【輸入輸出】
一個(gè)過程的所有基本塊,除entry和exit外的每個(gè)基本塊包含指令序列
【流程】
由前向數(shù)據(jù)流分析、局部復(fù)寫傳播和遍歷基本塊構(gòu)成
1. 前向數(shù)據(jù)流分析:目標(biāo)是計(jì)算出每個(gè)基本塊入口處有效的復(fù)寫賦值集合,這里定義為CPin(i),i為基本塊,其元素為表示復(fù)寫賦值的四元組<u,v,blk,pos>,u為左變量,v為右變量,blk為基本塊,pos為在blk中的位置。另外定義COPY(i)為基本塊i中出現(xiàn)且到達(dá)了出口的那些復(fù)寫賦值集合,即u和v在i中pos后沒被賦值;KILL(i)為被基本塊i殺死的那些賦值集合,即i中存在對(duì)其它基本塊復(fù)寫賦值右變量的賦值;CPout(i)為基本塊i出口處有效的復(fù)寫賦值集合。以上四種集合的數(shù)據(jù)流方程為:CPin(i)等于i的每個(gè)前驅(qū)p的CPout的交集,CPout(i)等于COPY(i)與CPin(i)減去KILL(i)之差的并集。CPout(entry)初值為空集,其它基本塊的CPout初值為全集U,U為過程所有復(fù)寫賦值的集合即所有基本塊的COPY之并集,根據(jù)迭代求不動(dòng)點(diǎn)法可算出每個(gè)基本塊最終的CPin值
2. 局部復(fù)寫傳播:作為被全局復(fù)寫傳播調(diào)用的例程,有兩個(gè)參數(shù),一個(gè)為輸入輸出參數(shù)單個(gè)基本塊,另一個(gè)為輸入?yún)?shù)CPin,即前向數(shù)據(jù)流分析求得的結(jié)果。該例程內(nèi)部維護(hù)一個(gè)有效復(fù)寫賦值的表,稱作ACP,其元素為二元組<u,v>,u是復(fù)寫賦值的左變量,v是右變量。首先初始化ACP即將CPin中的復(fù)寫賦值加入到ACP,再遍歷基本塊的每條指令,針對(duì)指令類別做對(duì)應(yīng)的處理,有以下幾種情況
a)對(duì)于一元/二元表達(dá)式及過程調(diào)用,將表達(dá)式的操作數(shù)或調(diào)用參數(shù)替換為ACP中對(duì)應(yīng)元組的第二分量,若不存在這樣的元組則不用替換
b)對(duì)于賦值語句(包括復(fù)寫賦值),從ACP中刪除第一或第二分量為賦值語句左變量的元組,這是為了刪除被殺死的復(fù)寫賦值
c)對(duì)于復(fù)寫賦值且左變量u不等于右變量v,將元組<u,v>加入到ACP
當(dāng)遍歷結(jié)束后,局部復(fù)寫傳播就完成了
3. 遍歷基本塊:對(duì)每個(gè)基本塊調(diào)用局部復(fù)寫傳播,當(dāng)遍歷結(jié)束后,全局復(fù)寫傳播就完成了
【分析】
數(shù)據(jù)流分析的復(fù)雜度取決于基本塊總數(shù)及指令總數(shù),局部復(fù)寫傳播的復(fù)雜度取決于基本塊的指令總數(shù),遍歷基本塊復(fù)雜度取決于基本塊數(shù)量。全局復(fù)寫傳播會(huì)造成無用的賦值指令,但是這正給死代碼刪除和強(qiáng)度削減(比如兩個(gè)相同的整型變量加法用移位代替)提供了機(jī)會(huì)
【輸入】
ssa控制流圖。結(jié)點(diǎn)為一個(gè)phi函數(shù)或一條運(yùn)算指令,邊包含控制流邊和ssa邊
【輸出】
所有ssa變量的最終LatCell(常量半格值)
【流程】
1. 算法維護(hù)兩個(gè)工作表,一是流圖邊FlowWL,用于跟蹤控制流的執(zhí)行,二是ssa邊SSAWL,用于單賦值變量的傳播。還有一個(gè)ExecFlag映射,用于確保僅有控制流邊導(dǎo)向的運(yùn)算結(jié)點(diǎn)最多執(zhí)行一次,多次執(zhí)行是沒必要的,因?yàn)檫\(yùn)算涉及的分量不會(huì)變(沒有ssa前驅(qū)邊),ExecFlag(a,b)為true表示邊a->b導(dǎo)向的結(jié)點(diǎn)b已執(zhí)行,否則未執(zhí)行
2. 兩種結(jié)點(diǎn)的分析:
a) 對(duì)于phi結(jié)點(diǎn),不管被哪種邊導(dǎo)向,都先計(jì)算其LatCell(phi結(jié)果與各個(gè)phi參數(shù)的交),若與舊值不同,則將它的ssa后繼邊加入SSAWL,若控制流后繼邊尚未執(zhí)行即對(duì)應(yīng)ExecFlag為false,則將它的控制流后繼邊加入FlowWL
b) 對(duì)于運(yùn)算結(jié)點(diǎn),若是控制流邊導(dǎo)向且未被執(zhí)行過(到結(jié)點(diǎn)的所有邊的ExecFlag為false)或ssa邊導(dǎo)向且以前執(zhí)行過(存在至少一條邊的ExecFlag為true),則執(zhí)行其運(yùn)算,計(jì)算左值變量的LatCell(解釋執(zhí)行整數(shù)運(yùn)算),若與舊值不同,則將ssa后繼邊加入SSAWL,若LatCell是常量且為條件運(yùn)算,則將滿足條件的Y或N邊加入FlowWL,否則將所有控制流后繼邊加入FlowWL
3. 算法初始時(shí),設(shè)置所有控制流邊的ExecFlag為false,設(shè)置所有ssa變量的LatCell為未知(半格頂元素),將流圖入口到第1個(gè)結(jié)點(diǎn)的邊加入FlowWL。然后進(jìn)行主循環(huán),先從FlowWL移出一條邊,若邊的ExecFlag為false則設(shè)為true,判斷尾結(jié)點(diǎn)類型,若為phi則轉(zhuǎn)到上述2-a處理,若為運(yùn)算則轉(zhuǎn)到2-b處理;再從SSAWL移出一條邊,若邊尾結(jié)點(diǎn)為phi類型則轉(zhuǎn)到2-a處理,否則為運(yùn)算類型轉(zhuǎn)到2-b處理,以上過程直至FlowWL和SSAWL皆為空
【分析】
該算法思想是符號(hào)執(zhí)行,對(duì)于運(yùn)算x=y或x=y+z(這里+泛指對(duì)整型有意義的操作),在常量半格中,x、y、z初值為未知,y和z單調(diào)降低,導(dǎo)致x也單調(diào)降低,它們最多降低2次,故當(dāng)格值不變后,SSAWL終為空,另外由于ExecFlag的作用導(dǎo)致所有僅控制流邊導(dǎo)向的結(jié)點(diǎn)最多執(zhí)行一次,因此FlowWL終為空,算法是收斂的,復(fù)雜度取決于控制流邊和ssa邊的總數(shù)
【輸入】
程序控制流圖CFG
【輸出】
帶區(qū)域結(jié)點(diǎn)的控制依賴圖CDG
【流程】
1. 為CFG添加一個(gè)虛構(gòu)謂詞結(jié)點(diǎn)start,它的Y邊指向入口結(jié)點(diǎn)entry,出邊指向出口結(jié)點(diǎn)exit,得到CFG+。添加start是因?yàn)閑ntry到第1個(gè)基本塊沒有條件判斷
2. 為CFG+構(gòu)建后必經(jīng)結(jié)點(diǎn)樹PDOMTree,將CFG+中所有n不是m的后必經(jīng)結(jié)點(diǎn)的邊m->n加入集合S,邊的標(biāo)號(hào)來自CFG為Y或N
3. 遍歷S,對(duì)每條邊m->n,先在PDOMTree中找到最低公共祖先p(如果m為根結(jié)點(diǎn)則為m,否則為m的父結(jié)點(diǎn)),再將PDOMTree中p到n路徑上每個(gè)結(jié)點(diǎn)(p和entry除外)x加入CDG,并添加邊m->x,其邊標(biāo)號(hào)同m->n
4. 對(duì)CDG的每個(gè)內(nèi)部結(jié)點(diǎn),若存在Y邊,則新建一個(gè)區(qū)域結(jié)點(diǎn),連接所有Y邊對(duì)應(yīng)的子結(jié)點(diǎn);若存在N結(jié)點(diǎn),則新建一個(gè)區(qū)域結(jié)點(diǎn),連接所有N邊對(duì)應(yīng)的子結(jié)點(diǎn)
【應(yīng)用】
對(duì)于控制依賴于同一結(jié)點(diǎn)的所有結(jié)點(diǎn),只要它們之間沒有數(shù)據(jù)依賴關(guān)系,就可以并行執(zhí)行
【輸入】
根過程,及每個(gè)過程(含根過程)的指令序列
【輸出】
調(diào)用圖,由過程點(diǎn)集和調(diào)用邊(形如<p,i,q>,p在位置i調(diào)用q)集構(gòu)成
【全局結(jié)構(gòu)】
PVVs:過程值變量集合
PVVals:過程值變量到過程常數(shù)集合的映射
PVBinds:過程值變量到過程值變量集合的映射
PVCalls:調(diào)用邊的集合
【流程核心】
1. 分析過程p內(nèi)指令,要處理調(diào)用指令和賦值指令兩種類型。對(duì)于調(diào)用指令,若被調(diào)過程q是過程常數(shù),則將q和<p,i,q>加入調(diào)用圖,先解析q的過程值形參與傳入實(shí)參的關(guān)系,有4種情況
a)過程常數(shù)cp傳入過程值形參fp,將偶對(duì)<fp,cp>加入PVVals,fp加入PVVs
b)過程值變量vp傳入過程值形參fp,將<fp,vp>加入PVBinds,fp和vp加入PVVs
c)過程值形參fp傳出過程值變量vp,將<vp,fp>加入PVBinds,vp和fp加入PVVs
d)過程值形參fp傳出過程常數(shù)cp,將<fp,cp>加入PVVals,fp加入PVVs
若q不是常數(shù)而是過程值變量,則將q加入PVVs,<p,i,q>加入PVCalls。再解析q的返回與p的關(guān)系,有2種情況
e)返回一個(gè)過程值變量vp1賦給另一過程值變量vp2,將<vp2,vp1>加入PVBinds,vp2和vp1加入PVVs
f)返回一個(gè)過程常數(shù)cp賦給一個(gè)過程值變量vp,將<vp,cp>加入PVVals,vp加入PVVs
對(duì)于賦值指令,其實(shí)情況和上述返回賦值一樣
----------------------------------------------------------------
2. 遍歷PVVs,傳播各過程值變量的PVBinds,直至不再改變(迭代求不動(dòng)解),本質(zhì)是計(jì)算過程值變量的傳遞閉包
3. 遍歷PVCalls,對(duì)每個(gè)<p,i,q>,先遍歷它的每個(gè)PVVals u,將u和<p,i,u>加入調(diào)用圖;再遍歷它的每個(gè)PVBinds u及u的每個(gè)PVVals v,將v和<p,i,v>加入調(diào)用圖
----------------------------------------------------------------
以上三環(huán)節(jié)可使用工作表w來驅(qū)動(dòng),w初始只有根過程,不斷從w移出一個(gè)過程p、分析p,每當(dāng)在環(huán)節(jié)1或環(huán)節(jié)3發(fā)現(xiàn)一個(gè)新過程(過程常數(shù))就加入w,直至w為空,這時(shí)所有過程都已分析,調(diào)用圖構(gòu)建完成