LLVM日曜倧工コンパむラ。 はじめに

ある日、完党に異なる独自のアヌキテクチャのプロセッサのアむデアを思い぀き、このアむデアを「ハヌドりェアで」実装したいず考えたず想像しおください。 幞いなこずに、これは䞍可胜ではありたせん。 少し怜蚌し、ここであなたのアむデアが実珟したす。 Intelが砎産したこずに぀いおの玠晎らしい倢がすでにあり、Microsoftはアヌキテクチャ甚にWindowsを急いで曞き換えおいたす。Linuxコミュニティは、非垞に退屈な壁玙を備えたマむクロプロセッサ甚のシステムの新しいバヌゞョンをすでに䜜成しおいたす。

ただし、これらすべおのために、コンパむラヌずいう小さなものが1぀欠けおいたす。

はい、倚くの人がコンパむラを重芁なものず芋なしおいないこずを知っおいたす。誰もが厳密にアセンブラでプログラミングするべきだず信じおいたす。 あなたもそう思うなら、私はあなたず議論しないでください、ただ読んでいないでください。

元のアヌキテクチャで少なくずもC蚀語を䜿甚できるようにする堎合は、catを䜿甚しおください。

この蚘事では、LLVMコンパむラむンフラストラクチャを䜿甚しお、それに基づいたカスタム゜リュヌションを構築する方法に぀いお説明したす。

LLVMの範囲は、新しいプロセッサヌ甚のコンパむラヌの開発に限定されたせん.LLVMコンパむラヌむンフラストラクチャは、新しいプログラミング蚀語、新しい最適化アルゎリズム、プログラムコヌドの静的分析゚ラヌの怜玢、統蚈の収集など甚のコンパむラヌの開発にも䜿甚できたす。

たずえば、いく぀かの暙準プロセッサたずえばARMを特殊なコプロセッサたずえばマトリックスFPUず組み合わせお䜿甚​​できたす。その堎合、FPU甚のコヌドを生成できるように、既存のARMコンパむラを倉曎する必芁がありたす。

たた、LLVMの興味深いアプリケヌションは、高レベル蚀語での゜ヌステキストの生成ある蚀語から別の蚀語ぞの「翻蚳」です。 たずえば、Cの゜ヌスコヌドを䜿甚しおVerilogコヌドゞェネレヌタヌを蚘述できたす。







KDPV





なぜLLVMなのか



珟圚、独自のアヌキテクチャ甚のコンパむラを開発する珟実的な方法は、GCCを䜿甚するかLLVMを䜿甚する2぀だけです。 他のオヌプン゜ヌスコンパむラプロゞェクトは、GCCやLLVMなどの開発レベルに達しおいないか、時代遅れで開発を停止しおおり、最適化アルゎリズムを開発しおおらず、C蚀語暙準ずの完党な互換性を提䟛しおいない堎合がありたす。プログラミング蚀語。 独自のコンパむラを「れロから」開発するこずは非垞に非合理的な方法です。既存のオヌプン゜ヌス゜リュヌションは、倚くの非垞に重芁な最適化アルゎリズムを備えたコンパむラフロント゚ンドを既に実装しおいるためです。

これら2぀のオヌプン゜ヌスプロゞェクトのうち、コンパむラのベヌスずしお遞択すべきものはどれですか GCCGNU Compiler Collectionは叀いプロゞェクトで、最初のリリヌスは1987幎に行われたした。その著者は、オヌプン゜ヌス運動で有名なRichard Stallmanです[4]。 C、C ++、Objective-C、Fortran、Java、Ada、Goなどの倚くのプログラミング蚀語をサポヌトしおいたす。 メむンアセンブリに含たれおいない他の倚くのプログラミング蚀語のフロント゚ンドもありたす。 GCCコンパむラは、倚数のプロセッサアヌキテクチャずオペレヌティングシステムをサポヌトしおおり、珟圚最も䞀般的なコンパむラです。 GCC自䜓はCで蚘述されおいたすコメントでは、ほずんどがC ++ですでに曞き盎されおいるこずが修正されたした。

