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"
28 using namespace circt;
52 class 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;
187 class SimplexScheduler :
public SimplexSchedulerBase {
192 Problem &getProblem()
override {
return prob; }
195 SimplexScheduler(
Problem &prob, Operation *lastOp)
196 : SimplexSchedulerBase(lastOp), prob(prob) {}
198 LogicalResult schedule()
override;
206 class 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;
223 class SharedOperatorsSimplexScheduler :
public SimplexSchedulerBase {
228 Problem &getProblem()
override {
return prob; }
233 : SimplexSchedulerBase(lastOp), prob(prob) {}
234 LogicalResult schedule()
override;
239 class 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;
276 class 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;
298 class 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;
323 LogicalResult SimplexSchedulerBase::checkLastOp() {
324 auto &prob = getProblem();
325 if (!prob.hasOperation(lastOp))
326 return prob.getContainingOp()->emitError(
327 "problem does not include last operation");
331 bool SimplexSchedulerBase::fillObjectiveRow(SmallVector<int> &row,
335 row[startTimeLocations[startTimeVariables[lastOp]]] = 1;
339 void 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;
352 void SimplexSchedulerBase::fillAdditionalConstraintRow(
359 void 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();
413 int SimplexSchedulerBase::getParametricConstant(
unsigned row) {
414 auto &rowVec = tableau[row];
417 return rowVec[parameter1Column] + rowVec[parameterSColumn] * parameterS +
418 rowVec[parameterTColumn] * parameterT;
421 SmallVector<int> SimplexSchedulerBase::getObjectiveVector(
unsigned column) {
422 SmallVector<int> objVec;
424 for (
unsigned obj = 0; obj < nObjectives; ++obj)
425 objVec.push_back(tableau[obj][column]);
429 std::optional<unsigned> SimplexSchedulerBase::findDualPivotRow() {
431 for (
unsigned row = firstConstraintRow; row < nRows; ++row)
432 if (getParametricConstant(row) < 0)
438 std::optional<unsigned>
439 SimplexSchedulerBase::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())) {
476 std::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()))
493 std::optional<unsigned>
494 SimplexSchedulerBase::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) {
518 void SimplexSchedulerBase::multiplyRow(
unsigned row,
int factor) {
520 for (
unsigned col = 0; col < nColumns; ++col)
521 tableau[row][col] *= factor;
523 implicitBasicVariableColumnVector[row] *= factor;
526 void 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;
541 void 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);
586 LogicalResult 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');
625 LogicalResult SimplexSchedulerBase::restoreDualFeasibility() {
630 while (
auto pivotCol = findPrimalPivotColumn()) {
632 if (
auto pivotRow = findPrimalPivotRow(*pivotCol)) {
633 pivot(*pivotRow, *pivotCol);
645 bool 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");
655 unsigned 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);
682 void 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;
696 LogicalResult 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,
745 void 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,
762 unsigned SimplexSchedulerBase::getStartTime(
unsigned startTimeVariable) {
763 assert(startTimeVariable < startTimeLocations.size());
765 if (!isInBasis(startTimeVariable))
768 return frozenVariables.lookup(startTimeVariable);
772 return getParametricConstant(-startTimeLocations[startTimeVariable]);
775 void 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]);
811 LogicalResult SimplexScheduler::schedule() {
812 if (failed(checkLastOp()))
819 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
821 if (failed(solveTableau()))
822 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
826 dbgs() <<
"Final tableau:\n"; dumpTableau();
827 dbgs() <<
"Optimal solution found with start time of last operation = "
828 << -getParametricConstant(0) <<
'\n');
830 for (
auto *op : prob.getOperations())
831 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
840 void CyclicSimplexScheduler::fillConstraintRow(SmallVector<int> &row,
842 SimplexSchedulerBase::fillConstraintRow(row, dep);
843 if (
auto dist = prob.getDistance(dep))
844 row[parameterTColumn] = *dist;
847 LogicalResult CyclicSimplexScheduler::schedule() {
848 if (failed(checkLastOp()))
855 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
857 if (failed(solveTableau()))
858 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
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');
865 prob.setInitiationInterval(parameterT);
866 for (
auto *op : prob.getOperations())
867 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
880 LogicalResult SharedOperatorsSimplexScheduler::schedule() {
881 if (failed(checkLastOp()))
888 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
890 if (failed(solveTableau()))
891 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
893 LLVM_DEBUG(dbgs() <<
"After solving resource-free problem:\n"; dumpTableau());
904 auto &ops = prob.getOperations();
905 SmallVector<Operation *> limitedOps;
908 limitedOps.push_back(op);
920 std::stable_sort(limitedOps.begin(), limitedOps.end(),
921 [&](Operation *a, Operation *b) {
922 return getStartTime(startTimeVariables[a]) <
923 getStartTime(startTimeVariables[b]);
931 for (
auto *op : limitedOps) {
932 auto opr = *prob.getLinkedOperatorType(op);
933 unsigned limit = prob.getLimit(opr).value_or(0);
938 unsigned startTimeVar = startTimeVariables[op];
939 unsigned candTime = getStartTime(startTimeVar);
940 while (reservationTable[opr].lookup(candTime) == limit)
945 auto fixed = scheduleAt(startTimeVar, candTime);
950 ++reservationTable[opr][candTime];
952 LLVM_DEBUG(dbgs() <<
"After scheduling " << startTimeVar
953 <<
" to t=" << candTime <<
":\n";
959 dbgs() <<
"Final tableau:\n"; dumpTableau();
960 dbgs() <<
"Feasible solution found with start time of last operation = "
961 << -getParametricConstant(0) <<
'\n');
964 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
973 LogicalResult ModuloSimplexScheduler::checkLastOp() {
974 auto *contOp = prob.getContainingOp();
975 if (!prob.hasOperation(lastOp))
976 return contOp->emitError(
"problem does not include last operation");
979 auto &ops = prob.getOperations();
980 DenseSet<Operation *> sinks(ops.begin(), ops.end());
982 for (
auto &dep : prob.getDependences(op))
983 if (prob.getDistance(dep).value_or(0) == 0)
986 if (!sinks.contains(lastOp))
987 return contOp->emitError(
"last operation is not a sink");
988 if (sinks.size() > 1)
989 return contOp->emitError(
"multiple sinks detected");
994 LogicalResult ModuloSimplexScheduler::MRT::enter(Operation *op,
996 auto opr = *sched.prob.getLinkedOperatorType(op);
997 auto lim = *sched.prob.getLimit(opr);
1000 auto &revTab = reverseTables[opr];
1001 assert(!revTab.count(op));
1003 unsigned slot = timeStep % sched.parameterT;
1004 auto &cell = tables[opr][slot];
1005 if (cell.size() < lim) {
1013 void ModuloSimplexScheduler::MRT::release(Operation *op) {
1014 auto opr = *sched.prob.getLinkedOperatorType(op);
1015 auto &revTab = reverseTables[opr];
1016 auto it = revTab.find(op);
1017 assert(it != revTab.end());
1018 tables[opr][it->second].erase(op);
1022 bool ModuloSimplexScheduler::fillObjectiveRow(SmallVector<int> &row,
1027 row[startTimeLocations[startTimeVariables[lastOp]]] = 1;
1031 for (
auto *op : getProblem().getOperations())
1033 row[startTimeLocations[startTimeVariables[op]]] = 1;
1036 llvm_unreachable(
"Unsupported objective requested");
1040 void ModuloSimplexScheduler::updateMargins() {
1046 for (
auto *axapTimes : {&alapTimes, &asapTimes}) {
1047 multiplyRow(OBJ_AXAP, -1);
1049 auto dualFeasRestored = restoreDualFeasibility();
1050 auto solved = solveTableau();
1051 assert(succeeded(dualFeasRestored) && succeeded(solved));
1052 (void)dualFeasRestored, (
void)solved;
1054 for (
unsigned stv = 0; stv < startTimeLocations.size(); ++stv)
1055 (*axapTimes)[stv] = getStartTime(stv);
1059 void ModuloSimplexScheduler::scheduleOperation(Operation *n) {
1060 auto oprN = *prob.getLinkedOperatorType(n);
1061 unsigned stvN = startTimeVariables[n];
1068 unsigned stN = getStartTime(stvN);
1069 unsigned ubN = stN + parameterT - 1;
1071 LLVM_DEBUG(dbgs() <<
"Attempting to schedule in [" << stN <<
", " << ubN
1072 <<
"]: " << *n <<
'\n');
1074 for (
unsigned ct = stN; ct <= ubN; ++ct)
1075 if (succeeded(mrt.enter(n, ct))) {
1076 auto fixedN = scheduleAt(stvN, ct);
1077 if (succeeded(fixedN)) {
1078 LLVM_DEBUG(dbgs() <<
"Success at t=" << ct <<
" " << *n <<
'\n');
1092 LLVM_DEBUG(dbgs() <<
"Incrementing II to " << (parameterT + 1)
1093 <<
" to resolve resource conflict for " << *n <<
'\n');
1100 unsigned phiN = stN / parameterT;
1101 unsigned tauN = stN % parameterT;
1105 unsigned deltaN = 1;
1108 SmallVector<Operation *> moved;
1109 for (Operation *j : scheduled) {
1110 auto oprJ = *prob.getLinkedOperatorType(j);
1111 unsigned stvJ = startTimeVariables[j];
1112 unsigned stJ = getStartTime(stvJ);
1113 unsigned phiJ = stJ / parameterT;
1114 unsigned tauJ = stJ % parameterT;
1115 unsigned deltaJ = 0;
1121 if (tauN < tauJ || (tauN == tauJ && phiN > phiJ) ||
1122 (tauN == tauJ && phiN == phiJ && stvN < stvJ)) {
1142 moveBy(stvJ, phiJ + deltaJ);
1147 auto solved = solveTableau();
1148 assert(succeeded(solved));
1152 for (
auto *m : moved)
1154 for (
auto *m : moved) {
1155 auto enteredM = mrt.enter(m, getStartTime(startTimeVariables[m]));
1156 assert(succeeded(enteredM));
1162 auto fixedN = scheduleAt(stvN, stN + phiN + deltaN);
1163 auto enteredN = mrt.enter(n, tauN + deltaN);
1164 assert(succeeded(fixedN) && succeeded(enteredN));
1165 (void)fixedN, (
void)enteredN;
1168 unsigned ModuloSimplexScheduler::computeResMinII() {
1169 unsigned resMinII = 1;
1171 for (
auto *op : prob.getOperations())
1173 ++uses[*prob.getLinkedOperatorType(op)];
1175 for (
auto pair : uses)
1176 resMinII = std::max(
1177 resMinII, (
unsigned)ceil(pair.second / *prob.getLimit(pair.first)));
1182 LogicalResult ModuloSimplexScheduler::schedule() {
1183 if (failed(checkLastOp()))
1187 parameterT = computeResMinII();
1188 LLVM_DEBUG(dbgs() <<
"ResMinII = " << parameterT <<
"\n");
1190 asapTimes.resize(startTimeLocations.size());
1191 alapTimes.resize(startTimeLocations.size());
1193 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1195 if (failed(solveTableau()))
1196 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
1199 auto &ops = prob.getOperations();
1200 for (
auto *op : ops)
1202 unscheduled.push_back(op);
1205 while (!unscheduled.empty()) {
1212 std::min_element(unscheduled.begin(), unscheduled.end(),
1213 [&](Operation *opA, Operation *opB) {
1214 auto stvA = startTimeVariables[opA];
1215 auto stvB = startTimeVariables[opB];
1216 auto slackA = alapTimes[stvA] - asapTimes[stvA];
1217 auto slackB = alapTimes[stvB] - asapTimes[stvB];
1218 return slackA < slackB;
1220 Operation *op = *opIt;
1221 unscheduled.erase(opIt);
1223 scheduleOperation(op);
1224 scheduled.push_back(op);
1227 LLVM_DEBUG(dbgs() <<
"Final tableau:\n"; dumpTableau();
1228 dbgs() <<
"Solution found with II = " << parameterT
1229 <<
" and start time of last operation = "
1230 << -getParametricConstant(0) <<
'\n');
1232 prob.setInitiationInterval(parameterT);
1233 for (
auto *op : ops)
1234 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
1243 void ChainingSimplexScheduler::fillAdditionalConstraintRow(
1245 fillConstraintRow(row, dep);
1248 row[parameter1Column] -= 1;
1251 LogicalResult ChainingSimplexScheduler::schedule() {
1253 prob, cycleTime, additionalConstraints)))
1260 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1262 if (failed(solveTableau()))
1263 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
1267 dbgs() <<
"Final tableau:\n"; dumpTableau();
1268 dbgs() <<
"Optimal solution found with start time of last operation = "
1269 << -getParametricConstant(0) <<
'\n');
1271 for (
auto *op : prob.getOperations())
1272 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
1275 assert(succeeded(filledIn));
1285 void ChainingCyclicSimplexScheduler::fillConstraintRow(
1287 SimplexSchedulerBase::fillConstraintRow(row, dep);
1288 if (
auto dist = prob.getDistance(dep))
1289 row[parameterTColumn] = *dist;
1292 void ChainingCyclicSimplexScheduler::fillAdditionalConstraintRow(
1294 fillConstraintRow(row, dep);
1297 row[parameter1Column] -= 1;
1300 LogicalResult ChainingCyclicSimplexScheduler::schedule() {
1302 prob, cycleTime, additionalConstraints)))
1309 LLVM_DEBUG(dbgs() <<
"Initial tableau:\n"; dumpTableau());
1311 if (failed(solveTableau()))
1312 return prob.getContainingOp()->emitError() <<
"problem is infeasible";
1314 LLVM_DEBUG(dbgs() <<
"Final tableau:\n"; dumpTableau();
1315 dbgs() <<
"Optimal solution found with II = " << parameterT
1316 <<
" and start time of last operation = "
1317 << -getParametricConstant(0) <<
'\n');
1319 prob.setInitiationInterval(parameterT);
1320 for (
auto *op : prob.getOperations())
1321 prob.setStartTime(op, getStartTime(startTimeVariables[op]));
1324 assert(succeeded(filledIn));
1335 SimplexScheduler simplex(prob, lastOp);
1336 return simplex.schedule();
1340 Operation *lastOp) {
1341 CyclicSimplexScheduler simplex(prob, lastOp);
1342 return simplex.schedule();
1346 Operation *lastOp) {
1347 SharedOperatorsSimplexScheduler simplex(prob, lastOp);
1348 return simplex.schedule();
1352 Operation *lastOp) {
1353 ModuloSimplexScheduler simplex(prob, lastOp);
1354 return simplex.schedule();
1358 Operation *lastOp,
float cycleTime) {
1359 ChainingSimplexScheduler simplex(prob, lastOp, cycleTime);
1360 return simplex.schedule();
1364 Operation *lastOp,
float cycleTime) {
1365 ChainingCyclicSimplexScheduler simplex(prob, lastOp, cycleTime);
1366 return simplex.schedule();
assert(baseType &&"element must be base type")
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.
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.
std::optional< OperatorType > getLinkedOperatorType(Operation *op)
The linked operator type provides the runtime characteristics for op.
This class models a resource-constrained scheduling problem.
std::optional< unsigned > getLimit(OperatorType opr)
The limit is the maximum number of operations using opr that are allowed to start in the same time st...
A wrapper class to uniformly handle def-use and auxiliary dependence edges.
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.