16#include "mlir/Pass/Pass.h"
17#include "llvm/Support/Debug.h"
21#define GEN_PASS_DEF_EXPLICITREGS
22#include "circt/Dialect/Pipeline/PipelinePasses.h.inc"
28using namespace pipeline;
35 operator Value()
const {
return v; }
36 operator Attribute()
const {
return name; }
37 operator llvm::StringRef()
const {
return name.getValue(); }
41 :
public circt::pipeline::impl::ExplicitRegsBase<ExplicitRegsPass> {
43 void runOnOperation()
override;
46 void runOnPipeline(ScheduledPipelineOp p);
51 NamedValue routeThroughStage(Value v, Block *stage);
55 int64_t stageDistance(Block *from, Block *to);
67 operator NamedValue() {
return NamedValue{v, name}; }
75 DenseMap<Block *, llvm::MapVector<Value, RoutedValue>> stageRegOrPassMap;
78 llvm::DenseMap<Block *, unsigned> stageMap;
80 std::shared_ptr<BackedgeBuilder> bb;
81 ScheduledPipelineOp parent;
86int64_t ExplicitRegsPass::stageDistance(Block *from, Block *to) {
87 int64_t fromStage = stageMap[from];
88 int64_t toStage = stageMap[to];
89 return toStage - fromStage;
92StringAttr ExplicitRegsPass::genValueName(Value v) {
93 Operation *definingOp = v.getDefiningOp();
95 auto setNameFn = [&](Value other, StringRef name) {
97 valueName = StringAttr::get(other.getContext(), name);
100 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(definingOp))
101 asmInterface.getAsmResultNames(setNameFn);
103 else if (
auto nameHint =
104 definingOp->getAttrOfType<StringAttr>(
"sv.namehint"))
107 valueName = StringAttr::get(v.getContext(),
"");
111 auto asmInterface = cast<OpAsmOpInterface>(parent.getOperation());
112 asmInterface.getAsmBlockArgumentNames(parent.getBody(), setNameFn);
120NamedValue ExplicitRegsPass::routeThroughStage(Value v, Block *stage) {
122 Block *definingStage = retVal.getParentBlock();
125 if (definingStage == stage) {
131 auto regIt = stageRegOrPassMap[stage].find(retVal);
132 if (regIt != stageRegOrPassMap[stage].
end()) {
135 return regIt->second;
140 auto *definingOp = retVal.getDefiningOp();
141 if (definingOp && definingOp->hasTrait<OpTrait::ConstantLike>())
142 return NamedValue{retVal, StringAttr::get(retVal.getContext(),
"")};
146 int64_t valueLatency = 0;
147 if (
auto latencyOp = dyn_cast_or_null<LatencyOp>(definingOp))
148 valueLatency = latencyOp.getLatency();
152 bool isReg = valueLatency < stageDistance(definingStage, stage);
153 auto valueBackedge = bb->get(retVal.getType());
154 auto stageRegBE = stageRegOrPassMap[stage].insert(
155 {retVal, RoutedValue{valueBackedge, isReg,
156 StringAttr::get(retVal.getContext(),
"")}});
157 retVal = valueBackedge;
160 Block *stagePred = stage->getSinglePredecessor();
161 assert(stagePred &&
"Expected stage to have a single predecessor");
162 auto namedV = routeThroughStage(v, stagePred);
164 stageRegBE.first->second.name = namedV.name;
166 return NamedValue{retVal, namedV.name};
169void ExplicitRegsPass::runOnPipeline(ScheduledPipelineOp pipeline) {
170 OpBuilder b(pipeline.getContext());
172 bb = std::make_shared<BackedgeBuilder>(b, pipeline.getLoc());
176 llvm::DenseSet<Value> extLikeInputs;
177 for (
auto extInput : pipeline.getExtInputs())
178 extLikeInputs.insert(extInput);
179 extLikeInputs.insert(pipeline.getClock());
180 extLikeInputs.insert(pipeline.getReset());
181 if (pipeline.hasStall())
182 extLikeInputs.insert(pipeline.getStall());
185 stageMap = pipeline.getStageMap();
186 for (Block *stage : pipeline.getOrderedStages()) {
189 stage->walk([&](Operation *op) {
192 for (OpOperand &operand : op->getOpOperands()) {
193 if (extLikeInputs.contains(operand.get())) {
206 llvm::dyn_cast_or_null<pipeline::SourceOp>(operand.getOwner());
209 "Only pipeline.srcOp's should be allowed to reference "
210 "values outside of this block. Verifiers should have caught this");
212 Value reroutedValue = routeThroughStage(operand.get(), stage);
213 if (reroutedValue != operand.get())
214 op->setOperand(operand.getOperandNumber(), reroutedValue);
219 auto *ctx = &getContext();
225 for (
auto &it : stageRegOrPassMap) {
226 Block *stage = it.first;
227 auto ®OrPassMap = it.second;
231 llvm::MapVector<Value, Value> regInsMap, passInsMap;
232 llvm::SmallVector<Attribute> regNames, passNames;
233 Block *predecessorStage = stage->getSinglePredecessor();
234 auto predStageRegOrPassMap = stageRegOrPassMap.find(predecessorStage);
235 assert(predecessorStage &&
"Stage should always have a single predecessor");
236 for (
auto &[value, backedge] : regOrPassMap) {
238 regNames.push_back(backedge.name);
240 passNames.push_back(backedge.name);
242 if (predStageRegOrPassMap != stageRegOrPassMap.end()) {
245 auto predRegIt = predStageRegOrPassMap->second.find(value);
246 if (predRegIt != predStageRegOrPassMap->second.end()) {
247 if (backedge.isReg) {
248 regInsMap[value] = predRegIt->second.v;
250 passInsMap[value] = predRegIt->second.v;
258 regInsMap[value] = value;
260 passInsMap[value] = value;
265 llvm::SmallVector<Value> regIns, passIns;
266 llvm::transform(regInsMap, std::back_inserter(regIns),
267 [](
auto &pair) {
return pair.second; });
268 llvm::transform(passInsMap, std::back_inserter(passIns),
269 [](
auto &pair) {
return pair.second; });
271 StageOp terminator = cast<StageOp>(predecessorStage->getTerminator());
272 b.setInsertionPoint(terminator);
273 llvm::SmallVector<llvm::SmallVector<Value>> clockGates;
274 b.create<StageOp>(terminator.getLoc(), terminator.getNextStage(), regIns,
275 passIns, clockGates, b.getArrayAttr(regNames),
276 b.getArrayAttr(passNames));
285 auto addArgAndRewriteBE = [&](llvm::MapVector<Value, Value> &map) {
286 for (
auto origToActualValue : map) {
287 Value origValue = origToActualValue.first;
288 stage->insertArgument(argIdx, origValue.getType(),
289 UnknownLoc::get(ctx));
290 auto *backedgeIt = regOrPassMap.find(origValue);
291 assert(backedgeIt != regOrPassMap.end() &&
292 "Expected to find backedge for value");
293 backedgeIt->second.v.setValue(stage->getArgument(argIdx));
297 addArgAndRewriteBE(regInsMap);
298 addArgAndRewriteBE(passInsMap);
302 stageRegOrPassMap.clear();
305 for (
auto srcOp :
llvm::make_early_inc_range(pipeline.getOps<SourceOp>())) {
306 srcOp.getResult().replaceAllUsesWith(srcOp.getInput());
311void ExplicitRegsPass::runOnOperation() {
312 getOperation()->walk(
313 [&](ScheduledPipelineOp pipeline) { runOnPipeline(pipeline); });
317 return std::make_unique<ExplicitRegsPass>();
assert(baseType &&"element must be base type")
static std::string valueName(Operation *scopeOp, Value v)
Convenience function for getting the SSA name of v under the scope of operation scopeOp.
static llvm::raw_string_ostream & genValueName(llvm::raw_string_ostream &os, Value value)
Backedge is a wrapper class around a Value.
std::unique_ptr< mlir::Pass > createExplicitRegsPass()
Block * getParentStageInPipeline(ScheduledPipelineOp pipeline, Operation *op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.