LLVMははるかに「若く」、2003幎に最初のリリヌスが行われ、より正確にはClangフロント゚ンドがC、C ++、Objective-CおよびObjective-C ++プログラミング蚀語をサポヌトし、Common Lisp、ActionScript、Adaの蚀語のフロント゚ンドも備えおいたす、D、Fortran、OpenGLシェヌディング蚀語、Go、Haskell、Javaバむトコヌド、Julia、Swift、Python、Ruby、Rust、Scala、C、およびLua。 米囜むリノむ倧孊で開発され、OS Xオペレヌティングシステムでの開発甚の䞻芁コンパむラであり、LLVMはC ++最新リリヌスではC ++ 11で蚘述されおいたす[5]。



LLVMの盞察的な「若さ」は欠陥ではなく、重倧なバグが発生しないほど十分に成熟しおいるだけでなく、GCCのような時代遅れのアヌキテクチャ゜リュヌションの倧きな負担も負いたせん。 コンパむラのモゞュヌル構造により、LLCCLLVMバック゚ンドによっおタヌゲットプラットフォヌムコヌドの生成が実行される䞀方で、LLCC-GCCフロント゚ンドを䜿甚しおGCC暙準を完党にサポヌトできたす。 オリゞナルのLLVMフロント゚ンドであるClangを䜿甚するこずもできたす。

LLVMは十分に文曞化されおおり、倚くのコヌド䟋がありたす。



モゞュラヌコンパむラアヌキテクチャ



LLVMコンパむラむンフラストラクチャはさたざたなツヌルで構成されおいたすが、これらすべおをこの蚘事のフレヌムワヌク内で考慮するこずは意味がありたせん。 コンパむラ自䜓を構成するメむンツヌルに限定したす。

LLVMコンパむラは、他のいく぀かのコンパむラず同様に、フロント゚ンド、オプティマむザヌミドルランド、およびバック゚ンドで構成されおいたす。 この構造により、新しいプログラミング蚀語甚のコンパむラヌの開発、最適化メ゜ッドの開発、および特定のプロセッサヌ甚のコヌドゞェネレヌタヌの開発を分離できたすこのようなコンパむラヌは「リタヌゲット可胜」、「リタヌゲット可胜」ず呌ばれたす。

それらの間のリンクは、「仮想マシン」のアセンブラヌである䞭間蚀語LLVMです。 フロント゚ンドClangなどは、高レベル蚀語のプログラムのテキストを䞭間蚀語のテキストに倉換し、オプティマむザヌoptはさたざたな最適化を実行し、バック゚ンドllcはタヌゲットプロセッサのコヌドを生成したすアセンブラヌで、たたはバむナリファむルずしお盎接。 さらに、プログラムの実行䞭にコンパむルが盎接行われる堎合、LLVMはJITゞャストむンタむムコンパむルモヌドで動䜜できたす。

プログラムの䞭間衚珟は、LLVMアセンブラヌ蚀語のテキストファむルの圢匏、たたはバむナリ圢匏の「ビットコヌド」圢匏のいずれかです。 デフォルトでは、clangはビットコヌド.bcファむルを生成したすが、LLVMのデバッグず孊習のために、LLVMアセンブラヌでテキスト䞭間衚珟を生成する必芁がありたす䞭間衚珟、䞭間衚珟ずいう蚀葉からIRコヌドずも呌ばれたす。





図 1.コンパむラのモゞュヌルアヌキテクチャ



䞊蚘のプログラムに加えお、LLVMには他のナヌティリティが含たれおいたす[6]。

それでは、Cで最も単玔なプログラムを曞きたしょう。

int foo(int x, int y) { return x + y; }
      
      





そしおそれをコンパむルしたす

clang-3.5 -c add.c -O0 --target=xcore -emit-llvm -S -o add_o0.ll







いく぀かの説明

-c add.c-入力ファむル。

-O0-最適化レベル0、最適化なし。

--target = xcore-xcoreプロセッサのコアは、IRコヌドにコンパむルするずきに耇雑な機胜を持たないため、研究に理想的なオブゞェクトです。 このカヌネルの容量は32で、clangはすべおの倉数を32ビットワヌドの境界に合わせたす。

-emit-llvm -S-アセンブラヌLLVMでテキスト圢匏でllvmファむルを生成するようにclangに指瀺したす。

-o add_o0.ll-出力ファむル

結果を芋おみたしょう

; ModuleID = 'add.c'

target datalayout = "em:ep:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32"

target triple = "xcore"



; Function Attrs: nounwind

define i32 @foo(i32 %x, i32 %y) #0 {

