CIRCT 20.0.0git
Loading...
Searching...
No Matches
KanagawaOps.cpp
Go to the documentation of this file.
1//===- KanagawaOps.cpp - Implementation of Kanagawa dialect ops -----------===//
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
12
13#include "mlir/IR/BuiltinOps.h"
14#include "mlir/IR/DialectImplementation.h"
15#include "mlir/IR/PatternMatch.h"
16#include "mlir/IR/SymbolTable.h"
17#include "mlir/Interfaces/FunctionImplementation.h"
18#include "llvm/ADT/TypeSwitch.h"
19
20using namespace mlir;
21using namespace circt;
22using namespace kanagawa;
23
24template <typename TSymAttr>
25ParseResult parseScopeRefFromName(OpAsmParser &parser, Type &scopeRefType,
26 TSymAttr sym) {
27 // Nothing to parse, since this is already encoded in the child symbol.
28 scopeRefType = ScopeRefType::get(parser.getContext(), sym);
29 return success();
30}
31
32template <typename TSymAttr>
33void printScopeRefFromName(OpAsmPrinter &p, Operation *op, Type type,
34 TSymAttr sym) {
35 // Nothing to print since this information is already encoded in the child
36 // symbol.
37}
38
39// Generates a name for Kanagawa values.
40// NOLINTBEGIN(misc-no-recursion)
41static llvm::raw_string_ostream &genValueName(llvm::raw_string_ostream &os,
42 Value value) {
43 auto *definingOp = value.getDefiningOp();
44 assert(definingOp && "scoperef should always be defined by some op");
45 llvm::TypeSwitch<Operation *, void>(definingOp)
46 .Case<InstanceOp, ContainerInstanceOp>(
47 [&](auto op) { os << op.getInstanceNameAttr().strref(); })
48 .Case<PortOpInterface>([&](auto op) { os << op.getNameHint(); })
49 .Case<PathOp>([&](auto op) {
50 llvm::interleave(
51 op.getPathAsRange(), os,
52 [&](PathStepAttr step) {
53 if (step.getDirection() == PathDirection::Parent)
54 os << "parent";
55 else
56 os << step.getChild().getAttr().strref();
57 },
58 ".");
59 })
60 .Case<GetPortOp>([&](auto op) {
61 genValueName(os, op.getInstance())
62 << "." << op.getPortSymbol() << ".ref";
63 })
64 .Case<PortReadOp>(
65 [&](auto op) { genValueName(os, op.getPort()) << ".val"; })
66 .Default([&](auto op) {
67 op->emitOpError() << "unhandled value type";
68 assert(false && "unhandled value type");
69 });
70 return os;
71}
72// NOLINTEND(misc-no-recursion)
73
74// Generates a name for Kanagawa values, and returns a StringAttr.
75static StringAttr genValueNameAttr(Value v) {
76 std::string s;
77 llvm::raw_string_ostream os(s);
78 genValueName(os, v);
79 return StringAttr::get(v.getContext(), s);
80}
81
82//===----------------------------------------------------------------------===//
83// ScopeOpInterface
84//===----------------------------------------------------------------------===//
85
87 if (!isa<hw::InnerSymbolOpInterface>(op))
88 return op->emitOpError("must implement 'InnerSymbolOpInterface'");
89
90 return success();
91}
92
93//===----------------------------------------------------------------------===//
94// MethodOp
95//===----------------------------------------------------------------------===//
96
97template <typename TOp>
98ParseResult parseMethodLikeOp(OpAsmParser &parser, OperationState &result) {
99 // Parse the name as a symbol.
100 StringAttr nameAttr;
101 if (parser.parseSymbolName(nameAttr))
102 return failure();
103
104 result.attributes.append(hw::InnerSymbolTable::getInnerSymbolAttrName(),
105 hw::InnerSymAttr::get(nameAttr));
106
107 // Parse the function signature.
108 SmallVector<OpAsmParser::Argument, 4> args;
109 SmallVector<Attribute> argNames;
110 SmallVector<Type> resultTypes;
111 TypeAttr functionType;
112
113 using namespace mlir::function_interface_impl;
114 auto *context = parser.getContext();
115
116 // Parse the argument list.
117 if (parser.parseArgumentList(args, OpAsmParser::Delimiter::Paren,
118 /*allowType=*/true, /*allowAttrs=*/false))
119 return failure();
120
121 // Parse the result types
122 if (parser.parseOptionalArrowTypeList(resultTypes))
123 return failure();
124
125 // Process the ssa args for the information we're looking for.
126 SmallVector<Type> argTypes;
127 for (auto &arg : args) {
128 argNames.push_back(parsing_util::getNameFromSSA(context, arg.ssaName.name));
129 argTypes.push_back(arg.type);
130 if (!arg.sourceLoc)
131 arg.sourceLoc = parser.getEncodedSourceLoc(arg.ssaName.location);
132 }
133
134 functionType =
135 TypeAttr::get(FunctionType::get(context, argTypes, resultTypes));
136
137 // Parse the attribute dict.
138 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
139 return failure();
140
141 result.addAttribute("argNames", ArrayAttr::get(context, argNames));
142 result.addAttribute(TOp::getFunctionTypeAttrName(result.name), functionType);
143
144 // Parse the function body.
145 auto *body = result.addRegion();
146 if (parser.parseRegion(*body, args))
147 return failure();
148
149 return success();
150}
151
152template <typename TOp>
153void printMethodLikeOp(TOp op, OpAsmPrinter &p) {
154 FunctionType funcTy = op.getFunctionType();
155 p << ' ';
156 p.printSymbolName(op.getInnerSym().getSymName());
157 Region &body = op.getBody();
158 p << "(";
159 llvm::interleaveComma(body.getArguments(), p,
160 [&](BlockArgument arg) { p.printRegionArgument(arg); });
161 p << ") ";
162 p.printArrowTypeList(funcTy.getResults());
163 p.printOptionalAttrDictWithKeyword(op.getOperation()->getAttrs(),
164 op.getAttributeNames());
165 if (!body.empty()) {
166 p << ' ';
167 p.printRegion(body, /*printEntryBlockArgs=*/false,
168 /*printBlockTerminators=*/true);
169 }
170}
171
172ParseResult MethodOp::parse(OpAsmParser &parser, OperationState &result) {
173 return parseMethodLikeOp<MethodOp>(parser, result);
174}
175
176void MethodOp::print(OpAsmPrinter &p) { return printMethodLikeOp(*this, p); }
177
178void MethodOp::getAsmBlockArgumentNames(mlir::Region &region,
179 OpAsmSetValueNameFn setNameFn) {
180 if (region.empty())
181 return;
182
183 auto func = cast<MethodOp>(region.getParentOp());
184 auto argNames = func.getArgNames().getAsRange<StringAttr>();
185 auto *block = &region.front();
186
187 for (auto [idx, argName] : llvm::enumerate(argNames))
188 if (!argName.getValue().empty())
189 setNameFn(block->getArgument(idx), argName);
190}
191
192//===----------------------------------------------------------------------===//
193// DataflowMethodOp
194//===----------------------------------------------------------------------===//
195
196ParseResult DataflowMethodOp::parse(OpAsmParser &parser,
197 OperationState &result) {
198 return parseMethodLikeOp<DataflowMethodOp>(parser, result);
199}
200
201void DataflowMethodOp::print(OpAsmPrinter &p) {
202 return printMethodLikeOp(*this, p);
203}
204
205//===----------------------------------------------------------------------===//
206// ReturnOp
207//===----------------------------------------------------------------------===//
208
209void ReturnOp::build(OpBuilder &odsBuilder, OperationState &odsState) {}
210
211LogicalResult ReturnOp::verify() {
212 // Check that the return operand type matches the function return type.
213 auto methodLike = cast<MethodLikeOpInterface>((*this)->getParentOp());
214 ArrayRef<Type> resTypes = methodLike.getResultTypes();
215
216 if (getNumOperands() != resTypes.size())
217 return emitOpError(
218 "must have the same number of operands as the method has results");
219
220 for (auto [arg, resType] : llvm::zip(getOperands(), resTypes))
221 if (arg.getType() != resType)
222 return emitOpError("operand type (")
223 << arg.getType() << ") must match function return type ("
224 << resType << ")";
225
226 return success();
227}
228
229//===----------------------------------------------------------------------===//
230// GetVarOp
231//===----------------------------------------------------------------------===//
232
233LogicalResult GetVarOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
234 auto varOp = getVar(ns);
235 if (!varOp)
236 return failure();
237
238 // Ensure that the dereferenced type is the same type as the variable type.
239 if (varOp.getType() != getType())
240 return emitOpError() << "dereferenced type (" << getType()
241 << ") must match variable type (" << varOp.getType()
242 << ")";
243
244 return success();
245}
246
247VarOp GetVarOp::getVar(const hw::InnerRefNamespace &ns) {
248 ScopeRefType parentType = cast<ScopeRefType>(getInstance().getType());
249 auto scopeRefOp = ns.lookupOp<ScopeOpInterface>(parentType.getScopeRef());
250
251 if (!scopeRefOp)
252 return nullptr;
253
254 return dyn_cast_or_null<VarOp>(scopeRefOp.lookupInnerSym(getVarName()));
255}
256
257//===----------------------------------------------------------------------===//
258// InstanceOp
259//===----------------------------------------------------------------------===//
260
261LogicalResult InstanceOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
262 if (!getClass(ns))
263 return emitOpError() << "'" << getTargetName() << "' does not exist";
264
265 return success();
266}
267
268void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
269 setNameFn(getResult(), genValueNameAttr(getResult()));
270}
271
272//===----------------------------------------------------------------------===//
273// GetPortOp
274//===----------------------------------------------------------------------===//
275
276LogicalResult GetPortOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
277 auto portOp = getPort(ns);
278 if (!portOp)
279 return emitOpError() << "port '@" << getPortSymbol()
280 << "' does not exist in @"
281 << cast<ScopeRefType>(getInstance().getType())
282 .getScopeRef()
283 .getName()
284 .getValue();
285
286 Type targetPortType = portOp.getPortType();
287 Type thisPortType = getType().getPortType();
288 if (targetPortType != thisPortType)
289 return emitOpError() << "symbol '" << getPortSymbolAttr()
290 << "' refers to a port of type " << targetPortType
291 << ", but this op has type " << thisPortType;
292
293 return success();
294}
295
296PortOpInterface GetPortOp::getPort(const hw::InnerRefNamespace &ns) {
297 // Lookup the target module type of the instance class reference.
298 auto targetScope = ns.lookupOp<ScopeOpInterface>(
299 cast<ScopeRefType>(getInstance().getType()).getScopeRef());
300
301 if (!targetScope)
302 return nullptr;
303
304 return dyn_cast_or_null<PortOpInterface>(
305 targetScope.lookupInnerSym(getPortSymbol()));
306}
307
308void GetPortOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
309 setNameFn(getResult(), genValueNameAttr(getResult()));
310}
311
312//===----------------------------------------------------------------------===//
313// PortReadOp
314//===----------------------------------------------------------------------===//
315
316void PortReadOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
317 setNameFn(getResult(), genValueNameAttr(getResult()));
318}
319
320//===----------------------------------------------------------------------===//
321// ContainerInstanceOp
322//===----------------------------------------------------------------------===//
323
324LogicalResult ContainerInstanceOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
325 auto targetContainer = getContainer(ns);
326 if (!targetContainer)
327 return emitOpError() << "'" << getTargetName() << "' does not exist";
328
329 return success();
330}
331
332void ContainerInstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
333 setNameFn(getResult(), genValueNameAttr(getResult()));
334}
335
336//===----------------------------------------------------------------------===//
337// CallOp
338//===----------------------------------------------------------------------===//
339
340MethodOp CallOp::getTarget(const hw::InnerRefNamespace &ns) {
341 return ns.lookupOp<MethodOp>(getCallee());
342}
343
344LogicalResult CallOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
345 if (!getTarget(ns))
346 return emitOpError() << "'" << getCallee() << "' does not exist";
347
348 return success();
349}
350
351//===----------------------------------------------------------------------===//
352// PathOp
353//===----------------------------------------------------------------------===//
354
355/// Infer the return types of this operation.
356LogicalResult PathOp::inferReturnTypes(
357 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
358 DictionaryAttr attrs, mlir::OpaqueProperties properties,
359 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
360 Adaptor adaptor(operands, attrs, properties, regions);
361 auto path = adaptor.getPathAttr();
362 if (path.empty())
363 return failure();
364
365 auto lastStep = cast<PathStepAttr>(path.getValue().back());
366 results.push_back(lastStep.getType());
367 return success();
368}
369
370LogicalResult PathStepAttr::verify(function_ref<InFlightDiagnostic()> emitError,
371 PathDirection direction, mlir::Type type,
372 mlir::FlatSymbolRefAttr instance) {
373 // 'parent' should never have an instance name specified.
374 if (direction == PathDirection::Parent && instance)
375 return emitError()
376 << "kanagawa.step 'parent' may not specify an instance name";
377
378 if (direction == PathDirection::Child && !instance)
379 return emitError() << "kanagawa.step 'child' must specify an instance name";
380
381 // Only allow scoperefs
382 auto scoperefType = llvm::dyn_cast<ScopeRefType>(type);
383 if (!scoperefType)
384 return emitError()
385 << "kanagawa.step type must be an !kanagawa.scoperef type";
386
387 return success();
388}
389
390LogicalResult PathOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
391 auto pathRange = getPathAsRange();
392 if (pathRange.empty())
393 return emitOpError() << "kanagawa.path must have at least one step";
394
395 // Verify that each referenced child symbol actually exists at the module
396 // level.
397 for (PathStepAttr step : getPathAsRange()) {
398 auto scoperefType = cast<ScopeRefType>(step.getType());
399 hw::InnerRefAttr scopeRefSym = scoperefType.getScopeRef();
400 if (!scopeRefSym)
401 continue;
402
403 auto *targetScope = ns.lookupOp(scopeRefSym);
404 if (!targetScope)
405 return emitOpError() << "kanagawa.step scoperef symbol '@"
406 << scopeRefSym.getName().getValue()
407 << "' does not exist";
408 }
409
410 // Verify that the last step is fully typed.
411 PathStepAttr lastStep = *std::prev(getPathAsRange().end());
412 ScopeRefType lastStepType = cast<ScopeRefType>(lastStep.getType());
413 if (!lastStepType.getScopeRef())
414 return emitOpError() << "last kanagawa.step in path must specify a symbol "
415 "for the scoperef";
416
417 return success();
418}
419
420LogicalResult PathOp::canonicalize(PathOp op, PatternRewriter &rewriter) {
421 // Canonicalize away kanagawa.path [kanagawa.child] to just referencing the
422 // instance in the current scope.
423 auto range = op.getPathAsRange();
424 size_t pathSize = std::distance(range.begin(), range.end());
425 PathStepAttr firstStep = *range.begin();
426 if (pathSize == 1 && firstStep.getDirection() == PathDirection::Child) {
427 auto parentScope = cast<ScopeOpInterface>(op->getParentOp());
428 auto childInstance = dyn_cast_or_null<ContainerInstanceOp>(
429 parentScope.lookupInnerSym(firstStep.getChild().getValue()));
430 assert(childInstance && "should have been verified by the op verifier");
431 rewriter.replaceOp(op, {childInstance.getResult()});
432 return success();
433 }
434
435 return failure();
436}
437
438void PathOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
439 setNameFn(getResult(), genValueNameAttr(getResult()));
440}
441
442//===----------------------------------------------------------------------===//
443// OutputPortOp
444//===----------------------------------------------------------------------===//
445
446LogicalResult OutputPortOp::canonicalize(OutputPortOp op,
447 PatternRewriter &rewriter) {
448 // Replace any reads of an output port op that is written to from the same
449 // scope, with the value that is written to it.
450 PortWriteOp writer;
451 llvm::SmallVector<PortReadOp, 4> readers;
452 for (auto *user : op.getResult().getUsers()) {
453 if (auto read = dyn_cast<PortReadOp>(user)) {
454 readers.push_back(read);
455 } else if (auto write = dyn_cast<PortWriteOp>(user);
456 write && write.getPort() == op.getPort()) {
457 assert(!writer && "should only have one writer");
458 writer = write;
459 }
460 }
461
462 if (!readers.empty()) {
463 for (auto reader : readers)
464 rewriter.replaceOp(reader, writer.getValue());
465 return success();
466 }
467
468 return failure();
469}
470
471void OutputPortOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
472 setNameFn(getPort(), genValueNameAttr(getPort()));
473}
474
475//===----------------------------------------------------------------------===//
476// InputPortOp
477//===----------------------------------------------------------------------===//
478
479void InputPortOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
480 setNameFn(getPort(), genValueNameAttr(getPort()));
481}
482
483//===----------------------------------------------------------------------===//
484// InputWireOp
485//===----------------------------------------------------------------------===//
486
487LogicalResult InputWireOp::canonicalize(InputWireOp op,
488 PatternRewriter &rewriter) {
489 // Canonicalize away wires which are assigned within this scope.
490 auto portUsers = op.getPort().getUsers();
491 size_t nPortUsers = std::distance(portUsers.begin(), portUsers.end());
492 for (auto *portUser : op.getPort().getUsers()) {
493 auto writer = dyn_cast<PortWriteOp>(portUser);
494 if (writer && writer.getPort() == op.getPort() && nPortUsers == 1) {
495 rewriter.replaceAllUsesWith(op.getOutput(), writer.getValue());
496 rewriter.eraseOp(writer);
497 rewriter.eraseOp(op);
498 return success();
499 }
500 }
501
502 return failure();
503}
504
505void InputWireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
506 auto name = genValueNameAttr(getOutput());
507 setNameFn(getPort(), name);
508 setNameFn(getOutput(),
509 StringAttr::get(getContext(), name.strref() + ".out").strref());
510}
511
512//===----------------------------------------------------------------------===//
513// OutputWireOp
514//===----------------------------------------------------------------------===//
515
516LogicalResult OutputWireOp::canonicalize(OutputWireOp op,
517 PatternRewriter &rewriter) {
518 // Canonicalize away wires which are read (and nothing else) within this
519 // scope. Assume that duplicate reads have been CSE'd away and just look
520 // for a single reader.
521 auto portUsers = op.getPort().getUsers();
522 size_t nPortUsers = std::distance(portUsers.begin(), portUsers.end());
523 for (auto *portUser : op.getPort().getUsers()) {
524 auto reader = dyn_cast<PortReadOp>(portUser);
525 if (reader && reader.getPort() == op.getPort() && nPortUsers == 1) {
526 rewriter.replaceOp(reader, op.getInput());
527 rewriter.eraseOp(op);
528 return success();
529 }
530 }
531
532 return failure();
533}
534
535void OutputWireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
536 setNameFn(getPort(), genValueNameAttr(getPort()));
537}
538
539//===----------------------------------------------------------------------===//
540// StaticBlockOp
541//===----------------------------------------------------------------------===//
542
543template <typename TOp>
544static ParseResult parseBlockLikeOp(
545 OpAsmParser &parser, OperationState &result,
546 llvm::function_ref<ParseResult(OpAsmParser::Argument &)> argAdjuster = {}) {
547 // Parse the argument initializer list.
548 llvm::SmallVector<OpAsmParser::UnresolvedOperand> inputOperands;
549 llvm::SmallVector<OpAsmParser::Argument> inputArguments;
550 llvm::SmallVector<Type> inputTypes;
551 ArrayAttr inputNames;
552 if (parsing_util::parseInitializerList(parser, inputArguments, inputOperands,
553 inputTypes, inputNames))
554 return failure();
555
556 // Parse the result types.
557 llvm::SmallVector<Type> resultTypes;
558 if (parser.parseOptionalArrowTypeList(resultTypes))
559 return failure();
560 result.addTypes(resultTypes);
561
562 // Parse the attribute dict.
563 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
564 return failure();
565
566 // All operands have been parsed - resolve.
567 if (parser.resolveOperands(inputOperands, inputTypes, parser.getNameLoc(),
568 result.operands))
569 return failure();
570
571 // If the user provided an arg adjuster, apply it to each argument.
572 if (argAdjuster) {
573 for (auto &arg : inputArguments)
574 if (failed(argAdjuster(arg)))
575 return failure();
576 }
577
578 // Parse the body region.
579 Region *body = result.addRegion();
580 if (parser.parseRegion(*body, inputArguments))
581 return failure();
582
583 TOp::ensureTerminator(*body, parser.getBuilder(), result.location);
584 return success();
585}
586
587template <typename T>
588static void printBlockLikeOp(T op, OpAsmPrinter &p) {
589 p << ' ';
590 parsing_util::printInitializerList(p, op.getInputs(),
591 op.getBodyBlock()->getArguments());
592 p.printOptionalArrowTypeList(op.getResultTypes());
593 p.printOptionalAttrDictWithKeyword(op.getOperation()->getAttrs());
594 p << ' ';
595 p.printRegion(op.getBody(), /*printEntryBlockArgs=*/false);
596}
597
598LogicalResult StaticBlockOp::verify() {
599 if (getInputs().size() != getBodyBlock()->getNumArguments())
600 return emitOpError("number of inputs must match number of block arguments");
601
602 for (auto [arg, barg] :
603 llvm::zip(getInputs(), getBodyBlock()->getArguments())) {
604 if (arg.getType() != barg.getType())
605 return emitOpError("block argument type must match input type");
606 }
607
608 return success();
609}
610
611ParseResult StaticBlockOp::parse(OpAsmParser &parser, OperationState &result) {
612 return parseBlockLikeOp<StaticBlockOp>(parser, result);
613}
614
615void StaticBlockOp::print(OpAsmPrinter &p) {
616 return printBlockLikeOp(*this, p);
617}
618
619//===----------------------------------------------------------------------===//
620// IsolatedStaticBlockOp
621//===----------------------------------------------------------------------===//
622
623LogicalResult IsolatedStaticBlockOp::verify() {
624 if (getInputs().size() != getBodyBlock()->getNumArguments())
625 return emitOpError("number of inputs must match number of block arguments");
626
627 for (auto [arg, barg] :
628 llvm::zip(getInputs(), getBodyBlock()->getArguments())) {
629 if (arg.getType() != barg.getType())
630 return emitOpError("block argument type must match input type");
631 }
632
633 return success();
634}
635
636ParseResult IsolatedStaticBlockOp::parse(OpAsmParser &parser,
637 OperationState &result) {
638 return parseBlockLikeOp<IsolatedStaticBlockOp>(parser, result);
639}
640
641void IsolatedStaticBlockOp::print(OpAsmPrinter &p) {
642 return printBlockLikeOp(*this, p);
643}
644
645//===----------------------------------------------------------------------===//
646// DCBlockOp
647//===----------------------------------------------------------------------===//
648
649void DCBlockOp::build(OpBuilder &odsBuilder, OperationState &odsState,
650 TypeRange outputs, ValueRange inputs,
651 IntegerAttr maxThreads) {
652 odsState.addOperands(inputs);
653 if (maxThreads)
654 odsState.addAttribute(getMaxThreadsAttrName(odsState.name), maxThreads);
655 auto *region = odsState.addRegion();
656 llvm::SmallVector<Type> resTypes;
657 for (auto output : outputs) {
658 dc::ValueType dcType = dyn_cast<dc::ValueType>(output);
659 assert(dcType && "DCBlockOp outputs must be dc::ValueType");
660 resTypes.push_back(dcType);
661 }
662 odsState.addTypes(resTypes);
663 ensureTerminator(*region, odsBuilder, odsState.location);
664 llvm::SmallVector<Location> argLocs;
665 llvm::SmallVector<Type> argTypes;
666 for (auto input : inputs) {
667 argLocs.push_back(input.getLoc());
668 dc::ValueType dcType = dyn_cast<dc::ValueType>(input.getType());
669 assert(dcType && "DCBlockOp inputs must be dc::ValueType");
670 argTypes.push_back(dcType.getInnerType());
671 }
672 region->front().addArguments(argTypes, argLocs);
673}
674
675LogicalResult DCBlockOp::verify() {
676 if (getInputs().size() != getBodyBlock()->getNumArguments())
677 return emitOpError("number of inputs must match number of block arguments");
678
679 for (auto [arg, barg] :
680 llvm::zip(getInputs(), getBodyBlock()->getArguments())) {
681 dc::ValueType dcType = dyn_cast<dc::ValueType>(arg.getType());
682 if (!dcType)
683 return emitOpError("DCBlockOp inputs must be dc::ValueType but got ")
684 << arg.getType();
685
686 if (dcType.getInnerType() != barg.getType())
687 return emitOpError("block argument type must match input type. Got ")
688 << barg.getType() << " expected " << dcType.getInnerType();
689 }
690
691 return success();
692}
693
694ParseResult DCBlockOp::parse(OpAsmParser &parser, OperationState &result) {
695 return parseBlockLikeOp<DCBlockOp>(
696 parser, result, [&](OpAsmParser::Argument &arg) -> LogicalResult {
697 dc::ValueType valueType = dyn_cast<dc::ValueType>(arg.type);
698 if (!valueType)
699 return parser.emitError(parser.getCurrentLocation(),
700 "DCBlockOp inputs must be dc::ValueType");
701 arg.type = valueType.getInnerType();
702 return success();
703 });
704}
705
706void DCBlockOp::print(OpAsmPrinter &p) { return printBlockLikeOp(*this, p); }
707
708//===----------------------------------------------------------------------===//
709// BlockReturnOp
710//===----------------------------------------------------------------------===//
711
712LogicalResult BlockReturnOp::verify() {
713 Operation *parent = getOperation()->getParentOp();
714 auto parentBlock = dyn_cast<BlockOpInterface>(parent);
715 if (!parentBlock)
716 return emitOpError("must be nested in a block");
717
718 if (getNumOperands() != parent->getNumResults())
719 return emitOpError("number of operands must match number of block outputs");
720
721 for (auto [op, out] :
722 llvm::zip(getOperands(), parentBlock.getInternalResultTypes())) {
723 if (op.getType() != out)
724 return emitOpError(
725 "operand type must match parent block output type. Expected ")
726 << out << " got " << op.getType();
727 }
728
729 return success();
730}
731
732//===----------------------------------------------------------------------===//
733// InlineStaticBlockEndOp
734//===----------------------------------------------------------------------===//
735
736InlineStaticBlockBeginOp InlineStaticBlockEndOp::getBeginOp() {
737 auto curr = getOperation()->getReverseIterator();
738 Operation *firstOp = &getOperation()->getBlock()->front();
739 while (true) {
740 if (auto beginOp = dyn_cast<InlineStaticBlockBeginOp>(*curr))
741 return beginOp;
742 if (curr.getNodePtr() == firstOp)
743 break;
744 ++curr;
745 }
746 return nullptr;
747}
748
749//===----------------------------------------------------------------------===//
750// InlineStaticBlockBeginOp
751//===----------------------------------------------------------------------===//
752
753InlineStaticBlockEndOp InlineStaticBlockBeginOp::getEndOp() {
754 auto curr = getOperation()->getIterator();
755 auto end = getOperation()->getBlock()->end();
756 while (curr != end) {
757 if (auto endOp = dyn_cast<InlineStaticBlockEndOp>(*curr))
758 return endOp;
759
760 ++curr;
761 }
762 return nullptr;
763}
764
765//===----------------------------------------------------------------------===//
766// TableGen generated logic
767//===----------------------------------------------------------------------===//
768
769#include "circt/Dialect/Kanagawa/KanagawaInterfaces.cpp.inc"
770
771// Provide the autogenerated implementation guts for the Op classes.
772#define GET_OP_CLASSES
773#include "circt/Dialect/Kanagawa/Kanagawa.cpp.inc"
assert(baseType &&"element must be base type")
static PortInfo getPort(ModuleTy &mod, size_t idx)
Definition HWOps.cpp:1440
static InstancePath empty
ParseResult parseMethodLikeOp(OpAsmParser &parser, OperationState &result)
void printScopeRefFromName(OpAsmPrinter &p, Operation *op, Type type, TSymAttr sym)
static llvm::raw_string_ostream & genValueName(llvm::raw_string_ostream &os, Value value)
void printMethodLikeOp(TOp op, OpAsmPrinter &p)
static StringAttr genValueNameAttr(Value v)
ParseResult parseScopeRefFromName(OpAsmParser &parser, Type &scopeRefType, TSymAttr sym)
static void printBlockLikeOp(T op, OpAsmPrinter &p)
static ParseResult parseBlockLikeOp(OpAsmParser &parser, OperationState &result, llvm::function_ref< ParseResult(OpAsmParser::Argument &)> argAdjuster={})
static Block * getBodyBlock(FModuleLike mod)
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
LogicalResult verifyScopeOpInterface(Operation *op)
ParseResult parseInitializerList(mlir::OpAsmParser &parser, llvm::SmallVector< mlir::OpAsmParser::Argument > &inputArguments, llvm::SmallVector< mlir::OpAsmParser::UnresolvedOperand > &inputOperands, llvm::SmallVector< Type > &inputTypes, ArrayAttr &inputNames)
Parses an initializer.
void printInitializerList(OpAsmPrinter &p, ValueRange ins, ArrayRef< BlockArgument > args)
static StringAttr getNameFromSSA(MLIRContext *context, StringRef name)
Get a name from an SSA value string, if said value name is not a number.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:182
This class represents the namespace in which InnerRef's can be resolved.
Operation * lookupOp(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...