日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

静态程序分析chapter3 - 数据流分析详述(Reaching Definitions、Live Variables、Available Expressions Analysis)

發(fā)布時(shí)間:2025/6/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 静态程序分析chapter3 - 数据流分析详述(Reaching Definitions、Live Variables、Available Expressions Analysis) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 二、
  • 數(shù)據(jù)流分析
    • introduction1
    • introduction2
      • 輸入和輸出狀態(tài)
    • 轉(zhuǎn)換函數(shù)
  • 數(shù)據(jù)流分析應(yīng)用
    • 1,Reaching Definitions Analysis
      • 概述
      • 用途
      • 分析流程
        • 1,抽象
        • 2,轉(zhuǎn)換函數(shù)
        • 3,控制流處理
        • 4,算法實(shí)現(xiàn)
          • 1,初始化
          • 2,第一輪迭代
          • 3,第二輪迭代
          • 4,第三輪迭代
      • 小結(jié)
    • 2,Live Variables Analysis
      • 概述
      • 用途
      • 分析流程
      • 前向分析與后向分析
        • 1,抽象
        • 2,轉(zhuǎn)換函數(shù)
        • 3,控制流處理
        • 4,算法實(shí)現(xiàn)
          • 1,初始化
          • 2,第一輪迭代
          • 3,第二輪迭代
          • 4,第三輪迭代
    • 3,Available Expressions Analysis
      • 概述
      • 用途
      • 分析流程
        • 1,抽象
        • 2,轉(zhuǎn)換函數(shù)
        • 3,控制流處理
        • must analysis 可能會產(chǎn)生漏報(bào)的示例:
        • 4,算法實(shí)現(xiàn)
          • 1,初始化
          • 2,第一輪迭代
          • 3,第二輪迭代
  • 總結(jié)


二、

數(shù)據(jù)流分析

introduction1

??????數(shù)據(jù)流分析:怎樣的數(shù)據(jù)?如何流向?在什么上分析?

??????怎樣的數(shù)據(jù)?我們所關(guān)心的感興趣的屬性,比如像之前提到過的變量的符號(抽象和過近似見博客:https://blog.csdn.net/Little_ant_/article/details/118701090),需要對屬性進(jìn)行抽象

??????如何流向?一般情況下需要采用過近似,包括轉(zhuǎn)換函數(shù)控制流處理。通常情況下視問題的不同,需要采用 over-approximate 或 under-approximate,對應(yīng)的是傾向于 Sound 和 Complete。通常將采用的 over-approximate 的數(shù)據(jù)流分析稱為 may analysis,將采用的 under-approximate 的數(shù)據(jù)流分析稱為 must analysis。因?yàn)?may analysis 是偏向于 Sound 的,所以它分析的結(jié)果可能是真的;而 must analysis 是偏向于 Complete 的,所以它分析的結(jié)果一定是真的。

??????在什么上分析?在 CFG 上來分析(CFG是在 IR 上建立的,IR 是由待分析程序得到的),CFG 包括節(jié)點(diǎn)和邊。在節(jié)點(diǎn)上分析遵循的方法是轉(zhuǎn)換函數(shù),在邊上的分析遵循的是控制流處理。

introduction2

輸入和輸出狀態(tài)

??????針對一條 IR 語句和我們感興趣的屬性,在該語句執(zhí)行前屬性的狀態(tài)稱為輸入狀態(tài);在該語句執(zhí)行后屬性的狀態(tài)稱為輸出狀態(tài)。在順序執(zhí)行時(shí),上一條語句的輸出狀態(tài)是下一條語句的輸入狀態(tài)。在有分支的情況下,匯合點(diǎn)之前的輸入狀態(tài)和多條分支的輸出狀態(tài)均有關(guān),需要對這些輸出狀態(tài)進(jìn)行某種操作,具體為哪種操作取決于具體的問題。見下圖:其中 s1、s2、s3 為 IR 語句。

??????在一個(gè)數(shù)據(jù)流分析應(yīng)用中,在每一個(gè)程序點(diǎn)都會關(guān)聯(lián)一個(gè)數(shù)據(jù)流狀態(tài),這個(gè)數(shù)據(jù)流狀態(tài)是我們能夠在該點(diǎn)處能夠觀測到的所關(guān)心屬性的抽象之后的全部狀態(tài)。比如在對所有變量的符號判斷中,抽象之后的符號域中有 5 個(gè)元素:+、-、O、T、⊥。對下圖中程序,一些程序點(diǎn)處的數(shù)據(jù)流狀態(tài)被列出在右側(cè)綠色區(qū)域中。

??????數(shù)據(jù)流分析就是在所有程序點(diǎn)的輸入狀態(tài)和輸出狀態(tài)上,采用某種近似方法(包括轉(zhuǎn)換函數(shù)和控制流處理)對程序進(jìn)行分析,從而得到針對某種問題的解決方案。

轉(zhuǎn)換函數(shù)

?????? 前向分析:按著程序執(zhí)行流的方向進(jìn)行分析,可認(rèn)為是由輸入得到輸出。后向分析:按著程序執(zhí)行流的反方向進(jìn)行分析,可認(rèn)為是由輸出得到輸入。

??????轉(zhuǎn)換函數(shù):描述某一條語句 s 的輸入狀態(tài) IN[s] 和輸出狀態(tài) OUT[s] 之間的轉(zhuǎn)換關(guān)系。在前向分析中,描述如何通過 IN[s] 得到 OUT[s];在后向分析中,描述如何通過 OUT[s] 得到 IN[s]。如下圖:

??????存在一個(gè)基本塊 B ,它包含有語句 s1、s2、s3 … sn 。

??????那么在基本塊之內(nèi)有:IN[s2] = OUT[s1]、IN[s3] = OUT[s2]、IN[s4] = OUT[s3] …即之前提到過的 “在順序執(zhí)行時(shí),上一條語句的輸出狀態(tài)是下一條語句的輸入狀態(tài)”