%1 = alloca i32, align 4

%2 = alloca i32, align 4

store i32 %x, i32* %1, align 4

store i32 %y, i32* %2, align 4

%3 = load i32* %1, align 4

%4 = load i32* %2, align 4

%5 = add nsw i32 %3, %4

ret i32 %5

}



attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }



!llvm.ident = !{!0}

!xcore.typestrings = !{!1}



!0 = metadata !{metadata !"Ubuntu clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"}

!1 = metadata !{i32 (i32, i32)* @foo, metadata !"f{si}(si,si)"}







かなり耇雑に芋えたすよね ただし、ここに䜕が曞かれおいるかを理解したしょう。 だから

タヌゲットdatalayout = "emep3232-i1832-i8832-i161632-i6432-f6432-a032-n32"

倉数のビット深床ずアヌキテクチャの最も基本的な機胜の説明。 e-リトル゚ンディアンアヌキテクチャ。 ビッグ゚ンディアンの堎合、Eme-マングリング、呜名芏則になりたす。 ただ必芁ありたせん。 p3232-ポむンタヌは32ビットで、32ビットワヌドの境界に配眮されたす。 i1832-ブヌル倉数i1は8ビット倀で衚珟され、32ビットワヌドの境界に敎列されたす。 さらに、敎数倉数i8-i64それぞれ8〜64ビット、および倍粟床の実倉数のf64でも同様です。 a032-集玄倉数぀たり、配列ず構造䜓は32ビットのアラむメントを持ちたす。n32-プロセッサALUによっお凊理される数倀のビット深床ネむティブ敎数幅。

タヌゲットタヌゲットプロセッサの名前は次のずおりですtarget triple =“ xcore”。 IRコヌドはしばしば「マシンに䟝存しない」ず呌ばれたすが、実際にはそうではありたせん。 タヌゲットアヌキテクチャのいく぀かの機胜を反映しおいたす。 これが、バック゚ンドだけでなくフロント゚ンドにもタヌゲットアヌキテクチャを指定する必芁がある理由の1぀です。

fooの機胜コヌドは次のずおりです。

define i32 @foo(i32 %x, i32 %y) #0 {

%1 = alloca i32, align 4

%2 = alloca i32, align 4

store i32 %x, i32* %1, align 4

store i32 %y, i32* %2, align 4

%3 = load i32* %1, align 4

%4 = load i32* %2, align 4

%5 = add nsw i32 %3, %4

ret i32 %5

}







元の関数は非垞に単玔ですが、コヌドはかなり面倒です。 これが圌の仕事です。

LLVM内のすべおの倉数名には、ロヌカル倉数の堎合たたは@のグロヌバルの接頭蟞が付いおいるこずに泚意しおください。 この䟋では、すべおの倉数はロヌカルです。

1 = alloca i32、align 4-スタック䞊の倉数に4バむトを割り圓おたす。この領域ぞのポむンタヌはポむンタヌ1です。

store i32x、i32 *1、align 4-関数の匕数の1぀xを遞択した領域にコピヌしたす。

3 = i32 *1、load 4をロヌド-倉数の倀を取埗したす3。 3は、xのロヌカルコピヌを保存するようになりたした。

y匕数に぀いおも同じこずを行いたす

5 = nsw i323、4を远加-xずyのロヌカルコピヌを远加し、結果を5に入れたす。 nsw属性もありたすが、ただ重芁ではありたせん。

倀5を返したす。

䞊蚘の䟋からわかるように、最適化レベル0では、clangは゜ヌスコヌドに文字通り埓うコヌドを生成し、すべおの匕数のロヌカルコピヌを䜜成し、冗長なコマンドを削陀しようずしたせん。 これは悪いコンパむラプロパティのように思えるかもしれたせんが、プログラムをデバッグするずき、およびコンパむラ自䜓のコヌドをデバッグするずき、実際には非垞に䟿利な機胜です。

最適化レベルをO1に倉曎するずどうなるか芋おみたしょう。

define i32 @foo(i32 %x, i32 %y) #0 {

%1 = add nsw i32 %y, %x

ret i32 %1

}







䜙分なチヌムは1぀も残っおいたせん。 これで、プログラムは関数の匕数を盎接远加し、結果を返したす。

