我有一个外部(C)函数,我在我的LLVM IR中调用.IR获取JITed并且一切正常,但生成的代码对性能敏感,并且我想删除对外部函数的重复调用(如果可能).该功能没有副作用.是否有一个FunctionPass消除了对该功能的冗余调用?有什么我必须做的事情来标记该功能没有副作用?
谢谢!
根据http://llvm.org/docs/LangRef.html#function-attributes,您可以为函数指定属性 readonly 或 readnone :
declare i32 @fn(i32 %i);
declare i32 @readonly_fn(i32 %i) readonly;
declare i32 @readnone_fn(i32 %i) readnone;
Run Code Online (Sandbox Code Playgroud)
readonly意味着该函数不写入内存,
readnone意味着它甚至不读取内存(例如 sin() 可以是 readnone)
如果一个函数不写内存,它应该只根据参数返回结果,因此是一个纯函数(如果全局状态没有改变)。在 readnone 函数的情况下,甚至全局状态也可能发生变化。
llvm 优化器可以使用EarlyCSEpass(公共子表达式消除)来优化对 readonly 和 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
}
Run Code Online (Sandbox Code Playgroud)
运行opt -early-cse -S readonly_fn.ll > readonly_fn_opt.ll优化了对 readonly 和 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)
%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
}
Run Code Online (Sandbox Code Playgroud)
和函数仅被调用一次,从而消除了冗余调用readonly_fn。readnone_fn
pass-functionattrs还可以将这些属性添加到定义的函数中