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