【LLVM】AliasAnalysis別名分析的介紹與使用


一、介紹

Alias Analysis (又名 Pointer Analysis)是用于確定兩個指針是否指向內(nèi)存中的同一對象,這里有很多不同的別名分析算法决采,分為幾種類型:流敏感vs流非敏感脱羡、上下文敏感vs上下文非敏感罚渐、域敏感vs域非敏感捏膨、基于一致性的vs基于子集的秧均。傳統(tǒng)的別名分析用于回答must、may脊奋、no的問題熬北,也即兩個指針總是指向同一對象疙描,可能指向同一對象以及絕不會指向同一對象诚隙。(SSA—靜態(tài)單一賦值,將同一變量名用多個名表示起胰,被賦值的變量名不會重復久又,便于尋找變量的產(chǎn)生與使用點)。

LLVM AliasAnalysis類是實現(xiàn)別名分析的基礎(chǔ)類效五,能夠提供簡單的別名分析信息地消,且能提供Mod/Ref信息,有利于進行更復雜的分析畏妖。本文介紹了該接口的實現(xiàn)與使用脉执。

首先,我們來了解一下別名分析戒劫,以及別名分析該如何使用半夷。

1.別名分析的作用

例如以下c代碼:

    int foo (int __attribute__((address_space(0)))* a,
             int __attribute__((address_space(1)))* b) {
        *a = 42;
        *b = 20;
        return *a;
    }

轉(zhuǎn)換成llvm如下:

    define i32 @foo(i32 addrspace(0)* %a, i32 addrspace(1)* %b) #0 {
    entry:
      store i32 42, i32 addrspace(0)* %a, align 4
      store i32 20, i32 addrspace(1)* %b, align 4
      %0 = load i32, i32* %a, align 4
      ret i32 %0
    }

現(xiàn)在需要對foo進行優(yōu)化婆廊,去掉不必要的load:

    define i32 @foo(i32 addrspace(0)* %a, i32 addrspace(1)* %b) #0 {
    entry:
      store i32 42, i32 addrspace(0)* %a, align 4
      store i32 20, i32 addrspace(1)* %b, align 4
      ret i32 42
    }

但是這個優(yōu)化的前提是,a和b不能別名巫橄,否則會導致錯誤如下:

    int i = 0;
    int result = foo(&i, &i);

以上可以看到淘邻,以上調(diào)用會使a和b別名,本應該返回20湘换,結(jié)果因為優(yōu)化的緣故返回了42宾舅,導致錯誤。所以編譯器只有確定兩個指針不會產(chǎn)生別名時彩倚,才能進行以上優(yōu)化筹我。

2.使用方法

一種實現(xiàn)是利用 llvm::AAResultBase,如果我們的目標是TAR帆离,則可以創(chuàng)建一個從AAResultBase<TARAAResult>繼承的類TARAAResult:

    class TARAAResult : public AAResultBase<TARAAResult> {
    public:
      explicit TARAAResult() : AAResultBase() {}
      TARAAResult(TARAAResult &&Arg) : AAResultBase(std::move(Arg)) {}
    
      AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
    };

alias函數(shù)的輸入是兩個MemoryLocation崎溃,返回AliasResult。返回結(jié)果顯示內(nèi)存對象絕不別名盯质、可能別名袁串、部分別名或正好別名。

    AliasResult TARAAResult::alias(const MemoryLocation &LocA,
                                   const MemoryLocation &LocB) {
      auto AsA = LocA.Ptr->getType()->getPointerAddressSpace();
      auto AsB = LocB.Ptr->getType()->getPointerAddressSpace();
    
      if (AsA != AsB) {
        return NoAlias;
      }
    
      // Forward the query to the next analysis.
      return AAResultBase::alias(LocA, LocB);
    }

二呼巷、AliasAnalysis類總覽

AliasAnalysis定義了別名分析必須支持的接口囱修,并且導出了兩個重要方法,AliasResult和ModRefResult輸出別名結(jié)果和mod/ref結(jié)果王悍。

AliasAnalysis接口能夠用不同的方式輸出內(nèi)存信息破镰,例如,內(nèi)存對象表示成開始地址和size压储,函數(shù)調(diào)用表示成實際的call和invoke指令鲜漩。AliasAnalysis接口也提供了helper方法,允許你獲取任意指令的mod/ref信息集惋。

