--- /dev/null
+//===-- 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_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
include "mlir/Dialect/SPIRV/SPIRVArithmeticOps.td"
#endif // SPIRV_ARITHMETIC_OPS
+#ifdef SPIRV_CONTROLFLOW_OPS
+#else
+include "mlir/Dialect/SPIRV/SPIRVControlFlowOps.td"
+#endif // SPIRV_CONTROLFLOW_OPS
+
#ifdef SPIRV_LOGICAL_OPS
#else
include "mlir/Dialect/SPIRV/SPIRVLogicalOps.td"
// -----
-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); }];
-
- let verifier = [{ return verifyReturn(*this); }];
-}
-
-// -----
-
-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);
-}
-
-// -----
-
def SPV_StoreOp : SPV_Op<"Store", []> {
let summary = "Store through a pointer.";
static LogicalResult extractValueFromConstOp(Operation *op,
int32_t &indexValue) {
- auto constOp = llvm::dyn_cast<spirv::ConstantOp>(op);
+ auto constOp = dyn_cast<spirv::ConstantOp>(op);
if (!constOp) {
return failure();
}
// For EntryPoint op, check that the function and execution model is not
// duplicated in EntryPointOps. Also verify that the interface specified
// comes from globalVariables here to make this check cheaper.
- if (auto entryPointOp = llvm::dyn_cast<spirv::EntryPointOp>(op)) {
+ if (auto entryPointOp = dyn_cast<spirv::EntryPointOp>(op)) {
auto funcOp = table.lookup<FuncOp>(entryPointOp.fn());
if (!funcOp) {
return entryPointOp.emitError("function '")
continue;
}
- auto funcOp = llvm::dyn_cast<FuncOp>(op);
+ auto funcOp = dyn_cast<FuncOp>(op);
if (!funcOp)
return op.emitError("'spv.module' can only contain func and spv.* ops");
if (op.getDialect() == dialect)
continue;
- if (llvm::isa<FuncOp>(op))
+ if (isa<FuncOp>(op))
return op.emitError("'spv.module' cannot contain nested functions");
return op.emitError(
// spv.Return
//===----------------------------------------------------------------------===//
-static LogicalResult verifyReturn(spirv::ReturnOp returnOp) {
- auto funcOp = llvm::cast<FuncOp>(returnOp.getParentOp());
+static LogicalResult verify(spirv::ReturnOp returnOp) {
+ auto funcOp = cast<FuncOp>(returnOp.getParentOp());
auto numOutputs = funcOp.getType().getNumResults();
if (numOutputs != 0)
return returnOp.emitOpError("cannot be used in functions returning value")
}
static LogicalResult verify(spirv::ReturnValueOp retValOp) {
- auto funcOp = llvm::cast<FuncOp>(retValOp.getParentOp());
+ auto funcOp = cast<FuncOp>(retValOp.getParentOp());
auto numFnResults = funcOp.getType().getNumResults();
if (numFnResults != 1)
return retValOp.emitOpError(
--- /dev/null
+// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
+
+//===----------------------------------------------------------------------===//
+// spv.Return
+//===----------------------------------------------------------------------===//
+
+"foo.function"() ({
+ // expected-error @+1 {{op must appear in a 'func' block}}
+ spv.Return
+}) : () -> ()
+
+// -----
+
+// Return mismatches function signature
+spv.module "Logical" "VulkanKHR" {
+ func @work() -> (i32) {
+ // expected-error @+1 {{cannot be used in functions returning value}}
+ spv.Return
+ }
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spv.ReturnValue
+//===----------------------------------------------------------------------===//
+
+func @ret_val() -> (i32) {
+ %0 = spv.constant 42 : i32
+ // CHECK: spv.ReturnValue %{{.*}} : i32
+ spv.ReturnValue %0 : i32
+}
+
+// -----
+
+"foo.function"() ({
+ %0 = spv.constant true
+ // expected-error @+1 {{op must appear in a 'func' block}}
+ spv.ReturnValue %0 : i1
+}) : () -> ()
+
+// -----
+
+func @value_count_mismatch() -> () {
+ %0 = spv.constant 42 : i32
+ // expected-error @+1 {{op returns 1 value but enclosing function requires 0 results}}
+ spv.ReturnValue %0 : i32
+}
+
+// -----
+
+func @value_type_mismatch() -> (f32) {
+ %0 = spv.constant 42 : i32
+ // expected-error @+1 {{return value's type ('i32') mismatch with function's result type ('f32')}}
+ spv.ReturnValue %0 : i32
+}
// -----
//===----------------------------------------------------------------------===//
-// spv.Return
-//===----------------------------------------------------------------------===//
-
-"foo.function"() ({
- // expected-error @+1 {{op must appear in a 'func' block}}
- spv.Return
-}) : () -> ()
-
-// -----
-
-// Return mismatches function signature
-spv.module "Logical" "VulkanKHR" {
- func @work() -> (i32) {
- // expected-error @+1 {{cannot be used in functions returning value}}
- spv.Return
- }
-}
-
-// -----
-
-//===----------------------------------------------------------------------===//
-// spv.ReturnValue
-//===----------------------------------------------------------------------===//
-
-func @ret_val() -> (i32) {
- %0 = spv.constant 42 : i32
- spv.ReturnValue %0 : i32
-}
-
-// -----
-
-"foo.function"() ({
- %0 = spv.constant true
- // expected-error @+1 {{op must appear in a 'func' block}}
- spv.ReturnValue %0 : i1
-}) : () -> ()
-
-// -----
-
-func @value_count_mismatch() -> () {
- %0 = spv.constant 42 : i32
- // expected-error @+1 {{op returns 1 value but enclosing function requires 0 results}}
- spv.ReturnValue %0 : i32
-}
-
-// -----
-
-func @value_type_mismatch() -> (f32) {
- %0 = spv.constant 42 : i32
- // expected-error @+1 {{return value's type ('i32') mismatch with function's result type ('f32')}}
- spv.ReturnValue %0 : i32
-}
-
-// -----
-
-//===----------------------------------------------------------------------===//
// spv.StoreOp
//===----------------------------------------------------------------------===//