CIRCT 22.0.0git
Loading...
Searching...
No Matches
RTGAttributes.cpp
Go to the documentation of this file.
1//===- RTGAttributes.cpp --------------------------------------------------===//
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
11#include "mlir/IR/Builders.h"
12#include "mlir/IR/DialectImplementation.h"
13#include "llvm/ADT/TypeSwitch.h"
14
15using namespace circt;
16using namespace rtg;
17
18//===----------------------------------------------------------------------===//
19// Helpers
20//===----------------------------------------------------------------------===//
21
22namespace llvm {
23template <typename T>
24// NOLINTNEXTLINE(readability-identifier-naming)
25llvm::hash_code hash_value(const DenseSet<T> &set) {
26 // TODO: improve collision resistance
27 unsigned hash = 0;
28 for (auto element : set)
29 hash ^= element;
30 return hash;
31}
32} // namespace llvm
33
34//===----------------------------------------------------------------------===//
35// SetAttr
36//===----------------------------------------------------------------------===//
37
38LogicalResult
39SetAttr::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
40 rtg::SetType type, const DenseSet<TypedAttr> *elements) {
41
42 // check that all elements have the right type
43 // iterating over the set is fine here because the iteration order is not
44 // visible to the outside (it would not be fine to print the earliest invalid
45 // element)
46 if (!llvm::all_of(*elements, [&](auto element) {
47 return element.getType() == type.getElementType();
48 })) {
49 return emitError() << "all elements must be of the set element type "
50 << type.getElementType();
51 }
52
53 return success();
54}
55
56Attribute SetAttr::parse(AsmParser &odsParser, Type odsType) {
57 DenseSet<TypedAttr> elements;
58 Type elementType;
59 if (odsParser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
60 [&]() {
61 TypedAttr element;
62 if (odsParser.parseAttribute(element))
63 return failure();
64 elements.insert(element);
65 elementType = element.getType();
66 return success();
67 }))
68 return {};
69
70 auto setType = llvm::dyn_cast_or_null<SetType>(odsType);
71 if (odsType && !setType) {
72 odsParser.emitError(odsParser.getNameLoc())
73 << "type must be a an '!rtg.set' type";
74 return {};
75 }
76
77 if (!setType && elements.empty()) {
78 odsParser.emitError(odsParser.getNameLoc())
79 << "type must be explicitly provided: cannot infer set element type "
80 "from empty set";
81 return {};
82 }
83
84 if (!setType && !elements.empty())
85 setType = SetType::get(elementType);
86
87 return SetAttr::getChecked(
88 odsParser.getEncodedSourceLoc(odsParser.getNameLoc()),
89 odsParser.getContext(), setType, &elements);
90}
91
92void SetAttr::print(AsmPrinter &odsPrinter) const {
93 odsPrinter << "<";
94 // Sort elements lexicographically by their printed string representation
95 SmallVector<std::string> sortedElements;
96 for (auto element : *getElements()) {
97 std::string &elementStr = sortedElements.emplace_back();
98 llvm::raw_string_ostream elementOS(elementStr);
99 element.print(elementOS);
100 }
101 llvm::sort(sortedElements);
102 llvm::interleaveComma(sortedElements, odsPrinter);
103 odsPrinter << ">";
104}
105
106//===----------------------------------------------------------------------===//
107// TupleAttr
108//===----------------------------------------------------------------------===//
109
110Type TupleAttr::getType() const {
111 SmallVector<Type> elementTypes(llvm::map_range(
112 getElements(), [](auto element) { return element.getType(); }));
113 return TupleType::get(getContext(), elementTypes);
114}
115
116//===----------------------------------------------------------------------===//
117// ImmediateAttr
118//===----------------------------------------------------------------------===//
119
120namespace circt {
121namespace rtg {
122namespace detail {
123struct ImmediateAttrStorage : public mlir::AttributeStorage {
124 using KeyTy = APInt;
125 ImmediateAttrStorage(APInt value) : value(std::move(value)) {}
126
127 KeyTy getAsKey() const { return value; }
128
129 // NOTE: the implementation of this operator is the reason we need to define
130 // the storage manually. The auto-generated version would just do the direct
131 // equality check of the APInt, but that asserts the bitwidth of both to be
132 // the same, leading to a crash. This implementation, therefore, checks for
133 // matching bit-width beforehand.
134 bool operator==(const KeyTy &key) const {
135 return (value.getBitWidth() == key.getBitWidth() && value == key);
136 }
137
138 static llvm::hash_code hashKey(const KeyTy &key) {
139 return llvm::hash_value(key);
140 }
141
142 static ImmediateAttrStorage *
143 construct(mlir::AttributeStorageAllocator &allocator, KeyTy &&key) {
144 return new (allocator.allocate<ImmediateAttrStorage>())
145 ImmediateAttrStorage(std::move(key));
146 }
147
148 APInt value;
149};
150} // namespace detail
151} // namespace rtg
152} // namespace circt
153
154Type ImmediateAttr::getType() const {
155 return ImmediateType::get(getContext(), getValue().getBitWidth());
156}
157
158APInt ImmediateAttr::getValue() const { return getImpl()->value; }
159
160Attribute ImmediateAttr::parse(AsmParser &odsParser, Type odsType) {
161 llvm::SMLoc loc = odsParser.getCurrentLocation();
162
163 APInt val;
164 uint32_t width; // NOTE: this integer type should match the 'width' parameter
165 // type in immediate type.
166 if (odsParser.parseLess() || odsParser.parseInteger(width) ||
167 odsParser.parseComma() || odsParser.parseInteger(val) ||
168 odsParser.parseGreater())
169 return {};
170
171 // If the attribute type is explicitly given, check that the bit-widths match.
172 if (auto immTy = llvm::dyn_cast_or_null<ImmediateType>(odsType)) {
173 if (immTy.getWidth() != width) {
174 odsParser.emitError(loc) << "explicit immediate type bit-width does not "
175 "match attribute bit-width, "
176 << immTy.getWidth() << " vs " << width;
177 return {};
178 }
179 }
180
181 if (width > val.getBitWidth()) {
182 // sext is always safe here, even for unsigned values, because the
183 // parseOptionalInteger method will return something with a zero in the
184 // top bits if it is a positive number.
185 val = val.sext(width);
186 } else if (width < val.getBitWidth()) {
187 // The parser can return an unnecessarily wide result.
188 // This isn't a problem, but truncating off bits is bad.
189 unsigned neededBits =
190 val.isNegative() ? val.getSignificantBits() : val.getActiveBits();
191 if (width < neededBits) {
192 odsParser.emitError(loc)
193 << "integer value out-of-range for bit-width " << width;
194 return {};
195 }
196 val = val.trunc(width);
197 }
198
199 return ImmediateAttr::get(odsParser.getContext(), val);
200}
201
202void ImmediateAttr::print(AsmPrinter &odsPrinter) const {
203 odsPrinter << "<" << getValue().getBitWidth() << ", " << getValue() << ">";
204}
205
206Type VirtualRegisterConfigAttr::getType() const {
207 return getAllowedRegs()[0].getType();
208}
209
210LogicalResult VirtualRegisterConfigAttr::verify(
211 llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
212 ArrayRef<rtg::RegisterAttrInterface> allowedRegs) {
213 if (allowedRegs.empty())
214 return emitError() << "must have at least one allowed register";
215
216 if (!llvm::all_of(allowedRegs, [&](auto reg) {
217 return reg.getType() == allowedRegs[0].getType();
218 })) {
219 return emitError() << "all allowed registers must be of the same type";
220 }
221
222 return success();
223}
224
225//===----------------------------------------------------------------------===//
226// TableGen generated logic.
227//===----------------------------------------------------------------------===//
228
229void RTGDialect::registerAttributes() {
230 addAttributes<
231#define GET_ATTRDEF_LIST
232#include "circt/Dialect/RTG/IR/RTGAttributes.cpp.inc"
233 >();
234}
235
236#define GET_ATTRDEF_CLASSES
237#include "circt/Dialect/RTG/IR/RTGAttributes.cpp.inc"
MlirType elementType
Definition CHIRRTL.cpp:29
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Definition HWTypes.cpp:110
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::hash_code hash_value(const DenseSet< T > &set)
Definition rtg.py:1
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21
static llvm::hash_code hashKey(const KeyTy &key)
bool operator==(const KeyTy &key) const
static ImmediateAttrStorage * construct(mlir::AttributeStorageAllocator &allocator, KeyTy &&key)