17#include "mlir/IR/Operation.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/Format.h"
26#define DEBUG_TYPE "simplex-schedulers"
52class SimplexSchedulerBase {
88 SmallVector<SmallVector<int>> tableau;
92 SmallVector<int> implicitBasicVariableColumnVector;
103 SmallVector<unsigned> nonBasicVariables;
108 SmallVector<unsigned> basicVariables;
113 DenseMap<Operation *, unsigned> startTimeVariables;
119 SmallVector<int> startTimeLocations;
123 DenseMap<unsigned, unsigned> frozenVariables;
131 unsigned nObjectives;
133 unsigned &firstConstraintRow = nObjectives;
136 static constexpr unsigned nParameters = 3;
138 static constexpr unsigned parameter1Column = 0;
140 static constexpr unsigned parameterSColumn = 1;
142 static constexpr unsigned parameterTColumn = 2;
144 static constexpr unsigned firstNonBasicVariableColumn = nParameters;
148 SmallVector<Problem::Dependence> additionalConstraints;
150 virtual Problem &getProblem() = 0;
151 virtual LogicalResult checkLastOp();
152 virtual bool fillObjectiveRow(SmallVector<int> &row,
unsigned obj);
153 virtual void fillConstraintRow(SmallVector<int> &row,
155 virtual void fillAdditionalConstraintRow(SmallVector<int> &row,
159 int getParametricConstant(
unsigned row);
160 SmallVector<int> getObjectiveVector(
unsigned column);
161 std::optional<unsigned> findDualPivotRow();
162 std::optional<unsigned> findDualPivotColumn(
unsigned pivotRow,
163 bool allowPositive =
false);
164 std::optional<unsigned> findPrimalPivotColumn();
165 std::optional<unsigned> findPrimalPivotRow(
unsigned pivotColumn);
166 void multiplyRow(
unsigned row,
int factor);
167 void addMultipleOfRow(
unsigned sourceRow,
int factor,
unsigned targetRow);
168 void pivot(
unsigned pivotRow,
unsigned pivotColumn);
169 LogicalResult solveTableau();
170 LogicalResult restoreDualFeasibility();
171 bool isInBasis(
unsigned startTimeVariable);
172 unsigned freeze(
unsigned startTimeVariable,
unsigned timeStep);
173 void translate(
unsigned column,
int factor1,
int factorS,
int factorT);
174 LogicalResult scheduleAt(
unsigned startTimeVariable,
unsigned timeStep);
175 void moveBy(
unsigned startTimeVariable,
unsigned amount);
176 unsigned getStartTime(
unsigned startTimeVariable);
181 explicit SimplexSchedulerBase(Operation *lastOp) : lastOp(lastOp) {}
182 virtual ~SimplexSchedulerBase() =
default;
183 virtual LogicalResult schedule() = 0;
187class SimplexScheduler :
public SimplexSchedulerBase {
192 Problem &getProblem()
override {
return prob; }
195 SimplexScheduler(
Problem &prob, Operation *lastOp)
196 : SimplexSchedulerBase(lastOp), prob(prob) {}
198 LogicalResult schedule()
override;
206class CyclicSimplexScheduler :
public SimplexSchedulerBase {
211 Problem &getProblem()
override {
return prob; }
212 void fillConstraintRow(SmallVector<int> &row,
216 CyclicSimplexScheduler(
CyclicProblem &prob, Operation *lastOp)
217 : SimplexSchedulerBase(lastOp), prob(prob) {}
218 LogicalResult schedule()
override;
223class SharedOperatorsSimplexScheduler :
public SimplexSchedulerBase {
228 Problem &getProblem()
override {
return prob; }
233 : SimplexSchedulerBase(lastOp), prob(prob) {}
234 LogicalResult schedule()
override;
239class ModuloSimplexScheduler :
public CyclicSimplexScheduler {
242 ModuloSimplexScheduler &sched;
249 explicit MRT(ModuloSimplexScheduler &sched) : sched(sched) {}
250 LogicalResult enter(Operation *op,
unsigned timeStep);
251 void release(Operation *op);
255 SmallVector<unsigned> asapTimes, alapTimes;
256 SmallVector<Operation *> unscheduled, scheduled;
260 Problem &getProblem()
override {
return prob; }
261 LogicalResult checkLastOp()
override;
262 enum { OBJ_LATENCY = 0, OBJ_AXAP };
263 bool fillObjectiveRow(SmallVector<int> &row,
unsigned obj)
override;
264 void updateMargins();
265 void scheduleOperation(Operation *n);
266 unsigned computeResMinII();
269 ModuloSimplexScheduler(
ModuloProblem &prob, Operation *lastOp)
270 : CyclicSimplexScheduler(prob, lastOp), prob(prob), mrt(*
this) {}
271 LogicalResult schedule()
override;
276class ChainingSimplexScheduler :
public SimplexSchedulerBase {
282 Problem &getProblem()
override {
return prob; }
283 void fillAdditionalConstraintRow(SmallVector<int> &row,
289 : SimplexSchedulerBase(lastOp), prob(prob), cycleTime(cycleTime) {}
290 LogicalResult schedule()
override;
298class ChainingCyclicSimplexScheduler :
public SimplexSchedulerBase {
304 Problem &getProblem()
override {
return prob; }
305 void fillConstraintRow(SmallVector<int> &row,
307 void fillAdditionalConstraintRow(SmallVector<int> &row,
313 : SimplexSchedulerBase(lastOp), prob(prob), cycleTime(cycleTime) {}
314 LogicalResult schedule()
override;
323LogicalResult SimplexSchedulerBase::checkLastOp() {
324 auto &prob = getProblem();
325 if (!prob.hasOperation(lastOp))
326 return prob.getContainingOp()->emitError(
327 "problem does not include last operation");
331bool SimplexSchedulerBase::fillObjectiveRow(SmallVector<int> &row,
335 row[startTimeLocations[startTimeVariables[lastOp]]] = 1;
339void SimplexSchedulerBase::fillConstraintRow(SmallVector<int> &row,
341 auto &prob = getProblem();
344 unsigned latency = *prob.getLatency(*prob.getLinkedOperatorType(src));
345 row[parameter1Column] = -latency;
347 row[startTimeLocations[startTimeVariables[src]]] = 1;
348 row[startTimeLocations[startTimeVariables[dst]]] = -1;
352void SimplexSchedulerBase::fillAdditionalConstraintRow(
359void SimplexSchedulerBase::buildTableau() {
360 auto &prob = getProblem();
368 for (
auto *op : prob.getOperations()) {
369 nonBasicVariables.push_back(var);
370 startTimeVariables[op] = var;
371 startTimeLocations.push_back(firstNonBasicVariableColumn + var);
376 nColumns = nParameters + nonBasicVariables.size();
379 auto addRow = [&]() -> SmallVector<int> & {
380 implicitBasicVariableColumnVector.push_back(0);
381 return tableau.emplace_back(nColumns, 0);
386 bool hasMoreObjectives;
388 auto &objRowVec = addRow();
389 hasMoreObjectives = fillObjectiveRow(objRowVec, nObjectives);
391 }
while (hasMoreObjectives);
394 for (
auto *op : prob.getOperations()) {
395 for (
auto &dep : prob.getDependences(op)) {
396 auto &consRowVec = addRow();
397 fillConstraintRow(consRowVec, dep);
398 basicVariables.push_back(var);
402 for (
auto &dep : additionalConstraints) {
403 auto &consRowVec = addRow();
404 fillAdditionalConstraintRow(consRowVec, dep);
405 basicVariables.push_back(var);
410 nRows = tableau.size();
413int SimplexSchedulerBase::getParametricConstant(
unsigned row) {
414 auto &rowVec = tableau[row];
417 return rowVec[parameter1Column] + rowVec[parameterSColumn] * parameterS +
418 rowVec[parameterTColumn] * parameterT;
421SmallVector<int> SimplexSchedulerBase::getObjectiveVector(
unsigned column) {
422 SmallVector<int> objVec;
424 for (
unsigned obj = 0; obj < nObjectives; ++obj)
425 objVec.push_back(tableau[obj][column]);
429std::optional<unsigned> SimplexSchedulerBase::findDualPivotRow() {
431 for (
unsigned row = firstConstraintRow; row < nRows; ++row)
432 if (getParametricConstant(row) < 0)
438std::optional<unsigned>
439SimplexSchedulerBase::findDualPivotColumn(
unsigned pivotRow,
440 bool allowPositive) {
441 SmallVector<int> maxQuot(nObjectives, std::numeric_limits<int>::min());
442 std::optional<unsigned> pivotCol;
448 for (
unsigned col = firstNonBasicVariableColumn; col < nColumns; ++col) {
449 if (frozenVariables.count(
450 nonBasicVariables[col - firstNonBasicVariableColumn]))
453 int pivotCand = tableau[pivotRow][col];
457 if (pivotCand < 0 || (allowPositive && pivotCand > 0)) {
459 assert(pivotCand * pivotCand == 1);
461 SmallVector<int> quot;
462 for (
unsigned obj = 0; obj < nObjectives; ++obj)
463 quot.push_back(tableau[obj][col] / pivotCand);
465 if (std::lexicographical_compare(maxQuot.begin(), maxQuot.end(),
466 quot.begin(), quot.end())) {
476std::optional<unsigned> SimplexSchedulerBase::findPrimalPivotColumn() {
478 SmallVector<int> zeroVec(nObjectives, 0);
479 for (
unsigned col = firstNonBasicVariableColumn; col < nColumns; ++col) {
480 if (frozenVariables.count(
481 nonBasicVariables[col - firstNonBasicVariableColumn]))
484 SmallVector<int> objVec = getObjectiveVector(col);
485 if (std::lexicographical_compare(objVec.begin(), objVec.end(),
486 zeroVec.begin(), zeroVec.end()))
493std::optional<unsigned>
494SimplexSchedulerBase::findPrimalPivotRow(
unsigned pivotColumn) {
495 int minQuot = std::numeric_limits<int>::max();
496 std::optional<unsigned> pivotRow;
502 for (
unsigned row = firstConstraintRow; row < nRows; ++row) {
503 int pivotCand = tableau[row][pivotColumn];
507 int quot = getParametricConstant(row) / pivotCand;
508 if (quot < minQuot) {
518void SimplexSchedulerBase::multiplyRow(
unsigned row,
int factor) {
520 for (
unsigned col = 0; col < nColumns; ++col)
521 tableau[row][col] *= factor;
523 implicitBasicVariableColumnVector[row] *= factor;
526void SimplexSchedulerBase::addMultipleOfRow(
unsigned sourceRow,
int factor,
527 unsigned targetRow) {
528 assert(factor != 0 && sourceRow != targetRow);
529 for (
unsigned col = 0; col < nColumns; ++col)
530 tableau[targetRow][col] += tableau[sourceRow][col] * factor;
532 implicitBasicVariableColumnVector[targetRow] +=
533 implicitBasicVariableColumnVector[sourceRow] * factor;
541void SimplexSchedulerBase::pivot(
unsigned pivotRow,
unsigned pivotColumn) {
543 implicitBasicVariableColumnVector[pivotRow] = 1;
545 int pivotElem = tableau[pivotRow][pivotColumn];
547 assert(pivotElem * pivotElem == 1);
549 multiplyRow(pivotRow, 1 / pivotElem);
551 for (
unsigned row = 0; row < nRows; ++row) {
555 int elem = tableau[row][pivotColumn];
560 addMultipleOfRow(pivotRow, -elem, row);
566 for (
unsigned row = 0; row < nRows; ++row) {
567 tableau[row][pivotColumn] = implicitBasicVariableColumnVector[row];
568 implicitBasicVariableColumnVector[row] = 0;
572 unsigned &nonBasicVar =
573 nonBasicVariables[pivotColumn - firstNonBasicVariableColumn];
574 unsigned &basicVar = basicVariables[pivotRow - firstConstraintRow];
577 if (nonBasicVar < startTimeLocations.size())
578 startTimeLocations[nonBasicVar] = -pivotRow;
579 if (basicVar < startTimeLocations.size())
580 startTimeLocations[basicVar] = pivotColumn;
583 std::swap(nonBasicVar, basicVar);
586LogicalResult SimplexSchedulerBase::solveTableau() {
590 while (
auto pivotRow = findDualPivotRow()) {
592 if (
auto pivotCol = findDualPivotColumn(*pivotRow)) {
593 pivot(*pivotRow, *pivotCol);
601 int entry1Col = tableau[*pivotRow][parameter1Column];
602 int entryTCol = tableau[*pivotRow][parameterTColumn];
609 int newParameterT = (-entry1Col - 1) / entryTCol + 1;
610 if (newParameterT > parameterT) {
611 parameterT = newParameterT;
612 LLVM_DEBUG(dbgs() <<
"Increased II to " << parameterT <<
'\n');
625LogicalResult SimplexSchedulerBase::restoreDualFeasibility() {
630 while (
auto pivotCol = findPrimalPivotColumn()) {
632 if (
auto pivotRow = findPrimalPivotRow(*pivotCol)) {
633 pivot(*pivotRow, *pivotCol);
645bool SimplexSchedulerBase::isInBasis(
unsigned startTimeVariable) {
646 assert(startTimeVariable < startTimeLocations.size());
647 int loc = startTimeLocations[startTimeVariable];
648 if (-loc >= (
int)firstConstraintRow)
650 if (loc >= (
int)firstNonBasicVariableColumn)
652 llvm_unreachable(
"Invalid variable location");
655unsigned SimplexSchedulerBase::freeze(
unsigned startTimeVariable,
657 assert(startTimeVariable < startTimeLocations.size());
658 assert(!frozenVariables.count(startTimeVariable));
661 frozenVariables[startTimeVariable] = timeStep;
663 if (!isInBasis(startTimeVariable))
665 return startTimeLocations[startTimeVariable];
668 unsigned pivotRow = -startTimeLocations[startTimeVariable];
672 auto pivotCol = findDualPivotColumn(pivotRow,
true);
676 pivot(pivotRow, *pivotCol);
682void SimplexSchedulerBase::translate(
unsigned column,
int factor1,
int factorS,
684 for (
unsigned row = 0; row < nRows; ++row) {
685 auto &rowVec = tableau[row];
686 int elem = rowVec[column];
690 rowVec[parameter1Column] += -elem * factor1;
691 rowVec[parameterSColumn] += -elem * factorS;
692 rowVec[parameterTColumn] += -elem * factorT;
696LogicalResult SimplexSchedulerBase::scheduleAt(
unsigned startTimeVariable,
698 assert(startTimeVariable < startTimeLocations.size());
699 assert(!frozenVariables.count(startTimeVariable));
702 unsigned frozenCol = freeze(startTimeVariable, timeStep);
703 translate(frozenCol, 0, 1, 0);
706 parameterS = timeStep;
707 auto solved = solveTableau();
710 if (failed(solved)) {
713 translate(frozenCol, 0, -1, 0);
714 frozenVariables.erase(startTimeVariable);
715 auto solvedAfterRollback = solveTableau();
716 assert(succeeded(solvedAfterRollback));
717 (void)solvedAfterRollback;
739 translate(parameterSColumn, -timeStep, 1,
745void SimplexSchedulerBase::moveBy(
unsigned startTimeVariable,
unsigned amount) {
746 assert(startTimeVariable < startTimeLocations.size());
747 assert(frozenVariables.count(startTimeVariable));
750 frozenVariables[startTimeVariable] += amount;
754 translate(startTimeLocations[startTimeVariable], amount,
762unsigned SimplexSchedulerBase::getStartTime(
unsigned startTimeVariable) {
763 assert(startTimeVariable < startTimeLocations.size());
765 if (!isInBasis(startTimeVariable))
768 return frozenVariables.lookup(startTimeVariable);
772 return getParametricConstant(-startTimeLocations[startTimeVariable]);
775void SimplexSchedulerBase::dumpTableau() {
776 for (
unsigned j = 0; j < nColumns; ++j)
779 for (
unsigned i = 0; i < nRows; ++i) {
780 if (i == firstConstraintRow) {
781 for (
unsigned j = 0; j < nColumns; ++j) {
782 if (j == firstNonBasicVariableColumn)
788 for (
unsigned j = 0; j < nColumns; ++j) {
789 if (j == firstNonBasicVariableColumn)
791 dbgs() << format(
" %3d", tableau[i][j]);
793 if (i >= firstConstraintRow)
794 dbgs() << format(
" |< %2d", basicVariables[i - firstConstraintRow]);
797 for (
unsigned j = 0; j < nColumns; ++j)
800 dbgs() << format(
" %3d %3d %3d | ", 1, parameterS, parameterT);
801 for (
unsigned j = firstNonBasicVariableColumn; j < nColumns; ++j)
802 dbgs() << format(
" %2d^",
803 nonBasicVariables[j - firstNonBasicVariableColumn]);
811LogicalResult SimplexScheduler::schedule() {
812 if (failed(checkLastOp()))
819 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
821 if (failed(solveTableau()))
826 dbgs() <<
"Final tableau:\n"; dumpTableau();
827 dbgs() <<
"Optimal solution found with start time of last operation = "
828 << -getParametricConstant(0) <<
'\n');
831 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
840void CyclicSimplexScheduler::fillConstraintRow(SmallVector<int> &row,
842 SimplexSchedulerBase::fillConstraintRow(row, dep);
844 row[parameterTColumn] = *dist;
847LogicalResult CyclicSimplexScheduler::schedule() {
848 if (failed(checkLastOp()))
855 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
857 if (failed(solveTableau()))
860 LLVM_DEBUG(dbgs() <<
"Final tableau:\n"; dumpTableau();
861 dbgs() <<
"Optimal solution found with II = " << parameterT
862 <<
" and start time of last operation = "
863 << -getParametricConstant(0) <<
'\n');
867 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
881 return prob.
getLimit(rsrc).value_or(0) > 0;
885LogicalResult SharedOperatorsSimplexScheduler::schedule() {
886 if (failed(checkLastOp()))
893 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
895 if (failed(solveTableau()))
898 LLVM_DEBUG(dbgs() <<
"After solving resource-free problem:\n"; dumpTableau());
910 SmallVector<Operation *> limitedOps;
913 limitedOps.push_back(op);
925 llvm::stable_sort(limitedOps, [&](Operation *a, Operation *b) {
926 return getStartTime(startTimeVariables[a]) <
927 getStartTime(startTimeVariables[b]);
932 SmallDenseMap<Problem::ResourceType, SmallDenseMap<unsigned, unsigned>>
935 for (
auto *op : limitedOps) {
937 assert(maybeRsrcs &&
"Limited operation must have linked resource types");
939 auto &rsrcs = *maybeRsrcs;
940 assert(rsrcs.size() == 1 &&
941 "Multi-resource operations are not yet supported by this scheduler");
943 auto rsrc = rsrcs[0];
944 unsigned limit = prob.
getLimit(rsrc).value_or(0);
949 unsigned startTimeVar = startTimeVariables[op];
950 unsigned candTime = getStartTime(startTimeVar);
951 while (reservationTable[rsrc].lookup(candTime) == limit)
956 auto fixed = scheduleAt(startTimeVar, candTime);
961 ++reservationTable[rsrc][candTime];
963 LLVM_DEBUG(dbgs() <<
"After scheduling " << startTimeVar
964 <<
" to t=" << candTime <<
":\n";
970 dbgs() <<
"Final tableau:\n"; dumpTableau();
971 dbgs() <<
"Feasible solution found with start time of last operation = "
972 << -getParametricConstant(0) <<
'\n');
975 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
984LogicalResult ModuloSimplexScheduler::checkLastOp() {
987 return contOp->emitError(
"problem does not include last operation");
991 DenseSet<Operation *> sinks(ops.begin(), ops.end());
997 if (!sinks.contains(lastOp))
998 return contOp->emitError(
"last operation is not a sink");
999 if (sinks.size() > 1)
1000 return contOp->emitError(
"multiple sinks detected");
1005LogicalResult ModuloSimplexScheduler::MRT::enter(Operation *op,
1006 unsigned timeStep) {
1008 assert(maybeRsrcs &&
"Operation must have linked resource types");
1010 auto &rsrcs = *maybeRsrcs;
1011 assert(rsrcs.size() == 1 &&
1012 "Multi-resource operations are not yet supported by MRT");
1014 auto rsrc = rsrcs[0];
1015 auto lim = *sched.prob.
getLimit(rsrc);
1018 auto &revTab = reverseTables[rsrc];
1019 assert(!revTab.count(op));
1021 unsigned slot = timeStep % sched.parameterT;
1022 auto &cell = tables[rsrc][slot];
1023 if (cell.size() < lim) {
1031void ModuloSimplexScheduler::MRT::release(Operation *op) {
1032 auto maybeRsrcs = sched.prob.getLinkedResourceTypes(op);
1033 assert(maybeRsrcs &&
"Operation must have linked resource types");
1035 auto &rsrcs = *maybeRsrcs;
1036 assert(rsrcs.size() == 1 &&
1037 "Multi-resource operations are not yet supported by MRT");
1039 auto rsrc = rsrcs[0];
1040 auto &revTab = reverseTables[rsrc];
1041 auto it = revTab.find(op);
1042 assert(it != revTab.end());
1043 tables[rsrc][it->second].erase(op);
1047bool ModuloSimplexScheduler::fillObjectiveRow(SmallVector<int> &row,
1052 row[startTimeLocations[startTimeVariables[lastOp]]] = 1;
1056 for (
auto *op : getProblem().getOperations())
1058 row[startTimeLocations[startTimeVariables[op]]] = 1;
1061 llvm_unreachable(
"Unsupported objective requested");
1065void ModuloSimplexScheduler::updateMargins() {
1071 for (
auto *axapTimes : {&alapTimes, &asapTimes}) {
1072 multiplyRow(OBJ_AXAP, -1);
1074 auto dualFeasRestored = restoreDualFeasibility();
1075 auto solved = solveTableau();
1076 assert(succeeded(dualFeasRestored) && succeeded(solved));
1077 (void)dualFeasRestored, (
void)solved;
1079 for (
unsigned stv = 0; stv < startTimeLocations.size(); ++stv)
1080 (*axapTimes)[stv] = getStartTime(stv);
1084void ModuloSimplexScheduler::scheduleOperation(Operation *n) {
1086 unsigned stvN = startTimeVariables[n];
1093 unsigned stN = getStartTime(stvN);
1094 unsigned ubN = stN + parameterT - 1;
1096 LLVM_DEBUG(dbgs() <<
"Attempting to schedule in [" << stN <<
", " << ubN
1097 <<
"]: " << *n <<
'\n');
1099 for (
unsigned ct = stN; ct <= ubN; ++ct)
1100 if (succeeded(mrt.enter(n, ct))) {
1101 auto fixedN = scheduleAt(stvN, ct);
1102 if (succeeded(fixedN)) {
1103 LLVM_DEBUG(dbgs() <<
"Success at t=" << ct <<
" " << *n <<
'\n');
1117 LLVM_DEBUG(dbgs() <<
"Incrementing II to " << (parameterT + 1)
1118 <<
" to resolve resource conflict for " << *n <<
'\n');
1125 unsigned phiN = stN / parameterT;
1126 unsigned tauN = stN % parameterT;
1130 unsigned deltaN = 1;
1133 SmallVector<Operation *> moved;
1134 for (Operation *j : scheduled) {
1136 unsigned stvJ = startTimeVariables[j];
1137 unsigned stJ = getStartTime(stvJ);
1138 unsigned phiJ = stJ / parameterT;
1139 unsigned tauJ = stJ % parameterT;
1140 unsigned deltaJ = 0;
1146 if (tauN < tauJ || (tauN == tauJ && phiN > phiJ) ||
1147 (tauN == tauJ && phiN == phiJ && stvN < stvJ)) {
1167 moveBy(stvJ, phiJ + deltaJ);
1172 auto solved = solveTableau();
1173 assert(succeeded(solved));
1177 for (
auto *m : moved)
1179 for (
auto *m : moved) {
1180 auto enteredM = mrt.enter(m, getStartTime(startTimeVariables[m]));
1181 assert(succeeded(enteredM));
1187 auto fixedN = scheduleAt(stvN, stN + phiN + deltaN);
1188 auto enteredN = mrt.enter(n, tauN + deltaN);
1189 assert(succeeded(fixedN) && succeeded(enteredN));
1190 (void)fixedN, (
void)enteredN;
1193unsigned ModuloSimplexScheduler::computeResMinII() {
1194 unsigned resMinII = 1;
1195 SmallDenseMap<Problem::ResourceType, unsigned> uses;
1201 for (
auto rsrc : *maybeRsrcs) {
1202 if (prob.
getLimit(rsrc).value_or(0) > 0)
1207 for (
auto pair : uses)
1208 resMinII = std::max(
1209 resMinII, (
unsigned)ceil(pair.second / *prob.
getLimit(pair.first)));
1214LogicalResult ModuloSimplexScheduler::schedule() {
1215 if (failed(checkLastOp()))
1219 parameterT = computeResMinII();
1220 LLVM_DEBUG(dbgs() <<
"ResMinII = " << parameterT <<
"\n");
1222 asapTimes.resize(startTimeLocations.size());
1223 alapTimes.resize(startTimeLocations.size());
1225 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1227 if (failed(solveTableau()))
1228 return prob.
getContainingOp()->emitError() <<
"problem is infeasible";
1232 for (
auto *op : ops)
1234 unscheduled.push_back(op);
1237 while (!unscheduled.empty()) {
1244 llvm::min_element(unscheduled, [&](Operation *opA, Operation *opB) {
1245 auto stvA = startTimeVariables[opA];
1246 auto stvB = startTimeVariables[opB];
1247 auto slackA = alapTimes[stvA] - asapTimes[stvA];
1248 auto slackB = alapTimes[stvB] - asapTimes[stvB];
1249 return slackA < slackB;
1251 Operation *op = *opIt;
1252 unscheduled.erase(opIt);
1254 scheduleOperation(op);
1255 scheduled.push_back(op);
1258 LLVM_DEBUG(dbgs() <<
"Final tableau:\n"; dumpTableau();
1259 dbgs() <<
"Solution found with II = " << parameterT
1260 <<
" and start time of last operation = "
1261 << -getParametricConstant(0) <<
'\n');
1264 for (
auto *op : ops)
1265 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
1274void ChainingSimplexScheduler::fillAdditionalConstraintRow(
1276 fillConstraintRow(row, dep);
1279 row[parameter1Column] -= 1;
1282LogicalResult ChainingSimplexScheduler::schedule() {
1284 prob, cycleTime, additionalConstraints)))
1291 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1293 if (failed(solveTableau()))
1294 return prob.
getContainingOp()->emitError() <<
"problem is infeasible";
1298 dbgs() <<
"Final tableau:\n"; dumpTableau();
1299 dbgs() <<
"Optimal solution found with start time of last operation = "
1300 << -getParametricConstant(0) <<
'\n');
1303 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
1306 assert(succeeded(filledIn));
1316void ChainingCyclicSimplexScheduler::fillConstraintRow(
1318 SimplexSchedulerBase::fillConstraintRow(row, dep);
1320 row[parameterTColumn] = *dist;
1323void ChainingCyclicSimplexScheduler::fillAdditionalConstraintRow(
1325 fillConstraintRow(row, dep);
1328 row[parameter1Column] -= 1;
1331LogicalResult ChainingCyclicSimplexScheduler::schedule() {
1333 prob, cycleTime, additionalConstraints)))
1340 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1342 if (failed(solveTableau()))
1343 return prob.
getContainingOp()->emitError() <<
"problem is infeasible";
1345 LLVM_DEBUG(dbgs() <<
"Final tableau:\n"; dumpTableau();
1346 dbgs() <<
"Optimal solution found with II = " << parameterT
1347 <<
" and start time of last operation = "
1348 << -getParametricConstant(0) <<
'\n');
1352 prob.
setStartTime(op, getStartTime(startTimeVariables[op]));
1355 assert(succeeded(filledIn));
1366 SimplexScheduler simplex(prob, lastOp);
1367 return simplex.schedule();
1371 Operation *lastOp) {
1372 CyclicSimplexScheduler simplex(prob, lastOp);
1373 return simplex.schedule();
1377 Operation *lastOp) {
1378 SharedOperatorsSimplexScheduler simplex(prob, lastOp);
1379 return simplex.schedule();
1383 Operation *lastOp) {
1384 ModuloSimplexScheduler simplex(prob, lastOp);
1385 return simplex.schedule();
1389 Operation *lastOp,
float cycleTime) {
1390 ChainingSimplexScheduler simplex(prob, lastOp, cycleTime);
1391 return simplex.schedule();
1395 Operation *lastOp,
float cycleTime) {
1396 ChainingCyclicSimplexScheduler simplex(prob, lastOp, cycleTime);
1397 return simplex.schedule();
assert(baseType &&"element must be base type")
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static bool isLimited(Operation *op, SharedOperatorsProblem &prob)
This class models the accumulation of physical propagation delays on combinational paths along SSA de...
This class models the accumulation of physical propagation delays on combinational paths along SSA de...
This class models a cyclic scheduling problem.
std::optional< unsigned > getDistance(Dependence dep)
The distance determines whether a dependence has to be satisfied in the same iteration (distance=0 or...
void setInitiationInterval(unsigned val)
This class models the modulo scheduling problem as the composition of the cyclic problem and the reso...
This class models the most basic scheduling problem.
bool hasOperation(Operation *op)
Return true if op is part of this problem.
std::optional< SmallVector< ResourceType > > getLinkedResourceTypes(Operation *op)
The linked resource type provides the available resources for op.
std::optional< OperatorType > getLinkedOperatorType(Operation *op)
The linked operator type provides the runtime characteristics for op.
void setStartTime(Operation *op, unsigned val)
const OperationSet & getOperations()
Return the set of operations.
detail::Dependence Dependence
A thin wrapper to allow a uniform handling of def-use and auxiliary dependences.
DependenceRange getDependences(Operation *op)
Return a range object to transparently iterate over op's incoming 1) implicit def-use dependences (ba...
Operation * getContainingOp()
Return the operation containing this problem, e.g. to emit diagnostics.
This class models a resource-constrained scheduling problem.
std::optional< unsigned > getLimit(ResourceType rsrc)
The limit is the maximum number of operations using rsrc that are available in the target hardware.
Operation * getDestination() const
Return the destination of the dependence.
Operation * getSource() const
Return the source of the dependence.
LogicalResult computeChainBreakingDependences(ChainingProblem &prob, float cycleTime, SmallVectorImpl< Problem::Dependence > &result)
Analyse combinational chains in prob's dependence graph and determine pairs of operations that must b...
LogicalResult scheduleSimplex(Problem &prob, Operation *lastOp)
Solve the basic problem using linear programming and a handwritten implementation of the simplex algo...
LogicalResult computeStartTimesInCycle(ChainingProblem &prob)
Assuming prob is scheduled and contains (integer) start times, this method fills in the start times i...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Resource types are distinguished by name (chosen by the client).