??????如果 B 的前驅(qū)為 P1 和 P2,后繼為 S1 和 S2 ,在基本塊之間有:IN[B] = IN[s1]、OUT[B] = OUT[sn] 。從而得到 OUT[B] 和 IN[B] 的關(guān)系與 B 中的所有語句的轉(zhuǎn)換函數(shù)有關(guān),并且在前向分析中: B 的輸入狀態(tài) IN[B] 和它的所有前驅(qū)的輸出狀態(tài) OUT[P] 有關(guān)系;后向分析中:B 的輸出狀態(tài) OUT[B] 和它的所有后繼的輸入狀態(tài) IN[S] 有關(guān)系。在下圖中,淡黃色部分表示前向分析,淡紅色部分表示后向分析,Λ表示 meet operator。

數(shù)據(jù)流分析應(yīng)用

??????下面介紹三個(gè)基本的數(shù)據(jù)流分析應(yīng)用示例。

1,Reaching Definitions Analysis

概述

??????注意在這里 definition 的意思不是定義,而是賦值/初始化。

??????Reaching Definition Analysis :A definition d at program point p reaches a point q if there is a path from p to q such that d is not “killed” along that path . 中文翻譯為:在程序點(diǎn) p 處,存在一個(gè)賦值語句 d 表示對某個(gè)變量進(jìn)行賦值,如果在通往之后的程序點(diǎn) q 之間的任意一條路徑上,d 是存活的(即該變量并沒有被重新賦值,仍然是之前的那個(gè)值),那么認(rèn)為在 p 處的賦值語句 d 能夠到達(dá) q 點(diǎn)(即 d 在 q 處依然是有效的)。

??????Reaching Definitions Analysis是,針對程序中的每個(gè)賦值語句(d, v = C),分析出它可能到達(dá)的所有程序點(diǎn)(通常是一條指令的前后處)。等價(jià)說法是,RDA是針對程序中的每個(gè)程序點(diǎn)(通常是一條指令的前后處),分析出可能到達(dá)此處的所有賦值語句(d, v = E)。

??????可以看出,它屬于 may analysis。因?yàn)橹灰嬖谝粭l路徑上沒有對變量 v 重新賦值,就認(rèn)為原來的賦值語句 v = C 是有效地,但是,可能會在別的路徑上對 v 重新賦值(令 v = C1)。所以并不能確定該賦值語句 100% 能夠到達(dá)之后的程序點(diǎn),這取決于程序執(zhí)行時(shí)走的哪條路徑。may analysis 采用的是過近似,即哪怕有99條路徑上變量 v 都被賦值/初始化了,但是有一條路徑上沒有,那這一條路徑也是需要考慮的,因?yàn)槌绦蚴怯锌赡茏哌@條沒有被賦值/初始化的路徑的,過近似的特點(diǎn)就是不放過任何一個(gè)程序執(zhí)行時(shí)可能的行為(不放過任何一條路徑),所以它得到的結(jié)果有可能是真的。

用途

??????可用于死代碼去除。對于某條賦值語句(d, v = C),它可以到達(dá)的程序點(diǎn)假設(shè)為 p1、p2、p3 … 那么如果在這些程序點(diǎn)處,發(fā)現(xiàn)變量 v 并沒有被使用過,從而得出該賦值語句是一條無用代碼,刪除該賦值語句 d 做代碼優(yōu)化。

??????簡單的內(nèi)存泄露檢查。原理是類似的,對于動(dòng)態(tài)內(nèi)存分配指令(d,v = new …),判斷在該語句所有可達(dá)的程序點(diǎn)處,是否存在有 delete 語句,如果這些可達(dá)程序點(diǎn)處均沒有 delete 語句,則認(rèn)為發(fā)生了內(nèi)存泄露。

??????簡單的錯(cuò)誤檢測。我們首先在 entery 塊中對程序中的變量引入一條條假的賦值/初始化語句(即這些變量還沒有被賦值/初始化),如果在之后某條假賦值語句的的可達(dá)程序點(diǎn)處,發(fā)現(xiàn)這個(gè)變量被使用了,那么有可能發(fā)生了錯(cuò)誤(變量在賦值/初始化前被使用)。“可能” 意味著不確定,因?yàn)橛锌赡軇e的路徑上存在這個(gè)變量的賦值/初始化語句。

分析流程

??????可以發(fā)現(xiàn):對于 RDA,在程序的第一條語句之前,還沒有任何語句被執(zhí)行,那么在此處所有賦值語句都是不可達(dá)的。而在程序的最后一條語句之后,所有的賦值語句是否可達(dá)并不確定,所以我們采用前向分析,從第一條語句至最后一條語句。

1,抽象

??????抽象:因?yàn)槲覀冴P(guān)心的是程序中所有變量的賦值語句都能到達(dá)哪些程序點(diǎn),那么就需要對這些賦值語句進(jìn)行抽象。這里采用位向量來表示。假設(shè)程序中有賦值語句100個(gè),那么需要有100個(gè)比特位來表示,第一位表示第一條賦值語句是否可達(dá),若可達(dá)置為1,不可達(dá)置為0。那么在第一個(gè)程序點(diǎn)(程序的第一條語句之前)處,置這100個(gè)比特位均為0,表示均不可達(dá)。

2,轉(zhuǎn)換函數(shù)

??????轉(zhuǎn)換函數(shù):在前向分析中的轉(zhuǎn)換函數(shù)是計(jì)算如何從輸入狀態(tài)得到輸出狀態(tài),我們以一條語句來進(jìn)行分析。

