blob: ffc87aa0db85fb614bf0223c8be50be1ed24409e [file] [log] [blame]
Chris Lattner21e67f62018-07-06 10:46:19 -07001//===- 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 instruction from an instruction before
27// re-inserting it in a new place), but each transformation must complete with
28// the IR in a valid form.
29//
30// This should not check for things that are always wrong by construction (e.g.
31// affine maps 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/IR/CFGFunction.h"
37#include "mlir/IR/MLFunction.h"
38#include "mlir/IR/Module.h"
39#include "mlir/IR/OperationSet.h"
40#include "llvm/ADT/Twine.h"
41#include "llvm/Support/raw_ostream.h"
42using namespace mlir;
43
44template <typename T>
45static void failure(const Twine &message, const T &value) {
46 // Print the error message and flush the stream in case printing the value
47 // causes a crash.
48 llvm::errs() << "MLIR verification failure: " << message << "\n";
49 llvm::errs().flush();
50 value.dump();
51}
52
53//===----------------------------------------------------------------------===//
54// CFG Functions
55//===----------------------------------------------------------------------===//
56
57namespace {
58class CFGFuncVerifier {
59public:
60 const CFGFunction &fn;
61 OperationSet &operationSet;
62
63 CFGFuncVerifier(const CFGFunction &fn)
64 : fn(fn), operationSet(OperationSet::get(fn.getContext())) {}
65
66 void verify();
67 void verifyBlock(const BasicBlock &block);
68 void verifyTerminator(const TerminatorInst &term);
69 void verifyOperation(const OperationInst &inst);
70};
71} // end anonymous namespace
72
73void CFGFuncVerifier::verify() {
74 // TODO: Lots to be done here, including verifying dominance information when
75 // we have uses and defs.
76
77 for (auto &block : fn) {
78 verifyBlock(block);
79 }
80}
81
82void CFGFuncVerifier::verifyBlock(const BasicBlock &block) {
83 if (!block.getTerminator())
84 failure("basic block with no terminator", block);
85 verifyTerminator(*block.getTerminator());
86
87 for (auto &inst : block) {
88 verifyOperation(inst);
89 }
90}
91
92void CFGFuncVerifier::verifyTerminator(const TerminatorInst &term) {
93 if (term.getFunction() != &fn)
94 failure("terminator in the wrong function", term);
95
96 // TODO: Check that operands are structurally ok.
97 // TODO: Check that successors are in the right function.
98}
99
100void CFGFuncVerifier::verifyOperation(const OperationInst &inst) {
101 if (inst.getFunction() != &fn)
102 failure("operation in the wrong function", inst);
103
104 // TODO: Check that operands are structurally ok.
105
106 // See if we can get operation info for this.
107 if (auto *opInfo = inst.getAbstractOperation(fn.getContext())) {
108 if (auto errorMessage = opInfo->verifyInvariants(&inst))
109 failure(errorMessage, inst);
110 }
111}
112
113//===----------------------------------------------------------------------===//
114// ML Functions
115//===----------------------------------------------------------------------===//
116
117namespace {
118class MLFuncVerifier {
119public:
120 const MLFunction &fn;
121
122 MLFuncVerifier(const MLFunction &fn) : fn(fn) {}
123
124 void verify() {
125 // TODO.
126 }
127};
128} // end anonymous namespace
129
130//===----------------------------------------------------------------------===//
131// Entrypoints
132//===----------------------------------------------------------------------===//
133
134/// Perform (potentially expensive) checks of invariants, used to detect
135/// compiler bugs. This aborts on failure.
136void Function::verify() const {
137 switch (getKind()) {
138 case Kind::ExtFunc:
139 // No body, nothing can be wrong here.
140 break;
141 case Kind::CFGFunc:
142 return CFGFuncVerifier(*cast<CFGFunction>(this)).verify();
143 case Kind::MLFunc:
144 return MLFuncVerifier(*cast<MLFunction>(this)).verify();
145 }
146}
147
148/// Perform (potentially expensive) checks of invariants, used to detect
149/// compiler bugs. This aborts on failure.
150void Module::verify() const {
151 /// Check that each function is correct.
152 for (auto fn : functionList) {
153 fn->verify();
154 }
155}