LLVMビットコードファイルフォーマット

概要

このドキュメントでは、LLVMビットストリームファイルフォーマットと、LLVM IRのそのフォーマットへのエンコーディングについて説明します。

概要

一般的にLLVMビットコードファイルフォーマット(時代錯誤的にバイトコードと呼ばれることもある)として知られているものは、実際には2つのものから構成されています。それはビットストリームコンテナフォーマットと、そのコンテナフォーマットへのLLVM IRのエンコーディングです。

ビットストリームフォーマットは、構造化データの抽象的なエンコーディングであり、ある意味ではXMLと非常によく似ています。XMLと同様に、ビットストリームファイルにはタグと入れ子構造が含まれており、タグを理解しなくてもファイルを解析できます。XMLとは異なり、ビットストリームフォーマットはバイナリエンコーディングであり、XMLとは異なり、ファイルが「省略記号」(コンテンツのサイズ最適化に効果的なもの)を自己記述するメカニズムを提供します。

LLVM IRファイルは、オプションでラッパー構造体、またはネイティブオブジェクトファイルに埋め込むことができます。これら2つのメカニズムにより、LLVM IRファイルと共に追加データを簡単に埋め込むことができます。

このドキュメントでは、最初にLLVMビットストリームフォーマット、ラッパーフォーマットについて説明し、次にLLVM IRファイルで使用されるレコード構造について説明します。

ビットストリームフォーマット

ビットストリームフォーマットは、文字通りビットのストリームであり、非常に単純な構造を持っています。この構造は、以下の概念で構成されています。

  • ストリームの内容を識別する「マジックナンバー」。

  • プリミティブ(可変ビットレート整数など)のエンコーディング。

  • ブロックは、入れ子になったコンテンツを定義します。

  • データレコードは、ファイル内のエンティティを記述します。

  • 省略記号は、ファイルの圧縮最適化を指定します。

llvm-bcanalyzerツールを使用すると、任意のビットストリームをダンプして検査することができ、エンコーディングの理解に非常に役立ちます。

マジックナンバー

ビットストリームの先頭4バイトは、アプリケーション固有のマジックナンバーとして使用されます。一般的なビットコードツールは、先頭4バイトを見て、ストリームが既知のストリームタイプかどうかを判断できます。ただし、これらのツールは、マジックナンバーだけでビットストリームが有効かどうかを判断すべきではありません。新しいアプリケーション固有のビットストリームフォーマットは常に開発されており、ツールはこれまでに見られなかったマジックナンバーを持っているという理由だけでそれらを拒否するべきではありません。

プリミティブ

ビットストリームは、文字通りビットのストリームで構成され、各バイトの最下位ビットから順番に読み取られます。ストリームは、符号なし整数のストリームをエンコードするいくつかのプリミティブ値で構成されています。これらの整数は、固定幅整数または可変幅整数の2つの方法でエンコードされます。

固定幅整数

固定幅整数の値は、その下位ビットがファイルに直接出力されます。たとえば、3ビットの整数の値は、1を001としてエンコードします。固定幅整数は、フィールドに既知のオプションの数がある場合に使用されます。たとえば、ブール値は通常、1ビット幅の整数でエンコードされます。

可変幅整数

可変幅整数(VBR)値は、任意のサイズの値をエンコードし、値が小さい場合に最適化されます。4ビットのVBRフィールドの場合、任意の3ビット値(0〜7)は、上位ビットが0に設定されて直接エンコードされます。N-1ビットより大きい値は、そのビットをN-1ビットチャンクのシリーズで出力します。最後のチャンクを除くすべての上位ビットが設定されます。

たとえば、値30(0x1E)は、vbr4値として出力されると、62(0b0011’1110)としてエンコードされます。最下位ビットから始まる最初の4ビットのセットは、継続部分(上位ビットが1で示される)を持つ値6(110)を示します。次の4ビットのセットは、継続部分のない値24(011 << 3)を示します。合計(6+24)は値30になります。

6ビット文字

6ビット文字は、一般的な文字を固定6ビットフィールドにエンコードします。それらは、以下の6ビット値で以下の文字を表します。

'a' .. 'z' ---  0 .. 25
'A' .. 'Z' --- 26 .. 51
'0' .. '9' --- 52 .. 61
       '.' --- 62
       '_' --- 63

このエンコーディングは、上記の文字のみで構成される文字列と文字のエンコーディングにのみ適しています。セットにない文字をエンコードすることは完全にできません。

ワードアラインメント

場合によっては、ビットストリームが32ビットの倍数になるまでゼロビットを出力することが役立ちます。これにより、ストリーム内のビット位置を32ビットワードの倍数として表すことができます。

省略記号ID

ビットストリームは、ブロックデータレコードのシーケンシャルなシリーズです。これらは両方とも、固定ビット幅フィールドとしてエンコードされた省略記号IDで始まります。幅は、以下で説明するように、現在のブロックによって指定されます。省略記号IDの値は、組み込みID(以下で定義されている特別な意味を持つ)またはストリーム自体によって現在のブロックに対して定義された省略記号IDのいずれかを指定します。

組み込み省略記号IDのセットは次のとおりです。

  • 0 - END_BLOCK — この省略記号IDは、現在のブロックの終了を示します。

  • 1 - ENTER_SUBBLOCK — この省略記号IDは、新しいブロックの開始を示します。

  • 2 - DEFINE_ABBREV — これは新しい省略記号を定義します。

  • 3 - UNABBREV_RECORD — このIDは、省略されていないレコードの定義を指定します。

省略記号ID 4以上は、ストリーム自体によって定義され、省略されたレコードエンコーディングを指定します。

ブロック