??????假設(shè)存在一條語句 D:v = x op y ,這一條語句使用變量 x 和 y 對變量 v 賦值。重申:我們分析的是程序中所有賦值語句,判斷它們在各個(gè)程序點(diǎn)處的可達(dá)情況。所以得出:在語句 D 執(zhí)行之后的程序點(diǎn)處,賦值語句 D 中變量 v 是可達(dá)的,而在程序中其余的對 v 的賦值語句在此是不可達(dá)的。而對于變量 x、y,仍然保持在語句 D 執(zhí)行之前的可達(dá)性。 新的賦值語句 D 的比特位在此設(shè)置為 1,其余的對 v 的賦值語句全設(shè)置為 0.

??????轉(zhuǎn)換函數(shù)用公式表示為:OUT[B] = genB U (IN[B] - killB) ??????U表示或操作。

??????B表示一個(gè)基本塊,這個(gè)公式做兩件事:令其他地方的賦值語句不可達(dá),設(shè)置當(dāng)前的新賦值語句可達(dá)。當(dāng)然對于每一條語句也是一樣適用的。下圖計(jì)算程序中的基本塊的 genB 和 killB:

3,控制流處理

??????控制流處理:在有分支的情況下,假設(shè)基本塊 B 的兩個(gè)前驅(qū)為 P1 和 P2。現(xiàn)在討論IN[B],如果OUT[P1]中的某些賦值語句的變量是可達(dá)的,而在OUT[P2]中的這些賦值語句的變量是不可達(dá)的,根據(jù) RDA 的定義,只要有一條路徑上某個(gè)變量是可達(dá)的,就認(rèn)為它是可達(dá)的。所以應(yīng)該采用或操作,1 或 0 = 1。

??????控制流處理用公式表示為:IN[B] = U OUT[P](p is a predecessor of B )

4,算法實(shí)現(xiàn)

??????在抽象、轉(zhuǎn)換函數(shù)和控制流處理之后,關(guān)于 RDA 的算法如下圖:
??????這個(gè)算法是一個(gè)迭代算法,可以當(dāng)做模板應(yīng)用于別的數(shù)據(jù)流分析中。算法的輸入是 CFG ,輸出是判斷每一個(gè)程序點(diǎn)(這里以基本塊為單位)處所有賦值語句是否可達(dá)。

1,初始化

??????初始化語句第一步,令 entry 的輸出狀態(tài)為空,這個(gè)之前講過,需要從語義上來理解:因?yàn)榇颂幹皼]有任何語句,所以在這里所有賦值語句均是不可達(dá)的。

??????初始化語句第二步,令除了 entry 之外的其他基本塊的輸出狀態(tài)也為空,為空的原因后面會講到,總之 may analysis 通常都會初始化為空集,用符號⊥來表示,稱為 bottom。而 must analysis 剛好相反,常被初始化為滿集,用符號 T 來表示,稱為 top。

??????while 循環(huán)的判定條件為任何一個(gè)基本塊的 OUT 集合發(fā)生改變時(shí),循環(huán)主體是對除了 entry 塊的其余基本塊做:控制流處理和轉(zhuǎn)換函數(shù)的實(shí)現(xiàn)。至于這個(gè)循環(huán)一定會停止的原因后面再講,我們先通過一個(gè)例子熟悉這個(gè)迭代算法,見下圖:一共有8個(gè)賦值語句,5個(gè)基本塊,緊接著會對算法執(zhí)行流程做說明。

??????初始化:初始化的結(jié)果如上圖的黑色字體來表示,按照算法描述,所有的 OUT 均初始化為 0000 0000。

2,第一輪迭代

??????第一輪迭代:執(zhí)行循環(huán)體,用紅色字體來表示執(zhí)行結(jié)果,如上圖顯示的是 IN[B1] = OUT[entry] = 0000 0000
前向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:OUT[B1] = 1100 0000 U (0000 0000 - 0001 1010)= 1100 0000。這里的減法運(yùn)算為:1-1=0、1-0=1、0-1=0、0-0=0。

IN[B2] = OUT[B4] U OUT[B1] = 0000 0000 U 1100 0000 = 1100 0000;
OUT[B2] = 0011 0000 U (1100 0000 - 0100 0000)= 1011 0000

IN[B3] = OUT[B2];
OUT[B3] = 0000 0010 U (1011 0000 - 1000 1000)= 0011 0010

IN[B4] = OUT[B2];
OUT[B4] = 0000 1100 U (1011 0000 - 1000 0011)= 0011 1100

IN[B5] = OUT[B4] U OUT[B3] = 0011 1100 U 0011 0010 = 0011 1110;
OUT[B5] = 0000 0001 U (0011 1110 - 0000 0100)= 0011 1011

??????根據(jù)算法的循環(huán)判定條件,存在有基本塊的 OUT 發(fā)生了變化(事實(shí)上所有基本塊的 OUT 都發(fā)生了變化,不再是初始的 0000 0000了),那么將進(jìn)入第二輪迭代。第一輪迭代執(zhí)行完畢的結(jié)果如下圖:

3,第二輪迭代

??????第二輪迭代:在上圖第一輪的執(zhí)行結(jié)果上進(jìn)行,IN[B1]保持不變,IN[B1] = OUT[entry] = 0000 0000
前向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:OUT[B1] = 1100 0000 U (0000 0000 - 0001 1010)= 1100 0000

IN[B2] = OUT[B4] U OUT[B1] = 0011 1100U 1100 0000 = 1111 1100;
OUT[B2] = 0011 0000 U (1111 1100 - 0100 0000)= 1011 1100

IN[B3] = OUT[B2];
OUT[B3] = 0000 0010 U (1011 1100 - 1000 1000)= 0011 0110

IN[B4] = OUT[B2];
OUT[B4] = 0000 1100 U (1011 1100 - 1000 0011)= 0011 1100

IN[B5] = OUT[B4] U OUT[B3] = 0011 1100 U 0011 0110 = 0011 1110;
OUT[B5] = 0000 0001 U (0011 1110 - 0000 0100)= 0011 1011

??????根據(jù)算法的循環(huán)判定條件,存在有基本塊的 OUT 發(fā)生了變化(B2,B3),那么將進(jìn)入第三輪迭代。第二輪迭代執(zhí)行完畢的結(jié)果如下圖:

