[spirv] Add ModuleOp
authorLei Zhang <antiagainst@google.com>
Wed, 29 May 2019 17:47:16 +0000 (10:47 -0700)
committerMehdi Amini <joker.eph@gmail.com>
Sun, 2 Jun 2019 03:07:10 +0000 (20:07 -0700)
    This op defines a SPIR-V module using a MLIR region. The region contains
    one block. Module-level operations, including functions definitions,
    are all placed in this block.

    This CL extracts common definitions from SPIRVOps.td into SPIRVBase.td.
    The new op is placed in SPIRVStructureOps.td.

--

PiperOrigin-RevId: 250522320

mlir/include/mlir/SPIRV/CMakeLists.txt
mlir/include/mlir/SPIRV/SPIRVBase.td [new file with mode: 0644]
mlir/include/mlir/SPIRV/SPIRVOps.h
mlir/include/mlir/SPIRV/SPIRVOps.td
mlir/include/mlir/SPIRV/SPIRVStructureOps.td [new file with mode: 0644]
mlir/lib/SPIRV/CMakeLists.txt
mlir/lib/SPIRV/SPIRVDialect.cpp
mlir/lib/SPIRV/SPIRVOps.cpp
mlir/test/SPIRV/structure-ops.mlir [new file with mode: 0644]

index df4287b..90699d9 100644 (file)
@@ -2,3 +2,8 @@ set(LLVM_TARGET_DEFINITIONS SPIRVOps.td)
 mlir_tablegen(SPIRVOps.h.inc -gen-op-decls)
 mlir_tablegen(SPIRVOps.cpp.inc -gen-op-defs)
 add_public_tablegen_target(MLIRSPIRVOpsIncGen)
