From: Lei Zhang Date: Wed, 29 May 2019 17:47:16 +0000 (-0700) Subject: [spirv] Add ModuleOp X-Git-Tag: llvmorg-11-init~1466^2~1571 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=22e3aa75948a489bf37b94014d50bdf9a89dd986;p=platform%2Fupstream%2Fllvm.git [spirv] Add ModuleOp 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 --- diff --git a/mlir/include/mlir/SPIRV/CMakeLists.txt b/mlir/include/mlir/SPIRV/CMakeLists.txt index df4287b..90699d9 100644 --- a/mlir/include/mlir/SPIRV/CMakeLists.txt +++ b/mlir/include/mlir/SPIRV/CMakeLists.txt @@ -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 index 0000000..0fd8231 --- /dev/null +++ b/mlir/include/mlir/SPIRV/SPIRVBase.td @@ -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.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 traits = []> : + Op; + +#endif // SPIRV_BASE diff --git a/mlir/include/mlir/SPIRV/SPIRVOps.h b/mlir/include/mlir/SPIRV/SPIRVOps.h index 00f8548..bb80c25 100644 --- a/mlir/include/mlir/SPIRV/SPIRVOps.h +++ b/mlir/include/mlir/SPIRV/SPIRVOps.h @@ -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 diff --git a/mlir/include/mlir/SPIRV/SPIRVOps.td b/mlir/include/mlir/SPIRV/SPIRVOps.td index a3d74d1..cb82268 100644 --- a/mlir/include/mlir/SPIRV/SPIRVOps.td +++ b/mlir/include/mlir/SPIRV/SPIRVOps.td @@ -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. // //===----------------------------------------------------------------------===// @@ -23,51 +24,10 @@ #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.predicate]>, - "scalar/vector of " # type.description>; - -//===----------------------------------------------------------------------===// -// SPIR-V op definitions -//===----------------------------------------------------------------------===// - -// Base class for all SPIR-V ops. -class SPV_Op traits = []> : - Op; +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 index 0000000..7fef351 --- /dev/null +++ b/mlir/include/mlir/SPIRV/SPIRVStructureOps.td @@ -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:$capabilities, + OptionalAttr:$extensions, + OptionalAttr:$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 diff --git a/mlir/lib/SPIRV/CMakeLists.txt b/mlir/lib/SPIRV/CMakeLists.txt index efc8b1e..622a7b4 100644 --- a/mlir/lib/SPIRV/CMakeLists.txt +++ b/mlir/lib/SPIRV/CMakeLists.txt @@ -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) diff --git a/mlir/lib/SPIRV/SPIRVDialect.cpp b/mlir/lib/SPIRV/SPIRVDialect.cpp index 9df0453..77b9301 100644 --- a/mlir/lib/SPIRV/SPIRVDialect.cpp +++ b/mlir/lib/SPIRV/SPIRVDialect.cpp @@ -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(); diff --git a/mlir/lib/SPIRV/SPIRVOps.cpp b/mlir/lib/SPIRV/SPIRVOps.cpp index ae23ba2..6b3449a 100644 --- a/mlir/lib/SPIRV/SPIRVOps.cpp +++ b/mlir/lib/SPIRV/SPIRVOps.cpp @@ -21,13 +21,44 @@ #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 index 0000000..157ccd7 --- /dev/null +++ b/mlir/test/SPIRV/structure-ops.mlir @@ -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 +}