4,第三輪迭代

??????第三輪迭代:在上圖第二輪的執(zhí)行結(jié)果上進(jìn)行,IN[B1]保持不變,IN[B1] = OUT[entry] = 0000 0000
前向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:OUT[B1] = 1100 0000 U (0000 0000 - 0001 1010)= 1100 0000

IN[B2] = OUT[B4] U OUT[B1] = 0011 1100 U 1100 0000 = 1111 1100;
OUT[B2] = 0011 0000 U (1111 1100 - 0100 0000)= 1011 1100

IN[B3] = OUT[B2];
OUT[B3] = 0000 0010 U (1011 1100 - 1000 1000)= 0011 0110

IN[B4] = OUT[B2];
OUT[B4] = 0000 1100 U (1011 1100 - 1000 0011)= 0011 1100

IN[B5] = OUT[B4] U OUT[B3] = 0011 1100 U 0011 0110 = 0011 1110;
OUT[B5] = 0000 0001 U (0011 1110 - 0000 0100)= 0011 1011

??????根據(jù)算法的循環(huán)判定條件,所有基本塊的 OUT 都沒有發(fā)生變化,迭代停止,算法執(zhí)行完畢。第三輪迭代執(zhí)行完畢的結(jié)果如下圖:

??????此時(shí)那些綠色字體表示的就是算法的最終結(jié)果,我們在每一個(gè)程序點(diǎn)處得到了所有賦值語句的最終狀態(tài)(是否可達(dá))。

小結(jié)

??????數(shù)據(jù)流分析:我們首先在每一個(gè)程序點(diǎn)處關(guān)聯(lián)一個(gè)數(shù)據(jù)流值,這個(gè)數(shù)據(jù)流值是對該程序點(diǎn)處可以觀測到的所有可能的程序狀態(tài)做抽象得到的 ;然后對所有程序點(diǎn)處應(yīng)用某種近似(over-appro or under-appro)方法得到某種結(jié)論的分析手段。(可直白的認(rèn)為:在抽象域上,采用轉(zhuǎn)換函數(shù)和控制流處理對程序分析并得出結(jié)論)

??????RDA可應(yīng)用于死代碼消除,在上面例子中,對于賦值語句 D1,它的可達(dá)程序點(diǎn)為 OUT[B1] 和 OUT[B2]。而在 B1 和 B2 兩個(gè)基本塊中可以發(fā)現(xiàn) D1 中的變量 x 并沒有被使用過,所以賦值語句 D1 在這個(gè)程序就是一條死代碼,于程序而言,它的存在沒什么意義,應(yīng)予以刪除。

??????迭代為什么能停止?
??????可以發(fā)現(xiàn):根據(jù)轉(zhuǎn)換函數(shù)的公式,一個(gè)基本塊中的 genB 和 killB 在每一輪的迭代中是不會發(fā)生變化的,因?yàn)槌绦驔]有改變,只有 IN[B] 發(fā)生變化,OUT[B] 才會發(fā)生變化,而由初始化可知,所有程序點(diǎn)的 OUT 是初始化為空集的(bottom),所以 OUT[B] 只能增長或不變,而不會下降,即不會從 1 變?yōu)?0。這些可能增長的狀態(tài)(從 0 變?yōu)?1)在之后的迭代中會流向 IN[B] 并生成新的 OUT[B] (這里忽略掉控制流處理,因?yàn)樗膊荒軐?1 變?yōu)?0)。這個(gè)新的 OUT[B] 因?yàn)?genB 和 killB 始終是不變的,而它又可能保留有更多的狀態(tài),所以它比之前會包含更多的 1 。而程序之中的賦值語句數(shù)量是有限的,那么最多當(dāng) OUT[B] 增長為滿集(全為1)時(shí),程序的 OUT 集就不再發(fā)生變化了,那么算法就會停止。當(dāng)算法的所有 OUT 集不發(fā)生變化時(shí),稱這個(gè)狀態(tài)為該算法的不動(dòng)點(diǎn)(fixed point)。

2,Live Variables Analysis

概述

??????RDA是對賦值語句的可達(dá)性進(jìn)行判定,應(yīng)用于死代碼消除中的判斷某個(gè)變量在程序點(diǎn)是否被使用便是LVA的工作,這兩者結(jié)合起來便構(gòu)成了死代碼消除。

??????LVA :Live variables analysis tells whether the value of variable v at program point p could be used along some path in CFG starting at p. If so, v is live at p; otherwise, v is dead at p. 在程序點(diǎn) p 處,一個(gè)變量 v 的值如果被 CFG 中在 p 之后直到程序結(jié)束的任何一條路徑上被使用,則認(rèn)為 v 在 p 處是存活的,否則為死亡的。

??????注意:這里指的是在程序點(diǎn) p 處變量 v 的值會不會在之后被使用,如果變量在程序點(diǎn)之后直到程序結(jié)束的某一條路徑上,先是被重新賦值,然后再被使用,那么顯而易見,在 p 處變量 v 是死亡的

??????LVA 在每一個(gè)程序點(diǎn)處判斷程序中所有變量的存活性,可以看出,它也屬于 may analysis ,因?yàn)樵谀硞€(gè)程序點(diǎn)之后,只要存在一條路徑上某個(gè)變量是存活的,就認(rèn)為該變量存活,但是在程序中別的路徑上該變量可能是死亡的,所以并不能確定該變量是100%存活的,這取決于程序執(zhí)行時(shí)走的哪條路徑。may analysis 采用的是過近似,即哪怕有99條路徑上變量 v 都是存活的,但是有一條路徑上沒有,那這一條路徑也是需要考慮到的,因?yàn)槌绦驁?zhí)行時(shí)是有可能走這條路徑的,過近似的特點(diǎn)就是不放過任何一個(gè)程序執(zhí)行時(shí)可能的行為(不放過任何一條路徑),所以它得到的結(jié)果有可能是真的。

