xref: /llvm-project/mlir/lib/TableGen/Constraint.cpp (revision a3d41879ecf5690a73f9226951d3856c7faa34a4)
1 //===- Constraint.cpp - Constraint class ----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Constraint wrapper to simplify using TableGen Record for constraints.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/TableGen/Constraint.h"
14 #include "llvm/TableGen/Record.h"
15 
16 using namespace mlir;
17 using namespace mlir::tblgen;
18 
19 Constraint::Constraint(const llvm::Record *record)
20     : Constraint(record, CK_Uncategorized) {
21   // Look through OpVariable's to their constraint.
22   if (def->isSubClassOf("OpVariable"))
23     def = def->getValueAsDef("constraint");
24 
25   if (def->isSubClassOf("TypeConstraint")) {
26     kind = CK_Type;
27   } else if (def->isSubClassOf("AttrConstraint")) {
28     kind = CK_Attr;
29   } else if (def->isSubClassOf("RegionConstraint")) {
30     kind = CK_Region;
31   } else if (def->isSubClassOf("SuccessorConstraint")) {
32     kind = CK_Successor;
33   } else if (!def->isSubClassOf("Constraint")) {
34     llvm::errs() << "Expected a constraint but got: \n" << *def << "\n";
35     llvm::report_fatal_error("Abort");
36   }
37 }
38 
39 Pred Constraint::getPredicate() const {
40   auto *val = def->getValue("predicate");
41 
42   // If no predicate is specified, then return the null predicate (which
43   // corresponds to true).
44   if (!val)
45     return Pred();
46 
47   const auto *pred = dyn_cast<llvm::DefInit>(val->getValue());
48   return Pred(pred);
49 }
50 
51 std::string Constraint::getConditionTemplate() const {
52   return getPredicate().getCondition();
53 }
54 
55 StringRef Constraint::getSummary() const {
56   if (std::optional<StringRef> summary =
57           def->getValueAsOptionalString("summary"))
58     return *summary;
59   return def->getName();
60 }
61 
62 StringRef Constraint::getDescription() const {
63   return def->getValueAsOptionalString("description").value_or("");
64 }
65 
66 StringRef Constraint::getDefName() const {
67   if (std::optional<StringRef> baseDefName = getBaseDefName())
68     return *baseDefName;
69   return def->getName();
70 }
71 
72 std::string Constraint::getUniqueDefName() const {
73   std::string defName = def->getName().str();
74 
75   // Non-anonymous classes already have a unique name from the def.
76   if (!def->isAnonymous())
77     return defName;
78 
79   // Otherwise, this is an anonymous class. In these cases we still use the def
80   // name, but we also try attach the name of the base def when present to make
81   // the name more obvious.
82   if (std::optional<StringRef> baseDefName = getBaseDefName())
83     return (*baseDefName + "(" + defName + ")").str();
84   return defName;
85 }
86 
87 std::optional<StringRef> Constraint::getBaseDefName() const {
88   // Functor used to check a base def in the case where the current def is
89   // anonymous.
90   auto checkBaseDefFn = [&](StringRef baseName) -> std::optional<StringRef> {
91     if (const auto *defValue = def->getValue(baseName)) {
92       if (const auto *defInit = dyn_cast<llvm::DefInit>(defValue->getValue()))
93         return Constraint(defInit->getDef(), kind).getDefName();
94     }
95     return std::nullopt;
96   };
97 
98   switch (kind) {
99   case CK_Attr:
100     if (def->isAnonymous())
101       return checkBaseDefFn("baseAttr");
102     return std::nullopt;
103   case CK_Type:
104     if (def->isAnonymous())
105       return checkBaseDefFn("baseType");
106     return std::nullopt;
107   default:
108     return std::nullopt;
109   }
110 }
111 
112 std::optional<StringRef> Constraint::getCppFunctionName() const {
113   std::optional<StringRef> name =
114       def->getValueAsOptionalString("cppFunctionName");
115   if (!name || *name == "")
116     return std::nullopt;
117   return name;
118 }
119 
120 AppliedConstraint::AppliedConstraint(Constraint &&constraint,
121                                      llvm::StringRef self,
122                                      std::vector<std::string> &&entities)
123     : constraint(constraint), self(std::string(self)),
124       entities(std::move(entities)) {}
125 
126 Constraint DenseMapInfo<Constraint>::getEmptyKey() {
127   return Constraint(RecordDenseMapInfo::getEmptyKey(),
128                     Constraint::CK_Uncategorized);
129 }
130 
131 Constraint DenseMapInfo<Constraint>::getTombstoneKey() {
132   return Constraint(RecordDenseMapInfo::getTombstoneKey(),
133                     Constraint::CK_Uncategorized);
134 }
135 
136 unsigned DenseMapInfo<Constraint>::getHashValue(Constraint constraint) {
137   if (constraint == getEmptyKey())
138     return RecordDenseMapInfo::getHashValue(RecordDenseMapInfo::getEmptyKey());
139   if (constraint == getTombstoneKey()) {
140     return RecordDenseMapInfo::getHashValue(
141         RecordDenseMapInfo::getTombstoneKey());
142   }
143   return llvm::hash_combine(constraint.getPredicate(), constraint.getSummary());
144 }
145 
146 bool DenseMapInfo<Constraint>::isEqual(Constraint lhs, Constraint rhs) {
147   if (lhs == rhs)
148     return true;
149   if (lhs == getEmptyKey() || lhs == getTombstoneKey())
150     return false;
151   if (rhs == getEmptyKey() || rhs == getTombstoneKey())
152     return false;
153   return lhs.getPredicate() == rhs.getPredicate() &&
154          lhs.getSummary() == rhs.getSummary();
155 }
156