+
+set(LLVM_TARGET_DEFINITIONS SPIRVStructureOps.td)
+mlir_tablegen(SPIRVStructureOps.h.inc -gen-op-decls)
+mlir_tablegen(SPIRVStructureOps.cpp.inc -gen-op-defs)
+add_public_tablegen_target(MLIRSPIRVStructureOpsIncGen)
diff --git a/mlir/include/mlir/SPIRV/SPIRVBase.td b/mlir/include/mlir/SPIRV/SPIRVBase.td
new file mode 100644 (file)
index 0000000..0fd8231
--- /dev/null
@@ -0,0 +1,96 @@
+//===-- SPIRVOps.td - MLIR SPIR-V Op Definitions Spec ------*- 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 is the base file for SPIR-V operation definition specification.
+// This file defines the SPIR-V dialect, common SPIR-V types, and utilities
+// for facilitating defining SPIR-V ops.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef SPIRV_BASE
+#else
+#define SPIRV_BASE
+
+#ifdef OP_BASE
+#else
+include "mlir/IR/OpBase.td"
+#endif // OP_BASE
+
+//===----------------------------------------------------------------------===//
+// SPIR-V dialect definitions
+//===----------------------------------------------------------------------===//
+
+def SPV_Dialect : Dialect {
+  let name = "spv";
+
+  let description = [{
+    The SPIR-V dialect in MLIR.
+
+    SPIR-V is the Khronos Group's binary intermediate language for representing
+    graphical-shader stages and compute kernels for multiple Khronos APIs,
+    including OpenCL, OpenGL, and Vulkan.
+    See https://www.khronos.org/registry/spir-v for more details.
+
+    This dialect aims to be a simple proxy for the SPIR-V binary format to
+    enable straightforward and lightweight conversion from/to the binary
+    format. Ops in this dialect should stay at the same semantic level and
+    try to be a mechanical mapping to the corresponding SPIR-V instructions;
+    but they may deviate representationally to allow using MLIR mechanisms.
+    As a convention, if such deviation happens, the op name follows "snake_case"
+    style; otherwise, the op name just follows the SPIR-V mnemonic (by removing
+    the leading `Op` prefix) to use "CamelCase" style.
+  }];
+
+  let cppNamespace = "spirv";
+}
+
+//===----------------------------------------------------------------------===//
+// SPIR-V type definitions
+//===----------------------------------------------------------------------===//
+
+class SPV_ScalarOrVectorOf<Type type> :
+    Type<Or<[type.predicate, VectorOf<[type]>.predicate]>,
+         "scalar/vector of " # type.description>;
+
+def SPV_AM_Logical   : EnumAttrCase<"Logical">;
+def SPV_AM_Pysical32 : EnumAttrCase<"Pysical32">;
+def SPV_AM_Pysical64 : EnumAttrCase<"Pysical64">;
+
+def SPV_AddressingModelAttr :
+    EnumAttr<"AddressingModel", "SPIR-V addressing model", [
+      SPV_AM_Logical, SPV_AM_Pysical32, SPV_AM_Pysical64
+    ]>;
+
+def SPV_MM_Simple    : EnumAttrCase<"Simple">;
+def SPV_MM_GLSL450   : EnumAttrCase<"GLSL450">;
+def SPV_MM_OpenCL    : EnumAttrCase<"OpenCL">;
+def SPV_MM_VulkanKHR : EnumAttrCase<"VulkanKHR">;
+
+def SPV_MemoryModelAttr :
+    EnumAttr<"MemoryModel", "SPIR-V memory model", [
+      SPV_MM_Simple, SPV_MM_GLSL450, SPV_MM_OpenCL, SPV_MM_VulkanKHR
+    ]>;
+
+//===----------------------------------------------------------------------===//
+// SPIR-V op definitions
+//===----------------------------------------------------------------------===//
+
+// Base class for all SPIR-V ops.
+class SPV_Op<string mnemonic, list<OpTrait> traits = []> :
+    Op<SPV_Dialect, mnemonic, traits>;
+
+#endif // SPIRV_BASE
index 00f8548..bb80c25 100644 (file)
@@ -29,6 +29,8 @@ namespace spirv {
 
 #define GET_OP_CLASSES
 #include "mlir/SPIRV/SPIRVOps.h.inc"
+#define GET_OP_CLASSES
+#include "mlir/SPIRV/SPIRVStructureOps.h.inc"
 
 } // end namespace spirv
 } // end namespace mlir
index a3d74d1..cb82268 100644 (file)
@@ -15,7 +15,8 @@
 // limitations under the License.
 // =============================================================================
 //
-// This is the operation definition specification file for SPIR-V operations.
+// This is the main operation definition specification file for SPIR-V
+// operations.
 //
 //===----------------------------------------------------------------------===//
 
 #else
 #define SPIRV_OPS
 
-#ifdef OP_BASE
+#ifdef SPIRV_BASE
 #else
