Skip to content
This repository was archived by the owner on Apr 23, 2021. It is now read-only.

Commit c42cb08

Browse files
antiagainsttensorflower-gardener
authored andcommitted
[spirv] Support OpPhi using block arguments
This CL adds another control flow instruction in SPIR-V: OpPhi. It is modelled as block arguments to be idiomatic with MLIR. See the rationale.md doc for "Block Arguments vs PHI nodes". Serialization and deserialization is updated to convert between block arguments and SPIR-V OpPhi instructions. PiperOrigin-RevId: 277161545
1 parent fec39f6 commit c42cb08

File tree

5 files changed

+657
-116
lines changed

5 files changed

+657
-116
lines changed

g3doc/Dialects/SPIR-V.md

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ A SPIR-V function is defined using the builtin `func` op. `spv.module` verifies
199199
that the functions inside it comply with SPIR-V requirements: at most one
200200
result, no nested functions, and so on.
201201

202+
## Operations
203+
204+
Operation documentation is written in each op's Op Definition Spec using
205+
TableGen. A markdown version of the doc can be generated using `mlir-tblgen
206+
-gen-doc`.
207+
202208
## Control Flow
203209

204210
SPIR-V binary format uses merge instructions (`OpSelectionMerge` and
@@ -385,7 +391,63 @@ func @loop(%count : i32) -> () {
385391
}
386392
```
387393

388-
## Serialization
394+
### Block argument for Phi
395+
396+
There are no direct Phi operations in the SPIR-V dialect; SPIR-V `OpPhi`
397+
instructions are modelled as block arguments in the SPIR-V dialect. (See the
398+
[Rationale][Rationale] doc for "Block Arguments vs Phi nodes".) Each block
399+
argument corresponds to one `OpPhi` instruction in the SPIR-V binary format. For
400+
example, for the following SPIR-V function `foo`:
401+
402+
```spirv
403+
%foo = OpFunction %void None ...
404+
%entry = OpLabel
405+
%var = OpVariable %_ptr_Function_int Function
406+
OpSelectionMerge %merge None
407+
OpBranchConditional %true %true %false
408+
%true = OpLabel
409+
OpBranch %phi
410+
%false = OpLabel
411+
OpBranch %phi
412+
%phi = OpLabel
413+
%val = OpPhi %int %int_1 %false %int_0 %true
414+
OpStore %var %val
415+
OpReturn
416+
%merge = OpLabel
417+
OpReturn
418+
OpFunctionEnd
419+
```
420+
421+
It will be represented as:
422+
423+
```mlir
424+
func @foo() -> () {
425+
%var = spv.Variable : !spv.ptr<i32, Function>
426+
427+
spv.selection {
428+
%true = spv.constant true
429+
spv.BranchConditional %true, ^true, ^false
430+
431+
^true:
432+
%zero = spv.constant 0 : i32
433+
spv.Branch ^phi(%zero: i32)
434+
435+
^false:
436+
%one = spv.constant 1 : i32
437+
spv.Branch ^phi(%one: i32)
438+
439+
^phi(%arg: i32):
440+
spv.Store "Function" %var, %arg : i32
441+
spv.Return
442+
443+
^merge:
444+
spv._merge
445+
}
446+
spv.Return
447+
}
448+
```
449+
450+
## Serialization and deserialization
389451

390452
The serialization library provides two entry points, `mlir::spirv::serialize()`
391453
and `mlir::spirv::deserialize()`, for converting a MLIR SPIR-V module to binary
@@ -399,10 +461,30 @@ the SPIR-V binary module and does not guarantee roundtrip equivalence (at least
399461
for now). For the latter, please use the assembler/disassembler in the
400462
[SPIRV-Tools][SPIRV-Tools] project.
401463

464+
A few transformations are performed in the process of serialization because of
465+
the representational differences between SPIR-V dialect and binary format:
466+
467+
* Attributes on `spv.module` are emitted as their corresponding SPIR-V
468+
instructions.
469+
* `spv.constant`s are unified and placed in the SPIR-V binary module section
470+
for types, constants, and global variables.
471+
* `spv.selection`s and `spv.loop`s are emitted as basic blocks with `Op*Merge`
472+
instructions in the header block as required by the binary format.
473+
474+
Similarly, a few transformations are performed during deserialization:
475+
476+
* Instructions for execution environment requirements will be placed as
477+
attribues on `spv.module`.
478+
* `OpConstant*` instructions are materialized as `spv.constant` at each use
479+
site.
480+
* `OpPhi` instructions are converted to block arguments.
481+
* Structured control flow are placed inside `spv.selection` and `spv.loop`.
482+
402483
[SPIR-V]: https://www.khronos.org/registry/spir-v/
403484
[ArrayType]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpTypeArray
404485
[ImageType]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpTypeImage
405486
[PointerType]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpTypePointer
406487
[RuntimeArrayType]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#OpTypeRuntimeArray
407488
[StructType]: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html#Structure
408489
[SPIRV-Tools]: https://github.com/KhronosGroup/SPIRV-Tools
490+
[Rationale]: https://github.com/tensorflow/mlir/blob/master/g3doc/Rationale.md#block-arguments-vs-phi-nodes

include/mlir/Dialect/SPIRV/SPIRVBase.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ def SPV_OC_OpBitwiseXor : I32EnumAttrCase<"OpBitwiseXor", 198>;
166166
def SPV_OC_OpBitwiseAnd : I32EnumAttrCase<"OpBitwiseAnd", 199>;
167167
def SPV_OC_OpControlBarrier : I32EnumAttrCase<"OpControlBarrier", 224>;
168168
def SPV_OC_OpMemoryBarrier : I32EnumAttrCase<"OpMemoryBarrier", 225>;
169+
def SPV_OC_OpPhi : I32EnumAttrCase<"OpPhi", 245>;
169170
def SPV_OC_OpLoopMerge : I32EnumAttrCase<"OpLoopMerge", 246>;
170171
def SPV_OC_OpSelectionMerge : I32EnumAttrCase<"OpSelectionMerge", 247>;
171172
def SPV_OC_OpLabel : I32EnumAttrCase<"OpLabel", 248>;
@@ -205,8 +206,8 @@ def SPV_OpcodeAttr :
205206
SPV_OC_OpFOrdLessThanEqual, SPV_OC_OpFUnordLessThanEqual,
206207
SPV_OC_OpFOrdGreaterThanEqual, SPV_OC_OpFUnordGreaterThanEqual,
207208
SPV_OC_OpBitwiseOr, SPV_OC_OpBitwiseXor, SPV_OC_OpBitwiseAnd,
208-
SPV_OC_OpControlBarrier, SPV_OC_OpMemoryBarrier, SPV_OC_OpLoopMerge,
209-
SPV_OC_OpSelectionMerge, SPV_OC_OpLabel, SPV_OC_OpBranch,
209+
SPV_OC_OpControlBarrier, SPV_OC_OpMemoryBarrier, SPV_OC_OpPhi,
210+
SPV_OC_OpLoopMerge, SPV_OC_OpSelectionMerge, SPV_OC_OpLabel, SPV_OC_OpBranch,
210211
SPV_OC_OpBranchConditional, SPV_OC_OpReturn, SPV_OC_OpReturnValue,
211212
SPV_OC_OpModuleProcessed
212213
]> {

0 commit comments

Comments
 (0)