SPIR-V 目標使用者指南¶
簡介¶
SPIR-V 目標提供 SPIR-V 官方規範 中所述 SPIR-V 二進位格式的程式碼產生。
用法¶
SPIR-V 後端可以從 LLVM 的靜態編譯器 (llc) 或 Clang 呼叫,允許開發人員將 LLVM 中間語言 (IL) 檔案或 OpenCL 核心來源直接編譯成 SPIR-V。本節概述了利用 SPIR-V 後端實現不同目的的各種命令的用法。
靜態編譯器命令¶
**基本 SPIR-V 編譯** 命令:llc -mtriple=spirv32-unknown-unknown input.ll -o output.spvt 說明:此命令將 LLVM IL 檔案 (input.ll) 編譯成 32 位元架構的 SPIR-V 二進位檔案 (output.spvt)。
**使用擴充和最佳化的編譯** 命令:llc -O1 -mtriple=spirv64-unknown-unknown –spirv-ext=+SPV_INTEL_arbitrary_precision_integers input.ll -o output.spvt 說明:將 LLVM IL 檔案編譯成 SPIR-V,並使用 (-O1) 最佳化,目標為 64 位元架構。它啟用了 SPV_INTEL_arbitrary_precision_integers 擴充。
**使用實驗性 NonSemantic.Shader.DebugInfo.100 支援的編譯** 命令:llc –spv-emit-nonsemantic-debug-info –spirv-ext=+SPV_KHR_non_semantic_info input.ll -o output.spvt 說明:將 LLVM IL 檔案編譯成 SPIR-V,並帶有額外的 NonSemantic.Shader.DebugInfo.100 指令。它啟用了所需的 SPV_KHR_non_semantic_info 擴充。
**SPIR-V 二進位檔案產生** 命令:llc -O0 -mtriple=spirv64-unknown-unknown -filetype=obj input.ll -o output.spvt 說明:從 LLVM 模組產生 SPIR-V 物件檔案 (output.spvt),目標為 64 位元 SPIR-V 架構,無需最佳化。
Clang 命令¶
**SPIR-V 產生** 命令:clang –target=spirv64 input.cl 說明:直接從 OpenCL 核心來源檔案 (input.cl) 產生 SPIR-V 檔案。
編譯器選項¶
目標三元組¶
對於交叉編譯成 SPIR-V,請使用選項
-target <架構><子架構>-<廠商>-<作業系統>-<環境>
指定目標三元組
表 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 供應商¶ 供應商
說明
<空>/
未知
沒有任何供應商特定設定的通用 SPIR-V 目標。
amd
AMDGCN SPIR-V 目標,支援目標特定的內建函式和 ASM,旨在由 AMDGCN 工具鏈使用。
表 115 作業系統¶ 作業系統
說明
<空>/
未知
預設為 OpenCL 執行階段。
vulkan
Vulkan 著色器執行階段。
vulkan1.2
Vulkan 1.2 執行階段,對應於 SPIR-V 1.5。
vulkan1.3
Vulkan 1.3 執行階段,對應於 SPIR-V 1.6。
amdhsa
AMDHSA 執行階段,旨在用於與 HSA 相容的執行階段,對應於 SPIR-V 1.6。
表 116 SPIR-V 環境¶ 環境
說明
<空>/
未知
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 擴充功能列表
擴充功能名稱 |
說明 |
---|---|
|
擴展 SPV_EXT_shader_atomic_float_add 擴充功能,以支援對記憶體中的 16 位元浮點數進行原子加法。 |
|
新增對浮點數的原子加法指令。 |
|
新增對浮點數的原子最小值和最大值指令。 |
|
允許產生任意寬度的整數型別。 |
|
新增在單精度 32 位元浮點值和 16 位元 bfloat16 值之間轉換的指令。 |
|
允許將快取控制資訊應用於記憶體存取指令。 |
|
允許轉譯函式指標。 |
|
允許使用內嵌組譯。 |
|
新增可以應用於全域(模組範圍)變數的裝飾。 |
|
新增可以應用於全域(模組範圍)變數的裝飾,以協助 FPGA 裝置的程式碼產生。 |
|
為函式控制遮罩新增 OptNoneINTEL 值,表示請求不要最佳化函式。 |
|
允許子群組中的工作項目在不使用本地記憶體和工作群組屏障的情況下共用資料,並利用專用硬體從圖像或緩衝區載入和儲存資料塊。 |
|
引入了兩個新的儲存類別,它們是 CrossWorkgroup 儲存類別的子類別,提供可啟用最佳化的額外資訊。 |
|
允許配置在編譯時元素數量未知的本地陣列。 |
|
允許 SPIR-V 模組使用位指令,而無需 Shader 功能。 |
|
類似於 llvm.assume 和 llvm.expect 內建函式,提供額外的編譯器資訊。 |
|
提供新的執行模式,透過覆寫實作對捨入模式、非正規數、帶符號零和無窮大的預設行為來控制浮點數計算。 |
|
允許使用 LinkOnceODR 連結類型,該類型允許在連結時將函式或全域變數與同名的其他函式或全域變數合併。 |
|
新增修飾詞以指示給定指令不會導致整數溢位。 |
|
新增擴充 cl_khr_kernel_clock,允許內核從計算單元提供的時鐘採樣值。 |
|
新增一條新指令,允許在子群組內的調用之間旋轉值。 |
|
允許在統一控制流程中支援額外的群組操作。 |
|
新增宣告擴充指令集的功能,這些指令集沒有語義影響,可以安全地從模組中移除。 |
若要啟用多個擴充,請以空格分隔列出它們。例如,若要啟用對浮點數和任意精度整數的原子操作支援,請使用
-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 旨在與各種中介表示 (IR) 無縫整合,包括 LLVM IR,方便大多數實體的直接映射。SPIR-V 後端的開發遵循與 Khronos Group SPIR-V LLVM 轉譯器 相容的原則。因此,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
,表示二维。采样图像类型包含其底层图像类型的参数,因此先前类型的采样图像表示为 target("spirv.SampledImage, void, 1, 1, 0, 0, 0, 0, 0)
。
目標內建函式¶
SPIR-V 後端採用多種 LLVM IR 內建函式,這些函式有助於執行生成正確且高效的 SPIR-V 代碼所需的各種低階操作。這些內建函式的功能涵蓋類型分配和記憶體管理,以及控制流程和原子操作。下表詳細列出了 SPIR-V 後端中使用的選定內建函式,以及它們的描述和參數詳細資訊。
內建函式 ID |
返回類型 |
參數類型 |
說明 |
---|---|---|---|
int_spv_assign_type |
無 |
[類型、中繼資料] |
將類型與中繼資料關聯,這對於維護 SPIR-V 結構中的類型資訊至關重要。不會直接發出,但在內部支援類型系統。 |
int_spv_assign_ptr_type |
無 |
[類型、中繼資料、整數] |
類似於 int_spv_assign_type,但適用於帶有指定儲存類別的額外整數的指標類型。支援 SPIR-V 的詳細指標類型系統。不會直接發出。 |
int_spv_assign_name |
無 |
[類型、可變參數] |
為類型或值分配名稱,增強 SPIR-V 代碼的可讀性和可除錯性。不會直接發出,但用於豐富中繼資料。 |
int_spv_assign_decoration |
無 |
[類型、中繼資料] |
通過將裝飾與中繼資料關聯來將其分配給值。不會直接發出,但用於在 LLVM IR 中支援 SPIR-V 表示。 |
int_spv_track_constant |
類型 |
[類型、中繼資料] |
追蹤 SPIR-V 模組中的常數。對於優化和減少冗餘至關重要。僅發出供內部使用。 |
int_spv_init_global |
無 |
[類型、類型] |
初始化全域變數,這是確保 SPIR-V 中正確的全域狀態管理的必要步驟。僅發出供內部使用。 |
int_spv_unref_global |
無 |
[類型] |
通過將全域變數標記為未引用來管理其生命週期,從而實現與全域變數使用相關的優化。僅發出供內部使用。 |
int_spv_gep |
指標 |
[布林值、類型、可變參數] |
計算聚合類型子元素的地址。對於存取陣列元素和結構欄位至關重要。以通用的方式支援有條件地定址元素。 |
int_spv_load |
32 位元整數 |
[指標、16 位元整數、8 位元整數] |
從記憶體位置載入值。額外的整數指定記憶體存取和對齊方式的詳細資訊,這對於確保正確且高效的記憶體操作至關重要。 |
int_spv_store |
無 |
[類型、指標、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 |
無 |
[類型、可變參數] |
根據值實現多路分支。啟用複雜的控制流程結構,類似於高階語言中的 switch 語句。 |
int_spv_cmpxchg |
32 位元整數 |
[類型、可變參數] |
執行原子比較和交換操作。對於計算著色器中的同步和並發控制至關重要。 |
int_spv_unreachable |
無 |
[] |
標記程式碼中永遠不應到達的點,通過指示不可到達的程式碼路徑來啟用優化。 |
int_spv_alloca |
類型 |
[] |
在堆疊上分配記憶體。函數中局部變數儲存的基本。 |
int_spv_alloca_array |
類型 |
[任何整數] |
在堆疊上分配陣列。擴展 int_spv_alloca 以支援陣列分配,這對於臨時陣列至關重要。 |
int_spv_undef |
32 位元整數 |
[] |
產生未定義的值。用於優化和指示未初始化的變數。 |
int_spv_inline_asm |
無 |
[中繼資料, 中繼資料, 可變參數] |
通過創建中繼資料並保留原始參數,將內聯組譯功能關聯到內聯組譯呼叫實例。不直接發出,而是用於支援 LLVM IR 中的 SPIR-V 表示。 |
int_spv_assume |
無 |
[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
表示 OpenCL 擴展指令集中用於 float32 輸入的 acos 函數。
內建變數¶
SPIR-V 內建變數提供對特殊硬體或執行模型屬性的存取,它們會映射到 LLVM 函數呼叫或 LLVM 全域變數。表示法遵循命名慣例
__spirv_BuiltIn{VariableName}
例如,SPIR-V 內建變數 GlobalInvocationId 在 LLVM IR 中可作為 __spirv_BuiltInGlobalInvocationId 存取。
向量載入和儲存內建函數¶
SPIR-V 的向量載入和儲存功能在 LLVM IR 中使用模擬 SPIR-V 指令的函數來表示。這些內建函數處理 LLVM 原生指令不直接支援的情況,可以對記憶體操作進行細粒度控制。
原子操作¶
SPIR-V 的原子操作,特別是對浮點數資料進行的操作,在 LLVM IR 中以相應的函數呼叫表示。這些內建函數確保 LLVM 可能沒有直接支援的操作的原子性,這對於平行執行和同步至關重要。
影像操作¶
SPIR-V 提供對影像和取樣器操作的廣泛支援,LLVM 透過對內建函數的函數呼叫來表示這些操作。這些操作包括影像讀取、寫入和查詢,允許對影像資料和參數進行詳細操作。
群組和子群組操作¶
對於工作群組和子群組操作,LLVM 使用函數呼叫來表示 SPIR-V 的基於群組的指令。這些內建函數有助於群組同步、資料共用和集體操作,這些操作對於高效的平行計算至關重要。