2016-03-30 13 views
2

LLVMパスで、llvm::Module::getFunctionList()によって返されたリストを使用してモジュール関数リストを反復しようとしています。私はこの1つのようなループを使用します。LLVM pass:モジュール関数リストを反復するときのエラー

for (auto curFref = M->getFunctionList().begin(), 
       endFref = M->getFunctionList().end(); 
       curFref != endFref; ++curFref) { 
     errs() << "found function: " << curFref->getName() << "\n"; 
    } 

予想通り、このループの最初の反復は、機能を取得し、それはリストの終わりを検出していないし、ちょうど後続の反復である他のオブジェクトを取得し続けその関数パラメータのような関数ではありません(getName()によって報告されています)。いくつかの反復の後、おそらく現在の "関数"参照を参照していくらかのゴミ(またはNULL)に達し、クラッシュします。

このIRコードになり
int foo(int k) { 
    int i, s = 0; 
    for (i = 0; i < k; ++i) 
     s += i; 
    return s; 
} 

... 
; Function Attrs: nounwind uwtable 
define i32 @foo(i32 %k) #0 { 
entry: 
... 

出力は次のようになります。

found function: foo 
found function: k 
found function: #0 0x00007f481f77c46e llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/me/work/llvm-3.8.0/lib/Support/Unix/Signals.inc:322:0 
... 

ですから、後に正常に反復処理することを見ることができる。例えば、このプログラムの fooを超えると、パラメータkのようなオブジェクトに続きました。

モジュールパス(runOnModule())とFunctionパス(F.getParent()を使用してモジュールをクエリしています)の両方でこれを試してみたところ、同じ結果が得られました。

問題は、LLVM 3.8.0とLLVM 3.5.2の両方にも複製されます。

戻り値の関数リストを正しく反復できないことが何であるか考えてみてください。

=====

EDIT:

注そのようなイテレータためM.begin()/end()を用いて、またはCを使用した場合であっても場合など、モジュールの機能の上に別の反復を使用する場合と同じ挙動が示されていること++ 11範囲ベースforループ:for (Function &curF: M) ...

さらに、M.getFunctionList().size()は、リスト項目を反復しようとする際にセグメンテーション違反を引き起こします。関数リストが実際に壊れているようです。しかし、それは私がrunOnModule()エントリポイントのちょうど始めに得たリストです。だから私のコードで壊れてしまったようなものではない。

======

EDIT 2:この問題は、私のLLVMパスが動的にロード可能なライブラリとしてLLVMのソースツリーから外部に構築され、その後にロードされている場合

私は考えていますコマンドラインオプション-load=foo.soを使用してください。

+0

@Chandler Carruthの答えがこの問題を解決しました。彼の答えの中核をなすのは、LLVMをmake/configureでビルドしたときに、ninja/cmakeを使ってLLVMをビルドすることを勧めました。 ninja/cmakeを使って再構築することでこの問題は解決されました。 LLVM 3.8.0のリリースノートは、make/configureでのビルドがまだサポートされていることを示唆していますが、この問題は何とか壊れていることを示唆しています。 – ElazarR

答えて

2

をvelopers。

これはほとんどの場合、LLVMの誤ったチェックアウト、誤ったコンパイル済みのLLVM、またはパスが個別のDSOとして構築されているという問題です(私はそれがどのようになるか分かりませんが)。

LLVMの多くの部分は、機能のみを反復するためにM->functions()(またはM->begin() & M->end())を使用します。動作が壊れた場合、これらのパーツは一貫して失敗します。これらのメカニズムと関数リストに直接アクセスするのは、M->getFunctionList()のように直接の違いは、リストが変更可能かどうかだけです。表示するユースケースについては、正確にはと同じ動作にする必要があります。

LLVMテストスイートを実行して、正しく動作することを確認することをお勧めします。あなたは(私が推薦するよう)忍者CMakeのジェネレータを使用する場合はLLVMを構築する:

% ninja check-llvm 

をこれに失敗した場合、それは問題があなたのコピーに何かがあることを、非常に良い兆候だという、同様の分野でクラッシュした場合は特にLLVMの

それにもかかわらず、SOはここでさらに助けを得るには最適な場所ではありません。質問への答えは "それは実際に働くべきである"と私はLLVMのコードをチェックしたと私は明らかな説明は表示されません。だから私の提案は、上記を試して、LLVMの新鮮なコピーを試してみることです(おそらくツリーのトップか、最新のリリース)。 LLVMを構築するのに十分な近代的なホストツールチェーンがあることを確認してください。他のすべてが失敗した場合はメーリングリストで開発者に手を差し伸べるしてみてください、 http://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library

http://lists.llvm.org/mailman/listinfo/llvm-dev

