CIRCT 22.0.0git
Loading...
Searching...
No Matches
ArcOps.cpp
Go to the documentation of this file.
1//===- ArcOps.cpp ---------------------------------------------------------===//
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
11#include "mlir/Dialect/Func/IR/FuncOps.h"
12#include "mlir/IR/Builders.h"
13#include "mlir/IR/OpImplementation.h"
14#include "mlir/IR/PatternMatch.h"
15#include "mlir/IR/SymbolTable.h"
16#include "mlir/Interfaces/FunctionImplementation.h"
17#include "mlir/Interfaces/SideEffectInterfaces.h"
18#include "llvm/ADT/SmallPtrSet.h"
19#include "llvm/ADT/TypeSwitch.h"
20
21using namespace circt;
22using namespace arc;
23using namespace mlir;
24
25//===----------------------------------------------------------------------===//
26// Helpers
27//===----------------------------------------------------------------------===//
28
29static LogicalResult verifyTypeListEquivalence(Operation *op,
30 TypeRange expectedTypeList,
31 TypeRange actualTypeList,
32 StringRef elementName) {
33 if (expectedTypeList.size() != actualTypeList.size())
34 return op->emitOpError("incorrect number of ")
35 << elementName << "s: expected " << expectedTypeList.size()
36 << ", but got " << actualTypeList.size();
37
38 for (unsigned i = 0, e = expectedTypeList.size(); i != e; ++i) {
39 if (expectedTypeList[i] != actualTypeList[i]) {
40 auto diag = op->emitOpError(elementName)
41 << " type mismatch: " << elementName << " #" << i;
42 diag.attachNote() << "expected type: " << expectedTypeList[i];
43 diag.attachNote() << " actual type: " << actualTypeList[i];
44 return diag;
45 }
46 }
47
48 return success();
49}
50
51static LogicalResult verifyArcSymbolUse(Operation *op, TypeRange inputs,
52 TypeRange results,
53 SymbolTableCollection &symbolTable) {
54 // Check that the arc attribute was specified.
55 auto arcName = op->getAttrOfType<FlatSymbolRefAttr>("arc");
56 // The arc attribute is verified by the tablegen generated verifier as it is
57 // an ODS defined attribute.
58 assert(arcName && "FlatSymbolRefAttr called 'arc' missing");
59 DefineOp arc = symbolTable.lookupNearestSymbolFrom<DefineOp>(op, arcName);
60 if (!arc)
61 return op->emitOpError() << "`" << arcName.getValue()
62 << "` does not reference a valid `arc.define`";
63
64 // Verify that the operand and result types match the arc.
65 auto type = arc.getFunctionType();
66 if (failed(
67 verifyTypeListEquivalence(op, type.getInputs(), inputs, "operand")))
68 return failure();
69
70 if (failed(
71 verifyTypeListEquivalence(op, type.getResults(), results, "result")))
72 return failure();
73
74 return success();
75}
76
77static bool isSupportedModuleOp(Operation *moduleOp) {
78 return llvm::isa<arc::ModelOp, hw::HWModuleLike>(moduleOp);
79}
80
81/// Fetches the operation pointed to by `pointing` with name `symbol`, checking
82/// that it is a supported model operation for simulation.
83static Operation *getSupportedModuleOp(SymbolTableCollection &symbolTable,
84 Operation *pointing, StringAttr symbol) {
85 Operation *moduleOp = symbolTable.lookupNearestSymbolFrom(pointing, symbol);
86 if (!moduleOp) {
87 pointing->emitOpError("model not found");
88 return nullptr;
89 }
90
91 if (!isSupportedModuleOp(moduleOp)) {
92 pointing->emitOpError("model symbol does not point to a supported model "
93 "operation, points to ")
94 << moduleOp->getName() << " instead";
95 return nullptr;
96 }
97
98 return moduleOp;
99}
100
101static std::optional<hw::ModulePort> getModulePort(Operation *moduleOp,
102 StringRef portName) {
103 auto findRightPort = [&](auto ports) -> std::optional<hw::ModulePort> {
104 const hw::ModulePort *port = llvm::find_if(
105 ports, [&](hw::ModulePort port) { return port.name == portName; });
106 if (port == ports.end())
107 return std::nullopt;
108 return *port;
109 };
110
111 return TypeSwitch<Operation *, std::optional<hw::ModulePort>>(moduleOp)
112 .Case<arc::ModelOp>(
113 [&](arc::ModelOp modelOp) -> std::optional<hw::ModulePort> {
114 return findRightPort(modelOp.getIo().getPorts());
115 })
116 .Case<hw::HWModuleLike>(
117 [&](hw::HWModuleLike moduleLike) -> std::optional<hw::ModulePort> {
118 return findRightPort(moduleLike.getPortList());
119 })
120 .Default([](Operation *) { return std::nullopt; });
121}
122
123//===----------------------------------------------------------------------===//
124// DefineOp
125//===----------------------------------------------------------------------===//
126
127ParseResult DefineOp::parse(OpAsmParser &parser, OperationState &result) {
128 auto buildFuncType =
129 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
130 function_interface_impl::VariadicFlag,
131 std::string &) { return builder.getFunctionType(argTypes, results); };
132
133 return function_interface_impl::parseFunctionOp(
134 parser, result, /*allowVariadic=*/false,
135 getFunctionTypeAttrName(result.name), buildFuncType,
136 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
137}
138
139void DefineOp::print(OpAsmPrinter &p) {
140 function_interface_impl::printFunctionOp(
141 p, *this, /*isVariadic=*/false, "function_type", getArgAttrsAttrName(),
142 getResAttrsAttrName());
143}
144
145LogicalResult DefineOp::verifyRegions() {
146 // Check that the body does not contain any side-effecting operations. We can
147 // simply iterate over the ops directly within the body; operations with
148 // regions, like scf::IfOp, implement the `HasRecursiveMemoryEffects` trait
149 // which causes the `isMemoryEffectFree` check to already recur into their
150 // regions.
151 for (auto &op : getBodyBlock()) {
152 if (isMemoryEffectFree(&op))
153 continue;
154
155 // We don't use a op-error here because that leads to the whole arc being
156 // printed. This can be switched of when creating the context, but one
157 // might not want to switch that off for other error messages. Here it's
158 // definitely not desirable as arcs can be very big and would fill up the
159 // error log, making it hard to read. Currently, only the signature (first
160 // line) of the arc is printed.
161 auto diag = mlir::emitError(getLoc(), "body contains non-pure operation");
162 diag.attachNote(op.getLoc()).append("first non-pure operation here: ");
163 return diag;
164 }
165 return success();
166}
167
168bool DefineOp::isPassthrough() {
169 if (getNumArguments() != getNumResults())
170 return false;
171
172 return llvm::all_of(
173 llvm::zip(getArguments(), getBodyBlock().getTerminator()->getOperands()),
174 [](const auto &argAndRes) {
175 return std::get<0>(argAndRes) == std::get<1>(argAndRes);
176 });
177}
178
179//===----------------------------------------------------------------------===//
180// OutputOp
181//===----------------------------------------------------------------------===//
182
183LogicalResult OutputOp::verify() {
184 auto *parent = (*this)->getParentOp();
185 TypeRange expectedTypes = parent->getResultTypes();
186 if (auto defOp = dyn_cast<DefineOp>(parent))
187 expectedTypes = defOp.getResultTypes();
188
189 TypeRange actualTypes = getOperands().getTypes();
190 return verifyTypeListEquivalence(*this, expectedTypes, actualTypes, "output");
191}
192
193//===----------------------------------------------------------------------===//
194// StateOp
195//===----------------------------------------------------------------------===//
196
197LogicalResult StateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
198 return verifyArcSymbolUse(*this, getInputs().getTypes(),
199 getResults().getTypes(), symbolTable);
200}
201
202LogicalResult StateOp::verify() {
203 if (getLatency() < 1)
204 return emitOpError("latency must be a positive integer");
205
206 if (!getOperation()->getParentOfType<ClockDomainOp>() && !getClock())
207 return emitOpError("outside a clock domain requires a clock");
208
209 if (getOperation()->getParentOfType<ClockDomainOp>() && getClock())
210 return emitOpError("inside a clock domain cannot have a clock");
211
212 return success();
213}
214
215//===----------------------------------------------------------------------===//
216// StateWriteOp
217//===----------------------------------------------------------------------===//
218
219LogicalResult
220StateWriteOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
221 if (!getTraceTapModel().has_value())
222 return success();
223
224 auto modelOp = symbolTable.lookupNearestSymbolFrom<ModelOp>(
225 getOperation(), getTraceTapModelAttr());
226 if (!modelOp)
227 return emitOpError() << "`" << getTraceTapModelAttr()
228 << "` does not reference a valid `arc.model`";
229 if (!modelOp.getTraceTaps())
230 return emitOpError() << "referenced model has no trace metadata";
231 if (modelOp.getTraceTapsAttr().size() <= *getTraceTapIndex())
232 return emitOpError() << "tap index exceeds model's tap array";
233 auto tapAttr =
234 cast<TraceTapAttr>(modelOp.getTraceTapsAttr()[*getTraceTapIndex()]);
235 if (tapAttr.getSigType().getValue() != getValue().getType())
236 return emitOpError() << "incorrect signal type in referenced tap attribute";
237
238 return success();
239}
240
241LogicalResult StateWriteOp::verify() {
242 if (getTraceTapIndex().has_value() == getTraceTapModel().has_value())
243 return success();
244 return emitOpError() << "must specify both a trace tap model and index";
245}
246
247//===----------------------------------------------------------------------===//
248// CallOp
249//===----------------------------------------------------------------------===//
250
251LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
252 return verifyArcSymbolUse(*this, getInputs().getTypes(),
253 getResults().getTypes(), symbolTable);
254}
255
256bool CallOp::isClocked() { return false; }
257
258Value CallOp::getClock() { return Value{}; }
259
260void CallOp::eraseClock() {}
261
262uint32_t CallOp::getLatency() { return 0; }
263
264//===----------------------------------------------------------------------===//
265// MemoryWritePortOp
266//===----------------------------------------------------------------------===//
267
268SmallVector<Type> MemoryWritePortOp::getArcResultTypes() {
269 auto memType = cast<MemoryType>(getMemory().getType());
270 SmallVector<Type> resultTypes{memType.getAddressType(),
271 memType.getWordType()};
272 if (getEnable())
273 resultTypes.push_back(IntegerType::get(getContext(), 1));
274 if (getMask())
275 resultTypes.push_back(memType.getWordType());
276 return resultTypes;
277}
278
279LogicalResult
280MemoryWritePortOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
281 return verifyArcSymbolUse(*this, getInputs().getTypes(), getArcResultTypes(),
282 symbolTable);
283}
284
285LogicalResult MemoryWritePortOp::verify() {
286 if (getLatency() < 1)
287 return emitOpError("latency must be at least 1");
288
289 if (!getOperation()->getParentOfType<ClockDomainOp>() && !getClock())
290 return emitOpError("outside a clock domain requires a clock");
291
292 if (getOperation()->getParentOfType<ClockDomainOp>() && getClock())
293 return emitOpError("inside a clock domain cannot have a clock");
294
295 return success();
296}
297
298//===----------------------------------------------------------------------===//
299// ClockDomainOp
300//===----------------------------------------------------------------------===//
301
302LogicalResult ClockDomainOp::verifyRegions() {
303 return verifyTypeListEquivalence(*this, getBodyBlock().getArgumentTypes(),
304 getInputs().getTypes(), "input");
305}
306
307//===----------------------------------------------------------------------===//
308// RootInputOp
309//===----------------------------------------------------------------------===//
310
311void RootInputOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
312 SmallString<32> buf("in_");
313 buf += getName();
314 setNameFn(getState(), buf);
315}
316
317//===----------------------------------------------------------------------===//
318// RootOutputOp
319//===----------------------------------------------------------------------===//
320
321void RootOutputOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
322 SmallString<32> buf("out_");
323 buf += getName();
324 setNameFn(getState(), buf);
325}
326
327//===----------------------------------------------------------------------===//
328// ModelOp
329//===----------------------------------------------------------------------===//
330
331LogicalResult ModelOp::verify() {
332 if (getBodyBlock().getArguments().size() != 1)
333 return emitOpError("must have exactly one argument");
334 if (auto type = getBodyBlock().getArgument(0).getType();
335 !isa<StorageType>(type))
336 return emitOpError("argument must be of storage type");
337 for (const hw::ModulePort &port : getIo().getPorts())
338 if (port.dir == hw::ModulePort::Direction::InOut)
339 return emitOpError("inout ports are not supported");
340 return success();
341}
342
343LogicalResult ModelOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
344 auto fnAttrs = std::array{getInitialFnAttr(), getFinalFnAttr()};
345 auto nouns = std::array{"initializer", "finalizer"};
346 for (auto [fnAttr, noun] : llvm::zip(fnAttrs, nouns)) {
347 if (!fnAttr)
348 continue;
349 auto fn = symbolTable.lookupNearestSymbolFrom<func::FuncOp>(*this, fnAttr);
350 if (!fn)
351 return emitOpError() << noun << " '" << fnAttr.getValue()
352 << "' does not reference a valid function";
353 if (!llvm::equal(fn.getArgumentTypes(), getBody().getArgumentTypes())) {
354 auto diag = emitError() << noun << " '" << fnAttr.getValue()
355 << "' arguments must match arguments of model";
356 diag.attachNote(fn.getLoc()) << noun << " declared here:";
357 return diag;
358 }
359 }
360 return success();
361}
362
363//===----------------------------------------------------------------------===//
364// LutOp
365//===----------------------------------------------------------------------===//
366
367LogicalResult LutOp::verify() {
368 Location firstSideEffectOpLoc = UnknownLoc::get(getContext());
369 const WalkResult result = getBody().walk([&](Operation *op) {
370 if (auto memOp = dyn_cast<MemoryEffectOpInterface>(op)) {
371 SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>> effects;
372 memOp.getEffects(effects);
373
374 if (!effects.empty()) {
375 firstSideEffectOpLoc = memOp->getLoc();
376 return WalkResult::interrupt();
377 }
378 }
379
380 return WalkResult::advance();
381 });
382
383 if (result.wasInterrupted())
384 return emitOpError("no operations with side-effects allowed inside a LUT")
385 .attachNote(firstSideEffectOpLoc)
386 << "first operation with side-effects here";
387
388 return success();
389}
390
391//===----------------------------------------------------------------------===//
392// VectorizeOp
393//===----------------------------------------------------------------------===//
394
395LogicalResult VectorizeOp::verify() {
396 if (getInputs().empty())
397 return emitOpError("there has to be at least one input vector");
398
399 if (!llvm::all_equal(llvm::map_range(
400 getInputs(), [](OperandRange range) { return range.size(); })))
401 return emitOpError("all input vectors must have the same size");
402
403 for (OperandRange range : getInputs()) {
404 if (!llvm::all_equal(range.getTypes()))
405 return emitOpError("all input vector lane types must match");
406
407 if (range.empty())
408 return emitOpError("input vector must have at least one element");
409 }
410
411 if (getResults().empty())
412 return emitOpError("must have at least one result");
413
414 if (!llvm::all_equal(getResults().getTypes()))
415 return emitOpError("all result types must match");
416
417 if (getResults().size() != getInputs().front().size())
418 return emitOpError("number results must match input vector size");
419
420 return success();
421}
422
423static FailureOr<unsigned> getVectorWidth(Type base, Type vectorized) {
424 if (isa<VectorType>(base))
425 return failure();
426
427 if (auto vectorTy = dyn_cast<VectorType>(vectorized)) {
428 if (vectorTy.getElementType() != base)
429 return failure();
430
431 return vectorTy.getDimSize(0);
432 }
433
434 if (vectorized.getIntOrFloatBitWidth() < base.getIntOrFloatBitWidth())
435 return failure();
436
437 if (vectorized.getIntOrFloatBitWidth() % base.getIntOrFloatBitWidth() == 0)
438 return vectorized.getIntOrFloatBitWidth() / base.getIntOrFloatBitWidth();
439
440 return failure();
441}
442
443LogicalResult VectorizeOp::verifyRegions() {
444 auto returnOp = cast<VectorizeReturnOp>(getBody().front().getTerminator());
445 TypeRange bodyArgTypes = getBody().front().getArgumentTypes();
446
447 if (bodyArgTypes.size() != getInputs().size())
448 return emitOpError(
449 "number of block arguments must match number of input vectors");
450
451 // Boundary and body are vectorized, or both are not vectorized
452 if (returnOp.getValue().getType() == getResultTypes().front()) {
453 for (auto [i, argTy] : llvm::enumerate(bodyArgTypes))
454 if (argTy != getInputs()[i].getTypes().front())
455 return emitOpError("if terminator type matches result type the "
456 "argument types must match the input types");
457
458 return success();
459 }
460
461 // Boundary is vectorized, body is not
462 if (auto width = getVectorWidth(returnOp.getValue().getType(),
463 getResultTypes().front());
464 succeeded(width)) {
465 for (auto [i, argTy] : llvm::enumerate(bodyArgTypes)) {
466 Type inputTy = getInputs()[i].getTypes().front();
467 FailureOr<unsigned> argWidth = getVectorWidth(argTy, inputTy);
468 if (failed(argWidth))
469 return emitOpError("block argument must be a scalar variant of the "
470 "vectorized operand");
471
472 if (*argWidth != width)
473 return emitOpError("input and output vector width must match");
474 }
475
476 return success();
477 }
478
479 // Body is vectorized, boundary is not
480 if (auto width = getVectorWidth(getResultTypes().front(),
481 returnOp.getValue().getType());
482 succeeded(width)) {
483 for (auto [i, argTy] : llvm::enumerate(bodyArgTypes)) {
484 Type inputTy = getInputs()[i].getTypes().front();
485 FailureOr<unsigned> argWidth = getVectorWidth(inputTy, argTy);
486 if (failed(argWidth))
487 return emitOpError(
488 "block argument must be a vectorized variant of the operand");
489
490 if (*argWidth != width)
491 return emitOpError("input and output vector width must match");
492
493 if (getInputs()[i].size() > 1 && argWidth != getInputs()[i].size())
494 return emitOpError(
495 "when boundary not vectorized the number of vector element "
496 "operands must match the width of the vectorized body");
497 }
498
499 return success();
500 }
501
502 return returnOp.emitOpError(
503 "operand type must match parent op's result value or be a vectorized or "
504 "non-vectorized variant of it");
505}
506
507bool VectorizeOp::isBoundaryVectorized() {
508 return getInputs().front().size() == 1;
509}
510bool VectorizeOp::isBodyVectorized() {
511 auto returnOp = cast<VectorizeReturnOp>(getBody().front().getTerminator());
512 if (isBoundaryVectorized() &&
513 returnOp.getValue().getType() == getResultTypes().front())
514 return true;
515
516 if (auto width = getVectorWidth(getResultTypes().front(),
517 returnOp.getValue().getType());
518 succeeded(width))
519 return *width > 1;
520
521 return false;
522}
523
524//===----------------------------------------------------------------------===//
525// SimInstantiateOp
526//===----------------------------------------------------------------------===//
527
528void SimInstantiateOp::print(OpAsmPrinter &p) {
529 BlockArgument modelArg = getBody().getArgument(0);
530 auto modelType = cast<SimModelInstanceType>(modelArg.getType());
531
532 p << " " << modelType.getModel() << " as ";
533 p.printRegionArgument(modelArg, {}, true);
534
535 if (getRuntimeModel() || getRuntimeArgs()) {
536 p << " runtime ";
537 if (getRuntimeModel())
538 p << getRuntimeModelAttr();
539 p << "(";
540 if (getRuntimeArgs())
541 p << getRuntimeArgsAttr();
542 p << ")";
543 }
544
545 p.printOptionalAttrDictWithKeyword(
546 getOperation()->getAttrs(),
547 {getRuntimeModelAttrName(), getRuntimeArgsAttrName()});
548
549 p << " ";
550
551 p.printRegion(getBody(), false);
552}
553
554ParseResult SimInstantiateOp::parse(OpAsmParser &parser,
555 OperationState &result) {
556 StringAttr modelName;
557 if (failed(parser.parseSymbolName(modelName)))
558 return failure();
559
560 if (failed(parser.parseKeyword("as")))
561 return failure();
562
563 OpAsmParser::Argument modelArg;
564 if (failed(parser.parseArgument(modelArg, false, false)))
565 return failure();
566
567 if (succeeded(parser.parseOptionalKeyword("runtime"))) {
568 StringAttr runtimeSym;
569 StringAttr runtimeArgs;
570 auto symOpt = parser.parseOptionalSymbolName(runtimeSym);
571 if (parser.parseLParen())
572 return failure();
573 auto nameOpt = parser.parseOptionalAttribute(runtimeArgs);
574 if (parser.parseRParen())
575 return failure();
576 if (succeeded(symOpt))
577 result.addAttribute(
578 SimInstantiateOp::getRuntimeModelAttrName(result.name),
579 FlatSymbolRefAttr::get(runtimeSym));
580 if (nameOpt.has_value())
581 result.addAttribute(SimInstantiateOp::getRuntimeArgsAttrName(result.name),
582 runtimeArgs);
583 }
584
585 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
586 return failure();
587
588 MLIRContext *ctxt = result.getContext();
589 modelArg.type =
590 SimModelInstanceType::get(ctxt, FlatSymbolRefAttr::get(ctxt, modelName));
591
592 std::unique_ptr<Region> body = std::make_unique<Region>();
593 if (failed(parser.parseRegion(*body, {modelArg})))
594 return failure();
595
596 result.addRegion(std::move(body));
597 return success();
598}
599
600LogicalResult SimInstantiateOp::verifyRegions() {
601 Region &body = getBody();
602 if (body.getNumArguments() != 1)
603 return emitError("entry block of body region must have the model instance "
604 "as a single argument");
605 if (!llvm::isa<SimModelInstanceType>(body.getArgument(0).getType()))
606 return emitError("entry block argument type is not a model instance");
607 return success();
608}
609
610LogicalResult
611SimInstantiateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
612 bool failed = false;
613 Operation *moduleOp = getSupportedModuleOp(
614 symbolTable, getOperation(),
615 llvm::cast<SimModelInstanceType>(getBody().getArgument(0).getType())
616 .getModel()
617 .getAttr());
618 if (!moduleOp)
619 failed = true;
620
621 if (getRuntimeModel().has_value()) {
622 Operation *runtimeModelOp = symbolTable.lookupNearestSymbolFrom(
623 getOperation(), getRuntimeModelAttr());
624 if (!runtimeModelOp) {
625 emitOpError("runtime model not found");
626 failed = true;
627 } else if (!isa<RuntimeModelOp>(runtimeModelOp)) {
628 emitOpError("referenced runtime model is not a RuntimeModelOp");
629 failed = true;
630 }
631 }
632
633 return success(!failed);
634}
635
636//===----------------------------------------------------------------------===//
637// SimSetInputOp
638//===----------------------------------------------------------------------===//
639
640LogicalResult
641SimSetInputOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
642 Operation *moduleOp = getSupportedModuleOp(
643 symbolTable, getOperation(),
644 llvm::cast<SimModelInstanceType>(getInstance().getType())
645 .getModel()
646 .getAttr());
647 if (!moduleOp)
648 return failure();
649
650 std::optional<hw::ModulePort> port = getModulePort(moduleOp, getInput());
651 if (!port)
652 return emitOpError("port not found on model");
653
654 if (port->dir != hw::ModulePort::Direction::Input &&
655 port->dir != hw::ModulePort::Direction::InOut)
656 return emitOpError("port is not an input port");
657
658 if (port->type != getValue().getType())
659 return emitOpError(
660 "mismatched types between value and model port, port expects ")
661 << port->type;
662
663 return success();
664}
665
666//===----------------------------------------------------------------------===//
667// SimGetPortOp
668//===----------------------------------------------------------------------===//
669
670LogicalResult
671SimGetPortOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
672 Operation *moduleOp = getSupportedModuleOp(
673 symbolTable, getOperation(),
674 llvm::cast<SimModelInstanceType>(getInstance().getType())
675 .getModel()
676 .getAttr());
677 if (!moduleOp)
678 return failure();
679
680 std::optional<hw::ModulePort> port = getModulePort(moduleOp, getPort());
681 if (!port)
682 return emitOpError("port not found on model");
683
684 if (port->type != getValue().getType())
685 return emitOpError(
686 "mismatched types between value and model port, port expects ")
687 << port->type;
688
689 return success();
690}
691
692//===----------------------------------------------------------------------===//
693// SimStepOp
694//===----------------------------------------------------------------------===//
695
696LogicalResult SimStepOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
697 Operation *moduleOp = getSupportedModuleOp(
698 symbolTable, getOperation(),
699 llvm::cast<SimModelInstanceType>(getInstance().getType())
700 .getModel()
701 .getAttr());
702 if (!moduleOp)
703 return failure();
704
705 return success();
706}
707
708//===----------------------------------------------------------------------===//
709// ExecuteOp
710//===----------------------------------------------------------------------===//
711
712LogicalResult ExecuteOp::verifyRegions() {
713 return verifyTypeListEquivalence(*this, getInputs().getTypes(),
714 getBody().getArgumentTypes(), "input");
715}
716
717#include "circt/Dialect/Arc/ArcInterfaces.cpp.inc"
718
719#define GET_OP_CLASSES
720#include "circt/Dialect/Arc/Arc.cpp.inc"
static FailureOr< unsigned > getVectorWidth(Type base, Type vectorized)
Definition ArcOps.cpp:423
static std::optional< hw::ModulePort > getModulePort(Operation *moduleOp, StringRef portName)
Definition ArcOps.cpp:101
static bool isSupportedModuleOp(Operation *moduleOp)
Definition ArcOps.cpp:77
static LogicalResult verifyArcSymbolUse(Operation *op, TypeRange inputs, TypeRange results, SymbolTableCollection &symbolTable)
Definition ArcOps.cpp:51
static LogicalResult verifyTypeListEquivalence(Operation *op, TypeRange expectedTypeList, TypeRange actualTypeList, StringRef elementName)
Definition ArcOps.cpp:29
static Operation * getSupportedModuleOp(SymbolTableCollection &symbolTable, Operation *pointing, StringAttr symbol)
Fetches the operation pointed to by pointing with name symbol, checking that it is a supported model ...
Definition ArcOps.cpp:83
assert(baseType &&"element must be base type")
static PortInfo getPort(ModuleTy &mod, size_t idx)
Definition HWOps.cpp:1448
@ InOut
Definition HW.h:42
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:216
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
Definition arc.py:1
Direction
The direction of a Component or Cell port.
Definition CalyxOps.h:76
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:183
mlir::StringAttr name
Definition HWTypes.h:30