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> {
 
  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) {
 
  117    if (sv::hasSVAttributes(op1) || sv::hasSVAttributes(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;
 
  131void HWCleanupPass::runOnOperation() {
 
  134  anythingChanged = 
false;
 
  135  runOnGraphRegion(getOperation().getBody());
 
  139  if (!anythingChanged)
 
  140    markAllAnalysesPreserved();
 
  145void HWCleanupPass::runOnRegionsInOp(Operation &op) {
 
  147    for (
auto ®ion : op.getRegions())
 
  148      runOnProceduralRegion(region);
 
  150    for (
auto ®ion : op.getRegions())
 
  151      runOnGraphRegion(region);
 
  156void 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);
 
  210void 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)
Signals that an operations regions are procedural.
std::unique_ptr< mlir::Pass > createHWCleanupPass(bool mergeAlwaysBlocks=true)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.