用途

??????LVA 可用于寄存器分配上。當(dāng)所有寄存器上都存在數(shù)據(jù)時(shí),而我們又需要使用一個(gè)寄存器,就可以采用 LVA 淘汰掉一個(gè)寄存器,因?yàn)檫@個(gè)寄存器中的數(shù)據(jù)值一直到程序結(jié)束時(shí)都不會被使用。

分析流程

??????對于 RDA ,它是判斷在程序點(diǎn) p 處的賦值語句在之后的程序點(diǎn)上的可達(dá)性,是依據(jù)于當(dāng)前的情況去判斷之后程序點(diǎn)上的狀態(tài),采用的是前向分析;而 LVA 是根據(jù)在 p 處之后的路徑上判斷在 p 處的變量是否被使用,從而判斷在 p 處變量的存活性,就是說:它是從后往前分析的,通過 p 后面的情況得到 p 處的結(jié)果。

??????并且可以可發(fā)現(xiàn):所以對于 LVA ,在程序的最后一條語句之后,所有變量在此處都是死亡的,因?yàn)楹竺娌粫姓Z句執(zhí)行了,也就不存在變量被使用了;而在程序的第一條語句之前,我們無法判斷在此處變量的存活性,所以我們采用后向分析

前向分析與后向分析

??????對于如下代碼:

a = 1; b = 2; c = a + 8; b = 9; d = b + c;

??????通過前向分析,在第二條語句執(zhí)行之后:在 RDA 中,我們可以輕易得到,賦值語句 a =1 和 b = 2 在此處是可達(dá)的。而在 LVA 中,因?yàn)闆]有執(zhí)行后面的三行代碼,我們并不清楚在此處所有變量的存活性,程序必須走完最后一行才可以判斷,所以需要采用后向分析。

1,抽象

??????抽象:因?yàn)槲覀冴P(guān)心的是程序中所有變量在所有程序點(diǎn)的存活性,那么就需要對這些變量進(jìn)行抽象。這里采用位向量來表示。類似的:假設(shè)程序中有變量100個(gè),那么需要有100個(gè)比特位來表示,第一位表示第一個(gè)變量是否存活,若存活置為1,死亡置為0。那么在最后一個(gè)程序點(diǎn)(程序的最后一條語句之后)處,置這100個(gè)比特位均為0,表示均不存活。

2,轉(zhuǎn)換函數(shù)

??????轉(zhuǎn)換函數(shù):在后向分析中的轉(zhuǎn)換函數(shù)是計(jì)算如何從輸出狀態(tài)得到輸入狀態(tài)。

??????要判斷一個(gè)變量在程序點(diǎn) p 處的存活性,首先需要判斷之后的基本塊中該變量是否被使用,其次需要注意的是只有在重新賦值語句之前被使用才表示在 p 處存活,我們來分析一下可能存在的語句情況:

??????假設(shè)存在有三個(gè)基本塊,其中基本塊 P 是 B 的前驅(qū),基本塊 S1 是 B 后繼。變量 v 在 P 中被賦值/初始化,S1 是程序中最后一個(gè)基本塊(除過 Exit),在 S1 中變量 v 被使用。下面需要針對 B 中可能存在的情況對 IN[B] 處變量 v 的存活性進(jìn)行討論:
若:
??????B中語句為:k = n ;??????按照定義,在 IN[B] 處變量 v 存活。
??????B中語句為:k = v ;??????按照定義,在 IN[B] 處變量 v 存活。
??????B中語句為:v = 2 ;??????因?yàn)橹暗?v 還沒有被使用,就對 v 重新賦值,所以在 IN[B] 處變量 v 死亡。
??????B中語句為:v = v - 1 ;??????因?yàn)橄葓?zhí)行等式右邊的表達(dá)式再對 v 重新賦值,即使用在賦值之前,故在 IN[B] 處變量 v 存活。
??????B中語句為:v = 2 ; k = v ;??????重新賦值在使用之前,故在 IN[B] 處變量 v 死亡。
??????B中語句為:k = v ; v = 2 ;??????和上面剛好相反,使用在重新賦值之前,故在 IN[B] 處變量 v 存活。

??????得出轉(zhuǎn)換函數(shù)為:IN[B] = useB U (OUT[B] - redefB)

??????U 表示或操作。只要存在 redefinition 就要減去,之后再加上 “used before redefinition” 的情況(通過 U 操作)。OUT[B] 表示沒有被重新賦值的其他變量的狀態(tài)。

3,控制流處理

??????控制流處理:在有分支的情況下,假設(shè)基本塊 B 的兩個(gè)后繼為 S1 和 S2。現(xiàn)在討論OUT[B],如果IN[S1]中的某些變量是存活的,而在IN[S2]中的這些變量是死亡的,根據(jù) RDA 的定義,只要在 B 之后有一條路徑上某個(gè)變量是存活的,就認(rèn)為它是存活的。所以應(yīng)該采用或操作,1 或 0 = 1。

??????控制流處理用公式表示為:OUT[B] = U IN[S](S is a successor of B )

??????關(guān)于轉(zhuǎn)換函數(shù)和控制流處理也可以參考下圖:其中 defB 和上面的 redefB 意思相同。

4,算法實(shí)現(xiàn)

??????在抽象、轉(zhuǎn)換函數(shù)和控制流處理之后,關(guān)于 LVA 的算法如下圖:


??????這個(gè)算法也是一個(gè)迭代算法,算法的輸入是 CFG ,輸出是判斷每一個(gè)程序點(diǎn)(這里以基本塊為單位)處所有變量是否存活。

1,初始化

??????初始化語句第一步,令 exit 的輸出狀態(tài)為空,這個(gè)之前講過,需要從語義上來理解:因?yàn)榇颂幹鬀]有任何語句,所以在這里所有變量均是死亡的。

