1 TableGen バックエンド開発者ガイド

1.1 はじめに

TableGen の目的は、出力ファイルよりも大幅にコード化しやすく、時間の経過とともに保守および変更が容易なソースファイルからの情報に基づいて複雑な出力ファイルを生成することです。情報は、クラスとレコードを含む宣言スタイルでコード化され、TableGen によって処理されます。内部化されたレコードは、さまざまなバックエンドに渡され、バックエンドはレコードのサブセットから情報を抽出し、出力ファイルを生成します。これらの出力ファイルは通常、C++ の .inc ファイルですが、バックエンド開発者が必要とする任意のタイプのファイルである可能性があります。

このドキュメントは、TableGen のバックエンドを作成するためのガイドです。完全なリファレンスマニュアルではなく、バックエンド用の TableGen によって提供される機能を使用するためのガイドです。関連するさまざまなデータ構造と関数に関する完全なリファレンスについては、プライマリ TableGen ヘッダーファイル (record.h) または Doxygen ドキュメントを参照してください。

このドキュメントでは、TableGen ソースファイルのコーディングに関する詳細なリファレンスを提供する TableGen プログラマーリファレンス を読んだことを前提としています。既存のバックエンドの説明については、TableGen バックエンド を参照してください。

1.2 データ構造

次のセクションでは、TableGen パーサーによって TableGen ソースファイルから収集されたクラスとレコードを格納するデータ構造について説明します。_クラス_という用語は抽象レコードクラスを指し、_レコード_という用語は具体的なレコードを指すことに注意してください。

特に明記されていない限り、クラスに関連付けられた関数はインスタンス関数です。

1.2.1 RecordKeeper

RecordKeeper クラスのインスタンスは、TableGen によって解析および収集されたすべてのクラスとレコードのコンテナとして機能します。RecordKeeper インスタンスは、TableGen によって呼び出されるときにバックエンドに渡されます。このクラスは通常 RK と略されます。

レコードキーパーには 2 つのマップがあり、1 つはクラス用、もう 1 つはレコード用です (後者はしばしば _defs_ と呼ばれます)。各マップは、クラスまたはレコード名を Record クラス ( Record を参照) のインスタンスにマップします。これには、そのクラスまたはレコードに関するすべての情報が含まれています。

2 つのマップに加えて、RecordKeeper インスタンスには次のものが含まれています。

  • グローバル変数の名前をそれらの値にマップするマップ。グローバル変数は、TableGen ファイルで外部の defvar ステートメントを使用して定義されます。

  • 匿名レコードを命名するためのカウンター。

RecordKeeper クラスには、いくつかの便利な関数が用意されています。

  • 完全なクラスマップとレコードマップを取得する関数。

  • 親クラスに基づいてレコードのサブセットを取得する関数。

  • 名前で個々のクラス、レコード、グローバルを取得する関数。

RecordKeeper インスタンスは、<< 演算子を使用して出力ストリームに出力できます。

1.2.2 Record

TableGen によって構築された各クラスまたはレコードは、Record クラスのインスタンスによって表されます。RecordKeeper インスタンスには、クラス用のマップとレコード用のマップが 1 つずつ含まれています。レコードの主要なデータメンバーは、レコード名、フィールド名とその値のベクトル、およびレコードのスーパークラスのベクトルです。

レコード名は、Init ( Init を参照) へのポインターとして格納されます。これは、TableGen 値 ( _イニシャライザー_ と呼ばれることもあります) を保持するクラスです。フィールド名と値は、RecordVal インスタンス ( RecordVal を参照) のベクトルに格納されます。各インスタンスには、フィールド名とその値の両方が含まれています。スーパークラスベクトルには、スーパークラスレコードとそのソースファイルロケーションを含むペアのシーケンスが含まれています。

これらのメンバーに加えて、Record インスタンスには次のものが含まれています。

  • レコード定義自体に加えて、その定義に関与するマルチクラスの場所を含むソースファイルロケーションのベクトル。

  • クラスレコードの場合、クラスのテンプレート引数のベクトル。

  • このレコードに対応する DefInit ( DefInit を参照) のインスタンス。

  • 一意のレコード ID。

  • これがクラス定義であるかどうかを指定するブール値。

  • これが匿名レコードであるかどうかを指定するブール値。

