12

I have been reading about heterogeneous computing and came across SPIR-V. There I found the following:

SPIR-V is the first open standard, cross-API intermediate language for natively representing parallel compute and graphics..

From this image I can see that all the high-level languages such as GLSL, HLSL, OpenCL C, etc., are compiled into SPIR-V and in this way passed to the correct physical device to be executed.

My question is why do we need to compile our shader/kernel code to SPIR-V and not compile it directly into machine instructions that will be executed by the chosen physical device? In case this question is not correct, can you please explain why do we need SPIR-V at all?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Dimitar Hristov
  • 123
  • 1
  • 7
  • Based on what I found in [this video](https://youtu.be/qKbtrVEhaw8?t=32m40s), I can see that SPIR-V is "technically a binary language". Also if I understand it correctly, the whole point is that by converting the high-level languages to SPIR-V allows us to achieve a **single** standard that is understandable by all the different drivers for the different physical devices. Can anybody with more experience share their thoughts on this and say if it is correct? – Dimitar Hristov Apr 02 '18 at 21:43
  • 1
    This is an interesting question, but maybe not one that is suited for Stack Overflow. SPIR-V is probably not an imperative, but rather the result of engineering tradeoffs. By nature, tradeoffs weigh opinions about the importance of specific facts, and Stack Overflow hates discussing opinions. – zneak Apr 02 '18 at 21:52

1 Answers1

30

In general you can split a compiler into two parts: a front-end for a specific language (or family of languages), and a back-end, which is language-agnostic and can generate machine code for one or more specific architectures (you can break this down further, but that's enough for now). Optimizations can happen in both parts; some are more appropriate in either place. This is the relationship between clang and LLVM for example: clang is a front-end for C-family languages, and LLVM is the backend.

Because different GPUs have significantly different machine code (often much more different than, say, arm64 vs. x86_64), the backend compiler needs to be in the GPU driver. But there's no reason to have the front-end be there too, even though that's how it worked in OpenGL. By separating the two, and using SPIR-V as the language they use to communicate, we get:

  1. One parsing and syntax checking implementation, instead of one per vendor. This means developers get to target just one variant of the language, instead of a bunch of vendor-specific variants (due to implementing different versions, bugs, differences in interpretation, etc.)

  2. Support for multiple languages. You can use ESSL (OpenGL ES's variant of GLSL), GLSL, HLSL, and OpenCL-C to write Vulkan shaders, making it easier for developers to support multiple APIs. All emit SPIR-V, so drivers don't have to support each of these languages. In theory someone could design their own language, or support MetalSL, etc.

  3. Since SPIR-V is meant to be machine-written / machine-read instead of human-friendly, it is a simpler and more regular language than GLSL. So it should be easier to get all vendors to implement it with high-quality. (At the moment, implementations are a lot less mature than in GL drivers, so we're not quite there yet.)

  4. Some expensive optimizations can be done offline, e.g. as part of the app build process, instead of at runtime when you're trying to finish a frame in 16 or 33 milliseconds.

user703016
  • 37,307
  • 8
  • 87
  • 112
Jesse Hall
  • 6,441
  • 23
  • 29
  • Thank you for the quick answer. I have a few questions based on your answer: 1) Is it correct to say that the front-end part=host program that can be written in C++, for example. And the back-end part=shaders/kernels written in GLSL or OpenCL C? 2) You said that in OpenGL, the back-end and front-end compilers were in the gpu driver which is no longer the case. Do you know where do we have the front-end compiler in Vulkan, for example? – Dimitar Hristov Apr 02 '18 at 22:25
  • 3) The whole point of converting the high-level languages to SPIR-V is to allow us to achieve a single standard that is understandable by all the different drivers for the different physical devices. Is this correct? – Dimitar Hristov Apr 02 '18 at 22:26
  • 4
    The front-end translates a language like GLSL or HLSL into the intermediate representation, SPIR-V. The backend reads SPIR-V and generates machine code. In OpenGL, the driver translated from GLSL to a proprietary internal intermediate representation and from there to machine code. Vulkan doesn't have a built-in front-end, it only handles SPIR-V as input. [glslang](https://github.com/KhronosGroup/glslang) is the most common front-end used with Vulkan for translating GLSL or HLSL to SPIR-V, but there's also [clspv](https://github.com/google/clspv) for OpenCL. – Jesse Hall Apr 02 '18 at 23:30
  • Thanks. Now it makes more sense. I have just one more final question. You said that previously "the driver translated from GLSL to a proprietary internal intermediate representation". Where was SPIR used in this case? Currently in Vulkan the "intermediate representation" is SPIR-V which based on [this image](https://www.khronos.org/assets/uploads/apis/2018-api-spirv-2.jpg) seems to be an enhanced version of SPIR. So assume it was again used somewhere there in the whole process but where exactly? – Dimitar Hristov Apr 03 '18 at 21:06
  • In GL both frontend and backend lives in the driver and weren't independent of each other, so drivers usually didn't use a standardized intermediate representation: each vendor defined their own proprietary representation, and could change it whenever they wanted. SPIR-V was invented for Vulkan, so it wasn't used prior to that. – Jesse Hall Apr 03 '18 at 22:50
  • @DimitarHrsitov: "*Where was SPIR used in this case?*" Despite SPIR-V taking its name from SPIR, they really have absolutely nothing to do with one another. SPIR-V is an actual assembly-like language. SPIR is merely a set of transformations from a higher level language containing OpenCL constructs to LLVM assembly. SPIR used to be used in older versions of OpenCL, but it is effectively defunct now. Think of SPIR as a failed experiment, an attempt to try to provide an intermediate representation without having an actual language. – Nicol Bolas Apr 04 '18 at 05:06
  • @JesseHall: "*SPIR-V was invented for Vulkan*" Not really. It was invented for Vulkan and OpenCL to share. – Nicol Bolas Apr 04 '18 at 05:07