Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LLVM mark function as const and remove duplicate calls

Tags:

llvm

I have an external (C) function that I am calling in my LLVM IR. The IR gets JITed and everything works fine, but the generated code is performance sensitive, and I want to remove duplicate calls to my external function if possible. The function has no side effects. Is there a FunctionPass that eliminates redundant calls to the function? Is there something I have to do to mark the function as having no side effects?

Thanks!

like image 770
Jared Pochtar Avatar asked Nov 04 '22 19:11

Jared Pochtar


1 Answers

According to http://llvm.org/docs/LangRef.html#function-attributes you can specify the attributes readonly or readnone for a function:

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

readonly means that the function doesn't write memory, readnone means that it doesn't even read memory (for example sin() could be readnone)

If a function doesn't write memory, it should return the result only based on the parameters, and therefor be a pure function (if the global state doesn't change). In case of a readnone function, even the global state could change.

The llvm optimizer can optimize calls to readonly and readnone functions with the EarlyCSE pass (common subexpression elimination), as shown in the following example:

using the following test functions

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
}

and running opt -early-cse -S readonly_fn.ll > readonly_fn_opt.ll optimizes away the second call for the readonly and readnone functions, resulting in

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
}

The readonly_fn and readnone_fn functions are only called once, thus eleminating redundand calls.

The -functionattrs pass can also add these attributes to defined functions

like image 119
Azegor Avatar answered Dec 16 '22 19:12

Azegor