Record クラスには、多くの便利な関数が用意されています。

  • レコード名、フィールド、ソースファイルロケーション、テンプレート引数、および一意の ID を取得する関数。

  • レコードのすべてのスーパークラスまたは直接のスーパークラスのみを取得する関数。

  • 名前をさまざまな形式で指定し、値をさまざまな形式で返すことで、特定のフィールド値を取得する関数 ( レコード名とフィールドの取得 を参照)。

  • レコードのさまざまな属性を確認するためのブール関数。

Record インスタンスは、<< 演算子を使用して出力ストリームに出力できます。

1.2.3 RecordVal

レコードの各フィールドは、RecordVal クラスのインスタンスに格納されます。Record インスタンスには、これらの値インスタンスのベクトルが含まれています。RecordVal インスタンスには、Init インスタンスに格納されたフィールドの名前が含まれています。また、同様に Init に格納されたフィールドの値も含まれています。(このクラスのより適切な名前は RecordField かもしれません。)

これらの主要なメンバーに加えて、RecordVal には他のデータメンバーがあります。

  • フィールド定義のソースファイルロケーション。

  • フィールドの型は、RecTy クラス(RecTyを参照)のインスタンスとして格納されます。

RecordVal クラスは、いくつかの便利な機能を提供します。

  • フィールドの名前をさまざまな形式で取得する関数。

  • フィールドの型を取得する関数。

  • フィールドの値を取得する関数。

  • ソースファイルの場所を取得する関数。

フィールドの値は、Record インスタンス(Recordを参照)から直接取得する方が簡単であることに注意してください。

RecordVal インスタンスは、<< 演算子を使って出力ストリームに出力できます。

1.2.4 RecTy

RecTy クラスは、フィールド値の型を表すために使用されます。これは、使用可能なフィールド型ごとに1つずつ、一連のサブクラスの基本クラスです。RecTy クラスには、フィールド値の特定の型を指定する列挙型である1つのデータメンバーがあります。(このクラスのより適切な名前は FieldTy かもしれません。)

RecTy クラスは、いくつかの便利な機能を提供します。

  • 型名を文字列として取得する仮想関数。

  • この型のすべての値を、別の指定された型に変換できるかどうかを確認する仮想関数。

  • この型が、別の指定された型のサブタイプであるかどうかを確認する仮想関数。

  • この型の要素を持つリストに対応する list 型を取得する関数。たとえば、int 型で呼び出された場合、関数は list<int> 型を返します。

RecTy から継承するサブクラスは、BitRecTyBitsRecTyCodeRecTyDagRecTyIntRecTyListRecTyRecordRecTy、および StringRecTy です。これらのクラスの一部には、次のサブセクションで説明する追加のメンバーがあります。

RecTy から派生したすべてのクラスは、get() 関数を提供します。これは、派生クラスに対応する Recty のインスタンスを返します。一部の get() 関数では、どの特定の型のバリアントが必要かを指定するために引数が必要です。これらの引数については、次のサブセクションで説明します。

RecTy インスタンスは、<< 演算子を使って出力ストリームに出力できます。

警告

特定の型の RecTy インスタンスが1つであるか、複数のインスタンスであるかは指定されていません。

1.2.4.1 BitsRecTy

このクラスには、bits 値のサイズを持つデータメンバーと、そのサイズを取得する関数が含まれています。

get() 関数は、シーケンスの長さ *n* を取り、bits<*n*> に対応する BitsRecTy 型を返します。

1.2.4.2 ListRecTy

このクラスには、リストの要素の型を指定するデータメンバーと、その型を取得する関数が含まれています。

get() 関数は、リストメンバーの RecTy *型* を取り、list<*型*> に対応する ListRecTy 型を返します。

1.2.4.3 RecordRecTy

このクラスには、このレコードの親クラスのリストを含むデータメンバーが含まれています。また、クラスの配列を取得する関数と、イテレータ begin() および end() 値を取得する2つの関数を提供します。クラスは、後者の2つの関数の戻り値の型を定義します。

using const_record_iterator = Record * const *;

get() 関数は、レコードの直接のスーパークラスの Record インスタンスへのポインタの ArrayRef を受け取り、それらのスーパークラスから継承するレコードに対応する RecordRecTy を返します。

1.2.5 Init

Init クラスは、TableGenの値を表すために使用されます。名前は、 *初期化値* に由来します。このクラスを、レコードフィールドの名前と値の両方を表す RecordVal クラスと混同しないでください。Init クラスは、使用可能な値の型ごとに1つずつ、一連のサブクラスの基本クラスです。Init の主要なデータメンバーは、値の特定の型を表す列挙型です。