-include "mlir/IR/OpBase.td"
-#endif // OP_BASE
-
-//===----------------------------------------------------------------------===//
-// SPIR-V dialect definitions
-//===----------------------------------------------------------------------===//
-
-def SPV_Dialect : Dialect {
-  let name = "spv";
-
-  let description = [{
-    The SPIR-V dialect in MLIR.
-
-    SPIR-V is the Khronos Group's binary intermediate language for representing
-    graphical-shader stages and compute kernels for multiple Khronos APIs,
-    including OpenCL, OpenGL, and Vulkan.
-    See https://www.khronos.org/registry/spir-v for more details.
-
-    This dialect aims to be a simple proxy for the SPIR-V binary format to
-    enable straightforward and lightweight conversion from/to the binary
-    format. Ops in this dialect should stay at the same semantic level and
-    try to be a mechanical mapping to the corresponding SPIR-V instructions;
-    but they may deviate representationally to allow using MLIR mechanisms.
-  }];
-
-  let cppNamespace = "spirv";
-}
-
-//===----------------------------------------------------------------------===//
-// SPIR-V type definitions
-//===----------------------------------------------------------------------===//
-
-class SPV_ScalarOrVectorOf<Type type> :
-    Type<Or<[type.predicate, VectorOf<[type]>.predicate]>,
-         "scalar/vector of " # type.description>;
-
-//===----------------------------------------------------------------------===//
-// SPIR-V op definitions
-//===----------------------------------------------------------------------===//
-
-// Base class for all SPIR-V ops.
-class SPV_Op<string mnemonic, list<OpTrait> traits = []> :
-    Op<SPV_Dialect, mnemonic, traits>;
+include "mlir/SPIRV/SPIRVBase.td"
+#endif // SPIRV_BASE
 
 def SPV_FMulOp : SPV_Op<"FMul", [NoSideEffect, SameOperandsAndResultType]> {
   let summary = "Floating-point multiplication of Operand 1 and Operand 2";
diff --git a/mlir/include/mlir/SPIRV/SPIRVStructureOps.td b/mlir/include/mlir/SPIRV/SPIRVStructureOps.td
new file mode 100644 (file)
index 0000000..7fef351
--- /dev/null
@@ -0,0 +1,82 @@
+//===-- SPIRVOps.td - MLIR SPIR-V Op Definitions Spec ------*- 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 ops for defining the SPIR-V structure: module, function,
+// and module-level operations. The representational form of these ops deviate
+// from the SPIR-V binary format in order to utilize MLIR mechanisms.
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef SPIRV_STRUCTURE_OPS
+#else
+#define SPIRV_STRUCTURE_OPS
+
+#ifdef SPIRV_BASE
+#else
+include "mlir/SPIRV/SPIRVBase.td"
+#endif // SPIRV_BASE
+
+def SPV_ModuleOp : SPV_Op<"module", []> {
+  let summary = "The top-level op that defines a SPIR-V module";
+
+  let description = [{
+    This op defines a SPIR-V module using a MLIR region. The region contains
+    one block. Module-level operations, including functions definitions,
+    are all placed in this block.
+
+    Using an op with a region to define a SPIR-V module enables "embedding"
+    SPIR-V modules in other dialects in a clean manner: this op guarantees
+    the validaty and serializability of a SPIR-V module and thus serves as
+    a clear-cut boundary.
+
+    Regularity is one of the design goals of SPIR-V. All concepts are
+    represented as SPIR-V instructions, including declaring extensions and
+    capabilities, defining types and constants, defining functions, attaching
+    additional properties to computation results, etc. This way favors driver
+    consumption but not necessarily compiler transformations. The purpose of
+    the SPIR-V dialect is to serve as the proxy of the binary format and to
+    facilitate transformations. So we adjust how certain module-level SPIR-V
+    instructions are represented in the SPIR-V dialect. Notably,
+
+    * Requirements for capabilities, extensions, extended instruction sets,
+      addressing model, and memory model is conveyed using op attributes.
+      This is considered better because these information are for the
+      exexcution environment. It's eaiser to probe them if on the module op
+      itself.
+
+    This op takes no operands and generates no results. This op should not
+    implicitly capture values from the enclosing environment.
+  }];
+
+  let arguments = (ins
+    OptionalAttr<StrArrayAttr>:$capabilities,
+    OptionalAttr<StrArrayAttr>:$extensions,
+    OptionalAttr<StrArrayAttr>:$extended_instruction_sets,
+    SPV_AddressingModelAttr:$addressing_model,
+    SPV_MemoryModelAttr:$memory_model
+  );
+
+  let results = (outs);
+
+  let numRegions = 1;
+
+  // Custom parser and printer implemented by static functions in SPVOps.cpp
+  let parser = [{ return parseModule(parser, result); }];
+  let printer = [{ printModule(getOperation(), p); }];
+}
+
+#endif // SPIRV_STRUCTURE_OPS
index efc8b1e..622a7b4 100644 (file)
@@ -7,6 +7,6 @@ add_llvm_library(MLIRSPIRV
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/SPIRV
   )
 
-add_dependencies(MLIRSPIRV MLIRSPIRVOpsIncGen)
+add_dependencies(MLIRSPIRV MLIRSPIRVOpsIncGen MLIRSPIRVStructureOpsIncGen)
 
 target_link_libraries(MLIRSPIRV MLIRIR MLIRSupport)
index 9df0453..77b9301 100644 (file)
@@ -32,6 +32,10 @@ SPIRVDialect::SPIRVDialect(MLIRContext *context) : Dialect("spv", context) {
 #define GET_OP_LIST
 #include "mlir/SPIRV/SPIRVOps.cpp.inc"
       >();
+  addOperations<
+#define GET_OP_LIST
+#include "mlir/SPIRV/SPIRVStructureOps.cpp.inc"
+      >();
 
   // Allow unknown operations because SPIR-V is extensible.
   allowUnknownOperations();
index ae23ba2..6b3449a 100644 (file)
 
 #include "mlir/SPIRV/SPIRVOps.h"
 
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/OpImplementation.h"
 #include "mlir/IR/StandardTypes.h"
 
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// spv.module
+//===----------------------------------------------------------------------===//
+
+static ParseResult parseModule(OpAsmParser *parser, OperationState *state) {
+  Region *body = state->addRegion();
+
+  if (parser->parseRegion(*body, /*arguments=*/{}, /*argTypes=*/{}) ||
+      parser->parseKeyword("attributes") ||
+      parser->parseOptionalAttributeDict(state->attributes))
+    return failure();
+
+  return success();
+}
+
+static ParseResult printModule(Operation *op, OpAsmPrinter *printer) {
+  *printer << op->getName();
+  printer->printRegion(op->getRegion(0), /*printEntryBlockArgs=*/false,
+                       /*printBlockTerminators=*/false);
+  *printer << " attributes";
+  printer->printOptionalAttrDict(op->getAttrs(),
+                                 /*elidedAttrs=*/{});
+  return success();
+}
+
 namespace mlir {
 namespace spirv {
 
 #define GET_OP_CLASSES
 #include "mlir/SPIRV/SPIRVOps.cpp.inc"
+#define GET_OP_CLASSES
+#include "mlir/SPIRV/SPIRVStructureOps.cpp.inc"
 
 } // namespace spirv
 } // namespace mlir
diff --git a/mlir/test/SPIRV/structure-ops.mlir b/mlir/test/SPIRV/structure-ops.mlir
new file mode 100644 (file)
index 0000000..157ccd7
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: mlir-opt -split-input-file -verify %s | FileCheck %s
+
+// TODO(antiagainst): Remove the wrapping functions once MLIR is moved to
+// be generally region-based.
+
+//===----------------------------------------------------------------------===//
+// spv.module
+//===----------------------------------------------------------------------===//
+
+func @module_without_cap_ext() -> () {
+  // CHECK: spv.module
+  spv.module { } attributes {
+    addressing_model: "Logical",
+    memory_model: "VulkanKHR"
+  }
+  return
+}
+
+func @module_with_cap_ext() -> () {
+  // CHECK: spv.module
+  spv.module { } attributes {
+    capability: ["Shader"],
+    extension: ["SPV_KHR_16bit_storage"],
+    addressing_model: "Logical",
+    memory_model: "VulkanKHR"
+  }
+  return
+}
+
+// -----
+
+func @missing_addressing_model() -> () {
+  // expected-error@+1 {{requires attribute 'addressing_model'}}
+  spv.module { } attributes {}
+  return
+}
+
+// -----
+
+func @wrong_addressing_model() -> () {
+  // expected-error@+1 {{attribute 'addressing_model' failed to satisfy constraint}}
+  spv.module { } attributes {addressing_model: "Physical", memory_model: "VulkanHKR"}
+  return
+}
+
+// -----
+
+func @missing_memory_model() -> () {
+  // expected-error@+1 {{requires attribute 'memory_model'}}
+  spv.module { } attributes {addressing_model: "Logical"}
+  return
+}