2012-07-23 69 views
5

我有一個外部(C)函數,我在LLVM IR中調用。 IR獲得JIT並且一切正常,但生成的代碼是性能敏感的,並且如果可能的話,我想刪除對我的外部函數的重複調用。該功能沒有副作用。是否有一個FunctionPass可以消除對該函數的多餘調用?有什麼我必須做的標記功能沒有副作用?LLVM標記函數爲const並刪除重複調用

謝謝!

回答

1

根據http://llvm.org/docs/LangRef.html#function-attributes您可以指定只讀屬性或readnone的功能:

declare i32 @fn(i32 %i); 
declare i32 @readonly_fn(i32 %i) readonly; 
declare i32 @readnone_fn(i32 %i) readnone; 

readonly意味着函數不寫內存, readnone意味着它甚至不讀內存(用於示例sin()可以被讀取)

如果一個函數不寫內存,它應該只返回基於參數的結果,因此是一個純函數(如果全局狀態不變)。在readnone函數的情況下,即使是全局狀態也會改變。

LLVM的優化可以優化呼叫爲只讀並且與EarlyCSE通(公共子表達式消除)readnone功能,顯示在下面的例子:使用下列測試功能

define i32 @test_no_readonly() 
{ 
    %1 = call i32 @fn(i32 0) 
    %2 = call i32 @fn(i32 0) 
    %add = add i32 %1, %2 
    ret i32 %add 
} 
define i32 @test_readonly() 
{ 
    %1 = call i32 @readonly_fn(i32 0) 
    %2 = call i32 @readonly_fn(i32 0) 
    %add = add i32 %1, %2 
    ret i32 %add 
} 
define i32 @test_readnone() 
{ 
    %1 = call i32 @readnone_fn(i32 0) 
    %2 = call i32 @readnone_fn(i32 0) 
    %add = add i32 %1, %2 
    ret i32 %add 
} 

和運行

opt -early-cse -S readonly_fn.ll > readonly_fn_opt.ll優化了讀取和讀取函數的第二個呼叫,從而生成

define i32 @test_no_readonly() { 
    %1 = call i32 @fn(i32 0) 
    %2 = call i32 @fn(i32 0) 
    %add = add i32 %1, %2 
    ret i32 %add 
} 

define i32 @test_readonly() { 
    %1 = call i32 @readonly_fn(i32 0) 
    %add = add i32 %1, %1 
    ret i32 %add 
} 

define i32 @test_readnone() { 
    %1 = call i32 @readnone_fn(i32 0) 
    %add = add i32 %1, %1 
    ret i32 %add 
} 

readonly_fnreadnone_fn函數只被調用一次,因此調用冗餘和調用。

通過-functionattrs也可以將這些屬性添加到定義的功能