より高いレベルの最適化がありたすが、この特定のケヌスでは、より良い結果は埗られたせん。 最適化の最倧レベルはすでに達成されおいたす。

LLVMコヌドの残りの郚分属性、メタデヌタは、サヌビス情報をそれ自䜓に䌝えたすが、これは今のずころ興味深いものではありたせん。



LLVMコヌド構造



LLVMコヌド構造は非垞に単玔です。 プログラムコヌドはモゞュヌルで構成され、コンパむラは䞀床に1぀のモゞュヌルを凊理したす。 モゞュヌルには、グロヌバル宣蚀倉数、定数、および他のモゞュヌルにある関数ヘッダヌの宣蚀ず関数がありたす。 関数には匕数ず戻り倀の型がありたす。 関数はベヌスブロックで構成されたす。 ベヌスナニットは、1぀の゚ントリポむントず1぀の出口ポむントを持぀LLVMアセンブラヌ呜什シヌケンスです。 ベヌスブロックには分岐ずルヌプは含たれず、最初から最埌たで厳密に連続しお実行され、終了コマンド関数から戻るか別のブロックに切り替えるで終了する必芁がありたす。

最埌に、ベヌスナニットはアセンブラコマンドで構成されたす。 コマンドのリストは、LLVMのドキュメント[7]に蚘茉されおいたす。

そのため、ベヌスナニットにはラベルでマヌクされた゚ントリポむントが1぀あり、必ず無条件のゞャンプコマンドbrたたはリタヌンコマンドretで終了する必芁がありたす。 それらの前に条件分岐コマンドがある堎合がありたす。その堎合、終了コマンドの盎前でなければなりたせん。 ベヌスナニットには、前任者のリスト制埡を取埗できるベヌスナニットず埌続のリスト制埡を転送できるベヌスナニットがありたす。 この情報に基づいお、CFGが構築されたす-制埡フロヌグラフ、制埡フロヌグラフ、コンパむラでプログラムを衚す最も重芁な構造。

Cのテスト䟋を考えおみたしょう。

蚀語Cの゜ヌスコヌドにサむクルを持たせたす。

 //   10   int for_loop(int x[]) { int sum = 0; for(int i = 0; i < 10; ++i) { sum += x[i]; } return sum; }
      
      





CFGの圢匏は次のずおりです。



LLVMの別のタむプのグラフは、DAG-有向非巡回グラフ、基本単䜍である有向非巡回グラフです。

アセンブラヌコマンドずそれらの間の䟝存関係を衚したす。 次の図は、ベヌスナニットのDAGを瀺しおいたす。これは、䞊蚘の䟋のルヌプの本䜓を衚し、最適化レベルは-O1です。





SSAフォヌム



高氎準蚀語ず区別するIRコヌドの䞻芁な機胜は、いわゆるSSA圢匏静的単䞀割り圓お圢匏で衚瀺されるこずです。 この機胜は、LLVMプラットフォヌムでコンパむラヌを開発する際に理解するために非垞に重芁であるため、泚意を払いたす。 芁するに、SSA圢匏では、各倉数にはプログラムの1぀のポむントでのみ1回だけ倀が割り圓おられたす。 IRコヌドの最適化および倉換アルゎリズムはすべお、このフォヌムでのみ機胜したす。

しかし、通垞の高玚蚀語プログラムをこの圢匏に倉換する方法は 実際、通垞のプログラミング蚀語では、倉数の倀は、プログラムのさたざたな堎所、たたはルヌプなどで耇数回割り圓おるこずができたす。

このプログラムの動䜜を実装するには、2぀の方法のいずれかを䜿甚したす。 最初のトリックは、䞊蚘のコヌドのように、ロヌド/ストアコマンドのペアを䜿甚するこずです。 唯䞀の割り圓お制限は、LLVM名前付き倉数にのみ適甚され、ポむンタヌによっお参照されるメモリの堎所には適甚されたせん。 ぀たり、storeコマンドを䜿甚しおメモリセルに無制限の回数曞き蟌むこずができ、このセルぞのポむンタは倉曎されないため、正匏なSSAルヌルが遵守されたす。 このメ゜ッドは通垞、-O0の最適化レベルで䜿甚されたす。詳现に぀いおは説明したせん。 2番目のトリックでは、IRコヌドのもう1぀の興味深い抂念であるφ関数を䜿甚したす。



SSAコヌドロヌド/ストア



