[Mlir-commits] [mlir] b579803 - [mlir][Parser] Don't hardcode the use of ModuleOp in the parser

River Riddle llvmlistbot at llvm.org
Thu Dec 3 15:53:57 PST 2020


Author: River Riddle
Date: 2020-12-03T15:47:02-08:00
New Revision: b57980309a699a47a46b5b5749b36fea06eaaf33

URL: https://github.com/llvm/llvm-project/commit/b57980309a699a47a46b5b5749b36fea06eaaf33
DIFF: https://github.com/llvm/llvm-project/commit/b57980309a699a47a46b5b5749b36fea06eaaf33.diff

LOG: [mlir][Parser] Don't hardcode the use of ModuleOp in the parser

This was important when ModuleOp was the only top level operation, but that isn't necessarily the case anymore. This is one of the last remaining aspects of the infrastructure that is hardcoded to ModuleOp.

Differential Revision: https://reviews.llvm.org/D92605

Added: 
    mlir/include/mlir/IR/OwningOpRef.h

Modified: 
    mlir/include/mlir/Dialect/SPIRV/SPIRVModule.h
    mlir/include/mlir/IR/BuiltinOps.h
    mlir/include/mlir/IR/OpDefinition.h
    mlir/include/mlir/Parser.h
    mlir/lib/Parser/Parser.cpp

Removed: 
    mlir/include/mlir/IR/OwningOpRefBase.h


################################################################################
diff  --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVModule.h b/mlir/include/mlir/Dialect/SPIRV/SPIRVModule.h
index a53331eda4fa..9f2692f8e903 100644
--- a/mlir/include/mlir/Dialect/SPIRV/SPIRVModule.h
+++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVModule.h
@@ -10,7 +10,7 @@
 #define MLIR_DIALECT_SPIRV_SPIRVMODULE_H
 
 #include "mlir/Dialect/SPIRV/SPIRVOps.h"
