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