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!
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With