Init クラスは、いくつかの便利な機能を提供します。

  • 型列挙子を取得する関数。

  • 値が完全に指定されているかどうか、つまり、初期化されていないサブ値がないかどうかを判断するブール値の仮想関数。

  • 値を文字列として取得する仮想関数。

  • 値を他の型にキャストし、TableGenのビット範囲機能を実装し、リストスライス機能を実装する仮想関数。

  • 値の特定のビットを取得する仮想関数。

Init から直接継承するサブクラスは、UnsetInitTypedInit です。

Init インスタンスは、<< 演算子を使って出力ストリームに出力できます。

警告

同じ基本型と値を持つ2つの個別の初期化値(たとえば、値「Hello」を持つ2つの文字列)が、2つの Init で表されるか、同じ Init を共有するかは指定されていません。

1.2.5.1 UnsetInit

このクラスは、Init のサブクラスであり、設定されていない(初期化されていない)値を表します。静的関数 get() を使用して、この型のシングルトン Init を取得できます。

1.2.5.2 TypedInit

このクラスは、Init のサブクラスであり、特定の値の型を表すクラスの親クラスとして機能します(設定されていない値を除く)。これらのクラスには、BitInitBitsInitDagInitDefInitIntInitListInit、および StringInit が含まれます。(TableGenパーサーで使用される追加の派生型があります。)

このクラスには、値の RecTy 型を指定するデータメンバーが含まれています。その RecTy 型を取得する関数を提供します。

1.2.5.3 BitInit

BitInit クラスは、TypedInit のサブクラスです。そのインスタンスは、ビットの可能な値(0または1)を表します。ビットを含むデータメンバーが含まれています。

TypedInit から派生したすべてのクラスは、次の関数を提供します。

  • 指定された値を表す Init を返す、get() という名前の静的関数。BitInit の場合、get(true) は true を表す BitInit のインスタンスを返し、get(false) は false を表すインスタンスを返します。上記のように、true(または false)を表す BitInit が1つだけであるか、複数であるかは指定されていません。

  • インスタンスの値をより直接的な形式で返す、GetValue() という名前の関数。この場合は bool として。

1.2.5.4 BitsInit

BitsInit クラスは、TypedInit のサブクラスです。そのインスタンスは、高位から低位までのビットのシーケンスを表します。シーケンスの長さを持つデータメンバーと、ビットごとに1つの Init インスタンスへのポインタのベクターが含まれています。

クラスは、通常の get() 関数を提供します。getValue() 関数は提供しません。

クラスは、次の追加関数を提供します。

  • シーケンス内のビット数を取得する関数。

  • 整数インデックスで指定されたビットを取得する関数。

1.2.5.5 DagInit

DagInit クラスは TypedInit のサブクラスです。そのインスタンスは、あり得る有向非巡回グラフ(dag)を表します。

このクラスには、DAG演算子に対する Init へのポインタと、演算子名に対する StringInit へのポインタが含まれます。DAGオペランドの数とオペランド名の数も含まれます。最後に、オペランドに対する Init インスタンスへのポインタのベクターと、オペランド名に対する StringInit インスタンスへのポインタのベクターが含まれます。(DAGオペランドは *引数* とも呼ばれます。)

このクラスは、通常の get() 関数の2つの形式を提供します。通常の getValue() 関数は提供しません。

このクラスは、多くの追加機能を提供します。

  • さまざまな形式で演算子を取得し、さまざまな形式で演算子名を取得する機能。

  • オペランドがあるかどうかを判断し、オペランドの数を取得する機能。

  • オペランドを個別に、およびまとめて取得する機能。

  • 名前があるかどうかを判断し、名前の数を取得する機能。

  • 名前を個別に、およびまとめて取得する機能。

  • オペランドイテレータ begin() および end() の値を取得する機能。

  • 名前イテレータ begin() および end() の値を取得する機能。

このクラスは、オペランドと名前のイテレータの戻り値の型を2つ定義します。

using const_arg_iterator = SmallVectorImpl<Init*>::const_iterator;
using const_name_iterator = SmallVectorImpl<StringInit*>::const_iterator;

1.2.5.6 DefInit

DefInit クラスは TypedInit のサブクラスです。そのインスタンスは、TableGen によって収集されたレコードを表します。レコードの Record インスタンスへのポインタであるデータメンバーが含まれます。

