20 #include "mlir/Pass/Pass.h"
24 #define GEN_PASS_DEF_HWCLEANUP
25 #include "circt/Dialect/SV/SVPasses.h.inc"
29 using namespace circt;
40 static unsigned getHashValue(
const Operation *opC) {
41 return mlir::OperationEquivalence::computeHash(
42 const_cast<Operation *
>(opC),
43 mlir::OperationEquivalence::directHashValue,
44 mlir::OperationEquivalence::ignoreHashValue,
45 mlir::OperationEquivalence::IgnoreLocations);
47 static bool isEqual(
const Operation *lhsC,
const Operation *rhsC) {
48 auto *lhs =
const_cast<Operation *
>(lhsC);
49 auto *rhs =
const_cast<Operation *
>(rhsC);
54 if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
55 rhs == getTombstoneKey() || rhs == getEmptyKey())
58 if (lhs->getName() != rhs->getName() ||
59 lhs->getAttrDictionary() != rhs->getAttrDictionary() ||
60 lhs->getNumOperands() != rhs->getNumOperands())
63 for (
auto operandPair : llvm::zip(lhs->getOperands(), rhs->getOperands())) {
64 Value lhsOperand = std::get<0>(operandPair);
65 Value rhsOperand = std::get<1>(operandPair);
66 if (lhsOperand != rhsOperand)
78 assert(region1->getBlocks().size() <= 1 && region2->getBlocks().size() <= 1 &&
79 "Can only merge regions with a single block");
80 if (region1->empty()) {
85 region1->getBlocks().splice(region1->end(), region2->getBlocks());
91 if (!region2->empty()) {
92 auto &block1 = region1->front();
93 auto &block2 = region2->front();
94 block1.getOperations().splice(block1.begin(), block2.getOperations());
103 struct HWCleanupPass :
public circt::sv::impl::HWCleanupBase<HWCleanupPass> {
104 using sv::impl::HWCleanupBase<HWCleanupPass>::mergeAlwaysBlocks;
106 void runOnOperation()
override;
108 void runOnRegionsInOp(Operation &op);
109 void runOnGraphRegion(Region ®ion);
110 void runOnProceduralRegion(Region ®ion);
115 void mergeOperationsIntoFrom(Operation *op1, Operation *op2) {
119 assert(op1 != op2 &&
"Cannot merge an op into itself");
120 for (
size_t i = 0, e = op1->getNumRegions(); i != e; ++i)
124 anythingChanged =
true;
127 bool anythingChanged;
131 void HWCleanupPass::runOnOperation() {
134 anythingChanged =
false;
135 runOnGraphRegion(getOperation().getBody());
139 if (!anythingChanged)
140 markAllAnalysesPreserved();
145 void HWCleanupPass::runOnRegionsInOp(Operation &op) {
146 if (op.hasTrait<sv::ProceduralRegion>()) {
147 for (
auto ®ion : op.getRegions())
148 runOnProceduralRegion(region);
150 for (
auto ®ion : op.getRegions())
151 runOnGraphRegion(region);
156 void HWCleanupPass::runOnGraphRegion(Region ®ion) {
157 if (region.getBlocks().size() != 1)
159 Block &body = region.front();
164 DenseSet<Operation *, AlwaysLikeOpInfo> alwaysFFOpsSeen;
166 sv::InitialOp initialOpSeen;
168 for (Operation &op : llvm::make_early_inc_range(body)) {
171 if (isa<sv::AlwaysOp, sv::AlwaysFFOp>(op) && mergeAlwaysBlocks) {
173 auto itAndInserted = alwaysFFOpsSeen.insert(&op);
174 if (itAndInserted.second)
176 auto *existingAlways = *itAndInserted.first;
177 mergeOperationsIntoFrom(&op, existingAlways);
179 *itAndInserted.first = &op;
184 if (
auto ifdefOp = dyn_cast<sv::IfDefOp>(op)) {
185 auto *&entry = ifdefOps[ifdefOp.getCondAttr()];
187 mergeOperationsIntoFrom(ifdefOp, entry);
194 if (
auto initialOp = dyn_cast<sv::InitialOp>(op)) {
196 mergeOperationsIntoFrom(initialOp, initialOpSeen);
197 initialOpSeen = initialOp;
202 for (Operation &op : llvm::make_early_inc_range(body)) {
204 if (op.getNumRegions() != 0)
205 runOnRegionsInOp(op);
210 void HWCleanupPass::runOnProceduralRegion(Region ®ion) {
211 if (region.getBlocks().size() != 1)
213 Block &body = region.front();
215 Operation *lastSideEffectingOp =
nullptr;
216 for (Operation &op : llvm::make_early_inc_range(body)) {
218 if (
auto ifdef = dyn_cast<sv::IfDefProceduralOp>(op)) {
220 dyn_cast_or_null<sv::IfDefProceduralOp>(lastSideEffectingOp)) {
221 if (ifdef.getCond() == prevIfDef.getCond()) {
224 mergeOperationsIntoFrom(ifdef, prevIfDef);
230 if (
auto ifop = dyn_cast<sv::IfOp>(op)) {
231 if (
auto prevIf = dyn_cast_or_null<sv::IfOp>(lastSideEffectingOp)) {
232 if (ifop.getCond() == prevIf.getCond()) {
235 mergeOperationsIntoFrom(ifop, prevIf);
241 if (!mlir::isMemoryEffectFree(&op))
242 lastSideEffectingOp = &op;
245 for (Operation &op : llvm::make_early_inc_range(body)) {
247 if (op.getNumRegions() != 0)
248 runOnRegionsInOp(op);
253 auto pass = std::make_unique<HWCleanupPass>();
254 pass->mergeAlwaysBlocks = mergeAlwaysBlocks;
assert(baseType &&"element must be base type")
static void mergeRegions(Region *region1, Region *region2)
bool hasSVAttributes(mlir::Operation *op)
Helper functions to handle SV attributes.
std::unique_ptr< mlir::Pass > createHWCleanupPass(bool mergeAlwaysBlocks=true)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.