1.指針表示

AliasAnalysis類提供了不同的方法孕似,來query兩個內(nèi)存對象是否別名,以及函數(shù)調(diào)用是否可以修改或讀內(nèi)存對象刮刑。對于所有query喉祭,內(nèi)存對象表示為開始地址(符號化的LLVM值)+size。

內(nèi)存對象的表示對于正確的別名分析至關(guān)重要雷绢,例如以下c代碼:

    int i;
    char C[2];
    char A[10];
    /* ... */
    for (i = 0; i != 10; ++i) {
      C[0] = A[i];          /* One byte store */
      C[1] = A[9-i];        /* One byte store */
    }

對于以上代碼泛烙,basicaa pass將消除對C[0]和C[1]的store,因為他們都是訪問不同地址的單個字節(jié)翘紊,互不干擾蔽氨,Loop Invariant Code Motion (LICM) pass會使用store motion移除循環(huán)中的store。

    int i;
    char C[2];
    char A[10];
    /* ... */
    for (i = 0; i != 10; ++i) {
      ((short*)C)[0] = A[i];  /* Two byte store! */
      C[1] = A[9-i];          /* One byte store */
    }

相反,對于以上代碼鹉究,兩個對C的store會分開中捆,因為訪問&C[0]元素是2個字節(jié)訪問;如果query中沒有size信息坊饶,第一個案例也會別名泄伪。

2.alias方法

alias方法用于確定兩個內(nèi)存對象是否別名,它輸入兩個內(nèi)存對象匿级,輸出MustAlias, PartialAlias, MayAlias, 或 NoAlias蟋滴。對于所有AliasAnalysis接口,alias方法要求兩個指針值在同一個函數(shù)中定義痘绎,或者至少1個值是常數(shù)津函。

NoAlias表示兩個內(nèi)存對象沒有任何重疊區(qū)域;MayAlias表示兩個指針可能指向同一對象孤页;PartialAlias表示兩個內(nèi)存對象可能有重疊尔苦;MustAlias表示兩個內(nèi)存對象總是從同一位置開始。

3.GetModRefInfo方法

GetModRefInfo方法返回信息是行施,指令是否可以讀或修改某個內(nèi)存區(qū)域允坚。Mod/Ref信息是保守的,如果一條指令可能讀或?qū)懩硡^(qū)域蛾号,就返回ModRef稠项。

4.其他AliasAnalysis方法

(1)pointsToConstantMemory方法

若能確定指針僅指向不變的內(nèi)存區(qū)域(函數(shù),全局常量鲜结,null指針)則返回true展运,該信息可以優(yōu)化mod/ref信息:因為不變的內(nèi)存區(qū)域是不能被修改的。

(2)doesNotAccessMemory和onlyReadsMemory方法

若確定函數(shù)從不讀寫內(nèi)存精刷,或者函數(shù)僅從常量內(nèi)存讀拗胜,則doesNotAccessMemory返回true。

若確定函數(shù)僅從非易失性內(nèi)存讀怒允,則onlyReadsMemory返回true埂软。注意,滿足doesNotAccessMemory方法的所有函數(shù)也都滿足onlyReadsMemory误算。


三仰美、實現(xiàn)新的AliasAnalysis

1.不同的Pass類型

選擇使用哪種LLVM pass來做別名分析取決于你想要解決哪種問題。

  • 做過程間分析儿礼,用Pass
  • 做局部函數(shù)的分析,用FunctionPass子類
  • 若不需要看程序庆寺,則選擇ImmutablePass

除了繼承以上pass蚊夫,你也需要繼承AliasAnalysis接口,當然懦尝,也可以用RegisterAnalysisGroup模板去注冊AliasAnalysis實現(xiàn)知纷。

2.進行初始化所需的調(diào)用

所寫的AliasAnalysis的子類需調(diào)用AliasAnalysis基類的兩個方法:getAnalysisUsage和InitializeAliasAnalysis壤圃。例如,實現(xiàn)你的getAnalysisUsage時琅轧,除了聲明pass依賴伍绳,還需顯式調(diào)用AliasAnalysis::getAnalysisUsage方法。

    void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      // declare your dependencies here.
    }

