CIRCT 21.0.0git
Loading...
Searching...
No Matches
InlineSequencesPass.cpp
Go to the documentation of this file.
1//===- InlineSequencesPass.cpp - RTG InlineSequencesPass implementation ---===//
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// This pass inlines sequences and computes sequence interleavings.
10//
11//===----------------------------------------------------------------------===//
12
17#include "mlir/IR/IRMapping.h"
18#include "llvm/Support/Debug.h"
19
20namespace circt {
21namespace rtg {
22#define GEN_PASS_DEF_INLINESEQUENCESPASS
23#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
24} // namespace rtg
25} // namespace circt
26
27using namespace mlir;
28using namespace circt;
29using namespace circt::rtg;
30
31#define DEBUG_TYPE "rtg-inline-sequences"
32
33//===----------------------------------------------------------------------===//
34// Inline Sequences Pass
35//===----------------------------------------------------------------------===//
36
37namespace {
38struct InlineSequencesPass
39 : public rtg::impl::InlineSequencesPassBase<InlineSequencesPass> {
40 using Base::Base;
41
42 void runOnOperation() override;
43};
44
45/// Enum to indicate to the visitor driver whether the operation should be
46/// deleted.
47enum class DeletionKind { Delete, Keep };
48
49/// The SequenceInliner computes sequence interleavings and inlines them.
50struct SequenceInliner
51 : public RTGOpVisitor<SequenceInliner, FailureOr<DeletionKind>> {
52 using RTGOpVisitor<SequenceInliner, FailureOr<DeletionKind>>::visitOp;
53
54 SequenceInliner(ModuleOp moduleOp) : table(moduleOp) {}
55
56 LogicalResult inlineSequences(TestOp testOp);
57 void materializeInterleavedSequence(Value value, ArrayRef<Block *> blocks,
58 uint32_t batchSize);
59
60 // Visitor methods
61
62 FailureOr<DeletionKind> visitOp(InterleaveSequencesOp op) {
63 SmallVector<Block *> blocks;
64 for (auto [i, seq] : llvm::enumerate(op.getSequences())) {
65 auto *block = materializedSequences.lookup(seq);
66 if (!block)
67 return op->emitError()
68 << "sequence operand #" << i
69 << " could not be resolved; it was likely produced by an op or "
70 "block argument not supported by this pass";
71
72 blocks.push_back(block);
73 }
74
75 LLVM_DEBUG(llvm::dbgs()
76 << " - Computing sequence interleaving: " << op << "\n");
77
78 materializeInterleavedSequence(op.getInterleavedSequence(), blocks,
79 op.getBatchSize());
80 return DeletionKind::Delete;
81 }
82
83 FailureOr<DeletionKind> visitOp(GetSequenceOp op) {
84 auto seqOp = table.lookup<SequenceOp>(op.getSequenceAttr());
85 if (!seqOp)
86 return op->emitError() << "referenced sequence not found";
87
88 LLVM_DEBUG(llvm::dbgs() << " - Registering existing sequence: "
89 << op.getSequence() << "\n");
90
91 materializedSequences[op.getResult()] = seqOp.getBody();
92 return DeletionKind::Delete;
93 }
94
95 FailureOr<DeletionKind> visitOp(RandomizeSequenceOp op) {
96 LLVM_DEBUG(llvm::dbgs() << " - Randomize sequence: " << op << "\n");
97
98 auto *block = materializedSequences.lookup(op.getSequence());
99 if (!block)
100 return op->emitError() << "sequence operand could not be resolved; it "
101 "was likely produced by an op or block "
102 "argument not supported by this pass";
103
104 materializedSequences[op.getResult()] = block;
105 return DeletionKind::Delete;
106 }
107
108 FailureOr<DeletionKind> visitOp(EmbedSequenceOp op) {
109 LLVM_DEBUG(llvm::dbgs() << " - Inlining sequence: " << op << "\n");
110
111 auto *block = materializedSequences.lookup(op.getSequence());
112 if (!block)
113 return op->emitError() << "sequence operand could not be resolved; it "
114 "was likely produced by an op or block "
115 "argument not supported by this pass";
116
117 OpBuilder builder(op);
118 builder.setInsertionPointAfter(op);
119 IRMapping mapping;
120 for (auto &op : *block)
121 builder.clone(op, mapping);
122
123 ++numSequencesInlined;
124
125 return DeletionKind::Delete;
126 }
127
128 FailureOr<DeletionKind> visitUnhandledOp(Operation *op) {
129 return DeletionKind::Keep;
130 }
131
132 FailureOr<DeletionKind> visitExternalOp(Operation *op) {
133 return DeletionKind::Keep;
134 }
135
136 SymbolTable table;
137 DenseMap<Value, Block *> materializedSequences;
138 SmallVector<std::unique_ptr<Block>> blockStorage;
139 size_t numSequencesInlined = 0;
140 size_t numSequencesInterleaved = 0;
141};
142
143} // namespace
144
145void SequenceInliner::materializeInterleavedSequence(Value value,
146 ArrayRef<Block *> blocks,
147 uint32_t batchSize) {
148 auto *interleavedBlock =
149 blockStorage.emplace_back(std::make_unique<Block>()).get();
150 IRMapping mapping;
151 OpBuilder builder(value.getContext());
152 builder.setInsertionPointToStart(interleavedBlock);
153
154 SmallVector<Block::iterator> iters(blocks.size());
155 for (auto [i, block] : llvm::enumerate(blocks))
156 iters[i] = block->begin();
157
158 llvm::BitVector finishedBlocks(blocks.size());
159 for (unsigned i = 0; !finishedBlocks.all(); i = (i + 1) % blocks.size()) {
160 if (finishedBlocks[i])
161 continue;
162 for (unsigned k = 0; k < batchSize;) {
163 if (iters[i] == blocks[i]->end()) {
164 finishedBlocks.set(i);
165 break;
166 }
167 auto *op = builder.clone(*iters[i], mapping);
168 if (isa<InstructionOpInterface>(op))
169 ++k;
170 ++iters[i];
171 }
172 }
173
174 materializedSequences[value] = interleavedBlock;
175 numSequencesInterleaved += blocks.size();
176}
177
178LogicalResult SequenceInliner::inlineSequences(TestOp testOp) {
179 LLVM_DEBUG(llvm::dbgs() << "\n=== Processing test @" << testOp.getSymName()
180 << "\n\n");
181
182 SmallVector<Operation *> toDelete;
183 for (auto &op : *testOp.getBody()) {
184 auto result = dispatchOpVisitor(&op);
185 if (failed(result))
186 return failure();
187
188 if (*result == DeletionKind::Delete)
189 toDelete.push_back(&op);
190 }
191
192 for (auto *op : llvm::reverse(toDelete))
193 op->erase();
194
195 return success();
196}
197
198void InlineSequencesPass::runOnOperation() {
199 auto moduleOp = getOperation();
200 SequenceInliner inliner(moduleOp);
201
202 // Inline all sequences and remove the operations that place the sequences.
203 for (auto testOp : moduleOp.getOps<TestOp>())
204 if (failed(inliner.inlineSequences(testOp)))
205 return signalPassFailure();
206
207 // Remove all sequences since they are not accessible from the outside and
208 // are not needed anymore since we fully inlined them.
209 for (auto seqOp : llvm::make_early_inc_range(moduleOp.getOps<SequenceOp>()))
210 seqOp->erase();
211
212 numSequencesInlined = inliner.numSequencesInlined;
213 numSequencesInterleaved = inliner.numSequencesInterleaved;
214}
This helps visit TypeOp nodes.
Definition RTGVisitors.h:29
ResultType visitExternalOp(Operation *op, ExtraArgs... args)
Definition RTGVisitors.h:76
ResultType visitUnhandledOp(Operation *op, ExtraArgs... args)
This callback is invoked on any operations that are not handled by the concrete visitor.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition rtg.py:1
Definition seq.py:1