CIRCT  20.0.0git
EarlyCodeMotionPass.cpp
Go to the documentation of this file.
1 //===- EarlyCodeMotionPass.cpp - Implement Early Code Motion Pass ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Implement pass to move allowed instructions as far up in the CFG as possible.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "TemporalRegions.h"
16 #include "circt/Support/LLVM.h"
17 #include "mlir/IR/Dominance.h"
18 #include "mlir/Pass/Pass.h"
19 
20 namespace circt {
21 namespace llhd {
22 #define GEN_PASS_DEF_EARLYCODEMOTION
23 #include "circt/Dialect/LLHD/Transforms/Passes.h.inc"
24 } // namespace llhd
25 } // namespace circt
26 
27 using namespace circt;
28 namespace {
29 struct EarlyCodeMotionPass
30  : public circt::llhd::impl::EarlyCodeMotionBase<EarlyCodeMotionPass> {
31  void runOnOperation() override;
32  void runOnProcess(llhd::ProcessOp proc);
33 };
34 } // namespace
35 
36 /// Calculate intersection of two vectors, returns a new vector
37 static SmallVector<Block *, 8> intersection(SmallVectorImpl<Block *> &v1,
38  SmallVectorImpl<Block *> &v2) {
39  SmallVector<Block *, 8> res;
40  std::sort(v1.begin(), v1.end());
41  std::sort(v2.begin(), v2.end());
42 
43  std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(),
44  std::back_inserter(res));
45  return res;
46 }
47 
48 void EarlyCodeMotionPass::runOnOperation() {
49  for (auto proc : getOperation().getOps<llhd::ProcessOp>())
50  runOnProcess(proc);
51 }
52 
53 void EarlyCodeMotionPass::runOnProcess(llhd::ProcessOp proc) {
55  mlir::DominanceInfo dom(proc);
56 
57  DenseMap<Block *, unsigned> entryDistance;
58  SmallPtrSet<Block *, 32> workDone;
59  SmallPtrSet<Block *, 32> workPending;
60 
61  Block &entryBlock = proc.getBody().front();
62  workPending.insert(&entryBlock);
63  entryDistance.insert(std::make_pair(&entryBlock, 0));
64 
65  while (!workPending.empty()) {
66  Block *block = *workPending.begin();
67  workPending.erase(block);
68  workDone.insert(block);
69 
70  for (auto iter = block->getOperations().begin();
71  iter != block->getOperations().end(); ++iter) {
72  Operation &op = *iter;
73  if (!isa<llhd::PrbOp>(op) && !isa<llhd::SignalOp>(op) &&
74  (!mlir::isMemoryEffectFree(&op) ||
75  op.hasTrait<OpTrait::IsTerminator>()))
76  continue;
77 
78  SmallVector<Block *, 8> validPlacements;
79  // Initialize validPlacements to all blocks in the process
80  for (Block &b : proc.getBody().getBlocks())
81  validPlacements.push_back(&b);
82 
83  // Delete all blocks in validPlacements that are not common to all
84  // operands
85  for (Value operand : op.getOperands()) {
86  SmallVector<Block *, 8> dominationSet;
87  Block *instBlock = nullptr;
88  if (BlockArgument arg = dyn_cast<BlockArgument>(operand)) {
89  instBlock = arg.getParentBlock();
90  } else {
91  instBlock = operand.getDefiningOp()->getBlock();
92  }
93 
94  for (Block &b : proc.getBody().getBlocks()) {
95  if (dom.dominates(instBlock, &b))
96  dominationSet.push_back(&b);
97  }
98  validPlacements = intersection(dominationSet, validPlacements);
99  }
100 
101  // The probe instruction has to stay in the same temporal region
102  if (isa<llhd::PrbOp>(op)) {
103  SmallVector<Block *, 8> blocksInTR =
104  trAnalysis.getBlocksInTR(trAnalysis.getBlockTR(block));
105  validPlacements = intersection(validPlacements, blocksInTR);
106  }
107 
108  if (validPlacements.empty())
109  continue;
110 
111  // Move the instruction to the block which is the closest to the entry
112  // block (and valid)
113  unsigned minBBdist = -1;
114  Block *minBB = nullptr;
115  for (Block *b : validPlacements) {
116  if (!entryDistance.count(b))
117  continue;
118  if (entryDistance[b] < minBBdist) {
119  minBBdist = entryDistance[b];
120  minBB = b;
121  }
122  }
123 
124  if (!minBB || minBB == op.getBlock())
125  continue;
126 
127  auto prev = std::prev(iter);
128  op.moveBefore(minBB->getTerminator());
129  iter = prev;
130  }
131 
132  // Add successors of this block
133  for (Block *succ : block->getSuccessors()) {
134  if (!workDone.count(succ)) {
135  workPending.insert(succ);
136  assert(entryDistance.count(block) &&
137  "ECM: block has to be present in entryDistance map");
138  unsigned nextDist = entryDistance[block] + 1;
139  entryDistance.insert(std::make_pair(succ, nextDist));
140  }
141  }
142  }
143 }
144 
145 std::unique_ptr<OperationPass<hw::HWModuleOp>>
147  return std::make_unique<EarlyCodeMotionPass>();
148 }
assert(baseType &&"element must be base type")
static SmallVector< Block *, 8 > intersection(SmallVectorImpl< Block * > &v1, SmallVectorImpl< Block * > &v2)
Calculate intersection of two vectors, returns a new vector.
std::unique_ptr< OperationPass< hw::HWModuleOp > > createEarlyCodeMotionPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
SmallVector< Block *, 8 > getBlocksInTR(int) const