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(Name: "OpVariable" )) |
23 | def = def->getValueAsDef(FieldName: "constraint" ); |
24 | |
25 | if (def->isSubClassOf(Name: "TypeConstraint" )) { |
26 | kind = CK_Type; |
27 | } else if (def->isSubClassOf(Name: "AttrConstraint" )) { |
28 | kind = CK_Attr; |
29 | } else if (def->isSubClassOf(Name: "RegionConstraint" )) { |
30 | kind = CK_Region; |
31 | } else if (def->isSubClassOf(Name: "SuccessorConstraint" )) { |
32 | kind = CK_Successor; |
33 | } else if(!def->isSubClassOf(Name: "Constraint" )) { |
34 | llvm::errs() << "Expected a constraint but got: \n" << *def << "\n" ; |
35 | llvm::report_fatal_error(reason: "Abort" ); |
36 | } |
37 | } |
38 | |
39 | Pred Constraint::getPredicate() const { |
40 | auto *val = def->getValue(Name: "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: 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(FieldName: "summary" )) |
58 | return *summary; |
59 | return def->getName(); |
60 | } |
61 | |
62 | StringRef Constraint::getDescription() const { |
63 | return def->getValueAsOptionalString(FieldName: "description" ).value_or(u: "" ); |
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(Name: baseName)) { |
92 | if (const auto *defInit = dyn_cast<llvm::DefInit>(Val: 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 | AppliedConstraint::AppliedConstraint(Constraint &&constraint, |
113 | llvm::StringRef self, |
114 | std::vector<std::string> &&entities) |
115 | : constraint(constraint), self(std::string(self)), |
116 | entities(std::move(entities)) {} |
117 | |
118 | Constraint DenseMapInfo<Constraint>::getEmptyKey() { |
119 | return Constraint(RecordDenseMapInfo::getEmptyKey(), |
120 | Constraint::CK_Uncategorized); |
121 | } |
122 | |
123 | Constraint DenseMapInfo<Constraint>::getTombstoneKey() { |
124 | return Constraint(RecordDenseMapInfo::getTombstoneKey(), |
125 | Constraint::CK_Uncategorized); |
126 | } |
127 | |
128 | unsigned DenseMapInfo<Constraint>::getHashValue(Constraint constraint) { |
129 | if (constraint == getEmptyKey()) |
130 | return RecordDenseMapInfo::getHashValue(PtrVal: RecordDenseMapInfo::getEmptyKey()); |
131 | if (constraint == getTombstoneKey()) { |
132 | return RecordDenseMapInfo::getHashValue( |
133 | PtrVal: RecordDenseMapInfo::getTombstoneKey()); |
134 | } |
135 | return llvm::hash_combine(args: constraint.getPredicate(), args: constraint.getSummary()); |
136 | } |
137 | |
138 | bool DenseMapInfo<Constraint>::isEqual(Constraint lhs, Constraint rhs) { |
139 | if (lhs == rhs) |
140 | return true; |
141 | if (lhs == getEmptyKey() || lhs == getTombstoneKey()) |
142 | return false; |
143 | if (rhs == getEmptyKey() || rhs == getTombstoneKey()) |
144 | return false; |
145 | return lhs.getPredicate() == rhs.getPredicate() && |
146 | lhs.getSummary() == rhs.getSummary(); |
147 | } |
148 | |