21#include "mlir/Pass/Pass.h"
25#define GEN_PASS_DEF_HWCLEANUP
26#include "circt/Dialect/SV/SVPasses.h.inc"
41 static unsigned getHashValue(
const Operation *opC) {
42 return mlir::OperationEquivalence::computeHash(
43 const_cast<Operation *
>(opC),
44 mlir::OperationEquivalence::directHashValue,
45 mlir::OperationEquivalence::ignoreHashValue,
46 mlir::OperationEquivalence::IgnoreLocations);
48 static bool isEqual(
const Operation *lhsC,
const Operation *rhsC) {
49 auto *lhs =
const_cast<Operation *
>(lhsC);
50 auto *rhs =
const_cast<Operation *
>(rhsC);
55 if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
56 rhs == getTombstoneKey() || rhs == getEmptyKey())
59 if (lhs->getName() != rhs->getName() ||
60 lhs->getAttrDictionary() != rhs->getAttrDictionary() ||
61 lhs->getNumOperands() != rhs->getNumOperands())
64 for (
auto operandPair :
llvm::zip(lhs->getOperands(), rhs->getOperands())) {
65 Value lhsOperand = std::get<0>(operandPair);
66 Value rhsOperand = std::get<1>(operandPair);
67 if (lhsOperand != rhsOperand)
79 assert(region1->getBlocks().size() <= 1 && region2->getBlocks().size() <= 1 &&
80 "Can only merge regions with a single block");
81 if (region1->empty()) {
86 region1->getBlocks().splice(region1->end(), region2->getBlocks());
92 if (!region2->empty()) {
93 auto &block1 = region1->front();
94 auto &block2 = region2->front();
95 block1.getOperations().splice(block1.begin(), block2.getOperations());
104struct HWCleanupPass :
public circt::sv::impl::HWCleanupBase<HWCleanupPass> {
106 using sv::impl::HWCleanupBase<HWCleanupPass>::mergeAlwaysBlocks;
108 void runOnOperation()
override;
110 void runOnRegionsInOp(Operation &op);
111 void runOnGraphRegion(Region ®ion);
112 void runOnProceduralRegion(Region ®ion);
117 void mergeOperationsIntoFrom(Operation *op1, Operation *op2) {
119 if (sv::hasSVAttributes(op1) || sv::hasSVAttributes(op2))
121 assert(op1 != op2 &&
"Cannot merge an op into itself");
122 for (
size_t i = 0, e = op1->getNumRegions(); i != e; ++i)
126 anythingChanged =
true;
129 bool anythingChanged;
133void HWCleanupPass::runOnOperation() {
136 anythingChanged =
false;
137 runOnGraphRegion(getOperation().getBody());
141 if (!anythingChanged)
142 markAllAnalysesPreserved();
147void HWCleanupPass::runOnRegionsInOp(Operation &op) {
149 for (
auto ®ion : op.getRegions())
150 runOnProceduralRegion(region);
152 for (
auto ®ion : op.getRegions())
153 runOnGraphRegion(region);
158void HWCleanupPass::runOnGraphRegion(Region ®ion) {
159 if (region.getBlocks().size() != 1)
161 Block &body = region.front();
166 DenseSet<Operation *, AlwaysLikeOpInfo> alwaysFFOpsSeen;
168 sv::InitialOp initialOpSeen;
170 for (Operation &op :
llvm::make_early_inc_range(body)) {
173 if (isa<sv::AlwaysOp, sv::AlwaysFFOp>(op) && mergeAlwaysBlocks) {
175 auto itAndInserted = alwaysFFOpsSeen.insert(&op);
176 if (itAndInserted.second)
178 auto *existingAlways = *itAndInserted.first;
179 mergeOperationsIntoFrom(&op, existingAlways);
181 *itAndInserted.first = &op;
186 if (
auto ifdefOp = dyn_cast<sv::IfDefOp>(op)) {
187 auto *&entry = ifdefOps[ifdefOp.getCondAttr()];
189 mergeOperationsIntoFrom(ifdefOp, entry);
196 if (
auto initialOp = dyn_cast<sv::InitialOp>(op)) {
198 mergeOperationsIntoFrom(initialOp, initialOpSeen);
199 initialOpSeen = initialOp;
204 for (Operation &op :
llvm::make_early_inc_range(body)) {
206 if (op.getNumRegions() != 0)
207 runOnRegionsInOp(op);
212void HWCleanupPass::runOnProceduralRegion(Region ®ion) {
213 if (region.getBlocks().size() != 1)
215 Block &body = region.front();
217 Operation *lastSideEffectingOp =
nullptr;
218 for (Operation &op :
llvm::make_early_inc_range(body)) {
220 if (
auto ifdef = dyn_cast<sv::IfDefProceduralOp>(op)) {
222 dyn_cast_or_null<sv::IfDefProceduralOp>(lastSideEffectingOp)) {
223 if (ifdef.getCond() == prevIfDef.getCond()) {
226 mergeOperationsIntoFrom(ifdef, prevIfDef);
232 if (
auto ifop = dyn_cast<sv::IfOp>(op)) {
233 if (
auto prevIf = dyn_cast_or_null<sv::IfOp>(lastSideEffectingOp)) {
234 if (ifop.getCond() == prevIf.getCond()) {
237 mergeOperationsIntoFrom(ifop, prevIf);
243 if (!mlir::isMemoryEffectFree(&op))
244 lastSideEffectingOp = &op;
247 for (Operation &op :
llvm::make_early_inc_range(body)) {
249 if (op.getNumRegions() != 0)
250 runOnRegionsInOp(op);
assert(baseType &&"element must be base type")
static void mergeRegions(Region *region1, Region *region2)
Signals that an operation's regions are procedural.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.