??????初始化語句第二步,令除了 exit 之外的其他基本塊的輸出狀態(tài)也為空,為空的原因后面會講到,總之 may analysis 通常都會初始化為空集,用符號⊥來表示,稱為 bottom。而 must analysis 剛好相反,常被初始化為滿集,用符號 T 來表示,稱為 top。

??????while 循環(huán)的判定條件為任何一個(gè)基本塊的 IN 集合發(fā)生改變時(shí),循環(huán)主體是對除了 exit 塊的其余基本塊做:控制流處理和轉(zhuǎn)換函數(shù)的實(shí)現(xiàn)。我們先通過一個(gè)例子熟悉這個(gè)算法,見下圖:一共有7個(gè)變量,5個(gè)基本塊,緊接著會對算法執(zhí)行流程做說明。

??????初始化:初始化的結(jié)果如上圖的黑色字體來表示,按照算法描述,所有的 IN 均初始化為 000 0000。

2,第一輪迭代

??????第一輪迭代:執(zhí)行循環(huán)體,用紅色字體來表示執(zhí)行結(jié)果,如上圖顯示的是 OUT[B5] = IN[exit] = 000 0000
后向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:IN[B5] = 000 1000 U(000 0000 - 001 0000)= 000 1000。這里的減法運(yùn)算為:1-1=0、1-0=1、0-1=0、0-0=0。

OUT[B3] = IN[B5] = 000 1000;
IN[B3] = 100 0000 U (000 1000 - 100 0000)= 100 1000

OUT[B4] = IN[B5] U IN[B2] = 000 1000 U 000 0000 = 000 1000;
IN[B4] = 010 0000 U (000 1000 - 100 0100)= 010 1000

OUT[B2] = IN[B3] U IN[B4] = 100 1000 U 010 1000 = 110 1000;
IN[B2] = 000 0001 U (110 1000 - 010 0010)= 100 1001

OUT[B1] = OUT[B4] = IN[B2] = 100 1001
IN[B1] = 001 1100 U (100 1001 - 110 0000)= 001 1101

??????根據(jù)算法的循環(huán)判定條件,存在有基本塊的 IN 發(fā)生了變化(事實(shí)上所有基本塊的 IN 都發(fā)生了變化,不再是初始的 000 0000了),那么將進(jìn)入第二輪迭代。第一輪迭代執(zhí)行完畢的結(jié)果如下圖:

3,第二輪迭代

??????第二輪迭代:在上圖第一輪的執(zhí)行結(jié)果上進(jìn)行,OUT[B5] 保持不變, OUT[B5] = IN[exit] = 000 0000。后向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:IN[B5] = 000 1000 U(000 0000 - 001 0000)= 000 1000

OUT[B3] = IN[B5] = 000 1000;
IN[B3] = 100 0000 U (000 1000 - 100 0000)= 100 1000

OUT[B4] = IN[B5] U IN[B2] = 000 1000 U 100 1001 = 100 1001;
IN[B4] = 010 0000 U (100 1001 - 100 0100)= 010 1001

OUT[B2] = IN[B3] U IN[B4] = 100 1000 U 010 1001 = 110 1001;
IN[B2] = 000 0001 U (110 1001 - 010 0010)= 100 1001

OUT[B1] = OUT[B4] = IN[B2] = 100 1001
IN[B1] = 001 1100 U (100 1001 - 110 0000)= 001 1101

??????根據(jù)算法的循環(huán)判定條件,存在有基本塊的 IN 發(fā)生了變化(B4),那么將進(jìn)入第三輪迭代。第二輪迭代執(zhí)行完畢的結(jié)果如下圖:

4,第三輪迭代

??????第三輪迭代:在上圖第二輪的執(zhí)行結(jié)果上進(jìn)行,OUT[B5] 保持不變, OUT[B5] = IN[exit] = 000 0000。后向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:IN[B5] = 000 1000 U(000 0000 - 001 0000)= 000 1000

OUT[B3] = IN[B5] = 000 1000;
IN[B3] = 100 0000 U (000 1000 - 100 0000)= 100 1000

OUT[B4] = IN[B5] U IN[B2] = 000 1000 U 100 1001 = 100 1001;
IN[B4] = 010 0000 U (100 1001 - 100 0100)= 010 1001

OUT[B2] = IN[B3] U IN[B4] = 100 1000 U 010 1001= 110 1001;
IN[B2] = 000 0001 U (110 1001 - 010 0010)= 100 1001

OUT[B1] = OUT[B4] = IN[B2] = 100 1001
IN[B1] = 001 1100 U (100 1001 - 110 0000)= 001 1101

??????根據(jù)算法的循環(huán)判定條件,所有基本塊的 IN 都沒有發(fā)生變化,迭代停止,算法執(zhí)行完畢。第三輪迭代執(zhí)行完畢的結(jié)果如下圖:

??????此時(shí)那些綠色字體表示的就是算法的最終結(jié)果,我們在每一個(gè)程序點(diǎn)處得到了所有變量的存活狀態(tài)。

3,Available Expressions Analysis

概述

??????AEA :An expression x op y is available at program point p if (1) all paths from the entry to p must pass through the evaluation of x op y, and (2) after the last evaluation of x op y, there is no redefinition of x or y 。在程序點(diǎn) p 處,一個(gè)表達(dá)式 x op y (IR的值 )是否有效取決于:(1)所有從 entry 到 p 處的路徑都必須執(zhí)行 x op y 表達(dá)式。(2)在每一條路徑最后一次執(zhí)行 x op y 后,都不能重新對 x 或者 y 賦值。

