CIRCT  20.0.0git
KanagawaReblockPass.cpp
Go to the documentation of this file.
1 //===- KanagawaReblockPass.cpp --------------------------------------------===//
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 
11 #include "mlir/Pass/Pass.h"
12 
17 
19 #include "mlir/Transforms/DialectConversion.h"
20 
21 namespace circt {
22 namespace kanagawa {
23 #define GEN_PASS_DEF_KANAGAWAREBLOCK
24 #include "circt/Dialect/Kanagawa/KanagawaPasses.h.inc"
25 } // namespace kanagawa
26 } // namespace circt
27 
28 using namespace circt;
29 using namespace kanagawa;
30 
31 namespace {
32 
33 struct ReblockPass
34  : public circt::kanagawa::impl::KanagawaReblockBase<ReblockPass> {
35  void runOnOperation() override;
36 
37  // Transforms an `kanagawa.sblock.inline.begin/end` scope into an
38  // `kanagawa.sblock`.
39  LogicalResult reblock(ArrayRef<Operation *> ops, Operation *blockTerminator);
40 
41  /// Track ops that should be erased.
42  SmallVector<Operation *> opsToErase;
43 };
44 
45 // Returns true if the given op signal that the existing set of sblock
46 // operations should be closed.
47 static bool isSBlockTerminator(Operation *op) {
48  return op->hasTrait<OpTrait::IsTerminator>() ||
49  isa<kanagawa::InlineStaticBlockEndOp, InlineStaticBlockBeginOp>(op);
50 }
51 
52 } // anonymous namespace
53 
54 void ReblockPass::runOnOperation() {
55  MethodOp parent = getOperation();
56 
57  llvm::SmallVector<Operation *> opsToBlock;
58  for (Block &block : parent.getRegion()) {
59  for (Operation &op : llvm::make_early_inc_range(block)) {
60  if (isSBlockTerminator(&op)) {
61  if (opsToBlock.empty())
62  continue;
63  if (failed(reblock(opsToBlock, &op)))
64  return signalPassFailure();
65  opsToBlock.clear();
66  if (isa<InlineStaticBlockBeginOp>(op))
67  opsToBlock.push_back(&op);
68  } else
69  opsToBlock.push_back(&op);
70  }
71  }
72 
73  llvm::for_each(opsToErase, [](Operation *op) { op->erase(); });
74 }
75 
76 LogicalResult ReblockPass::reblock(ArrayRef<Operation *> ops,
77  Operation *blockTerminator) {
78  // Determine which values we need to return from within the block scope.
79  // This is done by collecting all values defined within the start/end scope,
80  // and recording uses that exist outside of the scope.
81  kanagawa::InlineStaticBlockBeginOp blockBeginOp;
82  if (isa<InlineStaticBlockEndOp>(blockTerminator)) {
83  blockBeginOp = dyn_cast<InlineStaticBlockBeginOp>(ops.front());
84  assert(blockBeginOp &&
85  "Expected block begin op when a block end block was provided");
86  ops = ops.drop_front();
87  }
88 
89  Operation *beginOp = ops.front();
90  auto startIt = ops.front()->getIterator();
91  Operation *endOp = ops.back();
92  auto terminatorIt = blockTerminator->getIterator();
93  Block *sblockParentBlock = beginOp->getBlock();
94 
95  auto usedOutsideBlock = [&](OpOperand &use) {
96  Operation *owner = use.getOwner();
97  Block *useBlock = owner->getBlock();
98  if (useBlock != sblockParentBlock)
99  return true;
100  bool isBefore = owner->isBeforeInBlock(beginOp);
101  bool isAfter = isBefore ? false : endOp->isBeforeInBlock(owner);
102  return isBefore || isAfter;
103  };
104 
105  llvm::MapVector<Value, llvm::SmallVector<OpOperand *>> returnValueUses;
106  for (auto &op : llvm::make_range(startIt, terminatorIt)) {
107  for (Value result : op.getResults()) {
108  for (OpOperand &use : result.getUses())
109  if (usedOutsideBlock(use))
110  returnValueUses[result].push_back(&use);
111  }
112  }
113 
114  // Gather the set of types that needs to be returned from within the block.
115  llvm::SmallVector<Type> blockRetTypes;
116  llvm::SmallVector<Value> blockRetValues;
117  for (auto &[v, _] : returnValueUses) {
118  blockRetTypes.push_back(v.getType());
119  blockRetValues.push_back(v);
120  }
121 
122  auto b = OpBuilder(beginOp);
123  auto kanagawaBlock =
124  b.create<StaticBlockOp>(beginOp->getLoc(), blockRetTypes, ValueRange{});
125 
126  // The new `kanagawa.sblock` should inherit the attributes of the block begin
127  // op, if provided.
128  if (blockBeginOp)
129  kanagawaBlock->setAttrs(blockBeginOp->getAttrs());
130 
131  // Move operations into the `kanagawa.sblock` op.
132  BlockReturnOp blockReturn =
133  cast<BlockReturnOp>(kanagawaBlock.getBodyBlock()->getTerminator());
134 
135  for (auto &op :
136  llvm::make_early_inc_range(llvm::make_range(startIt, terminatorIt)))
137  op.moveBefore(blockReturn);
138 
139  // Append the terminator operands to the block return.
140  blockReturn->setOperands(blockRetValues);
141 
142  // Replace the uses of the returned values outside of the block with the
143  // block return values.
144  for (auto [blockRet, innerDefAndUses] :
145  llvm::zip(kanagawaBlock.getResults(), returnValueUses)) {
146  auto &uses = std::get<1>(innerDefAndUses);
147  for (OpOperand *use : uses)
148  use->set(blockRet);
149  }
150 
151  // If this was an explicit sblock, erase the markers.
152  if (blockBeginOp) {
153  opsToErase.push_back(blockBeginOp);
154  opsToErase.push_back(blockTerminator);
155  }
156 
157  return success();
158 }
159 
160 std::unique_ptr<Pass> circt::kanagawa::createReblockPass() {
161  return std::make_unique<ReblockPass>();
162 }
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createReblockPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21