SPIR-V ターゲットのユーザーガイド

はじめに

SPIR-V ターゲットは、公式の SPIR-V 仕様で説明されている SPIR-V バイナリ形式のコード生成を提供します。

使用法

SPIR-V バックエンドは、LLVM の静的コンパイラ (llc) または Clang から呼び出すことができ、開発者は LLVM 中間言語 (IL) ファイルまたは OpenCL カーネルソースを SPIR-V に直接コンパイルできます。このセクションでは、さまざまな目的で SPIR-V バックエンドを活用するためのさまざまなコマンドの使用法について概説します。

静的コンパイラコマンド

  1. 基本的な SPIR-V コンパイル コマンド: llc -mtriple=spirv32-unknown-unknown input.ll -o output.spvt 説明: このコマンドは、LLVM IL ファイル (input.ll) を 32 ビットアーキテクチャ用の SPIR-V バイナリ (output.spvt) にコンパイルします。

  2. 拡張機能と最適化を使用したコンパイル コマンド: llc -O1 -mtriple=spirv64-unknown-unknown –spirv-ext=+SPV_INTEL_arbitrary_precision_integers input.ll -o output.spvt 説明: LLVM IL ファイルを (-O1) 最適化を施して SPIR-V にコンパイルし、64 ビットアーキテクチャをターゲットとします。これにより、SPV_INTEL_arbitrary_precision_integers 拡張機能が有効になります。

  3. 実験的な NonSemantic.Shader.DebugInfo.100 サポートを使用したコンパイル コマンド: llc –spv-emit-nonsemantic-debug-info –spirv-ext=+SPV_KHR_non_semantic_info input.ll -o output.spvt 説明: LLVM IL ファイルを、追加の NonSemantic.Shader.DebugInfo.100 命令を使用して SPIR-V にコンパイルします。これにより、必要な SPV_KHR_non_semantic_info 拡張機能が有効になります。

  4. SPIR-V バイナリの生成 コマンド: llc -O0 -mtriple=spirv64-unknown-unknown -filetype=obj input.ll -o output.spvt 説明: 最適化なしで、64 ビット SPIR-V アーキテクチャをターゲットとする LLVM モジュールから SPIR-V オブジェクトファイル (output.spvt) を生成します。

Clang コマンド

  1. SPIR-V の生成 コマンド: clang –target=spirv64 input.cl 説明: OpenCL カーネルソースファイル (input.cl) から SPIR-V ファイルを直接生成します。

コンパイラオプション

ターゲットトリプル

SPIR-V へのクロスコンパイルには、次のオプションを使用します。

-target <アーキテクチャ><サブアーキテクチャ>-<ベンダー>-<OS>-<環境>

ターゲットトリプルを指定します。

表 112 SPIR-V アーキテクチャ

アーキテクチャ

説明

spirv32

32 ビットポインタ幅の SPIR-V。

spirv64

64 ビットポインタ幅の SPIR-V。

spirv

論理メモリレイアウトの SPIR-V。

表 113 SPIR-V サブアーキテクチャ

サブアーキテクチャ

説明

<空>

入力に基づいてバックエンドによって推論された SPIR-V バージョン。

v1.0

SPIR-V バージョン 1.0。

v1.1

SPIR-V バージョン 1.1。

v1.2

SPIR-V バージョン 1.2。

v1.3

SPIR-V バージョン 1.3。

v1.4

SPIR-V バージョン 1.4。

v1.5

SPIR-V バージョン 1.5。

v1.6

SPIR-V バージョン 1.6。

表 114 SPIR-V ベンダー

ベンダー

説明

<空>/unknown

ベンダー固有の設定がない汎用 SPIR-V ターゲット。

amd

AMDGCN ツールチェーンで使用されることを意図した、ターゲット固有の組み込み関数と ASM をサポートする AMDGCN SPIR-V ターゲット。

表 115 オペレーティングシステム

OS

説明

<空>/unknown

デフォルトは OpenCL ランタイムです。

vulkan

Vulkan シェーダーランタイム。

vulkan1.2

SPIR-V 1.5 に対応する Vulkan 1.2 ランタイム。

vulkan1.3

