LLVM IRで呼び出している外部(C)関数があります。IRはJITされ、すべてが正常に機能しますが、生成されたコードはパフォーマンスに敏感であり、可能であれば、外部関数への重複呼び出しを削除したいと思います。この機能には副作用はありません。関数への冗長な呼び出しを排除するFunctionPassはありますか?関数に副作用がないことをマークするために私がしなければならないことはありますか?
ありがとう!
LLVM IRで呼び出している外部(C)関数があります。IRはJITされ、すべてが正常に機能しますが、生成されたコードはパフォーマンスに敏感であり、可能であれば、外部関数への重複呼び出しを削除したいと思います。この機能には副作用はありません。関数への冗長な呼び出しを排除する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 関数の呼び出しを最適化できます。
次のテスト関数を使用して
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 関数の 2 番目の呼び出しが最適化されなくなります。
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
}
および関数は 1 回だけ呼び出されるためreadonly_fn
、readnone_fn
冗長な呼び出しがなくなります。
パスは、-functionattrs
これらの属性を定義済み関数に追加することもできます