CIRCT 20.0.0git
Loading...
Searching...
No Matches
KanagawaPrepareScheduling.cpp
Go to the documentation of this file.
1//===- KanagawaPrepareScheduling.cpp - Prepares static blocks for scheduling =//
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
20
23#include "mlir/Transforms/DialectConversion.h"
24
25namespace circt {
26namespace kanagawa {
27#define GEN_PASS_DEF_KANAGAWAPREPARESCHEDULING
28#include "circt/Dialect/Kanagawa/KanagawaPasses.h.inc"
29} // namespace kanagawa
30} // namespace circt
31
32using namespace circt;
33using namespace kanagawa;
34
35namespace {
36
37struct PrepareSchedulingPass
38 : public circt::kanagawa::impl::KanagawaPrepareSchedulingBase<
39 PrepareSchedulingPass> {
40 void runOnOperation() override;
41
42 // Prepares the given sblock for scheduling by moving its body into a
43 // pipeline.unscheduled operation, and returns the pipeline op.
44 pipeline::UnscheduledPipelineOp prepareSBlock(IsolatedStaticBlockOp sblock);
45
46 // Iterates over the operations in the pipeline, looks up the corresponding
47 // operator in the provided operator library, and attaches the operator type
48 // to the op.
49 LogicalResult attachOperatorTypes(pipeline::UnscheduledPipelineOp pipeline);
50};
51} // anonymous namespace
52
53pipeline::UnscheduledPipelineOp
54PrepareSchedulingPass::prepareSBlock(IsolatedStaticBlockOp sblock) {
55 Location loc = sblock.getLoc();
56 Block *bodyBlock = sblock.getBodyBlock();
57 auto b = OpBuilder::atBlockBegin(bodyBlock);
58 auto ph = b.create<kanagawa::PipelineHeaderOp>(loc);
59
60 // Create a pipeline.unscheduled operation which returns the same types
61 // as that returned by the sblock.
62 auto sblockRet = cast<BlockReturnOp>(bodyBlock->getTerminator());
63 auto retTypes = sblockRet.getOperandTypes();
64
65 // Generate in- and output names.
66 SmallVector<Attribute> inNames, outNames;
67 for (size_t i = 0, e = bodyBlock->getNumArguments(); i < e; ++i)
68 inNames.push_back(b.getStringAttr("in" + std::to_string(i)));
69 for (size_t i = 0, e = retTypes.size(); i < e; ++i)
70 outNames.push_back(b.getStringAttr("out" + std::to_string(i)));
71
72 auto pipeline = b.create<pipeline::UnscheduledPipelineOp>(
73 loc, retTypes, bodyBlock->getArguments(), b.getArrayAttr(inNames),
74 b.getArrayAttr(outNames), ph.getClock(), ph.getGo(), ph.getReset(),
75 ph.getStall());
76 b.setInsertionPointToEnd(pipeline.getEntryStage());
77
78 // First, we replace all of the operands of the return op with the values
79 // generated by the pipeline. This ensures that argument of the sblock that
80 // is directly returned without being modified by an operation inside the
81 // sblock is still being passed through the pipeline. While doing so, we
82 // sneakily also set the pipeline return values so that it will reflect the
83 // later value replacements.
84 auto pipelineRet = b.create<pipeline::ReturnOp>(loc, sblockRet.getOperands());
85 for (size_t i = 0, e = retTypes.size(); i < e; ++i)
86 sblockRet.setOperand(i, pipeline.getResult(i));
87
88 // Next, we can replace all of the sblock argument uses within the pipeline
89 // with the pipeline arguments.
90 for (auto [sbArg, plArg] :
91 llvm::zip(bodyBlock->getArguments(),
92 pipeline.getEntryStage()->getArguments())) {
93 sbArg.replaceAllUsesExcept(plArg, pipeline);
94 }
95
96 // And now we're safe to move the body of the sblock into the pipeline.
97 // Drop the 2 first ops (pipeline, pipeline header) and the back (the return
98 // op). Block::getOperations doesn't play nicely with ArrayRef's so have to
99 // copy it...
100 llvm::SmallVector<Operation *> opsToMove;
101 llvm::transform(bodyBlock->getOperations(), std::back_inserter(opsToMove),
102 [&](Operation &op) { return &op; });
103 for (Operation *op :
104 ArrayRef(opsToMove.begin(), opsToMove.end()).drop_front(2).drop_back())
105 op->moveBefore(pipelineRet);
106
107 return pipeline;
108}
109
110LogicalResult PrepareSchedulingPass::attachOperatorTypes(
111 pipeline::UnscheduledPipelineOp pipeline) {
112 for (Operation &op : *pipeline.getEntryStage()) {
113 if (op.hasAttr("ssp.operator_type"))
114 continue;
115
116 // Skip unscheduled pipeline ops.
117 if (isa<pipeline::ReturnOp>(op) || op.hasTrait<OpTrait::ConstantLike>())
118 continue;
119
120 // The operator lib convention just assumes that the exact
121 // operation name is present in the library.
122 op.setAttr(
123 "ssp.operator_type",
124 FlatSymbolRefAttr::get(op.getContext(), op.getName().getStringRef()));
125 }
126
127 // Attach the operator lib attribute
128 pipeline->setAttr(
129 "operator_lib",
130 FlatSymbolRefAttr::get(pipeline.getContext(), kKanagawaOperatorLibName));
131
132 return success();
133}
134
135void PrepareSchedulingPass::runOnOperation() {
136 pipeline::UnscheduledPipelineOp pipeline = prepareSBlock(getOperation());
137 if (failed(attachOperatorTypes(pipeline)))
138 return signalPassFailure();
139}
140
142 return std::make_unique<PrepareSchedulingPass>();
143}
static constexpr const char * kKanagawaOperatorLibName
Definition KanagawaOps.h:35
std::unique_ptr< mlir::Pass > createPrepareSchedulingPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.