ビットストリームのブロックは、ストリームの入れ子になった領域を示し、コンテンツ固有のID番号で識別されます(たとえば、LLVM IRは関数本体を表すためにID 12を使用します)。ブロックID 0〜7は、意味がBitcodeによって定義されている標準ブロック用に予約されており、ブロックID 8以上はアプリケーション固有です。入れ子になったブロックは、それにエンコードされたデータの階層構造を捉え、ファイルが解析されると、さまざまなプロパティがブロックに関連付けられます。ブロックの定義により、リーダーは、ブロックの概要が必要な場合、または理解できないデータを効率的にスキップする必要がある場合、定数時間でブロックを効率的にスキップできます。LLVM IRリーダーは、このメカニズムを使用して関数本体をスキップし、必要に応じて遅延読み込みを行います。

ストリームを読み書きする際、ブロックに対していくつかのプロパティが維持されます。特に、各ブロックは次のものを維持します。

  1. 現在の省略記号ID幅。この値はストリームの開始時に2から始まり、ブロックレコードが入力されるたびに設定されます。ブロックエントリは、ブロックの本体の省略記号ID幅を指定します。

  2. 省略記号のセット。省略記号はブロック内で定義できます。その場合、そのブロック内でのみ定義されます(サブブロックも包含ブロックも省略記号を参照しません)。省略記号はBLOCKINFOブロック内にも定義できます。その場合、BLOCKINFOブロックが記述しているIDと一致するすべてのブロックで定義されます。

サブブロックが入力されると、これらのプロパティが保存され、新しいサブブロックには独自の省略記号セットと独自の省略記号ID幅が設定されます。サブブロックがポップされると、保存された値が復元されます。

ENTER_SUBBLOCK エンコーディング

[ENTER_SUBBLOCK, blockidvbr8, newabbrevlenvbr4, <align32bits>, blocklen_32]

ENTER_SUBBLOCK は、新しいブロックレコードの開始を指定する省略記号IDです。blockid の値は8ビットVBR識別子としてエンコードされ、入力されるブロックの種類を示します。これは標準ブロックまたはアプリケーション固有のブロックのいずれかです。newabbrevlen の値は4ビットVBRで、サブブロックの省略記号ID幅を指定します。blocklen の値は32ビット境界に整列された値で、サブブロックのサイズを32ビットワード単位で指定します。この値により、リーダーは一度のジャンプでブロック全体をスキップできます。

END_BLOCK エンコーディング

[END_BLOCK, <align32bits>]

END_BLOCK 省略記号IDは、現在のブロックレコードの終了を指定します。その終了は32ビット境界に整列され、ブロックサイズが32ビットの偶数倍になるようにします。

データレコード

データレコードは、レコードコードと複数の(最大)64ビット整数値で構成されます。コードと値の解釈はアプリケーション固有であり、異なるブロックタイプ間で異なる場合があります。レコードは、未省略レコードを使用してエンコードすることも、省略記号を使用してエンコードすることもできます。たとえば、LLVM IR形式では、モジュールのターゲットトリプルをエンコードするレコードがあります。コードはMODULE_CODE_TRIPLEで、レコードの値は文字列内の文字のASCIIコードです。

UNABBREV_RECORD エンコーディング

[UNABBREV_RECORD, codevbr6, numopsvbr6, op0vbr6, op1vbr6, …]

UNABBREV_RECORD は、完全に汎用的で非常に非効率的なデフォルトのフォールバックエンコーディングを提供します。コードとオペランドをVBRとして出力することで、任意のレコードを記述できます。

たとえば、LLVM IRターゲットトリプルを未省略レコードとして出力するには、UNABBREV_RECORD abbrevid、MODULE_CODE_TRIPLE コードのvbr6、文字列の長さ(オペランドの数に等しい)のvbr6、および各文字のvbr6を出力する必要があります。32未満の値を持つ文字がないため、各文字は少なくとも2部構成のVBRとして出力する必要があり、これは各文字に少なくとも12ビットが必要であることを意味します。これは効率的なエンコーディングではありませんが、完全に汎用的です。

省略記号付きレコードエンコーディング

[<abbrevid>, fields...]

省略記号付きレコードは、省略記号IDと、省略記号定義に従ってエンコードされたフィールドのセットで構成されます。これにより、UNABBREV_RECORD型でエンコードされたレコードよりも大幅に高密度にレコードをエンコードでき、ストリーム自体で省略記号の種類を指定できるため、ファイルは完全に自己記述可能になります。省略記号の実際のエンコーディングは以下で定義されています。

省略記号付きレコードの最初のフィールドであるレコードコードは、省略記号定義(リテラルオペランドとして)でエンコードすることも、省略記号付きレコード(固定またはVBRオペランド値として)で提供することもできます。

省略記号

省略記号は、ビットストリームの重要な圧縮形式です。これは、レコードのクラスの高密度エンコーディングを一度指定し、そのエンコーディングを使用して多くのレコードを出力するというアイデアです。エンコーディングをファイルに出力するにはスペースが必要ですが、スペースは(おそらくプラスアルファで)エンコーディングを使用するレコードが出力されるときに回収されます。

省略記号は、クライアントごと、ファイルごとに動的に決定できます。省略記号はビットストリーム自体に格納されているため、同じ形式の異なるストリームには、特定のストリームのニーズに応じて異なる省略記号セットを含めることができます。具体的な例として、LLVM IRファイルは通常、バイナリ演算子の省略記号を出力します。特定のLLVMモジュールにバイナリ演算子が存在しないか、少ない場合、省略記号を出力する必要はありません。

DEFINE_ABBREV エンコーディング

[DEFINE_ABBREV, numabbrevopsvbr5, abbrevop0, abbrevop1, …]

DEFINE_ABBREV レコードは、このブロックのスコープ内で現在定義されている省略記号のリストに省略記号を追加します。この定義は、この直近のブロック内でのみ有効です。サブブロックまたは上位ブロックでは表示されません。省略記号には、4(最初のアプリケーション定義の省略記号ID)から順番にIDが暗黙的に割り当てられます。特定のブロックタイプのBLOCKINFOレコードで定義された省略記号には、最初に順番にIDが割り当てられ、その後にブロック自体内で定義された省略記号が続きます。省略記号付きデータレコードは、このIDを参照して、呼び出している省略記号を示します。

