CIRCT 22.0.0git
Loading...
Searching...
No Matches
HWBypassInnerSymbols.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass moves inner symbols from ports to wires, then bypasses wire
10// operations with inner symbols by replacing uses with their inputs while
11// keeping the wire to preserve the symbol. This enables optimizations to
12// cross symbol boundaries while maintaining symbol references.
13//
14// Note: This transformation assumes that values associated with inner
15// symbols are not mutated through inner symbols (e.g. force). This assumption
16// may not hold in design verification contexts, but is safe in synthesis.
17//
18//===----------------------------------------------------------------------===//
19
23#include "mlir/IR/PatternMatch.h"
24#include "mlir/Transforms/WalkPatternRewriteDriver.h"
25
26namespace circt {
27namespace hw {
28#define GEN_PASS_DEF_HWBYPASSINNERSYMBOLS
29#include "circt/Dialect/HW/Passes.h.inc"
30} // namespace hw
31} // namespace circt
32
33using namespace circt;
34using namespace circt::hw;
35
36namespace {
37struct HWBypassInnerSymbolsPass
38 : public impl::HWBypassInnerSymbolsBase<HWBypassInnerSymbolsPass> {
39 void runOnOperation() override;
40 using HWBypassInnerSymbolsBase<
41 HWBypassInnerSymbolsPass>::HWBypassInnerSymbolsBase;
42};
43
44/// Pattern to bypass wire operations with inner symbols.
45struct BypassWireWithInnerSym : public OpRewritePattern<WireOp> {
47
48 LogicalResult matchAndRewrite(WireOp wire,
49 PatternRewriter &rewriter) const override {
50 // Only bypass wires that have an inner symbol or use
51 if (!wire.getInnerSymAttr() || wire.use_empty())
52 return failure();
53
54 // Replace all uses of the wire with its input
55 rewriter.modifyOpInPlace(wire, [&] {
56 wire->replaceAllUsesWith(ArrayRef<Value>{wire.getInput()});
57 });
58 return success();
59 }
60};
61} // namespace
62
63void HWBypassInnerSymbolsPass::runOnOperation() {
64 auto module = getOperation();
65
66 // First move the inner symbol from the port to allow constprop and other
67 // optimizations to cross the boundary.
68 hw::ModulePortInfo portList(module.getPortList());
69 auto *outputOp = module.getBodyBlock()->getTerminator();
70 OpBuilder builder(&getContext());
71 bool hasInnerSym = false;
72 auto moduleType = module.getModuleType();
73 for (auto [index, port] : llvm::enumerate(portList)) {
74 auto sym = port.getSym();
75 if (!sym)
76 continue;
77 hasInnerSym = true;
78 ++numPortsMoved;
79 if (port.isOutput()) {
80 auto value = outputOp->getOperand(moduleType.getOutputIdForPortId(index));
81 builder.setInsertionPointAfterValue(value);
82 auto wire = WireOp::create(builder, value.getLoc(), value);
83 wire.setInnerSymAttr(sym);
84 } else {
85 auto arg = module.getBodyBlock()->getArgument(
86 moduleType.getInputIdForPortId(index));
87 builder.setInsertionPointToStart(module.getBodyBlock());
88 auto wire = WireOp::create(builder, arg.getLoc(), arg);
89 wire.setInnerSymAttr(sym);
90 }
91 }
92
93 if (hasInnerSym) {
94 // Bulk clear all port symbols.
95 auto innerSymAttr = StringAttr::get(
96 &getContext(), hw::HWModuleLike::getPortSymbolAttrName());
97 SmallVector<Attribute, 0> newAttrs(portList.size(), {});
98 cast<HWModuleLike>(*module).setPortAttrs(innerSymAttr, newAttrs);
99 }
100
101 RewritePatternSet patterns(&getContext());
102 patterns.add<BypassWireWithInnerSym>(&getContext());
103 mlir::walkAndApplyPatterns(module, std::move(patterns));
104}
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
This holds a decoded list of input/inout and output ports for a module or instance.