CIRCT 22.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 = kanagawa::PipelineHeaderOp::create(b, 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 = pipeline::UnscheduledPipelineOp::create(
73 b, 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 =
85 pipeline::ReturnOp::create(b, loc, sblockRet.getOperands());
86 for (size_t i = 0, e = retTypes.size(); i < e; ++i)
87 sblockRet.setOperand(i, pipeline.getResult(i));
88
89 // Next, we can replace all of the sblock argument uses within the pipeline
90 // with the pipeline arguments.
91 for (auto [sbArg, plArg] :
92 llvm::zip(bodyBlock->getArguments(),
93 pipeline.getEntryStage()->getArguments())) {
94 sbArg.replaceAllUsesExcept(plArg, pipeline);
95 }
96
97 // And now we're safe to move the body of the sblock into the pipeline.
98 // Drop the 2 first ops (pipeline, pipeline header) and the back (the return
99 // op). Block::getOperations doesn't play nicely with ArrayRef's so have to
100 // copy it...
101 llvm::SmallVector<Operation *> opsToMove;
102 llvm::transform(bodyBlock->getOperations(), std::back_inserter(opsToMove),
103 [&](Operation &op) { return &op; });
104 for (Operation *op :
105 ArrayRef(opsToMove.begin(), opsToMove.end()).drop_front(2).drop_back())
106 op->moveBefore(pipelineRet);
107
108 return pipeline;
109}
110
111LogicalResult PrepareSchedulingPass::attachOperatorTypes(
112 pipeline::UnscheduledPipelineOp pipeline) {
113 for (Operation &op : *pipeline.getEntryStage()) {
114 if (op.hasAttr("ssp.operator_type"))
115 continue;
116
117 // Skip unscheduled pipeline ops.
118 if (isa<pipeline::ReturnOp>(op) || op.hasTrait<OpTrait::ConstantLike>())
119 continue;
120
121 // The operator lib convention just assumes that the exact
122 // operation name is present in the library.
123 op.setAttr(
124 "ssp.operator_type",
125 FlatSymbolRefAttr::get(op.getContext(), op.getName().getStringRef()));
126 }
127
128 // Attach the operator lib attribute
129 pipeline->setAttr(
130 "operator_lib",
131 FlatSymbolRefAttr::get(pipeline.getContext(), kKanagawaOperatorLibName));
132
133 return success();
134}
135
136void PrepareSchedulingPass::runOnOperation() {
137 pipeline::UnscheduledPipelineOp pipeline = prepareSBlock(getOperation());
138 if (failed(attachOperatorTypes(pipeline)))
139 return signalPassFailure();
140}
141
143 return std::make_unique<PrepareSchedulingPass>();
144}
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.