省略記号の定義は、DEFINE_ABBREV abbrevid、省略記号オペランドの数を指定するVBR、および省略記号オペランド自体で構成されます。省略記号オペランドは3つの形式があります。すべて、省略記号オペランドがリテラルオペランドである場合(ビットが1の場合)またはエンコーディングオペランドである場合(ビットが0の場合)を示す1ビットで始まります。

  1. リテラルオペランド — [11, litvaluevbr8] — リテラルオペランドは、結果の値が常に1つの特定の値であることを指定します。この特定の値は、リテラルオペランドであることを示すビットの後にvbr8として出力されます。

  2. データなしのエンコーディング情報 — [01, encoding3] — 余分なデータを持たないオペランドエンコーディングは、そのコードとして出力されます。

  3. データを含むエンコーディング情報 — [01, encoding3, valuevbr5] — 余分なデータを持つオペランドエンコーディングは、そのコードと、その後の余分なデータとして出力されます。

可能なオペランドエンコーディングは次のとおりです。

  • 固定(コード1):フィールドは、固定幅の値として出力する必要があります。その幅は、オペランドの追加データで指定されます。

  • VBR(コード2):フィールドは、可変幅の値として出力する必要があります。その幅は、オペランドの追加データで指定されます。

  • 配列(コード3):このフィールドは値の配列です。配列オペランドには追加データがありませんが、その後に別のオペランドが続き、配列の要素タイプを示す必要があります。省略記号付きレコードで配列を読み取るときは、最初の整数は配列の長さを示すvbr6であり、その後に配列のエンコードされた要素が続きます。配列は、(配列の型を与える最後の1つのオペランドを除いて)省略記号の最後のオペランドとしてのみ出現できます。

  • Char6(コード4):このフィールドは、Char6エンコード値として出力する必要があります。このオペランドタイプは追加データを取りません。Char6エンコーディングは通常、配列要素タイプとして使用されます。

  • Blob(コード5):このフィールドはvbr6として出力され、その後に32ビット境界へのパディング(アライメント用)、および8ビットオブジェクトの配列が続きます。バイトの配列の後に、その合計長が4バイトの倍数になるようにテールパディングが続きます。これにより、リーダーはデータのコピーを作成する必要なく、データのデコードを非常に効率的に行うことができます。マップされたファイル内のデータへのポインターを使用し、直接アクセスできます。Blobは、省略記号の最後のオペランドとしてのみ出現できます。

たとえば、LLVMモジュールのターゲットトリプルは、[TRIPLE, 'a', 'b', 'c', 'd']という形式のレコードとしてエンコードされます。ビットストリームが次のabbrevエントリを出力した場合を考えてみます。

[0, Fixed, 4]
[0, Array]
[0, Char6]

この省略記号を使用してレコードを出力すると、上記のエントリは次のように出力されます。

[4abbrevwidth, 24, 4vbr6, 06, 16, 26, 36]

これらの値は次のとおりです。

  1. 最初の値4は、この省略記号の省略記号IDです。

  2. 2番目の値2は、LLVM IRファイルMODULE_BLOCKブロック内のTRIPLEレコードのレコードコードです。

  3. 3番目の値4は、配列の長さです。

  4. 残りの値は、"abcd"のChar6エンコード値です。

この省略記号を使用すると、トリプルはわずか37ビットで出力されます(abbrev ID幅が3と仮定)。省略記号を使用しないと、ターゲットトリプルの出力にははるかに多くのスペースが必要です。また、TRIPLE値は省略記号内でリテラルとして出力されないため、省略記号は他の文字列値にも使用できます。

標準ブロック

基本的なブロック構造とレコードエンコーディングに加えて、ビットストリームは特定の組み込みブロックタイプも定義します。これらのブロックタイプは、ストリームのデコード方法またはその他のメタデータを示します。将来、新しい標準ブロックが追加される可能性があります。ブロックID 0~7は標準ブロック用に予約されています。

#0 - BLOCKINFOブロック

BLOCKINFO ブロックを使用すると、他のブロックのメタデータを記述できます。現在指定されているレコードは次のとおりです。

