21 using namespace circt;
32 struct AlwaysLikeOpInfo :
public llvm::DenseMapInfo<Operation *> {
33 static unsigned getHashValue(
const Operation *opC) {
34 return mlir::OperationEquivalence::computeHash(
35 const_cast<Operation *
>(opC),
36 mlir::OperationEquivalence::directHashValue,
37 mlir::OperationEquivalence::ignoreHashValue,
38 mlir::OperationEquivalence::IgnoreLocations);
40 static bool isEqual(
const Operation *lhsC,
const Operation *rhsC) {
41 auto *lhs =
const_cast<Operation *
>(lhsC);
42 auto *rhs =
const_cast<Operation *
>(rhsC);
47 if (lhs == getTombstoneKey() || lhs == getEmptyKey() ||
48 rhs == getTombstoneKey() || rhs == getEmptyKey())
51 if (lhs->getName() != rhs->getName() ||
52 lhs->getAttrDictionary() != rhs->getAttrDictionary() ||
53 lhs->getNumOperands() != rhs->getNumOperands())
56 for (
auto operandPair : llvm::zip(lhs->getOperands(), rhs->getOperands())) {
57 Value lhsOperand = std::get<0>(operandPair);
58 Value rhsOperand = std::get<1>(operandPair);
59 if (lhsOperand != rhsOperand)
71 assert(region1->getBlocks().size() <= 1 && region2->getBlocks().size() <= 1 &&
72 "Can only merge regions with a single block");
73 if (region1->empty()) {
78 region1->getBlocks().splice(region1->end(), region2->getBlocks());
84 if (!region2->empty()) {
85 auto &block1 = region1->front();
86 auto &block2 = region2->front();
87 block1.getOperations().splice(block1.begin(), block2.getOperations());
96 struct HWCleanupPass :
public sv::HWCleanupBase<HWCleanupPass> {
97 using sv::HWCleanupBase<HWCleanupPass>::mergeAlwaysBlocks;
99 void runOnOperation()
override;
101 void runOnRegionsInOp(Operation &op);
102 void runOnGraphRegion(Region ®ion);
103 void runOnProceduralRegion(Region ®ion);
108 void mergeOperationsIntoFrom(Operation *op1, Operation *op2) {
112 assert(op1 != op2 &&
"Cannot merge an op into itself");
113 for (
size_t i = 0, e = op1->getNumRegions(); i != e; ++i)
117 anythingChanged =
true;
120 bool anythingChanged;
124 void HWCleanupPass::runOnOperation() {
127 anythingChanged =
false;
128 runOnGraphRegion(getOperation().getBody());
132 if (!anythingChanged)
133 markAllAnalysesPreserved();
138 void HWCleanupPass::runOnRegionsInOp(Operation &op) {
139 if (op.hasTrait<sv::ProceduralRegion>()) {
140 for (
auto ®ion : op.getRegions())
141 runOnProceduralRegion(region);
143 for (
auto ®ion : op.getRegions())
144 runOnGraphRegion(region);
149 void HWCleanupPass::runOnGraphRegion(Region ®ion) {
150 if (region.getBlocks().size() != 1)
152 Block &body = region.front();
157 DenseSet<Operation *, AlwaysLikeOpInfo> alwaysFFOpsSeen;
159 sv::InitialOp initialOpSeen;
161 for (Operation &op : llvm::make_early_inc_range(body)) {
164 if (isa<sv::AlwaysOp, sv::AlwaysFFOp>(op) && mergeAlwaysBlocks) {
166 auto itAndInserted = alwaysFFOpsSeen.insert(&op);
167 if (itAndInserted.second)
169 auto *existingAlways = *itAndInserted.first;
170 mergeOperationsIntoFrom(&op, existingAlways);
172 *itAndInserted.first = &op;
177 if (
auto ifdefOp = dyn_cast<sv::IfDefOp>(op)) {
178 auto *&entry = ifdefOps[ifdefOp.getCondAttr()];
180 mergeOperationsIntoFrom(ifdefOp, entry);
187 if (
auto initialOp = dyn_cast<sv::InitialOp>(op)) {
189 mergeOperationsIntoFrom(initialOp, initialOpSeen);
190 initialOpSeen = initialOp;
195 for (Operation &op : llvm::make_early_inc_range(body)) {
197 if (op.getNumRegions() != 0)
198 runOnRegionsInOp(op);
203 void HWCleanupPass::runOnProceduralRegion(Region ®ion) {
204 if (region.getBlocks().size() != 1)
206 Block &body = region.front();
208 Operation *lastSideEffectingOp =
nullptr;
209 for (Operation &op : llvm::make_early_inc_range(body)) {
211 if (
auto ifdef = dyn_cast<sv::IfDefProceduralOp>(op)) {
213 dyn_cast_or_null<sv::IfDefProceduralOp>(lastSideEffectingOp)) {
214 if (ifdef.getCond() == prevIfDef.getCond()) {
217 mergeOperationsIntoFrom(ifdef, prevIfDef);
223 if (
auto ifop = dyn_cast<sv::IfOp>(op)) {
224 if (
auto prevIf = dyn_cast_or_null<sv::IfOp>(lastSideEffectingOp)) {
225 if (ifop.getCond() == prevIf.getCond()) {
228 mergeOperationsIntoFrom(ifop, prevIf);
234 if (!mlir::isMemoryEffectFree(&op))
235 lastSideEffectingOp = &op;
238 for (Operation &op : llvm::make_early_inc_range(body)) {
240 if (op.getNumRegions() != 0)
241 runOnRegionsInOp(op);
246 auto pass = std::make_unique<HWCleanupPass>();
247 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)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...