17#include "mlir/IR/IRMapping.h"
18#include "llvm/Support/Debug.h"
22#define GEN_PASS_DEF_INLINESEQUENCESPASS
23#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
31#define DEBUG_TYPE "rtg-inline-sequences"
38struct InlineSequencesPass
39 :
public rtg::impl::InlineSequencesPassBase<InlineSequencesPass> {
42 void runOnOperation()
override;
47enum class DeletionKind { Delete, Keep };
51 :
public RTGOpVisitor<SequenceInliner, FailureOr<DeletionKind>> {
52 using RTGOpVisitor<SequenceInliner, FailureOr<DeletionKind>>::visitOp;
54 SequenceInliner(ModuleOp moduleOp,
bool failOnRemaining)
55 : table(moduleOp), failOnRemaining(failOnRemaining) {}
57 LogicalResult inlineSequences(Block &block);
58 void materializeInterleavedSequence(Value value, ArrayRef<Block *> blocks,
61 FailureOr<std::pair<Block *, IRMapping>>
62 getMaterializedSequence(Value
seq, Location loc) {
63 auto iter = materializedSequences.find(
seq);
64 if (iter == materializedSequences.end()) {
65 StringLiteral msg =
"sequence operand could not be resolved; it "
66 "was likely produced by an op or block "
67 "argument not supported by this pass";
69 return mlir::emitError(loc, msg);
71 LLVM_DEBUG(llvm::dbgs() << msg <<
"\n");
75 return iter->getSecond();
80 FailureOr<DeletionKind> visitOp(InterleaveSequencesOp op) {
81 SmallVector<Block *> blocks;
82 for (
auto [i,
seq] : llvm::enumerate(op.getSequences())) {
83 auto res = getMaterializedSequence(
seq, op.getLoc());
87 blocks.push_back(res->first);
90 LLVM_DEBUG(llvm::dbgs()
91 <<
" - Computing sequence interleaving: " << op <<
"\n");
93 materializeInterleavedSequence(op.getInterleavedSequence(), blocks,
95 return DeletionKind::Delete;
98 FailureOr<DeletionKind> visitOp(GetSequenceOp op) {
99 auto seqOp = table.lookup<SequenceOp>(op.getSequenceAttr().getAttr());
101 return op->emitError() <<
"referenced sequence not found";
103 LLVM_DEBUG(llvm::dbgs() <<
" - Registering existing sequence: "
104 << op.getSequence() <<
"\n");
106 materializedSequences[op.getResult()] =
107 std::make_pair(seqOp.getBody(), IRMapping());
108 return DeletionKind::Delete;
111 FailureOr<DeletionKind> visitOp(SubstituteSequenceOp op) {
112 LLVM_DEBUG(llvm::dbgs() <<
" - Substitute sequence: " << op <<
"\n");
114 auto res = getMaterializedSequence(op.getSequence(), op.getLoc());
118 IRMapping mapping = res->second;
119 Block *block = res->first;
120 for (
auto [arg, repl] :
121 llvm::zip(block->getArguments(), op.getReplacements())) {
122 LLVM_DEBUG(llvm::dbgs()
123 <<
" - Mapping " << arg <<
" to " << repl <<
"\n");
124 mapping.map(arg, repl);
127 materializedSequences[op.getResult()] = std::make_pair(block, mapping);
128 return DeletionKind::Delete;
131 FailureOr<DeletionKind> visitOp(RandomizeSequenceOp op) {
132 LLVM_DEBUG(llvm::dbgs() <<
" - Randomize sequence: " << op <<
"\n");
134 auto res = getMaterializedSequence(op.getSequence(), op.getLoc());
140 materializedSequences[op.getResult()] = *res;
141 return DeletionKind::Delete;
144 FailureOr<DeletionKind> visitOp(EmbedSequenceOp op) {
145 LLVM_DEBUG(llvm::dbgs() <<
" - Inlining sequence: " << op <<
"\n");
147 auto res = getMaterializedSequence(op.getSequence(), op.getLoc());
151 OpBuilder builder(op);
152 builder.setInsertionPointAfter(op);
153 IRMapping mapping = res->second;
156 for (
auto [k, v] : mapping.getValueMap())
157 llvm::dbgs() <<
" - Maps " << k <<
" to " << v <<
"\n";
160 for (
auto &opToInline : *res->first) {
161 Operation *o = builder.clone(opToInline, mapping);
162 o->setLoc(op.getLoc());
164 LLVM_DEBUG(llvm::dbgs() <<
" - Inlined " << *o <<
"\n");
167 ++numSequencesInlined;
169 return DeletionKind::Delete;
173 return DeletionKind::Keep;
177 return DeletionKind::Keep;
181 DenseMap<Value, std::pair<Block *, IRMapping>> materializedSequences;
182 SmallVector<std::unique_ptr<Block>> blockStorage;
183 size_t numSequencesInlined = 0;
184 size_t numSequencesInterleaved = 0;
185 bool failOnRemaining;
190void SequenceInliner::materializeInterleavedSequence(Value value,
191 ArrayRef<Block *> blocks,
192 uint32_t batchSize) {
193 auto *interleavedBlock =
194 blockStorage.emplace_back(std::make_unique<Block>()).get();
196 OpBuilder builder(value.getContext());
197 builder.setInsertionPointToStart(interleavedBlock);
199 SmallVector<Block::iterator> iters(blocks.size());
200 for (
auto [i, block] :
llvm::enumerate(blocks))
201 iters[i] = block->begin();
203 llvm::BitVector finishedBlocks(blocks.size());
204 for (
unsigned i = 0; !finishedBlocks.all(); i = (i + 1) % blocks.size()) {
205 if (finishedBlocks[i])
207 for (
unsigned k = 0; k < batchSize;) {
208 if (iters[i] == blocks[i]->
end()) {
209 finishedBlocks.set(i);
212 auto *op = builder.clone(*iters[i], mapping);
213 if (isa<InstructionOpInterface>(op))
219 materializedSequences[value] = std::make_pair(interleavedBlock, IRMapping());
220 numSequencesInterleaved += blocks.size();
224LogicalResult SequenceInliner::inlineSequences(Block &block) {
228 SmallVector<Operation *> toDelete;
229 for (
auto &op : block) {
230 for (
auto ®ion : op.getRegions())
231 for (auto &block : region)
232 if (failOnRemaining && failed(inlineSequences(block)))
235 auto result = dispatchOpVisitor(&op);
239 if (*result == DeletionKind::Delete)
240 toDelete.push_back(&op);
243 for (
auto *op :
llvm::reverse(toDelete))
249void InlineSequencesPass::runOnOperation() {
250 auto moduleOp = getOperation();
251 SequenceInliner inliner(moduleOp, failOnRemaining);
254 if (moduleOp.getOps<SequenceOp>().empty())
258 for (
auto testOp : moduleOp.getOps<TestOp>()) {
259 auto res = inliner.inlineSequences(*testOp.getBody());
260 if (failOnRemaining && failed(res))
261 return signalPassFailure();
264 numSequencesInlined = inliner.numSequencesInlined;
265 numSequencesInterleaved = inliner.numSequencesInterleaved;
This helps visit TypeOp nodes.
ResultType visitExternalOp(Operation *op, ExtraArgs... args)
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.