??????AEA 在每一個(gè)程序點(diǎn)處判斷程序中所有表達(dá)式的有效性,可以看出,它屬于 must analysis ,因?yàn)閺?entry 到 p 處的路徑都必須執(zhí)行 x op y 表達(dá)式,并且都不能重新對 x 或者 y 賦值,must analysis 采用的是 under-appro,它要求所有路徑上的行為都必須符合要求,哪怕有一條路徑不符合要求也不行,相對的是 may analysis ,它要求只要有一條路徑符合要求就可以了。從這里能夠看出,may analysis 在控制流處理時(shí)一般取或操作(1 op 0 = 1),而 must analysis 應(yīng)該取與操作(1 op 0 = 0)。所以 must analysis 得到的結(jié)果必然是真的,缺點(diǎn)是可能存在有漏報(bào)。

用途

??????用作優(yōu)化:在程序點(diǎn) p 處,可以用 p 之前的某一條路徑上最后一次執(zhí)行 x op y 的結(jié)果來代替表達(dá)式 x op y ,這樣就不需要在 p 處重新計(jì)算表達(dá)式 x op y 的值了 。(類似于 C 中的 #define ??x op y ? number) 下面這個(gè)示例形象地說明了 AEA 的用途,建議閱讀完分析流程的前三小節(jié)之后食用。

??????圖片的左邊表示在最后一條語句之前表達(dá)式 e16 * x 是有效的。這個(gè)是由 AEA 的定義得出的結(jié)論,雖然 a 的值與 b 的值不相等,但是不妨礙做右側(cè)的編譯優(yōu)化:這個(gè)優(yōu)化是在表達(dá)式 e16 * x 有效的程序點(diǎn)處,將該表達(dá)式統(tǒng)一用一個(gè)臨時(shí)變量 t 做替換,不再保留原來的變量 a、b、c ,當(dāng)程序執(zhí)行時(shí),如果走左邊的路徑,原來 c 的值等于 b 的值,如果走右邊的路徑,原來 c 的值等于 a 的值。也就不要求 a 的值等于 b 的值啦。

分析流程

??????對于 AEA ,它是判斷從 entry 開始到當(dāng)前程序點(diǎn)之間所有表達(dá)式的在當(dāng)前程序點(diǎn)的有效性,應(yīng)該采用前向分析

??????并且可以發(fā)現(xiàn):對于 AEA ,在程序的第一條語句之前,沒有任何表達(dá)式被執(zhí)行,所以在此處所有表達(dá)式都不是有效的;而在程序的最后一條語句之后,我們無法判斷在此處表達(dá)式的有效性,所以我們采用前向分析。

1,抽象

??????抽象:因?yàn)槲覀冴P(guān)心的是程序中所有表達(dá)式在所有程序點(diǎn)的有效性,那么就需要對這些表達(dá)式進(jìn)行抽象。這里采用位向量來表示。類似的:假設(shè)程序中有表達(dá)式100個(gè),那么需要有100個(gè)比特位來表示,第一位表示第一個(gè)表達(dá)式是否有效,若有效置為1,否則置為0。那么在第一個(gè)程序點(diǎn)(程序的第一條語句之前)處,置這100個(gè)比特位均為0,表示均不有效。

2,轉(zhuǎn)換函數(shù)

??????轉(zhuǎn)換函數(shù):在前向分析中的轉(zhuǎn)換函數(shù)是計(jì)算如何從輸入狀態(tài)得到輸出狀態(tài),我們以一條語句來進(jìn)行分析。

??????假設(shè)存在一條語句 D:a = x op y ,這一條語句使將表達(dá)式 x op y 的結(jié)果賦給 a。所以得出:在語句 D 執(zhí)行之后的程序點(diǎn)處,新的表達(dá)式 x op y 肯定是有效的,而所有含有 a 的表達(dá)式在此時(shí)均不是有效的,因?yàn)?a 在此處被重新賦值了。。 新的表達(dá)式 x op y 的比特位在此設(shè)置為 1,其余和 a 相關(guān)的表達(dá)式全設(shè)置為 0.

??????轉(zhuǎn)換函數(shù)用公式表示為:OUT[B] = genB U (IN[B] - killB) ??????U表示或操作。

??????B表示一個(gè)基本塊,genB 表示符合要求的有效表達(dá)式,而 killB 表示與被重新賦值的變量相關(guān)的表達(dá)式。公式對于每一條語句也是一樣適用的

3,控制流處理

??????控制流處理:在有分支的情況下,假設(shè)基本塊 B 的兩個(gè)前驅(qū)為 P1 和 P2。現(xiàn)在討論 IN[B] ,如果 OUT[P1] 中的某些表達(dá)式是有效的,而在 OUT[P2] 中的這些表達(dá)式不是有效的,根據(jù) AEA 的定義 “必須保證每一條路徑都是有效的”,認(rèn)為 IN [B] 不是有效的。所以應(yīng)該采用與操作,1 與 0 = 0。

??????控制流處理用公式表示為:IN[B] = OUT[P](P is a predecessor of B )

must analysis 可能會產(chǎn)生漏報(bào)的示例:


??????上圖左側(cè)得到在最后一條語句之前該表達(dá)式不是有效的無可厚非,那如果恰好是右側(cè)的那一種情況呢?雖然它實(shí)際上是有效的,但是數(shù)據(jù)流分析認(rèn)為它不是有效的,這便是產(chǎn)生了漏報(bào)。

4,算法實(shí)現(xiàn)

??????在抽象、轉(zhuǎn)換函數(shù)和控制流處理之后,關(guān)于 AEA 的算法如下圖:

??????這個(gè)算法是一個(gè)迭代算法,算法的輸入是 CFG ,輸出是判斷每一個(gè)程序點(diǎn)(這里以基本塊為單位)處所有表達(dá)式是否有效。

1,初始化

??????初始化語句第一步,令 entry 的輸出狀態(tài)為空,這個(gè)之前講過,需要從語義上來理解:因?yàn)榇颂幹皼]有任何語句,所以在這里所有表達(dá)式均不是有效的。