另外乍桂,在你的run方法中需調(diào)用InitializeAliasAnalysis方法(Pass—run冲杀;FunctionPass—runOnFunction;ImmutablePass—InitializePass)睹酌。

    bool run(Module &M) {
      InitializeAliasAnalysis(this);
      // Perform analysis here...
      return false;
    }
3.需要覆蓋的方法

在你的AliasAnalysis子類中必須覆蓋getAdjustedAnalysisPointer方法权谁,例如:

    void *getAdjustedAnalysisPointer(const void* ID) override {
      if (ID == &AliasAnalysis::ID)
        return (AliasAnalysis*)this;
      return this;
    }
4.可指定的接口

所有AliasAnalysis虛方法都默認為其他別名分析提供一個鏈接,最終能返回正確結(jié)果(為alias query和mod/ref query返回May和Mod/Ref)憋沿,根據(jù)你分析的功能旺芽,覆蓋相應的接口即可。

5.AliasAnalysis鏈接行為

除了-no-aa pass辐啄,每個分析pass都鏈接到另一個別名分析的實現(xiàn)(例如采章,可以使用"-basicaa -ds-aa -licm"來從多個別名分析達到最大優(yōu)化)。別名分析會自動處理你未覆蓋的方法壶辜,對于已覆蓋的方法共缕,若需返回AmayAlias或Mod/Ref結(jié)果,只需返回超類計算的結(jié)果士复。

    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size) {
      if (...)
        return NoAlias;
      ...
    
      // Couldn't determine a must or no-alias result.
      return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
    }

除了分析查詢图谷,如果你需要覆蓋某方法,需將更新通知傳給超類阱洪,這樣就允許所有別名分析進行更新便贵。

6.更新代碼轉(zhuǎn)換后的分析結(jié)果

別名分析最初用于建立程序的靜態(tài)快照,但用戶也用于進行代碼轉(zhuǎn)換冗荸。所有別名分析都需要更新分析結(jié)果承璃,以反映代碼轉(zhuǎn)換所做的變換。AliasAnalysis接口提供了4個方法來更新程序變化后的分析結(jié)果蚌本。

(1)deleteValue方法

當從程序刪除某個指令或值(包括不使用指針的值)時調(diào)用deleteValue方法盔粹。通常,別名分析會保留數(shù)據(jù)結(jié)構(gòu)程癌,這些數(shù)據(jù)結(jié)構(gòu)包含程序中每個值的條目舷嗡。調(diào)用此方法時,則刪除指定值的任何條目(如果存在)嵌莉。

(2)copyValue方法

當程序引入新的值時調(diào)用copyValue方法进萄。通常不會引入程序中不存在的值(編譯器安全轉(zhuǎn)換),所以這是引入新值的唯一方法,這個方法指示新值和拷貝值有相同的屬性中鼠。

(3)replaceWithNewValue方法

用新值替換舊值可婶,該方法不能被別名分析實現(xiàn)所覆蓋。

(4)addEscapingUse方法

當指針的使用導致之前計算的分析結(jié)果無效時援雇,調(diào)用addEscapingUse方法矛渴。該方法會提供保守的返回,或者重新計算分析結(jié)果惫搏。

總之具温,只要有新的指針使用,就需要調(diào)用該方法晶府,除了一下3種情況:

  • 指針的bitcast或getelementptr
  • 通過指針來store桂躏,但并非存指針
  • 通過指針load

四、使用別名分析結(jié)果

1.使用MemoryDependenceAnalysis Pass

memdep pass使用別名分析來提供內(nèi)存使用指令的高級依賴信息川陆,例如剂习,告訴你哪個store提供給了load。它也使用緩存等技術(shù)提高效率较沪,一般用于Dead Store Elimination, GVN 和 memcpy優(yōu)化鳞绕。

2.使用AliasSetTracker類

有些代碼轉(zhuǎn)換需要某個代碼區(qū)域內(nèi)的活躍的別名集,而不是成對的別名信息尸曼。AliasSetTracker類可以根據(jù)AliasAnalysis接口提供的成對的別名分析信息们何,高效的構(gòu)建所需的別名集。

首先需要調(diào)用add方法對AliasSetTracker進行初始化控轿,添加該代碼區(qū)域內(nèi)可能導致別名的指令冤竹。當別名集構(gòu)建完成后,你可以利用AliasSetTrackerbegin() / end()方法迭代訪問該別名集茬射。

