20#include "mlir/Pass/Pass.h"
24#define GEN_PASS_DEF_HWCLEANUP
25#include "circt/Dialect/SV/SVPasses.h.inc"
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());
103struct HWCleanupPass :
public circt::sv::impl::HWCleanupBase<HWCleanupPass> {
105 using sv::impl::HWCleanupBase<HWCleanupPass>::mergeAlwaysBlocks;
107 void runOnOperation()
override;
109 void runOnRegionsInOp(Operation &op);
110 void runOnGraphRegion(Region ®ion);
111 void runOnProceduralRegion(Region ®ion);
116 void mergeOperationsIntoFrom(Operation *op1, Operation *op2) {
118 if (sv::hasSVAttributes(op1) || sv::hasSVAttributes(op2))
120 assert(op1 != op2 &&
"Cannot merge an op into itself");
121 for (
size_t i = 0, e = op1->getNumRegions(); i != e; ++i)
125 anythingChanged =
true;
128 bool anythingChanged;
132void HWCleanupPass::runOnOperation() {
135 anythingChanged =
false;
136 runOnGraphRegion(getOperation().getBody());
140 if (!anythingChanged)
141 markAllAnalysesPreserved();
146void HWCleanupPass::runOnRegionsInOp(Operation &op) {
148 for (
auto ®ion : op.getRegions())
149 runOnProceduralRegion(region);
151 for (
auto ®ion : op.getRegions())
152 runOnGraphRegion(region);
157void HWCleanupPass::runOnGraphRegion(Region ®ion) {
158 if (region.getBlocks().size() != 1)
160 Block &body = region.front();
165 DenseSet<Operation *, AlwaysLikeOpInfo> alwaysFFOpsSeen;
167 sv::InitialOp initialOpSeen;
169 for (Operation &op :
llvm::make_early_inc_range(body)) {
172 if (isa<sv::AlwaysOp, sv::AlwaysFFOp>(op) && mergeAlwaysBlocks) {
174 auto itAndInserted = alwaysFFOpsSeen.insert(&op);
175 if (itAndInserted.second)
177 auto *existingAlways = *itAndInserted.first;
178 mergeOperationsIntoFrom(&op, existingAlways);
180 *itAndInserted.first = &op;
185 if (
auto ifdefOp = dyn_cast<sv::IfDefOp>(op)) {
186 auto *&entry = ifdefOps[ifdefOp.getCondAttr()];
188 mergeOperationsIntoFrom(ifdefOp, entry);
195 if (
auto initialOp = dyn_cast<sv::InitialOp>(op)) {
197 mergeOperationsIntoFrom(initialOp, initialOpSeen);
198 initialOpSeen = initialOp;
203 for (Operation &op :
llvm::make_early_inc_range(body)) {
205 if (op.getNumRegions() != 0)
206 runOnRegionsInOp(op);
211void HWCleanupPass::runOnProceduralRegion(Region ®ion) {
212 if (region.getBlocks().size() != 1)
214 Block &body = region.front();
216 Operation *lastSideEffectingOp =
nullptr;
217 for (Operation &op :
llvm::make_early_inc_range(body)) {
219 if (
auto ifdef = dyn_cast<sv::IfDefProceduralOp>(op)) {
221 dyn_cast_or_null<sv::IfDefProceduralOp>(lastSideEffectingOp)) {
222 if (ifdef.getCond() == prevIfDef.getCond()) {
225 mergeOperationsIntoFrom(ifdef, prevIfDef);
231 if (
auto ifop = dyn_cast<sv::IfOp>(op)) {
232 if (
auto prevIf = dyn_cast_or_null<sv::IfOp>(lastSideEffectingOp)) {
233 if (ifop.getCond() == prevIf.getCond()) {
236 mergeOperationsIntoFrom(ifop, prevIf);
242 if (!mlir::isMemoryEffectFree(&op))
243 lastSideEffectingOp = &op;
246 for (Operation &op :
llvm::make_early_inc_range(body)) {
248 if (op.getNumRegions() != 0)
249 runOnRegionsInOp(op);
assert(baseType &&"element must be base type")
static void mergeRegions(Region *region1, Region *region2)
Signals that an operations regions are procedural.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.