5

LLVM IRで呼び出している外部(C)関数があります。IRはJITされ、すべてが正常に機能しますが、生成されたコードはパフォーマンスに敏感であり、可能であれば、外部関数への重複呼び出しを削除したいと思います。この機能には副作用はありません。関数への冗長な呼び出しを排除するFunctionPassはありますか?関数に副作用がないことをマークするために私がしなければならないことはありますか?

ありがとう!

4

1 に答える 1

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 である可能性があります)。

関数がメモリを書き込まない場合は、パラメーターに基づいてのみ結果を返す必要があるため、(グローバルな状態が変化しない場合) 純粋な関数である必要があります。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_fnreadnone_fn冗長な呼び出しがなくなります。

パスは、-functionattrsこれらの属性を定義済み関数に追加することもできます

于 2015-04-20T18:56:43.520 に答える