Implement a simple IR verifier, including support for custom ops adding their
own requirements.

PiperOrigin-RevId: 203497491
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
new file mode 100644
index 0000000..ffc87aa
--- /dev/null
+++ b/lib/IR/Verifier.cpp
@@ -0,0 +1,155 @@
+//===- Verifier.cpp - MLIR Verifier Implementation ------------------------===//
+//
+// 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 implements the verify() methods on the various IR types, performing
+// (potentially expensive) checks on the holistic structure of the code.  This
+// can be used for detecting bugs in compiler transformations and hand written
+// .mlir files.
+//
+// The checks in this file are only for things that can occur as part of IR
+// transformations: e.g. violation of dominance information, malformed operation
+// attributes, etc.  MLIR supports transformations moving IR through locally
+// invalid states (e.g. unlinking an instruction from an instruction before
+// re-inserting it in a new place), but each transformation must complete with
+// the IR in a valid form.
+//
+// This should not check for things that are always wrong by construction (e.g.
+// affine maps or other immutable structures that are incorrect), because those
+// are not mutable and can be checked at time of construction.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/IR/CFGFunction.h"
+#include "mlir/IR/MLFunction.h"
+#include "mlir/IR/Module.h"
+#include "mlir/IR/OperationSet.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace mlir;
+
+template <typename T>
+static void failure(const Twine &message, const T &value) {
+  // Print the error message and flush the stream in case printing the value
+  // causes a crash.
+  llvm::errs() << "MLIR verification failure: " << message << "\n";
+  llvm::errs().flush();
+  value.dump();
+}
+
+//===----------------------------------------------------------------------===//
+// CFG Functions
+//===----------------------------------------------------------------------===//
+
+namespace {
+class CFGFuncVerifier {
+public:
+  const CFGFunction &fn;
+  OperationSet &operationSet;
+
+  CFGFuncVerifier(const CFGFunction &fn)
+      : fn(fn), operationSet(OperationSet::get(fn.getContext())) {}
+
+  void verify();
+  void verifyBlock(const BasicBlock &block);
+  void verifyTerminator(const TerminatorInst &term);
+  void verifyOperation(const OperationInst &inst);
+};
+} // end anonymous namespace
+
+void CFGFuncVerifier::verify() {
+  // TODO: Lots to be done here, including verifying dominance information when
+  // we have uses and defs.
+
+  for (auto &block : fn) {
+    verifyBlock(block);
+  }
+}
+
+void CFGFuncVerifier::verifyBlock(const BasicBlock &block) {
+  if (!block.getTerminator())
+    failure("basic block with no terminator", block);
+  verifyTerminator(*block.getTerminator());
+
+  for (auto &inst : block) {
+    verifyOperation(inst);
+  }
+}
+
+void CFGFuncVerifier::verifyTerminator(const TerminatorInst &term) {
+  if (term.getFunction() != &fn)
+    failure("terminator in the wrong function", term);
+
+  // TODO: Check that operands are structurally ok.
+  // TODO: Check that successors are in the right function.
+}
+
+void CFGFuncVerifier::verifyOperation(const OperationInst &inst) {
+  if (inst.getFunction() != &fn)
+    failure("operation in the wrong function", inst);
+
+  // TODO: Check that operands are structurally ok.
+
+  // See if we can get operation info for this.
+  if (auto *opInfo = inst.getAbstractOperation(fn.getContext())) {
+    if (auto errorMessage = opInfo->verifyInvariants(&inst))
+      failure(errorMessage, inst);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// ML Functions
+//===----------------------------------------------------------------------===//
+
+namespace {
+class MLFuncVerifier {
+public:
+  const MLFunction &fn;
+
+  MLFuncVerifier(const MLFunction &fn) : fn(fn) {}
+
+  void verify() {
+    // TODO.
+  }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Entrypoints
+//===----------------------------------------------------------------------===//
+
+/// Perform (potentially expensive) checks of invariants, used to detect
+/// compiler bugs.  This aborts on failure.
+void Function::verify() const {
+  switch (getKind()) {
+  case Kind::ExtFunc:
+    // No body, nothing can be wrong here.
+    break;
+  case Kind::CFGFunc:
+    return CFGFuncVerifier(*cast<CFGFunction>(this)).verify();
+  case Kind::MLFunc:
+    return MLFuncVerifier(*cast<MLFunction>(this)).verify();
+  }
+}
+
+/// Perform (potentially expensive) checks of invariants, used to detect
+/// compiler bugs.  This aborts on failure.
+void Module::verify() const {
+  /// Check that each function is correct.
+  for (auto fn : functionList) {
+    fn->verify();
+  }
+}