LLVM IRの勉強メモ #6

名前付きメタデータとパラメータアトリビュートについて見てみます。
詳細は[LLVMのリファレンスマニュアル](https://llvm.org/docs/LangRef.html)を参照。

### 名前付きメタデータ(Named Metadata)

メタデータの集合。`!`+文字列（命名ルールは識別子とほぼ同じ）が付けられる。

```txt:syntax
; Some unnamed metadata nodes, which are referenced by the named metadata.
!0 = !{!"zero"}
!1 = !{!"one"}
!2 = !{!"two"}
; A named metadata.
!name = !{!0, !1, !2}
```

### パラメータアトリビュート(Parameter Attributes)

関数の引数と戻り値の型にはパラメータアトリビュートを付与できる。パラメータアトリビュートは単純なスペース区切りのキーワードで、追加情報を伝達するために使われる。
パラメータアトリビュートは関数の一部とみなされるため、異なるパラメータアトリビュートを持つ関数は同じ関数の型を持つことができる。

```txt:e.g.
declare i32 @printf(ptr noalias nocapture, ...)
declare i32 @atoi(i8 zeroext)
declare signext i8 @returns_signed_char()
```

- `zeroext`
callerまたはcalleeがターゲットのABIで要求される範囲まで、引数または戻り値をゼロ拡張すべきであることを示す。
（ゼロ拡張: ビット数が少ない値をゼロで埋める）
- `signext`
callerまたはcalleeがターゲットのABIで要求される範囲まで、引数または戻り値を符号拡張すべきであることを示す。
- `inreg`
引数や戻り値がターゲットに依存した特別な方法で扱われることを示す。仕様はターゲット固有に定義される。
- `byval(<ty>)`
ポインタ引数が実際の値で関数に渡されるべきことを示す。このアトリビュートでは、callerとcalleeの間で隠しコピーが作成されるため、calleeはcallerの値を変更することができなくなる。alignと組み合わせることでアラインメントを明示できる。
- `byref(<ty>)`
ポインタのメモリタイプを指定することができる。byvalと異なりコピーが作られるのではなく、ポインタがそのメモリサイズまで再参照可能であることを示す。alignと組み合わせることでアラインメントを明示できる。
- `preallocated(<ty>)`
ポインタ引数が実値で関数に渡される（且つ、ポインタは呼び出し命令の前に初期化されている）ことを示す。
- `inalloca(<ty>)`
alloca命令によって生成されたスタックメモリへのポインタについて、外にあるスタック引数のアドレスを取ることを指定する。
（LLVMはもともと分割されたスタックメモリを呼び出すことができなかったが、Microsoft C++ ABIとの互換性のために必要となったよう。[参考](https://llvm.org/docs/InAlloca.html)）
- `sret(<ty>)`
ポインタ引数がプログラムの関数の戻り値である構造体のアドレスを指定することを示す。
- `elementtype(<ty>)`
ポインタ要素がある不明瞭なポインタと互換を持つことができるように指定される。このアトリビュート自体は特定のセマンティクスを持っておらず、intrinsicが個々に特定のセマンティクスを割り当てることができる。intrinsicコールのポインタ型引数にのみ使用できる。
- `align(<n>)`
ポインタ値やポインタベクトルが指定されたアラインメントを持つことを示す。
- `noalias`
関数の実行中に、引数や戻り値に基づくポインタ値によってアクセスされたメモリ位置が、引数や戻り値に基づかないポインタ値によってアクセスされないことを示す。
noalias応答は、一方のポインタのメモリ参照と、もう一方のポインタのメモリ参照との間に直接的な依存関係がない場合に使用される。
- `nocapture`
calleeがポインタをキャプチャしていないことを示す。callerは一つのポインタについて2つのコピーを渡すことができ、その一方がnocaptureとアノテーションされる。

```txt
define void @f(ptr nocapture %a, ptr %b) {
  ; (capture %b)
}
```

- `nofree`
calleeがポインタをfreeしないことを示す。
- `nest`
trampoline intrinsicsを使ってポインタ引数を削除できることを示す。
- `returned`
関数が常に引数を戻り値として返すことを示す。これはオプティマイザやコードジェネレータがcallerを生成するときのヒントで、値伝搬、tail call最適化、レジスタのセーブ・リストアの省略などを可能にする。
- `nonnull`
引数や戻り値のポインタがnullではないことを示す。
- `dereferenceable(<n>)`
引数や戻り値のポインタが再参照可能（参照先のデータを取得できる）であることを示す。
- `dereferenceable_or_null(<n>)`
引数や戻り値が再参照可能かnullであることを示す。
- `swiftself`
引数がself/contextであることを示す。
- `swiftasync`
引数が非同期コンテキストであることを示す。これによりポインタを格納する拡張フレームレコードが行われる。
- `swifterror`
Swiftのエラーハンドリングを最適化するためのアトリビュート。
- `immarg`
引数が即値（整数や浮動小数点の定数）でなければならないことを示す。
- `noundef`
引数や戻り値が未定義ビットを含まないことを示す。未定義やポイズンビットがある場合、動作が未定義となる。
- `nofpclass (<test mask>)`
浮動小数点型や浮動小数点型のベクトル、そのような型の配列を持つ引数、戻り値に適用され、マスクによってどのクラスの浮動小数点が許されないかを示す。クラスとビットマスクの値の対応は[表](https://llvm.org/docs/LangRef.html#id1864)を参照。
- `alignstack (<n>)`
呼び出し規約のローワリングで、この引数をスタックスロットに割り当てる際、バックエンドが考慮するアラインメントを示す。このアトリビュートは、バックエンドの基本型にマッピングされていない言語固有のアラインメント情報を伝達する目的で利用される。
- `allocalign`
このアトリビュートで示された引数が、この関数が返す新しく割り当てられたブロックのアラインメントであることを示す。戻り値は指定されたアラインメントを持つかnullポインタでなければならない。
- `allocptr`
このアトリビュートで示された引数が、アロケータによって操作されるポインタであることを示す。
- `readnone`
このアトリビュートは、そのポインタが他のポインタを通してアクセスされた場合に、そのポインタがさすメモリを読み書きする可能性があっても関数が再参照（参照先のデータを取得）しないことを示す。
- `readonly`
関数がこのポインタ引数を通して書き込まないことを示す。
- `writeonly`
関数がこのポインタ引数に書き込むことはできるが、このポインタ引数を通して読み込むことはないことを示す。
- `writable`
deferenceable(N)やポインタ引数の最初のNバイトが再参照可能であることを意味する他のアトリビュートと組み合わせて使用し、最初のNバイトが関数に入る際、非アトミックにロードされ、ストアバックされることを示す。
- `initializes((Lo1, Hi1), ...)`
関数がポインタ引数の指定されたメモリ範囲を初期化することを示す。
- `dead_on_unwind`
callerはメモリの内容に依存しないという意味で、呼び出しが巻き戻された場合、そのポインタ引数が死んでいることを示す。
- `range(<ty> <a>, <b>)`
引数や戻り値の値の範囲を示す。もし値がその範囲外である場合はポイズンとなる。ベクトル型の引数の場合はエレメントワイズに適用される。