web-dev-qa-db-ja.com

VMのバイトコードを出力するGCCまたはClang?

要するに、私はCをスクリプト言語として移植可能な方法で使用したかったので、これを実現するためにレジスターベースのJITless VM=を作成しました。

VMのISA、スクリプトファイル形式、呼び出し規則を形式化し、人間が読み取れるバイトコードを数値バイトコードにアセンブルするアセンブラーも作成しました。今度は、VMをターゲットとするコンパイラーが必要です。

これを実現するためにGCCとLLVMのどちらのバックエンドを作成するかを検討しましたが、そのようなプロジェクトをこれまで行ったことはありません。 GCCバックエンド、LLVMバックエンドを作成する必要がありますか、それとも選択できる追加のオプションはありますか?

vm/runtime envへのリンク

2
Nergal

私はLLVMを強く主張します。

LLVMは未来であり、IMHOはGCCと比較して新しいコンパイラーの実装に適しています。
理由は次のとおりです。

  • モジュール性

    • LLVMはモジュラーコンパイラフレームワークであり、GCCよりもはるかに優れています。コンポーネントを実装して、ライブラリ、プラグイン、または「ツール」として再利用できます。このため、LLVMに新しいツールやモジュールを追加して、既存の機能を再利用するのはかなり簡単です。例: [〜#〜] lldb [〜#〜] 、LLVMデバッガーは、clangのインフラストラクチャを利用して、正確で豊富なC++デバッグ情報を表示します。ゼロから実装する必要はありません。推奨される推奨事項: ClangチュートリアルパートI:はじめに(ビット、バイト、Boos)
  • 保守性:

    • LLVM byetcodeとIRは、それらのGCCの対応物(RTL、GIMPLEなど)よりも扱いが簡単で、友好性が低く、より急な学習曲線が必要になる可能性があります。
    • GCCは何年も前から存在しており、そのため、レガシーコードの巨大な部分があり、改善がより難しく、柔軟性が低くなっています。
    • GCCのほとんどは、CおよびCライクなC++でまだ書かれていますが、LLVMは最新のC++方言で書かれています。
    • LLVMは、リポジトリをSVNから単一のGithubモノリポジトリ( https://github.com/llvm/llvm-project )に移動する最終プロセスです。これはGitファンにとって朗報であり、Github機能は将来のコラボレーションを改善するために使用される可能性があります。 GCCは現在もSVNでホストされています。
  • 採用:

    • GCCは引き続き強力で、安定した開発者コミュニティがありますが、LLVMコミュニティははるかに急速に成長しています: GCC vs LLVM Q3 2017:Active Developer Counts
    • ほとんどの新しい言語コンパイラはLLVMの上に実装されています:いくつか例を挙げると、Swift、Julia、Rust、Haskell、およびKotlin(詳細は WikipediaのLLVM を参照)。また、静的アナライザー、オプティマイザー、およびその他の多くのツールを実装するための最も一般的な選択肢です( LLVMを使用したプロジェクト ページを確認してください)。私のお気に入りのプロジェクトの1つは Emscripten で、サポートされている任意の言語からコンパイルされたLLVMビットコードをJavascriptに変換できます。
    • ますます多くの企業が、従来の独自のGCCコンパイラーからLLVMベースのコンパイラーに移行しています。
  • ライセンス:

    • LLVMで使用されるBSDライセンスとは対照的に、GCCにはより厳密なGPL3ライセンスがあります。どちらが良いかというと、BSDライセンスの方が柔軟性が高く、ソースコードを公開する必要もありません。これは実際、大企業がGCCからLLVMに移行している主な理由の1つです(そして、LLVMを後援するためにAppleを得た理由)。

さらに、LLVMには多くのリソース、ドキュメント、およびチュートリアルがあり、特にバックエンドの立ち上げのために、たとえば次のようになります。 チュートリアル:Cpu0アーキテクチャー用のLLVMバックエンドの作成

上記のすべての理由から、バックエンド開発にはLLVMを強くお勧めします。
私は上記のTCCに詳しくありませんが、今後のフレームワークに真剣な計画がある場合は、LLVMよりも安全です。

編集:

Alex Reinkingが述べたように、LLVMは非常に動的なプロジェクトであり、非常に速く前進しています。最新のツリーに追いつくには、常に考慮する必要があります。 LLVMは活気に満ちており、状況は常に変化しているため、内部APIがバージョン間で中断することはまずありません。

6
valiano

GCCとLLVMの間では、最初にLLVMを検討することをお勧めします。 GCCは開発が面倒であることが明らかに知られていますが、LLVMのコードの一部は、まったく同じ面倒さに反応して特別に作成されました。

そうは言っても、私が推奨とするのは、TCC、Tiny Cコンパイラのバックエンドを作成することです。それは難読化されたCコンテストエントリに由来しますが、それは2001年であり、コードベースの明確さを改善することはそれ以来継続的なプロジェクトです。 TCC自体はあまり最適化されていませんが、一部(またはすべて)の定数式を最適化します。

TCCには高活動のメーリングリストはありませんが、いくらか活動的であり、いくつかのプロジェクトで積極的に(ゆっくりではありますが)維持および使用されています(Pythonバインディングがあるなど)、サポートC99のほとんど、そして何よりも重要なことは、かなり単純であるだけでなく、いくつかのターゲットをある程度サポートしているため、そのようなファイルに使用されているファイルを参照することで、何が関係しているかを理解できます。

2
aerohammer

簡単に言えば、私はCをスクリプト言語として、移植可能な方法で使用したかったので、これを実現するためにレジスターベースのJITless VMを作成しました。

Cコードのコンパイルは簡単です。しかし、最適化コンパイラを作るのは難しいです。 this の回答を参照してください。

したがって、おそらくスクリプトを作成する目的でCを使用したいので、パフォーマンスは気にしないでしょう。また、VM内の最適化作業に集中することになると思います。そうすれば、Cコンパイラのコーディングは基本的には簡単です( tinyccTinyCC ウィキペディアを調べてください)。 nwcc )に挿入します。しかし、実装で 未定義の動作 が何を意味するかという問題がまだあります。

Cをスクリプト言語として使用するのは間違いだと思います(ただし、 this を参照してください)。より高いレベル semantics を使用することをお勧めします(Cのような構文を維持することもできます)。特に、スクリプト言語には未定義の動作がほとんどないはずです(理想的にはなし)。実際には、障害のあるスクリプトでVMをクラッシュさせたくありません。

特定の目的のためにLLVMやGCCは必要ありません(どちらもやり過ぎです)。 C標準ライブラリが必要です。 C(またはその妥当なサブセット)の解析は非常に簡単で、naïveCコンパイラの記述は簡単な練習です(最適化を行うのが難しいのは難しいことです)コンパイラ、そしておそらくあなたは何も必要としません)。

ただし、 libgccjit または [〜#〜] llvm [〜#〜] (または を使用できます。 asmjit またはGNU lightning )をVM実装でJIT目的で(ただし、問題ではありません)あなたが求めている)。

ところで、単純に(VMのワードサイズ、配置制約、および endianness がネイティブマシンと同じである場合、または一部の既存のGCCクロスコンパイラ)は、CコンパイラをGCC plugin としてプロトタイプし、 Gimple で動作します。実際には、ほとんどのGimpleは非常に安定しています(おそらくLLVMの内部よりも安定しています)。