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 (!getTargetType().entryTypesMatch(getBody()->getArgumentTypes()))
501 return emitOpError(
"argument types must match dict entry types");
506LogicalResult TestOp::verify() {
507 if (getTemplateName().
empty())
508 return emitOpError(
"template name must not be empty");
513LogicalResult TestOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
514 if (!getTargetAttr())
518 symbolTable.lookupNearestSymbolFrom<TargetOp>(*
this, getTargetAttr());
521 <<
"'" << *getTarget()
522 <<
"' does not reference a valid 'rtg.target' operation";
526 size_t targetIdx = 0;
527 auto targetEntries = target.getTarget().getEntries();
528 for (
auto testEntry : getTargetType().getEntries()) {
530 while (targetIdx < targetEntries.size() &&
531 targetEntries[targetIdx].name.getValue() < testEntry.name.getValue())
535 if (targetIdx >= targetEntries.size() ||
536 targetEntries[targetIdx].name != testEntry.name ||
537 targetEntries[targetIdx].type != testEntry.type) {
538 return emitOpError(
"referenced 'rtg.target' op's type is invalid: "
539 "missing entry called '")
540 << testEntry.name.getValue() <<
"' of type " << testEntry.type;
547ParseResult TestOp::parse(OpAsmParser &parser, OperationState &result) {
549 StringAttr symNameAttr;
550 if (parser.parseSymbolName(symNameAttr))
553 result.getOrAddProperties<TestOp::Properties>().sym_name = symNameAttr;
556 SmallVector<OpAsmParser::Argument> arguments;
557 SmallVector<StringAttr> names;
559 auto parseOneArgument = [&]() -> ParseResult {
561 if (parser.parseKeywordOrString(&name) || parser.parseEqual() ||
562 parser.parseArgument(arguments.emplace_back(),
true,
566 names.push_back(StringAttr::get(result.getContext(), name));
569 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
570 parseOneArgument,
" in argument list"))
573 SmallVector<Type> argTypes;
574 SmallVector<DictEntry> entries;
575 SmallVector<Location> argLocs;
576 argTypes.reserve(arguments.size());
577 argLocs.reserve(arguments.size());
578 for (
auto [name, arg] :
llvm::zip(names, arguments)) {
579 argTypes.push_back(arg.type);
580 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
581 entries.push_back({name, arg.type});
583 auto emitError = [&]() -> InFlightDiagnostic {
584 return parser.emitError(parser.getCurrentLocation());
586 Type type = DictType::getChecked(emitError, result.getContext(),
587 ArrayRef<DictEntry>(entries));
590 result.getOrAddProperties<TestOp::Properties>().targetType =
593 std::string templateName;
594 if (!parser.parseOptionalKeyword(
"template")) {
595 auto loc = parser.getCurrentLocation();
596 if (parser.parseString(&templateName))
599 if (templateName.empty())
600 return parser.emitError(loc,
"template name must not be empty");
603 StringAttr templateNameAttr = symNameAttr;
604 if (!templateName.empty())
605 templateNameAttr = StringAttr::get(result.getContext(), templateName);
607 StringAttr targetName;
608 if (!parser.parseOptionalKeyword(
"target"))
609 if (parser.parseSymbolName(targetName))
612 result.getOrAddProperties<TestOp::Properties>().templateName =
614 result.getOrAddProperties<TestOp::Properties>().target = targetName;
616 auto loc = parser.getCurrentLocation();
617 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
619 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
620 return parser.emitError(loc)
621 <<
"'" << result.name.getStringRef() <<
"' op ";
625 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
626 if (parser.parseRegion(*bodyRegionRegion, arguments))
629 if (bodyRegionRegion->empty()) {
630 bodyRegionRegion->emplaceBlock();
631 bodyRegionRegion->addArguments(argTypes, argLocs);
633 result.addRegion(std::move(bodyRegionRegion));
638void TestOp::print(OpAsmPrinter &p) {
640 p.printSymbolName(getSymNameAttr().getValue());
642 SmallString<32> resultNameStr;
643 llvm::interleaveComma(
644 llvm::zip(getTargetType().getEntries(), getBody()->getArguments()), p,
645 [&](
auto entryAndArg) {
646 auto [entry, arg] = entryAndArg;
647 p << entry.name.getValue() <<
" = ";
648 p.printRegionArgument(arg);
652 if (getSymNameAttr() != getTemplateNameAttr())
653 p <<
" template " << getTemplateNameAttr();
655 if (getTargetAttr()) {
657 p.printSymbolName(getTargetAttr().getValue());
660 p.printOptionalAttrDictWithKeyword(
661 (*this)->getAttrs(), {getSymNameAttrName(), getTargetTypeAttrName(),
662 getTargetAttrName(), getTemplateNameAttrName()});
664 p.printRegion(getBodyRegion(),
false);
667void TestOp::getAsmBlockArgumentNames(Region ®ion,
669 for (
auto [entry, arg] :
670 llvm::zip(getTargetType().getEntries(), region.getArguments()))
671 setNameFn(arg, entry.name.getValue());
678LogicalResult TargetOp::verifyRegions() {
679 if (!getTarget().entryTypesMatch(
680 getBody()->getTerminator()->getOperandTypes()))
681 return emitOpError(
"terminator operand types must match dict entry types");
690LogicalResult ValidateOp::verify() {
691 if (!getRef().getType().isValidContentType(getType()))
693 "result type must be a valid content type for the ref value");
702LogicalResult ArrayCreateOp::verify() {
703 if (!getElements().
empty() &&
704 getElements()[0].getType() != getType().getElementType())
705 return emitOpError(
"operand types must match array element type, expected ")
706 << getType().getElementType() <<
" but got "
707 << getElements()[0].getType();
712ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
713 SmallVector<OpAsmParser::UnresolvedOperand> operands;
716 if (parser.parseOperandList(operands) || parser.parseColon() ||
718 parser.parseOptionalAttrDict(result.attributes))
721 if (failed(parser.resolveOperands(operands,
elementType, result.operands)))
729void ArrayCreateOp::print(OpAsmPrinter &p) {
731 p.printOperands(getElements());
732 p <<
" : " << getType().getElementType();
733 p.printOptionalAttrDict((*this)->getAttrs(), {});
740LogicalResult MemoryBlockDeclareOp::verify() {
743 "base address width must match memory block address width");
747 "end address width must match memory block address width");
749 if (getBaseAddress().ugt(getEndAddress()))
751 "base address must be smaller than or equal to the end address");
756ParseResult MemoryBlockDeclareOp::parse(OpAsmParser &parser,
757 OperationState &result) {
758 SmallVector<OpAsmParser::UnresolvedOperand> operands;
759 MemoryBlockType memoryBlockType;
762 if (parser.parseLSquare())
765 auto startLoc = parser.getCurrentLocation();
766 if (parser.parseInteger(start))
769 if (parser.parseMinus())
772 auto endLoc = parser.getCurrentLocation();
773 if (parser.parseInteger(end) || parser.parseRSquare() ||
774 parser.parseColonType(memoryBlockType) ||
775 parser.parseOptionalAttrDict(result.attributes))
778 auto width = memoryBlockType.getAddressWidth();
779 auto adjustAPInt = [&](APInt value, llvm::SMLoc loc) -> FailureOr<APInt> {
780 if (value.getBitWidth() > width) {
781 if (!value.isIntN(width))
782 return parser.emitError(
784 "address out of range for memory block with address width ")
787 return value.trunc(width);
790 if (value.getBitWidth() < width)
791 return value.zext(width);
796 auto startRes = adjustAPInt(start, startLoc);
797 auto endRes = adjustAPInt(end, endLoc);
798 if (failed(startRes) || failed(endRes))
801 auto intType = IntegerType::get(result.getContext(), width);
802 result.addAttribute(getBaseAddressAttrName(result.name),
803 IntegerAttr::get(intType, *startRes));
804 result.addAttribute(getEndAddressAttrName(result.name),
805 IntegerAttr::get(intType, *endRes));
807 result.addTypes(memoryBlockType);
811void MemoryBlockDeclareOp::print(OpAsmPrinter &p) {
812 SmallVector<char> str;
813 getBaseAddress().toString(str, 16,
false,
false,
false);
817 getEndAddress().toString(str, 16,
false,
false,
false);
818 p << str <<
"] : " << getType();
819 p.printOptionalAttrDict((*this)->getAttrs(),
820 {getBaseAddressAttrName(), getEndAddressAttrName()});
827LogicalResult MemoryBaseAddressOp::inferReturnTypes(
828 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
829 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
830 SmallVectorImpl<Type> &inferredReturnTypes) {
831 if (operands.empty())
833 auto memTy = dyn_cast<MemoryType>(operands[0].getType());
836 inferredReturnTypes.push_back(
837 ImmediateType::get(context, memTy.getAddressWidth()));
845#define GET_OP_CLASSES
846#include "circt/Dialect/RTG/IR/RTG.cpp.inc"
assert(baseType &&"element must be base type")
static size_t getAddressWidth(size_t depth)
static InstancePath empty
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn