What You Need To Know About SPIR-V 1.0

Written by Michael Larabel in Standards on 16 November 2015 at 12:49 PM EST. 12 Comments
STANDARDS
For those that haven't been paying attention to SPIR-V as the new intermediate representation that makes up OpenCL 2.1+ and Vulkan, here's various details about this newest Khronos Group specification you may not be familiar with now that Khronos formally released OpenCL 2.1 and SPIR-V 1.0..

Like all Khronos specifications, this IR specification was designed over the period of months by Khronos Group member companies. The authors of SPIR-V 1.0 are listed as:
Connor Abbott, Intel
Alexey Badar, Intel
Dan Baker, Oxide Games
Kenneth Benzie, Codeplay
Gordon Brown, Codeplay
Pat Brown, NVIDIA
Diana Po-Yu Chen, MediaTek
Stephen Clarke, Imagination
Patrick Doane, Blizzard Entertainment
Stefanus Du Toit, Google
Tim Foley, Intel
Ben Gaster, Qualcomm
Alexander Galazin, ARM
Christopher Gautier, ARM
Neil Henning, Codeplay
Kerch Holt, NVIDIA
Lee Howes, Qualcomm
Roy Ju, MediaTek
Daniel Koch, NVIDIA
Ashwin Kolhe, NVIDIA
Raun Krisch, Intel
Graeme Leese, Broadcom
Yuan Lin, NVIDIA
Yaxun Liu, AMD
Timothy Lottes, Epic Games
John McDonald, Valve
David Neto, Google
Christophe Riccio, Unity
Andrew Richards, Codeplay
Ian Romanick, Intel
Graham Sellers, AMD
Robert Simpson, Qualcomm
Brian Sumner, AMD
Andrew Woloszyn, Google
Weifeng Zhang, Qualcomm
So in looking at a company breakdown of the listed authors: NVIDIA [5], Intel [5], Qualcomm [4], Codeplay [4], AMD [3], Google [3], ARM [2], MediaTek [2], Valve [1], Unity [1], Epic Games [1], Broadcom [1], Imagination [1], Blizzard Entertainment [1], Oxide Games [1]. NVIDIA and Intel have the most involved. Also worth a shout out to one of the listed developers: Connor Abbott. If the name doesn't ring a bell, he began contributing to open-source graphics while in high school via the Lima driver project. When he was fresh out of high school, he interned at Intel and fleshed out NIR, the new intermediate representation used by some Mesa / Gallium3D drivers. So in between university and his time working on Mesa, he's also been working on SPIR-V through Intel.

Unlike the earlier SPIR specifications, SPIR-V isn't based on LLVM IR. Instead, it's a fresh design and with that has native support for graphics and compute constructs. SPIR-V is of importance to OpenGL, GLSL, OpenCL++, and -- of course -- Vulkan.

While SPIR-V isn't derived from LLVM IR, it still can be converted to/from LLVM IR. Khronos has made the translators available via GitHub along with some other SPIR-V 1.0 tools.

While a binary format, for those curious what SPIR-V looks like in disassembled, human-readable form, here's a look with the output from the SPIR-V documentation showing a GLSL fragment shader. Khronos made public their open-source SPIR-V assembler and disassembler too.

; Magic:     0x07230203 (SPIR-V)
; Version:   0x00010000 (Version: 1.0.0)
; Generator: 0x00080001 (Khronos Glslang Reference Front End; 1)
; Bound:     58
; Schema:    0

               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main" %22 %38 %20
               OpExecutionMode %4 OriginLowerLeft

; Debug information
               OpSource GLSL 450
               OpName %4 "main"
               OpName %9 "scale"
               OpName %15 "cond"
               OpName %20 "color"
               OpName %22 "color1"
               OpName %28 "S"
               OpMemberName %28 0 "b"
               OpMemberName %28 1 "v"
               OpMemberName %28 2 "i"
               OpName %30 "s"
               OpName %38 "color2"
               OpName %44 "i"
               OpName %52 "multiplier"

; Annotations (non-debug)
               OpDecorate %38 NoPerspective

