15#include "mlir/IR/BuiltinOps.h"
16#include "llvm/ADT/TypeSwitch.h"
20#define GEN_PASS_DEF_VERIFYAXI4NETWORKS
21#include "circt/Dialect/AXI4/AXI4Passes.h.inc"
38 return TypeSwitch<Operation *, FailureOr<Domain>>(op)
39 .Case<AbstractManagerOp, AbstractSubordinateOp, ChannelStructsToPortOp,
40 PortToChannelStructsOp, XbarOp>([](
auto op) {
41 return Domain{op.getClock(), op.getReset()};
43 .Default([](Operation *op) -> FailureOr<Domain> {
44 op->emitOpError(
"unsupported AXI4 network op; cannot verify which "
45 "clock and reset domain it is in");
52 if (!isa<PortType>(port.getType()))
54 if (port.use_empty()) {
55 mlir::emitWarning(port.getLoc())
56 <<
"AXI4 port has no uses, so takes no part in a network";
59 if (port.hasNUsesOrMore(2))
60 return mlir::emitError(port.getLoc())
61 <<
"AXI4 port must have at most one use; route through an "
62 "'axi4.xbar' to fan out to multiple endpoints";
69 auto diag = op->emitOpError()
70 <<
"is in a different " << domain <<
" domain to the '"
71 << other->getName().getStringRef() <<
"' connected to it";
72 diag.attachNote(other->getLoc()) <<
"connected operation here";
79 uint32_t writes, uint32_t reads) {
80 PortType reaching = port.getType();
81 if (writes < reaching.getOutstandingWrites())
82 op->emitWarning() <<
"endpoint can handle fewer writes than the port "
83 "reaching it can have concurrently outstanding ("
84 << writes <<
" < " << reaching.getOutstandingWrites()
86 if (reads < reaching.getOutstandingReads())
87 op->emitWarning() <<
"endpoint can handle fewer reads than the port "
88 "reaching it can have concurrently outstanding ("
89 << reads <<
" < " << reaching.getOutstandingReads()
94struct VerifyAXI4NetworksPass
95 :
public circt::axi4::impl::VerifyAXI4NetworksBase<VerifyAXI4NetworksPass> {
96 void runOnOperation()
override;
100void VerifyAXI4NetworksPass::runOnOperation() {
101 ModuleOp
module = getOperation();
102 Dialect *axi4Dialect =
module->getContext()->getLoadedDialect<AXI4Dialect>();
103 bool anyFailed =
false;
106 module.walk([&](Operation *op) {
107 for (Value result : op->getResults())
108 if (failed(verifyPortUses(result)))
110 for (Region ®ion : op->getRegions())
111 for (
Block &block : region)
112 for (BlockArgument arg : block.getArguments())
118 module.walk([&](Operation *op) {
119 if (op->getDialect() != axi4Dialect)
121 FailureOr<Domain> domain =
getDomain(op);
122 if (failed(domain)) {
127 for (Value operand : op->getOperands()) {
128 if (!isa<PortType>(operand.getType()))
131 Operation *upstream = operand.getDefiningOp();
132 if (!upstream || upstream->getDialect() != axi4Dialect)
135 FailureOr<Domain> upstreamDomain =
getDomain(upstream);
136 if (failed(upstreamDomain)) {
140 if (domain->clock != upstreamDomain->clock) {
144 if (domain->reset != upstreamDomain->reset) {
153 module.walk([](Operation *op) {
154 TypeSwitch<Operation *>(op)
155 .Case<AbstractSubordinateOp>([](AbstractSubordinateOp subordinate) {
156 warnBottleneck(subordinate, subordinate.getUpstream(),
157 subordinate.getConcurrentWrites(),
158 subordinate.getConcurrentReads());
160 .Case<PortToChannelStructsOp>([](PortToChannelStructsOp bridge) {
161 warnBottleneck(bridge, bridge.getPort(), bridge.getConcurrentWrites(),
162 bridge.getConcurrentReads());
static void emitDomainCrossing(Operation *op, Operation *other, StringRef domain)
Report two ops connected by a port but operating in different domains.
static FailureOr< Domain > getDomain(Operation *op)
The domain of an AXI4 op, or failure for one this pass does not know.
static LogicalResult verifyPortUses(Value port)
Report a port value with more than one consumer, or with none at all.
static void warnBottleneck(Operation *op, TypedValue< PortType > port, uint32_t writes, uint32_t reads)
Report an endpoint that can handle fewer requests than the port reaching it can have concurrently out...
Domain
The number of values each bit of a type can assume.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.