このクラスは、通常の get() 関数を提供します。getValue() は提供しません。代わりに、Record インスタンスを返す getDef() を提供します。

1.2.5.7 IntInit

IntInit クラスは TypedInit のサブクラスです。そのインスタンスは、64ビット整数の可能な値を表します。整数を含むデータメンバーが含まれます。

このクラスは、通常の get() 関数と getValue() 関数を提供します。後者の関数は、整数を int64_t として返します。

このクラスは、整数の指定されたビットを取得する関数 getBit() も提供します。

1.2.5.8 ListInit

ListInit クラスは TypedInit のサブクラスです。そのインスタンスは、ある型の要素のリストを表します。リストの長さを持つデータメンバーと、要素ごとに Init インスタンスへのポインタのベクターが含まれます。

このクラスは、通常の get() 関数と getValues() 関数を提供します。後者の関数は、Init インスタンスへのポインタのベクターの ArrayRef を返します。

このクラスは、以下の追加機能を提供します。

  • 要素の型を取得する機能。

  • ベクターの長さを取得し、空かどうかを判断する機能。

  • 整数インデックスで指定された要素を取得し、さまざまな形式で返す機能。

  • イテレータ begin() および end() の値を取得する機能。このクラスは、これらの2つの関数の戻り値の型を定義します。

using const_iterator = Init *const *;

1.2.5.9 StringInit

StringInit クラスは TypedInit のサブクラスです。そのインスタンスは、任意の長さの文字列を表します。値の StringRef を含むデータメンバーが含まれます。

このクラスは、通常の get() 関数と getValue() 関数を提供します。後者の関数は、StringRef を返します。

1.3 新しいバックエンドの作成

TableGen の新しいバックエンドを作成するには、次の手順が必要です。

  1. バックエンドの C++ ファイルの名前を考えてください(例:GenAddressModes)。

  2. TableGenBackendSkeleton.cpp ファイルを出発点として、新しいバックエンドを作成します。

  3. 新しいバックエンドを必要とする TableGen のインスタンスを決定します。Clang 用と LLVM 用のインスタンスが1つずつあります。または、独自のインスタンスを構築している可能性があります。

  4. ビルドされるように、適切な CMakeLists.txt ファイルにバックエンドの C++ ファイルを追加します。

  5. C++ ファイルをシステムに追加します。

1.4 バックエンドのスケルトン

TableGenBackendSkeleton.cpp ファイルは、新しい TableGen バックエンドを作成するためのスケルトン C++ 翻訳ユニットを提供します。ファイルに関するいくつかの注意事項を次に示します。

  • include のリストは、ほとんどのバックエンドで必要な最小限のリストです。

  • すべての LLVM C++ ファイルと同様に、using namespace llvm; ステートメントがあります。また、ファイル固有のデータ構造定義と、エミッターのデータメンバーと関数を具体化するクラスを含む匿名名前空間があります。GenAddressModes の例を続けると、このクラスは AddressModesEmitter という名前になります。

  • エミッタークラスのコンストラクターは、通常 RK という名前の RecordKeeper 参照を受け入れます。RecordKeeper 参照は、レコードをそこから取得できるように、データメンバーに保存されます。このデータメンバーは、通常 Records という名前になります。

  • run という名前の関数が1つあります。これは、バックエンドの「main関数」によって呼び出され、レコードを収集して出力ファイルを生成します。これは、通常 OS という名前の raw_ostream クラスのインスタンスを受け入れます。出力ファイルは、このストリームに書き込むことによって出力されます。

  • run 関数は、emitSourceFileHeader ヘルパー関数を使用して、出力ファイルに標準ヘッダーを含める必要があります。

  • llvm/TableGen/TableGenBackend.h を使用して、クラスまたは関数をコマンドラインオプションとして登録します。

    • クラスにコンストラクター (RK) とメソッド run(OS) がある場合は、llvm::TableGen::Emitter::OptClass<AddressModesEmitter> を使用します。

    • それ以外の場合は、llvm::TableGen::Emitter::Opt を使用します。

このドキュメントの残りの部分のすべての例では、スケルトンファイルで使用されている命名規則を想定しています。

1.5 クラスの取得

RecordKeeper クラスは、TableGen ファイルで定義されたクラスの Record インスタンスを取得するための2つの関数を提供します。

  • getClasses() は、すべてのクラスの RecordMap 参照を返します。

  • getClass(name) は、指定されたクラスの Record 参照を返します。

