1# SPIR-V Dialect to LLVM Dialect conversion manual
2
3This manual describes the conversion from [SPIR-V Dialect](Dialects/SPIR-V.md)
4to [LLVM Dialect](Dialects/LLVM.md). It assumes familiarity with both, and
5describes the design choices behind the modelling of SPIR-V concepts in LLVM
6Dialect. The conversion is an ongoing work, and is expected to grow as more
7features are implemented.
8
9Conversion can be performed by invoking an appropriate conversion pass:
10
11```shell
12mlir-opt -convert-spirv-to-llvm <filename.mlir>
13```
14
15This pass performs type and operation conversions for SPIR-V operations as
16described in this document.
17
18[TOC]
19
20## Type Conversion
21
22This section describes how SPIR-V Dialect types are mapped to LLVM Dialect.
23
24### Scalar types
25
26SPIR-V Dialect                       | LLVM Dialect
27:----------------------------------: | :----------------------------------:
28`i<bitwidth>`                        | `!llvm.i<bitwidth>`
29`si<bitwidth>`                       | `!llvm.i<bitwidth>`
30`ui<bitwidth>`                       | `!llvm.i<bitwidth>`
31`f16`                                | `!llvm.half`
32`f32`                                | `!llvm.float`
33`f64`                                | `!llvm.double`
34
35### Vector types
36
37SPIR-V Dialect                       | LLVM Dialect
38:----------------------------------: | :----------------------------------:
39`vector<<count> x <scalar-type>>`    | `!llvm.vec<<count> x <scalar-type>>`
40
41### Pointer types
42
43A SPIR-V pointer also takes a Storage Class. At the moment, conversion does
44**not** take it into account.
45
46SPIR-V Dialect                                | LLVM Dialect
47:-------------------------------------------: | :-------------------------:
48`!spv.ptr< <element-type>, <storage-class> >` | `!llvm.ptr<<element-type>>`
49
50### Array types
51
52SPIR-V distinguishes between array type and run-time array type, the length of
53which is not known at compile time. In LLVM, it is possible to index beyond the
54end of the array. Therefore, runtime array can be implemented as a zero length
55array type.
56
57Moreover, SPIR-V supports the notion of array stride. Currently only natural
58strides (based on [`VulkanLayoutUtils`](VulkanLayoutUtils)) are supported. They
59are also mapped to LLVM array.
60
61SPIR-V Dialect                        | LLVM Dialect
62:-----------------------------------: | :-----------------------------------:
63`!spv.array<<count> x <element-type>>`| `!llvm.array<<count> x <element-type>>`
64`!spv.rtarray< <element-type> >`      | `!llvm.array<0 x <element-type>>`
65
66### Struct types
67
68Members of SPIR-V struct types may have decorations and offset information.
69Currently, there is **no** support of member decorations conversion for structs.
70For more information see section on [Decorations](#Decorations-conversion).
71
72Usually we expect that each struct member has a natural size and alignment.
73However, there are cases (*e.g.* in graphics) where one would place struct
74members explicitly at particular offsets. This case is **not** supported
75at the moment. Hence, we adhere to the following mapping:
76
77*   Structs with no offset are modelled as LLVM packed structures.
78
79*   Structs with natural offset (*i.e.* offset that equals to cumulative size of
80    the previous struct elements or is a natural alignment) are mapped to
81    naturally padded structs.
82
83*   Structs with unnatural offset (*i.e.* offset that is not equal to cumulative
84    size of the previous struct elements) are **not** supported. In this case,
85    offsets can be emulated with padding fields (*e.g.* integers). However, such
86    a design would require index recalculation in the conversion of ops that
87    involve memory addressing.
88
89Examples of SPIR-V struct conversion are:
90```mlir
91!spv.struct<i8, i32>          =>  !llvm.struct<packed (i8, i32)>
92!spv.struct<i8 [0], i32 [4]>  =>  !llvm.struct<(i8, i32)>
93
94// error
95!spv.struct<i8 [0], i32 [8]>
96```
97
98### Not implemented types
99
100The rest of the types not mentioned explicitly above are not supported by the
101conversion. This includes `ImageType` and `MatrixType`.
102
103## Operation Conversion
104
105This section describes how SPIR-V Dialect operations are converted to LLVM
106Dialect. It lists already working conversion patterns, as well as those that are
107an ongoing work.
108
109There are also multiple ops for which there is no clear mapping in LLVM.
110Conversion for those have to be discussed within the community on the
111case-by-case basis.
112
113### Arithmetic ops
114
115SPIR-V arithmetic ops mostly have a direct equivalent in LLVM Dialect. Such
116exceptions as `spv.SMod` and `spv.FMod` are rare.
117
118SPIR-V Dialect op                     | LLVM Dialect op
119:-----------------------------------: | :-----------------------------------:
120`spv.FAdd`                            | `llvm.fadd`
121`spv.FDiv`                            | `llvm.fdiv`
122`spv.FNegate`                         | `llvm.fneg`
123`spv.FMul`                            | `llvm.fmul`
124`spv.FRem`                            | `llvm.frem`
125`spv.FSub`                            | `llvm.fsub`
126`spv.IAdd`                            | `llvm.add`
127`spv.IMul`                            | `llvm.mul`
128`spv.ISub`                            | `llvm.sub`
129`spv.SDiv`                            | `llvm.sdiv`
130`spv.SRem`                            | `llvm.srem`
131`spv.UDiv`                            | `llvm.udiv`
132`spv.UMod`                            | `llvm.urem`
133
134### Bitwise ops
135
136SPIR-V has a range of bit ops that are mapped to LLVM dialect ops, intrinsics or
137may have a specific conversion pattern.
138
139#### Direct conversion
140
141As with arithmetic ops, most of bitwise ops have a semantically equivalent op in
142LLVM:
143
144SPIR-V Dialect op                     | LLVM Dialect op
145:-----------------------------------: | :-----------------------------------:
146`spv.BitwiseAnd`                      | `llvm.and`
147`spv.BitwiseOr`                       | `llvm.or`
148`spv.BitwiseXor`                      | `llvm.xor`
149
150Also, some of bitwise ops can be modelled with LLVM intrinsics:
151
152SPIR-V Dialect op                     | LLVM Dialect intrinsic
153:-----------------------------------: | :-----------------------------------:
154`spv.BitCount`                        | `llvm.intr.ctpop`
155`spv.BitReverse`                      | `llvm.intr.bitreverse`
156
157#### `spv.Not`
158
159`spv.Not` is modelled with a `xor` operation with a mask with all bits set.
160
161```mlir
162                            %mask = llvm.mlir.constant(-1 : i32) : !llvm.i32
163%0 = spv.Not %op : i32  =>  %0  = llvm.xor %op, %mask : !llvm.i32
164```
165
166#### Bitfield ops
167
168SPIR-V dialect has three bitfield ops: `spv.BitFieldInsert`,
169`spv.BitFieldSExtract` and `spv.BitFieldUExtract`. This section will first
170outline the general design of conversion patterns for this ops, and then
171describe each of them.
172
173All of these ops take `base`, `offset` and `count` (`insert` for
174`spv.BitFieldInsert`) as arguments. There are two important things
175to note:
176
177*   `offset` and `count` are always scalar. This means that we can have the
178    following case:
179
180    ```mlir
181    %0 = spv.BitFieldSExtract %base, %offset, %count : vector<2xi32>, i8, i8
182    ```
183
184    To be able to proceed with conversion algorithms described below, all
185    operands have to be of the same type and bitwidth. This requires
186    broadcasting of `offset` and `count` to vectors, for example for the case
187    above it gives:
188
189    ```mlir
190    // Broadcasting offset
191    %offset0 = llvm.mlir.undef : !llvm.vec<2 x i8>
192    %zero = llvm.mlir.constant(0 : i32) : !llvm.i32
193    %offset1 = llvm.insertelement %offset, %offset0[%zero : !llvm.i32] : !llvm.vec<2 x i8>
194    %one = llvm.mlir.constant(1 : i32) : !llvm.i32
195    %vec_offset = llvm.insertelement  %offset, %offset1[%one : !llvm.i32] : !llvm.vec<2 x i8>
196
197    // Broadcasting count
198    // ...
199    ```
200
201*   `offset` and `count` may have different bitwidths from `base`. In this case,
202    both of these operands have to be zero extended (since they are treated as
203    unsigned by the specification) or truncated. For the above example it would
204    be:
205
206    ```mlir
207    // Zero extending offset after broadcasting
208    %res_offset = llvm.zext %vec_offset: !llvm.vec<2 x i8> to !llvm.vec<2 x i32>
209    ```
210
211    Also, note that if the bitwidth of `offset` or `count` is greater than the
212    bitwidth of `base`, truncation is still permitted. This is because the ops have a
213    defined behaviour with `offset` and `count` being less than the size of
214    `base`. It creates a natural upper bound on what values `offset` and `count`
215    can take, which is 64. This can be expressed in less than 8 bits.
216
217Now, having these two cases in mind, we can proceed with conversion for the ops
218and their operands.
219
220##### `spv.BitFieldInsert`
221
222This operation is implemented as a series of LLVM Dialect operations. First step
223would be to create a mask with bits set outside
224[`offset`, `offset` + `count` - 1]. Then, unchanged bits are extracted from
225`base` that are outside of [`offset`, `offset` + `count` - 1]. The result is
226`or`ed with shifted `insert`.
227
228```mlir
229// Create mask
230// %minus_one = llvm.mlir.constant(-1 : i32) : !llvm.i32
231// %t0        = llvm.shl %minus_one, %count : !llvm.i32
232// %t1        = llvm.xor %t0, %minus_one : !llvm.i32
233// %t2        = llvm.shl %t1, %offset : !llvm.i32
234// %mask      = llvm.xor %t2, %minus_one : !llvm.i32
235
236// Extract unchanged bits from the Base
237// %new_base  = llvm.and %base, %mask : !llvm.i32
238
239// Insert new bits
240// %sh_insert = llvm.shl %insert, %offset : !llvm.i32
241// %res       = llvm.or %new_base, %sh_insert : !llvm.i32
242%res = spv.BitFieldInsert %base, %insert, %offset, %count : i32, i32, i32
243```
244
245##### `spv.BitFieldSExtract`
246
247To implement `spv.BitFieldSExtract`, `base` is shifted left by [sizeof(`base`) -
248(`count` + `offset`)], so that the bit at `offset` + `count` - 1 is the most
249significant bit. After, the result is shifted right, filling the bits with the
250sign bit.
251
252```mlir
253// Calculate the amount to shift left.
254// %size    = llvm.mlir.constant(32 : i32) : !llvm.i32
255// %t0      = llvm.add %count, %offset : !llvm.i32
256// %t1      = llvm.sub %size, %t0 : !llvm.i32
257
258// Shift left and then right to extract the bits
259// %sh_left = llvm.shl %base, %t1 : !llvm.i32
260// %t2      = llvm.add %offset, %t1 : !llvm.i32
261// %res     = llvm.ashr %sh_left, %t2 : !llvm.i32
262%res = spv.BitFieldSExtract %base, %offset, %count : i32, i32, i32
263```
264
265##### `spv.BitFieldUExtract`
266
267For this op a similar pattern as for `spv.BitFieldInsert` is used. First, a mask
268with bits set at [0, `count` - 1] is created. Then `base` is shifted by `offset`
269and the mask is applied.
270
271```mlir
272// Create a mask
273// %minus_one = llvm.mlir.constant(-1 : i32) : !llvm.i32
274// %t0        = llvm.shl %minus_one, %count : !llvm.i32
275// mask       = llvm.xor  %t0, %minus_one : !llvm.i32
276
277// Shift Base and apply mask
278// %sh_base   = llvm.lshr %base, %offset : !llvm.i32
279// %res       = llvm.and %sh_base, %mask : !llvm.i32
280%res = spv.BitFieldUExtract %base, %offset, %count : i32, i32, i32
281```
282
283### Cast ops
284
285#### Direct conversions
286
287SPIR-V Dialect op                     | LLVM Dialect op
288:-----------------------------------: | :-----------------------------------:
289`spv.ConvertFToS`                     | `llvm.fptosi`
290`spv.ConvertFToU`                     | `llvm.fptoui`
291`spv.ConvertSToF`                     | `llvm.sitofp`
292`spv.ConvertUToF`                     | `llvm.uitofp`
293
294#### spv.Bitcast
295This operation has a direct counterpart in LLVM: `llvm.bitcast`. It is treated
296separately since it also supports pointer to pointer bit pattern-preserving type
297conversion, apart from regular scalar or vector of numerical type.
298
299#### Special cases
300Special cases include `spv.FConvert`, `spv.SConvert` and `spv.UConvert`. These
301operations are either a truncate or extend. Let's denote the operand component
302width as A, and result component width as R. Then, the following mappings are
303used:
304
305##### `spv.FConvert`
306Case            | LLVM Dialect op
307:-------------: | :-----------------------------------:
308A < R           | `llvm.fpext`
309A > R           | `llvm.fptrunc`
310
311##### `spv.SConvert`
312Case            | LLVM Dialect op
313:-------------: | :-----------------------------------:
314A < R           | `llvm.sext`
315A > R           | `llvm.trunc`
316
317##### `spv.UConvert`
318Case            | LLVM Dialect op
319:-------------: | :-----------------------------------:
320A < R           | `llvm.zext`
321A > R           | `llvm.trunc`
322
323The case when A = R is not possible, based on SPIR-V Dialect specification:
324> The component width cannot equal the component width in Result Type.
325
326### Comparison ops
327
328SPIR-V comparison ops are mapped to LLVM `icmp` and `fcmp` operations.
329
330SPIR-V Dialect op                     | LLVM Dialect op
331:-----------------------------------: | :-----------------------------------:
332`spv.IEqual`                          | `llvm.icmp "eq"`
333`spv.INotEqual`                       | `llvm.icmp "ne"`
334`spv.FOrdEqual`                       | `llvm.fcmp "oeq"`
335`spv.FOrdGreaterThan`                 | `llvm.fcmp "ogt"`
336`spv.FOrdGreaterThanEqual`            | `llvm.fcmp "oge"`
337`spv.FOrdLessThan`                    | `llvm.fcmp "olt"`
338`spv.FOrdLessThanEqual`               | `llvm.fcmp "ole"`
339`spv.FOrdNotEqual`                    | `llvm.fcmp "one"`
340`spv.FUnordEqual`                     | `llvm.fcmp "ueq"`
341`spv.FUnordGreaterThan`               | `llvm.fcmp "ugt"`
342`spv.FUnordGreaterThanEqual`          | `llvm.fcmp "uge"`
343`spv.FUnordLessThan`                  | `llvm.fcmp "ult"`
344`spv.FUnordLessThanEqual`             | `llvm.fcmp "ule"`
345`spv.FUnordNotEqual`                  | `llvm.fcmp "une"`
346`spv.SGreaterThan`                    | `llvm.icmp "sgt"`
347`spv.SGreaterThanEqual`               | `llvm.icmp "sge"`
348`spv.SLessThan`                       | `llvm.icmp "slt"`
349`spv.SLessThanEqual`                  | `llvm.icmp "sle"`
350`spv.UGreaterThan`                    | `llvm.icmp "ugt"`
351`spv.UGreaterThanEqual`               | `llvm.icmp "uge"`
352`spv.ULessThan`                       | `llvm.icmp "ult"`
353`spv.ULessThanEqual`                  | `llvm.icmp "ule"`
354
355### Composite ops
356
357Currently, conversion supports rewrite patterns for `spv.CompositeExtract` and
358`spv.CompositeInsert`. We distinguish two cases for these operations: when the
359composite object is a vector, and when the composite object is of a non-vector
360type (*i.e.* struct, array or runtime array).
361
362Composite type  | SPIR-V Dialect op      | LLVM Dialect op
363:-------------: | :--------------------: | :--------------------:
364vector          | `spv.CompositeExtract` | `llvm.extractelement`
365vector          | `spv.CompositeInsert`  | `llvm.insertelement`
366non-vector      | `spv.CompositeExtract` | `llvm.extractvalue`
367non-vector      | `spv.CompositeInsert`  | `llvm.insertvalue`
368
369### `spv.EntryPoint` and `spv.ExecutionMode`
370
371**Note: these conversions are likely to be changed in the future**
372
373First of all, it is important to note that there is no direct representation of
374entry points in LLVM. At the moment, we choose to **remove these ops**, assuming
375that the module generated from SPIR-V has no other internal functions (This
376assumption is actually made in [`mlir-spirv-cpu-runner`](#`mlir-spirv-cpu-runner`)).
377
378However, these ops can be used to see which functions in the module are entry
379point functions. `spv.ExecutionMode` also carries the metadata associated with
380the entry point such as `LocalSize`, which indicates the workgroup size in the
381x, y, and z dimensions. It will be useful to represent this on the LLVM side
382(TODO).
383
384### Logical ops
385
386Logical ops follow a similar pattern as bitwise ops, with the difference that
387they operate on `i1` or vector of `i1` values. The following mapping is used to
388emulate SPIR-V ops behaviour:
389
390SPIR-V Dialect op                     | LLVM Dialect op
391:-----------------------------------: | :-----------------------------------:
392`spv.LogicalAnd`                      | `llvm.and`
393`spv.LogicalOr`                       | `llvm.or`
394`spv.LogicalEqual`                    | `llvm.icmp "eq"`
395`spv.LogicalNotEqual`                 | `llvm.icmp "ne"`
396
397`spv.LogicalNot` has the same conversion pattern as bitwise `spv.Not`. It is
398modelled with `xor` operation with a mask with all bits set.
399
400```mlir
401                                  %mask = llvm.mlir.constant(-1 : i1) : !llvm.i1
402%0 = spv.LogicalNot %op : i1  =>  %0    = llvm.xor %op, %mask : !llvm.i1
403```
404
405### Memory ops
406
407This section describes the conversion patterns for SPIR-V dialect operations
408that concern memory.
409
410#### `spv.AccessChain`
411
412`spv.AccessChain` is mapped to `llvm.getelementptr` op. In order to create a
413valid LLVM op, we also add a 0 index to the `spv.AccessChain`'s indices list in
414order to go through the pointer.
415
416```mlir
417// Access the 1st element of the array
418%i   = spv.constant 1: i32
419%var = spv.Variable : !spv.ptr<!spv.struct<f32, !spv.array<4xf32>>, Function>
420%el  = spv.AccessChain %var[%i, %i] : !spv.ptr<!spv.struct<f32, !spv.array<4xf32>>, Function>, i32, i32
421
422// Corresponding LLVM dialect code
423%i   = ...
424%var = ...
425%0   = llvm.mlir.constant(0 : i32) : !llvm.i32
426%el  = llvm.getelementptr %var[%0, %i, %i] : (!llvm.ptr<struct<packed (float, array<4 x float>)>>, !llvm.i32, !llvm.i32, !llvm.i32)
427```
428
429#### `spv.Load` and `spv.Store`
430
431These ops are converted to their LLVM counterparts: `llvm.load` and
432`llvm.store`. If the op has a memory access attribute, then there are the
433following cases, based on the value of the attribute:
434
435* **Aligned**: alignment is passed on to LLVM op builder, for example:
436  ```mlir
437  // llvm.store %ptr, %val {alignment = 4 : i64} : !llvm.ptr<float>
438  spv.Store "Function" %ptr, %val ["Aligned", 4] : f32
439  ```
440* **None**: same case as if there is no memory access attribute.
441
442* **Nontemporal**: set `nontemporal` flag, for example:
443  ```mlir
444  // %res = llvm.load %ptr {nontemporal} : !llvm.ptr<float>
445  %res = spv.Load "Function" %ptr ["Nontemporal"] : f32
446  ```
447* **Volatile**: mark the op as `volatile`, for example:
448  ```mlir
449  // %res = llvm.load volatile %ptr : !llvm.ptr<float>
450  %res = spv.Load "Function" %ptr ["Volatile"] : f32
451  ```
452Otherwise the conversion fails as other cases (`MakePointerAvailable`,
453`MakePointerVisible`, `NonPrivatePointer`) are not supported yet.
454
455#### `spv.globalVariable` and `spv._address_of`
456
457`spv.globalVariable` is modelled with `llvm.mlir.global` op. However, there
458is a difference that has to be pointed out.
459
460In SPIR-V dialect, the global variable returns a pointer, whereas in LLVM
461dialect the global holds an actual value. This difference is handled by
462`spv._address_of` and `llvm.mlir.addressof` ops that both return a pointer and
463are used to reference the global.
464
465```mlir
466// Original SPIR-V module
467spv.module Logical GLSL450 {
468  spv.globalVariable @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
469  spv.func @func() -> () "None" {
470    %0 = spv._address_of @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
471    spv.Return
472  }
473}
474
475// Converted result
476module {
477  llvm.mlir.global private @struct() : !llvm.struct<packed (float, [10 x float])>
478  llvm.func @func() {
479    %0 = llvm.mlir.addressof @struct : !llvm.ptr<struct<packed (float, [10 x float])>>
480    llvm.return
481  }
482}
483```
484
485The SPIR-V to LLVM conversion does not involve modelling of workgroups.
486Hence, we say that only current invocation is in conversion's scope. This means
487that global variables with pointers of `Input`, `Output`, and `Private` storage
488classes are supported. Also, `StorageBuffer` storage class is allowed for
489executing [`mlir-spirv-cpu-runner`](#`mlir-spirv-cpu-runner`).
490
491Moreover, `bind` that specifies the descriptor set and the binding number and
492`built_in` that specifies SPIR-V `BuiltIn` decoration have no conversion into
493LLVM dialect.
494
495Currently `llvm.mlir.global`s are created with `private` linkage for `Private`
496storage class and `External` for other storage classes, based on SPIR-V spec:
497
498> By default, functions and global variables are private to a module and cannot
499be accessed by other modules. However, a module may be written to export or
500import functions and global (module scope) variables.
501
502If the global variable's pointer has `Input` storage class, then a `constant`
503flag is added to LLVM op:
504
505```mlir
506spv.globalVariable @var : !spv.ptr<f32, Input>    =>    llvm.mlir.global external constant @var() : !llvm.float
507```
508
509#### `spv.Variable`
510
511Per SPIR-V dialect spec, `spv.Variable` allocates an object in memory, resulting
512in a pointer to it, which can be used with `spv.Load` and `spv.Store`. It is
513also a function-level variable.
514
515`spv.Variable` is modelled as `llvm.alloca` op. If initialized, an additional
516store instruction is used. Note that there is no initialization for arrays and
517structs since constants of these types are not supported in LLVM dialect (TODO).
518Also, at the moment initialization is only possible via `spv.constant`.
519
520```mlir
521// Conversion of VariableOp without initialization
522                                                               %size = llvm.mlir.constant(1 : i32) : !llvm.i32
523%res = spv.Variable : !spv.ptr<vector<3xf32>, Function>   =>   %res  = llvm.alloca  %size x !llvm.vec<3 x float> : (!llvm.i32) -> !llvm.ptr<vec<3 x float>>
524
525// Conversion of VariableOp with initialization
526                                                               %c    = llvm.mlir.constant(0 : i64) : !llvm.i64
527%c   = spv.constant 0 : i64                                    %size = llvm.mlir.constant(1 : i32) : !llvm.i32
528%res = spv.Variable init(%c) : !spv.ptr<i64, Function>    =>   %res	 = llvm.alloca %[[SIZE]] x !llvm.i64 : (!llvm.i32) -> !llvm.ptr<i64>
529                                                               llvm.store %c, %res : !llvm.ptr<i64>
530```
531
532Note that simple conversion to `alloca` may not be sufficient if the code has
533some scoping. For example, if converting ops executed in a loop into `alloca`s,
534a stack overflow may occur. For this case, `stacksave`/`stackrestore` pair can
535be used (TODO).
536
537### Miscellaneous ops with direct conversions
538
539There are multiple SPIR-V ops that do not fit in a particular group but can be
540converted directly to LLVM dialect. Their conversion is addressed in this
541section.
542
543SPIR-V Dialect op                     | LLVM Dialect op
544:-----------------------------------: | :-----------------------------------:
545`spv.Select`                          | `llvm.select`
546`spv.Undef`                           | `llvm.mlir.undef`
547
548### Shift ops
549
550Shift operates on two operands: `shift` and `base`.
551
552In SPIR-V dialect, `shift` and `base` may have different bit width. On the
553contrary, in LLVM Dialect both `base` and `shift` have to be of the same
554bitwidth. This leads to the following conversions:
555
556*   if `base` has the same bitwidth as `shift`, the conversion is
557    straightforward.
558
559*   if `base` has a greater bit width than `shift`, shift is sign or zero
560    extended first. Then the extended value is passed to the shift.
561
562*   otherwise, the conversion is considered to be illegal.
563
564```mlir
565// Shift without extension
566%res0 = spv.ShiftRightArithmetic %0, %2 : i32, i32  =>  %res0 = llvm.ashr %0, %2 : !llvm.i32
567
568// Shift with extension
569                                                        %ext  = llvm.sext %1 : !llvm.i16 to !llvm.i32
570%res1 = spv.ShiftRightArithmetic %0, %1 : i32, i16  =>  %res1 = llvm.ashr %0, %ext: !llvm.i32
571```
572
573### `spv.constant`
574
575At the moment `spv.constant` conversion supports scalar and vector constants
576**only**.
577
578#### Mapping
579
580`spv.constant` is mapped to `llvm.mlir.constant`. This is a straightforward
581conversion pattern with a special case when the argument is signed or unsigned.
582
583#### Special case
584
585SPIR-V constant can be a signed or unsigned integer. Since LLVM Dialect does not
586have signedness semantics, this case should be handled separately.
587
588The conversion casts constant value attribute to a signless integer or a vector
589of signless integers. This is correct because in SPIR-V, like in LLVM, how to
590interpret an integer number is also dictated by the opcode. However, in reality
591hardware implementation might show unexpected behavior. Therefore, it is better
592to handle it case-by-case, given that the purpose of the conversion is not to
593cover all possible corner cases.
594
595```mlir
596// %0 = llvm.mlir.constant(0 : i8) : !llvm.i8
597%0 = spv.constant  0 : i8
598
599// %1 = llvm.mlir.constant(dense<[2, 3, 4]> : vector<3xi32>) : !llvm.vec<3 x i32>
600%1 = spv.constant dense<[2, 3, 4]> : vector<3xui32>
601```
602
603### Not implemented ops
604
605There is no support of the following ops:
606
607*   All Atomic ops
608*   All matrix ops
609*   All GroupNonUniform ops
610
611As well as:
612
613*   spv.CompositeConstruct
614*   spv.ControlBarrier
615*   spv.CopyMemory
616*   spv.FMod
617*   spv.GLSL.SAbs
618*   spv.GLSL.SSign
619*   spv.GLSL.FSign
620*   spv.MemoryBarrier
621*   spv._reference_of
622*   spv.SMod
623*   spv.specConstant
624*   spv.SubgroupBallotKHR
625*   spv.Unreachable
626
627## Control flow conversion
628
629### Branch ops
630
631`spv.Branch` and `spv.BranchConditional` are mapped to `llvm.br` and
632`llvm.cond_br`. Branch weights for `spv.BranchConditional` are mapped to
633corresponding `branch_weights` attribute of `llvm.cond_br`. When translated to
634proper LLVM, `branch_weights` are converted into LLVM metadata associated with
635the conditional branch.
636
637### `spv.FunctionCall`
638
639`spv.FunctionCall` maps to `llvm.call`. For example:
640
641```mlir
642%0 = spv.FunctionCall @foo() : () -> i32    =>    %0 = llvm.call @foo() : () -> !llvm.float
643spv.FunctionCall @bar(%0) : (i32) -> ()     =>    llvm.call @bar(%0) : (!llvm.float) -> ()
644```
645
646### `spv.selection` and `spv.loop`
647
648Control flow within `spv.selection` and `spv.loop` is lowered directly to LLVM
649via branch ops. The conversion can only be applied to selection or loop with all
650blocks being reachable. Moreover, selection and loop control attributes (such as
651`Flatten` or `Unroll`) are not supported at the moment.
652
653```mlir
654// Conversion of selection
655%cond = spv.constant true                               %cond = llvm.mlir.constant(true) : !llvm.i1
656spv.selection {
657  spv.BranchConditional %cond, ^true, ^false            llvm.cond_br %cond, ^true, ^false
658
659^true:																								^true:
660  // True block code                                    // True block code
661  spv.Branch ^merge                             =>      llvm.br ^merge
662
663^false:                                               ^false:
664  // False block code                                   // False block code
665  spv.Branch ^merge                                     llvm.br ^merge
666
667^merge:                                               ^merge:
668  spv._merge                                            llvm.br ^continue
669}
670// Remaining code																			^continue:
671                                                        // Remaining code
672```
673
674```mlir
675// Conversion of loop
676%cond = spv.constant true                               %cond = llvm.mlir.constant(true) : !llvm.i1
677spv.loop {
678  spv.Branch ^header                                    llvm.br ^header
679
680^header:                                              ^header:
681  // Header code                                        // Header code
682  spv.BranchConditional %cond, ^body, ^merge    =>      llvm.cond_br %cond, ^body, ^merge
683
684^body:                                                ^body:
685  // Body code                                          // Body code
686  spv.Branch ^continue                                  llvm.br ^continue
687
688^continue:                                            ^continue:
689  // Continue code                                      // Continue code
690  spv.Branch ^header                                    llvm.br ^header
691
692^merge:                                               ^merge:
693  spv._merge                                            llvm.br ^remaining
694}
695// Remaining code                                     ^remaining:
696                                                        // Remaining code
697```
698
699## Decorations conversion
700
701**Note: these conversions have not been implemented yet**
702
703## GLSL extended instruction set
704
705This section describes how SPIR-V ops from GLSL extended instructions set are
706mapped to LLVM Dialect.
707
708### Direct conversions
709
710SPIR-V Dialect op                     | LLVM Dialect op
711:-----------------------------------: | :-----------------------------------:
712`spv.GLSL.Ceil`                       | `llvm.intr.ceil`
713`spv.GLSL.Cos`                        | `llvm.intr.cos`
714`spv.GLSL.Exp`                        | `llvm.intr.exp`
715`spv.GLSL.FAbs`                       | `llvm.intr.fabs`
716`spv.GLSL.Floor`                      | `llvm.intr.floor`
717`spv.GLSL.FMax`                       | `llvm.intr.maxnum`
718`spv.GLSL.FMin`                       | `llvm.intr.minnum`
719`spv.GLSL.Log`                        | `llvm.intr.log`
720`spv.GLSL.Sin`                        | `llvm.intr.sin`
721`spv.GLSL.Sqrt`                       | `llvm.intr.sqrt`
722`spv.GLSL.SMax`                       | `llvm.intr.smax`
723`spv.GLSL.SMin`                       | `llvm.intr.smin`
724
725### Special cases
726
727`spv.InverseSqrt` is mapped to:
728```mlir
729                                           %one  = llvm.mlir.constant(1.0 : f32) : !llvm.float
730%res = spv.InverseSqrt %arg : f32    =>    %sqrt = "llvm.intr.sqrt"(%arg) : (!llvm.float) -> !llvm.float
731                                           %res  = fdiv %one, %sqrt : !llvm.float
732```
733
734`spv.Tan` is mapped to:
735```mlir
736                                   %sin = "llvm.intr.sin"(%arg) : (!llvm.float) -> !llvm.float
737%res = spv.Tan %arg : f32    =>    %cos = "llvm.intr.cos"(%arg) : (!llvm.float) -> !llvm.float
738                                   %res = fdiv %sin, %cos : !llvm.float
739```
740
741`spv.Tanh` is modelled using the equality `tanh(x) = {exp(2x) - 1}/{exp(2x) + 1}`:
742```mlir
743                                     %two   = llvm.mlir.constant(2.0: f32) : !llvm.float
744                                     %2xArg = llvm.fmul %two, %arg : !llvm.float
745                                     %exp   = "llvm.intr.exp"(%2xArg) : (!llvm.float) -> !llvm.float
746%res = spv.Tanh %arg : f32     =>    %one   = llvm.mlir.constant(1.0 : f32) : !llvm.float
747                                     %num   = llvm.fsub %exp, %one : !llvm.float
748                                     %den   = llvm.fadd %exp, %one : !llvm.float
749                                     %res   = llvm.fdiv %num, %den : !llvm.float
750```
751
752## Function conversion and related ops
753
754This section describes the conversion of function-related operations from SPIR-V
755to LLVM dialect.
756
757### `spv.func`
758This op declares or defines a SPIR-V function and it is converted to `llvm.func`.
759This conversion handles signature conversion, and function control attributes
760remapping to LLVM dialect function [`passthrough` attribute](Dialects/LLVM.md#Attribute-pass-through).
761
762The following mapping is used to map [SPIR-V function control](SPIRVFunctionAttributes) to
763[LLVM function attributes](LLVMFunctionAttributes):
764
765SPIR-V Function Control Attributes    | LLVM Function Attributes
766:-----------------------------------: | :-----------------------------------:
767None                                  | No function attributes passed
768Inline                                | `alwaysinline`
769DontInline                            | `noinline`
770Pure                                  | `readonly`
771Const                                 | `readnone`
772
773### `spv.Return` and `spv.ReturnValue`
774
775In LLVM IR, functions may return either 1 or 0 value. Hence, we map both ops to
776`llvm.return` with or without a return value.
777
778## Module ops
779
780Module in SPIR-V has one region that contains one block. It is defined via
781`spv.module` op that also takes a range of attributes:
782
783*   Addressing model
784*   Memory model
785*   Version-Capability-Extension attribute
786
787`spv.module` is converted into `ModuleOp`. This plays a role of enclosing scope
788to LLVM ops. At the moment, SPIR-V module attributes are ignored.
789
790`spv._module_end` is mapped to an equivalent terminator `ModuleTerminatorOp`.
791
792## `mlir-spirv-cpu-runner`
793
794**Note: this is a section in progress, more information will appear soon**
795
796[LLVMFunctionAttributes]: https://llvm.org/docs/LangRef.html#function-attributes
797[SPIRVFunctionAttributes]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#_a_id_function_control_a_function_control
798[VulkanLayoutUtils]: https://github.com/llvm/llvm-project/blob/master/mlir/include/mlir/Dialect/SPIRV/LayoutUtils.h
799