2

私はコンパイラとツールのコースをやっています(今学期)。私は中間コード生成まで読み、最適性のためのDAG表現も見ました。コンパイラーで明らかなことの1つは、生成された中間コードが何であれ、プログラムを実行できるように、システムの命令セットにマップする必要があるということです。

特定のアーキテクチャ(たとえばA)用のコンパイラを作成しているとしましょう。2つの数値の加算はADD R1、R2、R3(Aの命令セットから)です。ここで、R1-は宛先、R2、R3は情報源。そして、私はこれらの命令でマッピングしました。つまり、中間コードで表される2つの数値(タイプに関係なく、簡単にするため)を追加したい場合は、ADDオペコードを実行します。

新しいアーキテクチャが市場に到着したと仮定します。このアーキテクチャでは、2つの数値を加算すると、AD R1、R2、R3などの異なる命令セットが使用されます。今、明らかに私のコンパイラは数字を追加しません!

さて、私の質問は、プログラミング言語用のコンパイラを作成するときに、すべてのアーキテクチャを命令セットとともに追加して、コンパイラが必要なことを正しく実行できるようにする必要があるということです。もしそうなら、この効果を最適化するためにそこにあるすべての方法は何ですか?すべての命令セットを追加すると、パフォーマンスがほぼ低下するためです。

私が間違っていたら正解です!

4

2 に答える 2

4

選択した「命令セットアーキテクチャ(ISA)」のサブセットである特定の命令セット用のコンパイラを構築します。(多くの命令セットにはI / O命令がありますが、コンパイラーがこれらを生成することはほとんどありません)。選択した特定の命令サブセットで動作するこの「命令セットアーキテクチャ」を実行するいくつかの異なるプロセッサ設計が存在する場合があります。

実際には3種類の進化イベントが発生します。

  • ISAからの命令をさらに使用すると、コンパイラの方が優れていると判断します。たとえば、MULTIPLY命令を使用すると、コンパイラが過去に乗算に使用したサブルーチン呼び出しよりも高速なコードを生成できるようになると判断する場合があります。この場合、コンパイラを少し拡張します。

  • ISAの所有者(Intel、AMD、IBMなど)は、まったく新しい一連の命令をISAに追加します。たとえば、データのキャッシュラインでのデータ並列操作(「SIMD命令」)。これらのいくつかをコンパイラーに追加することを決定できます。新しい命令ファミリは通常、データのレイアウトと処理方法についてさまざまな仮定を行うため、このイベントは困難な場合があります。

  • 処理したい完全に異なるISAがいくつか見つかります。この場合、どのレジスタが存在するか、どのように使用されるかなどの点で、命令セットが完全に異なるため、コンパイラのバックエンドを再構築します。

コンパイラビルダーは、段階的に動作するコンパイラをビルドすることがよくあります。実際のマシンコードを生成する前の最後の段階では、通常、プログラムは、かなり標準的な抽象演算(ADD、MULTIPLY、COMPARE、JUMP、 CALL、STORE、LOAD、...)実際のISAへのコミットメントはありません(特に、登録または特定のマシン命令に関するコミットメントはありません)。このようにすることで、ISAとは無関係に高レベルの最適化を実行できます。これを優れたモジュール化と考えてください。最後のいくつかの段階はISAに特化しています。通常、レジスタを割り当てるためのステージで、その後にパターンが実際の命令を抽象命令と照合します。

より高いレベルでの最適化について書かれた本全体と、最終的なコード生成状態について書かれた他の本(そして多くの場合、別々の章で両方を扱っている本)があります。[Aho&UllmanDragonの本とTorczonのEngineeringaCompilerはどちらも両方のトピックについて非常に優れた本です)。最終的な命令セットを書き留めてレイアウトを登録することを可能にする多くの技術があり、最終段階の多くを生成します。GCCにはそのようなものがあります。そのテクノロジーは複雑で、この文には当てはまりません。本を読みに行くのが一番です。

この方法で最初のISAでコンパイラを動作させると、同じテクノロジを使用してバリアントを構築できます。最終的に、ISAごとに1つずつ、合計2つの物理コンパイラが作成されます。それらはすべてのフロントエンドロジックを共有し、コード生成と最適化を抽象化します。それらは最終段階で完全に異なります。

理解しておくべきことは、命令セットを利用するコンパイラーの構築は複雑なプロセスであるということです。

于 2011-04-14T13:58:45.357 に答える
1

それはすべて、変化の大きさに依存します。命令ADDR1、R2、R3を備えたISAX1.0があるとします。命令ADDR1、R2、R3をAD R1、R2、R3に置き換える新しいバージョンX 1.1を入手した場合、変更はわずかです。基本的に、同じ命令で異なる名前が付けられています。この変更は、「ADD」の代わりに「AD」を発行するフラグcc-archX1.1で対応できます。

変更がADR1、R2(R2 <-R1 + R2)のように大きい場合、新しい命令は古いADDとは異なります。この場合、コードジェネレーターを変更し、この命令を使用可能な命令のセットに含める必要があります。この場合も、cc -arch X1.1は、この命令が使用可能であることをジェネレーターに通知する必要があります。

コンパイラをISAYにリターゲットするなど、変更がさらに大きい場合は、コードジェネレータによって生成されるすべての命令を変更する必要があります。それは大変な作業になる可能性があります。

現在、既存の低レベルのコンパイラ最適化が新しいターゲットで機能するかどうかも疑問です。一般に、明確に定義されたバックエンド(gccなど)は、多くのISAをサポートできます。低レベルの中間表現(IR)を使用しており、命令にはオペコード名("ADD"または"AD")を含むいくつかのプロパティがあります。ただし、低レベルのオプティマイザは、命令の他のプロパティほど名前にあまり関心がありません。つまり、オペランドはいくつありますか。どのオペランドが読み取り/書き込みされますか?メモリにアクセスしますか?プログラムの流れは変わりますか?等

ターゲットアーキテクチャをコンパイラフレームワークに適合させることができれば、既存の最適化をうまく利用できます。

于 2011-04-14T22:49:28.523 に答える