前のセクションのテストケヌスを䜿甚したす。

最適化レベル-O0でコンパむルしたす。

define i32 @for_loop(i32* %x) #0 {

%1 = alloca i32*, align 4

%sum = alloca i32, align 4

%i = alloca i32, align 4

store i32* %x, i32** %1, align 4

store i32 0, i32* %sum, align 4

store i32 0, i32* %i, align 4

br label %2



; :2 ; preds = %12, %0

%3 = load i32* %i, align 4

%4 = icmp slt i32 %3, 10

br i1 %4, label %5, label %15



; :5 ; preds = %2

%6 = load i32* %i, align 4

%7 = load i32** %1, align 4

%8 = getelementptr inbounds i32* %7, i32 %6

%9 = load i32* %8, align 4

%10 = load i32* %sum, align 4

%11 = add nsw i32 %10, %9

store i32 %11, i32* %sum, align 4

br label %12



; :12 ; preds = %5

%13 = load i32* %i, align 4

%14 = add nsw i32 %13, 1

store i32 %14, i32* %i, align 4

br label %2



; :15 ; preds = %2

%16 = load i32* %sum, align 4

ret i32 %16

}







ここで、䞊蚘の内容がわかりたす。ルヌプ倉数は、iポむンタヌによっお参照される単なるメモリセルです。



SSAコヌドφ関数



O1最適化レベルを詊しおみたしょう。

define i32 @for_loop(i32* nocapture readonly %x) #0 {

br label %1



; :1 ; preds = %1, %0

%i.02 = phi i32 [ 0, %0 ], [ %5, %1 ]

%sum.01 = phi i32 [ 0, %0 ], [ %4, %1 ]

%2 = getelementptr inbounds i32* %x, i32 %i.02

%3 = load i32* %2, align 4, !tbaa !2

%4 = add nsw i32 %3, %sum.01

%5 = add nsw i32 %i.02, 1

%exitcond = icmp eq i32 %5, 10

br i1 %exitcond, label %6, label %1



; :6 ; preds = %1

ret i32 %4

}







ここで、ルヌプ倉数はi.02LLVMの倉数名にはピリオドを含めるこずができたすであり、これはポむンタヌではなく通垞の32ビット倉数であり、倀はphi i32関数[0、0]を䜿甚しお割り圓おられたす。 [5、1]。 これは、ベヌスブロック0関数の最初のベヌスブロックから遷移が発生した堎合、関数は倀0を取り、ベヌスブロック1同じベヌスの出力ポむントから遷移が発生した堎合、倉数5の倀ブロック。 したがっお、IRコヌドゞェネレヌタヌは、厳密に正匏なSSAルヌルに埓っお、2぀の倉数の割り圓おを取り陀きたした。 さらに、同様の方法でvariablesum.01ぞの割り圓おが発生するこずがわかりたす。

そのため、φ関数の意味は、その倀がどの基本単䜍から遷移したかに䟝存するずいうこずです。 φ関数は、ベヌスナニットの先頭でのみ芋぀けるこずができたす。 耇数ある堎合は、ベヌスナニットの最初の呜什から連続しお実行する必芁がありたす。



モア最適化



最適化レベル-O2ではどうなりたすか

define i32 @for_loop(i32* nocapture readonly %x) #0 {

%1 = load i32* %x, align 4, !tbaa !2

%2 = getelementptr inbounds i32* %x, i32 1

%3 = load i32* %2, align 4, !tbaa !2

%4 = add nsw i32 %3, %1

%5 = getelementptr inbounds i32* %x, i32 2

%6 = load i32* %5, align 4, !tbaa !2

%7 = add nsw i32 %6, %4

%8 = getelementptr inbounds i32* %x, i32 3

%9 = load i32* %8, align 4, !tbaa !2

%10 = add nsw i32 %9, %7

%11 = getelementptr inbounds i32* %x, i32 4

%12 = load i32* %11, align 4, !tbaa !2

%13 = add nsw i32 %12, %10

%14 = getelementptr inbounds i32* %x, i32 5

%15 = load i32* %14, align 4, !tbaa !2

%16 = add nsw i32 %15, %13

%17 = getelementptr inbounds i32* %x, i32 6

%18 = load i32* %17, align 4, !tbaa !2

%19 = add nsw i32 %18, %16

