LLVM标记函数为const并删除重复调用

时间:2012-07-23 12:43:37

标签: llvm

我有一个外部(C)函数,我在我的LLVM IR中调用。 IR获取JITed并且一切正常,但生成的代码对性能敏感,并且我想删除对外部函数的重复调用(如果可能)。该功能没有副作用。是否有一个FunctionPass消除了对该功能的冗余调用?我是否需要做一些事情来将功能标记为没有副作用?

谢谢!

1 个答案:

答案 0 :(得分:2)

根据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;

readonly表示该函数没有写入内存, readnone意味着它甚至不读取内存(例如sin()可以被读取)

如果一个函数没有写入内存,它应该只根据参数返回结果,因此是一个纯函数(如果全局状态没有改变)。如果是readnone函数,甚至全局状态也可能发生变化。

llvm优化器可以使用EarlyCSE传递(公共子表达式消除)优化对只读和读取函数的调用,如以下示例所示:

使用以下测试功能

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_fnreadnone_fn函数只调用一次,从而消除冗余和调用。

-functionattrs传递还可以将这些属性添加到已定义的函数