単子葉類プログラマーのメモ

C++、LLVMについて思いついたことや勉強したことのまとめ

LLVM言語 学習メモ (4) - 識別子、型、定数

LLVMLLVM言語識別子定数リテラル)の仕様についての自分用メモ。

本家ドキュメントから今自分に必要そうな部分を抜き出し、日本語の情報として残しておく。

LLVMのバージョンは10.0.0

目次

識別子

関数、レジスタ、型につける名前を「識別子」と呼ぶ。

識別子にはvalue(値)を割り当てることができる。

要するに、識別子は一般的なプログラミング言語における変数のようなものと理解すればよい。

ただし、LLVM言語においては識別子と変数は区別すべきと思われる。 ここでいう変数とは、スタック領域に配置されるローカル変数や、静的領域に配置されるグローバル変数などのこと。 LLVM言語では、これらの変数には名前を付けることができず、ポインタ型の識別子経由でアクセスする必要がある。

識別子の先頭には、@%をつける。

  • 先頭が@の場合はグローバル識別子になる。
  • 先頭が%の場合はローカル識別子になる。

識別子には名前付きの値と無名の値がある。

  • 名前付きの値
    • 識別子につけられる名前の書式は、正規表現であらわすと[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*
  • 名前なしの値
    • 明示的に名前を付けなかった場合、名前として@%と数値が割り当てられる。数値は、関数内に登場した順番に0から割り当てられる。
    • 関数の引数と先頭ブロックに名前を付けていない場合、それらも無名の値として番号が割り当てられる。
    • 例:

      define i32 @main(i32, i8**) {
          add i32 %0, 10
          ret i32 %3
      }
      
      • main関数の2つの引数それぞれに%0%1が割り当てられる。
      • 関数の先頭のブロックにラベル%2が割り当てられる。
      • add命令の戻り値に%3が割り当てられる。

LLVM言語は静的型付き言語である。

型は大きく分けて以下の3つ。

  • Void型
  • 関数型
  • ファーストクラス型

ファーストクラス型とは、主に以下のような性質を持つ型のことである(参考)。

  • 引数として渡せる
  • 関数から返せる
  • 変更できる
  • 変数に割り当てられる

LLVM言語におけるファーストクラス型は、整数型、浮動小数点型、ポインタ型、配列型、構造体型など。

以降で示す各型の構文は、他の何らかの構文の中の<type><ty>等の部分に記述できるものを表す。

Void型

値とサイズを持たない型。

構文

void

例えば、call <ty> <fnptrval>()という引数なしの関数呼び出しの構文に対して、戻り値の型がVoid型である関数fooを呼び出す場合、以下のように書く。

call void @foo()

関数型

返却値の型と引数の型のリストからなる関数を表す型。 いわゆる関数シグネチャのこと。

構文

<returntype> (<parameter list>)

<returntype>はラベルとメタデータ以外の任意の型。

<parameter list>は、カンマ区切り型のリスト。

i32 (i32) i32型を引数にとりi32型を返す関数
float (i16, i32 *) * i16型とi32のポインタ型を引数にとり、floatを返す関数へのポインタ
{i32, i32} (i32) i32型を引数にとり、2つのi32型を持つ構造体を返す関数

ファーストクラス型

整数型

1から2の32乗-1までの任意のビット幅を持つ整数。

構文

iN

Nはビット幅を表す整数。

i1 1ビット幅整数
i32 32ビット幅整数
i8388607 800万以上のビット幅の整数

LLVM言語ではC言語などと違って、型は符号付きか符号なしかの情報を持たない。 演算の際に、符号付きか符号なしかを指定する。

浮動小数点数

説明
half 16ビット浮動小数点数
float 32ビット浮動小数点数
double 64ビット浮動小数点数
fp128 128ビット浮動小数点数 (112ビットが仮数部)
x86_fp80 80ビット浮動小数点数X87
ppc_fp128 128ビット浮動小数点数(2つの64ビット)

half、float、double、fp128のバイナリ形式はそれぞれ、IEEE-754-2008のbinary16、binary32、binary64、binary128に対応する。

ポインタ型

メモリ位置を指す型。

構文

<type>*

[4 x i32]* i32配列のポインタ
i32 (i32*) * i32*型を引数にとりi32型を返す関数のポインタ

LLVM言語ではvoid*label*は使えない。代わりにi8*を使う。

ラベル型

ラベルを表す型。

構文

label

配列型

同じ型の要素を複数もつデータ構造を表す型。

構文

[<# elements> x <elementtype>]

<# elements>は要素数

<elementtype>は要素の型。

[40 x i32] 32ビット整数の配列
[3 x [4 x i32]] 二次元配列
[2 x [3 x [4 x i16]]] 三次元配列

構造体型

複数の任意の型の組み合わせを表す型。

構文

type { <type list> }

{i32, i32, i32} 3つの整数の組

定数

公式ドキュメントではconstants(定数)と記述されているが、いわゆるリテラルのこと。

単純な定数

  • ブール定数
    • truefalse
    • 型はi1
  • 整数定数
    • 4などの整数
    • 負の数も使用可能。
  • 浮動小数点定数
    • 3つの表記方法がある
      • 10進表記(例:123.421
        • 2進数で表現できない小数を10進表記で指定することはできない(例:1.3はNG)
      • 指数表記(例:1.23421e+2)
      • IEEE754の16進表記(例:0x432ff973cafa8000)
  • nullポインター定数

複雑な定数

  • 構造体定数
    • {}で囲んだカンマ区切りの値のリスト(例:{ i32 4, float 17.0, i32* @G }
  • 配列定数
    • []で囲んだカンマ区切りの値のリスト(例:[ i32 42, i32 11, i32 74 ]
    • 文字列定数はc""で囲む(例:c"Hello World\0A\00"
  • ゼロ初期化
    • zeroinitializerで任意の型の値をゼロ値に初期化できる。