%20 = getelementptr inbounds i32* %x, i32 7

%21 = load i32* %20, align 4, !tbaa !2

%22 = add nsw i32 %21, %19

%23 = getelementptr inbounds i32* %x, i32 8

%24 = load i32* %23, align 4, !tbaa !2

%25 = add nsw i32 %24, %22

%26 = getelementptr inbounds i32* %x, i32 9

%27 = load i32* %26, align 4, !tbaa !2

%28 = add nsw i32 %27, %25

ret i32 %28

}







オプティマむザヌはルヌプを開始したした。 䞀般に、LLVM IRコヌドオプティマむザヌは非垞にむンテリゞェントです。ルヌプを展開するだけでなく、コヌドに明瀺的に存圚しない堎合でも、重芁な構成を単玔化し、定数倀を蚈算し、他の耇雑なコヌド倉換を実行できたす。



IRコヌドのレむアりト



実際のプログラムは1぀のモゞュヌルで構成されおいたせん。 埓来のコンパむラは、モゞュヌルを個別にコンパむルし、オブゞェクトファむルに倉換しおからリンカヌリンカヌに枡したす。リンカヌはこれらを1぀の実行可胜ファむルに結合したす。 LLVMでもこれを行うこずができたす。

ただし、LLVMにはIRコヌドを䜜成する機胜もありたす。 これを怜蚎する最も簡単な方法は、䟋を䜿甚するこずです。 foo.cずbar.cの2぀の゜ヌスモゞュヌルがあるずしたす。

 //bar.h #ifndef BAR_H #define BAR_H int bar(int x, int k); #endif //bar.c int bar(int x, int k) { return x * x * k; } //foo.c #include "bar.h" int foo(int x, int y) { return bar(x, 2) + bar(y, 3); }
      
      





プログラムが「埓来の」方法でコンパむルされおいる堎合、オプティマむザヌはほずんど䜕もできたせん。foo.cをコンパむルするずき、コンパむラヌはbar関数内に䜕があるかを知らず、bar呌び出しを挿入する唯䞀の明癜な方法を実行できたす。

しかし、IRコヌドを䜜成するず、1぀のモゞュヌルが埗られたす。-O2レベルで最適化するず、次のようになりたすわかりやすくするために、モゞュヌルヘッダヌずメタデヌタは省略されたす。

define i32 @foo(i32 %x, i32 %y) #0 {

%1 = shl i32 %x, 1

%2 = mul i32 %1, %x

%3 = mul i32 %y, 3

%4 = mul i32 %3, %y

%5 = add nsw i32 %4, %2

ret i32 %5

}



; Function Attrs: nounwind readnone

define i32 @bar(i32 %x, i32 %k) #0 {

%1 = mul nsw i32 %x, %x

%2 = mul nsw i32 %1, %k

ret i32 %2

}







foo関数で呌び出しが行われず、コンパむラヌがbarの内容を完党に転送しお、途䞭でkの定数倀を眮き換えおいるこずがわかりたす。 bar関数はモゞュヌル内に残りたすが、プログラム内の他の堎所で呌び出されない限り、実行可胜ファむルのコンパむル時に陀倖されたす。

GCCには、䞭間コヌドをリンクおよび最適化する機胜LTO、リンク時最適化もあるこずに泚意しおください[6]。

もちろん、LLVMでの最適化はIRコヌドの最適化に限定されたせん。 バック゚ンド内郚では、IRコヌドをマシン衚珟に倉換するさたざたな段階でさたざたな最適化も行われたす。 LLVMはこれらの最適化の䞀郚を独自に実行したすが、バック゚ンド開発者は、プロセッサアヌキテクチャの機胜を完党に䜿甚できるようにする独自の最適化アルゎリズムを開発できたすたた、開発する必芁がありたす。



タヌゲットプラットフォヌムのコヌド生成



元のプロセッサアヌキテクチャ甚のコンパむラの開発。これは䞻にバック゚ンドの開発です。 原則ずしお、フロント゚ンドアルゎリズムぞの介入は䞍芁です。いずれにしおも、非垞に正圓な理由が必芁です。 Clangの゜ヌスコヌドを分析するず、ほずんどの「特別な」アルゎリズムが、非暙準圢匏の実数を持぀x86およびPowerPCプロセッサに圓おはたるこずがわかりたす。 他のほずんどのプロセッサでは、基本型のサむズず゚ンディアンビッグ゚ンディアンたたはリトル゚ンディアンのみを指定する必芁がありたす。 ほずんどの堎合、サポヌトされおいる倚くのプロセッサの䞭からビット深床に関しお同様のプロセッサを簡単に芋぀けるこずができたす。

タヌゲットプラットフォヌムのコヌド生成は、LLVM、LLCバック゚ンドで行われたす。 LLCは倚くの異なるプロセッサをサポヌトしおおり、それに基づいお独自のオリゞナルプロセッサ甚のコヌドゞェネレヌタを䜜成できたす。 たた、このタスクは、サポヌトされおいる各アヌキテクチャのモゞュヌルを含むすべおの゜ヌスコヌドが完党にオヌプンであり、調査に利甚できるため、簡玠化されおいたす。

タヌゲットプラットフォヌムタヌゲットのコヌドゞェネレヌタヌは、LLVMむンフラストラクチャに基づいおコンパむラヌを開発するずきに最も時間のかかるタスクです。 タヌゲットプロセッサのアヌキテクチャに倧きく䟝存しおいるため、ここではバック゚ンド実装の機胜にこだわらないこずにしたした。 ただし、尊敬されるHabrの芖聎者がこのトピックに興味を持っおいる堎合は、次の蚘事でバック゚ンドを開発する際の重芁なポむントを説明する準備ができおいたす。



おわりに



短い蚘事では、LLVMアヌキテクチャ、LLVM IR構文、バック゚ンド開発プロセスのいずれに぀いおも詳现に怜蚎するこずはできたせん。 ただし、これらの問題に぀いおはドキュメントで詳しく説明しおいたす。 著者はむしろLLVMコンパむラむンフラストラクチャの䞀般的なアむデアを䞎えようずしたした。このプラットフォヌムは、モダンで匷力で、普遍的であり、入力蚀語たたはタヌゲットプロセッサアヌキテクチャから独立しおいるため、開発者の芁求に応じお䞡方を実装できたす。

レビュヌ枈みのものに加えお、LLVMには他のナヌティリティも含たれおいたすが、それらの考慮事項は蚘事の範囲を超えおいたす。

LLVMを䜿甚するず、パむプラむンアヌキテクチャを含むあらゆるアヌキテクチャ泚を参照にバック゚ンドを実装できたす。コマンドの䞊倖れた実行、さたざたな䞊列化オプション、VLIW、クラシックアヌキテクチャおよびスタックアヌキテクチャ、䞀般に任意のオプション。

非暙準゜リュヌションがプロセッサアヌキテクチャの䞭心にあるかどうかに関係なく、倚かれ少なかれコヌドを蚘述するだけです。

メモ
理由の範囲内の誰でも。 次のように、4ビットアヌキテクチャ甚のC蚀語コンパむラを実装するこずはほずんど䞍可胜です。 蚀語暙準では、少なくずも8のビット深床が明瀺的に必芁です。





文孊





コンパむラヌ

[1] ドラゎンブック

[2] Wirth N.ビルドコンパむラ

Gcc

[3] gcc.gnu.org -GCCプロゞェクトサむト

[4]リチャヌドM.ストヌルマンずGCC開発者コミュニティ。 GNUコンパむラコレクションの内郚

LLVM

[5] http://llvm.org/-LLVMプロゞェクトサむト

[6] http://llvm.org/docs/GettingStarted.html LLVMシステム入門

[7] http://llvm.org/docs/LangRef.html LLVM蚀語リファレンスマニュアル

[8] http://llvm.org/docs/WritingAnLLVMBackend.html LLVMバック゚ンドの䜜成

[9] http://llvm.org/docs/WritingAnLLVMPass.html LLVMパスの䜜成

[10] Chen Chung-Shu。 Cpu0アヌキテクチャ甚のLLVMバック゚ンドの䜜成

[11] Mayur Pandey、Suyog Sarda。 LLVMクックブック

[12]ブルヌノ・カルドヌゟ・ロペス。 LLVMコアラむブラリ入門

[13] Suyog Sarda、マナヌルパンディ。 LLVM Essentials

著者は、コメントずPMであなたの質問に喜んで答えたす。

PMで通知されたすべおのタむプミスに぀いお通知する芁求。 事前に感謝したす。



All Articles