#include "mlir/Transforms/TopologicalSortUtils.h"
#include "mlir/IR/OpDefinition.h"
using namespace mlir;
static bool isOpReady(Operation *op, DenseSet<Operation *> &unscheduledOps,
function_ref<bool(Value, Operation *)> isOperandReady) {
const auto isReady = [&](Value value) {
if (isOperandReady && isOperandReady(value, op))
return true;
Operation *parent = value.getDefiningOp();
if (!parent)
return true;
do {
if (parent == op)
return true;
if (unscheduledOps.contains(parent))
return false;
} while ((parent = parent->getParentOp()));
return true;
};
WalkResult readyToSchedule = op->walk([&](Operation *nestedOp) {
return llvm::all_of(nestedOp->getOperands(),
[&](Value operand) { return isReady(operand); })
? WalkResult::advance()
: WalkResult::interrupt();
});
return !readyToSchedule.wasInterrupted();
}
bool mlir::sortTopologically(
Block *block, llvm::iterator_range<Block::iterator> ops,
function_ref<bool(Value, Operation *)> isOperandReady) {
if (ops.empty())
return true;
DenseSet<Operation *> unscheduledOps;
for (Operation &op : ops)
unscheduledOps.insert(&op);
Block::iterator nextScheduledOp = ops.begin();
Block::iterator end = ops.end();
bool allOpsScheduled = true;
while (!unscheduledOps.empty()) {
bool scheduledAtLeastOnce = false;
for (Operation &op :
llvm::make_early_inc_range(llvm::make_range(nextScheduledOp, end))) {
if (!isOpReady(&op, unscheduledOps, isOperandReady))
continue;
unscheduledOps.erase(&op);
op.moveBefore(block, nextScheduledOp);
scheduledAtLeastOnce = true;
if (&op == &*nextScheduledOp)
++nextScheduledOp;
}
if (!scheduledAtLeastOnce) {
allOpsScheduled = false;
unscheduledOps.erase(&*nextScheduledOp);
++nextScheduledOp;
}
}
return allOpsScheduled;
}
bool mlir::sortTopologically(
Block *block, function_ref<bool(Value, Operation *)> isOperandReady) {
if (block->empty())
return true;
if (block->back().hasTrait<OpTrait::IsTerminator>())
return sortTopologically(block, block->without_terminator(),
isOperandReady);
return sortTopologically(block, *block, isOperandReady);
}
bool mlir::computeTopologicalSorting(
MutableArrayRef<Operation *> ops,
function_ref<bool(Value, Operation *)> isOperandReady) {
if (ops.empty())
return true;
DenseSet<Operation *> unscheduledOps;
for (Operation *op : ops)
unscheduledOps.insert(op);
unsigned nextScheduledOp = 0;
bool allOpsScheduled = true;
while (!unscheduledOps.empty()) {
bool scheduledAtLeastOnce = false;
for (unsigned i = nextScheduledOp; i < ops.size(); ++i) {
if (!isOpReady(ops[i], unscheduledOps, isOperandReady))
continue;
unscheduledOps.erase(ops[i]);
std::swap(ops[i], ops[nextScheduledOp]);
scheduledAtLeastOnce = true;
++nextScheduledOp;
}
if (!scheduledAtLeastOnce) {
allOpsScheduled = false;
unscheduledOps.erase(ops[nextScheduledOp++]);
}
}
return allOpsScheduled;
}