やIRCチャンネル試してみてください。詳細については、このセクションを参照してください http://llvm.org/docs/#irc

・ホープ、このことができますが!

+0

このイテレータは、LLVMプロジェクト内に構築されたモジュールで動作することは間違いありません。しかし、私の場合、モジュールパスを共有オブジェクトとしてビルドし、 'opt'の '-load'オプションを使用してロードします。したがって、このユースケースに問題がある可能性があります(つまり、このユースケースが壊れている間はLLVMのすべてが機能する可能性があります)。また、 'llvm-config --cppflags'によって提供されるコンパイルフラグに依存して、自分自身のmakefileを使ってパス共有オブジェクトを外部的に構築します。だから、 'llvm-config --cppflags'の出力は、内部ビルドに使われるフラグとは異なるかもしれません。 これらのユースケースがテストされているかどうか知っていますか? – ElazarR

+0

忍者と一緒にビルドするように勧められたことが「魔法」でした。 オリジナルのLLVMビルドでconfigure/makeを使用しました。公式にはまだ3.8.0でサポートされていますが、問題があるようです。 LLVMをninjaで再構築し、更新された(ninja)LLVMに対して同じmakefileを使用してモジュールパスを構築すると、問題は解決しました。 LLVMのmakeベースのビルドは、リリースノートではサポートが中止されることを提案していたにもかかわらず、実際にはサポートされていないと思います。ありがとう。 – ElazarR

0

M->begin()M->end()M->getFunctionList().begin()M->getFunctionList().end()の代わりに使用したことがありますか?それは私のために働く。

+0

'M-> begin()/ end()'は 'M-> getFunctionsList()。begin()/ end()'の制限されたバージョンです。とにかく、私は単純なイテレーターも試してみましたが、同じ不運な結果を得ました。 – ElazarR

0

入力が壊れている可能性はありますか?最初にllvm::verifyModuleを実行してみてください(Verifier.hから)。opt -verifyを実行してください。同じである必要があります。また、optのコマンドラインオプション-verify-eachに興味があるかもしれません。あなたは合格登録するには、以下の使用している場合は

+0

問題は、私がテストしたどのモジュールでも再現されます。すべての入力モジュールは、次のコマンドを使用してCコードから生成されます: 'clang -c -emit-llvm -o foo-preopt.bc foo.c'そして' opt -mem2reg -licm -S -o foo.ll foo -preopt.bc'。 モジュールが壊れていると、それは 'clang'の結果であるか、標準の' opt'が通ります。とにかく、 '-verify'は何の問題も報告しません。私はLLVMの安定版を使用しています。 – ElazarR

+0

@ElazarR別の考え方:オペレーティングシステムに付属しているclangではなく、optと一緒にビルドされたclangを使用していることを確認してください。 – Oak

+0

私は使用しているLLVMツールと一貫しています。実際には、自分のOSにclang/LLVMパッケージをインストールすることは避けました。私はそれぞれのリリースのソースコードから構築したclang/LLVMのみを使用し、各ツールに明示的なパスを提供します。 – ElazarR

0

char SkeletonPass::ID = 0; 

// Automatically enable the pass. 
// This pass is taken from Adrian Samson Template project http://adriansampson.net/blog/clangpass.html 
static void registerSkeletonPass(const PassManagerBuilder &, 
         legacy::PassManagerBase &PM) { 
    PM.add(new SkeletonPass()); 
} 
static RegisterStandardPasses 
    RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 
       registerSkeletonPass); 

これはFunctionPass/BasicBlockPassに対してのみ機能を以下のように、一つの解決策は、任意のトリックなしでいつものように標準的なパスを使用することです: -

char SkeletonPass::ID = 0; 
static RegisterPass<SkeletonPass> X("passname","Pass Name Analysis"); 
static void registerPass(const PassManagerBuilder &, 
         legacy::PassManagerBase &PM) { 
    PM.add(new SkeletonPass()); 
} 
static RegisterStandardPasses 
     RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 
         registerPass); 

そして、次のcmdを使ってパスを実行します。私はコアLLVMドの一人です

$ clang -c -O1 -emit-llvm programs/hello.cpp -o programs/hello.bc 
$ opt -load build/Debug/libCallgraph.so -passname programs/hello.bc 
+0

残念ながら、これで問題は解決されません。 M.getFunctionList()を反復処理すると、モジュール内の最初の関数で始まり、その関数のパラメータなどの関数ではないシンボル(オブジェクト)を続けて返す項目が返されます。 実際には、isa ()は、これらのオブジェクト(関数パラメータ)をFunctionオブジェクトとしてレポートします。したがって、イテレータでは何かが完全に間違っているようです。 – ElazarR

関連する問題