CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
21namespace circt {
22namespace kanagawa {
23#define GEN_PASS_DEF_KANAGAWAREBLOCK
24#include "circt/Dialect/Kanagawa/KanagawaPasses.h.inc"
25} // namespace kanagawa
26} // namespace circt
27
28using namespace circt;
29using namespace kanagawa;
30
31namespace {
32
33struct 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.
47static bool isSBlockTerminator(Operation *op) {
48 return op->hasTrait<OpTrait::IsTerminator>() ||
49 isa<kanagawa::InlineStaticBlockEndOp, InlineStaticBlockBeginOp>(op);
50}
51
52} // anonymous namespace
53
54void 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
76LogicalResult 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
160std::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.