??????初始化語句第二步,令除了 entry 之外的其他基本塊的輸出狀態(tài)也為滿,為滿的原因后面會講到,總之 may analysis 通常都會初始化為空集,用符號⊥來表示,稱為 bottom。而 must analysis 剛好相反,常被初始化為滿集,用符號 T 來表示,稱為 top。

?????? 在這里多講一句,前兩個(gè)例子中 1 op 0 = 1,所以不難看出總體上是從 0 → 1進(jìn)行的;而 AEA 是 must analysis,1 op 0 = 0,總體上是從 1 → 0 進(jìn)行的,所以需要將所有的 OUT 初始化為滿集。也可以理解為 may analysis 是單調(diào)遞增的,而 must analysis 是單調(diào)遞減的。而它的算法停止條件和 may analysis是類似的,因?yàn)閙ust 是遞減的,所以最多減小到全為 0 的時(shí)候這個(gè)算法就停止。

??????while 循環(huán)的判定條件為任何一個(gè)基本塊的 OUT 集合發(fā)生改變時(shí),循環(huán)主體是對除了 entry 塊的其余基本塊做:控制流處理和轉(zhuǎn)換函數(shù)的實(shí)現(xiàn)。我們先通過一個(gè)例子熟悉這個(gè)迭代算法,見下圖:一共有5個(gè)表達(dá)式,5個(gè)基本塊,緊接著會對算法執(zhí)行流程做說明。

??????初始化:初始化的結(jié)果如上圖的黑色字體來表示,按照算法描述,entry 的 OUT 初始化為 00000,其余的 OUT 初始化為 11111。

2,第一輪迭代

??????第一輪迭代:執(zhí)行循環(huán)體,用紅色字體來表示執(zhí)行結(jié)果,如上圖顯示的是 IN[B1] = OUT[entry] = 00000
前向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:OUT[B1] = 10000 U (00000 - 00101)= 10000。這里的減法運(yùn)算為:1-1=0、1-0=1、0-1=0、0-0=0。

IN[B2] = OUT[B4] ∩ OUT[B1] = 11111 ∩ 10000 = 10000;
OUT[B2] = 01010 U (10000 - 10000)= 01010

IN[B3] = OUT[B2];
OUT[B3] = 00001 U (01010 - 01000)= 00011

IN[B4] = OUT[B2];
OUT[B4] = 00110 U (01010 - 00010)= 01110

IN[B5] = OUT[B4] ∩ OUT[B3] = 01110 ∩ 00011 = 00010;
OUT[B5] = 01010 U (00010 - 00101)= 01010

??????根據(jù)算法的循環(huán)判定條件,存在有基本塊的 OUT 發(fā)生了變化(事實(shí)上所有基本塊的 OUT 都發(fā)生了變化,不再是初始的 11111了),那么將進(jìn)入第二輪迭代。第一輪迭代執(zhí)行完畢的結(jié)果如下圖:

3,第二輪迭代

??????第二輪迭代:在上圖第一輪的執(zhí)行結(jié)果上進(jìn)行,IN[B1]保持不變,IN[B1] = OUT[entry] = 00000
前向分析繼續(xù)往下走,按照轉(zhuǎn)換函數(shù)計(jì)算出:OUT[B1] = 10000 U (00000 - 00101)= 10000

IN[B2] = OUT[B4] ∩ OUT[B1] = 01110∩ 10000 = 00000;
OUT[B2] = 01010 U (00000 - 10000)= 01010

IN[B3] = OUT[B2];
OUT[B3] = 00001 U (01010 - 01000)= 00011

IN[B4] = OUT[B2];
OUT[B4] = 00110 U (01010 - 00010)= 01110

IN[B5] = OUT[B4] ∩ OUT[B3] = 01110 ∩ 00011 = 00010;
OUT[B5] = 01010 U (00010 - 00101)= 01010

??????根據(jù)算法的循環(huán)判定條件,此時(shí)沒有基本塊的 OUT 發(fā)生了變化,迭代停止,算法執(zhí)行完畢。第二輪迭代執(zhí)行完畢的結(jié)果如下圖:

??????此時(shí)那些藍(lán)色字體表示的就是算法的最終結(jié)果,我們在每一個(gè)程序點(diǎn)處得到了所有表達(dá)式的有效性。

總結(jié)

??????本文首先講述了數(shù)據(jù)流分析的基本方法,并通過三個(gè)經(jīng)典的示例來闡述了如何對一個(gè)具體地問題采用數(shù)據(jù)流分析。在這三個(gè)示例中,我詳細(xì)介紹了實(shí)現(xiàn)數(shù)據(jù)流分析的具體細(xì)節(jié),比如:抽象(根據(jù)問題來選擇被抽象的對象),轉(zhuǎn)換函數(shù)(一般通過一個(gè)語句/基本塊得到其一般形式),控制流處理(通過問題來確定采用 與 or 或)。關(guān)于采用前向分析還是后向分析的原因,應(yīng)該采用 may 還是 must 的原因,在邊界處(entry 和 exit)的初始化值和別的初始化語句應(yīng)該為空還是滿的原因在文中也多次提到,不再贅述。

??????簡單在聊一下對一個(gè)問題做數(shù)據(jù)流分析的流程:

??????首先對問題進(jìn)行分析,分析之后能夠得到 如何抽象采用前向還是后向采用 may 還是 must在邊界處的初始化值,然后在確定了采用 may 或 must 之后,就可以得到 除邊界外的初始化語句值控制流處理采用 與 or 或。而轉(zhuǎn)換函數(shù)是需要另外對具體的語句/基本塊來分析得到的。

??????三個(gè)應(yīng)用的差異性比較見下圖:

??????后面會繼續(xù)介紹靜態(tài)程序分析的理論基礎(chǔ)-格理論。未完待續(xù)~

??????行文倉促,文章較長,若存在筆誤,抱歉!

總結(jié)

以上是生活随笔為你收集整理的静态程序分析chapter3 - 数据流分析详述(Reaching Definitions、Live Variables、Available Expressions Analysis)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。