すべてのクラスレコードを反復処理する必要がある場合

for (auto ClassPair : Records.getClasses()) {
  Record *ClassRec = ClassPair.second.get();
  ...
}

ClassPair.second はクラスの unique_ptr を取得し、次に .get() はクラスの Record 自体を取得します。

1.6 レコードの取得

RecordKeeper クラスは、TableGen ファイルで定義された具体的なレコードの Record インスタンスを取得するための4つの関数を提供します。

  • getDefs() は、すべての具体的なレコードの RecordMap 参照を返します。

  • getDef(name) は、指定された具体的なレコードの Record 参照を返します。

  • getAllDerivedDefinitions(classname) は、指定されたクラスから派生した具象レコードの Record 参照のベクターを返します。

  • getAllDerivedDefinitions(classnames) は、指定されたすべてのクラスから派生した具象レコードの Record 参照のベクターを返します。

このステートメントは、Attribute クラスから派生したすべてのレコードを取得し、それらを反復処理します。

auto AttrRecords = Records.getAllDerivedDefinitions("Attribute");
for (Record *AttrRec : AttrRecords) {
  ...
}

1.7 レコードの名前とフィールドの取得

上記で説明したように(レコードを参照)、レコードの名前を返す関数は複数あります。特に便利なものの1つは、getNameInitAsString() で、名前を std::string として返します。

レコードのフィールドを返す関数も複数あります。すべてのフィールドを取得して反復処理するには、

for (const RecordVal &Field : SomeRec->getValues()) {
  ...
}

RecordVal は、レコード内のフィールドに関する情報を含むインスタンスのクラスであることを思い出してください。

getValue() 関数は、名前で指定されたフィールドの RecordVal インスタンスを返します。複数のオーバーロードされた関数があり、一部は StringRef を取り、その他は const Init * を取ります。一部の関数は RecordVal * を返し、その他の関数は const RecordVal * を返します。フィールドが存在しない場合、致命的なエラーメッセージが出力されます。

多くの場合、RecordVal のすべての情報ではなく、フィールドの値に関心があります。いくつかの形式でフィールド名を受け取り、その値を返す関数が多数あります。1つの関数である getValueInit は、値を Init * として返します。別の関数である isValueUnset は、値が設定されていない(初期化されていない)かどうかを指定するブール値を返します。

ほとんどの関数は、より有用な形式で値を返します。たとえば、

std::vector<int64_t> RegCosts =
    SomeRec->getValueAsListOfInts("RegCosts");

フィールド RegCosts は整数のリストであると想定されています。そのリストは、64ビット整数の std::vector として返されます。フィールドが整数のリストでない場合、致命的なエラーメッセージが出力されます。

以下は、フィールド値を Record として返す関数ですが、フィールドが存在しない場合はnullを返します。

if (Record *BaseRec = SomeRec->getValueAsOptionalDef(BaseFieldName)) {
  ...
}

フィールドは、その値として別のレコードを持つと想定されています。そのレコードは、Record へのポインタとして返されます。フィールドが存在しないか、設定されていない場合、関数はnullを返します。

1.8 レコードのスーパークラスの取得

Record クラスは、レコードのスーパークラスを取得する機能を提供します。これは getSuperClasses という名前で、std::pair ペアの配列の ArrayRef を返します。スーパークラスは、ポストオーダーで、スーパークラスのフィールドをレコードにコピーする際に訪問した順序で並んでいます。各ペアは、スーパークラスレコードの Record インスタンスへのポインタと、SMRange クラスのインスタンスで構成されます。この範囲は、クラス定義の開始と終了のソースファイルの位置を示します。

この例では、Prototype レコードのスーパークラスを取得し、返された配列のペアを反復処理します。

ArrayRef<std::pair<Record *, SMRange>>
    Superclasses = Prototype->getSuperClasses();
for (const auto &SuperPair : Superclasses) {
  ...
}

Record クラスは、レコードの*直接*のスーパークラスを、SmallVectorImpl<Record *> 型の指定されたベクターに追加する関数 getDirectSuperClasses も提供します。

1.9 出力ストリームへのテキストの出力

