15#include "mlir/IR/Builders.h"
16#include "mlir/IR/DialectImplementation.h"
17#include "llvm/ADT/SmallString.h"
28ConstantOp::inferReturnTypes(MLIRContext *context, std::optional<Location> loc,
29 ValueRange operands, DictionaryAttr attributes,
30 OpaqueProperties properties, RegionRange regions,
31 SmallVectorImpl<Type> &inferredReturnTypes) {
32 inferredReturnTypes.push_back(
33 properties.as<Properties *>()->getValue().getType());
37OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) {
return getValueAttr(); }
43LogicalResult SequenceOp::verifyRegions() {
44 if (TypeRange(getSequenceType().getElementTypes()) !=
45 getBody()->getArgumentTypes())
46 return emitOpError(
"sequence type does not match block argument types");
51ParseResult SequenceOp::parse(OpAsmParser &parser, OperationState &result) {
53 if (parser.parseSymbolName(
54 result.getOrAddProperties<SequenceOp::Properties>().sym_name))
58 SmallVector<OpAsmParser::Argument> arguments;
59 if (parser.parseArgumentList(arguments, OpAsmParser::Delimiter::Paren,
63 SmallVector<Type> argTypes;
64 SmallVector<Location> argLocs;
65 argTypes.reserve(arguments.size());
66 argLocs.reserve(arguments.size());
67 for (
auto &arg : arguments) {
68 argTypes.push_back(arg.type);
69 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
71 Type type = SequenceType::get(result.getContext(), argTypes);
72 result.getOrAddProperties<SequenceOp::Properties>().sequenceType =
75 auto loc = parser.getCurrentLocation();
76 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
78 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
79 return parser.emitError(loc)
80 <<
"'" << result.name.getStringRef() <<
"' op ";
84 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
85 if (parser.parseRegion(*bodyRegionRegion, arguments))
88 if (bodyRegionRegion->empty()) {
89 bodyRegionRegion->emplaceBlock();
90 bodyRegionRegion->addArguments(argTypes, argLocs);
92 result.addRegion(std::move(bodyRegionRegion));
97void SequenceOp::print(OpAsmPrinter &p) {
99 p.printSymbolName(getSymNameAttr().getValue());
101 llvm::interleaveComma(getBody()->getArguments(), p,
102 [&](
auto arg) { p.printRegionArgument(arg); });
104 p.printOptionalAttrDictWithKeyword(
105 (*this)->getAttrs(), {getSymNameAttrName(), getSequenceTypeAttrName()});
107 p.printRegion(getBodyRegion(),
false);
115GetSequenceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
117 symbolTable.lookupNearestSymbolFrom<SequenceOp>(*
this, getSequenceAttr());
120 <<
"'" << getSequence()
121 <<
"' does not reference a valid 'rtg.sequence' operation";
123 if (
seq.getSequenceType() != getType())
124 return emitOpError(
"referenced 'rtg.sequence' op's type does not match");
133LogicalResult SubstituteSequenceOp::verify() {
134 if (getReplacements().
empty())
135 return emitOpError(
"must at least have one replacement value");
137 if (getReplacements().size() >
138 getSequence().getType().getElementTypes().size())
140 "must not have more replacement values than sequence arguments");
142 if (getReplacements().getTypes() !=
143 getSequence().getType().getElementTypes().take_front(
144 getReplacements().size()))
145 return emitOpError(
"replacement types must match the same number of "
146 "sequence argument types from the front");
151LogicalResult SubstituteSequenceOp::inferReturnTypes(
152 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
153 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
154 SmallVectorImpl<Type> &inferredReturnTypes) {
155 ArrayRef<Type> argTypes =
156 cast<SequenceType>(operands[0].getType()).getElementTypes();
158 SequenceType::get(context, argTypes.drop_front(operands.size() - 1));
159 inferredReturnTypes.push_back(seqType);
163ParseResult SubstituteSequenceOp::parse(::mlir::OpAsmParser &parser,
164 ::mlir::OperationState &result) {
165 OpAsmParser::UnresolvedOperand sequenceRawOperand;
166 SmallVector<OpAsmParser::UnresolvedOperand, 4> replacementsOperands;
167 Type sequenceRawType;
169 if (parser.parseOperand(sequenceRawOperand) || parser.parseLParen())
172 auto replacementsOperandsLoc = parser.getCurrentLocation();
173 if (parser.parseOperandList(replacementsOperands) || parser.parseRParen() ||
174 parser.parseColon() || parser.parseType(sequenceRawType) ||
175 parser.parseOptionalAttrDict(result.attributes))
178 if (!isa<SequenceType>(sequenceRawType))
179 return parser.emitError(parser.getNameLoc())
180 <<
"'sequence' must be handle to a sequence or sequence family, but "
184 if (parser.resolveOperand(sequenceRawOperand, sequenceRawType,
188 if (parser.resolveOperands(replacementsOperands,
189 cast<SequenceType>(sequenceRawType)
191 .take_front(replacementsOperands.size()),
192 replacementsOperandsLoc, result.operands))
195 SmallVector<Type> inferredReturnTypes;
196 if (failed(inferReturnTypes(
197 parser.getContext(), result.location, result.operands,
198 result.attributes.getDictionary(parser.getContext()),
199 result.getRawProperties(), result.regions, inferredReturnTypes)))
202 result.addTypes(inferredReturnTypes);
206void SubstituteSequenceOp::print(OpAsmPrinter &p) {
207 p <<
' ' << getSequence() <<
"(" << getReplacements()
208 <<
") : " << getSequence().getType();
209 p.printOptionalAttrDict((*this)->getAttrs(), {});
216LogicalResult InterleaveSequencesOp::verify() {
217 if (getSequences().
empty())
218 return emitOpError(
"must have at least one sequence in the list");
223OpFoldResult InterleaveSequencesOp::fold(FoldAdaptor adaptor) {
224 if (getSequences().size() == 1)
225 return getSequences()[0];
234ParseResult SetCreateOp::parse(OpAsmParser &parser, OperationState &result) {
235 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
238 if (parser.parseOperandList(operands) ||
239 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
240 parser.parseType(elemType))
243 result.addTypes({SetType::get(result.getContext(), elemType)});
245 for (
auto operand : operands)
246 if (parser.resolveOperand(operand, elemType, result.operands))
252void SetCreateOp::print(OpAsmPrinter &p) {
254 p.printOperands(getElements());
255 p.printOptionalAttrDict((*this)->getAttrs());
256 p <<
" : " << getSet().getType().getElementType();
259LogicalResult SetCreateOp::verify() {
260 if (getElements().size() > 0) {
263 if (getElements()[0].getType() != getSet().getType().getElementType())
264 return emitOpError() <<
"operand types must match set element type";
274LogicalResult SetCartesianProductOp::inferReturnTypes(
275 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
276 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
277 SmallVectorImpl<Type> &inferredReturnTypes) {
278 if (operands.empty()) {
280 return mlir::emitError(*loc) <<
"at least one set must be provided";
284 SmallVector<Type> elementTypes;
285 for (
auto operand : operands)
286 elementTypes.push_back(cast<SetType>(operand.getType()).getElementType());
287 inferredReturnTypes.push_back(
288 SetType::get(TupleType::get(context, elementTypes)));
296ParseResult BagCreateOp::parse(OpAsmParser &parser, OperationState &result) {
297 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> elementOperands,
301 if (!parser.parseOptionalLParen()) {
303 OpAsmParser::UnresolvedOperand elementOperand, multipleOperand;
304 if (parser.parseOperand(multipleOperand) || parser.parseKeyword(
"x") ||
305 parser.parseOperand(elementOperand))
308 elementOperands.push_back(elementOperand);
309 multipleOperands.push_back(multipleOperand);
311 if (parser.parseOptionalComma()) {
312 if (parser.parseRParen())
319 if (parser.parseColon() || parser.parseType(elemType) ||
320 parser.parseOptionalAttrDict(result.attributes))
323 result.addTypes({BagType::get(result.getContext(), elemType)});
325 for (
auto operand : elementOperands)
326 if (parser.resolveOperand(operand, elemType, result.operands))
329 for (
auto operand : multipleOperands)
330 if (parser.resolveOperand(operand, IndexType::
get(result.getContext()),
337void BagCreateOp::print(OpAsmPrinter &p) {
339 if (!getElements().
empty())
341 llvm::interleaveComma(llvm::zip(getElements(), getMultiples()), p,
342 [&](
auto elAndMultiple) {
343 auto [el, multiple] = elAndMultiple;
344 p << multiple <<
" x " << el;
346 if (!getElements().
empty())
349 p <<
" : " << getBag().getType().getElementType();
350 p.printOptionalAttrDict((*this)->getAttrs());
353LogicalResult BagCreateOp::verify() {
354 if (!llvm::all_equal(getElements().getTypes()))
355 return emitOpError() <<
"types of all elements must match";
357 if (getElements().size() > 0)
358 if (getElements()[0].getType() != getBag().getType().getElementType())
359 return emitOpError() <<
"operand types must match bag element type";
368LogicalResult TupleCreateOp::inferReturnTypes(
369 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
370 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
371 SmallVectorImpl<Type> &inferredReturnTypes) {
372 if (operands.empty()) {
374 return mlir::emitError(*loc) <<
"empty tuples not allowed";
378 SmallVector<Type> elementTypes;
379 for (
auto operand : operands)
380 elementTypes.push_back(operand.getType());
381 inferredReturnTypes.push_back(TupleType::get(context, elementTypes));
389LogicalResult TupleExtractOp::inferReturnTypes(
390 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
391 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
392 SmallVectorImpl<Type> &inferredReturnTypes) {
393 assert(operands.size() == 1 &&
"must have exactly one operand");
395 auto tupleTy = dyn_cast<TupleType>(operands[0].getType());
396 size_t idx = properties.as<Properties *>()->getIndex().getInt();
397 if (!tupleTy || tupleTy.getTypes().size() <= idx) {
399 return mlir::emitError(*loc)
401 <<
") must be smaller than number of elements in tuple ("
402 << tupleTy.getTypes().size() <<
")";
406 inferredReturnTypes.push_back(tupleTy.getTypes()[idx]);
414LogicalResult FixedRegisterOp::inferReturnTypes(
415 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
416 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
417 SmallVectorImpl<Type> &inferredReturnTypes) {
418 inferredReturnTypes.push_back(
419 properties.as<Properties *>()->getReg().getType());
423OpFoldResult FixedRegisterOp::fold(FoldAdaptor adaptor) {
return getRegAttr(); }
429LogicalResult VirtualRegisterOp::verify() {
430 if (getAllowedRegs().
empty())
431 return emitOpError(
"must have at least one allowed register");
433 if (llvm::any_of(getAllowedRegs(), [](Attribute attr) {
434 return !isa<RegisterAttrInterface>(attr);
436 return emitOpError(
"all elements must be of RegisterAttrInterface");
438 if (!llvm::all_equal(
439 llvm::map_range(getAllowedRegs().getAsRange<RegisterAttrInterface>(),
440 [](
auto attr) {
return attr.getType(); })))
441 return emitOpError(
"all allowed registers must be of the same type");
446LogicalResult VirtualRegisterOp::inferReturnTypes(
447 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
448 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
449 SmallVectorImpl<Type> &inferredReturnTypes) {
450 auto allowedRegs = properties.as<Properties *>()->getAllowedRegs();
451 if (allowedRegs.empty()) {
453 return mlir::emitError(*loc,
"must have at least one allowed register");
458 auto regAttr = dyn_cast<RegisterAttrInterface>(allowedRegs[0]);
461 return mlir::emitError(
462 *loc,
"allowed register attributes must be of RegisterAttrInterface");
466 inferredReturnTypes.push_back(regAttr.getType());
474LogicalResult ContextSwitchOp::verify() {
475 auto elementTypes = getSequence().getType().getElementTypes();
476 if (elementTypes.size() != 3)
477 return emitOpError(
"sequence type must have exactly 3 element types");
479 if (getFrom().getType() != elementTypes[0])
481 "first sequence element type must match 'from' attribute type");
483 if (getTo().getType() != elementTypes[1])
485 "second sequence element type must match 'to' attribute type");
487 auto seqTy = dyn_cast<SequenceType>(elementTypes[2]);
488 if (!seqTy || !seqTy.getElementTypes().empty())
490 "third sequence element type must be a fully substituted sequence");
499LogicalResult TestOp::verifyRegions() {
500 if (!getTarget().entryTypesMatch(getBody()->getArgumentTypes()))
501 return emitOpError(
"argument types must match dict entry types");
506ParseResult TestOp::parse(OpAsmParser &parser, OperationState &result) {
508 if (parser.parseSymbolName(
509 result.getOrAddProperties<TestOp::Properties>().sym_name))
513 SmallVector<OpAsmParser::Argument> arguments;
514 SmallVector<StringAttr> names;
516 auto parseOneArgument = [&]() -> ParseResult {
518 if (parser.parseKeywordOrString(&name) || parser.parseEqual() ||
519 parser.parseArgument(arguments.emplace_back(),
true,
523 names.push_back(StringAttr::get(result.getContext(), name));
526 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
527 parseOneArgument,
" in argument list"))
530 SmallVector<Type> argTypes;
531 SmallVector<DictEntry> entries;
532 SmallVector<Location> argLocs;
533 argTypes.reserve(arguments.size());
534 argLocs.reserve(arguments.size());
535 for (
auto [name, arg] :
llvm::zip(names, arguments)) {
536 argTypes.push_back(arg.type);
537 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
538 entries.push_back({name, arg.type});
540 auto emitError = [&]() -> InFlightDiagnostic {
541 return parser.emitError(parser.getCurrentLocation());
543 Type type = DictType::getChecked(emitError, result.getContext(),
544 ArrayRef<DictEntry>(entries));
547 result.getOrAddProperties<TestOp::Properties>().target = TypeAttr::get(type);
549 auto loc = parser.getCurrentLocation();
550 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
552 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
553 return parser.emitError(loc)
554 <<
"'" << result.name.getStringRef() <<
"' op ";
558 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
559 if (parser.parseRegion(*bodyRegionRegion, arguments))
562 if (bodyRegionRegion->empty()) {
563 bodyRegionRegion->emplaceBlock();
564 bodyRegionRegion->addArguments(argTypes, argLocs);
566 result.addRegion(std::move(bodyRegionRegion));
571void TestOp::print(OpAsmPrinter &p) {
573 p.printSymbolName(getSymNameAttr().getValue());
575 SmallString<32> resultNameStr;
576 llvm::interleaveComma(
577 llvm::zip(getTarget().getEntries(), getBody()->getArguments()), p,
578 [&](
auto entryAndArg) {
579 auto [entry, arg] = entryAndArg;
580 p << entry.name.getValue() <<
" = ";
581 p.printRegionArgument(arg);
584 p.printOptionalAttrDictWithKeyword(
585 (*this)->getAttrs(), {getSymNameAttrName(), getTargetAttrName()});
587 p.printRegion(getBodyRegion(),
false);
590void TestOp::getAsmBlockArgumentNames(Region ®ion,
592 for (
auto [entry, arg] :
593 llvm::zip(getTarget().getEntries(), region.getArguments()))
594 setNameFn(arg, entry.name.getValue());
601LogicalResult TargetOp::verifyRegions() {
602 if (!getTarget().entryTypesMatch(
603 getBody()->getTerminator()->getOperandTypes()))
604 return emitOpError(
"terminator operand types must match dict entry types");
613LogicalResult ArrayCreateOp::verify() {
614 if (!getElements().
empty() &&
615 getElements()[0].getType() != getType().getElementType())
616 return emitOpError(
"operand types must match array element type, expected ")
617 << getType().getElementType() <<
" but got "
618 << getElements()[0].getType();
623ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
624 SmallVector<OpAsmParser::UnresolvedOperand> operands;
627 if (parser.parseOperandList(operands) || parser.parseColon() ||
629 parser.parseOptionalAttrDict(result.attributes))
632 if (failed(parser.resolveOperands(operands,
elementType, result.operands)))
640void ArrayCreateOp::print(OpAsmPrinter &p) {
642 p.printOperands(getElements());
643 p <<
" : " << getType().getElementType();
644 p.printOptionalAttrDict((*this)->getAttrs(), {});
651#define GET_OP_CLASSES
652#include "circt/Dialect/RTG/IR/RTG.cpp.inc"
assert(baseType &&"element must be base type")
static InstancePath empty
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn