1 //===- Predicate.cpp - Predicate class ------------------------------------===//
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 // Wrapper around predicates defined in TableGen.
19 //
20 //===----------------------------------------------------------------------===//
21 
22 #include "mlir/TableGen/Predicate.h"
23 #include "llvm/ADT/SetVector.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/FormatVariadic.h"
26 #include "llvm/TableGen/Error.h"
27 #include "llvm/TableGen/Record.h"
28 
29 using namespace mlir;
30 
31 tblgen::PredCNF::PredCNF(const llvm::Init *init) : def(nullptr) {
32   if (const auto *defInit = dyn_cast<llvm::DefInit>(init)) {
33     def = defInit->getDef();
34     assert(def->isSubClassOf("PredCNF") &&
35            "must be subclass of TableGen 'PredCNF' class");
36   }
37 }
38 
39 const llvm::ListInit *tblgen::PredCNF::getConditions() const {
40   if (!def)
41     return nullptr;
42 
43   return def->getValueAsListInit("conditions");
44 }
45 
46 std::string
47 tblgen::PredCNF::createTypeMatcherTemplate(PredCNF predsKnownToHold) const {
48   const auto *conjunctiveList = getConditions();
49   if (!conjunctiveList)
50     return "true";
51 
52   // Create a set of all the disjunctive conditions that hold. This is taking
53   // advantage of uniquieing of lists to discard based on the pointer
54   // below. This is not perfect but this will also be moved to FSM matching in
55   // future and gets rid of trivial redundant checking.
56   llvm::SmallSetVector<const llvm::Init *, 4> existingConditions;
57   auto existingList = predsKnownToHold.getConditions();
58   if (existingList) {
59     for (auto disjunctiveInit : *existingList)
60       existingConditions.insert(disjunctiveInit);
61   }
62 
63   std::string outString;
64   llvm::raw_string_ostream ss(outString);
65   bool firstDisjunctive = true;
66   for (auto disjunctiveInit : *conjunctiveList) {
67     if (existingConditions.count(disjunctiveInit) != 0)
68       continue;
69     ss << (firstDisjunctive ? "(" : " && (");
70     firstDisjunctive = false;
71     bool firstConjunctive = true;
72     for (auto atom : *cast<llvm::ListInit>(disjunctiveInit)) {
73       auto predAtom = cast<llvm::DefInit>(atom)->getDef();
74       ss << (firstConjunctive ? "" : " || ")
75          << (predAtom->getValueAsBit("negated") ? "!" : "")
76          << predAtom->getValueAsString("predCall");
77       firstConjunctive = false;
78     }
79     ss << ")";
80   }
81   if (firstDisjunctive)
82     return "true";
83   ss.flush();
84   return outString;
85 }
86