run 関数には、出力ファイルを印刷する raw_ostream が渡されます。慣例により、このストリームは、一部の run 関数が単純で、保存せずにストリームを使用するだけであっても、OS という名前のエミッタクラスメンバに保存されます。出力は、値を直接出力ストリームに書き込むか、std::format() または llvm::formatv() 関数を使用して生成できます。

OS << "#ifndef " << NodeName << "\n";

OS << format("0x%0*x, ", Digits, Value);

次のクラスのインスタンスは、<< 演算子を使用して印刷できます:RecordKeeperRecordRecTyRecordVal、および Init

ヘルパー関数 emitSourceFileHeader() は、すべての出力ファイルの先頭に含める必要があるヘッダーコメントを印刷します。これへの呼び出しは、スケルトンバックエンドファイル TableGenBackendSkeleton.cpp に含まれています。

1.10 エラーメッセージの印刷

TableGen レコードは、多くの場合、複数のクラスから派生し、多くの場合、一連のマルチクラスを介して定義されます。このため、バックエンドが正確なソースファイルの位置を含む明確なエラーメッセージを報告することが困難になる場合があります。エラーレポートを容易にするために、4つのオーバーロードを持つ5つのエラーレポート関数が提供されています。

  • PrintWarning は、警告としてタグ付けされたメッセージを印刷します。

  • PrintError は、エラーとしてタグ付けされたメッセージを印刷します。

  • PrintFatalError は、エラーとしてタグ付けされたメッセージを印刷し、終了します。

  • PrintNote は、注記を印刷します。多くの場合、前の関数の1つを使用して、より多くの情報を提供します。

  • PrintFatalNote は、注記を印刷してから終了します。

これらの5つの関数はそれぞれ、4回オーバーロードされています。

  • PrintError(const Twine &Msg):ソースファイルの位置なしでメッセージを印刷します。

  • PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg):エラーが発生した項目へのポインタとともに、指定されたソース行に続くメッセージを印刷します。ソースファイルの位置の配列は、通常、Record インスタンスから取得されます。

  • PrintError(const Record *Rec, const Twine &Msg):指定されたレコードに関連付けられたソース行に続くメッセージを印刷します(レコードを参照)。

  • PrintError(const RecordVal *RecVal, const Twine &Msg):指定されたレコードフィールドに関連付けられたソース行に続くメッセージを印刷します(RecordValを参照)。

これらの関数を使用すると、可能な限り最も具体的なエラーレポートを生成することを目標とします。

1.11 デバッグツール

TableGenは、バックエンドのデバッグを支援するいくつかのツールを提供します。

1.11.1 PrintRecords バックエンド

TableGen コマンドオプション --print-records は、ソースファイルで定義されたすべてのクラスとレコードを印刷する簡単なバックエンドを起動します。これがデフォルトのバックエンドオプションです。出力の形式は、テストで出力を比較できるように、時間の経過とともに一定であることが保証されています。出力は次のようになります。

------------- Classes -----------------
...
class XEntry<string XEntry:str = ?, int XEntry:val1 = ?> { // XBase
  string Str = XEntry:str;
  bits<8> Val1 = { !cast<bits<8>>(XEntry:val1){7}, ... };
  bit Val3 = 1;
}
...
------------- Defs -----------------
def ATable {  // GenericTable
  string FilterClass = "AEntry";
  string CppTypeName = "AEntry";
  list<string> Fields = ["Str", "Val1", "Val2"];
  list<string> PrimaryKey = ["Val1", "Val2"];
  string PrimaryKeyName = "lookupATableByValues";
  bit PrimaryKeyEarlyOut = 0;
}
...
def anonymous_0 {     // AEntry
  string Str = "Bob";
  bits<8> Val1 = { 0, 0, 0, 0, 0, 1, 0, 1 };
  bits<10> Val2 = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
}