AliasSetTracker構(gòu)造的AliasSets是不相交的鹦蠕,計算mod/ref信息,并跟蹤記錄該集合所有指針是否是Must aliases在抛。

例如钟病,Loop Invariant Code Motion pass使用AliasSetTracker來計算每個循環(huán)嵌套的別名集,如果循環(huán)的某個AliasSet沒有被修改刚梭,則該集合所有的load指令可能被提出循環(huán)肠阱。如果所有別名集是store to 和must alias集,則store 在循環(huán)外部使用朴读,這樣在循環(huán)時將內(nèi)存位置放入進村器屹徘。只有當指針參數(shù)是循環(huán)不變的,才采用這些轉(zhuǎn)換磨德。

3.直接使用AliasAnalysis接口

如果這些功能類都用不到缘回,你可以直接使用AliasAnalysis類吆视。盡量使用高級方法典挑,以獲取更高的準確率和效率酥宴。


五、現(xiàn)有的別名分析實現(xiàn)

1.可用的AliasAnalysis實現(xiàn)

(1)-no-aa pass

不做別名分析您觉。

(2)-basicaa pass

(3)-globalsmodref-aa pass

(4)-steens-aa pass

(5)-ds-aa pass

(6)-scev-aa pass

注意:basicaa和steens-aa這類標準的LLVM pass太耗時了拙寡,Anderson Analysis也很耗時耗內(nèi)存,已經(jīng)有一些工作在優(yōu)化別名分析琳水。

2.別名分析驅(qū)動的轉(zhuǎn)換

(1)-adce pass

(2)-licm pass

(3)-argpromotion pass

(4)-gvn -memcpyopt -dse pass

3.用于調(diào)試和評估的client

命令:% opt -ds-aa -aa-eval foo.bc -disable-output -stats

(1)-print-alias-sets pass

% opt -ds-aa -print-alias-sets -disable-output

(2)-aa-eval pass

4.內(nèi)存依賴分析

正在將MemoryDependenceAnalysis遷移到MemorySSA肆糕。


參考:

https://llvm.org/docs/AliasAnalysis.html

https://blog.tartanllama.xyz/llvm-alias-analysis/

http://james0zan.github.io/resource/GSoC15-Proposal-AA.pdf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市在孝,隨后出現(xiàn)的幾起案子诚啃,更是在濱河造成了極大的恐慌,老刑警劉巖私沮,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件始赎,死亡現(xiàn)場離奇詭異,居然都是意外死亡仔燕,警方通過查閱死者的電腦和手機造垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晰搀,“玉大人五辽,你說我怎么就攤上這事⊥馑。” “怎么了杆逗?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鳞疲。 經(jīng)常有香客問我罪郊,道長,這世上最難降的妖魔是什么建丧? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任排龄,我火速辦了婚禮,結(jié)果婚禮上翎朱,老公的妹妹穿的比我還像新娘橄维。我一直安慰自己,他們只是感情好拴曲,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布争舞。 她就那樣靜靜地躺著,像睡著了一般澈灼。 火紅的嫁衣襯著肌膚如雪竞川。 梳的紋絲不亂的頭發(fā)上店溢,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音委乌,去河邊找鬼床牧。 笑死,一個胖子當著我的面吹牛遭贸,可吹牛的內(nèi)容都是我干的戈咳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼壕吹,長吁一口氣:“原來是場噩夢啊……” “哼本缠!你這毒婦竟也來了螺戳?” 一聲冷哼從身側(cè)響起醋旦,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咒劲,沒想到半個月后缎患,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫉父,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡仪际,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蹦玫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡绢馍,死狀恐怖刁赖,靈堂內(nèi)的尸體忽然破棺而出搁痛,到底是詐尸還是另有隱情纽甘,我是刑警寧澤左权,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布祷舀,位于F島的核電站抛丽,受9級特大地震影響妓蛮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜圾叼,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一蛤克、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夷蚊,春花似錦构挤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至呜笑,卻和暖如春夫否,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叫胁。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工凰慈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驼鹅。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓微谓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親输钩。 傳聞我的和親對象是個殘疾皇子豺型,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容