| //===-- SPIRVControlFlowOps.td - SPIR-V Control Flow Ops ---*- tablegen -*-===// |
| // |
| // Copyright 2019 The MLIR Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ============================================================================= |
| // |
| // This file contains control flow ops for the SPIR-V dialect. It corresponds |
| // to "3.32.17. Control-Flow Instructions" of the SPIR-V specification. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifdef SPIRV_CONTROLFLOW_OPS |
| #else |
| #define SPIRV_CONTROLFLOW_OPS |
| |
| #ifdef SPIRV_BASE |
| #else |
| include "mlir/SPIRV/SPIRVBase.td" |
| #endif // SPIRV_BASE |
| |
| // ----- |
| |
| def SPV_BranchOp : SPV_Op<"Branch", [Terminator]> { |
| let summary = "Unconditional branch to target block."; |
| |
| let description = [{ |
| This instruction must be the last instruction in a block. |
| |
| ### Custom assembly form |
| |
| ``` {.ebnf} |
| branch-op ::= `spv.Branch` successor |
| ``` |
| |
| For example: |
| |
| ``` |
| spv.Branch ^target |
| ``` |
| }]; |
| |
| let arguments = (ins); |
| |
| let results = (outs); |
| |
| let builders = [ |
| OpBuilder< |
| "Builder *, OperationState *state, Block *successor", [{ |
| state->addSuccessor(successor, {}); |
| }] |
| > |
| ]; |
| |
| let skipDefaultBuilders = 1; |
| |
| let autogenSerialization = 0; |
| } |
| |
| // ----- |
| |
| def SPV_BranchConditionalOp : SPV_Op<"BranchConditional", [Terminator]> { |
| let summary = [{ |
| If Condition is true, branch to true block, otherwise branch to false |
| block. |
| }]; |
| |
| let description = [{ |
| Condition must be a Boolean type scalar. |
| |
| Branch weights are unsigned 32-bit integer literals. There must be |
| either no Branch Weights or exactly two branch weights. If present, the |
| first is the weight for branching to True Label, and the second is the |
| weight for branching to False Label. The implied probability that a |
| branch is taken is its weight divided by the sum of the two Branch |
| weights. At least one weight must be non-zero. A weight of zero does not |
| imply a branch is dead or permit its removal; branch weights are only |
| hints. The two weights must not overflow a 32-bit unsigned integer when |
| added together. |
| |
| This instruction must be the last instruction in a block. |
| |
| ### Custom assembly form |
| |
| ``` {.ebnf} |
| branch-conditional-op ::= `spv.BranchConditional` ssa-use |
| (`[` integer-literal, integer-literal `]`)? |
| `,` successor `,` successor |
| ``` |
| |
| For example: |
| |
| ``` |
| spv.BranchConditional %condition, ^true_branch, ^false_branch |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_Bool:$condition, |
| OptionalAttr<I32ArrayAttr>:$branch_weights |
| ); |
| |
| let results = (outs); |
| |
| let builders = [ |
| OpBuilder< |
| "Builder *, OperationState *state, Value *condition, " |
| "Block *trueBranch, Block *falseBranch, /*optional*/ArrayAttr weights", |
| [{ |
| state->addOperands(condition); |
| state->addSuccessor(trueBranch, {}); |
| state->addSuccessor(falseBranch, {}); |
| state->addAttribute("branch_weights", weights); |
| }] |
| > |
| ]; |
| |
| let skipDefaultBuilders = 1; |
| |
| let autogenSerialization = 0; |
| |
| let extraClassDeclaration = [{ |
| // Branch indices into the successor list. |
| enum { kTrueIndex = 0, kFalseIndex = 1 }; |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_ReturnOp : SPV_Op<"Return", [InFunctionScope, Terminator]> { |
| let summary = "Return with no value from a function with void return type."; |
| |
| let description = [{ |
| This instruction must be the last instruction in a block. |
| |
| ### Custom assembly form |
| |
| ``` {.ebnf} |
| return-op ::= `spv.Return` |
| ``` |
| }]; |
| |
| let arguments = (ins); |
| |
| let results = (outs); |
| |
| let parser = [{ return parseNoIOOp(parser, result); }]; |
| let printer = [{ printNoIOOp(getOperation(), p); }]; |
| } |
| |
| // ----- |
| |
| def SPV_ReturnValueOp : SPV_Op<"ReturnValue", [InFunctionScope, Terminator]> { |
| let summary = "Return a value from a function."; |
| |
| let description = [{ |
| Value is the value returned, by copy, and must match the Return Type |
| operand of the OpTypeFunction type of the OpFunction body this return |
| instruction is in. |
| |
| This instruction must be the last instruction in a block. |
| |
| ### Custom assembly form |
| |
| ``` {.ebnf} |
| return-value-op ::= `spv.ReturnValue` ssa-use `:` spirv-type |
| ``` |
| |
| For example: |
| |
| ``` |
| spv.ReturnValue %0 : f32 |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_Type:$value |
| ); |
| |
| let results = (outs); |
| } |
| |
| #endif // SPIRV_CONTROLFLOW_OPS |