diff --git a/mlir/include/mlir/IR/BuiltinOps.h b/mlir/include/mlir/IR/BuiltinOps.h --- a/mlir/include/mlir/IR/BuiltinOps.h +++ b/mlir/include/mlir/IR/BuiltinOps.h @@ -13,6 +13,7 @@ #ifndef MLIR_IR_BUILTINOPS_H_ #define MLIR_IR_BUILTINOPS_H_ +#include "mlir/IR/ModuleInterfaces.h" #include "mlir/IR/OpImplementation.h" #include "mlir/IR/OwningOpRef.h" #include "mlir/IR/RegionKindInterface.h" diff --git a/mlir/include/mlir/IR/BuiltinOps.td b/mlir/include/mlir/IR/BuiltinOps.td --- a/mlir/include/mlir/IR/BuiltinOps.td +++ b/mlir/include/mlir/IR/BuiltinOps.td @@ -15,6 +15,7 @@ #define BUILTIN_OPS include "mlir/IR/BuiltinDialect.td" +include "mlir/IR/ModuleInterfaces.td" include "mlir/IR/OpAsmInterface.td" include "mlir/IR/RegionKindInterface.td" include "mlir/IR/SymbolInterfaces.td" @@ -31,8 +32,8 @@ //===----------------------------------------------------------------------===// def ModuleOp : Builtin_Op<"module", [ - AffineScope, IsolatedFromAbove, NoRegionArguments, SymbolTable, Symbol, - OpAsmOpInterface + ModuleOpInterface, AffineScope, IsolatedFromAbove, NoRegionArguments, + SymbolTable, Symbol, OpAsmOpInterface ] # GraphRegionNoTerminator.traits> { let summary = "A top level container operation"; let description = [{ diff --git a/mlir/include/mlir/IR/CMakeLists.txt b/mlir/include/mlir/IR/CMakeLists.txt --- a/mlir/include/mlir/IR/CMakeLists.txt +++ b/mlir/include/mlir/IR/CMakeLists.txt @@ -1,6 +1,7 @@ +add_mlir_interface(ModuleInterfaces) add_mlir_interface(OpAsmInterface) -add_mlir_interface(SymbolInterfaces) add_mlir_interface(RegionKindInterface) +add_mlir_interface(SymbolInterfaces) set(LLVM_TARGET_DEFINITIONS BuiltinAttributes.td) mlir_tablegen(BuiltinAttributes.h.inc -gen-attrdef-decls) diff --git a/mlir/include/mlir/IR/ModuleInterfaces.h b/mlir/include/mlir/IR/ModuleInterfaces.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/IR/ModuleInterfaces.h @@ -0,0 +1,16 @@ +//===- ModuleInterfaces.h - Interface for module ops ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_IR_MODULEINTERFACES_H +#define MLIR_IR_MODULEINTERFACES_H + +#include "mlir/IR/OpDefinition.h" + +#include "mlir/IR/ModuleInterfaces.h.inc" + +#endif // MLIR_IR_MODULEINTERFACES_H diff --git a/mlir/include/mlir/IR/ModuleInterfaces.td b/mlir/include/mlir/IR/ModuleInterfaces.td new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/IR/ModuleInterfaces.td @@ -0,0 +1,24 @@ +//===- ModuleInterface.td - Interface for module ops -------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains interfaces that can be used to define properties of +// top-level module-like operations. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_IR_MODULEINTERFACES +#define MLIR_IR_MODULEINTERFACES + +include "mlir/IR/OpBase.td" + +def ModuleOpInterface : OpInterface<"ModuleOpInterface"> { + let cppNamespace = "::mlir"; + let description = [{TODO}]; +} + +#endif // MLIR_IR_MODULEINTERFACES diff --git a/mlir/include/mlir/Parser/Parser.h b/mlir/include/mlir/Parser/Parser.h --- a/mlir/include/mlir/Parser/Parser.h +++ b/mlir/include/mlir/Parser/Parser.h @@ -15,6 +15,7 @@ #include "mlir/IR/AsmState.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinOps.h" #include "mlir/IR/OwningOpRef.h" #include @@ -147,6 +148,34 @@ return detail::parseSourceFile(config, sourceMgr); } +/// This parses the file specified by the indicated SourceMgr. If the source IR +/// contained a single instance of an op implementing `ModuleOpInterface`, it is +/// returned. Otherwise, a new `builtin.module` op is constructed containing all +/// of the parsed operations. If parsing was not successful, null is returned +/// and an error message is emitted through the error handler registered in the +/// context, and failure is returned. +inline OwningOpRef +parseSourceFile(const llvm::SourceMgr &sourceMgr, const ParserConfig &config) { + LocationAttr sourceFileLoc; + Block block; + if (failed(parseSourceFile(sourceMgr, &block, config, &sourceFileLoc))) + return nullptr; + + // Check to see if we parsed a single module-like operation. + if (llvm::hasSingleElement(block)) { + if (auto mod = dyn_cast(block.front())) { + mod->remove(); + return mod; + } + } + + // If not, then build a new module op to contain it. + auto mod = ModuleOp::create(sourceFileLoc); + Block *body = mod.getBody(); + body->getOperations().splice(body->begin(), block.getOperations()); + return cast(*mod); +} + /// This parses the file specified by the indicated filename. If the source IR /// contained a single instance of `ContainerOpT`, it is returned. Otherwise, a /// new instance of `ContainerOpT` is constructed containing all of the parsed diff --git a/mlir/lib/IR/CMakeLists.txt b/mlir/lib/IR/CMakeLists.txt --- a/mlir/lib/IR/CMakeLists.txt +++ b/mlir/lib/IR/CMakeLists.txt @@ -21,6 +21,7 @@ IntegerSet.cpp Location.cpp MLIRContext.cpp + ModuleInterfaces.cpp Operation.cpp OperationSupport.cpp PatternMatch.cpp diff --git a/mlir/lib/IR/ModuleInterfaces.cpp b/mlir/lib/IR/ModuleInterfaces.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/IR/ModuleInterfaces.cpp @@ -0,0 +1,10 @@ +//===- ModuleInterfaces.cpp - Interface for module ops ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "mlir/IR/ModuleInterfaces.h" +#include "mlir/IR/ModuleInterfaces.cpp.inc" diff --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp --- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp +++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp @@ -68,7 +68,7 @@ // Parse the input file and reset the context threading state. TimingScope parserTiming = timing.nest("Parser"); - OwningOpRef module(parseSourceFile(sourceMgr, config)); + OwningOpRef module = parseSourceFile(sourceMgr, config); context->enableMultithreading(wasThreadingEnabled); if (!module) return failure(); @@ -76,7 +76,7 @@ // Prepare the pass manager, applying command-line and reproducer options. PassManager pm(context, OpPassManager::Nesting::Implicit, - module->getOperationName()); + module->getOperation()->getName().getStringRef()); pm.enableVerifier(verifyPasses); applyPassManagerCLOptions(pm); pm.enableTiming(timing); diff --git a/mlir/test/IR/module-op.mlir b/mlir/test/IR/module-op.mlir --- a/mlir/test/IR/module-op.mlir +++ b/mlir/test/IR/module-op.mlir @@ -1,4 +1,4 @@ -// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -mlir-print-debuginfo -mlir-print-local-scope | FileCheck %s +// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -mlir-print-debuginfo -mlir-print-local-scope -verify-diagnostics | FileCheck %s // CHECK: module { module { @@ -34,6 +34,14 @@ // ----- +// Check that no implicit module is inserted if there's a already a top-level +// module-like operation. +// CHECK-NOT: module { +// CHECK: test.module +test.module + +// ----- + // Check that the implicit top-level module is also a name scope for SSA // values. This should not crash. // CHECK: module { diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -14,8 +14,9 @@ include "mlir/Dialect/DLTI/DLTIBase.td" include "mlir/Dialect/Linalg/IR/LinalgInterfaces.td" include "mlir/IR/EnumAttr.td" -include "mlir/IR/OpBase.td" +include "mlir/IR/ModuleInterfaces.td" include "mlir/IR/OpAsmInterface.td" +include "mlir/IR/OpBase.td" include "mlir/IR/PatternBase.td" include "mlir/IR/RegionKindInterface.td" include "mlir/IR/SymbolInterfaces.td" @@ -2996,4 +2997,12 @@ let assemblyFormat = "attr-dict $value"; } + +//===----------------------------------------------------------------------===// +// Test ModuleOpInterface +//===----------------------------------------------------------------------===// +def TestModuleOp : TEST_Op<"module", [ModuleOpInterface]> { + let assemblyFormat = "attr-dict"; +} + #endif // TEST_OPS