CIRCT 22.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 "llvm/ADT/SmallString.h"
19
20using namespace mlir;
21using namespace circt;
22using namespace rtg;
23
24//===----------------------------------------------------------------------===//
25// ConstantOp
26//===----------------------------------------------------------------------===//
27
28LogicalResult
29ConstantOp::inferReturnTypes(MLIRContext *context, std::optional<Location> loc,
30 ValueRange operands, DictionaryAttr attributes,
31 OpaqueProperties properties, RegionRange regions,
32 SmallVectorImpl<Type> &inferredReturnTypes) {
33 inferredReturnTypes.push_back(
34 properties.as<Properties *>()->getValue().getType());
35 return success();
36}
37
38OpFoldResult ConstantOp::fold(FoldAdaptor adaptor) { return getValueAttr(); }
39
40//===----------------------------------------------------------------------===//
41// SequenceOp
42//===----------------------------------------------------------------------===//
43
44LogicalResult SequenceOp::verifyRegions() {
45 if (TypeRange(getSequenceType().getElementTypes()) !=
46 getBody()->getArgumentTypes())
47 return emitOpError("sequence type does not match block argument types");
48
49 return success();
50}
51
52ParseResult SequenceOp::parse(OpAsmParser &parser, OperationState &result) {
53 // Parse the name as a symbol.
54 if (parser.parseSymbolName(
55 result.getOrAddProperties<SequenceOp::Properties>().sym_name))
56 return failure();
57
58 // Parse the function signature.
59 SmallVector<OpAsmParser::Argument> arguments;
60 if (parser.parseArgumentList(arguments, OpAsmParser::Delimiter::Paren,
61 /*allowType=*/true, /*allowAttrs=*/true))
62 return failure();
63
64 SmallVector<Type> argTypes;
65 SmallVector<Location> argLocs;
66 argTypes.reserve(arguments.size());
67 argLocs.reserve(arguments.size());
68 for (auto &arg : arguments) {
69 argTypes.push_back(arg.type);
70 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
71 }
72 Type type = SequenceType::get(result.getContext(), argTypes);
73 result.getOrAddProperties<SequenceOp::Properties>().sequenceType =
74 TypeAttr::get(type);
75
76 auto loc = parser.getCurrentLocation();
77 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
78 return failure();
79 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
80 return parser.emitError(loc)
81 << "'" << result.name.getStringRef() << "' op ";
82 })))
83 return failure();
84
85 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
86 if (parser.parseRegion(*bodyRegionRegion, arguments))
87 return failure();
88
89 if (bodyRegionRegion->empty()) {
90 bodyRegionRegion->emplaceBlock();
91 bodyRegionRegion->addArguments(argTypes, argLocs);
92 }
93 result.addRegion(std::move(bodyRegionRegion));
94
95 return success();
96}
97
98void SequenceOp::print(OpAsmPrinter &p) {
99 p << ' ';
100 p.printSymbolName(getSymNameAttr().getValue());
101 p << "(";
102 llvm::interleaveComma(getBody()->getArguments(), p,
103 [&](auto arg) { p.printRegionArgument(arg); });
104 p << ")";
105 p.printOptionalAttrDictWithKeyword(
106 (*this)->getAttrs(), {getSymNameAttrName(), getSequenceTypeAttrName()});
107 p << ' ';
108 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
109}
110
111mlir::SymbolTable::Visibility SequenceOp::getVisibility() {
112 return mlir::SymbolTable::Visibility::Private;
113}
114
115void SequenceOp::setVisibility(mlir::SymbolTable::Visibility visibility) {
116 // Do nothing, always private.
117 assert(false && "cannot change visibility of sequence");
118}
119
120//===----------------------------------------------------------------------===//
121// GetSequenceOp
122//===----------------------------------------------------------------------===//
123
124LogicalResult
125GetSequenceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
126 SequenceOp seq =
127 symbolTable.lookupNearestSymbolFrom<SequenceOp>(*this, getSequenceAttr());
128 if (!seq)
129 return emitOpError()
130 << "'" << getSequence()
131 << "' does not reference a valid 'rtg.sequence' operation";
132
133 if (seq.getSequenceType() != getType())
134 return emitOpError("referenced 'rtg.sequence' op's type does not match");
135
136 return success();
137}
138
139//===----------------------------------------------------------------------===//
140// SubstituteSequenceOp
141//===----------------------------------------------------------------------===//
142
143LogicalResult SubstituteSequenceOp::verify() {
144 if (getReplacements().empty())
145 return emitOpError("must at least have one replacement value");
146
147 if (getReplacements().size() >
148 getSequence().getType().getElementTypes().size())
149 return emitOpError(
150 "must not have more replacement values than sequence arguments");
151
152 if (getReplacements().getTypes() !=
153 getSequence().getType().getElementTypes().take_front(
154 getReplacements().size()))
155 return emitOpError("replacement types must match the same number of "
156 "sequence argument types from the front");
157
158 return success();
159}
160
161LogicalResult SubstituteSequenceOp::inferReturnTypes(
162 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
163 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
164 SmallVectorImpl<Type> &inferredReturnTypes) {
165 ArrayRef<Type> argTypes =
166 cast<SequenceType>(operands[0].getType()).getElementTypes();
167 auto seqType =
168 SequenceType::get(context, argTypes.drop_front(operands.size() - 1));
169 inferredReturnTypes.push_back(seqType);
170 return success();
171}
172
173ParseResult SubstituteSequenceOp::parse(::mlir::OpAsmParser &parser,
174 ::mlir::OperationState &result) {
175 OpAsmParser::UnresolvedOperand sequenceRawOperand;
176 SmallVector<OpAsmParser::UnresolvedOperand, 4> replacementsOperands;
177 Type sequenceRawType;
178
179 if (parser.parseOperand(sequenceRawOperand) || parser.parseLParen())
180 return failure();
181
182 auto replacementsOperandsLoc = parser.getCurrentLocation();
183 if (parser.parseOperandList(replacementsOperands) || parser.parseRParen() ||
184 parser.parseColon() || parser.parseType(sequenceRawType) ||
185 parser.parseOptionalAttrDict(result.attributes))
186 return failure();
187
188 if (!isa<SequenceType>(sequenceRawType))
189 return parser.emitError(parser.getNameLoc())
190 << "'sequence' must be handle to a sequence or sequence family, but "
191 "got "
192 << sequenceRawType;
193
194 if (parser.resolveOperand(sequenceRawOperand, sequenceRawType,
195 result.operands))
196 return failure();
197
198 if (parser.resolveOperands(replacementsOperands,
199 cast<SequenceType>(sequenceRawType)
200 .getElementTypes()
201 .take_front(replacementsOperands.size()),
202 replacementsOperandsLoc, result.operands))
203 return failure();
204
205 SmallVector<Type> inferredReturnTypes;
206 if (failed(inferReturnTypes(
207 parser.getContext(), result.location, result.operands,
208 result.attributes.getDictionary(parser.getContext()),
209 result.getRawProperties(), result.regions, inferredReturnTypes)))
210 return failure();
211
212 result.addTypes(inferredReturnTypes);
213 return success();
214}
215
216void SubstituteSequenceOp::print(OpAsmPrinter &p) {
217 p << ' ' << getSequence() << "(" << getReplacements()
218 << ") : " << getSequence().getType();
219 p.printOptionalAttrDict((*this)->getAttrs(), {});
220}
221
222//===----------------------------------------------------------------------===//
223// InterleaveSequencesOp
224//===----------------------------------------------------------------------===//
225
226LogicalResult InterleaveSequencesOp::verify() {
227 if (getSequences().empty())
228 return emitOpError("must have at least one sequence in the list");
229
230 return success();
231}
232
233OpFoldResult InterleaveSequencesOp::fold(FoldAdaptor adaptor) {
234 if (getSequences().size() == 1)
235 return getSequences()[0];
236
237 return {};
238}
239
240//===----------------------------------------------------------------------===//
241// SetCreateOp
242//===----------------------------------------------------------------------===//
243
244ParseResult SetCreateOp::parse(OpAsmParser &parser, OperationState &result) {
245 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
246 Type elemType;
247
248 if (parser.parseOperandList(operands) ||
249 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
250 parser.parseType(elemType))
251 return failure();
252
253 result.addTypes({SetType::get(result.getContext(), elemType)});
254
255 for (auto operand : operands)
256 if (parser.resolveOperand(operand, elemType, result.operands))
257 return failure();
258
259 return success();
260}
261
262void SetCreateOp::print(OpAsmPrinter &p) {
263 p << " ";
264 p.printOperands(getElements());
265 p.printOptionalAttrDict((*this)->getAttrs());
266 p << " : " << getSet().getType().getElementType();
267}
268
269LogicalResult SetCreateOp::verify() {
270 if (getElements().size() > 0) {
271 // We only need to check the first element because of the `SameTypeOperands`
272 // trait.
273 if (getElements()[0].getType() != getSet().getType().getElementType())
274 return emitOpError() << "operand types must match set element type";
275 }
276
277 return success();
278}
279
280//===----------------------------------------------------------------------===//
281// SetCartesianProductOp
282//===----------------------------------------------------------------------===//
283
284LogicalResult SetCartesianProductOp::inferReturnTypes(
285 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
286 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
287 SmallVectorImpl<Type> &inferredReturnTypes) {
288 if (operands.empty()) {
289 if (loc)
290 return mlir::emitError(*loc) << "at least one set must be provided";
291 return failure();
292 }
293
294 SmallVector<Type> elementTypes;
295 for (auto operand : operands)
296 elementTypes.push_back(cast<SetType>(operand.getType()).getElementType());
297 inferredReturnTypes.push_back(
298 SetType::get(rtg::TupleType::get(context, elementTypes)));
299 return success();
300}
301
302//===----------------------------------------------------------------------===//
303// BagCreateOp
304//===----------------------------------------------------------------------===//
305
306ParseResult BagCreateOp::parse(OpAsmParser &parser, OperationState &result) {
307 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> elementOperands,
308 multipleOperands;
309 Type elemType;
310
311 if (!parser.parseOptionalLParen()) {
312 while (true) {
313 OpAsmParser::UnresolvedOperand elementOperand, multipleOperand;
314 if (parser.parseOperand(multipleOperand) || parser.parseKeyword("x") ||
315 parser.parseOperand(elementOperand))
316 return failure();
317
318 elementOperands.push_back(elementOperand);
319 multipleOperands.push_back(multipleOperand);
320
321 if (parser.parseOptionalComma()) {
322 if (parser.parseRParen())
323 return failure();
324 break;
325 }
326 }
327 }
328
329 if (parser.parseColon() || parser.parseType(elemType) ||
330 parser.parseOptionalAttrDict(result.attributes))
331 return failure();
332
333 result.addTypes({BagType::get(result.getContext(), elemType)});
334
335 for (auto operand : elementOperands)
336 if (parser.resolveOperand(operand, elemType, result.operands))
337 return failure();
338
339 for (auto operand : multipleOperands)
340 if (parser.resolveOperand(operand, IndexType::get(result.getContext()),
341 result.operands))
342 return failure();
343
344 return success();
345}
346
347void BagCreateOp::print(OpAsmPrinter &p) {
348 p << " ";
349 if (!getElements().empty())
350 p << "(";
351 llvm::interleaveComma(llvm::zip(getElements(), getMultiples()), p,
352 [&](auto elAndMultiple) {
353 auto [el, multiple] = elAndMultiple;
354 p << multiple << " x " << el;
355 });
356 if (!getElements().empty())
357 p << ")";
358
359 p << " : " << getBag().getType().getElementType();
360 p.printOptionalAttrDict((*this)->getAttrs());
361}
362
363LogicalResult BagCreateOp::verify() {
364 if (!llvm::all_equal(getElements().getTypes()))
365 return emitOpError() << "types of all elements must match";
366
367 if (getElements().size() > 0)
368 if (getElements()[0].getType() != getBag().getType().getElementType())
369 return emitOpError() << "operand types must match bag element type";
370
371 return success();
372}
373
374//===----------------------------------------------------------------------===//
375// TupleCreateOp
376//===----------------------------------------------------------------------===//
377
378LogicalResult TupleCreateOp::inferReturnTypes(
379 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
380 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
381 SmallVectorImpl<Type> &inferredReturnTypes) {
382 SmallVector<Type> elementTypes;
383 for (auto operand : operands)
384 elementTypes.push_back(operand.getType());
385 inferredReturnTypes.push_back(rtg::TupleType::get(context, elementTypes));
386 return success();
387}
388
389//===----------------------------------------------------------------------===//
390// TupleExtractOp
391//===----------------------------------------------------------------------===//
392
393LogicalResult TupleExtractOp::inferReturnTypes(
394 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
395 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
396 SmallVectorImpl<Type> &inferredReturnTypes) {
397 assert(operands.size() == 1 && "must have exactly one operand");
398
399 auto tupleTy = dyn_cast<rtg::TupleType>(operands[0].getType());
400 size_t idx = properties.as<Properties *>()->getIndex().getInt();
401 if (!tupleTy) {
402 if (loc)
403 return mlir::emitError(*loc) << "only RTG tuples are supported";
404 return failure();
405 }
406
407 if (tupleTy.getFieldTypes().size() <= idx) {
408 if (loc)
409 return mlir::emitError(*loc)
410 << "index (" << idx
411 << ") must be smaller than number of elements in tuple ("
412 << tupleTy.getFieldTypes().size() << ")";
413 return failure();
414 }
415
416 inferredReturnTypes.push_back(tupleTy.getFieldTypes()[idx]);
417 return success();
418}
419
420//===----------------------------------------------------------------------===//
421// FixedRegisterOp
422//===----------------------------------------------------------------------===//
423
424LogicalResult FixedRegisterOp::inferReturnTypes(
425 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
426 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
427 SmallVectorImpl<Type> &inferredReturnTypes) {
428 inferredReturnTypes.push_back(
429 properties.as<Properties *>()->getReg().getType());
430 return success();
431}
432
433OpFoldResult FixedRegisterOp::fold(FoldAdaptor adaptor) { return getRegAttr(); }
434
435//===----------------------------------------------------------------------===//
436// VirtualRegisterOp
437//===----------------------------------------------------------------------===//
438
439LogicalResult VirtualRegisterOp::verify() {
440 if (getAllowedRegs().empty())
441 return emitOpError("must have at least one allowed register");
442
443 if (llvm::any_of(getAllowedRegs(), [](Attribute attr) {
444 return !isa<RegisterAttrInterface>(attr);
445 }))
446 return emitOpError("all elements must be of RegisterAttrInterface");
447
448 if (!llvm::all_equal(
449 llvm::map_range(getAllowedRegs().getAsRange<RegisterAttrInterface>(),
450 [](auto attr) { return attr.getType(); })))
451 return emitOpError("all allowed registers must be of the same type");
452
453 return success();
454}
455
456LogicalResult VirtualRegisterOp::inferReturnTypes(
457 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
458 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
459 SmallVectorImpl<Type> &inferredReturnTypes) {
460 auto allowedRegs = properties.as<Properties *>()->getAllowedRegs();
461 if (allowedRegs.empty()) {
462 if (loc)
463 return mlir::emitError(*loc, "must have at least one allowed register");
464
465 return failure();
466 }
467
468 auto regAttr = dyn_cast<RegisterAttrInterface>(allowedRegs[0]);
469 if (!regAttr) {
470 if (loc)
471 return mlir::emitError(
472 *loc, "allowed register attributes must be of RegisterAttrInterface");
473
474 return failure();
475 }
476 inferredReturnTypes.push_back(regAttr.getType());
477 return success();
478}
479
480//===----------------------------------------------------------------------===//
481// ContextSwitchOp
482//===----------------------------------------------------------------------===//
483
484LogicalResult ContextSwitchOp::verify() {
485 auto elementTypes = getSequence().getType().getElementTypes();
486 if (elementTypes.size() != 3)
487 return emitOpError("sequence type must have exactly 3 element types");
488
489 if (getFrom().getType() != elementTypes[0])
490 return emitOpError(
491 "first sequence element type must match 'from' attribute type");
492
493 if (getTo().getType() != elementTypes[1])
494 return emitOpError(
495 "second sequence element type must match 'to' attribute type");
496
497 auto seqTy = dyn_cast<SequenceType>(elementTypes[2]);
498 if (!seqTy || !seqTy.getElementTypes().empty())
499 return emitOpError(
500 "third sequence element type must be a fully substituted sequence");
501
502 return success();
503}
504
505//===----------------------------------------------------------------------===//
506// TestOp
507//===----------------------------------------------------------------------===//
508
509LogicalResult TestOp::verifyRegions() {
510 if (!getTargetType().entryTypesMatch(getBody()->getArgumentTypes()))
511 return emitOpError("argument types must match dict entry types");
512
513 return success();
514}
515
516LogicalResult TestOp::verify() {
517 if (getTemplateName().empty())
518 return emitOpError("template name must not be empty");
519
520 return success();
521}
522
523LogicalResult TestOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
524 if (!getTargetAttr())
525 return success();
526
527 auto target =
528 symbolTable.lookupNearestSymbolFrom<TargetOp>(*this, getTargetAttr());
529 if (!target)
530 return emitOpError()
531 << "'" << *getTarget()
532 << "' does not reference a valid 'rtg.target' operation";
533
534 // Check if target is a subtype of test requirements
535 // Since entries are sorted by name, we can do this in a single pass
536 size_t targetIdx = 0;
537 auto targetEntries = target.getTarget().getEntries();
538 for (auto testEntry : getTargetType().getEntries()) {
539 // Find the matching entry in target entries.
540 while (targetIdx < targetEntries.size() &&
541 targetEntries[targetIdx].name.getValue() < testEntry.name.getValue())
542 targetIdx++;
543
544 // Check if we found a matching entry with the same name and type
545 if (targetIdx >= targetEntries.size() ||
546 targetEntries[targetIdx].name != testEntry.name ||
547 targetEntries[targetIdx].type != testEntry.type) {
548 return emitOpError("referenced 'rtg.target' op's type is invalid: "
549 "missing entry called '")
550 << testEntry.name.getValue() << "' of type " << testEntry.type;
551 }
552 }
553
554 return success();
555}
556
557ParseResult TestOp::parse(OpAsmParser &parser, OperationState &result) {
558 // Parse the name as a symbol.
559 StringAttr symNameAttr;
560 if (parser.parseSymbolName(symNameAttr))
561 return failure();
562
563 result.getOrAddProperties<TestOp::Properties>().sym_name = symNameAttr;
564
565 // Parse the function signature.
566 SmallVector<OpAsmParser::Argument> arguments;
567 SmallVector<StringAttr> names;
568
569 auto parseOneArgument = [&]() -> ParseResult {
570 std::string name;
571 if (parser.parseKeywordOrString(&name) || parser.parseEqual() ||
572 parser.parseArgument(arguments.emplace_back(), /*allowType=*/true,
573 /*allowAttrs=*/true))
574 return failure();
575
576 names.push_back(StringAttr::get(result.getContext(), name));
577 return success();
578 };
579 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
580 parseOneArgument, " in argument list"))
581 return failure();
582
583 SmallVector<Type> argTypes;
584 SmallVector<DictEntry> entries;
585 SmallVector<Location> argLocs;
586 argTypes.reserve(arguments.size());
587 argLocs.reserve(arguments.size());
588 for (auto [name, arg] : llvm::zip(names, arguments)) {
589 argTypes.push_back(arg.type);
590 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
591 entries.push_back({name, arg.type});
592 }
593 auto emitError = [&]() -> InFlightDiagnostic {
594 return parser.emitError(parser.getCurrentLocation());
595 };
596 Type type = DictType::getChecked(emitError, result.getContext(),
597 ArrayRef<DictEntry>(entries));
598 if (!type)
599 return failure();
600 result.getOrAddProperties<TestOp::Properties>().targetType =
601 TypeAttr::get(type);
602
603 std::string templateName;
604 if (!parser.parseOptionalKeyword("template")) {
605 auto loc = parser.getCurrentLocation();
606 if (parser.parseString(&templateName))
607 return failure();
608
609 if (templateName.empty())
610 return parser.emitError(loc, "template name must not be empty");
611 }
612
613 StringAttr templateNameAttr = symNameAttr;
614 if (!templateName.empty())
615 templateNameAttr = StringAttr::get(result.getContext(), templateName);
616
617 StringAttr targetName;
618 if (!parser.parseOptionalKeyword("target"))
619 if (parser.parseSymbolName(targetName))
620 return failure();
621
622 result.getOrAddProperties<TestOp::Properties>().templateName =
623 templateNameAttr;
624 result.getOrAddProperties<TestOp::Properties>().target = targetName;
625
626 auto loc = parser.getCurrentLocation();
627 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
628 return failure();
629 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
630 return parser.emitError(loc)
631 << "'" << result.name.getStringRef() << "' op ";
632 })))
633 return failure();
634
635 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
636 if (parser.parseRegion(*bodyRegionRegion, arguments))
637 return failure();
638
639 if (bodyRegionRegion->empty()) {
640 bodyRegionRegion->emplaceBlock();
641 bodyRegionRegion->addArguments(argTypes, argLocs);
642 }
643 result.addRegion(std::move(bodyRegionRegion));
644
645 return success();
646}
647
648void TestOp::print(OpAsmPrinter &p) {
649 p << ' ';
650 p.printSymbolName(getSymNameAttr().getValue());
651 p << "(";
652 SmallString<32> resultNameStr;
653 llvm::interleaveComma(
654 llvm::zip(getTargetType().getEntries(), getBody()->getArguments()), p,
655 [&](auto entryAndArg) {
656 auto [entry, arg] = entryAndArg;
657 p << entry.name.getValue() << " = ";
658 p.printRegionArgument(arg);
659 });
660 p << ")";
661
662 if (getSymNameAttr() != getTemplateNameAttr())
663 p << " template " << getTemplateNameAttr();
664
665 if (getTargetAttr()) {
666 p << " target ";
667 p.printSymbolName(getTargetAttr().getValue());
668 }
669
670 p.printOptionalAttrDictWithKeyword(
671 (*this)->getAttrs(), {getSymNameAttrName(), getTargetTypeAttrName(),
672 getTargetAttrName(), getTemplateNameAttrName()});
673 p << ' ';
674 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
675}
676
677void TestOp::getAsmBlockArgumentNames(Region &region,
678 OpAsmSetValueNameFn setNameFn) {
679 for (auto [entry, arg] :
680 llvm::zip(getTargetType().getEntries(), region.getArguments()))
681 setNameFn(arg, entry.name.getValue());
682}
683
684//===----------------------------------------------------------------------===//
685// TargetOp
686//===----------------------------------------------------------------------===//
687
688LogicalResult TargetOp::verifyRegions() {
689 if (!getTarget().entryTypesMatch(
690 getBody()->getTerminator()->getOperandTypes()))
691 return emitOpError("terminator operand types must match dict entry types");
692
693 return success();
694}
695
696//===----------------------------------------------------------------------===//
697// ValidateOp
698//===----------------------------------------------------------------------===//
699
700LogicalResult ValidateOp::verify() {
701 if (!getRef().getType().isValidContentType(getValue().getType()))
702 return emitOpError(
703 "result type must be a valid content type for the ref value");
704
705 return success();
706}
707
708//===----------------------------------------------------------------------===//
709// ArrayCreateOp
710//===----------------------------------------------------------------------===//
711
712LogicalResult ArrayCreateOp::verify() {
713 if (!getElements().empty() &&
714 getElements()[0].getType() != getType().getElementType())
715 return emitOpError("operand types must match array element type, expected ")
716 << getType().getElementType() << " but got "
717 << getElements()[0].getType();
718
719 return success();
720}
721
722ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
723 SmallVector<OpAsmParser::UnresolvedOperand> operands;
724 Type elementType;
725
726 if (parser.parseOperandList(operands) || parser.parseColon() ||
727 parser.parseType(elementType) ||
728 parser.parseOptionalAttrDict(result.attributes))
729 return failure();
730
731 if (failed(parser.resolveOperands(operands, elementType, result.operands)))
732 return failure();
733
734 result.addTypes(ArrayType::get(elementType));
735
736 return success();
737}
738
739void ArrayCreateOp::print(OpAsmPrinter &p) {
740 p << ' ';
741 p.printOperands(getElements());
742 p << " : " << getType().getElementType();
743 p.printOptionalAttrDict((*this)->getAttrs(), {});
744}
745
746//===----------------------------------------------------------------------===//
747// MemoryBlockDeclareOp
748//===----------------------------------------------------------------------===//
749
750LogicalResult MemoryBlockDeclareOp::verify() {
751 if (getBaseAddress().getBitWidth() != getType().getAddressWidth())
752 return emitOpError(
753 "base address width must match memory block address width");
754
755 if (getEndAddress().getBitWidth() != getType().getAddressWidth())
756 return emitOpError(
757 "end address width must match memory block address width");
758
759 if (getBaseAddress().ugt(getEndAddress()))
760 return emitOpError(
761 "base address must be smaller than or equal to the end address");
762
763 return success();
764}
765
766ParseResult MemoryBlockDeclareOp::parse(OpAsmParser &parser,
767 OperationState &result) {
768 SmallVector<OpAsmParser::UnresolvedOperand> operands;
769 MemoryBlockType memoryBlockType;
770 APInt start, end;
771
772 if (parser.parseLSquare())
773 return failure();
774
775 auto startLoc = parser.getCurrentLocation();
776 if (parser.parseInteger(start))
777 return failure();
778
779 if (parser.parseMinus())
780 return failure();
781
782 auto endLoc = parser.getCurrentLocation();
783 if (parser.parseInteger(end) || parser.parseRSquare() ||
784 parser.parseColonType(memoryBlockType) ||
785 parser.parseOptionalAttrDict(result.attributes))
786 return failure();
787
788 auto width = memoryBlockType.getAddressWidth();
789 auto adjustAPInt = [&](APInt value, llvm::SMLoc loc) -> FailureOr<APInt> {
790 if (value.getBitWidth() > width) {
791 if (!value.isIntN(width))
792 return parser.emitError(
793 loc,
794 "address out of range for memory block with address width ")
795 << width;
796
797 return value.trunc(width);
798 }
799
800 if (value.getBitWidth() < width)
801 return value.zext(width);
802
803 return value;
804 };
805
806 auto startRes = adjustAPInt(start, startLoc);
807 auto endRes = adjustAPInt(end, endLoc);
808 if (failed(startRes) || failed(endRes))
809 return failure();
810
811 auto intType = IntegerType::get(result.getContext(), width);
812 result.addAttribute(getBaseAddressAttrName(result.name),
813 IntegerAttr::get(intType, *startRes));
814 result.addAttribute(getEndAddressAttrName(result.name),
815 IntegerAttr::get(intType, *endRes));
816
817 result.addTypes(memoryBlockType);
818 return success();
819}
820
821void MemoryBlockDeclareOp::print(OpAsmPrinter &p) {
822 SmallVector<char> str;
823 getBaseAddress().toString(str, 16, false, false, false);
824 p << " [0x" << str;
825 p << " - 0x";
826 str.clear();
827 getEndAddress().toString(str, 16, false, false, false);
828 p << str << "] : " << getType();
829 p.printOptionalAttrDict((*this)->getAttrs(),
830 {getBaseAddressAttrName(), getEndAddressAttrName()});
831}
832
833//===----------------------------------------------------------------------===//
834// MemoryBaseAddressOp
835//===----------------------------------------------------------------------===//
836
837LogicalResult MemoryBaseAddressOp::inferReturnTypes(
838 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
839 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
840 SmallVectorImpl<Type> &inferredReturnTypes) {
841 if (operands.empty())
842 return failure();
843 auto memTy = dyn_cast<MemoryType>(operands[0].getType());
844 if (!memTy)
845 return failure();
846 inferredReturnTypes.push_back(
847 ImmediateType::get(context, memTy.getAddressWidth()));
848 return success();
849}
850
851//===----------------------------------------------------------------------===//
852// ConcatImmediateOp
853//===----------------------------------------------------------------------===//
854
855LogicalResult ConcatImmediateOp::inferReturnTypes(
856 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
857 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
858 SmallVectorImpl<Type> &inferredReturnTypes) {
859 if (operands.empty()) {
860 if (loc)
861 return mlir::emitError(*loc) << "at least one operand must be provided";
862 return failure();
863 }
864
865 unsigned totalWidth = 0;
866 for (auto operand : operands) {
867 auto immType = dyn_cast<ImmediateType>(operand.getType());
868 if (!immType) {
869 if (loc)
870 return mlir::emitError(*loc)
871 << "all operands must be of immediate type";
872 return failure();
873 }
874 totalWidth += immType.getWidth();
875 }
876
877 inferredReturnTypes.push_back(ImmediateType::get(context, totalWidth));
878 return success();
879}
880
881OpFoldResult ConcatImmediateOp::fold(FoldAdaptor adaptor) {
882 // concat(x) -> x
883 if (getOperands().size() == 1)
884 return getOperands()[0];
885
886 // If all operands are constants, fold into a single constant
887 if (llvm::all_of(adaptor.getOperands(), [](Attribute attr) {
888 return isa_and_nonnull<ImmediateAttr>(attr);
889 })) {
890 auto result = APInt::getZeroWidth();
891 for (auto attr : adaptor.getOperands())
892 result = result.concat(cast<ImmediateAttr>(attr).getValue());
893
894 return ImmediateAttr::get(getContext(), result);
895 }
896
897 return {};
898}
899
900//===----------------------------------------------------------------------===//
901// SliceImmediateOp
902//===----------------------------------------------------------------------===//
903
904LogicalResult SliceImmediateOp::verify() {
905 auto srcWidth = getInput().getType().getWidth();
906 auto dstWidth = getResult().getType().getWidth();
907
908 if (getLowBit() >= srcWidth)
909 return emitOpError("from bit too large for input (got ")
910 << getLowBit() << ", but input width is " << srcWidth << ")";
911
912 if (srcWidth - getLowBit() < dstWidth)
913 return emitOpError("slice does not fit in input (trying to extract ")
914 << dstWidth << " bits starting at index " << getLowBit()
915 << ", but only " << (srcWidth - getLowBit())
916 << " bits are available)";
917
918 return success();
919}
920
921OpFoldResult SliceImmediateOp::fold(FoldAdaptor adaptor) {
922 if (auto inputAttr = dyn_cast_or_null<ImmediateAttr>(adaptor.getInput())) {
923 auto resultWidth = getType().getWidth();
924 APInt sliced = inputAttr.getValue().extractBits(resultWidth, getLowBit());
925 return ImmediateAttr::get(getContext(), sliced);
926 }
927
928 return {};
929}
930
931//===----------------------------------------------------------------------===//
932// TableGen generated logic.
933//===----------------------------------------------------------------------===//
934
935#define GET_OP_CLASSES
936#include "circt/Dialect/RTG/IR/RTG.cpp.inc"
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static SmallVector< T > concat(const SmallVectorImpl< T > &a, const SmallVectorImpl< T > &b)
Returns a new vector containing the concatenation of vectors a and b.
Definition CalyxOps.cpp:540
static size_t getAddressWidth(size_t depth)
static InstancePath empty
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:55
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:183
Definition rtg.py:1
Definition seq.py:1