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