[SETBID (#1), blockid]
[DEFINE_ABBREV, ...]
[BLOCKNAME, ...name...]
[SETRECORDNAME, RecordID, ...name...]

SETBID レコード(コード1)は、どのブロックIDが記述されているかを示します。SETBID レコードは、ブロック全体で複数回出現して、記述されているブロックIDを変更できます。他のレコードの前にSETBIDレコードが存在する必要があります。

標準のDEFINE_ABBREVレコードはBLOCKINFOブロック内に存在できますが、通常のブロック内での出現とは異なり、省略記号は記述しているブロックIDに対して定義され、BLOCKINFOブロック自体ではありません。BLOCKINFOブロックで定義された省略記号には、DEFINE_ABBREVで説明されているように省略記号IDが割り当てられます。

このブロックには、オプションとしてBLOCKNAMEレコード(コード2)を含めることができます。このレコードの要素は、ブロックの文字列名を表すバイトです。llvm-bcanalyzerはこの情報を使用して、ビットコードファイルをシンボリックにダンプアウトできます。

このブロックには、オプションとしてSETRECORDNAMEレコード(コード3)を含めることもできます。最初のオペランド値はレコードID番号で、レコードの残りの要素はレコードの文字列名を表すバイトです。llvm-bcanalyzerはこの情報を使用して、ビットコードファイルをシンボリックにダンプアウトできます。

BLOCKINFOブロックのデータは「メタデータ」として記述されていますが、それらが含む略語は対応するブロックからのレコードを解析するために不可欠です。これらをスキップすることは安全ではありません。

ビットコードラッパー形式

LLVM IRのビットコードファイルは、オプションで単純なラッパー構造にラップできます。この構造には、埋め込まれたBCファイルのオフセットとサイズを示す単純なヘッダーが含まれています。これにより、BCファイルと共に追加情報を保存できます。このファイルヘッダーの構造は次のとおりです。

[Magic32, Version32, Offset32, Size32, CPUType32]

各フィールドは、リトルエンディアン形式で格納された32ビットフィールドです(ビットコードファイルの他のフィールドと同様)。マジックナンバーは常に0x0B17C0DEで、バージョンは現在常に0です。Offsetフィールドはファイル内のビットコードストリームの先頭までのオフセット(バイト単位)、Sizeフィールドはストリームのサイズ(バイト単位)です。CPUTypeは、ターゲットのCPUをエンコードするために使用できるターゲット固有の値です。

ネイティブオブジェクトファイルラッパー形式

LLVM IRのビットコードファイルは、ネイティブオブジェクトファイル(つまり、ELF、COFF、Mach-O)にラップすることもできます。ビットコードは、MachOの場合は__LLVM,__bitcode、他のオブジェクト形式の場合は.llvmbcという名前のオブジェクトファイルのセクションに格納する必要があります。ELFオブジェクトは、FatLTO用の.llvm.ltoセクションもサポートしており、LTOコンパイルに適したビットコード(つまり、プリリンクLTOパイプラインを通過したビットコード)が含まれています。.llvmbcセクションはLLVMでのFatLTOサポートよりも前に存在しており、常にLTOに適したビットコード(つまり、-fembed-bitcodeからのもの)が含まれているとは限りません。このラッパー形式は、中間オブジェクトが他のセクションにメタデータを含むネイティブオブジェクトファイルでなければならないコンパイルパイプラインでLTOに対応するために役立ちます。

すべてのツールがこの形式をサポートしているわけではありません。たとえば、lldとgoldプラグインは、オブジェクトファイルをリンクする際に.llvmbcセクションを無視しますが、正しいコマンドラインオプションを渡すと.llvm.ltoセクションを使用できます。

LLVM IRエンコーディング

LLVM IRは、ブロックとレコードを定義することでビットストリームにエンコードされます。定数プール、関数、シンボルテーブルなどにはブロックを使用し、命令、グローバル変数記述子、型記述などにはレコードを使用します。このドキュメントでは、ライターが使用する略語のセットについては説明しません。これらはファイル内で完全に自己記述されており、リーダーはこれに関する知識を組み込むことは許可されていません。

基本事項

LLVM IRマジックナンバー

LLVM IRファイルのマジックナンバーは次のとおりです。

[‘B’8, ‘C’8, 0x04, 0xC4, 0xE4, 0xD4]

符号付きVBR

可変幅整数エンコーディングは、任意のサイズの符号なし値をエンコードするための効率的な方法ですが、符号付き値をエンコードするためには非常に非効率です。符号付き値は、それ以外の場合、最大限に大きな符号なし値として扱われます。

そのため、特定の幅の符号付きVBR値は次のように出力されます。

  • 正の値は、指定された幅のVBRとして出力されますが、その値は1つ左にシフトされます。

  • 負の値は、指定された幅のVBRとして出力されますが、負の値は1つ左にシフトされ、最下位ビットが設定されます。

このエンコーディングにより、小さな正の値と小さな負の値の両方を効率的に出力できます。符号付きVBRエンコーディングは、CONSTANTS_BLOCKブロック内のCST_CODE_INTEGERおよびCST_CODE_WIDE_INTEGERレコードで使用されます。また、MODULE_CODE_VERSION 1のphi命令オペランドにも使用されます。

LLVM IRブロック

LLVM IRは、次のブロックで定義されます。

  • 8 — MODULE_BLOCK — モジュール全体を含む最上位のブロックで、さまざまなモジュールごとの情報を記述します。

  • 9 — PARAMATTR_BLOCK — パラメーター属性を列挙します。

  • 10 — PARAMATTR_GROUP_BLOCK — 属性グループテーブルを記述します。

  • 11 — CONSTANTS_BLOCK — モジュールまたは関数の定数を記述します。

  • 12 — FUNCTION_BLOCK — 関数本体を記述します。

  • 14 — VALUE_SYMTAB_BLOCK — 値シンボルテーブルを記述します。

  • 15 — METADATA_BLOCK — メタデータ項目を記述します。

  • 16 — METADATA_ATTACHMENT — 関数命令値にメタデータを関連付けるレコードが含まれています。

  • 17 — TYPE_BLOCK — モジュール内のすべての型を記述します。

  • 23 — STRTAB_BLOCK — ビットコードファイルの文字列テーブル。

MODULE_BLOCKの内容

MODULE_BLOCKブロック(ID 8)はLLVMビットコードファイルの最上位ブロックであり、ビットコードファイル内の各モジュールには正確に1つ含まれている必要があります。マルチモジュールビットコードを含むビットコードファイルも有効です。モジュールに関する情報を含むレコード(以下に説明)に加えて、MODULE_BLOCKブロックには、次のサブブロックを含めることができます。

MODULE_CODE_VERSIONレコード

[VERSION, version#]

VERSIONレコード(コード1)には、形式バージョンを示す単一の値が含まれています。現在、バージョン0、1、2がサポートされています。バージョン0と1の違いは、各FUNCTION_BLOCKの命令オペランドのエンコーディングにあります。

バージョン0では、命令によって定義された各値には、関数に固有のIDが割り当てられます。関数レベルの値IDはNumModuleValuesから割り当てられます。なぜなら、それらはモジュールレベルの値と同じ名前空間を共有するからです。値列挙子は、各関数後にリセットされます。値が命令のオペランドである場合、値IDを使用してオペランドを表します。大きな関数または大きなモジュールの場合、これらのオペランド値は大きくなる可能性があります。

バージョン1のエンコーディングでは、一般的なケースで大きなオペランド値を回避しようとします。値IDを直接使用する代わりに、オペランドは現在の命令に対する相対値としてエンコードされます。したがって、オペランドが前の命令によって定義された値である場合、オペランドは1としてエンコードされます。

たとえば、次のようになります。

#n = load #n-1
#n+1 = icmp eq #n, #const0
br #n+1, label #(bb1), label #(bb2)

バージョン1では、命令は次のようにエンコードされます。

#n = load #1
#n+1 = icmp eq #1, (#n+1)-#const0
br #1, label #(bb1), label #(bb2)

この例では、定数であるオペランドも相対エンコーディングを使用しますが、基本ブロックラベルなどのオペランドは相対エンコーディングを使用しません。

前方参照は負の値になります。オペランドは通常符号なしVBRとしてエンコードされるため、これは非効率になる可能性があります。ただし、phi命令の場合を除き、前方参照はまれです。phi命令の場合、オペランドは符号付きVBRとしてエンコードされ、前方参照に対処します。

バージョン2では、モジュールレコードFUNCTIONGLOBALVARALIASIFUNCCOMDATの意味が変更され、最初の2つのオペランドが文字列テーブル内の文字列のオフセットとサイズを指定するようになり(STRTAB_BLOCKの内容を参照)、関数名が値シンボルテーブルのFNENTRYレコードから削除され、最上位のVALUE_SYMTAB_BLOCKにはFNENTRYレコードのみが含まれる場合があります。

MODULE_CODE_TRIPLE レコード

[TRIPLE, ...string...]

TRIPLE レコード(コード 2)は、target triple 仕様文字列のバイトを表す可変数の値を含みます。

MODULE_CODE_DATALAYOUT レコード

[DATALAYOUT, ...string...]

DATALAYOUT レコード(コード 3)は、target datalayout 仕様文字列のバイトを表す可変数の値を含みます。

MODULE_CODE_ASM レコード

[ASM, ...string...]

ASM レコード(コード 4)は、module asm 文字列のバイトを表す可変数の値を含みます。個々のアセンブリブロックは改行文字(ASCII 10)で区切られています。

MODULE_CODE_SECTIONNAME レコード

[SECTIONNAME, ...string...]

SECTIONNAME レコード(コード 5)は、単一のセクション名文字列のバイトを表す可変数の値を含みます。GLOBALVAR または FUNCTION レコード内の *section* フィールドで参照される各セクション名に対して、1 つの SECTIONNAME レコードが必要です。(例:グローバル変数または関数の section 属性内)。これらのレコードは、GLOBALVAR または FUNCTION レコードの *section* フィールド内の 1 ベースのインデックスで参照できます。

MODULE_CODE_DEPLIB レコード

[DEPLIB, ...string...]

DEPLIB レコード(コード 6)は、deplibs 宣言で言及されているライブラリのうち、単一の依存ライブラリ名文字列のバイトを表す可変数の値を含みます。参照される各ライブラリ名に対して、1 つの DEPLIB レコードが必要です。

MODULE_CODE_GLOBALVAR レコード

[GLOBALVAR, strtab offset, strtab size, pointer type, isconst, initid, linkage, alignment, section, visibility, threadlocal, unnamed_addr, externally_initialized, dllstorageclass, comdat, attributes, preemptionspecifier]

GLOBALVAR レコード(コード 7)は、グローバル変数の宣言または定義を示します。オペランドフィールドは次のとおりです。

  • strtab offset, strtab size: グローバル変数の名前を指定します。STRTAB_BLOCK の内容を参照してください。

  • pointer type: このグローバル変数を指すために使用されるポインター型の型インデックス

  • isconst: 変数がモジュール内で定数として扱われる場合は 0 以外、そうでない場合は 0

  • initid: 0 以外の場合、この変数の初期化子の値インデックス + 1。

  • linkage: この変数のリンケージタイプのエンコード

    • external: コード 0

    • weak: コード 1

    • appending: コード 2

    • internal: コード 3

    • linkonce: コード 4

    • dllimport: コード 5

    • dllexport: コード 6

    • extern_weak: コード 7

    • common: コード 8

    • private: コード 9

    • weak_odr: コード 10

    • linkonce_odr: コード 11

    • available_externally: コード 12

    • 非推奨: コード 13

    • 非推奨: コード 14

  • alignment*: 変数の要求されたアライメントの底辺 2 の対数 + 1

  • section: 0 以外の場合、MODULE_CODE_SECTIONNAME エントリのテーブル内の 1 ベースのセクションインデックス。

  • visibility: 存在する場合、この変数の可視性のエンコード

    • default: コード 0

    • hidden: コード 1

    • protected: コード 2

  • threadlocal: 存在する場合、変数のスレッドローカルストレージモードのエンコード

    • not thread local: コード 0

    • thread local; default TLS model: コード 1

    • localdynamic: コード 2

    • initialexec: コード 3

    • localexec: コード 4

  • unnamed_addr: 存在する場合、この変数の unnamed_addr 属性のエンコード

    • not unnamed_addr: コード 0

    • unnamed_addr: コード 1

    • local_unnamed_addr: コード 2

  • dllstorageclass: 存在する場合、この変数の DLL ストレージクラスのエンコード

    • default: コード 0

    • dllimport: コード 1

    • dllexport: コード 2

  • comdat: この関数の COMDAT のエンコード

  • attributes: 0 以外の場合、AttributeLists テーブル内の 1 ベースのインデックス。

  • preemptionspecifier: 存在する場合、この変数のランタイムプリエンプション指定子のエンコード

    • dso_preemptable: コード 0

    • dso_local: コード 1

MODULE_CODE_FUNCTION レコード

[FUNCTION, strtab offset, strtab size, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata, personalityfn, preemptionspecifier]

FUNCTION レコード(コード 8)は、関数の宣言または定義を示します。オペランドフィールドは次のとおりです。

  • strtab offset, strtab size: 関数の名前を指定します。STRTAB_BLOCK の内容を参照してください。

  • type: この関数を記述する関数型の型インデックス

  • callingconv: 呼び出し規約番号: * ccc: コード 0 * fastcc: コード 8 * coldcc: コード 9 * anyregcc: コード 13 * preserve_mostcc: コード 14 * preserve_allcc: コード 15 * swiftcc : コード 16 * cxx_fast_tlscc: コード 17 * tailcc : コード 18 * cfguard_checkcc : コード 19 * swifttailcc : コード 20 * x86_stdcallcc: コード 64 * x86_fastcallcc: コード 65 * arm_apcscc: コード 66 * arm_aapcscc: コード 67 * arm_aapcs_vfpcc: コード 68

  • isproto*: このエントリが定義ではなく宣言を表す場合は 0 以外

  • linkage: この関数のリンケージタイプのエンコード

  • paramattr: 0 以外の場合、PARAMATTR_CODE_ENTRY エントリのテーブル内の 1 ベースのパラメーター属性インデックス。

  • alignment: 関数の要求されたアライメントの底辺 2 の対数 + 1

  • section: 0 以外の場合、MODULE_CODE_SECTIONNAME エントリのテーブル内の 1 ベースのセクションインデックス。

  • visibility: この関数の可視性のエンコード

  • gc: 存在し、0 以外の場合、MODULE_CODE_GCNAME エントリのテーブル内の 1 ベースのガベージコレクターインデックス。

  • unnamed_addr: 存在する場合、この関数のunnamed_addr 属性のエンコード

  • prologuedata: 0 以外の場合、この関数のプロローグデータの値インデックス + 1。

  • dllstorageclass: この関数のdllstorageclassのエンコード

  • comdat: この関数の COMDAT のエンコード

  • prefixdata: 0 以外の場合、この関数のプレフィックスデータの値インデックス + 1。

  • personalityfn: 0 以外の場合、この関数のパーソナリティ関数の値インデックス + 1。

  • preemptionspecifier: 存在する場合、この関数のランタイムプリエンプション指定子のエンコード。

MODULE_CODE_ALIAS レコード

[ALIAS, strtab offset, strtab size, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr, preemptionspecifier]

ALIAS レコード(コード 9)は、エイリアスの定義を示します。オペランドフィールドは次のとおりです。

  • strtab offset, strtab size: エイリアスの名前を指定します。STRTAB_BLOCK の内容を参照してください。

  • alias type: エイリアスの型インデックス

  • aliasee val#: エイリアスされた値の値インデックス

  • linkage: このエイリアスのリンケージタイプのエンコーディング

  • visibility: 存在する場合、エイリアスの可視性のエンコーディング

  • dllstorageclass: 存在する場合、エイリアスのdllstorageclassのエンコーディング

  • threadlocal: 存在する場合、エイリアスのスレッドローカルプロパティのエンコーディング

  • unnamed_addr: 存在する場合、このエイリアスのunnamed_addr属性のエンコーディング

  • preemptionspecifier: 存在する場合、このエイリアスのランタイムプリエンプション指定子のエンコーディング。

MODULE_CODE_GCNAME レコード

[GCNAME, ...string...]

GCNAMEレコード(コード11)は、単一のガベージコレクタ名文字列のバイトを表す可変数の値を含みます。モジュール内の関数gc属性で参照される各ガベージコレクタ名に対して、1つのGCNAMEレコードが存在する必要があります。これらのレコードは、FUNCTIONレコードのgcフィールド内で、1ベースのインデックスで参照できます。

PARAMATTR_BLOCK 内容

PARAMATTR_BLOCKブロック(ID 9)には、関数パラメータの属性を記述するエントリのテーブルが含まれています。これらのエントリは、モジュールブロックFUNCTIONレコードのparamattrフィールド内、または関数ブロックINST_INVOKEおよびINST_CALLレコードのattrフィールド内で、1ベースのインデックスで参照されます。

PARAMATTR_BLOCK内のエントリは、それぞれがユニークになるように構築されています(つまり、2つのインデックスが等価な属性リストを表すことはありません)。

PARAMATTR_CODE_ENTRY レコード

[ENTRY, attrgrp0, attrgrp1, ...]

ENTRYレコード(コード2)は、関数パラメータ属性の一意のセットを記述する可変数の値を含みます。各attrgrp値は、PARAMATTR_GROUP_BLOCKブロックで説明されている属性グループテーブルのエントリを検索するためのキーとして使用されます。

PARAMATTR_CODE_ENTRY_OLD レコード

注記

これは、LLVMバージョン3.2以前によって生成された、属性のレガシーエンコーディングです。IR後方互換性ポリシーで指定されているように、現在のLLVMバージョンで確実に理解されます。

[ENTRY, paramidx0, attr0, paramidx1, attr1...]

ENTRYレコード(コード1)は、関数パラメータ属性の一意のセットを記述する偶数の値を含みます。各paramidx値は、どの属性セットを表すかを示します。0は戻り値の属性、0xFFFFFFFFは関数の属性、その他の値は1ベースの関数パラメータを表します。各attr値は、次の解釈を持つビットマップです。

  • ビット0: zeroext

  • ビット1: signext

  • ビット2: noreturn

  • ビット3: inreg

  • ビット4: sret

  • ビット5: nounwind

  • ビット6: noalias

  • ビット7: byval

  • ビット8: nest

  • ビット9: readnone

  • ビット10: readonly

  • ビット11: noinline

  • ビット12: alwaysinline

  • ビット13: optsize

  • ビット14: ssp

  • ビット15: sspreq

  • ビット16-31: align n

  • ビット32: nocapture

  • ビット33: noredzone

  • ビット34: noimplicitfloat

  • ビット35: naked

  • ビット36: inlinehint

  • ビット37-39: alignstack n(要求されたアライメントの底辺2の対数プラス1として表される)

PARAMATTR_GROUP_BLOCK 内容

PARAMATTR_GROUP_BLOCKブロック(ID 10)には、モジュールに存在する属性グループを記述するエントリのテーブルが含まれています。これらのエントリは、PARAMATTR_CODE_ENTRYエントリ内で参照できます。

PARAMATTR_GRP_CODE_ENTRY レコード

[ENTRY, grpid, paramidx, attr0, attr1, ...]

ENTRYレコード(コード3)は、grpidおよびparamidx値、それに続いて一意の属性グループを記述する可変数の値を含みます。grpid値は、属性グループの一意のキーであり、PARAMATTR_CODE_ENTRYエントリ内で参照できます。paramidx値は、どの属性セットを表すかを示します。0は戻り値の属性、0xFFFFFFFFは関数の属性、その他の値は1ベースの関数パラメータを表します。

attrは、可変数の値として表されます。

kind, key [, ...], [value [, ...]]

各属性は、よく知られたLLVM属性(それに関連付けられた整数値を持つ場合もある)、または任意の文字列(それに関連付けられた任意の文字列値を持つ場合もある)のいずれかです。kind値は、これらの可能性を区別する整数コードです。

  • コード0: よく知られた属性

  • コード1: 整数値を持つよく知られた属性

  • コード3: 文字列属性

  • コード4: 文字列値を持つ文字列属性

よく知られた属性(コード0または1)の場合、key値は属性を識別する整数コードです。整数引数を持つ属性(コード1)の場合、value値は引数を示します。

文字列属性(コード3または4)の場合、key値は実際には、ヌル終端文字列のバイトを表す可変数の値です。文字列引数を持つ属性(コード4)の場合、value値は同様に、ヌル終端文字列のバイトを表す可変数の値です。

整数コードは、ファイルLLVMBitCodes.hAttributeKindCodes列挙で説明されているように、属性にマッピングされます。

例:

enum AttributeKindCodes {
  // = 0 is unused
  ATTR_KIND_ALIGNMENT = 1,
  ATTR_KIND_ALWAYS_INLINE = 2,
  ...
  }

に対応します。

  • コード1: align(<n>)

  • コード2: alwaysinline

列挙と属性名文字列間のマッピングは、ファイルAttributes.tdにあります。

注記

allocsize属性は、その引数に対して特別なエンコーディングを持っています。2つの引数(32ビット整数)は、1つの64ビット整数値にパックされます(つまり、(EltSizeParam << 32) | NumEltsParam)。NumEltsParamは、指定されていない場合、セマンティック値-1になります。

注記

vscale_range属性は、その引数に対して特別なエンコーディングを持っています。2つの引数(32ビット整数)は、1つの64ビット整数値にパックされます(つまり、(Min << 32) | Max)。Maxは、指定されていない場合、Minの値になります。

TYPE_BLOCK 内容

TYPE_BLOCKブロック(ID 17)には、LLVMモジュール内で参照される型を表すために使用される型演算子エントリのテーブルを構成するレコードが含まれています。各レコード(NUMENTRYを除く)は、単一の型テーブルエントリを生成します。これは、命令、定数、メタデータ、型シンボルテーブルエントリ、またはその他の型演算子レコードから0ベースのインデックスで参照できます。

TYPE_BLOCK内のエントリは、各エントリが一意になるように構築されています(つまり、2つのインデックスが構造的に等価な型を表すことはありません)。

TYPE_CODE_NUMENTRY レコード

[NUMENTRY, numentries]

NUMENTRYレコード(コード1)には、モジュールの型テーブル内の型コードエントリの総数を示す単一の値が含まれています。存在する場合、NUMENTRYはブロックの最初のレコードである必要があります。

TYPE_CODE_VOID レコード

[VOID]

VOIDレコード(コード2)は、void型を型テーブルに追加します。

TYPE_CODE_HALF レコード

[HALF]

HALFレコード(コード10)は、half(16ビット浮動小数点)型を型テーブルに追加します。

TYPE_CODE_BFLOAT レコード

[BFLOAT]

BFLOAT レコード(コード 23)は、型テーブルにbfloat(16 ビット Brain Floating Point)型を追加します。

TYPE_CODE_FLOAT レコード

[FLOAT]

FLOAT レコード(コード 3)は、型テーブルにfloat(32 ビット浮動小数点)型を追加します。

TYPE_CODE_DOUBLE レコード

[DOUBLE]

DOUBLE レコード(コード 4)は、型テーブルにdouble(64 ビット浮動小数点)型を追加します。

TYPE_CODE_LABEL レコード

[LABEL]

LABEL レコード(コード 5)は、型テーブルにlabel型を追加します。

TYPE_CODE_OPAQUE レコード

[OPAQUE]

OPAQUE レコード(コード 6)は、型テーブルにopaque型を追加します。この型名は、以前に遭遇したSTRUCT_NAMEレコードによって定義されます。異なるopaque型は統合されないことに注意してください。

TYPE_CODE_INTEGER レコード

[INTEGER, width]

INTEGER レコード(コード 7)は、型テーブルに整数型を追加します。単一のwidthフィールドは、整数型の幅を示します。

TYPE_CODE_POINTER レコード

[POINTER, pointee type, address space]

POINTER レコード(コード 8)は、型テーブルにポインタ型を追加します。オペランドフィールドは次のとおりです。

  • pointee type: 指された型の型インデックス

  • address space: 指定されている場合、指されたオブジェクトが存在するターゲット固有の番号付きアドレス空間です。指定されていない場合、デフォルトのアドレス空間はゼロです。

TYPE_CODE_FUNCTION_OLD レコード

注記

これは、LLVM バージョン 3.0 以前によって生成された、関数のレガシーエンコーディングです。IR 後方互換性ポリシーで指定されているように、現在の LLVM バージョンで理解されることが保証されています。

[FUNCTION_OLD, vararg, ignored, retty, ...paramty...]

FUNCTION_OLD レコード(コード 9)は、型テーブルに関数型を追加します。オペランドフィールドは次のとおりです。

  • vararg: 型が可変引数関数を表す場合、ゼロ以外

  • ignored: この値フィールドは後方互換性のためだけに存在し、無視されます。

  • retty: 関数の戻り値の型インデックス

  • paramty: 関数のパラメータ型を表す0個以上の型インデックス

TYPE_CODE_ARRAY レコード

[ARRAY, numelts, eltty]

ARRAY レコード(コード 11)は、型テーブルに配列型を追加します。オペランドフィールドは次のとおりです。

  • numelts: この型の配列内の要素数

  • eltty: 配列要素型の型インデックス

TYPE_CODE_VECTOR レコード

[VECTOR, numelts, eltty]

VECTOR レコード(コード 12)は、型テーブルにベクトル型を追加します。オペランドフィールドは次のとおりです。

  • numelts: この型のベクトル内の要素数

  • eltty: ベクトルの要素型の型インデックス

TYPE_CODE_X86_FP80 レコード

[X86_FP80]

X86_FP80 レコード(コード 13)は、型テーブルにx86_fp80(80 ビット浮動小数点)型を追加します。

TYPE_CODE_FP128 レコード

[FP128]

FP128 レコード(コード 14)は、型テーブルにfp128(128 ビット浮動小数点)型を追加します。

TYPE_CODE_PPC_FP128 レコード

[PPC_FP128]

PPC_FP128 レコード(コード 15)は、型テーブルにppc_fp128(128 ビット浮動小数点)型を追加します。

TYPE_CODE_METADATA レコード

[METADATA]

METADATA レコード(コード 16)は、型テーブルにmetadata型を追加します。

TYPE_CODE_X86_MMX レコード

[X86_MMX]

X86_MMX レコード(コード 17)は非推奨であり、<1 x i64> ベクトルとしてインポートされます。

TYPE_CODE_STRUCT_ANON レコード

[STRUCT_ANON, ispacked, ...eltty...]

STRUCT_ANON レコード(コード 18)は、リテラル構造体型を型テーブルに追加します。オペランドフィールドは次のとおりです。

  • ispacked: 型がパックされた構造体を表す場合、ゼロ以外

  • eltty: 構造体の要素型を表す0個以上の型インデックス

TYPE_CODE_STRUCT_NAME レコード

[STRUCT_NAME, ...string...]

STRUCT_NAME レコード(コード 19)は、構造体名のバイトを表す可変数の値を含みます。次のOPAQUEまたはSTRUCT_NAMEDレコードはこの名前を使用します。

TYPE_CODE_STRUCT_NAMED レコード

[STRUCT_NAMED, ispacked, ...eltty...]

STRUCT_NAMED レコード(コード 20)は、以前に遭遇したSTRUCT_NAMEレコードによって定義された名前を持つ、識別された構造体型を型テーブルに追加します。オペランドフィールドは次のとおりです。

  • ispacked: 型がパックされた構造体を表す場合、ゼロ以外

  • eltty: 構造体の要素型を表す0個以上の型インデックス

TYPE_CODE_FUNCTION レコード

[FUNCTION, vararg, retty, ...paramty...]

FUNCTION レコード(コード 21)は、型テーブルに関数型を追加します。オペランドフィールドは次のとおりです。

  • vararg: 型が可変引数関数を表す場合、ゼロ以外

  • retty: 関数の戻り値の型インデックス

  • paramty: 関数のパラメータ型を表す0個以上の型インデックス

TYPE_CODE_X86_AMX レコード

[X86_AMX]

X86_AMX レコード(コード 24)は、型テーブルにx86_amx型を追加します。

TYPE_CODE_TARGET_TYPE レコード

[TARGET_TYPE, num_tys, ...ty_params..., ...int_params...]

TARGET_TYPE レコード(コード 26)は、以前に遭遇したSTRUCT_NAMEレコードによって定義された名前を持つ、ターゲット拡張型を型テーブルに追加します。オペランドフィールドは次のとおりです。

  • num_tys: 型であるパラメータの数(整数ではない)

  • ty_params: 型パラメータを表す型インデックス

  • int_params: 整数パラメータに対応する数値。

CONSTANTS_BLOCK の内容

CONSTANTS_BLOCK ブロック(ID 11)…

FUNCTION_BLOCK の内容

FUNCTION_BLOCK ブロック(ID 12)…

下記で説明するレコードタイプに加えて、FUNCTION_BLOCKブロックには次のサブブロックを含めることができます。

VALUE_SYMTAB_BLOCK の内容

VALUE_SYMTAB_BLOCK ブロック(ID 14)…

METADATA_BLOCK の内容

METADATA_BLOCK ブロック(ID 15)…

METADATA_ATTACHMENT の内容

METADATA_ATTACHMENT ブロック(ID 16)…

STRTAB_BLOCK の内容

STRTAB ブロック(ID 23)には、ビットコードファイルの文字列テーブルを含む単一のBLOBオペランドを持つ単一のレコード(STRTAB_BLOB、ID 1)が含まれています。

文字列テーブル内の文字列は、ヌル終端されていません。レコードのstrtab offsetおよびstrtab sizeオペランドは、文字列テーブル内の文字列のバイトオフセットとサイズを指定します。

文字列テーブルは、別の介入するSTRTABブロックが後続しない、ビットコードファイル内のすべての先行ブロックによって使用されます。通常、ビットコードファイルには文字列テーブルが1つだけありますが、複数のビットコードファイルをバイナリ連結して作成された場合は、複数存在する場合があります。