クラスは、テンプレート引数、親クラス(// に続く)、およびフィールドとともに表示されます。レコードは、親クラスとフィールドとともに表示されます。匿名レコードは anonymous_0anonymous_1 などと名前が付けられていることに注意してください。

1.11.2 PrintDetailedRecords バックエンド

TableGenコマンドのオプション--print-detailed-recordsは、ソースファイルで定義されたすべてのグローバル変数、クラス、およびレコードを出力するバックエンドを呼び出します。出力形式は、時間の経過とともに一定であることは保証されていません。出力は次のようになります。

DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td

-------------------- Global Variables (5) --------------------

AMDGPUBufferIntrinsics = [int_amdgcn_s_buffer_load, ...
AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
...
-------------------- Classes (758) --------------------

AMDGPUBufferLoad  |IntrinsicsAMDGPU.td:879|
  Template args:
    LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty  |IntrinsicsAMDGPU.td:879|
  Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
  Fields:
    list<SDNodeProperty> Properties = [SDNPMemOperand]  |Intrinsics.td:348|
    string LLVMName = ""  |Intrinsics.td:343|
...
-------------------- Records (12303) --------------------

AMDGPUSample_lz_o  |IntrinsicsAMDGPU.td:560|
  Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
  Superclasses: AMDGPUSampleVariant
  Fields:
    string UpperCaseMod = "_LZ_O"  |IntrinsicsAMDGPU.td:542|
    string LowerCaseMod = "_lz_o"  |IntrinsicsAMDGPU.td:543|
...
  • 外側のdefvarステートメントで定義されたグローバル変数は、その値とともに表示されます。

  • クラスは、ソースの場所、テンプレート引数、スーパークラス、およびフィールドとともに表示されます。

  • レコードは、ソースの場所、defmシーケンス、スーパークラス、およびフィールドとともに表示されます。

スーパークラスは処理された順序で表示され、間接的なスーパークラスは括弧で囲まれます。各フィールドは、その値と設定されたソースの場所とともに表示されます。defmシーケンスは、レコードの生成に関与したdefmステートメントの場所を、呼び出された順序で示します。

1.11.3 TableGenフェーズのタイミング測定

TableGenは、ソースファイルの解析と選択されたバックエンドの実行のさまざまなフェーズで使用された時間のレポートを生成するフェーズタイミング機能を提供します。この機能は、TableGenコマンドの--time-phasesオプションで有効になります。

バックエンドがタイミング測定用にインストルメント化されていない場合、次のようなレポートが生成されます。これは、AMDGPUターゲットで実行された--print-detailed-recordsバックエンドのタイミングです。

===-------------------------------------------------------------------------===
                             TableGen Phase Timing
===-------------------------------------------------------------------------===
  Total Execution Time: 101.0106 seconds (102.4819 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
  85.5197 ( 84.9%)   0.1560 ( 50.0%)  85.6757 ( 84.8%)  85.7009 ( 83.6%)  Backend overall
  15.1789 ( 15.1%)   0.0000 (  0.0%)  15.1789 ( 15.0%)  15.1829 ( 14.8%)  Parse, build records
   0.0000 (  0.0%)   0.1560 ( 50.0%)   0.1560 (  0.2%)   1.5981 (  1.6%)  Write output
  100.6986 (100.0%)   0.3120 (100.0%)  101.0106 (100.0%)  102.4819 (100.0%)  Total

バックエンドのすべての時間は、「Backend overall」にまとめられていることに注意してください。

バックエンドがタイミング測定用にインストルメント化されている場合、その処理はフェーズに分割され、それぞれが個別に計測されます。これは、AMDGPUターゲットで実行された--emit-dag-iselバックエンドのタイミングです。

===-------------------------------------------------------------------------===
                             TableGen Phase Timing
===-------------------------------------------------------------------------===
  Total Execution Time: 746.3868 seconds (747.1447 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
  657.7938 ( 88.1%)   0.1404 ( 90.0%)  657.9342 ( 88.1%)  658.6497 ( 88.2%)  Emit matcher table
  70.2317 (  9.4%)   0.0000 (  0.0%)  70.2317 (  9.4%)  70.2700 (  9.4%)  Convert to matchers
  14.8825 (  2.0%)   0.0156 ( 10.0%)  14.8981 (  2.0%)  14.9009 (  2.0%)  Parse, build records
   2.1840 (  0.3%)   0.0000 (  0.0%)   2.1840 (  0.3%)   2.1791 (  0.3%)  Sort patterns
   1.1388 (  0.2%)   0.0000 (  0.0%)   1.1388 (  0.2%)   1.1401 (  0.2%)  Optimize matchers
   0.0000 (  0.0%)   0.0000 (  0.0%)   0.0000 (  0.0%)   0.0050 (  0.0%)  Write output
  746.2308 (100.0%)   0.1560 (100.0%)  746.3868 (100.0%)  747.1447 (100.0%)  Total

バックエンドは4つのフェーズに分割され、個別に計測されています。

バックエンドをインストルメント化する場合は、バックエンドDAGISelEmitter.cppを参照し、Records.startTimerを検索してください。