23 #define DEBUG_TYPE "pipeline-schedule-linear"
26 using namespace circt;
28 using namespace pipeline;
32 class ScheduleLinearPipelinePass
33 :
public ScheduleLinearPipelineBase<ScheduleLinearPipelinePass> {
35 void runOnOperation()
override;
38 LogicalResult schedulePipeline(UnscheduledPipelineOp pipeline);
45 return op->hasTrait<OpTrait::ConstantLike>();
49 ScheduleLinearPipelinePass::schedulePipeline(UnscheduledPipelineOp pipeline) {
52 auto opLibAttr = pipeline->getAttrOfType<FlatSymbolRefAttr>(
"operator_lib");
54 return pipeline.emitError(
"missing 'operator_lib' attribute");
55 auto parentModule = pipeline->getParentOfType<ModuleOp>();
56 auto opLib = parentModule.lookupSymbol<ssp::OperatorLibraryOp>(opLibAttr);
58 return pipeline.emitError(
"operator library '")
59 << opLibAttr <<
"' not found";
64 DenseMap<SymbolRefAttr, Problem::OperatorType> operatorTypes;
69 cast<pipeline::ReturnOp>(pipeline.getEntryStage()->getTerminator());
70 for (
auto &op : pipeline.getOps()) {
76 bool isReturnOp = &op == returnOp.getOperation();
80 operatorType = problem.getOrInsertOperatorType(
"return");
81 problem.setLatency(operatorType, 0);
84 auto operatorTypeAttr =
85 op.getAttrOfType<SymbolRefAttr>(
"ssp.operator_type");
86 if (!operatorTypeAttr)
88 <<
"Expected 'ssp.operator_type' attribute on operation.";
90 auto operatorTypeIt = operatorTypes.find(operatorTypeAttr);
91 if (operatorTypeIt == operatorTypes.end()) {
94 opLib.lookupSymbol<ssp::OperatorTypeOp>(operatorTypeAttr);
96 return op.emitError() <<
"Operator type '" << operatorTypeAttr
97 <<
"' not found in operator library.";
99 auto insertRes = operatorTypes.try_emplace(
100 operatorTypeAttr, ssp::loadOperatorType<Problem, ssp::LatencyAttr>(
101 problem, opTypeOp, oprIds));
102 operatorTypeIt = insertRes.first;
104 operatorType = operatorTypeIt->second;
107 problem.insertOperation(&op);
108 problem.setLinkedOperatorType(&op, operatorType);
114 if (!isReturnOp && op.use_empty()) {
115 if (failed(problem.insertDependence({&op, returnOp.getOperation()})))
116 return op.emitError()
117 <<
"Failed to insert dependence from operation to return op.";
122 assert(succeeded(problem.check()));
124 return pipeline.emitError(
"Failed to schedule pipeline.");
126 assert(succeeded(problem.verify()));
129 using StageIdx = unsigned;
131 OpBuilder b(pipeline.getContext());
136 std::map<StageIdx, llvm::SmallVector<Operation *>> stageMap;
137 llvm::SmallVector<Operation *, 4> otherOps;
140 b.setInsertionPoint(pipeline);
141 auto schedPipeline = b.template create<pipeline::ScheduledPipelineOp>(
142 pipeline.getLoc(), pipeline.getDataOutputs().getTypes(),
143 pipeline.getInputs(), pipeline.getInputNames(), pipeline.getOutputNames(),
144 pipeline.getClock(), pipeline.getReset(), pipeline.getGo(),
145 pipeline.getStall(), pipeline.getNameAttr());
147 Block *currentStage = schedPipeline.getStage(0);
149 for (
auto [oldBArg, newBArg] :
150 llvm::zip(pipeline.getEntryStage()->getArguments(),
151 currentStage->getArguments()))
152 oldBArg.replaceAllUsesWith(newBArg);
156 unsigned currentEndTime = 0;
157 for (
auto &op : pipeline.getOps()) {
159 otherOps.push_back(&op);
162 unsigned startTime = *problem.getStartTime(&op);
163 stageMap[startTime].push_back(&op);
165 auto oldEndTime = currentEndTime;
166 currentEndTime = std::max(currentEndTime, *problem.getEndTime(&op));
167 for (
unsigned i = oldEndTime; i < currentEndTime; ++i) {
168 Block *newStage = schedPipeline.addStage();
172 b.setInsertionPointToEnd(currentStage);
173 b.create<pipeline::StageOp>(pipeline.getLoc(), newStage, ValueRange{},
175 currentStage = newStage;
180 returnOp->moveBefore(currentStage, currentStage->end());
184 Block *entryStage = schedPipeline.getStage(0);
185 Operation *entryStageTerminator = entryStage->getTerminator();
186 for (
auto *op : otherOps)
187 op->moveBefore(entryStageTerminator);
189 for (
auto [startTime, ops] : stageMap) {
190 Block *stage = schedPipeline.getStage(startTime);
191 assert(stage &&
"Stage not found");
192 Operation *stageTerminator = stage->getTerminator();
194 op->moveBefore(stageTerminator);
198 pipeline.replaceAllUsesWith(schedPipeline);
203 void ScheduleLinearPipelinePass::runOnOperation() {
204 for (
auto ®ion : getOperation()->getRegions()) {
206 llvm::make_early_inc_range(region.getOps<UnscheduledPipelineOp>())) {
207 if (failed(schedulePipeline(pipeline)))
208 return signalPassFailure();
213 std::unique_ptr<mlir::Pass>
215 return std::make_unique<ScheduleLinearPipelinePass>();
assert(baseType &&"element must be base type")
static bool ignoreOp(Operation *op)
mlir::StringAttr OperatorType
Operator types are distinguished by name (chosen by the client).
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createScheduleLinearPipelinePass()
LogicalResult scheduleSimplex(Problem &prob, Operation *lastOp)
Solve the basic problem using linear programming and a handwritten implementation of the simplex algo...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.