; All types, variables, and constants
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2                       ; void ()
          %6 = OpTypeFloat 32                          ; 32-bit float
          %7 = OpTypeVector %6 4                       ; vec4
          %8 = OpTypePointer Function %7               ; function-local vec4*
         %10 = OpConstant %6 1.0
         %11 = OpConstant %6 2.0
         %12 = OpConstantComposite %7 %10 %10 %11 %10  ; vec4(1.0, 1.0, 2.0, 1.0)
         %13 = OpTypeBool
         %14 = OpTypePointer UniformConstant %13       ; uniform bool*
         %15 = OpVariable %14 UniformConstant          ; cond
         %19 = OpTypePointer Output %7                 ; out vec4
         %20 = OpVariable %19 Output                   ; color
         %21 = OpTypePointer Input %7                  ; in vec4
         %22 = OpVariable %21 Input                    ; color1
         %24 = OpTypeInt 32 0
         %25 = OpConstant %24 5
         %26 = OpTypeArray %7 %25
         %27 = OpTypeInt 32 1
         %28 = OpTypeStruct %13 %26 %27                ; struct S
         %29 = OpTypePointer UniformConstant %28       ; uniform struct S*
         %30 = OpVariable %29 UniformConstant          ; s
         %31 = OpConstant %27 1
         %32 = OpConstant %27 2
         %33 = OpTypePointer UniformConstant %7        ; uniform S
         %38 = OpVariable %21 Input                    ; color2
         %43 = OpTypePointer Function %27
         %45 = OpConstant %27 0
         %50 = OpConstant %27 4
         %52 = OpVariable %33 UniformConstant          ; multiplier

; All functions
          %4 = OpFunction %2 None %3                   ; main
          %5 = OpLabel
          %9 = OpVariable %8 Function
         %44 = OpVariable %43 Function
               OpStore %9 %12
         %16 = OpLoad %13 %15
               OpSelectionMerge %18 None               ; structured if
               OpBranchConditional %16 %17 %37         ; if (cond)
         %17 = OpLabel                                 ; then
         %23 = OpLoad %7 %22
         %34 = OpAccessChain %33 %30 %31 %32           ; s.v[2]
         %35 = OpLoad %7 %34
         %36 = OpFAdd %7 %23 %35
               OpStore %20 %36
               OpBranch %18
         %37 = OpLabel                                 ; else
         %39 = OpLoad %7 %38
         %40 = OpExtInst %7 %1 Sqrt %39
         %41 = OpLoad %7 %9
         %42 = OpFMul %7 %40 %41
               OpStore %20 %42
               OpBranch %18
         %18 = OpLabel                                 ; end if
               OpStore %44 %45
               OpBranch %46
         %46 = OpLabel                                 ; loop header
         %49 = OpLoad %27 %44
         %51 = OpSLessThan %13 %49 %50
               OpLoopMerge %47 %46 None                ; structured loop
               OpBranchConditional %51 %48 %47         ; body or break
         %48 = OpLabel                                 ; body
         %53 = OpLoad %7 %52
         %54 = OpLoad %7 %20
         %55 = OpFMul %7 %54 %53
               OpStore %20 %55
         %56 = OpLoad %27 %44
         %57 = OpIAdd %27 %56 %31
               OpStore %44 %57
               OpBranch %46                            ; loop
         %47 = OpLabel
               OpReturn
               OpFunctionEnd

If you want to learn more about the IR, there is this white paper or the full specification.

SPIR-V 1.0 is very interesting and will be particularly interesting to see how the open-source community embraces it and what doors are opened up when leveraging LLVM.
Related News
About The Author
Michael Larabel

Michael Larabel is the principal author of Phoronix.com and founded the site in 2004 with a focus on enriching the Linux hardware experience. Michael has written more than 20,000 articles covering the state of Linux hardware support, Linux performance, graphics drivers, and other topics. Michael is also the lead developer of the Phoronix Test Suite, Phoromatic, and OpenBenchmarking.org automated benchmarking software. He can be followed via Twitter, LinkedIn, or contacted via MichaelLarabel.com.

Popular News This Week