github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/Analysis/Verifier.cpp (about)

     1  //===- Verifier.cpp - MLIR Verifier Implementation ------------------------===//
     2  //
     3  // Copyright 2019 The MLIR Authors.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //   http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  // =============================================================================
    17  //
    18  // This file implements the verify() methods on the various IR types, performing
    19  // (potentially expensive) checks on the holistic structure of the code.  This
    20  // can be used for detecting bugs in compiler transformations and hand written
    21  // .mlir files.
    22  //
    23  // The checks in this file are only for things that can occur as part of IR
    24  // transformations: e.g. violation of dominance information, malformed operation
    25  // attributes, etc.  MLIR supports transformations moving IR through locally
    26  // invalid states (e.g. unlinking an operation from a block before re-inserting
    27  // it in a new place), but each transformation must complete with the IR in a
    28  // valid form.
    29  //
    30  // This should not check for things that are always wrong by construction (e.g.
    31  // attributes or other immutable structures that are incorrect), because those
    32  // are not mutable and can be checked at time of construction.
    33  //
    34  //===----------------------------------------------------------------------===//
    35  
    36  #include "mlir/Analysis/Verifier.h"
    37  #include "mlir/Analysis/Dominance.h"
    38  #include "mlir/IR/Attributes.h"
    39  #include "mlir/IR/Dialect.h"
    40  #include "mlir/IR/Operation.h"
    41  #include "llvm/Support/FormatVariadic.h"
    42  #include "llvm/Support/PrettyStackTrace.h"
    43  #include "llvm/Support/Regex.h"
    44  using namespace mlir;
    45  
    46  namespace {
    47  /// This class encapsulates all the state used to verify an operation region.
    48  class OperationVerifier {
    49  public:
    50    explicit OperationVerifier(MLIRContext *ctx)
    51        : ctx(ctx), identifierRegex("^[a-zA-Z_][a-zA-Z_0-9\\.\\$]*$") {}
    52  
    53    /// Verify the given operation.
    54    LogicalResult verify(Operation &op);
    55  
    56    /// Returns the registered dialect for a dialect-specific attribute.
    57    Dialect *getDialectForAttribute(const NamedAttribute &attr) {
    58      assert(attr.first.strref().contains('.') && "expected dialect attribute");
    59      auto dialectNamePair = attr.first.strref().split('.');
    60      return ctx->getRegisteredDialect(dialectNamePair.first);
    61    }
    62  
    63    /// Returns if the given string is valid to use as an identifier name.
    64    bool isValidName(StringRef name) { return identifierRegex.match(name); }
    65  
    66  private:
    67    /// Verify the given potentially nested region or block.
    68    LogicalResult verifyRegion(Region &region);
    69    LogicalResult verifyBlock(Block &block);
    70    LogicalResult verifyOperation(Operation &op);
    71  
    72    /// Verify the dominance within the given IR unit.
    73    LogicalResult verifyDominance(Region &region);
    74    LogicalResult verifyDominance(Operation &op);
    75  
    76    /// Emit an error for the given block.
    77    InFlightDiagnostic emitError(Block &bb, const Twine &message) {
    78      // Take the location information for the first operation in the block.
    79      if (!bb.empty())
    80        return bb.front().emitError(message);
    81  
    82      // Worst case, fall back to using the parent's location.
    83      return mlir::emitError(bb.getParent()->getLoc(), message);
    84    }
    85  
    86    /// The current context for the verifier.
    87    MLIRContext *ctx;
    88  
    89    /// Dominance information for this operation, when checking dominance.
    90    DominanceInfo *domInfo = nullptr;
    91  
    92    /// Regex checker for attribute names.
    93    llvm::Regex identifierRegex;
    94  
    95    /// Mapping between dialect namespace and if that dialect supports
    96    /// unregistered operations.
    97    llvm::StringMap<bool> dialectAllowsUnknownOps;
    98  };
    99  } // end anonymous namespace
   100  
   101  /// Verify the given operation.
   102  LogicalResult OperationVerifier::verify(Operation &op) {
   103    // Verify the operation first.
   104    if (failed(verifyOperation(op)))
   105      return failure();
   106  
   107    // Since everything looks structurally ok to this point, we do a dominance
   108    // check for any nested regions. We do this as a second pass since malformed
   109    // CFG's can cause dominator analysis constructure to crash and we want the
   110    // verifier to be resilient to malformed code.
   111    DominanceInfo theDomInfo(&op);
   112    domInfo = &theDomInfo;
   113    for (auto &region : op.getRegions())
   114      if (failed(verifyDominance(region)))
   115        return failure();
   116  
   117    domInfo = nullptr;
   118    return success();
   119  }
   120  
   121  LogicalResult OperationVerifier::verifyRegion(Region &region) {
   122    if (region.empty())
   123      return success();
   124  
   125    // Verify the first block has no predecessors.
   126    auto *firstBB = &region.front();
   127    if (!firstBB->hasNoPredecessors())
   128      return mlir::emitError(region.getLoc(),
   129                             "entry block of region may not have predecessors");
   130  
   131    // Verify each of the blocks within the region.
   132    for (auto &block : region)
   133      if (failed(verifyBlock(block)))
   134        return failure();
   135    return success();
   136  }
   137  
   138  LogicalResult OperationVerifier::verifyBlock(Block &block) {
   139    for (auto *arg : block.getArguments())
   140      if (arg->getOwner() != &block)
   141        return emitError(block, "block argument not owned by block");
   142  
   143    // Verify that this block has a terminator.
   144    if (block.empty())
   145      return emitError(block, "block with no terminator");
   146  
   147    // Verify the non-terminator operations separately so that we can verify
   148    // they has no successors.
   149    for (auto &op : llvm::make_range(block.begin(), std::prev(block.end()))) {
   150      if (op.getNumSuccessors() != 0)
   151        return op.emitError(
   152            "operation with block successors must terminate its parent block");
   153  
   154      if (failed(verifyOperation(op)))
   155        return failure();
   156    }
   157  
   158    // Verify the terminator.
   159    if (failed(verifyOperation(block.back())))
   160      return failure();
   161    if (block.back().isKnownNonTerminator())
   162      return emitError(block, "block with no terminator");
   163  
   164    // Verify that this block is not branching to a block of a different
   165    // region.
   166    for (Block *successor : block.getSuccessors())
   167      if (successor->getParent() != block.getParent())
   168        return block.back().emitOpError(
   169            "branching to block of a different region");
   170  
   171    return success();
   172  }
   173  
   174  LogicalResult OperationVerifier::verifyOperation(Operation &op) {
   175    // Check that operands are non-nil and structurally ok.
   176    for (auto *operand : op.getOperands())
   177      if (!operand)
   178        return op.emitError("null operand found");
   179  
   180    /// Verify that all of the attributes are okay.
   181    for (auto attr : op.getAttrs()) {
   182      if (!identifierRegex.match(attr.first))
   183        return op.emitError("invalid attribute name '") << attr.first << "'";
   184  
   185      // Check for any optional dialect specific attributes.
   186      if (!attr.first.strref().contains('.'))
   187        continue;
   188      if (auto *dialect = getDialectForAttribute(attr))
   189        if (failed(dialect->verifyOperationAttribute(&op, attr)))
   190          return failure();
   191    }
   192  
   193    // If we can get operation info for this, check the custom hook.
   194    auto *opInfo = op.getAbstractOperation();
   195    if (opInfo && failed(opInfo->verifyInvariants(&op)))
   196      return failure();
   197  
   198    // Verify that all child regions are ok.
   199    for (auto &region : op.getRegions())
   200      if (failed(verifyRegion(region)))
   201        return failure();
   202  
   203    // If this is a registered operation, there is nothing left to do.
   204    if (opInfo)
   205      return success();
   206  
   207    // Otherwise, verify that the parent dialect allows un-registered operations.
   208    auto dialectPrefix = op.getName().getDialect();
   209  
   210    // Check for an existing answer for the operation dialect.
   211    auto it = dialectAllowsUnknownOps.find(dialectPrefix);
   212    if (it == dialectAllowsUnknownOps.end()) {
   213      // If the operation dialect is registered, query it directly.
   214      if (auto *dialect = ctx->getRegisteredDialect(dialectPrefix))
   215        it = dialectAllowsUnknownOps
   216                 .try_emplace(dialectPrefix, dialect->allowsUnknownOperations())
   217                 .first;
   218      // Otherwise, conservatively allow unknown operations.
   219      else
   220        it = dialectAllowsUnknownOps.try_emplace(dialectPrefix, true).first;
   221    }
   222  
   223    if (!it->second) {
   224      return op.emitError("unregistered operation '")
   225             << op.getName() << "' found in dialect ('" << dialectPrefix
   226             << "') that does not allow unknown operations";
   227    }
   228  
   229    return success();
   230  }
   231  
   232  LogicalResult OperationVerifier::verifyDominance(Region &region) {
   233    // Verify the dominance of each of the held operations.
   234    for (auto &block : region)
   235      for (auto &op : block)
   236        if (failed(verifyDominance(op)))
   237          return failure();
   238    return success();
   239  }
   240  
   241  LogicalResult OperationVerifier::verifyDominance(Operation &op) {
   242    // Check that operands properly dominate this use.
   243    for (unsigned operandNo = 0, e = op.getNumOperands(); operandNo != e;
   244         ++operandNo) {
   245      auto *operand = op.getOperand(operandNo);
   246      if (domInfo->properlyDominates(operand, &op))
   247        continue;
   248  
   249      auto diag = op.emitError("operand #")
   250                  << operandNo << " does not dominate this use";
   251      if (auto *useOp = operand->getDefiningOp())
   252        diag.attachNote(useOp->getLoc()) << "operand defined here";
   253      return failure();
   254    }
   255  
   256    // Verify the dominance of each of the nested blocks within this operation.
   257    for (auto &region : op.getRegions())
   258      if (failed(verifyDominance(region)))
   259        return failure();
   260  
   261    return success();
   262  }
   263  
   264  //===----------------------------------------------------------------------===//
   265  // Entrypoint
   266  //===----------------------------------------------------------------------===//
   267  
   268  /// Perform (potentially expensive) checks of invariants, used to detect
   269  /// compiler bugs.  On error, this reports the error through the MLIRContext and
   270  /// returns failure.
   271  LogicalResult mlir::verify(Operation *op) {
   272    return OperationVerifier(op->getContext()).verify(*op);
   273  }