16#include "mlir/IR/Builders.h"
17#include "mlir/IR/ImplicitLocOpBuilder.h"
18#include "mlir/IR/SymbolTable.h"
19#include "llvm/ADT/STLExtras.h"
29 auto *
context = parser.getContext();
30 auto loc = parser.getCurrentLocation();
32 if (parser.parseString(&rawPath))
35 return parser.emitError(loc,
"invalid base path");
51 StringAttr &module, StringAttr &ref,
54 auto *
context = parser.getContext();
55 auto loc = parser.getCurrentLocation();
57 if (parser.parseString(&rawPath))
60 return parser.emitError(loc,
"invalid path");
65 StringAttr module, StringAttr ref,
68 for (
const auto &elt : path)
69 p << elt.module.getValue() <<
'/' << elt.instance.getValue() <<
':';
70 if (!module.getValue().empty())
71 p << module.getValue();
72 if (!ref.getValue().empty())
73 p <<
'>' << ref.getValue();
74 if (!field.getValue().empty())
75 p << field.getValue();
79static ParseResult
parseFieldLocs(OpAsmParser &parser, ArrayAttr &fieldLocs) {
80 if (parser.parseOptionalKeyword(
"field_locs"))
82 if (parser.parseLParen() || parser.parseAttribute(fieldLocs) ||
83 parser.parseRParen()) {
90 ArrayAttr fieldLocs) {
91 mlir::OpPrintingFlags flags;
92 if (!flags.shouldPrintDebugInfo() || !fieldLocs)
94 printer <<
"field_locs(";
95 printer.printAttribute(fieldLocs);
103 SmallVectorImpl<Attribute> &fieldNames,
104 SmallVectorImpl<Type> &fieldTypes) {
106 llvm::StringMap<SMLoc> nameLocMap;
107 auto parseElt = [&]() -> ParseResult {
109 std::string fieldName;
110 if (parser.parseKeywordOrString(&fieldName))
112 SMLoc currLoc = parser.getCurrentLocation();
113 if (nameLocMap.count(fieldName)) {
114 parser.emitError(currLoc,
"field \"")
115 << fieldName <<
"\" is defined twice";
116 parser.emitError(nameLocMap[fieldName]) <<
"previous definition is here";
119 nameLocMap[fieldName] = currLoc;
120 fieldNames.push_back(StringAttr::get(parser.getContext(), fieldName));
123 fieldTypes.emplace_back();
124 if (parser.parseColonType(fieldTypes.back()))
130 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
134template <
typename ClassTy>
137 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, state.attributes);
141 if (parser.parseSymbolName(symName, ClassTy::getSymNameAttrName(state.name),
146 SmallVector<OpAsmParser::Argument> args;
147 if (parser.parseArgumentList(args, OpAsmParser::Delimiter::Paren,
151 SmallVector<Type> fieldTypes;
152 SmallVector<Attribute> fieldNames;
153 if (succeeded(parser.parseOptionalArrow()))
157 SmallVector<NamedAttribute> fieldTypesMap;
158 if (!fieldNames.empty()) {
159 for (
auto [name, type] : zip(fieldNames, fieldTypes))
160 fieldTypesMap.push_back(
161 NamedAttribute(cast<StringAttr>(name), TypeAttr::get(type)));
163 auto *ctx = parser.getContext();
164 state.addAttribute(
"fieldNames", mlir::ArrayAttr::get(ctx, fieldNames));
165 state.addAttribute(
"fieldTypes",
166 mlir::DictionaryAttr::get(ctx, fieldTypesMap));
169 if (failed(parser.parseOptionalAttrDictWithKeyword(state.attributes)))
173 Region *region = state.addRegion();
174 if (parser.parseRegion(*region, args))
179 region->emplaceBlock();
182 auto argNames = llvm::map_range(args, [&](OpAsmParser::Argument arg) {
183 return StringAttr::get(parser.getContext(), arg.ssaName.name.drop_front());
187 ArrayAttr::get(parser.getContext(), SmallVector<Attribute>(argNames)));
196 StringRef visibilityAttrName =
197 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
198 if (
auto visibility =
199 classLike->getAttrOfType<StringAttr>(visibilityAttrName))
200 printer << visibility.getValue() <<
' ';
203 printer.printSymbolName(classLike.getSymName());
206 auto argNames = SmallVector<StringRef>(
207 classLike.getFormalParamNames().getAsValueRange<StringAttr>());
208 ArrayRef<BlockArgument> args = classLike.getBodyBlock()->getArguments();
212 for (
size_t i = 0, e = args.size(); i < e; ++i) {
213 printer <<
'%' << argNames[i] <<
": " << args[i].getType();
219 ArrayRef<Attribute> fieldNames =
220 cast<ArrayAttr>(classLike->getAttr(
"fieldNames")).getValue();
222 if (!fieldNames.empty()) {
224 for (
size_t i = 0, e = fieldNames.size(); i < e; ++i) {
227 StringAttr name = cast<StringAttr>(fieldNames[i]);
228 printer.printKeywordOrString(name.getValue());
230 Type type = classLike.getFieldType(name).value();
231 printer.printType(type);
237 SmallVector<StringRef> elidedAttrs{
238 classLike.getSymNameAttrName(), classLike.getFormalParamNamesAttrName(),
239 visibilityAttrName,
"fieldTypes",
"fieldNames"};
240 printer.printOptionalAttrDictWithKeyword(classLike.getOperation()->getAttrs(),
244 printer.printRegion(classLike.getBody(),
false,
250 if (classLike.getFormalParamNames().size() !=
251 classLike.getBodyBlock()->getArguments().size()) {
252 auto error = classLike.emitOpError(
253 "formal parameter name list doesn't match formal parameter value list");
254 error.attachNote(classLike.getLoc())
255 <<
"formal parameter names: " << classLike.getFormalParamNames();
256 error.attachNote(classLike.getLoc())
257 <<
"formal parameter values: "
258 << classLike.getBodyBlock()->getArguments();
268 auto argNames = SmallVector<StringRef>(
269 classLike.getFormalParamNames().getAsValueRange<StringAttr>());
270 ArrayRef<BlockArgument> args = classLike.getBodyBlock()->getArguments();
273 for (
size_t i = 0, e = args.size(); i < e; ++i)
274 setNameFn(args[i], argNames[i]);
278 return NamedAttribute(name, TypeAttr::get(type));
283 return NamedAttribute(StringAttr(name),
284 mlir::IntegerAttr::get(mlir::IndexType::get(ctx), i));
289 DictionaryAttr fieldTypes = mlir::cast<DictionaryAttr>(
290 classLike.getOperation()->getAttr(
"fieldTypes"));
291 Attribute type = fieldTypes.get(name);
292 if (
auto field = dyn_cast_or_null<TypeAttr>(type))
293 return field.getValue();
298 AttrTypeReplacer &replacer) {
299 classLike->setAttr(
"fieldTypes", cast<DictionaryAttr>(replacer.replace(
300 classLike.getFieldTypes())));
307ParseResult circt::om::ClassOp::parse(OpAsmParser &parser,
308 OperationState &state) {
312circt::om::ClassOp circt::om::ClassOp::buildSimpleClassOp(
313 OpBuilder &odsBuilder, Location loc, Twine name,
314 ArrayRef<StringRef> formalParamNames, ArrayRef<StringRef> fieldNames,
315 ArrayRef<Type> fieldTypes) {
316 circt::om::ClassOp classOp = circt::om::ClassOp::create(
317 odsBuilder, loc, odsBuilder.getStringAttr(name), {},
318 odsBuilder.getStrArrayAttr(formalParamNames),
319 odsBuilder.getStrArrayAttr(fieldNames),
320 odsBuilder.getDictionaryAttr(llvm::map_to_vector(
321 llvm::zip(fieldNames, fieldTypes), [&](
auto field) -> NamedAttribute {
322 return NamedAttribute(odsBuilder.getStringAttr(std::get<0>(field)),
323 TypeAttr::get(std::get<1>(field)));
325 Block *body = &classOp.getRegion().emplaceBlock();
326 auto prevLoc = odsBuilder.saveInsertionPoint();
327 odsBuilder.setInsertionPointToEnd(body);
329 mlir::SmallVector<Attribute> locAttrs(fieldNames.size(), LocationAttr(loc));
331 ClassFieldsOp::create(odsBuilder, loc,
332 llvm::map_to_vector(fieldTypes,
333 [&](Type type) -> Value {
334 return body->addArgument(type,
337 odsBuilder.getArrayAttr(locAttrs));
339 odsBuilder.restoreInsertionPoint(prevLoc);
344void circt::om::ClassOp::print(OpAsmPrinter &printer) {
348LogicalResult circt::om::ClassOp::verify() {
349 if (getLinkonceOdr() && !isPublic())
350 return emitOpError(
"linkonce_odr requires public visibility");
354LogicalResult circt::om::ClassOp::verifyRegions() {
356 dyn_cast_or_null<ClassFieldsOp>(this->
getBodyBlock()->getTerminator());
358 return this->emitOpError(
"expected terminator to be ClassFieldsOp");
361 if (fieldsOp.getNumOperands() != this->getFieldNames().size()) {
362 auto diag = this->emitOpError()
363 <<
"returns '" << this->getFieldNames().size()
364 <<
"' fields, but its terminator returned '"
365 << fieldsOp.getNumOperands() <<
"' fields";
366 return diag.attachNote(fieldsOp.getLoc()) <<
"see terminator:";
370 auto types = this->getFieldTypes();
371 for (
auto [fieldName, terminatorOperandType] :
372 llvm::zip(this->getFieldNames(), fieldsOp.getOperandTypes())) {
374 auto fieldNameAttr = dyn_cast_or_null<StringAttr>(fieldName);
376 return this->emitOpError(
"field name is not a StringAttr");
378 if (
auto fieldType = types.get(fieldNameAttr))
379 if (
auto typeAttr = dyn_cast<TypeAttr>(fieldType))
380 if (typeAttr.getValue() == terminatorOperandType)
383 auto diag = this->emitOpError()
384 <<
"returns different field types than its terminator";
385 return diag.attachNote(fieldsOp.getLoc()) <<
"see terminator:";
391void circt::om::ClassOp::getAsmBlockArgumentNames(
396std::optional<mlir::Type>
397circt::om::ClassOp::getFieldType(mlir::StringAttr field) {
401void circt::om::ClassOp::replaceFieldTypes(AttrTypeReplacer &replacer) {
405void circt::om::ClassOp::updateFields(
406 mlir::ArrayRef<mlir::Location> newLocations,
407 mlir::ArrayRef<mlir::Value> newValues,
408 mlir::ArrayRef<mlir::Attribute> newNames) {
410 auto fieldsOp = getFieldsOp();
411 assert(fieldsOp &&
"The fields op should exist");
413 SmallVector<Attribute> names(getFieldNamesAttr().getAsRange<StringAttr>());
415 SmallVector<NamedAttribute> fieldTypes(getFieldTypesAttr().getValue());
417 SmallVector<Value> fieldVals(fieldsOp.getFields());
419 Location fieldOpLoc = fieldsOp->getLoc();
422 SmallVector<Location> locations;
423 if (
auto fl = dyn_cast<FusedLoc>(fieldOpLoc)) {
424 if (
auto metadataArr = dyn_cast_or_null<ArrayAttr>(fl.getMetadata())) {
425 if (names.size() == metadataArr.size()) {
426 auto r = metadataArr.getAsRange<LocationAttr>();
427 locations.append(r.begin(), r.end());
429 locations.append(names.size(), fieldOpLoc);
432 auto fieldLocs = fieldsOp.getFieldLocs();
433 if (fieldLocs.has_value() && names.size() == fieldLocs.value().size()) {
434 auto r = fieldLocs.value().getAsRange<LocationAttr>();
435 locations.append(r.begin(), r.end());
437 locations.append(names.size(), fieldOpLoc);
442 locations.append(names.size(), fieldOpLoc);
446 names.append(newNames.begin(), newNames.end());
447 locations.append(newLocations.begin(), newLocations.end());
448 fieldVals.append(newValues.begin(), newValues.end());
451 for (
auto [v, n] : llvm::zip(newValues, newNames))
452 fieldTypes.emplace_back(
453 NamedAttribute(llvm::cast<StringAttr>(n), TypeAttr::get(v.getType())));
456 SmallVector<Attribute> locationsAttr;
457 llvm::for_each(locations, [&](Location &l) {
458 locationsAttr.push_back(cast<Attribute>(l));
461 ImplicitLocOpBuilder builder(
getLoc(), *
this);
463 setFieldNamesAttr(builder.getArrayAttr(names));
465 setFieldTypesAttr(builder.getDictionaryAttr(fieldTypes));
466 fieldsOp.getFieldsMutable().assign(fieldVals);
468 fieldsOp->setLoc(builder.getFusedLoc(
469 locations, ArrayAttr::get(getContext(), locationsAttr)));
472void circt::om::ClassOp::addNewFieldsOp(mlir::OpBuilder &builder,
473 mlir::ArrayRef<Location> locs,
474 mlir::ArrayRef<Value> values) {
477 assert(locs.size() == values.size() &&
"Expected a location per value");
478 mlir::SmallVector<Attribute> locAttrs;
479 for (
auto loc : locs) {
480 locAttrs.push_back(cast<Attribute>(LocationAttr(loc)));
484 ClassFieldsOp::create(builder, builder.getFusedLoc(locs), values,
485 builder.getArrayAttr(locAttrs));
488mlir::Location circt::om::ClassOp::getFieldLocByIndex(
size_t i) {
489 auto fieldsOp = this->getFieldsOp();
490 auto fieldLocs = fieldsOp.getFieldLocs();
491 if (!fieldLocs.has_value())
492 return fieldsOp.getLoc();
493 assert(i < fieldLocs.value().size() &&
494 "field index too large for location array");
495 return cast<LocationAttr>(fieldLocs.value()[i]);
502ParseResult circt::om::ClassExternOp::parse(OpAsmParser &parser,
503 OperationState &state) {
507void circt::om::ClassExternOp::print(OpAsmPrinter &printer) {
511LogicalResult circt::om::ClassExternOp::verify() {
517 return this->emitOpError(
"external class body should be empty");
523void circt::om::ClassExternOp::getAsmBlockArgumentNames(
528std::optional<mlir::Type>
529circt::om::ClassExternOp::getFieldType(mlir::StringAttr field) {
533void circt::om::ClassExternOp::replaceFieldTypes(AttrTypeReplacer &replacer) {
541LogicalResult circt::om::ClassFieldsOp::verify() {
542 auto fieldLocs = this->getFieldLocs();
543 if (fieldLocs.has_value()) {
544 auto fieldLocsVal = fieldLocs.value();
545 if (fieldLocsVal.size() != this->getFields().size()) {
546 auto error = this->emitOpError(
"size of field_locs (")
547 << fieldLocsVal.size()
548 <<
") does not match number of fields ("
549 << this->getFields().size() <<
")";
559void circt::om::ObjectOp::build(::mlir::OpBuilder &odsBuilder,
560 ::mlir::OperationState &odsState,
562 ::mlir::ValueRange actualParams) {
563 return build(odsBuilder, odsState,
564 om::ClassType::get(odsBuilder.getContext(),
565 mlir::FlatSymbolRefAttr::get(classOp)),
566 mlir::FlatSymbolRefAttr::get(classOp.getNameAttr()),
570static FailureOr<ClassLike>
572 ClassType resultType, StringAttr className) {
573 StringAttr resultClassName = resultType.getClassName().getAttr();
574 if (resultClassName != className)
575 return op->emitOpError(
"result type (")
576 << resultClassName <<
") does not match referred to class ("
579 auto classDef = dyn_cast_or_null<ClassLike>(
580 symbolTable.lookupNearestSymbolFrom(op, className));
582 return op->emitOpError(
"refers to non-existant class (")
588circt::om::ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
591 getClassNameAttr().getAttr());
592 if (failed(classDef))
595 auto actualTypes = getActualParams().getTypes();
596 auto formalTypes = classDef->getBodyBlock()->getArgumentTypes();
599 if (actualTypes.size() != formalTypes.size()) {
600 auto error = emitOpError(
601 "actual parameter list doesn't match formal parameter list");
602 error.attachNote(classDef->getLoc())
603 <<
"formal parameters: " << classDef->getBodyBlock()->getArguments();
604 error.attachNote(
getLoc()) <<
"actual parameters: " << getActualParams();
609 for (
size_t i = 0, e = actualTypes.size(); i < e; ++i) {
610 if (actualTypes[i] != formalTypes[i]) {
611 return emitOpError(
"actual parameter type (")
612 << actualTypes[i] <<
") doesn't match formal parameter type ("
613 << formalTypes[i] <<
')';
625circt::om::ObjectFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
626 auto classType = getObject().getType();
627 auto className = classType.getClassName().getAttr();
630 auto classDef = dyn_cast_or_null<ClassLike>(
631 symbolTable.lookupNearestSymbolFrom(*
this, className));
633 return emitOpError(
"class ") << className <<
" was not found";
636 auto fieldName = getFieldAttr();
637 std::optional<Type> fieldType = classDef.getFieldType(fieldName);
639 auto diag = emitOpError(
"referenced non-existent field ") << fieldName;
640 diag.attachNote(classDef.getLoc()) <<
"class defined here";
645 if (getResult().getType() != fieldType.value())
646 return emitOpError(
"expected type ")
647 << getResult().getType() <<
", but accessed field has type "
648 << fieldType.value();
656void circt::om::ElaboratedObjectOp::build(OpBuilder &odsBuilder,
657 OperationState &odsState,
658 om::ClassLike classOp,
659 ValueRange fieldValues) {
660 return build(odsBuilder, odsState,
662 odsBuilder.getContext(),
663 mlir::FlatSymbolRefAttr::get(classOp.getSymNameAttr())),
664 mlir::FlatSymbolRefAttr::get(classOp.getSymNameAttr()),
668LogicalResult circt::om::ElaboratedObjectOp::verifySymbolUses(
669 SymbolTableCollection &symbolTable) {
672 getClassNameAttr().getAttr());
673 if (failed(classDef))
676 auto fieldNames = classDef->getFieldNames();
677 auto fieldValues = getFieldValues();
678 if (fieldValues.size() != fieldNames.size())
679 return emitOpError(
"field value list doesn't match class field list, "
681 << fieldNames.size() <<
" values but got " << fieldValues.size();
683 for (
auto [fieldName, fieldValue] : llvm::zip(fieldNames, fieldValues)) {
685 classDef->getFieldType(cast<StringAttr>(fieldName)).value();
686 if (fieldValue.getType() != expectedType)
687 return emitOpError(
"field value type for ")
688 << cast<StringAttr>(fieldName) <<
" (" << fieldValue.getType()
689 <<
") doesn't match class field type (" << expectedType <<
')';
699void circt::om::ConstantOp::build(::mlir::OpBuilder &odsBuilder,
700 ::mlir::OperationState &odsState,
701 ::mlir::TypedAttr constVal) {
702 return build(odsBuilder, odsState, constVal.getType(), constVal);
705OpFoldResult circt::om::ConstantOp::fold(FoldAdaptor adaptor) {
706 assert(adaptor.getOperands().empty() &&
"constant has no operands");
707 return getValueAttr();
714OpFoldResult circt::om::ListCreateOp::fold(FoldAdaptor adaptor) {
715 auto inputs = adaptor.getInputs();
716 if (!llvm::all_of(inputs, [](Attribute attr) {
return attr; }))
719 return ListAttr::get(getContext(), getType().getElementType(),
720 ArrayAttr::get(getContext(), inputs));
723void circt::om::ListCreateOp::print(OpAsmPrinter &p) {
725 p.printOperands(getInputs());
726 p.printOptionalAttrDict((*this)->getAttrs());
727 p <<
" : " << getType().getElementType();
730ParseResult circt::om::ListCreateOp::parse(OpAsmParser &parser,
731 OperationState &result) {
732 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
735 if (parser.parseOperandList(operands) ||
736 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
737 parser.parseType(elemType))
739 result.addTypes({circt::om::ListType::get(elemType)});
741 for (
auto operand : operands)
742 if (parser.resolveOperand(operand, elemType, result.operands))
751OpFoldResult circt::om::ListConcatOp::fold(FoldAdaptor adaptor) {
752 auto subLists = adaptor.getSubLists();
753 if (subLists.size() == 1)
754 return getSubLists().front();
756 SmallVector<Attribute> elements;
757 for (Attribute attr : subLists) {
758 auto listAttr = dyn_cast_or_null<ListAttr>(attr);
761 llvm::append_range(elements, listAttr.getElements());
764 return ListAttr::get(getContext(), getType().getElementType(),
765 ArrayAttr::get(getContext(), elements));
773BasePathCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
774 auto hierPath = symbolTable.lookupNearestSymbolFrom<hw::HierPathOp>(
775 *
this, getTargetAttr());
777 return emitOpError(
"invalid symbol reference");
786PathCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
787 auto hierPath = symbolTable.lookupNearestSymbolFrom<hw::HierPathOp>(
788 *
this, getTargetAttr());
790 return emitOpError(
"invalid symbol reference");
798OpFoldResult AnyCastOp::fold(FoldAdaptor adaptor) {
799 if (getInput().getType() == getType() && getInput() != getResult())
809 auto value = attr.getValue();
810 if (value.getType().isSignedInteger())
811 return value.getAPSInt();
816 return APSInt(value.getValue(),
false);
820 llvm::function_ref<FailureOr<APSInt>(
const APSInt &,
const APSInt &)>;
825 auto lhs = dyn_cast_or_null<circt::om::IntegerAttr>(lhsAttr);
826 auto rhs = dyn_cast_or_null<circt::om::IntegerAttr>(rhsAttr);
835 if (lhsVal.getBitWidth() > rhsVal.getBitWidth())
836 rhsVal = rhsVal.extend(lhsVal.getBitWidth());
837 else if (rhsVal.getBitWidth() > lhsVal.getBitWidth())
838 lhsVal = lhsVal.extend(rhsVal.getBitWidth());
841 auto result = evaluate(lhsVal, rhsVal);
846 auto *ctx = lhsAttr.getContext();
847 return circt::om::IntegerAttr::get(
848 ctx, mlir::IntegerAttr::get(ctx, result.value()));
855OpFoldResult IntegerAddOp::fold(FoldAdaptor adaptor) {
857 adaptor.getLhs(), adaptor.getRhs(),
858 [](
const APSInt &lhs,
const APSInt &rhs) { return success(lhs + rhs); });
865OpFoldResult IntegerMulOp::fold(FoldAdaptor adaptor) {
867 adaptor.getLhs(), adaptor.getRhs(),
868 [](
const APSInt &lhs,
const APSInt &rhs) { return success(lhs * rhs); });
875OpFoldResult IntegerShrOp::fold(FoldAdaptor adaptor) {
877 adaptor.getLhs(), adaptor.getRhs(),
878 [&](
const APSInt &lhs,
const APSInt &rhs) -> FailureOr<APSInt> {
880 if (!rhs.isNonNegative())
881 return (emitOpError(
"shift amount must be non-negative"), failure());
884 if (!rhs.isRepresentableByInt64())
885 return (emitOpError(
"shift amount must be representable in 64 bits"),
887 return success(lhs >> rhs.getExtValue());
895OpFoldResult IntegerShlOp::fold(FoldAdaptor adaptor) {
897 adaptor.getLhs(), adaptor.getRhs(),
898 [&](
const APSInt &lhs,
const APSInt &rhs) -> FailureOr<APSInt> {
900 if (!rhs.isNonNegative())
901 return (emitOpError(
"shift amount must be non-negative"), failure());
904 if (!rhs.isRepresentableByInt64())
905 return (emitOpError(
"shift amount must be representable in 64 bits"),
907 int64_t shiftAmt = rhs.getExtValue();
909 return success(lhs.extend(lhs.getBitWidth() + shiftAmt) << shiftAmt);
917OpFoldResult IntegerBitAndOp::fold(FoldAdaptor adaptor) {
919 adaptor.getLhs(), adaptor.getRhs(),
920 [](
const APSInt &lhs,
const APSInt &rhs) { return success(lhs & rhs); });
927OpFoldResult IntegerBitOrOp::fold(FoldAdaptor adaptor) {
929 adaptor.getLhs(), adaptor.getRhs(),
930 [](
const APSInt &lhs,
const APSInt &rhs) { return success(lhs | rhs); });
937OpFoldResult IntegerBitNotOp::fold(FoldAdaptor adaptor) {
938 auto input = dyn_cast_or_null<circt::om::IntegerAttr>(adaptor.getInput());
943 return circt::om::IntegerAttr::get(
944 getContext(), mlir::IntegerAttr::get(getContext(), result));
951OpFoldResult StringConcatOp::fold(FoldAdaptor adaptor) {
953 if (getStrings().size() == 1) {
954 if (
auto strAttr = adaptor.getStrings()[0])
957 return getStrings()[0];
961 if (!llvm::all_of(adaptor.getStrings(), [](Attribute operand) {
962 return isa_and_nonnull<StringAttr>(operand);
967 SmallString<64> result;
968 for (
auto operand : adaptor.getStrings())
969 result += cast<StringAttr>(operand).getValue();
971 return StringAttr::get(result, getResult().getType());
979 using OpRewritePattern::OpRewritePattern;
982 matchAndRewrite(StringConcatOp
concat,
983 mlir::PatternRewriter &rewriter)
const override {
987 bool hasNestedConcat = llvm::any_of(
concat.getStrings(), [](Value operand) {
988 auto nestedConcat = operand.getDefiningOp<StringConcatOp>();
989 return nestedConcat && operand.hasOneUse();
992 if (!hasNestedConcat)
996 SmallVector<Value> flatOperands;
997 for (
auto input :
concat.getStrings()) {
998 if (
auto nestedConcat = input.getDefiningOp<StringConcatOp>();
999 nestedConcat && input.hasOneUse())
1000 llvm::append_range(flatOperands, nestedConcat.getStrings());
1002 flatOperands.push_back(input);
1005 rewriter.modifyOpInPlace(
concat,
1006 [&]() {
concat->setOperands(flatOperands); });
1013class MergeAdjacentOMStringConstants
1016 using OpRewritePattern::OpRewritePattern;
1019 matchAndRewrite(StringConcatOp
concat,
1020 mlir::PatternRewriter &rewriter)
const override {
1022 SmallVector<Value> newOperands;
1023 SmallString<64> accumulatedLit;
1024 SmallVector<ConstantOp> accumulatedOps;
1025 bool changed =
false;
1027 auto flushLiterals = [&]() {
1028 if (accumulatedOps.empty())
1032 if (accumulatedOps.size() == 1) {
1033 newOperands.push_back(accumulatedOps[0]);
1036 auto newLit = rewriter.createOrFold<ConstantOp>(
1038 StringAttr::get(accumulatedLit,
concat.getResult().getType()));
1039 newOperands.push_back(newLit);
1042 accumulatedLit.clear();
1043 accumulatedOps.clear();
1046 for (
auto operand :
concat.getStrings()) {
1047 if (
auto litOp = operand.getDefiningOp<ConstantOp>()) {
1048 if (
auto strAttr = dyn_cast<StringAttr>(litOp.getValue())) {
1050 if (strAttr.getValue().empty()) {
1054 accumulatedLit += strAttr.getValue();
1055 accumulatedOps.push_back(litOp);
1061 newOperands.push_back(operand);
1071 if (newOperands.empty())
1072 return rewriter.replaceOpWithNewOp<ConstantOp>(
1073 concat, StringAttr::get(
"",
concat.getResult().getType())),
1077 rewriter.modifyOpInPlace(
concat,
1078 [&]() {
concat->setOperands(newOperands); });
1085void StringConcatOp::getCanonicalizationPatterns(RewritePatternSet &results,
1087 results.insert<FlattenOMStringConcat, MergeAdjacentOMStringConstants>(
1095static FailureOr<mlir::Attribute>
1097 auto resultType = mlir::IntegerType::get(lhsAttr.getContext(), 1);
1100 if (
auto lhs = dyn_cast<mlir::StringAttr>(lhsAttr))
1101 if (
auto rhs = dyn_cast<mlir::StringAttr>(rhsAttr))
1102 return mlir::Attribute(
1103 mlir::IntegerAttr::get(resultType, lhs == rhs ? 1 : 0));
1106 if (
auto lhs = dyn_cast<circt::om::IntegerAttr>(lhsAttr))
1107 if (
auto rhs = dyn_cast<circt::om::IntegerAttr>(rhsAttr)) {
1110 if (lhsVal.getBitWidth() > rhsVal.getBitWidth())
1111 rhsVal = rhsVal.extend(lhsVal.getBitWidth());
1112 else if (rhsVal.getBitWidth() > lhsVal.getBitWidth())
1113 lhsVal = lhsVal.extend(rhsVal.getBitWidth());
1114 return mlir::Attribute(
1115 mlir::IntegerAttr::get(resultType, lhsVal == rhsVal ? 1 : 0));
1119 if (
auto lhs = dyn_cast<mlir::IntegerAttr>(lhsAttr))
1120 if (
auto rhs = dyn_cast<mlir::IntegerAttr>(rhsAttr))
1121 return mlir::Attribute(
1122 mlir::IntegerAttr::get(resultType, lhs == rhs ? 1 : 0));
1127OpFoldResult PropEqOp::fold(FoldAdaptor adaptor) {
1128 auto lhsAttr = adaptor.getLhs();
1129 auto rhsAttr = adaptor.getRhs();
1130 if (!lhsAttr || !rhsAttr)
1144OpFoldResult ObjectEqOp::fold(FoldAdaptor adaptor) {
1146 if (getLhs() == getRhs())
1147 return mlir::IntegerAttr::get(getType(), 1);
1150 if (getLhs().getDefiningOp<ElaboratedObjectOp>() &&
1151 getRhs().getDefiningOp<ElaboratedObjectOp>())
1152 return mlir::IntegerAttr::get(getType(), 0);
1155 if (
auto cast = getLhs().getDefiningOp<AnyCastOp>();
1156 cast && isa<ClassType>(cast.getInput().getType())) {
1157 getLhsMutable().assign(cast.getInput());
1162 if (
auto cast = getRhs().getDefiningOp<AnyCastOp>();
1163 cast && isa<ClassType>(cast.getInput().getType())) {
1164 getRhsMutable().assign(cast.getInput());
1175OpFoldResult ListContainsOp::fold(FoldAdaptor adaptor) {
1177 if (
auto listCreate = getList().getDefiningOp<ListCreateOp>();
1178 listCreate && llvm::is_contained(listCreate.getInputs(), getElement()))
1179 return mlir::IntegerAttr::get(getResult().getType(), 1);
1181 auto listAttr = dyn_cast_or_null<ListAttr>(adaptor.getList());
1182 Attribute elementAttr = adaptor.getElement();
1185 if (!listAttr || !elementAttr)
1189 for (Attribute candidate : listAttr.getElements()) {
1191 if (failed(equality))
1193 found |= !cast<mlir::IntegerAttr>(*equality).getValue().isZero();
1196 return mlir::IntegerAttr::get(getResult().getType(),
found);
1205 auto lhsInt = dyn_cast_or_null<mlir::IntegerAttr>(lhsAttr);
1206 auto rhsInt = dyn_cast_or_null<mlir::IntegerAttr>(rhsAttr);
1207 if (!lhsInt || !rhsInt)
1209 APSInt lhsVal(lhsInt.getValue());
1210 APSInt rhsVal(rhsInt.getValue());
1211 auto result = evaluate(lhsVal, rhsVal);
1214 return mlir::IntegerAttr::get(
1215 lhsInt.getType(), result->extOrTrunc(lhsInt.getValue().getBitWidth()));
1220 auto i = dyn_cast_or_null<mlir::IntegerAttr>(a);
1221 return i && i.getValue().isZero();
1226 auto i = dyn_cast_or_null<mlir::IntegerAttr>(a);
1227 return i && i.getValue().isAllOnes();
1230OpFoldResult IntegerAndOp::fold(FoldAdaptor adaptor) {
1232 adaptor.getLhs(), adaptor.getRhs(),
1233 [](
const APSInt &lhs,
const APSInt &rhs) {
1234 return success(APSInt(lhs & rhs, false));
1239 return mlir::IntegerAttr::get(getResult().getType(),
1240 APInt::getZero(getType().
getWidth()));
1249OpFoldResult IntegerOrOp::fold(FoldAdaptor adaptor) {
1251 adaptor.getLhs(), adaptor.getRhs(),
1252 [](
const APSInt &lhs,
const APSInt &rhs) {
1253 return success(APSInt(lhs | rhs, false));
1258 return mlir::IntegerAttr::get(getResult().getType(),
1259 APInt::getAllOnes(getType().
getWidth()));
1268OpFoldResult IntegerXorOp::fold(FoldAdaptor adaptor) {
1270 adaptor.getLhs(), adaptor.getRhs(),
1271 [](
const APSInt &lhs,
const APSInt &rhs) {
1272 return success(APSInt(lhs ^ rhs, false));
1287LogicalResult circt::om::UnknownValueOp::verifySymbolUses(
1288 SymbolTableCollection &symbolTable) {
1291 auto classType = dyn_cast<ClassType>(getType());
1296 auto className = classType.getClassName();
1297 if (symbolTable.lookupNearestSymbolFrom<ClassLike>(*
this, className))
1300 return emitOpError() <<
"refers to non-existant class (\""
1301 << className.getValue() <<
"\")";
1308#define GET_OP_CLASSES
1309#include "circt/Dialect/OM/OM.cpp.inc"
assert(baseType &&"element must be base type")
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static OpFoldResult foldIntegerBitwise(Attribute lhsAttr, Attribute rhsAttr, IntegerBinaryFn evaluate)
LogicalResult verifyClassLike(ClassLike classLike)
std::optional< Type > getClassLikeFieldType(ClassLike classLike, StringAttr name)
void getClassLikeAsmBlockArgumentNames(ClassLike classLike, Region ®ion, OpAsmSetValueNameFn setNameFn)
static ParseResult parseBasePathString(OpAsmParser &parser, PathAttr &path)
static ParseResult parsePathString(OpAsmParser &parser, PathAttr &path, StringAttr &module, StringAttr &ref, StringAttr &field)
static APSInt getAPSIntForOMIntegerAttr(circt::om::IntegerAttr attr)
static void printBasePathString(OpAsmPrinter &p, Operation *op, PathAttr path)
llvm::function_ref< FailureOr< APSInt >(const APSInt &, const APSInt &)> IntegerBinaryFn
static FailureOr< ClassLike > verifyClassLikeSymbolUser(Operation *op, SymbolTableCollection &symbolTable, ClassType resultType, StringAttr className)
static void printFieldLocs(OpAsmPrinter &printer, Operation *op, ArrayAttr fieldLocs)
static bool isZeroInt(Attribute a)
static ParseResult parseFieldLocs(OpAsmParser &parser, ArrayAttr &fieldLocs)
static ParseResult parseClassFieldsList(OpAsmParser &parser, SmallVectorImpl< Attribute > &fieldNames, SmallVectorImpl< Type > &fieldTypes)
static FailureOr< mlir::Attribute > evaluateBinaryEquality(mlir::Attribute lhsAttr, mlir::Attribute rhsAttr)
static void printClassLike(ClassLike classLike, OpAsmPrinter &printer)
void replaceClassLikeFieldTypes(ClassLike classLike, AttrTypeReplacer &replacer)
NamedAttribute makeFieldType(StringAttr name, Type type)
NamedAttribute makeFieldIdx(MLIRContext *ctx, mlir::StringAttr name, unsigned i)
static void printPathString(OpAsmPrinter &p, Operation *op, PathAttr path, StringAttr module, StringAttr ref, StringAttr field)
static ParseResult parseClassLike(OpAsmParser &parser, OperationState &state)
static OpFoldResult foldIntegerBinaryArithmetic(Attribute lhsAttr, Attribute rhsAttr, IntegerBinaryFn evaluate)
static bool isAllOnesInt(Attribute a)
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
uint64_t getWidth(Type t)
void error(Twine message)
ParseResult parsePath(MLIRContext *context, StringRef spelling, PathAttr &path, StringAttr &module, StringAttr &ref, StringAttr &field)
Parse a target string in to a path.
ParseResult parseBasePath(MLIRContext *context, StringRef spelling, PathAttr &path)
Parse a target string of the form "Foo/bar:Bar/baz" in to a base path.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
A module name, and the name of an instance inside that module.
mlir::StringAttr instance