CIRCT  20.0.0git
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 
13 #include "circt/Dialect/HW/HWOps.h"
19 #include "mlir/Pass/Pass.h"
20 
22 
23 #include "llvm/ADT/StringExtras.h"
24 
25 namespace circt {
26 namespace ssp {
27 #define GEN_PASS_DEF_SCHEDULE
28 #include "circt/Dialect/SSP/SSPPasses.h.inc"
29 } // namespace ssp
30 } // namespace circt
31 
32 using namespace circt;
33 using namespace scheduling;
34 using 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.
42 static 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).
58 static 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 
70 static 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 
89 template <typename ProblemT>
90 static 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 
101 static 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 
113 static 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 
125 static 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 
174 template <typename ProblemT>
175 static 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 
184 static 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 
210 static 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 
241 static 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 
263 namespace {
264 struct SchedulePass : public circt::ssp::impl::ScheduleBase<SchedulePass> {
265  void runOnOperation() override;
266 };
267 } // end anonymous namespace
268 
269 void 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 
286 std::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 std::optional< float > getCycleTime(StringRef options)
Definition: Schedule.cpp:58
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 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.
Definition: DebugAnalysis.h:21