Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OMOps.cpp
Go to the documentation of this file.
1//===- OMOps.cpp - Object Model operation definitions ---------------------===//
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// This file contains the Object Model operation definitions.
10//
11//===----------------------------------------------------------------------===//
12
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/ImplicitLocOpBuilder.h"
18
19using namespace mlir;
20using namespace circt::om;
21
22//===----------------------------------------------------------------------===//
23// Custom Printers and Parsers
24//===----------------------------------------------------------------------===//
25
26static ParseResult parseBasePathString(OpAsmParser &parser, PathAttr &path) {
27 auto *context = parser.getContext();
28 auto loc = parser.getCurrentLocation();
29 std::string rawPath;
30 if (parser.parseString(&rawPath))
31 return failure();
32 if (parseBasePath(context, rawPath, path))
33 return parser.emitError(loc, "invalid base path");
34 return success();
35}
36
37static void printBasePathString(OpAsmPrinter &p, Operation *op, PathAttr path) {
38 p << '\"';
39 llvm::interleave(
40 path, p,
41 [&](const PathElement &elt) {
42 p << elt.module.getValue() << '/' << elt.instance.getValue();
43 },
44 ":");
45 p << '\"';
46}
47
48static ParseResult parsePathString(OpAsmParser &parser, PathAttr &path,
49 StringAttr &module, StringAttr &ref,
50 StringAttr &field) {
51
52 auto *context = parser.getContext();
53 auto loc = parser.getCurrentLocation();
54 std::string rawPath;
55 if (parser.parseString(&rawPath))
56 return failure();
57 if (parsePath(context, rawPath, path, module, ref, field))
58 return parser.emitError(loc, "invalid path");
59 return success();
60}
61
62static void printPathString(OpAsmPrinter &p, Operation *op, PathAttr path,
63 StringAttr module, StringAttr ref,
64 StringAttr field) {
65 p << '\"';
66 for (const auto &elt : path)
67 p << elt.module.getValue() << '/' << elt.instance.getValue() << ':';
68 if (!module.getValue().empty())
69 p << module.getValue();
70 if (!ref.getValue().empty())
71 p << '>' << ref.getValue();
72 if (!field.getValue().empty())
73 p << field.getValue();
74 p << '\"';
75}
76
77static ParseResult parseFieldLocs(OpAsmParser &parser, ArrayAttr &fieldLocs) {
78 if (parser.parseOptionalKeyword("field_locs"))
79 return success();
80 if (parser.parseLParen() || parser.parseAttribute(fieldLocs) ||
81 parser.parseRParen()) {
82 return failure();
83 }
84 return success();
85}
86
87static void printFieldLocs(OpAsmPrinter &printer, Operation *op,
88 ArrayAttr fieldLocs) {
89 mlir::OpPrintingFlags flags;
90 if (!flags.shouldPrintDebugInfo() || !fieldLocs)
91 return;
92 printer << "field_locs(";
93 printer.printAttribute(fieldLocs);
94 printer << ")";
95}
96
97//===----------------------------------------------------------------------===//
98// Shared definitions
99//===----------------------------------------------------------------------===//
100static ParseResult parseClassFieldsList(OpAsmParser &parser,
101 SmallVectorImpl<Attribute> &fieldNames,
102 SmallVectorImpl<Type> &fieldTypes) {
103
104 llvm::StringMap<SMLoc> nameLocMap;
105 auto parseElt = [&]() -> ParseResult {
106 // Parse the field name.
107 std::string fieldName;
108 if (parser.parseKeywordOrString(&fieldName))
109 return failure();
110 SMLoc currLoc = parser.getCurrentLocation();
111 if (nameLocMap.count(fieldName)) {
112 parser.emitError(currLoc, "field \"")
113 << fieldName << "\" is defined twice";
114 parser.emitError(nameLocMap[fieldName]) << "previous definition is here";
115 return failure();
116 }
117 nameLocMap[fieldName] = currLoc;
118 fieldNames.push_back(StringAttr::get(parser.getContext(), fieldName));
119
120 // Parse the field type.
121 fieldTypes.emplace_back();
122 if (parser.parseColonType(fieldTypes.back()))
123 return failure();
124
125 return success();
126 };
127
128 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
129 parseElt);
130}
131
132static ParseResult parseClassLike(OpAsmParser &parser, OperationState &state) {
133 // Parse the Class symbol name.
134 StringAttr symName;
135 if (parser.parseSymbolName(symName, mlir::SymbolTable::getSymbolAttrName(),
136 state.attributes))
137 return failure();
138
139 // Parse the formal parameters.
140 SmallVector<OpAsmParser::Argument> args;
141 if (parser.parseArgumentList(args, OpAsmParser::Delimiter::Paren,
142 /*allowType=*/true, /*allowAttrs=*/false))
143 return failure();
144
145 SmallVector<Type> fieldTypes;
146 SmallVector<Attribute> fieldNames;
147 if (succeeded(parser.parseOptionalArrow()))
148 if (failed(parseClassFieldsList(parser, fieldNames, fieldTypes)))
149 return failure();
150
151 SmallVector<NamedAttribute> fieldTypesMap;
152 if (!fieldNames.empty()) {
153 for (auto [name, type] : zip(fieldNames, fieldTypes))
154 fieldTypesMap.push_back(
155 NamedAttribute(cast<StringAttr>(name), TypeAttr::get(type)));
156 }
157 auto *ctx = parser.getContext();
158 state.addAttribute("fieldNames", mlir::ArrayAttr::get(ctx, fieldNames));
159 state.addAttribute("fieldTypes",
160 mlir::DictionaryAttr::get(ctx, fieldTypesMap));
161
162 // Parse the optional attribute dictionary.
163 if (failed(parser.parseOptionalAttrDictWithKeyword(state.attributes)))
164 return failure();
165
166 // Parse the body.
167 Region *region = state.addRegion();
168 if (parser.parseRegion(*region, args))
169 return failure();
170
171 // If the region was empty, add an empty block so it's still a SizedRegion<1>.
172 if (region->empty())
173 region->emplaceBlock();
174
175 // Remember the formal parameter names in an attribute.
176 auto argNames = llvm::map_range(args, [&](OpAsmParser::Argument arg) {
177 return StringAttr::get(parser.getContext(), arg.ssaName.name.drop_front());
178 });
179 state.addAttribute(
180 "formalParamNames",
181 ArrayAttr::get(parser.getContext(), SmallVector<Attribute>(argNames)));
182
183 return success();
184}
185
186static void printClassLike(ClassLike classLike, OpAsmPrinter &printer) {
187 // Print the Class symbol name.
188 printer << " @";
189 printer << classLike.getSymName();
190
191 // Retrieve the formal parameter names and values.
192 auto argNames = SmallVector<StringRef>(
193 classLike.getFormalParamNames().getAsValueRange<StringAttr>());
194 ArrayRef<BlockArgument> args = classLike.getBodyBlock()->getArguments();
195
196 // Print the formal parameters.
197 printer << '(';
198 for (size_t i = 0, e = args.size(); i < e; ++i) {
199 printer << '%' << argNames[i] << ": " << args[i].getType();
200 if (i < e - 1)
201 printer << ", ";
202 }
203 printer << ") ";
204
205 ArrayRef<Attribute> fieldNames =
206 cast<ArrayAttr>(classLike->getAttr("fieldNames")).getValue();
207
208 if (!fieldNames.empty()) {
209 printer << " -> (";
210 for (size_t i = 0, e = fieldNames.size(); i < e; ++i) {
211 if (i != 0)
212 printer << ", ";
213 StringAttr name = cast<StringAttr>(fieldNames[i]);
214 printer.printKeywordOrString(name.getValue());
215 printer << ": ";
216 Type type = classLike.getFieldType(name).value();
217 printer.printType(type);
218 }
219 printer << ") ";
220 }
221
222 // Print the optional attribute dictionary.
223 SmallVector<StringRef> elidedAttrs{classLike.getSymNameAttrName(),
224 classLike.getFormalParamNamesAttrName(),
225 "fieldTypes", "fieldNames"};
226 printer.printOptionalAttrDictWithKeyword(classLike.getOperation()->getAttrs(),
227 elidedAttrs);
228
229 // Print the body.
230 printer.printRegion(classLike.getBody(), /*printEntryBlockArgs=*/false,
231 /*printBlockTerminators=*/true);
232}
233
234LogicalResult verifyClassLike(ClassLike classLike) {
235 // Verify the formal parameter names match up with the values.
236 if (classLike.getFormalParamNames().size() !=
237 classLike.getBodyBlock()->getArguments().size()) {
238 auto error = classLike.emitOpError(
239 "formal parameter name list doesn't match formal parameter value list");
240 error.attachNote(classLike.getLoc())
241 << "formal parameter names: " << classLike.getFormalParamNames();
242 error.attachNote(classLike.getLoc())
243 << "formal parameter values: "
244 << classLike.getBodyBlock()->getArguments();
245 return error;
246 }
247
248 return success();
249}
250
251void getClassLikeAsmBlockArgumentNames(ClassLike classLike, Region &region,
252 OpAsmSetValueNameFn setNameFn) {
253 // Retrieve the formal parameter names and values.
254 auto argNames = SmallVector<StringRef>(
255 classLike.getFormalParamNames().getAsValueRange<StringAttr>());
256 ArrayRef<BlockArgument> args = classLike.getBodyBlock()->getArguments();
257
258 // Use the formal parameter names as the SSA value names.
259 for (size_t i = 0, e = args.size(); i < e; ++i)
260 setNameFn(args[i], argNames[i]);
261}
262
263NamedAttribute makeFieldType(StringAttr name, Type type) {
264 return NamedAttribute(name, TypeAttr::get(type));
265}
266
267NamedAttribute makeFieldIdx(MLIRContext *ctx, mlir::StringAttr name,
268 unsigned i) {
269 return NamedAttribute(StringAttr(name),
270 mlir::IntegerAttr::get(mlir::IndexType::get(ctx), i));
271}
272
273std::optional<Type> getClassLikeFieldType(ClassLike classLike,
274 StringAttr name) {
275 DictionaryAttr fieldTypes = mlir::cast<DictionaryAttr>(
276 classLike.getOperation()->getAttr("fieldTypes"));
277 Attribute type = fieldTypes.get(name);
278 if (!type)
279 return std::nullopt;
280 return cast<TypeAttr>(type).getValue();
281}
282
283void replaceClassLikeFieldTypes(ClassLike classLike,
284 AttrTypeReplacer &replacer) {
285 classLike->setAttr("fieldTypes", cast<DictionaryAttr>(replacer.replace(
286 classLike.getFieldTypes())));
287}
288
289//===----------------------------------------------------------------------===//
290// ClassOp
291//===----------------------------------------------------------------------===//
292
293ParseResult circt::om::ClassOp::parse(OpAsmParser &parser,
294 OperationState &state) {
295 return parseClassLike(parser, state);
296}
297
298circt::om::ClassOp circt::om::ClassOp::buildSimpleClassOp(
299 OpBuilder &odsBuilder, Location loc, Twine name,
300 ArrayRef<StringRef> formalParamNames, ArrayRef<StringRef> fieldNames,
301 ArrayRef<Type> fieldTypes) {
302 circt::om::ClassOp classOp = odsBuilder.create<circt::om::ClassOp>(
303 loc, odsBuilder.getStringAttr(name),
304 odsBuilder.getStrArrayAttr(formalParamNames),
305 odsBuilder.getStrArrayAttr(fieldNames),
306 odsBuilder.getDictionaryAttr(llvm::map_to_vector(
307 llvm::zip(fieldNames, fieldTypes), [&](auto field) -> NamedAttribute {
308 return NamedAttribute(odsBuilder.getStringAttr(std::get<0>(field)),
309 TypeAttr::get(std::get<1>(field)));
310 })));
311 Block *body = &classOp.getRegion().emplaceBlock();
312 auto prevLoc = odsBuilder.saveInsertionPoint();
313 odsBuilder.setInsertionPointToEnd(body);
314
315 mlir::SmallVector<Attribute> locAttrs(fieldNames.size(), LocationAttr(loc));
316
317 odsBuilder.create<ClassFieldsOp>(
318 loc,
319 llvm::map_to_vector(
320 fieldTypes,
321 [&](Type type) -> Value { return body->addArgument(type, loc); }),
322 odsBuilder.getArrayAttr(locAttrs));
323
324 odsBuilder.restoreInsertionPoint(prevLoc);
325
326 return classOp;
327}
328
329void circt::om::ClassOp::print(OpAsmPrinter &printer) {
330 printClassLike(*this, printer);
331}
332
333LogicalResult circt::om::ClassOp::verify() { return verifyClassLike(*this); }
334
335LogicalResult circt::om::ClassOp::verifyRegions() {
336 auto fieldsOp = cast<ClassFieldsOp>(this->getBodyBlock()->getTerminator());
337
338 // The number of results matches the number of terminator operands.
339 if (fieldsOp.getNumOperands() != this->getFieldNames().size()) {
340 auto diag = this->emitOpError()
341 << "returns '" << this->getFieldNames().size()
342 << "' fields, but its terminator returned '"
343 << fieldsOp.getNumOperands() << "' fields";
344 return diag.attachNote(fieldsOp.getLoc()) << "see terminator:";
345 }
346
347 // The type of each result matches the corresponding terminator operand type.
348 auto types = this->getFieldTypes();
349 for (auto [fieldName, terminatorOperandType] :
350 llvm::zip(this->getFieldNames(), fieldsOp.getOperandTypes())) {
351
352 if (terminatorOperandType ==
353 cast<TypeAttr>(types.get(cast<StringAttr>(fieldName))).getValue())
354 continue;
355
356 auto diag = this->emitOpError()
357 << "returns different field types than its terminator";
358 return diag.attachNote(fieldsOp.getLoc()) << "see terminator:";
359 }
360
361 return success();
362}
363
364void circt::om::ClassOp::getAsmBlockArgumentNames(
365 Region &region, OpAsmSetValueNameFn setNameFn) {
366 getClassLikeAsmBlockArgumentNames(*this, region, setNameFn);
367}
368
369std::optional<mlir::Type>
370circt::om::ClassOp::getFieldType(mlir::StringAttr field) {
371 return getClassLikeFieldType(*this, field);
372}
373
374void circt::om::ClassOp::replaceFieldTypes(AttrTypeReplacer replacer) {
375 replaceClassLikeFieldTypes(*this, replacer);
376}
377
378void circt::om::ClassOp::updateFields(
379 mlir::ArrayRef<mlir::Location> newLocations,
380 mlir::ArrayRef<mlir::Value> newValues,
381 mlir::ArrayRef<mlir::Attribute> newNames) {
382
383 auto fieldsOp = getFieldsOp();
384 assert(fieldsOp && "The fields op should exist");
385 // Get field names.
386 SmallVector<Attribute> names(getFieldNamesAttr().getAsRange<StringAttr>());
387 // Get the field types.
388 SmallVector<NamedAttribute> fieldTypes(getFieldTypesAttr().getValue());
389 // Get the field values.
390 SmallVector<Value> fieldVals(fieldsOp.getFields());
391 // Get the field locations.
392 Location fieldOpLoc = fieldsOp->getLoc();
393
394 // Extract the locations per field.
395 SmallVector<Location> locations;
396 if (auto fl = dyn_cast<FusedLoc>(fieldOpLoc)) {
397 auto metadataArr = dyn_cast<ArrayAttr>(fl.getMetadata());
398 assert(metadataArr && "Expected the metadata for the fused location");
399 auto r = metadataArr.getAsRange<LocationAttr>();
400 locations.append(r.begin(), r.end());
401 } else {
402 // Assume same loc for every field.
403 locations.append(names.size(), fieldOpLoc);
404 }
405
406 // Append the new names, locations and values.
407 names.append(newNames.begin(), newNames.end());
408 locations.append(newLocations.begin(), newLocations.end());
409 fieldVals.append(newValues.begin(), newValues.end());
410
411 // Construct the new field types from values and names.
412 for (auto [v, n] : llvm::zip(newValues, newNames))
413 fieldTypes.emplace_back(
414 NamedAttribute(llvm::cast<StringAttr>(n), TypeAttr::get(v.getType())));
415
416 // Keep the locations as array on the metadata.
417 SmallVector<Attribute> locationsAttr;
418 llvm::for_each(locations, [&](Location &l) {
419 locationsAttr.push_back(cast<Attribute>(l));
420 });
421
422 ImplicitLocOpBuilder builder(getLoc(), *this);
423 // Update the field names attribute.
424 setFieldNamesAttr(builder.getArrayAttr(names));
425 // Update the fields type attribute.
426 setFieldTypesAttr(builder.getDictionaryAttr(fieldTypes));
427 fieldsOp.getFieldsMutable().assign(fieldVals);
428 // Update the location.
429 fieldsOp->setLoc(builder.getFusedLoc(
430 locations, ArrayAttr::get(getContext(), locationsAttr)));
431}
432
433void circt::om::ClassOp::addNewFieldsOp(mlir::OpBuilder &builder,
434 mlir::ArrayRef<Location> locs,
435 mlir::ArrayRef<Value> values) {
436 // Store the original locations as a metadata array so that unique locations
437 // are preserved as a mapping from field index to location
438 assert(locs.size() == values.size() && "Expected a location per value");
439 mlir::SmallVector<Attribute> locAttrs;
440 for (auto loc : locs) {
441 locAttrs.push_back(cast<Attribute>(LocationAttr(loc)));
442 }
443 // Also store the locations incase there's some other analysis that might
444 // be able to use the default FusedLoc representation.
445 builder.create<ClassFieldsOp>(builder.getFusedLoc(locs), values,
446 builder.getArrayAttr(locAttrs));
447}
448
449mlir::Location circt::om::ClassOp::getFieldLocByIndex(size_t i) {
450 auto fieldsOp = this->getFieldsOp();
451 auto fieldLocs = fieldsOp.getFieldLocs();
452 if (!fieldLocs.has_value())
453 return fieldsOp.getLoc();
454 assert(i < fieldLocs.value().size() &&
455 "field index too large for location array");
456 return cast<LocationAttr>(fieldLocs.value()[i]);
457}
458
459//===----------------------------------------------------------------------===//
460// ClassExternOp
461//===----------------------------------------------------------------------===//
462
463ParseResult circt::om::ClassExternOp::parse(OpAsmParser &parser,
464 OperationState &state) {
465 return parseClassLike(parser, state);
466}
467
468void circt::om::ClassExternOp::print(OpAsmPrinter &printer) {
469 printClassLike(*this, printer);
470}
471
472LogicalResult circt::om::ClassExternOp::verify() {
473 if (failed(verifyClassLike(*this))) {
474 return failure();
475 }
476 // Verify body is empty
477 if (!this->getBodyBlock()->getOperations().empty()) {
478 return this->emitOpError("external class body should be empty");
479 }
480
481 return success();
482}
483
484void circt::om::ClassExternOp::getAsmBlockArgumentNames(
485 Region &region, OpAsmSetValueNameFn setNameFn) {
486 getClassLikeAsmBlockArgumentNames(*this, region, setNameFn);
487}
488
489std::optional<mlir::Type>
490circt::om::ClassExternOp::getFieldType(mlir::StringAttr field) {
491 return getClassLikeFieldType(*this, field);
492}
493
494void circt::om::ClassExternOp::replaceFieldTypes(AttrTypeReplacer replacer) {
495 replaceClassLikeFieldTypes(*this, replacer);
496}
497
498//===----------------------------------------------------------------------===//
499// ClassFieldsOp
500//===----------------------------------------------------------------------===//
501//
502LogicalResult circt::om::ClassFieldsOp::verify() {
503 auto fieldLocs = this->getFieldLocs();
504 if (fieldLocs.has_value()) {
505 auto fieldLocsVal = fieldLocs.value();
506 if (fieldLocsVal.size() != this->getFields().size()) {
507 auto error = this->emitOpError("size of field_locs (")
508 << fieldLocsVal.size()
509 << ") does not match number of fields ("
510 << this->getFields().size() << ")";
511 }
512 }
513 return success();
514}
515
516//===----------------------------------------------------------------------===//
517// ObjectOp
518//===----------------------------------------------------------------------===//
519
520void circt::om::ObjectOp::build(::mlir::OpBuilder &odsBuilder,
521 ::mlir::OperationState &odsState,
522 om::ClassOp classOp,
523 ::mlir::ValueRange actualParams) {
524 return build(odsBuilder, odsState,
525 om::ClassType::get(odsBuilder.getContext(),
526 mlir::FlatSymbolRefAttr::get(classOp)),
527 classOp.getNameAttr(), actualParams);
528}
529
530LogicalResult
531circt::om::ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
532 // Verify the result type is the same as the referred-to class.
533 StringAttr resultClassName = getResult().getType().getClassName().getAttr();
534 StringAttr className = getClassNameAttr();
535 if (resultClassName != className)
536 return emitOpError("result type (")
537 << resultClassName << ") does not match referred to class ("
538 << className << ')';
539
540 // Verify the referred to ClassOp exists.
541 auto classDef = dyn_cast_or_null<ClassLike>(
542 symbolTable.lookupNearestSymbolFrom(*this, className));
543 if (!classDef)
544 return emitOpError("refers to non-existant class (") << className << ')';
545
546 auto actualTypes = getActualParams().getTypes();
547 auto formalTypes = classDef.getBodyBlock()->getArgumentTypes();
548
549 // Verify the actual parameter list matches the formal parameter list.
550 if (actualTypes.size() != formalTypes.size()) {
551 auto error = emitOpError(
552 "actual parameter list doesn't match formal parameter list");
553 error.attachNote(classDef.getLoc())
554 << "formal parameters: " << classDef.getBodyBlock()->getArguments();
555 error.attachNote(getLoc()) << "actual parameters: " << getActualParams();
556 return error;
557 }
558
559 // Verify the actual parameter types match the formal parameter types.
560 for (size_t i = 0, e = actualTypes.size(); i < e; ++i) {
561 if (actualTypes[i] != formalTypes[i]) {
562 return emitOpError("actual parameter type (")
563 << actualTypes[i] << ") doesn't match formal parameter type ("
564 << formalTypes[i] << ')';
565 }
566 }
567
568 return success();
569}
570
571//===----------------------------------------------------------------------===//
572// ConstantOp
573//===----------------------------------------------------------------------===//
574
575void circt::om::ConstantOp::build(::mlir::OpBuilder &odsBuilder,
576 ::mlir::OperationState &odsState,
577 ::mlir::TypedAttr constVal) {
578 return build(odsBuilder, odsState, constVal.getType(), constVal);
579}
580
581OpFoldResult circt::om::ConstantOp::fold(FoldAdaptor adaptor) {
582 assert(adaptor.getOperands().empty() && "constant has no operands");
583 return getValueAttr();
584}
585
586//===----------------------------------------------------------------------===//
587// ListCreateOp
588//===----------------------------------------------------------------------===//
589
590void circt::om::ListCreateOp::print(OpAsmPrinter &p) {
591 p << " ";
592 p.printOperands(getInputs());
593 p.printOptionalAttrDict((*this)->getAttrs());
594 p << " : " << getType().getElementType();
595}
596
597ParseResult circt::om::ListCreateOp::parse(OpAsmParser &parser,
598 OperationState &result) {
599 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
600 Type elemType;
601
602 if (parser.parseOperandList(operands) ||
603 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
604 parser.parseType(elemType))
605 return failure();
606 result.addTypes({circt::om::ListType::get(elemType)});
607
608 for (auto operand : operands)
609 if (parser.resolveOperand(operand, elemType, result.operands))
610 return failure();
611 return success();
612}
613
614//===----------------------------------------------------------------------===//
615// TupleCreateOp
616//===----------------------------------------------------------------------===//
617
618LogicalResult TupleCreateOp::inferReturnTypes(
619 MLIRContext *context, std::optional<Location> location, ValueRange operands,
620 DictionaryAttr attributes, OpaqueProperties, RegionRange regions,
621 llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
622 ::llvm::SmallVector<Type> types;
623 for (auto op : operands)
624 types.push_back(op.getType());
625 inferredReturnTypes.push_back(TupleType::get(context, types));
626 return success();
627}
628
629//===----------------------------------------------------------------------===//
630// TupleGetOp
631//===----------------------------------------------------------------------===//
632
633LogicalResult TupleGetOp::inferReturnTypes(
634 MLIRContext *context, std::optional<Location> location, ValueRange operands,
635 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
636 llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
637 Adaptor adaptor(operands, attributes, properties, regions);
638 auto idx = adaptor.getIndexAttr();
639 if (operands.empty() || !idx)
640 return failure();
641
642 auto tupleTypes = cast<TupleType>(adaptor.getInput().getType()).getTypes();
643 if (tupleTypes.size() <= idx.getValue().getLimitedValue()) {
644 if (location)
645 mlir::emitError(*location,
646 "tuple index out-of-bounds, must be less than ")
647 << tupleTypes.size() << " but got "
648 << idx.getValue().getLimitedValue();
649 return failure();
650 }
651
652 inferredReturnTypes.push_back(tupleTypes[idx.getValue().getLimitedValue()]);
653 return success();
654}
655
656//===----------------------------------------------------------------------===//
657// MapCreateOp
658//===----------------------------------------------------------------------===//
659
660void circt::om::MapCreateOp::print(OpAsmPrinter &p) {
661 p << " ";
662 p.printOperands(getInputs());
663 p.printOptionalAttrDict((*this)->getAttrs());
664 p << " : " << cast<circt::om::MapType>(getType()).getKeyType() << ", "
665 << cast<circt::om::MapType>(getType()).getValueType();
666}
667
668ParseResult circt::om::MapCreateOp::parse(OpAsmParser &parser,
669 OperationState &result) {
670 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
671 Type elementType, valueType;
672
673 if (parser.parseOperandList(operands) ||
674 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
675 parser.parseType(elementType) || parser.parseComma() ||
676 parser.parseType(valueType))
677 return failure();
678 result.addTypes({circt::om::MapType::get(elementType, valueType)});
679 auto operandType =
680 mlir::TupleType::get(valueType.getContext(), {elementType, valueType});
681
682 for (auto operand : operands)
683 if (parser.resolveOperand(operand, operandType, result.operands))
684 return failure();
685 return success();
686}
687
688//===----------------------------------------------------------------------===//
689// BasePathCreateOp
690//===----------------------------------------------------------------------===//
691
692LogicalResult
693BasePathCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
694 auto hierPath = symbolTable.lookupNearestSymbolFrom<hw::HierPathOp>(
695 *this, getTargetAttr());
696 if (!hierPath)
697 return emitOpError("invalid symbol reference");
698 return success();
699}
700
701//===----------------------------------------------------------------------===//
702// PathCreateOp
703//===----------------------------------------------------------------------===//
704
705LogicalResult
706PathCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
707 auto hierPath = symbolTable.lookupNearestSymbolFrom<hw::HierPathOp>(
708 *this, getTargetAttr());
709 if (!hierPath)
710 return emitOpError("invalid symbol reference");
711 return success();
712}
713
714//===----------------------------------------------------------------------===//
715// IntegerAddOp
716//===----------------------------------------------------------------------===//
717
718FailureOr<llvm::APSInt>
719IntegerAddOp::evaluateIntegerOperation(const llvm::APSInt &lhs,
720 const llvm::APSInt &rhs) {
721 return success(lhs + rhs);
722}
723
724//===----------------------------------------------------------------------===//
725// IntegerMulOp
726//===----------------------------------------------------------------------===//
727
728FailureOr<llvm::APSInt>
729IntegerMulOp::evaluateIntegerOperation(const llvm::APSInt &lhs,
730 const llvm::APSInt &rhs) {
731 return success(lhs * rhs);
732}
733
734//===----------------------------------------------------------------------===//
735// IntegerShrOp
736//===----------------------------------------------------------------------===//
737
738FailureOr<llvm::APSInt>
739IntegerShrOp::evaluateIntegerOperation(const llvm::APSInt &lhs,
740 const llvm::APSInt &rhs) {
741 // Check non-negative constraint from operation semantics.
742 if (!rhs.isNonNegative())
743 return emitOpError("shift amount must be non-negative");
744 // Check size constraint from implementation detail of using getExtValue.
745 if (!rhs.isRepresentableByInt64())
746 return emitOpError("shift amount must be representable in 64 bits");
747 return success(lhs >> rhs.getExtValue());
748}
749
750//===----------------------------------------------------------------------===//
751// IntegerShlOp
752//===----------------------------------------------------------------------===//
753
754FailureOr<llvm::APSInt>
755IntegerShlOp::evaluateIntegerOperation(const llvm::APSInt &lhs,
756 const llvm::APSInt &rhs) {
757 // Check non-negative constraint from operation semantics.
758 if (!rhs.isNonNegative())
759 return emitOpError("shift amount must be non-negative");
760 // Check size constraint from implementation detail of using getExtValue.
761 if (!rhs.isRepresentableByInt64())
762 return emitOpError("shift amount must be representable in 64 bits");
763 return success(lhs << rhs.getExtValue());
764}
765
766//===----------------------------------------------------------------------===//
767// TableGen generated logic.
768//===----------------------------------------------------------------------===//
769
770#define GET_OP_CLASSES
771#include "circt/Dialect/OM/OM.cpp.inc"
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static InstancePath empty
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:212
static ParseResult parseClassLike(OpAsmParser &parser, OperationState &state)
Definition OMOps.cpp:132
LogicalResult verifyClassLike(ClassLike classLike)
Definition OMOps.cpp:234
std::optional< Type > getClassLikeFieldType(ClassLike classLike, StringAttr name)
Definition OMOps.cpp:273
void getClassLikeAsmBlockArgumentNames(ClassLike classLike, Region &region, OpAsmSetValueNameFn setNameFn)
Definition OMOps.cpp:251
static ParseResult parseBasePathString(OpAsmParser &parser, PathAttr &path)
Definition OMOps.cpp:26
static ParseResult parsePathString(OpAsmParser &parser, PathAttr &path, StringAttr &module, StringAttr &ref, StringAttr &field)
Definition OMOps.cpp:48
static void printBasePathString(OpAsmPrinter &p, Operation *op, PathAttr path)
Definition OMOps.cpp:37
static void printFieldLocs(OpAsmPrinter &printer, Operation *op, ArrayAttr fieldLocs)
Definition OMOps.cpp:87
static ParseResult parseFieldLocs(OpAsmParser &parser, ArrayAttr &fieldLocs)
Definition OMOps.cpp:77
static ParseResult parseClassFieldsList(OpAsmParser &parser, SmallVectorImpl< Attribute > &fieldNames, SmallVectorImpl< Type > &fieldTypes)
Definition OMOps.cpp:100
static void printClassLike(ClassLike classLike, OpAsmPrinter &printer)
Definition OMOps.cpp:186
void replaceClassLikeFieldTypes(ClassLike classLike, AttrTypeReplacer &replacer)
Definition OMOps.cpp:283
NamedAttribute makeFieldType(StringAttr name, Type type)
Definition OMOps.cpp:263
NamedAttribute makeFieldIdx(MLIRContext *ctx, mlir::StringAttr name, unsigned i)
Definition OMOps.cpp:267
static void printPathString(OpAsmPrinter &p, Operation *op, PathAttr path, StringAttr module, StringAttr ref, StringAttr field)
Definition OMOps.cpp:62
static Block * getBodyBlock(FModuleLike mod)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:55
void error(Twine message)
Definition LSPUtils.cpp:16
ParseResult parsePath(MLIRContext *context, StringRef spelling, PathAttr &path, StringAttr &module, StringAttr &ref, StringAttr &field)
Parse a target string in to a path.
Definition OMUtils.cpp:182
ParseResult parseBasePath(MLIRContext *context, StringRef spelling, PathAttr &path)
Parse a target string of the form "Foo/bar:Bar/baz" in to a base path.
Definition OMUtils.cpp:177
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:183
A module name, and the name of an instance inside that module.
mlir::StringAttr mlir::StringAttr instance