CIRCT 20.0.0git
Loading...
Searching...
No Matches
Schedule.cpp
Go to the documentation of this file.
1//===- Schedule.cpp - Schedule pass -----------------------------*- C++ -*-===//
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// Implements the Schedule pass.
10//
11//===----------------------------------------------------------------------===//
12
19#include "mlir/Pass/Pass.h"
20
22
23#include "llvm/ADT/StringExtras.h"
24
25namespace circt {
26namespace ssp {
27#define GEN_PASS_DEF_SCHEDULE
28#include "circt/Dialect/SSP/SSPPasses.h.inc"
29} // namespace ssp
30} // namespace circt
31
32using namespace circt;
33using namespace scheduling;
34using namespace ssp;
35
36//===----------------------------------------------------------------------===//
37// Helpers
38//===----------------------------------------------------------------------===//
39
40// Determine "last" operation, i.e. the one whose start time we are supposed to
41// minimize.
42static OperationOp getLastOp(InstanceOp instOp, StringRef options) {
43 StringRef lastOpName = "";
44 for (StringRef option : llvm::split(options, ',')) {
45 if (option.consume_front("last-op-name=")) {
46 lastOpName = option;
47 break;
48 }
49 }
50
51 auto graphOp = instOp.getDependenceGraph();
52 if (lastOpName.empty() && !graphOp.getBodyBlock()->empty())
53 return cast<OperationOp>(graphOp.getBodyBlock()->back());
54 return graphOp.lookupSymbol<OperationOp>(lastOpName);
55}
56
57// Determine desired cycle time (only relevant for `ChainingProblem` instances).
58static std::optional<float> getCycleTime(StringRef options) {
59 for (StringRef option : llvm::split(options, ',')) {
60 if (option.consume_front("cycle-time="))
61 return std::stof(option.str());
62 }
63 return std::nullopt;
64}
65
66//===----------------------------------------------------------------------===//
67// ASAP scheduler
68//===----------------------------------------------------------------------===//
69
70static InstanceOp scheduleWithASAP(InstanceOp instOp, OpBuilder &builder) {
71 auto problemName = instOp.getProblemName();
72 if (problemName != "Problem") {
73 llvm::errs() << "ssp-schedule: Unsupported problem '" << problemName
74 << "' for ASAP scheduler\n";
75 return {};
76 }
77
78 auto prob = loadProblem<Problem>(instOp);
79 if (failed(prob.check()) || failed(scheduling::scheduleASAP(prob)) ||
80 failed(prob.verify()))
81 return {};
82 return saveProblem(prob, builder);
83}
84
85//===----------------------------------------------------------------------===//
86// Simplex schedulers
87//===----------------------------------------------------------------------===//
88
89template <typename ProblemT>
90static InstanceOp scheduleProblemTWithSimplex(InstanceOp instOp,
91 Operation *lastOp,
92 OpBuilder &builder) {
93 auto prob = loadProblem<ProblemT>(instOp);
94 if (failed(prob.check()) ||
95 failed(scheduling::scheduleSimplex(prob, lastOp)) ||
96 failed(prob.verify()))
97 return {};
98 return saveProblem(prob, builder);
99}
100
101static InstanceOp scheduleChainingProblemWithSimplex(InstanceOp instOp,
102 Operation *lastOp,
103 float cycleTime,
104 OpBuilder &builder) {
105 auto prob = loadProblem<scheduling::ChainingProblem>(instOp);
106 if (failed(prob.check()) ||
107 failed(scheduling::scheduleSimplex(prob, lastOp, cycleTime)) ||
108 failed(prob.verify()))
109 return {};
110 return saveProblem(prob, builder);
111}
112
113static InstanceOp scheduleChainingCyclicProblemWithSimplex(InstanceOp instOp,
114 Operation *lastOp,
115 float cycleTime,
116 OpBuilder &builder) {
117 auto prob = loadProblem<scheduling::ChainingCyclicProblem>(instOp);
118 if (failed(prob.check()) ||
119 failed(scheduling::scheduleSimplex(prob, lastOp, cycleTime)) ||
120 failed(prob.verify()))
121 return {};
122 return saveProblem(prob, builder);
123}
124
125static InstanceOp scheduleWithSimplex(InstanceOp instOp, StringRef options,
126 OpBuilder &builder) {
127 auto lastOp = getLastOp(instOp, options);
128 if (!lastOp) {
129 auto instName = instOp.getSymName().value_or("unnamed");
130 llvm::errs()
131 << "ssp-schedule: Ambiguous objective for simplex scheduler: Instance '"
132 << instName << "' has no designated last operation\n";
133 return {};
134 }
135
136 auto problemName = instOp.getProblemName();
137 if (problemName == "Problem")
138 return scheduleProblemTWithSimplex<Problem>(instOp, lastOp, builder);
139 if (problemName == "CyclicProblem")
140 return scheduleProblemTWithSimplex<CyclicProblem>(instOp, lastOp, builder);
141 if (problemName == "SharedOperatorsProblem")
142 return scheduleProblemTWithSimplex<SharedOperatorsProblem>(instOp, lastOp,
143 builder);
144 if (problemName == "ModuloProblem")
145 return scheduleProblemTWithSimplex<ModuloProblem>(instOp, lastOp, builder);
146 if (problemName == "ChainingProblem") {
147 if (auto cycleTime = getCycleTime(options))
148 return scheduleChainingProblemWithSimplex(instOp, lastOp,
149 cycleTime.value(), builder);
150 llvm::errs() << "ssp-schedule: Missing option 'cycle-time' for "
151 "ChainingProblem simplex scheduler\n";
152 return {};
153 }
154 if (problemName == "ChainingCyclicProblem") {
155 if (auto cycleTime = getCycleTime(options))
157 instOp, lastOp, cycleTime.value(), builder);
158 llvm::errs() << "ssp-schedule: Missing option 'cycle-time' for "
159 "ChainingCyclicProblem simplex scheduler\n";
160 return {};
161 }
162
163 llvm::errs() << "ssp-schedule: Unsupported problem '" << problemName
164 << "' for simplex scheduler\n";
165 return {};
166}
167
168#ifdef SCHEDULING_OR_TOOLS
169
170//===----------------------------------------------------------------------===//
171// LP schedulers (require OR-Tools)
172//===----------------------------------------------------------------------===//
173
174template <typename ProblemT>
175static InstanceOp scheduleProblemTWithLP(InstanceOp instOp, Operation *lastOp,
176 OpBuilder &builder) {
177 auto prob = loadProblem<ProblemT>(instOp);
178 if (failed(prob.check()) || failed(scheduling::scheduleLP(prob, lastOp)) ||
179 failed(prob.verify()))
180 return {};
181 return saveProblem(prob, builder);
182}
183
184static InstanceOp scheduleWithLP(InstanceOp instOp, StringRef options,
185 OpBuilder &builder) {
186 auto lastOp = getLastOp(instOp, options);
187 if (!lastOp) {
188 auto instName = instOp.getSymName().value_or("unnamed");
189 llvm::errs()
190 << "ssp-schedule: Ambiguous objective for LP scheduler: Instance '"
191 << instName << "' has no designated last operation\n";
192 return {};
193 }
194
195 auto problemName = instOp.getProblemName();
196 if (problemName == "Problem")
197 return scheduleProblemTWithLP<Problem>(instOp, lastOp, builder);
198 if (problemName == "CyclicProblem")
199 return scheduleProblemTWithLP<CyclicProblem>(instOp, lastOp, builder);
200
201 llvm::errs() << "ssp-schedule: Unsupported problem '" << problemName
202 << "' for LP scheduler\n";
203 return {};
204}
205
206//===----------------------------------------------------------------------===//
207// CPSAT scheduler (requires OR-Tools)
208//===----------------------------------------------------------------------===//
209
210static InstanceOp scheduleWithCPSAT(InstanceOp instOp, StringRef options,
211 OpBuilder &builder) {
212 auto lastOp = getLastOp(instOp, options);
213 if (!lastOp) {
214 auto instName = instOp.getSymName().value_or("unnamed");
215 llvm::errs()
216 << "ssp-schedule: Ambiguous objective for CPSAT scheduler: Instance '"
217 << instName << "' has no designated last operation\n";
218 return {};
219 }
220
221 auto problemName = instOp.getProblemName();
222 if (problemName != "SharedOperatorsProblem") {
223 llvm::errs() << "ssp-schedule: Unsupported problem '" << problemName
224 << "' for CPSAT scheduler\n";
225 return {};
226 }
227
228 auto prob = loadProblem<SharedOperatorsProblem>(instOp);
229 if (failed(prob.check()) || failed(scheduling::scheduleCPSAT(prob, lastOp)) ||
230 failed(prob.verify()))
231 return {};
232 return saveProblem(prob, builder);
233}
234
235#endif // SCHEDULING_OR_TOOLS
236
237//===----------------------------------------------------------------------===//
238// Algorithm dispatcher
239//===----------------------------------------------------------------------===//
240
241static InstanceOp scheduleWith(InstanceOp instOp, StringRef scheduler,
242 StringRef options, OpBuilder &builder) {
243 if (scheduler.empty() || scheduler == "simplex")
244 return scheduleWithSimplex(instOp, options, builder);
245 if (scheduler == "asap")
246 return scheduleWithASAP(instOp, builder);
247#ifdef SCHEDULING_OR_TOOLS
248 if (scheduler == "lp")
249 return scheduleWithLP(instOp, options, builder);
250 if (scheduler == "cpsat")
251 return scheduleWithCPSAT(instOp, options, builder);
252#endif
253
254 llvm::errs() << "ssp-schedule: Unsupported scheduler '" << scheduler
255 << "' requested\n";
256 return {};
257}
258
259//===----------------------------------------------------------------------===//
260// Pass implementation
261//===----------------------------------------------------------------------===//
262
263namespace {
264struct SchedulePass : public circt::ssp::impl::ScheduleBase<SchedulePass> {
265 void runOnOperation() override;
266};
267} // end anonymous namespace
268
269void SchedulePass::runOnOperation() {
270 auto moduleOp = getOperation();
271
272 SmallVector<InstanceOp> instanceOps;
273 OpBuilder builder(&getContext());
274 for (auto instOp : moduleOp.getOps<InstanceOp>()) {
275 builder.setInsertionPoint(instOp);
276 auto scheduledOp = scheduleWith(instOp, scheduler.getValue(),
277 schedulerOptions.getValue(), builder);
278 if (!scheduledOp)
279 return signalPassFailure();
280 instanceOps.push_back(instOp);
281 }
282
283 llvm::for_each(instanceOps, [](InstanceOp op) { op.erase(); });
284}
285
286std::unique_ptr<mlir::Pass> circt::ssp::createSchedulePass() {
287 return std::make_unique<SchedulePass>();
288}
static InstanceOp scheduleProblemTWithSimplex(InstanceOp instOp, Operation *lastOp, OpBuilder &builder)
Definition Schedule.cpp:90
static InstanceOp scheduleWithASAP(InstanceOp instOp, OpBuilder &builder)
Definition Schedule.cpp:70
static OperationOp getLastOp(InstanceOp instOp, StringRef options)
Definition Schedule.cpp:42
static InstanceOp scheduleWithSimplex(InstanceOp instOp, StringRef options, OpBuilder &builder)
Definition Schedule.cpp:125
static InstanceOp scheduleChainingCyclicProblemWithSimplex(InstanceOp instOp, Operation *lastOp, float cycleTime, OpBuilder &builder)
Definition Schedule.cpp:113
static InstanceOp scheduleChainingProblemWithSimplex(InstanceOp instOp, Operation *lastOp, float cycleTime, OpBuilder &builder)
Definition Schedule.cpp:101
static std::optional< float > getCycleTime(StringRef options)
Definition Schedule.cpp:58
static InstanceOp scheduleWith(InstanceOp instOp, StringRef scheduler, StringRef options, OpBuilder &builder)
Definition Schedule.cpp:241
LogicalResult scheduleLP(Problem &prob, Operation *lastOp)
Solve the basic problem using linear programming and an external LP solver.
LogicalResult scheduleCPSAT(SharedOperatorsProblem &prob, Operation *lastOp)
Solve the acyclic problem with shared operators using constraint programming and an external SAT solv...
LogicalResult scheduleSimplex(Problem &prob, Operation *lastOp)
Solve the basic problem using linear programming and a handwritten implementation of the simplex algo...
LogicalResult scheduleASAP(Problem &prob)
This is a simple list scheduler for solving the basic scheduling problem.
std::unique_ptr< mlir::Pass > createSchedulePass()
Definition Schedule.cpp:286
InstanceOp saveProblem(ProblemT &prob, std::tuple< OperationPropertyTs... > opProps, std::tuple< OperatorTypePropertyTs... > oprProps, std::tuple< DependencePropertyTs... > depProps, std::tuple< InstancePropertyTs... > instProps, OpBuilder &builder)
Construct an InstanceOp from a given ProblemT instance, and create/attach attributes of the given cla...
Definition Utilities.h:320
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.