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 OpaqueProperties 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, OpaqueProperties 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, OpaqueProperties 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, OpaqueProperties 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, OpaqueProperties 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, OpaqueProperties 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// ContextSwitchOp
458//===----------------------------------------------------------------------===//
459
460LogicalResult ContextSwitchOp::verify() {
461 auto elementTypes = getSequence().getType().getElementTypes();
462 if (elementTypes.size() != 3)
463 return emitOpError("sequence type must have exactly 3 element types");
464
465 if (getFrom().getType() != elementTypes[0])
466 return emitOpError(
467 "first sequence element type must match 'from' attribute type");
468
469 if (getTo().getType() != elementTypes[1])
470 return emitOpError(
471 "second sequence element type must match 'to' attribute type");
472
473 auto seqTy = dyn_cast<SequenceType>(elementTypes[2]);
474 if (!seqTy || !seqTy.getElementTypes().empty())
475 return emitOpError(
476 "third sequence element type must be a fully substituted sequence");
477
478 return success();
479}
480
481//===----------------------------------------------------------------------===//
482// TestOp
483//===----------------------------------------------------------------------===//
484
485LogicalResult TestOp::verifyRegions() {
486 if (!getTargetType().entryTypesMatch(getBody()->getArgumentTypes()))
487 return emitOpError("argument types must match dict entry types");
488
489 return success();
490}
491
492LogicalResult TestOp::verify() {
493 if (getTemplateName().empty())
494 return emitOpError("template name must not be empty");
495
496 return success();
497}
498
499LogicalResult TestOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
500 if (!getTargetAttr())
501 return success();
502
503 auto target =
504 symbolTable.lookupNearestSymbolFrom<TargetOp>(*this, getTargetAttr());
505 if (!target)
506 return emitOpError()
507 << "'" << *getTarget()
508 << "' does not reference a valid 'rtg.target' operation";
509
510 // Check if target is a subtype of test requirements
511 // Since entries are sorted by name, we can do this in a single pass
512 size_t targetIdx = 0;
513 auto targetEntries = target.getTarget().getEntries();
514 for (auto testEntry : getTargetType().getEntries()) {
515 // Find the matching entry in target entries.
516 while (targetIdx < targetEntries.size() &&
517 targetEntries[targetIdx].name.getValue() < testEntry.name.getValue())
518 targetIdx++;
519
520 // Check if we found a matching entry with the same name and type
521 if (targetIdx >= targetEntries.size() ||
522 targetEntries[targetIdx].name != testEntry.name ||
523 targetEntries[targetIdx].type != testEntry.type) {
524 return emitOpError("referenced 'rtg.target' op's type is invalid: "
525 "missing entry called '")
526 << testEntry.name.getValue() << "' of type " << testEntry.type;
527 }
528 }
529
530 return success();
531}
532
533ParseResult TestOp::parse(OpAsmParser &parser, OperationState &result) {
534 // Parse the name as a symbol.
535 StringAttr symNameAttr;
536 if (parser.parseSymbolName(symNameAttr))
537 return failure();
538
539 result.getOrAddProperties<TestOp::Properties>().sym_name = symNameAttr;
540
541 // Parse the function signature.
542 SmallVector<OpAsmParser::Argument> arguments;
543 SmallVector<StringAttr> names;
544
545 auto parseOneArgument = [&]() -> ParseResult {
546 std::string name;
547 if (parser.parseKeywordOrString(&name) || parser.parseEqual() ||
548 parser.parseArgument(arguments.emplace_back(), /*allowType=*/true,
549 /*allowAttrs=*/true))
550 return failure();
551
552 names.push_back(StringAttr::get(result.getContext(), name));
553 return success();
554 };
555 if (parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
556 parseOneArgument, " in argument list"))
557 return failure();
558
559 SmallVector<Type> argTypes;
560 SmallVector<DictEntry> entries;
561 SmallVector<Location> argLocs;
562 argTypes.reserve(arguments.size());
563 argLocs.reserve(arguments.size());
564 for (auto [name, arg] : llvm::zip(names, arguments)) {
565 argTypes.push_back(arg.type);
566 argLocs.push_back(arg.sourceLoc ? *arg.sourceLoc : result.location);
567 entries.push_back({name, arg.type});
568 }
569 auto emitError = [&]() -> InFlightDiagnostic {
570 return parser.emitError(parser.getCurrentLocation());
571 };
572 Type type = DictType::getChecked(emitError, result.getContext(),
573 ArrayRef<DictEntry>(entries));
574 if (!type)
575 return failure();
576 result.getOrAddProperties<TestOp::Properties>().targetType =
577 TypeAttr::get(type);
578
579 std::string templateName;
580 if (!parser.parseOptionalKeyword("template")) {
581 auto loc = parser.getCurrentLocation();
582 if (parser.parseString(&templateName))
583 return failure();
584
585 if (templateName.empty())
586 return parser.emitError(loc, "template name must not be empty");
587 }
588
589 StringAttr templateNameAttr = symNameAttr;
590 if (!templateName.empty())
591 templateNameAttr = StringAttr::get(result.getContext(), templateName);
592
593 StringAttr targetName;
594 if (!parser.parseOptionalKeyword("target"))
595 if (parser.parseSymbolName(targetName))
596 return failure();
597
598 result.getOrAddProperties<TestOp::Properties>().templateName =
599 templateNameAttr;
600 result.getOrAddProperties<TestOp::Properties>().target = targetName;
601
602 auto loc = parser.getCurrentLocation();
603 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
604 return failure();
605 if (failed(verifyInherentAttrs(result.name, result.attributes, [&]() {
606 return parser.emitError(loc)
607 << "'" << result.name.getStringRef() << "' op ";
608 })))
609 return failure();
610
611 std::unique_ptr<Region> bodyRegionRegion = std::make_unique<Region>();
612 if (parser.parseRegion(*bodyRegionRegion, arguments))
613 return failure();
614
615 if (bodyRegionRegion->empty()) {
616 bodyRegionRegion->emplaceBlock();
617 bodyRegionRegion->addArguments(argTypes, argLocs);
618 }
619 result.addRegion(std::move(bodyRegionRegion));
620
621 return success();
622}
623
624void TestOp::print(OpAsmPrinter &p) {
625 p << ' ';
626 p.printSymbolName(getSymNameAttr().getValue());
627 p << "(";
628 SmallString<32> resultNameStr;
629 llvm::interleaveComma(
630 llvm::zip(getTargetType().getEntries(), getBody()->getArguments()), p,
631 [&](auto entryAndArg) {
632 auto [entry, arg] = entryAndArg;
633 p << entry.name.getValue() << " = ";
634 p.printRegionArgument(arg);
635 });
636 p << ")";
637
638 if (getSymNameAttr() != getTemplateNameAttr())
639 p << " template " << getTemplateNameAttr();
640
641 if (getTargetAttr()) {
642 p << " target ";
643 p.printSymbolName(getTargetAttr().getValue());
644 }
645
646 p.printOptionalAttrDictWithKeyword(
647 (*this)->getAttrs(), {getSymNameAttrName(), getTargetTypeAttrName(),
648 getTargetAttrName(), getTemplateNameAttrName()});
649 p << ' ';
650 p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);
651}
652
653void TestOp::getAsmBlockArgumentNames(Region &region,
654 OpAsmSetValueNameFn setNameFn) {
655 for (auto [entry, arg] :
656 llvm::zip(getTargetType().getEntries(), region.getArguments()))
657 setNameFn(arg, entry.name.getValue());
658}
659
660//===----------------------------------------------------------------------===//
661// TargetOp
662//===----------------------------------------------------------------------===//
663
664LogicalResult TargetOp::verifyRegions() {
665 if (!getTarget().entryTypesMatch(
666 getBody()->getTerminator()->getOperandTypes()))
667 return emitOpError("terminator operand types must match dict entry types");
668
669 return success();
670}
671
672//===----------------------------------------------------------------------===//
673// ValidateOp
674//===----------------------------------------------------------------------===//
675
676LogicalResult ValidateOp::verify() {
677 if (!getRef().getType().isValidContentType(getValue().getType()))
678 return emitOpError(
679 "result type must be a valid content type for the ref value");
680
681 return success();
682}
683
684//===----------------------------------------------------------------------===//
685// ArrayCreateOp
686//===----------------------------------------------------------------------===//
687
688LogicalResult ArrayCreateOp::verify() {
689 if (!getElements().empty() &&
690 getElements()[0].getType() != getType().getElementType())
691 return emitOpError("operand types must match array element type, expected ")
692 << getType().getElementType() << " but got "
693 << getElements()[0].getType();
694
695 return success();
696}
697
698ParseResult ArrayCreateOp::parse(OpAsmParser &parser, OperationState &result) {
699 SmallVector<OpAsmParser::UnresolvedOperand> operands;
700 Type elementType;
701
702 if (parser.parseOperandList(operands) || parser.parseColon() ||
703 parser.parseType(elementType) ||
704 parser.parseOptionalAttrDict(result.attributes))
705 return failure();
706
707 if (failed(parser.resolveOperands(operands, elementType, result.operands)))
708 return failure();
709
710 result.addTypes(ArrayType::get(elementType));
711
712 return success();
713}
714
715void ArrayCreateOp::print(OpAsmPrinter &p) {
716 p << ' ';
717 p.printOperands(getElements());
718 p << " : " << getType().getElementType();
719 p.printOptionalAttrDict((*this)->getAttrs(), {});
720}
721
722//===----------------------------------------------------------------------===//
723// ArrayAppendOp
724//===----------------------------------------------------------------------===//
725
726LogicalResult ArrayAppendOp::canonicalize(ArrayAppendOp op,
727 PatternRewriter &rewriter) {
728 auto createOp = op.getArray().getDefiningOp<ArrayCreateOp>();
729 if (!createOp)
730 return failure();
731
732 SmallVector<Value> newElements(createOp.getElements());
733 newElements.push_back(op.getElement());
734 rewriter.replaceOpWithNewOp<ArrayCreateOp>(op, op.getType(), newElements);
735 return success();
736}
737
738//===----------------------------------------------------------------------===//
739// MemoryBlockDeclareOp
740//===----------------------------------------------------------------------===//
741
742LogicalResult MemoryBlockDeclareOp::verify() {
743 if (getBaseAddress().getBitWidth() != getType().getAddressWidth())
744 return emitOpError(
745 "base address width must match memory block address width");
746
747 if (getEndAddress().getBitWidth() != getType().getAddressWidth())
748 return emitOpError(
749 "end address width must match memory block address width");
750
751 if (getBaseAddress().ugt(getEndAddress()))
752 return emitOpError(
753 "base address must be smaller than or equal to the end address");
754
755 return success();
756}
757
758ParseResult MemoryBlockDeclareOp::parse(OpAsmParser &parser,
759 OperationState &result) {
760 SmallVector<OpAsmParser::UnresolvedOperand> operands;
761 MemoryBlockType memoryBlockType;
762 APInt start, end;
763
764 if (parser.parseLSquare())
765 return failure();
766
767 auto startLoc = parser.getCurrentLocation();
768 if (parser.parseInteger(start))
769 return failure();
770
771 if (parser.parseMinus())
772 return failure();
773
774 auto endLoc = parser.getCurrentLocation();
775 if (parser.parseInteger(end) || parser.parseRSquare() ||
776 parser.parseColonType(memoryBlockType) ||
777 parser.parseOptionalAttrDict(result.attributes))
778 return failure();
779
780 auto width = memoryBlockType.getAddressWidth();
781 auto adjustAPInt = [&](APInt value, llvm::SMLoc loc) -> FailureOr<APInt> {
782 if (value.getBitWidth() > width) {
783 if (!value.isIntN(width))
784 return parser.emitError(
785 loc,
786 "address out of range for memory block with address width ")
787 << width;
788
789 return value.trunc(width);
790 }
791
792 if (value.getBitWidth() < width)
793 return value.zext(width);
794
795 return value;
796 };
797
798 auto startRes = adjustAPInt(start, startLoc);
799 auto endRes = adjustAPInt(end, endLoc);
800 if (failed(startRes) || failed(endRes))
801 return failure();
802
803 auto intType = IntegerType::get(result.getContext(), width);
804 result.addAttribute(getBaseAddressAttrName(result.name),
805 IntegerAttr::get(intType, *startRes));
806 result.addAttribute(getEndAddressAttrName(result.name),
807 IntegerAttr::get(intType, *endRes));
808
809 result.addTypes(memoryBlockType);
810 return success();
811}
812
813void MemoryBlockDeclareOp::print(OpAsmPrinter &p) {
814 SmallVector<char> str;
815 getBaseAddress().toString(str, 16, false, false, false);
816 p << " [0x" << str;
817 p << " - 0x";
818 str.clear();
819 getEndAddress().toString(str, 16, false, false, false);
820 p << str << "] : " << getType();
821 p.printOptionalAttrDict((*this)->getAttrs(),
822 {getBaseAddressAttrName(), getEndAddressAttrName()});
823}
824
825//===----------------------------------------------------------------------===//
826// MemoryBaseAddressOp
827//===----------------------------------------------------------------------===//
828
829LogicalResult MemoryBaseAddressOp::inferReturnTypes(
830 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
831 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
832 SmallVectorImpl<Type> &inferredReturnTypes) {
833 if (operands.empty())
834 return failure();
835 auto memTy = dyn_cast<MemoryType>(operands[0].getType());
836 if (!memTy)
837 return failure();
838 inferredReturnTypes.push_back(
839 ImmediateType::get(context, memTy.getAddressWidth()));
840 return success();
841}
842
843//===----------------------------------------------------------------------===//
844// ConcatImmediateOp
845//===----------------------------------------------------------------------===//
846
847LogicalResult ConcatImmediateOp::inferReturnTypes(
848 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
849 DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
850 SmallVectorImpl<Type> &inferredReturnTypes) {
851 if (operands.empty()) {
852 if (loc)
853 return mlir::emitError(*loc) << "at least one operand must be provided";
854 return failure();
855 }
856
857 unsigned totalWidth = 0;
858 for (auto operand : operands) {
859 auto immType = dyn_cast<ImmediateType>(operand.getType());
860 if (!immType) {
861 if (loc)
862 return mlir::emitError(*loc)
863 << "all operands must be of immediate type";
864 return failure();
865 }
866 totalWidth += immType.getWidth();
867 }
868
869 inferredReturnTypes.push_back(ImmediateType::get(context, totalWidth));
870 return success();
871}
872
873OpFoldResult ConcatImmediateOp::fold(FoldAdaptor adaptor) {
874 // concat(x) -> x
875 if (getOperands().size() == 1)
876 return getOperands()[0];
877
878 // If all operands are constants, fold into a single constant
879 if (llvm::all_of(adaptor.getOperands(), [](Attribute attr) {
880 return isa_and_nonnull<ImmediateAttr>(attr);
881 })) {
882 auto result = APInt::getZeroWidth();
883 for (auto attr : adaptor.getOperands())
884 result = result.concat(cast<ImmediateAttr>(attr).getValue());
885
886 return ImmediateAttr::get(getContext(), result);
887 }
888
889 return {};
890}
891
892//===----------------------------------------------------------------------===//
893// SliceImmediateOp
894//===----------------------------------------------------------------------===//
895
896LogicalResult SliceImmediateOp::verify() {
897 auto srcWidth = getInput().getType().getWidth();
898 auto dstWidth = getResult().getType().getWidth();
899
900 if (getLowBit() >= srcWidth)
901 return emitOpError("from bit too large for input (got ")
902 << getLowBit() << ", but input width is " << srcWidth << ")";
903
904 if (srcWidth - getLowBit() < dstWidth)
905 return emitOpError("slice does not fit in input (trying to extract ")
906 << dstWidth << " bits starting at index " << getLowBit()
907 << ", but only " << (srcWidth - getLowBit())
908 << " bits are available)";
909
910 return success();
911}
912
913OpFoldResult SliceImmediateOp::fold(FoldAdaptor adaptor) {
914 if (auto inputAttr = dyn_cast_or_null<ImmediateAttr>(adaptor.getInput())) {
915 auto resultWidth = getType().getWidth();
916 APInt sliced = inputAttr.getValue().extractBits(resultWidth, getLowBit());
917 return ImmediateAttr::get(getContext(), sliced);
918 }
919
920 return {};
921}
922
923//===----------------------------------------------------------------------===//
924// StringConcatOp
925//===----------------------------------------------------------------------===//
926
927OpFoldResult StringConcatOp::fold(FoldAdaptor adaptor) {
928 SmallString<32> result;
929 for (auto attr : adaptor.getStrings()) {
930 auto stringAttr = dyn_cast_or_null<StringAttr>(attr);
931 if (!stringAttr)
932 return {};
933
934 result += stringAttr.getValue();
935 }
936
937 return StringAttr::get(result, StringType::get(getContext()));
938}
939
940//===----------------------------------------------------------------------===//
941// IntFormatOp
942//===----------------------------------------------------------------------===//
943
944OpFoldResult IntFormatOp::fold(FoldAdaptor adaptor) {
945 auto intAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getValue());
946 if (!intAttr)
947 return {};
948 if (!intAttr.getType().isIndex())
949 return {};
950 return StringAttr::get(Twine(intAttr.getValue().getZExtValue()),
951 StringType::get(getContext()));
952}
953
954//===----------------------------------------------------------------------===//
955// StringToLabelOp
956//===----------------------------------------------------------------------===//
957
958OpFoldResult StringToLabelOp::fold(FoldAdaptor adaptor) {
959 if (auto stringAttr = dyn_cast_or_null<StringAttr>(adaptor.getString()))
960 return LabelAttr::get(getContext(), stringAttr.getValue());
961
962 return {};
963}
964
965//===----------------------------------------------------------------------===//
966// TableGen generated logic.
967//===----------------------------------------------------------------------===//
968
969#define GET_OP_CLASSES
970#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 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
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21