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

标签 llvm

我在我的 LLVM IR 中调用了一个外部 (C) 函数。 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;
readonly表示函数不写内存,readnone意味着它甚至不读取内存(例如 sin() 可能是 readnone)

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

llvm 优化器可以使用 EarlyCSE 优化对 readonly 和 readnone 函数的调用。通过(公共(public)子表达式消除),如下例所示:

使用以下测试功能
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 pass 还可以将这些属性添加到定义的函数中

关于LLVM 将函数标记为 const 并删除重复调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11612787/

相关文章:

c++ - LLVM,获取内部结构的偏移量

c++ - ArrayRef 的用途

LLVM 如何将 Attributes::NoUnwind 设置为 Function?

c++ - 将编译器从 x86 汇编移植到 LLVM

ios - 抑制可选框架的 `missing required architecture i386` 警告?

cmake - 如何仅在cmake中匹配主要版本

配置 $(CC) 以在可以安全删除包含时发出警告

llvm - 在 clang 中对 -O4 进行了哪些优化?

c++ - 为什么我必须为 LLVM 链接这些库两次?

c++ - 使用 LLVM 从 const void * 转换为模板类型时出现问题