CIRCT 24.0.0git
Loading...
Searching...
No Matches
RTGOps.cpp
Go to the documentation of this file.
1//===- RTGOps.cpp - Implement the RTG operations --------------------------===//
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 implements the RTG ops.
10//
11//===----------------------------------------------------------------------===//
12
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/DialectImplementation.h"
18#include "mlir/IR/Matchers.h"
19#include "mlir/IR/PatternMatch.h"
20#include "llvm/ADT/DenseSet.h"
21#include "llvm/ADT/SmallString.h"
22
23using namespace mlir;
24using namespace circt;
25using namespace rtg;
26
27//===----------------------------------------------------------------------===//
28// ConstantOp
29//===----------------------------------------------------------------------===//
30
31LogicalResult ConstantOp::verify() {
32 SmallVector<Attribute> worklist{getValueAttr()};
33 DenseSet<Attribute> visited;
34 while (!worklist.empty()) {
35 Attribute attr = worklist.pop_back_val();
36 // Attributes are uniqued DAG nodes, so shared children need only one visit.
37 if (!visited.insert(attr).second)
38 continue;
39
40 if (auto typedAttr = dyn_cast<TypedAttr>(attr))
41 if (isa<MutType, ContinuationType>(typedAttr.getType()))
42 return emitOpError("cannot encode value of type ")
43 << typedAttr.getType() << " in a constant attribute";
44
45 // Set and map contents are opaque to the generic sub-element walker.
46 if (auto set = dyn_cast<SetAttr>(attr))
47 llvm::append_range(worklist, *set.getElements());
48 else if (auto map = dyn_cast<MapAttr>(attr))
49 for (auto [key, value] : *map.getEntries()) {
50 worklist.push_back(key);
51 worklist.push_back(value);
52 }
53 attr.walkImmediateSubElements(
54 [&](Attribute subAttr) { worklist.push_back(subAttr); }, [](Type) {});
55 }
56 return success();
57}
58
59LogicalResult
60ConstantOp::inferReturnTypes(MLIRContext *context, std::optional<Location> loc,
61 ValueRange operands, DictionaryAttr attributes,
62 PropertyRef properties, RegionRange regions,
63 SmallVectorImpl<Type> &inferredReturnTypes) {
64 inferredReturnTypes.push_back(
65 properties.as<Properties *>()->getValue().getType());
66 return success();
67}
68
69OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) { return getValueAttr(); }
70
71void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
72 if (auto reg = dyn_cast<rtg::RegisterAttrInterface>(getValueAttr())) {
73 setNameFn(getResult(), reg.getRegisterAssembly());
74 return;
75 }
76}
77
78//===----------------------------------------------------------------------===//
79// SequenceOp
80//===----------------------------------------------------------------------===//
81
82LogicalResult SequenceOp::verifyRegions() {
83 if (TypeRange(getSequenceType().getElementTypes()) !=
84 getBody()->getArgumentTypes())
85 return emitOpError("sequence type does not match block argument types");
86
87 return success();
88}
89
90ParseResult SequenceOp::parse(OpAsmParser &parser, OperationState &result) {
91 // Parse the name as a symbol.
92 if (parser.parseSymbolName(
93 result.getOrAddProperties<SequenceOp::Properties>().sym_name))
94 return failure();
95
96 // Parse the function signature.
97 SmallVector<OpAsmParser::Argument> arguments;
98 if (parser.parseArgumentList(arguments, OpAsmParser::Delimiter::Paren,
99 /*allowType=*/true, /*allowAttrs=*/true))
100 return failure();
101
102 SmallVector<Type> argTypes;
103 SmallVector<Location> argLocs;
104 argTypes.reserve(arguments.size());
105 argLocs.reserve(arguments.size());
106 for (auto &arg : arguments) {
107 argTypes.push_back(arg.type);
108 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
109 }
110 Type type = SequenceType::get(result.getContext(), argTypes);
111 result.getOrAddProperties<SequenceOp::Properties>().sequenceType =
112 TypeAttr::get(type);
113
114 auto loc = parser.getCurrentLocation();
115 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
116 return failure();
117 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
118 return parser.emitError(loc)
119 << "'" << result.name.getStringRef() << "' op ";
120 })))
121 return failure();
122
123 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
124 if (parser.parseRegion(*bodyRegionRegion, arguments))
125 return failure();
126
127 if (bodyRegionRegion->empty()) {
128 bodyRegionRegion->emplaceBlock();
129 bodyRegionRegion->addArguments(argTypes, argLocs);
130 }
131 result.addRegion(std::move(bodyRegionRegion));
132
133 return success();
134}
135
136void SequenceOp::print(OpAsmPrinter &p) {
137 p << ' ';
138 p.printSymbolName(getSymNameAttr().getValue());
139 p << "(";
140 llvm::interleaveComma(getBody()->getArguments(), p,
141 [&](auto arg) { p.printRegionArgument(arg); });
142 p << ")";
143 p.printOptionalAttrDictWithKeyword(
144 (*this)->getAttrs(), {getSymNameAttrName(), getSequenceTypeAttrName()});
145 p << ' ';
146 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
147}
148
149StringAttr SequenceOp::getNameAttr() { return getSymNameAttr(); }
150
151mlir::SymbolTable::Visibility SequenceOp::getVisibility() {
152 return mlir::SymbolTable::Visibility::Private;
153}
154
155void SequenceOp::setVisibility(mlir::SymbolTable::Visibility visibility) {
156 // Do nothing, always private.
157 assert(false && "cannot change visibility of sequence");
158}
159
160//===----------------------------------------------------------------------===//
161// GetSequenceOp
162//===----------------------------------------------------------------------===//
163
164LogicalResult
165GetSequenceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
166 SequenceOp seq =
167 symbolTable.lookupNearestSymbolFrom<SequenceOp>(*this, getSequenceAttr());
168 if (!seq)
169 return emitOpError()
170 << "'" << getSequence()
171 << "' does not reference a valid 'rtg.sequence' operation";
172
173 if (seq.getSequenceType() != getType())
174 return emitOpError("referenced 'rtg.sequence' op's type does not match");
175
176 return success();
177}
178
179//===----------------------------------------------------------------------===//
180// SubstituteSequenceOp
181//===----------------------------------------------------------------------===//
182
183LogicalResult SubstituteSequenceOp::verify() {
184 if (getReplacements().empty())
185 return emitOpError("must at least have one replacement value");
186
187 if (getReplacements().size() >
188 getSequence().getType().getElementTypes().size())
189 return emitOpError(
190 "must not have more replacement values than sequence arguments");
191
192 if (getReplacements().getTypes() !=
193 getSequence().getType().getElementTypes().take_front(
194 getReplacements().size()))
195 return emitOpError("replacement types must match the same number of "
196 "sequence argument types from the front");
197
198 return success();
199}
200
201LogicalResult SubstituteSequenceOp::inferReturnTypes(
202 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
203 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
204 SmallVectorImpl<Type> &inferredReturnTypes) {
205 ArrayRef<Type> argTypes =
206 cast<SequenceType>(operands[0].getType()).getElementTypes();
207 auto seqType =
208 SequenceType::get(context, argTypes.drop_front(operands.size() - 1));
209 inferredReturnTypes.push_back(seqType);
210 return success();
211}
212
213ParseResult SubstituteSequenceOp::parse(::mlir::OpAsmParser &parser,
214 ::mlir::OperationState &result) {
215 OpAsmParser::UnresolvedOperand sequenceRawOperand;
216 SmallVector<OpAsmParser::UnresolvedOperand, 4> replacementsOperands;
217 Type sequenceRawType;
218
219 if (parser.parseOperand(sequenceRawOperand) || parser.parseLParen())
220 return failure();
221
222 auto replacementsOperandsLoc = parser.getCurrentLocation();
223 if (parser.parseOperandList(replacementsOperands) || parser.parseRParen() ||
224 parser.parseColon() || parser.parseType(sequenceRawType) ||
225 parser.parseOptionalAttrDict(result.attributes))
226 return failure();
227
228 if (!isa<SequenceType>(sequenceRawType))
229 return parser.emitError(parser.getNameLoc())
230 << "'sequence' must be handle to a sequence or sequence family, but "
231 "got "
232 << sequenceRawType;
233
234 if (parser.resolveOperand(sequenceRawOperand, sequenceRawType,
235 result.operands))
236 return failure();
237
238 if (parser.resolveOperands(replacementsOperands,
239 cast<SequenceType>(sequenceRawType)
240 .getElementTypes()
241 .take_front(replacementsOperands.size()),
242 replacementsOperandsLoc, result.operands))
243 return failure();
244
245 SmallVector<Type> inferredReturnTypes;
246 if (failed(inferReturnTypes(
247 parser.getContext(), result.location, result.operands,
248 result.attributes.getDictionary(parser.getContext()),
249 result.getRawProperties(), result.regions, inferredReturnTypes)))
250 return failure();
251
252 result.addTypes(inferredReturnTypes);
253 return success();
254}
255
256void SubstituteSequenceOp::print(OpAsmPrinter &p) {
257 p << ' ' << getSequence() << "(" << getReplacements()
258 << ") : " << getSequence().getType();
259 p.printOptionalAttrDict((*this)->getAttrs(), {});
260}
261
262//===----------------------------------------------------------------------===//
263// InterleaveSequencesOp
264//===----------------------------------------------------------------------===//
265
266LogicalResult InterleaveSequencesOp::verify() {
267 if (getSequences().empty())
268 return emitOpError("must have at least one sequence in the list");
269
270 return success();
271}
272
273OpFoldResult InterleaveSequencesOp::fold(FoldAdaptor adaptor) {
274 if (getSequences().size() == 1)
275 return getSequences()[0];
276
277 return {};
278}
279
280//===----------------------------------------------------------------------===//
281// SetCreateOp
282//===----------------------------------------------------------------------===//
283
284ParseResult SetCreateOp::parse(OpAsmParser &parser, OperationState &result) {
285 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
286 Type elemType;
287
288 if (parser.parseOperandList(operands) ||
289 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
290 parser.parseType(elemType))
291 return failure();
292
293 result.addTypes({SetType::get(result.getContext(), elemType)});
294
295 for (auto operand : operands)
296 if (parser.resolveOperand(operand, elemType, result.operands))
297 return failure();
298
299 return success();
300}
301
302void SetCreateOp::print(OpAsmPrinter &p) {
303 p << " ";
304 p.printOperands(getElements());
305 p.printOptionalAttrDict((*this)->getAttrs());
306 p << " : " << getSet().getType().getElementType();
307}
308
309LogicalResult SetCreateOp::verify() {
310 if (getElements().size() > 0) {
311 // We only need to check the first element because of the `SameTypeOperands`
312 // trait.
313 if (getElements()[0].getType() != getSet().getType().getElementType())
314 return emitOpError() << "operand types must match set element type";
315 }
316
317 return success();
318}
319
320//===----------------------------------------------------------------------===//
321// SetCartesianProductOp
322//===----------------------------------------------------------------------===//
323
324LogicalResult SetCartesianProductOp::inferReturnTypes(
325 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
326 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
327 SmallVectorImpl<Type> &inferredReturnTypes) {
328 if (operands.empty()) {
329 if (loc)
330 return mlir::emitError(*loc) << "at least one set must be provided";
331 return failure();
332 }
333
334 SmallVector<Type> elementTypes;
335 for (auto operand : operands)
336 elementTypes.push_back(cast<SetType>(operand.getType()).getElementType());
337 inferredReturnTypes.push_back(
338 SetType::get(rtg::TupleType::get(context, elementTypes)));
339 return success();
340}
341
342//===----------------------------------------------------------------------===//
343// BagCreateOp
344//===----------------------------------------------------------------------===//
345
346ParseResult BagCreateOp::parse(OpAsmParser &parser, OperationState &result) {
347 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> elementOperands,
348 multipleOperands;
349 Type elemType;
350
351 if (!parser.parseOptionalLParen()) {
352 while (true) {
353 OpAsmParser::UnresolvedOperand elementOperand, multipleOperand;
354 if (parser.parseOperand(multipleOperand) || parser.parseKeyword("x") ||
355 parser.parseOperand(elementOperand))
356 return failure();
357
358 elementOperands.push_back(elementOperand);
359 multipleOperands.push_back(multipleOperand);
360
361 if (parser.parseOptionalComma()) {
362 if (parser.parseRParen())
363 return failure();
364 break;
365 }
366 }
367 }
368
369 if (parser.parseColon() || parser.parseType(elemType) ||
370 parser.parseOptionalAttrDict(result.attributes))
371 return failure();
372
373 result.addTypes({BagType::get(result.getContext(), elemType)});
374
375 for (auto operand : elementOperands)
376 if (parser.resolveOperand(operand, elemType, result.operands))
377 return failure();
378
379 for (auto operand : multipleOperands)
380 if (parser.resolveOperand(operand, IndexType::get(result.getContext()),
381 result.operands))
382 return failure();
383
384 return success();
385}
386
387void BagCreateOp::print(OpAsmPrinter &p) {
388 p << " ";
389 if (!getElements().empty())
390 p << "(";
391 llvm::interleaveComma(llvm::zip(getElements(), getMultiples()), p,
392 [&](auto elAndMultiple) {
393 auto [el, multiple] = elAndMultiple;
394 p << multiple << " x " << el;
395 });
396 if (!getElements().empty())
397 p << ")";
398
399 p << " : " << getBag().getType().getElementType();
400 p.printOptionalAttrDict((*this)->getAttrs());
401}
402
403LogicalResult BagCreateOp::verify() {
404 if (!llvm::all_equal(getElements().getTypes()))
405 return emitOpError() << "types of all elements must match";
406
407 if (getElements().size() > 0)
408 if (getElements()[0].getType() != getBag().getType().getElementType())
409 return emitOpError() << "operand types must match bag element type";
410
411 return success();
412}
413
414//===----------------------------------------------------------------------===//
415// TupleCreateOp
416//===----------------------------------------------------------------------===//
417
418LogicalResult TupleCreateOp::inferReturnTypes(
419 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
420 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
421 SmallVectorImpl<Type> &inferredReturnTypes) {
422 SmallVector<Type> elementTypes;
423 for (auto operand : operands)
424 elementTypes.push_back(operand.getType());
425 inferredReturnTypes.push_back(rtg::TupleType::get(context, elementTypes));
426 return success();
427}
428
429//===----------------------------------------------------------------------===//
430// TupleExtractOp
431//===----------------------------------------------------------------------===//
432
433LogicalResult TupleExtractOp::inferReturnTypes(
434 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
435 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
436 SmallVectorImpl<Type> &inferredReturnTypes) {
437 assert(operands.size() == 1 && "must have exactly one operand");
438
439 auto tupleTy = dyn_cast<rtg::TupleType>(operands[0].getType());
440 size_t idx = properties.as<Properties *>()->getIndex().getInt();
441 if (!tupleTy) {
442 if (loc)
443 return mlir::emitError(*loc) << "only RTG tuples are supported";
444 return failure();
445 }
446
447 if (tupleTy.getFieldTypes().size() <= idx) {
448 if (loc)
449 return mlir::emitError(*loc)
450 << "index (" << idx
451 << ") must be smaller than number of elements in tuple ("
452 << tupleTy.getFieldTypes().size() << ")";
453 return failure();
454 }
455
456 inferredReturnTypes.push_back(tupleTy.getFieldTypes()[idx]);
457 return success();
458}
459
460//===----------------------------------------------------------------------===//
461// ConstraintOp
462//===----------------------------------------------------------------------===//
463
464LogicalResult ConstraintOp::canonicalize(ConstraintOp op,
465 PatternRewriter &rewriter) {
466 if (mlir::matchPattern(op.getCondition(), mlir::m_One())) {
467 rewriter.eraseOp(op);
468 return success();
469 }
470
471 return failure();
472}
473
474//===----------------------------------------------------------------------===//
475// VirtualRegisterOp
476//===----------------------------------------------------------------------===//
477
478LogicalResult VirtualRegisterOp::inferReturnTypes(
479 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
480 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
481 SmallVectorImpl<Type> &inferredReturnTypes) {
482 auto allowedRegs = properties.as<Properties *>()->getAllowedRegs();
483 inferredReturnTypes.push_back(allowedRegs.getType());
484 return success();
485}
486
487//===----------------------------------------------------------------------===//
488// RegisterToIndexOp
489//===----------------------------------------------------------------------===//
490
491OpFoldResult RegisterToIndexOp::fold(FoldAdaptor adaptor) {
492 if (auto reg = dyn_cast_or_null<rtg::RegisterAttrInterface>(adaptor.getReg()))
493 return IntegerAttr::get(IndexType::get(getContext()), reg.getClassIndex());
494
495 if (auto indexToRegOp = getReg().getDefiningOp<IndexToRegisterOp>())
496 return indexToRegOp.getIndex();
497
498 return {};
499}
500
501//===----------------------------------------------------------------------===//
502// IndexToRegisterOp
503//===----------------------------------------------------------------------===//
504
505LogicalResult IndexToRegisterOp::verify() {
506 // Check if the index is a constant and if it's within valid range
507 APInt indexValue;
508 if (matchPattern(getIndex(), m_ConstantInt(&indexValue))) {
509 if (indexValue.uge(getType().getRegisterClassSize())) {
510 SmallString<16> indexStr;
511 indexValue.toString(indexStr, 10, false);
512 return emitOpError() << "index " << indexStr
513 << " is out of range for register class "
514 << getReg().getType();
515 }
516 }
517
518 return success();
519}
520
521OpFoldResult IndexToRegisterOp::fold(FoldAdaptor adaptor) {
522 if (auto indexAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getIndex()))
523 return getType().getRegisterAttrForClassIndex(
524 getContext(), indexAttr.getValue().getZExtValue());
525
526 return {};
527}
528
529//===----------------------------------------------------------------------===//
530// ContextSwitchOp
531//===----------------------------------------------------------------------===//
532
533LogicalResult ContextSwitchOp::verify() {
534 auto elementTypes = getSequence().getType().getElementTypes();
535 if (elementTypes.size() != 3)
536 return emitOpError("sequence type must have exactly 3 element types");
537
538 if (getFrom().getType() != elementTypes[0])
539 return emitOpError(
540 "first sequence element type must match 'from' attribute type");
541
542 if (getTo().getType() != elementTypes[1])
543 return emitOpError(
544 "second sequence element type must match 'to' attribute type");
545
546 auto seqTy = dyn_cast<SequenceType>(elementTypes[2]);
547 if (!seqTy || !seqTy.getElementTypes().empty())
548 return emitOpError(
549 "third sequence element type must be a fully substituted sequence");
550
551 return success();
552}
553
554//===----------------------------------------------------------------------===//
555// TestOp
556//===----------------------------------------------------------------------===//
557
558LogicalResult TestOp::verifyRegions() {
559 if (!getTargetType().entryTypesMatch(getBody()->getArgumentTypes()))
560 return emitOpError("argument types must match dict entry types");
561
562 return success();
563}
564
565LogicalResult TestOp::verify() {
566 if (getTemplateName().empty())
567 return emitOpError("template name must not be empty");
568
569 return success();
570}
571
572LogicalResult TestOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
573 if (!getTargetAttr())
574 return success();
575
576 auto target =
577 symbolTable.lookupNearestSymbolFrom<TargetOp>(*this, getTargetAttr());
578 if (!target)
579 return emitOpError()
580 << "'" << *getTarget()
581 << "' does not reference a valid 'rtg.target' operation";
582
583 // Check if target is a subtype of test requirements
584 // Since entries are sorted by name, we can do this in a single pass
585 size_t targetIdx = 0;
586 auto targetEntries = target.getTarget().getEntries();
587 for (auto testEntry : getTargetType().getEntries()) {
588 // Find the matching entry in target entries.
589 while (targetIdx < targetEntries.size() &&
590 targetEntries[targetIdx].name.getValue() < testEntry.name.getValue())
591 targetIdx++;
592
593 // Check if we found a matching entry with the same name and type
594 if (targetIdx >= targetEntries.size() ||
595 targetEntries[targetIdx].name != testEntry.name ||
596 targetEntries[targetIdx].type != testEntry.type) {
597 return emitOpError("referenced 'rtg.target' op's type is invalid: "
598 "missing entry called '")
599 << testEntry.name.getValue() << "' of type " << testEntry.type;
600 }
601 }
602
603 return success();
604}
605
606ParseResult TestOp::parse(OpAsmParser &parser, OperationState &result) {
607 // Parse the name as a symbol.
608 StringAttr symNameAttr;
609 if (parser.parseSymbolName(symNameAttr))
610 return failure();
611
612 result.getOrAddProperties<TestOp::Properties>().sym_name = symNameAttr;
613
614 // Parse the function signature.
615 SmallVector<OpAsmParser::Argument> arguments;
616 SmallVector<StringAttr> names;
617
618 auto parseOneArgument = [&]() -> ParseResult {
619 std::string name;
620 if (parser.parseKeywordOrString(&name) || parser.parseEqual() ||
621 parser.parseArgument(arguments.emplace_back(), /*allowType=*/true,
622 /*allowAttrs=*/true))
623 return failure();
624
625 names.push_back(StringAttr::get(result.getContext(), name));
626 return success();
627 };
628 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
629 parseOneArgument, " in argument list"))
630 return failure();
631
632 SmallVector<Type> argTypes;
633 SmallVector<DictEntry> entries;
634 SmallVector<Location> argLocs;
635 argTypes.reserve(arguments.size());
636 argLocs.reserve(arguments.size());
637 for (auto [name, arg] : llvm::zip(names, arguments)) {
638 argTypes.push_back(arg.type);
639 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
640 entries.push_back({name, arg.type});
641 }
642 auto emitError = [&]() -> InFlightDiagnostic {
643 return parser.emitError(parser.getCurrentLocation());
644 };
645 Type type = DictType::getChecked(emitError, result.getContext(),
646 ArrayRef<DictEntry>(entries));
647 if (!type)
648 return failure();
649 result.getOrAddProperties<TestOp::Properties>().targetType =
650 TypeAttr::get(type);
651
652 std::string templateName;
653 if (!parser.parseOptionalKeyword("template")) {
654 auto loc = parser.getCurrentLocation();
655 if (parser.parseString(&templateName))
656 return failure();
657
658 if (templateName.empty())
659 return parser.emitError(loc, "template name must not be empty");
660 }
661
662 StringAttr templateNameAttr = symNameAttr;
663 if (!templateName.empty())
664 templateNameAttr = StringAttr::get(result.getContext(), templateName);
665
666 StringAttr targetName;
667 if (!parser.parseOptionalKeyword("target"))
668 if (parser.parseSymbolName(targetName))
669 return failure();
670
671 result.getOrAddProperties<TestOp::Properties>().templateName =
672 templateNameAttr;
673 result.getOrAddProperties<TestOp::Properties>().target = targetName;
674
675 auto loc = parser.getCurrentLocation();
676 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
677 return failure();
678 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
679 return parser.emitError(loc)
680 << "'" << result.name.getStringRef() << "' op ";
681 })))
682 return failure();
683
684 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
685 if (parser.parseRegion(*bodyRegionRegion, arguments))
686 return failure();
687
688 if (bodyRegionRegion->empty()) {
689 bodyRegionRegion->emplaceBlock();
690 bodyRegionRegion->addArguments(argTypes, argLocs);
691 }
692 result.addRegion(std::move(bodyRegionRegion));
693
694 return success();
695}
696
697void TestOp::print(OpAsmPrinter &p) {
698 p << ' ';
699 p.printSymbolName(getSymNameAttr().getValue());
700 p << "(";
701 SmallString<32> resultNameStr;
702 llvm::interleaveComma(
703 llvm::zip(getTargetType().getEntries(), getBody()->getArguments()), p,
704 [&](auto entryAndArg) {
705 auto [entry, arg] = entryAndArg;
706 p << entry.name.getValue() << " = ";
707 p.printRegionArgument(arg);
708 });
709 p << ")";
710
711 if (getSymNameAttr() != getTemplateNameAttr())
712 p << " template " << getTemplateNameAttr();
713
714 if (getTargetAttr()) {
715 p << " target ";
716 p.printSymbolName(getTargetAttr().getValue());
717 }
718
719 p.printOptionalAttrDictWithKeyword(
720 (*this)->getAttrs(), {getSymNameAttrName(), getTargetTypeAttrName(),
721 getTargetAttrName(), getTemplateNameAttrName()});
722 p << ' ';
723 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
724}
725
726void TestOp::getAsmBlockArgumentNames(Region &region,
727 OpAsmSetValueNameFn setNameFn) {
728 for (auto [entry, arg] :
729 llvm::zip(getTargetType().getEntries(), region.getArguments()))
730 setNameFn(arg, entry.name.getValue());
731}
732
733//===----------------------------------------------------------------------===//
734// TargetOp
735//===----------------------------------------------------------------------===//
736
737LogicalResult TargetOp::verifyRegions() {
738 if (!getTarget().entryTypesMatch(
739 getBody()->getTerminator()->getOperandTypes()))
740 return emitOpError("terminator operand types must match dict entry types");
741
742 return success();
743}
744
745//===----------------------------------------------------------------------===//
746// ValidateOp
747//===----------------------------------------------------------------------===//
748
749LogicalResult ValidateOp::verify() {
750 if (!getRef().getType().isValidContentType(getValue().getType()))
751 return emitOpError(
752 "result type must be a valid content type for the ref value");
753
754 return success();
755}
756
757bool ValidateOp::isSourceRegister(unsigned index) {
758 if (index == 0)
759 return isa<RegisterTypeInterface>(getRef().getType());
760 return false;
761}
762
763bool ValidateOp::isDestinationRegister(unsigned index) { return false; }
764
765//===----------------------------------------------------------------------===//
766// ArrayCreateOp
767//===----------------------------------------------------------------------===//
768
769LogicalResult ArrayCreateOp::verify() {
770 if (!getElements().empty() &&
771 getElements()[0].getType() != getType().getElementType())
772 return emitOpError("operand types must match array element type, expected ")
773 << getType().getElementType() << " but got "
774 << getElements()[0].getType();
775
776 return success();
777}
778
779ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
780 SmallVector<OpAsmParser::UnresolvedOperand> operands;
781 Type elementType;
782
783 if (parser.parseOperandList(operands) || parser.parseColon() ||
784 parser.parseType(elementType) ||
785 parser.parseOptionalAttrDict(result.attributes))
786 return failure();
787
788 if (failed(parser.resolveOperands(operands, elementType, result.operands)))
789 return failure();
790
791 result.addTypes(ArrayType::get(elementType));
792
793 return success();
794}
795
796void ArrayCreateOp::print(OpAsmPrinter &p) {
797 p << ' ';
798 p.printOperands(getElements());
799 p << " : " << getType().getElementType();
800 p.printOptionalAttrDict((*this)->getAttrs(), {});
801}
802
803//===----------------------------------------------------------------------===//
804// ArrayAppendOp
805//===----------------------------------------------------------------------===//
806
807LogicalResult ArrayAppendOp::canonicalize(ArrayAppendOp op,
808 PatternRewriter &rewriter) {
809 auto createOp = op.getArray().getDefiningOp<ArrayCreateOp>();
810 if (!createOp)
811 return failure();
812
813 SmallVector<Value> newElements(createOp.getElements());
814 newElements.push_back(op.getElement());
815 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(), newElements);
816 return success();
817}
818
819//===----------------------------------------------------------------------===//
820// MemoryBlockDeclareOp
821//===----------------------------------------------------------------------===//
822
823LogicalResult MemoryBlockDeclareOp::verify() {
824 if (getBaseAddress().getBitWidth() != getType().getAddressWidth())
825 return emitOpError(
826 "base address width must match memory block address width");
827
828 if (getEndAddress().getBitWidth() != getType().getAddressWidth())
829 return emitOpError(
830 "end address width must match memory block address width");
831
832 if (getBaseAddress().ugt(getEndAddress()))
833 return emitOpError(
834 "base address must be smaller than or equal to the end address");
835
836 return success();
837}
838
839ParseResult MemoryBlockDeclareOp::parse(OpAsmParser &parser,
840 OperationState &result) {
841 SmallVector<OpAsmParser::UnresolvedOperand> operands;
842 MemoryBlockType memoryBlockType;
843 APInt start, end;
844
845 if (parser.parseLSquare())
846 return failure();
847
848 auto startLoc = parser.getCurrentLocation();
849 if (parser.parseInteger(start))
850 return failure();
851
852 if (parser.parseMinus())
853 return failure();
854
855 auto endLoc = parser.getCurrentLocation();
856 if (parser.parseInteger(end) || parser.parseRSquare() ||
857 parser.parseColonType(memoryBlockType) ||
858 parser.parseOptionalAttrDict(result.attributes))
859 return failure();
860
861 auto width = memoryBlockType.getAddressWidth();
862 auto adjustAPInt = [&](APInt value, llvm::SMLoc loc) -> FailureOr<APInt> {
863 if (value.getBitWidth() > width) {
864 if (!value.isIntN(width))
865 return parser.emitError(
866 loc,
867 "address out of range for memory block with address width ")
868 << width;
869
870 return value.trunc(width);
871 }
872
873 if (value.getBitWidth() < width)
874 return value.zext(width);
875
876 return value;
877 };
878
879 auto startRes = adjustAPInt(start, startLoc);
880 auto endRes = adjustAPInt(end, endLoc);
881 if (failed(startRes) || failed(endRes))
882 return failure();
883
884 auto intType = IntegerType::get(result.getContext(), width);
885 result.addAttribute(getBaseAddressAttrName(result.name),
886 IntegerAttr::get(intType, *startRes));
887 result.addAttribute(getEndAddressAttrName(result.name),
888 IntegerAttr::get(intType, *endRes));
889
890 result.addTypes(memoryBlockType);
891 return success();
892}
893
894void MemoryBlockDeclareOp::print(OpAsmPrinter &p) {
895 SmallVector<char> str;
896 getBaseAddress().toString(str, 16, false, false, false);
897 p << " [0x" << str;
898 p << " - 0x";
899 str.clear();
900 getEndAddress().toString(str, 16, false, false, false);
901 p << str << "] : " << getType();
902 p.printOptionalAttrDict((*this)->getAttrs(),
903 {getBaseAddressAttrName(), getEndAddressAttrName()});
904}
905
906//===----------------------------------------------------------------------===//
907// MemoryBaseAddressOp
908//===----------------------------------------------------------------------===//
909
910LogicalResult MemoryBaseAddressOp::inferReturnTypes(
911 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
912 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
913 SmallVectorImpl<Type> &inferredReturnTypes) {
914 if (operands.empty())
915 return failure();
916 auto memTy = dyn_cast<MemoryType>(operands[0].getType());
917 if (!memTy)
918 return failure();
919 inferredReturnTypes.push_back(
920 IntegerType::get(context, memTy.getAddressWidth()));
921 return success();
922}
923
924//===----------------------------------------------------------------------===//
925// ConcatImmediateOp
926//===----------------------------------------------------------------------===//
927
928LogicalResult ConcatImmediateOp::inferReturnTypes(
929 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
930 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
931 SmallVectorImpl<Type> &inferredReturnTypes) {
932 if (operands.empty()) {
933 if (loc)
934 return mlir::emitError(*loc) << "at least one operand must be provided";
935 return failure();
936 }
937
938 unsigned totalWidth = 0;
939 for (auto operand : operands) {
940 auto immType = dyn_cast<IntegerType>(operand.getType());
941 if (!immType) {
942 if (loc)
943 return mlir::emitError(*loc)
944 << "all operands must be of immediate type";
945 return failure();
946 }
947 totalWidth += immType.getWidth();
948 }
949
950 inferredReturnTypes.push_back(IntegerType::get(context, totalWidth));
951 return success();
952}
953
954OpFoldResult ConcatImmediateOp::fold(FoldAdaptor adaptor) {
955 // concat(x) -> x
956 if (getOperands().size() == 1)
957 return getOperands()[0];
958
959 // If all operands are constants, fold into a single constant
960 if (llvm::all_of(adaptor.getOperands(), [](Attribute attr) {
961 return isa_and_nonnull<IntegerAttr>(attr);
962 })) {
963 auto result = APInt::getZeroWidth();
964 for (auto attr : adaptor.getOperands())
965 result = result.concat(cast<IntegerAttr>(attr).getValue());
966
967 return IntegerAttr::get(
968 IntegerType::get(getContext(), result.getBitWidth()), result);
969 }
970
971 return {};
972}
973
974//===----------------------------------------------------------------------===//
975// SliceImmediateOp
976//===----------------------------------------------------------------------===//
977
978LogicalResult SliceImmediateOp::verify() {
979 auto srcWidth = getInput().getType().getWidth();
980 auto dstWidth = getResult().getType().getWidth();
981
982 if (getLowBit() >= srcWidth)
983 return emitOpError("from bit too large for input (got ")
984 << getLowBit() << ", but input width is " << srcWidth << ")";
985
986 if (srcWidth - getLowBit() < dstWidth)
987 return emitOpError("slice does not fit in input (trying to extract ")
988 << dstWidth << " bits starting at index " << getLowBit()
989 << ", but only " << (srcWidth - getLowBit())
990 << " bits are available)";
991
992 return success();
993}
994
995OpFoldResult SliceImmediateOp::fold(FoldAdaptor adaptor) {
996 if (auto inputAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput())) {
997 auto resultWidth = getType().getWidth();
998 APInt sliced = inputAttr.getValue().extractBits(resultWidth, getLowBit());
999 return IntegerAttr::get(
1000 IntegerType::get(getContext(), sliced.getBitWidth()), sliced);
1001 }
1002
1003 return {};
1004}
1005
1006//===----------------------------------------------------------------------===//
1007// StringConcatOp
1008//===----------------------------------------------------------------------===//
1009
1010OpFoldResult StringConcatOp::fold(FoldAdaptor adaptor) {
1011 SmallString<32> result;
1012 for (auto attr : adaptor.getStrings()) {
1013 auto stringAttr = dyn_cast_or_null<StringAttr>(attr);
1014 if (!stringAttr)
1015 return {};
1016
1017 result += stringAttr.getValue();
1018 }
1019
1020 return StringAttr::get(result, StringType::get(getContext()));
1021}
1022
1023//===----------------------------------------------------------------------===//
1024// IntFormatOp
1025//===----------------------------------------------------------------------===//
1026
1027OpFoldResult IntFormatOp::fold(FoldAdaptor adaptor) {
1028 auto intAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getValue());
1029 if (!intAttr)
1030 return {};
1031 if (!intAttr.getType().isIndex())
1032 return {};
1033 return StringAttr::get(Twine(intAttr.getValue().getZExtValue()),
1034 StringType::get(getContext()));
1035}
1036
1037//===----------------------------------------------------------------------===//
1038// ImmediateFormatOp
1039//===----------------------------------------------------------------------===//
1040
1041OpFoldResult ImmediateFormatOp::fold(FoldAdaptor adaptor) {
1042 auto immAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getValue());
1043 if (!immAttr)
1044 return {};
1045 SmallString<16> strBuf("0x");
1046 immAttr.getValue().toString(strBuf, 16, /*Signed=*/false);
1047 return StringAttr::get(strBuf, StringType::get(getContext()));
1048}
1049
1050//===----------------------------------------------------------------------===//
1051// RegisterFormatOp
1052//===----------------------------------------------------------------------===//
1053
1054OpFoldResult RegisterFormatOp::fold(FoldAdaptor adaptor) {
1055 auto regAttr = dyn_cast_or_null<RegisterAttrInterface>(adaptor.getValue());
1056 if (!regAttr)
1057 return {};
1058 return StringAttr::get(regAttr.getRegisterAssembly(),
1059 StringType::get(getContext()));
1060}
1061
1062//===----------------------------------------------------------------------===//
1063// StringToLabelOp
1064//===----------------------------------------------------------------------===//
1065
1066OpFoldResult StringToLabelOp::fold(FoldAdaptor adaptor) {
1067 if (auto stringAttr = dyn_cast_or_null<StringAttr>(adaptor.getString()))
1068 return LabelAttr::get(getContext(), stringAttr.getValue());
1069
1070 return {};
1071}
1072
1073//===----------------------------------------------------------------------===//
1074// StringToASCIIArrayOp
1075//===----------------------------------------------------------------------===//
1076
1077LogicalResult StringToASCIIArrayOp::canonicalize(StringToASCIIArrayOp op,
1078 PatternRewriter &rewriter) {
1079 auto constOp = op.getString().getDefiningOp<ConstantOp>();
1080 if (!constOp)
1081 return failure();
1082
1083 auto strAttr = dyn_cast<StringAttr>(constOp.getValue());
1084 if (!strAttr)
1085 return failure();
1086
1087 auto i8Ty = rewriter.getIntegerType(8);
1088 SmallVector<Value> bytes;
1089 bytes.reserve(strAttr.getValue().size());
1090 for (unsigned char c : strAttr.getValue())
1091 bytes.push_back(ConstantOp::create(rewriter, op.getLoc(),
1092 rewriter.getIntegerAttr(i8Ty, c)));
1093
1094 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(), bytes);
1095 return success();
1096}
1097
1098//===----------------------------------------------------------------------===//
1099// MutCreateOp
1100//===----------------------------------------------------------------------===//
1101
1102void MutCreateOp::getEffects(
1103 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1104 &effects) {
1105 effects.emplace_back(MemoryEffects::Allocate::get(), cast<OpResult>(getRef()),
1106 MutResource::get());
1107}
1108
1109LogicalResult MutCreateOp::verify() {
1110 auto mutTy = cast<MutType>(getRef().getType());
1111 if (mutTy.getElementType() != getInitialValue().getType())
1112 return emitOpError("initial value type ")
1113 << getInitialValue().getType() << " does not match mut element type "
1114 << mutTy.getElementType();
1115 return success();
1116}
1117
1118//===----------------------------------------------------------------------===//
1119// MutReadOp
1120//===----------------------------------------------------------------------===//
1121
1122void MutReadOp::getEffects(
1123 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1124 &effects) {
1125 effects.emplace_back(MemoryEffects::Read::get(), &getRefMutable(),
1126 MutResource::get());
1127}
1128
1129LogicalResult MutReadOp::verify() {
1130 auto mutTy = cast<MutType>(getRef().getType());
1131 if (mutTy.getElementType() != getValue().getType())
1132 return emitOpError("result type ")
1133 << getValue().getType() << " does not match mut element type "
1134 << mutTy.getElementType();
1135 return success();
1136}
1137
1138//===----------------------------------------------------------------------===//
1139// MutWriteOp
1140//===----------------------------------------------------------------------===//
1141
1142void MutWriteOp::getEffects(
1143 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
1144 &effects) {
1145 effects.emplace_back(MemoryEffects::Write::get(), &getRefMutable(),
1146 MutResource::get());
1147}
1148
1149LogicalResult MutWriteOp::verify() {
1150 auto mutTy = cast<MutType>(getRef().getType());
1151 if (mutTy.getElementType() != getNewValue().getType())
1152 return emitOpError("new value type ")
1153 << getNewValue().getType() << " does not match mut element type "
1154 << mutTy.getElementType();
1155 return success();
1156}
1157
1158//===----------------------------------------------------------------------===//
1159// WithHandlersOp (algebraic effects)
1160//===----------------------------------------------------------------------===//
1161
1162ParseResult WithHandlersOp::parse(OpAsmParser &parser, OperationState &result) {
1163 // Syntax:
1164 // rtg.with_handlers {
1165 // handle @effect(arg: type, ...) { region }
1166 // ...
1167 // do { region }
1168 // }
1169 SmallVector<Attribute> effectSymbols;
1170 SmallVector<std::unique_ptr<Region>> handlerRegions;
1171
1172 if (parser.parseLBrace())
1173 return failure();
1174
1175 while (true) {
1176 // Stop when we see the 'do' keyword.
1177 if (succeeded(parser.parseOptionalKeyword("do")))
1178 break;
1179
1180 // 'handle' keyword
1181 if (parser.parseKeyword("handle"))
1182 return failure();
1183
1184 // @effect-symbol
1185 FlatSymbolRefAttr sym;
1186 if (parser.parseAttribute(sym))
1187 return failure();
1188 effectSymbols.push_back(sym);
1189
1190 // (arg: type, ...) — these become the entry block args of the handler.
1191 SmallVector<OpAsmParser::Argument> args;
1192 if (parser.parseArgumentList(args, OpAsmParser::Delimiter::Paren,
1193 /*allowType=*/true))
1194 return failure();
1195
1196 // { handler-body }
1197 auto handler = std::make_unique<Region>();
1198 if (parser.parseRegion(*handler, args))
1199 return failure();
1200 if (handler->empty())
1201 handler->emplaceBlock();
1202 handlerRegions.push_back(std::move(handler));
1203 }
1204
1205 // Set property (inherent attribute)
1206 auto &props = result.getOrAddProperties<WithHandlersOp::Properties>();
1207 props.effects = ArrayAttr::get(parser.getContext(), effectSymbols);
1208
1209 // Parse the do-body region (the 'do' keyword was already consumed above).
1210 Region *body = result.addRegion();
1211 if (parser.parseRegion(*body))
1212 return failure();
1213 if (body->empty())
1214 body->emplaceBlock();
1215
1216 // Move handler regions into the op (body is region[0], handlers follow).
1217 for (auto &h : handlerRegions) {
1218 Region *hr = result.addRegion();
1219 hr->takeBody(*h);
1220 }
1221
1222 if (parser.parseRBrace() || parser.parseOptionalAttrDict(result.attributes))
1223 return failure();
1224
1225 return success();
1226}
1227
1228void WithHandlersOp::print(OpAsmPrinter &printer) {
1229 printer << " {";
1230 printer.increaseIndent();
1231 for (auto [symAttr, handlerRegion] :
1232 llvm::zip(getEffects(), getHandlerRegions())) {
1233 printer.printNewline();
1234 printer << "handle " << symAttr << "(";
1235 bool first = true;
1236 for (BlockArgument arg : handlerRegion.front().getArguments()) {
1237 if (!first)
1238 printer << ", ";
1239 first = false;
1240 printer.printRegionArgument(arg);
1241 }
1242 printer << ") ";
1243 printer.printRegion(handlerRegion, /*printEntryBlockArgs=*/false);
1244 }
1245 printer.printNewline();
1246 printer << "do ";
1247 printer.printRegion(getBody());
1248 printer.decreaseIndent();
1249 printer.printNewline();
1250 printer << "}";
1251 // effects is a property (inherent), print discardable attributes only
1252 printer.printOptionalAttrDict(
1253 (*this)->getDiscardableAttrDictionary().getValue());
1254}
1255
1256LogicalResult WithHandlersOp::verify() {
1257 auto effects = getEffects();
1258 if (effects.size() != getHandlerRegions().size())
1259 return emitOpError("effects.size() (")
1260 << effects.size() << ") != handlerRegions.size() ("
1261 << getHandlerRegions().size() << ")";
1262
1263 llvm::SmallDenseSet<StringAttr> seen;
1264 for (auto attr : effects) {
1265 auto sym = cast<FlatSymbolRefAttr>(attr).getAttr();
1266 if (!seen.insert(sym).second)
1267 return emitOpError("duplicate handler for effect '")
1268 << sym.getValue() << "'";
1269 }
1270 return success();
1271}
1272
1273LogicalResult
1274WithHandlersOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1275 auto moduleOp = (*this)->getParentOfType<ModuleOp>();
1276 if (!moduleOp)
1277 return emitOpError("must be inside a module");
1278
1279 for (auto [idx, symAttr] : llvm::enumerate(getEffects())) {
1280 auto ref = dyn_cast<FlatSymbolRefAttr>(symAttr);
1281 if (!ref)
1282 return emitOpError("effects[") << idx << "] is not a symbol reference";
1283
1284 auto decl = symbolTable.lookupNearestSymbolFrom<EffectOp>(moduleOp, ref);
1285 if (!decl)
1286 return emitOpError("unresolved effect symbol '") << ref.getValue() << "'";
1287
1288 // Verify handler region block argument types.
1289 Region &handlerRegion = getHandlerRegions()[idx];
1290 if (handlerRegion.empty())
1291 return emitOpError("handler region ") << idx << " is empty";
1292
1293 Block &handlerBlock = handlerRegion.front();
1294 FunctionType ft = decl.getFunctionType();
1295 auto inputTypes = ft.getInputs();
1296 auto resultTypes = ft.getResults();
1297
1298 // Expected: input types + continuation<result>
1299 Type resumeType =
1300 resultTypes.empty() ? NoneType::get(getContext()) : resultTypes[0];
1301 size_t expectedArgs = inputTypes.size() + 1;
1302
1303 if (handlerBlock.getNumArguments() != expectedArgs)
1304 return emitOpError("handler region ")
1305 << idx << " expects " << expectedArgs << " block args but has "
1306 << handlerBlock.getNumArguments();
1307
1308 for (auto [argIdx, argType] : llvm::enumerate(inputTypes)) {
1309 if (handlerBlock.getArgument(argIdx).getType() != argType)
1310 return emitOpError("handler region ")
1311 << idx << " block arg " << argIdx << " has type "
1312 << handlerBlock.getArgument(argIdx).getType() << " but expected "
1313 << argType;
1314 }
1315
1316 auto contTy = ContinuationType::get(getContext(), resumeType);
1317 if (handlerBlock.getArgument(inputTypes.size()).getType() != contTy)
1318 return emitOpError("handler region ")
1319 << idx << " continuation arg has type "
1320 << handlerBlock.getArgument(inputTypes.size()).getType()
1321 << " but expected " << contTy;
1322 }
1323
1324 return success();
1325}
1326
1327//===----------------------------------------------------------------------===//
1328// PerformOp
1329//===----------------------------------------------------------------------===//
1330
1331ParseResult PerformOp::parse(OpAsmParser &parser, OperationState &result) {
1332 // Parse: @effect `(` operands `)` `:` `(` inputTypes `)` `->` resultType
1333 FlatSymbolRefAttr effectAttr;
1334 if (parser.parseAttribute(effectAttr))
1335 return failure();
1336 result.getOrAddProperties<PerformOp::Properties>().effect = effectAttr;
1337
1338 SmallVector<OpAsmParser::UnresolvedOperand> operands;
1339 if (parser.parseOperandList(operands, OpAsmParser::Delimiter::Paren))
1340 return failure();
1341
1342 if (parser.parseColon())
1343 return failure();
1344
1345 SmallVector<Type> operandTypes;
1346 if (parser.parseLParen())
1347 return failure();
1348 if (succeeded(parser.parseOptionalRParen())) {
1349 // empty operand list
1350 } else {
1351 if (parser.parseTypeList(operandTypes) || parser.parseRParen())
1352 return failure();
1353 }
1354
1355 if (parser.parseArrow())
1356 return failure();
1357
1358 Type resultType;
1359 if (parser.parseType(resultType))
1360 return failure();
1361
1362 if (parser.resolveOperands(operands, operandTypes,
1363 parser.getCurrentLocation(), result.operands))
1364 return failure();
1365
1366 if (!isa<NoneType>(resultType))
1367 result.addTypes(resultType);
1368
1369 if (parser.parseOptionalAttrDict(result.attributes))
1370 return failure();
1371
1372 return success();
1373}
1374
1375void PerformOp::print(OpAsmPrinter &printer) {
1376 printer << " " << getEffectAttr() << "(";
1377 llvm::interleaveComma(getOperands(), printer, [&](Value v) { printer << v; });
1378 printer << ") : (";
1379 llvm::interleaveComma(getOperands(), printer,
1380 [&](Value v) { printer << v.getType(); });
1381 printer << ") -> ";
1382 if (getResult())
1383 printer << getResult().getType();
1384 else
1385 printer << NoneType::get(getContext());
1386 // effect is a property (inherent), print discardable attributes only
1387 printer.printOptionalAttrDict(
1388 (*this)->getDiscardableAttrDictionary().getValue());
1389}
1390
1391LogicalResult PerformOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1392 auto moduleOp = (*this)->getParentOfType<ModuleOp>();
1393 if (!moduleOp)
1394 return emitOpError("must be inside a module");
1395
1396 auto decl =
1397 symbolTable.lookupNearestSymbolFrom<EffectOp>(moduleOp, getEffectAttr());
1398 if (!decl)
1399 return emitOpError("unresolved effect symbol '") << getEffect() << "'";
1400
1401 FunctionType ft = decl.getFunctionType();
1402 auto inputTypes = ft.getInputs();
1403 auto resultTypes = ft.getResults();
1404
1405 if (getOperands().size() != inputTypes.size())
1406 return emitOpError("effect '")
1407 << getEffect() << "' expects " << inputTypes.size()
1408 << " inputs but got " << getOperands().size();
1409
1410 for (auto [idx, opType, declType] :
1411 llvm::enumerate(getOperandTypes(), inputTypes)) {
1412 if (opType != declType)
1413 return emitOpError("operand ") << idx << " has type " << opType
1414 << " but effect declares " << declType;
1415 }
1416
1417 if (resultTypes.empty()) {
1418 if (getResult())
1419 return emitOpError("effect '")
1420 << getEffect() << "' returns none but perform has a result";
1421 } else {
1422 if (!getResult())
1423 return emitOpError("effect '")
1424 << getEffect() << "' returns " << resultTypes[0]
1425 << " but perform has no result";
1426 if (getResult().getType() != resultTypes[0])
1427 return emitOpError("result type ")
1428 << getResult().getType() << " does not match effect result type "
1429 << resultTypes[0];
1430 }
1431
1432 return success();
1433}
1434
1435//===----------------------------------------------------------------------===//
1436// ResumeOp
1437//===----------------------------------------------------------------------===//
1438
1439LogicalResult ResumeOp::verify() {
1440 auto contTy = cast<ContinuationType>(getContinuation().getType());
1441 Type resumeType = contTy.getResumeType();
1442
1443 if (isa<NoneType>(resumeType)) {
1444 if (getValue())
1445 return emitOpError(
1446 "continuation expects none but resume provides a value");
1447 } else {
1448 if (!getValue())
1449 return emitOpError("continuation expects ")
1450 << resumeType << " but resume provides no value";
1451 if (getValue().getType() != resumeType)
1452 return emitOpError("resume value type ")
1453 << getValue().getType()
1454 << " does not match continuation resume type " << resumeType;
1455 }
1456
1457 return success();
1458}
1459
1460//===----------------------------------------------------------------------===//
1461// TableGen generated logic.
1462//===----------------------------------------------------------------------===//
1463
1464#define GET_OP_CLASSES
1465#include "circt/Dialect/RTG/IR/RTG.cpp.inc"
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static std::unique_ptr< Context > context
static size_t getAddressWidth(size_t depth)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
return success()
static InstancePath empty
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Definition HWTypes.cpp:122
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:193
Definition rtg.py:1
Definition seq.py:1
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21