SPIR-V 1.6 に対応する Vulkan 1.3 ランタイム。

amdhsa

HSA 互換ランタイムで使用されることを意図した、SPIR-V 1.6 に対応する AMDHSA ランタイム。

表 116 SPIR-V 環境

環境

説明

<空>/unknown

OpenCL 環境または入力に基づいてバックエンドによって推論されます。

-target spirv64v1.0 は、64 ビットポインタ幅の SPIR-V バージョン 1.0 用にコンパイルするために使用できます。

-target spirv64-amd-amdhsa は、64 ビットポインタ幅の AMDGCN 風味の SPIR-V 用にコンパイルするために使用できます。

拡張機能

SPIR-V バックエンドは、コア SPIR-V 仕様を超えて機能を有効化または強化するさまざまな 拡張機能をサポートしています。これらの拡張機能は、-spirv-extensions オプションに続いて、有効にする拡張機能の名前を指定することで有効にできます。以下に、サポートされている SPIR-V 拡張機能のリストを示します。拡張機能名でアルファベット順にソートされています。

表 117 サポートされている SPIR-V 拡張機能

拡張機能名

説明

SPV_EXT_shader_atomic_float16_add

SPV_EXT_shader_atomic_float_add 拡張機能を拡張して、メモリ内の 16 ビット浮動小数点数へのアトミック加算をサポートします。

SPV_EXT_shader_atomic_float_add

浮動小数点数に対するアトミック加算命令を追加します。

SPV_EXT_shader_atomic_float_min_max

浮動小数点数に対するアトミック最小および最大命令を追加します。

SPV_INTEL_arbitrary_precision_integers

任意の幅の整数型を生成できるようにします。

SPV_INTEL_bfloat16_conversion

単精度 32 ビット浮動小数点値と 16 ビット bfloat16 値の間で変換する命令を追加します。

SPV_INTEL_cache_controls

メモリアクセス命令にキャッシュ制御情報を適用できるようにします。

SPV_INTEL_function_pointers

関数ポインタの変換を許可します。

SPV_INTEL_inline_assembly

インラインアセンブリの使用を許可します。

SPV_INTEL_global_variable_host_access

グローバル(モジュールスコープ)変数に適用できる装飾を追加します。

SPV_INTEL_global_variable_fpga_decorations

FPGA デバイスのコード生成を支援するために、グローバル(モジュールスコープ)変数に適用できる装飾を追加します。

SPV_INTEL_optnone

関数の最適化をしないというリクエストを示す、関数制御マスク用の OptNoneINTEL 値を追加します。

SPV_INTEL_subgroups

サブグループ内のワークアイテムが、ローカルメモリやワークグループバリアを使用せずにデータを共有し、専用のハードウェアを使用してイメージまたはバッファからデータのブロックをロードおよびストアできるようにします。

SPV_INTEL_usm_storage_classes

最適化を可能にする追加情報を提供する CrossWorkgroup ストレージクラスのサブクラスである 2 つの新しいストレージクラスを導入します。

SPV_INTEL_variable_length_array

要素数がコンパイル時に不明なローカル配列を割り当てできるようにします。

SPV_KHR_bit_instructions

シェーダー機能を必要とせずに、SPIR-V モジュールでビット命令を使用できるようにします。

SPV_KHR_expect_assume

llvm.assume および llvm.expect 組み込み関数と同様に、コンパイラに追加情報を提供します。

SPV_KHR_float_controls

丸めモード、非正規化数、符号付きゼロ、無限大の実装のデフォルトの動作をオーバーライドすることにより、浮動小数点計算を制御するための新しい実行モードを提供します。

SPV_KHR_linkonce_odr

リンクが発生したときに、同じ名前の他の関数またはグローバル変数とマージできる LinkOnceODR リンケージタイプを使用できるようにします。

SPV_KHR_no_integer_wrap_decoration

特定の命令が整数ラッピングを引き起こさないことを示す装飾を追加します。

SPV_KHR_shader_clock

コンピューティングユニットによって提供されるクロックから値をサンプリングする機能をカーネルに追加する拡張機能 cl_khr_kernel_clock を追加します。

SPV_KHR_subgroup_rotate

サブグループ内の呼び出し間で値をローテーションできるようにする新しい命令を追加します。

SPV_KHR_uniform_group_instructions

均一な制御フロー内での追加のグループ演算のサポートを許可します。

SPV_KHR_non_semantic_info

セマンティックな影響がなく、モジュールから安全に削除できる拡張命令セットを宣言する機能を追加します。

複数の拡張機能を有効にするには、スペースで区切ってそれらをリストします。たとえば、浮動小数点数と任意の精度整数に対するアトミック演算のサポートを有効にするには、次を使用します。

-spirv-ext=+SPV_EXT_shader_atomic_float_add,+SPV_INTEL_arbitrary_precision_integers

すべての拡張機能を有効にするには、次のオプションを使用します: -spirv-ext=all

指定されたものを除くすべての拡張機能を有効にするには、all に続けて、許可されない拡張機能のリストを指定します。例:-spirv-ext=all,-SPV_INTEL_arbitrary_precision_integers

LLVM IR における SPIR-V 表現

SPIR-V は、LLVM IR を含むさまざまな中間表現 (IR) とのシームレスな統合を意図的に設計されており、そのエンティティのほとんどを直接マッピングできます。SPIR-V バックエンドの開発は、Khronos Group SPIR-V LLVM Translator との互換性の原則に基づいて進められてきました。その結果、SPIR-V バックエンドによって受け入れられる入力表現は、LLVM ドキュメントにおける SPIR-V 表現で詳述されているものとほぼ一致しています。このドキュメントと以下のセクションでは、このバックエンドが処理する LLVM IR と他のツールで使用される規則との間の主なポイントと相違点に焦点を当てています。

特殊な型

SPIR-V は、いくつかの種類の不透明型を指定します。これらの型は、ターゲット拡張機能型を使用して表され、次のように表されます。

表 118 SPIR-V 不透明型

SPIR-V 型

LLVM 型名

LLVM 型引数

OpTypeImage

spirv.Image

サンプリングされた型、次元、深さ、配列化、MS、サンプリング、イメージ形式、アクセス修飾子

OpTypeSampler

spirv.Sampler

(なし)

OpTypeSampledImage

spirv.SampledImage

サンプリングされた型、次元、深さ、配列化、MS、サンプリング、イメージ形式、アクセス修飾子

OpTypeEvent

spirv.Event

(なし)

OpTypeDeviceEvent

spirv.DeviceEvent

(なし)

OpTypeReserveId

spirv.ReserveId

(なし)

OpTypeQueue

spirv.Queue

(なし)

OpTypePipe

spirv.Pipe

アクセス修飾子

OpTypePipeStorage

spirv.PipeStorage

(なし)

すべての整数引数は、対応する SPIR-V 命令と同じ値を持ちます。例えば、OpenCL 型の image2d_depth_ro_t は、SPIR-V IR では target("spirv.Image", void, 1, 1, 0, 0, 0, 0, 0) と表現され、その次元パラメータは 1 であり、2D を意味します。サンプリングされたイメージ型には、その基礎となるイメージ型のパラメータが含まれるため、前の型のサンプリングされたイメージは、target("spirv.SampledImage, void, 1, 1, 0, 0, 0, 0, 0) という表現になります。

ターゲットイントリンシック

SPIR-V バックエンドは、正しく効率的な SPIR-V コードを生成するために不可欠な、さまざまな低レベル操作を容易にするために、いくつかの LLVM IR イントリンシックを使用しています。これらのイントリンシックは、型割り当てやメモリ管理から、制御フローやアトミック操作まで、幅広い機能を網羅しています。以下は、SPIR-V バックエンドで使用される、選択されたイントリンシックの詳細な表と、その説明および引数の詳細です。

表 119 SPIR-V 用の LLVM IR イントリンシック

イントリンシック ID

戻り値の型

引数の型

説明

int_spv_assign_type

None

[型, メタデータ]

メタデータに型を関連付けます。これは、SPIR-V 構造体で型情報を維持するために重要です。直接出力されるわけではありませんが、内部で型システムをサポートします。

int_spv_assign_ptr_type

None

[型, メタデータ, 整数]

int_spv_assign_type と同様ですが、ポインタ型用で、追加の整数でストレージクラスを指定します。SPIR-V の詳細なポインタ型システムをサポートします。直接出力されるわけではありません。

int_spv_assign_name

None

[型, 可変長引数]

型または値に名前を割り当て、SPIR-V コードの可読性とデバッグ性を向上させます。直接出力されるわけではありませんが、メタデータの強化に使用されます。

int_spv_assign_decoration

None

[型, メタデータ]

メタデータと関連付けることで、値にデコレーションを割り当てます。直接出力されるわけではありませんが、LLVM IR での SPIR-V 表現をサポートするために使用されます。

int_spv_track_constant

[型, メタデータ]

SPIR-V モジュール内の定数を追跡します。最適化と冗長性の削減に不可欠です。内部使用でのみ出力されます。

int_spv_init_global

None

[型, 型]

グローバル変数を初期化します。これは、SPIR-V での正しいグローバル状態管理を確実にするために必要なステップです。内部使用でのみ出力されます。

int_spv_unref_global

None

[型]

グローバル変数を参照解除としてマークすることにより、グローバル変数の寿命を管理します。これにより、グローバル変数の使用に関する最適化が可能になります。内部使用でのみ出力されます。

int_spv_gep

ポインタ

[ブール値, 型, 可変長引数]

複合型のサブ要素のアドレスを計算します。配列要素や構造体フィールドにアクセスするために重要です。ジェネリックな方法で要素を条件付きでアドレス指定することをサポートします。

int_spv_load

32 ビット整数

[ポインタ, 16 ビット整数, 8 ビット整数]

メモリ位置から値をロードします。追加の整数は、メモリアクセスとアラインメントの詳細を指定します。これは、正しく効率的なメモリ操作を保証するために不可欠です。

int_spv_store

None

[型, ポインタ, 16 ビット整数, 8 ビット整数]

メモリ位置に値を格納します。int_spv_load と同様に、メモリアクセスとアラインメントの仕様が含まれており、メモリ操作に不可欠です。

int_spv_extractv

[32 ビット整数, 可変長引数]

ベクトルから値を抽出します。これにより、SPIR-V 内でのベクトル操作が可能になります。ベクトルコンポーネントの操作を可能にします。

int_spv_insertv

32 ビット整数

[32 ビット整数, 型, 可変長引数]

ベクトルに値を挿入します。int_spv_extractv を補完するもので、ベクトルの構築と操作を容易にします。

int_spv_extractelt

[型, 任意の整数]

インデックスに基づいて、複合型から要素を抽出します。配列やベクトルの操作に不可欠です。

int_spv_insertelt

[型, 型, 任意の整数]

指定されたインデックスで、複合型に要素を挿入します。配列やベクトルの構築と変更を可能にします。

int_spv_const_composite

[可変長引数]

与えられた要素から複合型を構築します。個々のコンポーネントから配列、構造体、ベクトルを作成するための鍵となります。

int_spv_bitcast

[型]

型間のビットごとのキャストを実行します。ビット表現を変更しない型変換に不可欠です。

int_spv_ptrcast

[型, メタデータ, 整数]

異なる型間でポインタをキャストします。int_spv_bitcast と同様ですが、特にポインタ用であり、SPIR-V の厳密な型システムを考慮します。

int_spv_switch

None

[型, 可変長引数]

値に基づいてマルチウェイ分岐を実装します。高水準言語の switch 文と同様に、複雑な制御フロー構造を可能にします。

int_spv_cmpxchg

32 ビット整数

[型, 可変長引数]

アトミックな比較と交換操作を実行します。コンピュートシェーダーでの同期と並行性制御に不可欠です。

int_spv_unreachable

None

[]

到達すべきではないコード内のポイントをマークします。これにより、到達不能なコードパスを示すことで、最適化が可能になります。

int_spv_alloca

[]

スタックにメモリを割り当てます。関数内のローカル変数ストレージの基本となります。

int_spv_alloca_array

[任意の整数]

スタックに配列を割り当てます。int_spv_alloca を拡張して、配列割り当てをサポートします。一時的な配列に不可欠です。

int_spv_undef

32 ビット整数

[]

未定義の値を生成します。最適化や未初期化変数の指示に役立ちます。

int_spv_inline_asm

None

[メタデータ, メタデータ, 可変長引数]

メタデータを作成し、元の引数を保持することで、インラインアセンブリ機能をインラインアセンブリ呼び出しインスタンスに関連付けます。直接出力されるわけではありませんが、LLVM IR での SPIR-V 表現をサポートするために使用されます。

int_spv_assume

None

[1 ビット整数]

プログラムの状態について想定できることについて、オプティマイザーにヒントを提供します。最適化の可能性を向上させます。

int_spv_expect

任意の整数型

[型, 型]

予期される分岐パスを示すことで、分岐予測をガイドします。一般的なコードパスを最適化することでパフォーマンスを向上させます。

int_spv_thread_id

32 ビット整数

[32 ビット整数]

ワークグループ内のスレッド ID を取得します。並列計算操作で実行コンテキストを識別するために不可欠です。

int_spv_create_handle

ポインタ

[8 ビット整数]

グラフィックスまたは計算リソースのリソースハンドルを作成します。シェーダーでのリソースの管理と使用を容易にします。

組み込み関数

次のセクションでは、LLVM IR における SPIR-V 組み込み関数の表現を強調し、LLVM に直接対応するものがない組み込み関数を強調します。

関数呼び出しとしての命令

直接対応する LLVM がない SPIR-V 組み込み関数は、LLVM 関数呼び出しとして表されます。これらの関数は、SPIR-V 組み込み関数と呼ばれ、SPIR-V 固有の拡張機能を使用した IA64 マングリングスキームに従います。組み込み関数への非マングリング呼び出しの解析は、一部のケースでサポートされていますが、広範囲にはテストされていません。一般的な形式は

__spirv_{OpCodeName}{_OptionalPostfixes}

ここで、{OpCodeName} は「Op」プレフィックスなしの SPIR-V オペコード名であり、{OptionalPostfixes} は、もしあれば、デコレーション固有のポストフィックスです。マングリングとポストフィックスにより、LLVM のフレームワーク内で SPIR-V の豊富な命令セットを表現できます。

拡張命令セット

SPIR-V は、OpenCL 固有の操作など、追加機能のためのいくつかの拡張命令セットを定義します。LLVM IR では、これらは、マングリングされた組み込み関数への関数呼び出しによって表現され、環境に基づいて選択されます。例えば

acos_f32

は、float32 入力に対する OpenCL 拡張命令セットの acos 関数を表します。

組み込み変数

特別なハードウェアまたは実行モデルのプロパティへのアクセスを提供する SPIR-V 組み込み変数は、LLVM 関数呼び出しまたは LLVM グローバル変数のいずれかにマッピングされます。表現は、次の命名規則に従います

__spirv_BuiltIn{VariableName}

例えば、SPIR-V 組み込み関数 GlobalInvocationId は、LLVM IR では __spirv_BuiltInGlobalInvocationId としてアクセスできます。

ベクトルのロードとストアの組み込み関数

ベクトルのロードと格納に対する SPIR-V の機能は、SPIR-V 命令を模倣する関数を使用して LLVM IR で表現されます。これらの組み込み関数は、LLVM のネイティブ命令が直接サポートしていないケースを処理し、メモリ操作に対するきめ細かい制御を可能にします。

アトミック操作

特に浮動小数点データを操作する SPIR-V のアトミック操作は、LLVM IR で対応する関数呼び出しによって表現されます。これらの組み込み関数は、LLVM が直接サポートしていない可能性がある操作でのアトミック性を保証します。これは、並列実行と同期に不可欠です。

イメージ操作

SPIR-V は、イメージとサンプラーの操作を広範にサポートしており、LLVM は、組み込み関数への関数呼び出しによってそれらを表します。これには、イメージの読み取り、書き込み、クエリが含まれており、イメージデータとパラメータの詳細な操作が可能になります。

グループ操作とサブグループ操作

ワークグループおよびサブグループの操作では、LLVM は関数呼び出しを使用して SPIR-V のグループベースの命令を表します。これらの組み込み関数は、効率的な並列計算に不可欠なグループ同期、データ共有、および集団操作を容易にします。