-#include "mlir/IR/OwningOpRefBase.h"
+#include "mlir/IR/OwningOpRef.h"
 
 namespace mlir {
 namespace spirv {
@@ -18,9 +18,10 @@ namespace spirv {
 /// This class acts as an owning reference to a SPIR-V module, and will
 /// automatically destroy the held module on destruction if the held module
 /// is valid.
-class OwningSPIRVModuleRef : public OwningOpRefBase<spirv::ModuleOp> {
+// TODO: Remove this class in favor of using OwningOpRef directly.
+class OwningSPIRVModuleRef : public OwningOpRef<spirv::ModuleOp> {
 public:
-  using OwningOpRefBase<spirv::ModuleOp>::OwningOpRefBase;
+  using OwningOpRef<spirv::ModuleOp>::OwningOpRef;
 };
 
 } // end namespace spirv

diff  --git a/mlir/include/mlir/IR/BuiltinOps.h b/mlir/include/mlir/IR/BuiltinOps.h
index 811b87ba4f09..dd23f90af6c7 100644
--- a/mlir/include/mlir/IR/BuiltinOps.h
+++ b/mlir/include/mlir/IR/BuiltinOps.h
@@ -14,7 +14,7 @@
 #define MLIR_IR_BUILTINOPS_H_
 
 #include "mlir/IR/FunctionSupport.h"
-#include "mlir/IR/OwningOpRefBase.h"
+#include "mlir/IR/OwningOpRef.h"
 #include "mlir/IR/SymbolTable.h"
 #include "mlir/Interfaces/CallInterfaces.h"
 #include "llvm/Support/PointerLikeTypeTraits.h"
@@ -33,9 +33,12 @@
 namespace mlir {
 /// This class acts as an owning reference to a module, and will automatically
 /// destroy the held module on destruction if the held module is valid.
-class OwningModuleRef : public OwningOpRefBase<ModuleOp> {
+// TODO: Remove this class in favor of using OwningOpRef directly.
+class OwningModuleRef : public OwningOpRef<ModuleOp> {
 public:
-  using OwningOpRefBase<ModuleOp>::OwningOpRefBase;
+  using OwningOpRef<ModuleOp>::OwningOpRef;
+  OwningModuleRef(OwningOpRef<ModuleOp> &&other)
+      : OwningOpRef<ModuleOp>(std::move(other)) {}
 };
 } // end namespace mlir
 

diff  --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h
index 2867c4c73290..b200f7c2dc6c 100644
--- a/mlir/include/mlir/IR/OpDefinition.h
+++ b/mlir/include/mlir/IR/OpDefinition.h
@@ -808,6 +808,9 @@ struct SingleBlockImplicitTerminator {
     }
 
   public:
+    /// The type of the operation used as the implicit terminator type.
+    using ImplicitTerminatorOpT = TerminatorOpType;
+
     static LogicalResult verifyTrait(Operation *op) {
       for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
         Region &region = op->getRegion(i);

diff  --git a/mlir/include/mlir/IR/OwningOpRefBase.h b/mlir/include/mlir/IR/OwningOpRef.h
similarity index 70%
rename from mlir/include/mlir/IR/OwningOpRefBase.h
rename to mlir/include/mlir/IR/OwningOpRef.h
index bfdf98f6f37e..c7ea1c615e60 100644
--- a/mlir/include/mlir/IR/OwningOpRefBase.h
+++ b/mlir/include/mlir/IR/OwningOpRef.h
@@ -1,4 +1,4 @@
-//===- OwningOpRefBase.h - MLIR OwningOpRefBase -----------------*- C++ -*-===//
+//===- OwningOpRef.h - MLIR OwningOpRef -------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,8 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef MLIR_IR_OWNINGOPREFBASE_H
-#define MLIR_IR_OWNINGOPREFBASE_H
+#ifndef MLIR_IR_OWNINGOPREF_H
+#define MLIR_IR_OWNINGOPREF_H
 
 #include <utility>
 
@@ -24,20 +24,23 @@ namespace mlir {
 /// instead, and this should only be used in situations where existing solutions
 /// are not viable.
 template <typename OpTy>
-class OwningOpRefBase {
+class OwningOpRef {
 public:
-  OwningOpRefBase(std::nullptr_t = nullptr) {}
-  OwningOpRefBase(OpTy op) : op(op) {}
-  OwningOpRefBase(OwningOpRefBase &&other) : op(other.release()) {}
-  ~OwningOpRefBase() {
+  /// The underlying operation type stored in this reference.
+  using OperationT = OpTy;
+
+  OwningOpRef(std::nullptr_t = nullptr) {}
+  OwningOpRef(OpTy op) : op(op) {}
+  OwningOpRef(OwningOpRef &&other) : op(other.release()) {}
+  ~OwningOpRef() {
     if (op)
-      op.erase();
+      op->erase();
   }
 
-  // Assign from another op reference.
-  OwningOpRefBase &operator=(OwningOpRefBase &&other) {
+  /// Assign from another op reference.
+  OwningOpRef &operator=(OwningOpRef &&other) {
     if (op)
-      op.erase();
+      op->erase();
     op = other.release();
     return *this;
   }
@@ -61,4 +64,4 @@ class OwningOpRefBase {
 
 } // end namespace mlir
 
-#endif // MLIR_IR_OWNINGOPREFBASE_H
+#endif // MLIR_IR_OWNINGOPREF_H

diff  --git a/mlir/include/mlir/Parser.h b/mlir/include/mlir/Parser.h
index 8bba2ef4d53d..b9e4d170a044 100644
--- a/mlir/include/mlir/Parser.h
+++ b/mlir/include/mlir/Parser.h
@@ -13,6 +13,8 @@
 #ifndef MLIR_PARSER_H
 #define MLIR_PARSER_H
 
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
 #include <cstddef>
 
 namespace llvm {
@@ -22,36 +24,195 @@ class StringRef;
 } // end namespace llvm
 
 namespace mlir {
-class Attribute;
-class Location;
-class MLIRContext;
-class OwningModuleRef;
-class Type;
-
-/// This parses the file specified by the indicated SourceMgr and returns an
-/// MLIR module if it was valid.  If not, the error message is emitted through
-/// the error handler registered in the context, and a null pointer is returned.
-OwningModuleRef parseSourceFile(const llvm::SourceMgr &sourceMgr,
-                                MLIRContext *context);
-
-/// This parses the file specified by the indicated filename and returns an
-/// MLIR module if it was valid.  If not, the error message is emitted through
-/// the error handler registered in the context, and a null pointer is returned.
-OwningModuleRef parseSourceFile(llvm::StringRef filename, MLIRContext *context);
+namespace detail {
+/// Given a block containing operations that have just been parsed, if the block
+/// contains a single operation of `ContainerOpT` type then remove it from the
+/// block and return it. If the block does not contain just that operation,
+/// create a new operation instance of `ContainerOpT` and move all of the
+/// operations within `parsedBlock` into the first block of the first region.
+/// `ContainerOpT` is required to have a single region containing a single
+/// block, and must implement the `SingleBlockImplicitTerminator` trait.
+template <typename ContainerOpT>
+inline OwningOpRef<ContainerOpT> constructContainerOpForParserIfNecessary(
+    Block *parsedBlock, MLIRContext *context, Location sourceFileLoc) {
+  static_assert(
+      ContainerOpT::template hasTrait<OpTrait::OneRegion>() &&
+          std::is_base_of<typename OpTrait::SingleBlockImplicitTerminator<
+                              typename ContainerOpT::ImplicitTerminatorOpT>::
+                              template Impl<ContainerOpT>,
+                          ContainerOpT>::value,
+      "Expected `ContainerOpT` to have a single region with a single "
+      "block that has an implicit terminator");
+
+  // Check to see if we parsed a single instance of this operation.
+  if (llvm::hasSingleElement(*parsedBlock)) {
+    if (ContainerOpT op = dyn_cast<ContainerOpT>(parsedBlock->front())) {
+      op->remove();
+      return op;
+    }
+  }
+
+  // If not, then build a new one to contain the parsed operations.
+  OpBuilder builder(context);
+  ContainerOpT op = builder.create<ContainerOpT>(sourceFileLoc);
+  OwningOpRef<ContainerOpT> opRef(op);
+  assert(op->getNumRegions() == 1 && llvm::hasSingleElement(op->getRegion(0)) &&
+         "expected generated operation to have a single region with a single "
+         "block");
+  Block *opBlock = &op->getRegion(0).front();
+  opBlock->getOperations().splice(opBlock->begin(),
+                                  parsedBlock->getOperations());
+
+  // After splicing, verify just this operation to ensure it can properly
+  // contain the operations inside of it.
+  if (failed(op.verify()))
+    return OwningOpRef<ContainerOpT>();
+  return std::move(opRef);
+}
+} // end namespace detail
+
+/// This parses the file specified by the indicated SourceMgr and appends parsed
+/// operations to the given block. If the block is non-empty, the operations are
+/// placed before the current terminator. If parsing is successful, success is
+/// returned. Otherwise, an error message is emitted through the error handler
+/// registered in the context, and failure is returned. If `sourceFileLoc` is
+/// non-null, it is populated with a file location representing the start of the
+/// source file that is being parsed.
+LogicalResult parseSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
+                              MLIRContext *context,
+                              LocationAttr *sourceFileLoc = nullptr);
+
+/// This parses the file specified by the indicated filename and appends parsed
+/// operations to the given block. If the block is non-empty, the operations are
+/// placed before the current terminator. If parsing is successful, success is
+/// returned. Otherwise, an error message is emitted through the error handler
+/// registered in the context, and failure is returned. If `sourceFileLoc` is
+/// non-null, it is populated with a file location representing the start of the
+/// source file that is being parsed.
+LogicalResult parseSourceFile(llvm::StringRef filename, Block *block,
+                              MLIRContext *context,
+                              LocationAttr *sourceFileLoc = nullptr);
 
 /// This parses the file specified by the indicated filename using the provided
-/// SourceMgr and returns an MLIR module if it was valid.  If not, the error
-/// message is emitted through the error handler registered in the context, and
-/// a null pointer is returned.
-OwningModuleRef parseSourceFile(llvm::StringRef filename,
-                                llvm::SourceMgr &sourceMgr,
-                                MLIRContext *context);
+/// SourceMgr and appends parsed operations to the given block. If the block is
+/// non-empty, the operations are placed before the current terminator. If
+/// parsing is successful, success is returned. Otherwise, an error message is
+/// emitted through the error handler registered in the context, and failure is
+/// returned. If `sourceFileLoc` is non-null, it is populated with a file
+/// location representing the start of the source file that is being parsed.
+LogicalResult parseSourceFile(llvm::StringRef filename,
+                              llvm::SourceMgr &sourceMgr, Block *block,
+                              MLIRContext *context,
+                              LocationAttr *sourceFileLoc = nullptr);
 
-/// This parses the module string to a MLIR module if it was valid.  If not, the
+/// This parses the IR string and appends parsed operations to the given block.
+/// If the block is non-empty, the operations are placed before the current
+/// terminator. If parsing is successful, success is returned. Otherwise, an
 /// error message is emitted through the error handler registered in the
-/// context, and a null pointer is returned.
-OwningModuleRef parseSourceString(llvm::StringRef moduleStr,
-                                  MLIRContext *context);
+/// context, and failure is returned. If `sourceFileLoc` is non-null, it is
+/// populated with a file location representing the start of the source file
+/// that is being parsed.
+LogicalResult parseSourceString(llvm::StringRef sourceStr, Block *block,
+                                MLIRContext *context,
+                                LocationAttr *sourceFileLoc = nullptr);
+
+/// This parses the file specified by the indicated SourceMgr. 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
+/// 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. `ContainerOpT` is required to have a single region
+/// containing a single block, and must implement the
+/// `SingleBlockImplicitTerminator` trait.
+template <typename ContainerOpT>
+inline OwningOpRef<ContainerOpT>
+parseSourceFile(const llvm::SourceMgr &sourceMgr, MLIRContext *context) {
+  LocationAttr sourceFileLoc;
+  Block block;
+  if (failed(parseSourceFile(sourceMgr, &block, context, &sourceFileLoc)))
+    return OwningOpRef<ContainerOpT>();
+  return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
+      &block, context, sourceFileLoc);
+}
+
+/// 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
+/// 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. `ContainerOpT` is required to have a single region
+/// containing a single block, and must implement the
+/// `SingleBlockImplicitTerminator` trait.
+template <typename ContainerOpT>
+inline OwningOpRef<ContainerOpT> parseSourceFile(llvm::StringRef filename,
+                                                 MLIRContext *context) {
+  LocationAttr sourceFileLoc;
+  Block block;
+  if (failed(parseSourceFile(filename, &block, context, &sourceFileLoc)))
+    return OwningOpRef<ContainerOpT>();
+  return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
+      &block, context, sourceFileLoc);
+}
+
+/// This parses the file specified by the indicated filename using the provided
+/// SourceMgr. 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 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. `ContainerOpT` is
+/// required to have a single region containing a single block, and must
+/// implement the `SingleBlockImplicitTerminator` trait.
+template <typename ContainerOpT>
+inline OwningOpRef<ContainerOpT> parseSourceFile(llvm::StringRef filename,
+                                                 llvm::SourceMgr &sourceMgr,
+                                                 MLIRContext *context) {
+  LocationAttr sourceFileLoc;
+  Block block;
+  if (failed(parseSourceFile(filename, sourceMgr, &block, context,
+                             &sourceFileLoc)))
+    return OwningOpRef<ContainerOpT>();
+  return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
+      &block, context, sourceFileLoc);
+}
+
+/// This parses the provided string containing MLIR. 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
+/// 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. `ContainerOpT` is required to have a single region
+/// containing a single block, and must implement the
+/// `SingleBlockImplicitTerminator` trait.
+template <typename ContainerOpT>
+inline OwningOpRef<ContainerOpT> parseSourceString(llvm::StringRef sourceStr,
+                                                   MLIRContext *context) {
+  LocationAttr sourceFileLoc;
+  Block block;
+  if (failed(parseSourceString(sourceStr, &block, context, &sourceFileLoc)))
+    return OwningOpRef<ContainerOpT>();
+  return detail::constructContainerOpForParserIfNecessary<ContainerOpT>(
+      &block, context, sourceFileLoc);
+}
+
+/// TODO: These methods are deprecated in favor of the above template versions.
+/// They should be removed when usages have been updated.
+inline OwningModuleRef parseSourceFile(const llvm::SourceMgr &sourceMgr,
+                                       MLIRContext *context) {
+  return parseSourceFile<ModuleOp>(sourceMgr, context);
+}
+inline OwningModuleRef parseSourceFile(llvm::StringRef filename,
+                                       MLIRContext *context) {
+  return parseSourceFile<ModuleOp>(filename, context);
+}
+inline OwningModuleRef parseSourceFile(llvm::StringRef filename,
+                                       llvm::SourceMgr &sourceMgr,
+                                       MLIRContext *context) {
+  return parseSourceFile<ModuleOp>(filename, sourceMgr, context);
+}
+inline OwningModuleRef parseSourceString(llvm::StringRef moduleStr,
+                                         MLIRContext *context) {
+  return parseSourceString<ModuleOp>(moduleStr, context);
+}
 
 /// This parses a single MLIR attribute to an MLIR context if it was valid.  If
 /// not, an error message is emitted through a new SourceMgrDiagnosticHandler

diff  --git a/mlir/lib/Parser/Parser.cpp b/mlir/lib/Parser/Parser.cpp
index 3cccefef9cf8..a5beb559f75b 100644
--- a/mlir/lib/Parser/Parser.cpp
+++ b/mlir/lib/Parser/Parser.cpp
@@ -103,8 +103,11 @@ namespace {
 /// operations.
 class OperationParser : public Parser {
 public:
-  OperationParser(ParserState &state, ModuleOp moduleOp)
-      : Parser(state), opBuilder(moduleOp.getBodyRegion()), moduleOp(moduleOp) {
+  OperationParser(ParserState &state, Operation *topLevelOp)
+      : Parser(state), opBuilder(topLevelOp->getRegion(0)),
+        topLevelOp(topLevelOp) {
+    // The top level operation starts a new name scope.
+    pushSSANameScope(/*isIsolated=*/true);
   }
 
   ~OperationParser();
@@ -310,8 +313,8 @@ class OperationParser : public Parser {
   /// The builder used when creating parsed operation instances.
   OpBuilder opBuilder;
 
-  /// The top level module operation.
-  ModuleOp moduleOp;
+  /// The top level operation that holds all of the parsed operations.
+  Operation *topLevelOp;
 };
 } // end anonymous namespace
 
@@ -359,7 +362,8 @@ ParseResult OperationParser::finalize() {
     it.first->setLoc(locAttr);
   }
 
-  return success();
+  // Pop the top level name scope.
+  return popSSANameScope();
 }
 
 //===----------------------------------------------------------------------===//
@@ -386,7 +390,7 @@ ParseResult OperationParser::popSSANameScope() {
     for (auto entry : forwardRefInCurrentScope) {
       errors.push_back({entry.second.getPointer(), entry.first});
       // Add this block to the top-level region to allow for automatic cleanup.
-      moduleOp->getRegion(0).push_back(entry.first);
+      topLevelOp->getRegion(0).push_back(entry.first);
     }
     llvm::array_pod_sort(errors.begin(), errors.end());
 
@@ -800,7 +804,7 @@ Operation *OperationParser::parseGenericOperation() {
   if (consumeIf(Token::l_paren)) {
     do {
       // Create temporary regions with the top level region as parent.
-      result.regions.emplace_back(new Region(moduleOp));
+      result.regions.emplace_back(new Region(topLevelOp));
       if (parseRegion(*result.regions.back(), /*entryArguments=*/{}))
         return nullptr;
     } while (consumeIf(Token::comma));
@@ -1920,11 +1924,12 @@ ParseResult OperationParser::parseOptionalBlockArgList(
 namespace {
 /// This parser handles entities that are only valid at the top level of the
 /// file.
-class ModuleParser : public Parser {
+class TopLevelOperationParser : public Parser {
 public:
-  explicit ModuleParser(ParserState &state) : Parser(state) {}
+  explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
 
-  ParseResult parseModule(ModuleOp module);
+  /// Parse a set of operations into the end of the given Block.
+  ParseResult parse(Block *topLevelBlock, Location parserLoc);
 
 private:
   /// Parse an attribute alias declaration.
@@ -1939,7 +1944,7 @@ class ModuleParser : public Parser {
 ///
 ///   attribute-alias-def ::= '#' alias-name `=` attribute-value
 ///
-ParseResult ModuleParser::parseAttributeAliasDef() {
+ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
   assert(getToken().is(Token::hash_identifier));
   StringRef aliasName = getTokenSpelling().drop_front();
 
@@ -1971,7 +1976,7 @@ ParseResult ModuleParser::parseAttributeAliasDef() {
 ///
 ///   type-alias-def ::= '!' alias-name `=` 'type' type
 ///
-ParseResult ModuleParser::parseTypeAliasDef() {
+ParseResult TopLevelOperationParser::parseTypeAliasDef() {
   assert(getToken().is(Token::exclamation_identifier));
   StringRef aliasName = getTokenSpelling().drop_front();
 
@@ -2001,13 +2006,11 @@ ParseResult ModuleParser::parseTypeAliasDef() {
   return success();
 }
 
-/// This is the top-level module parser.
-ParseResult ModuleParser::parseModule(ModuleOp module) {
-  OperationParser opParser(getState(), module);
-
-  // Module itself is a name scope.
-  opParser.pushSSANameScope(/*isIsolated=*/true);
-
+ParseResult TopLevelOperationParser::parse(Block *topLevelBlock,
+                                           Location parserLoc) {
+  // Create a top-level operation to contain the parsed state.
+  OwningOpRef<Operation *> topLevelOp(ModuleOp::create(parserLoc));
+  OperationParser opParser(getState(), topLevelOp.get());
   while (true) {
     switch (getToken().getKind()) {
     default:
@@ -2021,25 +2024,17 @@ ParseResult ModuleParser::parseModule(ModuleOp module) {
       if (opParser.finalize())
         return failure();
 
-      // Handle the case where the top level module was explicitly defined.
-      auto &bodyBlocks = module.getBodyRegion().getBlocks();
-      auto &operations = bodyBlocks.front().getOperations();
-      assert(!operations.empty() && "expected a valid module terminator");
-
-      // Check that the first operation is a module, and it is the only
-      // non-terminator operation.
-      ModuleOp nested = dyn_cast<ModuleOp>(operations.front());
-      if (nested && std::next(operations.begin(), 2) == operations.end()) {
-        // Merge the data of the nested module operation into 'module'.
-        module.setLoc(nested.getLoc());
-        module.setAttrs(nested->getMutableAttrDict());
-        bodyBlocks.splice(bodyBlocks.end(), nested.getBodyRegion().getBlocks());
-
-        // Erase the original module body.
-        bodyBlocks.pop_front();
-      }
+      // Verify that the parsed operations are valid.
+      if (failed(verify(topLevelOp.get())))
+        return failure();
 
-      return opParser.popSSANameScope();
+      // Splice the blocks of the parsed operation over to the provided
+      // top-level block.
+      auto &parsedOps = (*topLevelOp)->getRegion(0).front().getOperations();
+      auto &destOps = topLevelBlock->getOperations();
+      destOps.splice(destOps.empty() ? destOps.end() : std::prev(destOps.end()),
+                     parsedOps, parsedOps.begin(), std::prev(parsedOps.end()));
+      return success();
     }
 
     // If we got an error token, then the lexer already emitted an error, just
@@ -2065,73 +2060,55 @@ ParseResult ModuleParser::parseModule(ModuleOp module) {
 
 //===----------------------------------------------------------------------===//
 
-/// This parses the file specified by the indicated SourceMgr and returns an
-/// MLIR module if it was valid.  If not, it emits diagnostics and returns
-/// null.
-OwningModuleRef mlir::parseSourceFile(const llvm::SourceMgr &sourceMgr,
-                                      MLIRContext *context) {
-  auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
+LogicalResult mlir::parseSourceFile(const llvm::SourceMgr &sourceMgr,
+                                    Block *block, MLIRContext *context,
+                                    LocationAttr *sourceFileLoc) {
+  const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
 
-  // This is the result module we are parsing into.
-  OwningModuleRef module(ModuleOp::create(FileLineColLoc::get(
-      sourceBuf->getBufferIdentifier(), /*line=*/0, /*column=*/0, context)));
+  Location parserLoc = FileLineColLoc::get(sourceBuf->getBufferIdentifier(),
+                                           /*line=*/0, /*column=*/0, context);
+  if (sourceFileLoc)
+    *sourceFileLoc = parserLoc;
 
   SymbolState aliasState;
   ParserState state(sourceMgr, context, aliasState);
-  if (ModuleParser(state).parseModule(*module))
-    return nullptr;
-
-  // Make sure the parse module has no other structural problems detected by
-  // the verifier.
-  if (failed(verify(*module)))
-    return nullptr;
-
-  return module;
+  return TopLevelOperationParser(state).parse(block, parserLoc);
 }
 
-/// This parses the file specified by the indicated filename and returns an
-/// MLIR module if it was valid.  If not, the error message is emitted through
-/// the error handler registered in the context, and a null pointer is returned.
-OwningModuleRef mlir::parseSourceFile(StringRef filename,
-                                      MLIRContext *context) {
+LogicalResult mlir::parseSourceFile(llvm::StringRef filename, Block *block,
+                                    MLIRContext *context,
+                                    LocationAttr *sourceFileLoc) {
   llvm::SourceMgr sourceMgr;
-  return parseSourceFile(filename, sourceMgr, context);
+  return parseSourceFile(filename, sourceMgr, block, context, sourceFileLoc);
 }
 
-/// This parses the file specified by the indicated filename using the provided
-/// SourceMgr and returns an MLIR module if it was valid.  If not, the error
-/// message is emitted through the error handler registered in the context, and
-/// a null pointer is returned.
-OwningModuleRef mlir::parseSourceFile(StringRef filename,
-                                      llvm::SourceMgr &sourceMgr,
-                                      MLIRContext *context) {
+LogicalResult mlir::parseSourceFile(llvm::StringRef filename,
+                                    llvm::SourceMgr &sourceMgr, Block *block,
+                                    MLIRContext *context,
+                                    LocationAttr *sourceFileLoc) {
   if (sourceMgr.getNumBuffers() != 0) {
     // TODO: Extend to support multiple buffers.
-    emitError(mlir::UnknownLoc::get(context),
-              "only main buffer parsed at the moment");
-    return nullptr;
+    return emitError(mlir::UnknownLoc::get(context),
+                     "only main buffer parsed at the moment");
   }
   auto file_or_err = llvm::MemoryBuffer::getFileOrSTDIN(filename);
-  if (std::error_code error = file_or_err.getError()) {
-    emitError(mlir::UnknownLoc::get(context),
-              "could not open input file " + filename);
-    return nullptr;
-  }
+  if (std::error_code error = file_or_err.getError())
+    return emitError(mlir::UnknownLoc::get(context),
+                     "could not open input file " + filename);
 
-  // Load the MLIR module.
+  // Load the MLIR source file.
   sourceMgr.AddNewSourceBuffer(std::move(*file_or_err), llvm::SMLoc());
-  return parseSourceFile(sourceMgr, context);
+  return parseSourceFile(sourceMgr, block, context, sourceFileLoc);
 }
 
-/// This parses the program string to a MLIR module if it was valid. If not,
-/// it emits diagnostics and returns null.
-OwningModuleRef mlir::parseSourceString(StringRef moduleStr,
-                                        MLIRContext *context) {
-  auto memBuffer = MemoryBuffer::getMemBuffer(moduleStr);
+LogicalResult mlir::parseSourceString(llvm::StringRef sourceStr, Block *block,
+                                      MLIRContext *context,
+                                      LocationAttr *sourceFileLoc) {
+  auto memBuffer = MemoryBuffer::getMemBuffer(sourceStr);
   if (!memBuffer)
-    return nullptr;
+    return failure();
 
   SourceMgr sourceMgr;
   sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
-  return parseSourceFile(sourceMgr, context);
+  return parseSourceFile(sourceMgr, block, context, sourceFileLoc);
 }


        


More information about the Mlir-commits mailing list