LLVM将函数标记为常量并删除重复调用

LLVM将函数标记为常量并删除重复调用,llvm,Llvm,我在LLVM IR中调用了一个外部(C)函数。IR得到了JIT,一切正常,但生成的代码对性能非常敏感,如果可能的话,我希望删除对外部函数的重复调用。该功能没有副作用。是否有一个FunctionPass可以消除对函数的冗余调用?我需要做些什么来标记这个功能没有副作用吗 谢谢 根据,您可以为函数指定readonly或readnone属性: declare i32 @fn(i32 %i); declare i32 @readonly_fn(i32 %i) readonly; declare i32 @

我在LLVM IR中调用了一个外部(C)函数。IR得到了JIT,一切正常,但生成的代码对性能非常敏感,如果可能的话,我希望删除对外部函数的重复调用。该功能没有副作用。是否有一个FunctionPass可以消除对函数的冗余调用?我需要做些什么来标记这个功能没有副作用吗

谢谢

根据,您可以为函数指定readonly或readnone属性:

declare i32 @fn(i32 %i);
declare i32 @readonly_fn(i32 %i) readonly;
declare i32 @readnone_fn(i32 %i) readnone;
readonly
表示函数不写入内存,
readnone
表示它甚至不读取内存(例如sin()可以是readnone)

如果函数不写内存,它应该只根据参数返回结果,因此是纯函数(如果全局状态不变)。在readnone函数的情况下,即使全局状态也可能发生变化

llvm优化器可以使用
EarlyCSE
pass(公共子表达式消除)优化对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
}
并且运行
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
}
readonly\u fn
readnone\u fn
函数只调用一次,因此消除了冗余和调用

-functionattrs
过程还可以将这些属性添加到定义的函数中