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"
27 using namespace circt;
28 using namespace pipeline;
35 operator Value()
const {
return v; }
36 operator Attribute()
const {
return name; }
37 operator llvm::StringRef()
const {
return name.getValue(); }
40 class ExplicitRegsPass
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;
86 int64_t ExplicitRegsPass::stageDistance(Block *from, Block *to) {
87 int64_t fromStage = stageMap[from];
88 int64_t toStage = stageMap[to];
89 return toStage - fromStage;
93 Operation *definingOp = v.getDefiningOp();
95 auto setNameFn = [&](Value other, StringRef name) {
100 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(definingOp))
101 asmInterface.getAsmResultNames(setNameFn);
103 else if (
auto nameHint =
104 definingOp->getAttrOfType<StringAttr>(
"sv.namehint"))
111 auto asmInterface = cast<OpAsmOpInterface>(parent.getOperation());
112 asmInterface.getAsmBlockArgumentNames(parent.getBody(), setNameFn);
120 NamedValue 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>())
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,
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};
169 void 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())) {
202 Value reroutedValue = routeThroughStage(operand.get(), stage);
203 if (reroutedValue != operand.get())
204 op->setOperand(operand.getOperandNumber(), reroutedValue);
209 auto *ctx = &getContext();
215 for (
auto &it : stageRegOrPassMap) {
216 Block *stage = it.first;
217 auto ®OrPassMap = it.second;
221 llvm::MapVector<Value, Value> regInsMap, passInsMap;
222 llvm::SmallVector<Attribute> regNames, passNames;
223 Block *predecessorStage = stage->getSinglePredecessor();
224 auto predStageRegOrPassMap = stageRegOrPassMap.find(predecessorStage);
225 assert(predecessorStage &&
"Stage should always have a single predecessor");
226 for (
auto &[value, backedge] : regOrPassMap) {
228 regNames.push_back(backedge.name);
230 passNames.push_back(backedge.name);
232 if (predStageRegOrPassMap != stageRegOrPassMap.end()) {
235 auto predRegIt = predStageRegOrPassMap->second.find(value);
236 if (predRegIt != predStageRegOrPassMap->second.end()) {
237 if (backedge.isReg) {
238 regInsMap[value] = predRegIt->second.v;
240 passInsMap[value] = predRegIt->second.v;
248 regInsMap[value] = value;
250 passInsMap[value] = value;
255 llvm::SmallVector<Value> regIns, passIns;
256 llvm::transform(regInsMap, std::back_inserter(regIns),
257 [](
auto &pair) {
return pair.second; });
258 llvm::transform(passInsMap, std::back_inserter(passIns),
259 [](
auto &pair) {
return pair.second; });
261 StageOp terminator = cast<StageOp>(predecessorStage->getTerminator());
262 b.setInsertionPoint(terminator);
263 llvm::SmallVector<llvm::SmallVector<Value>> clockGates;
264 b.create<StageOp>(terminator.getLoc(), terminator.getNextStage(), regIns,
265 passIns, clockGates, b.getArrayAttr(regNames),
266 b.getArrayAttr(passNames));
275 auto addArgAndRewriteBE = [&](llvm::MapVector<Value, Value> &map) {
276 for (
auto origToActualValue : map) {
277 Value origValue = origToActualValue.first;
278 stage->insertArgument(argIdx, origValue.getType(),
280 auto *backedgeIt = regOrPassMap.find(origValue);
281 assert(backedgeIt != regOrPassMap.end() &&
282 "Expected to find backedge for value");
283 backedgeIt->second.v.setValue(stage->getArgument(argIdx));
287 addArgAndRewriteBE(regInsMap);
288 addArgAndRewriteBE(passInsMap);
292 stageRegOrPassMap.clear();
295 void ExplicitRegsPass::runOnOperation() {
296 getOperation()->walk(
297 [&](ScheduledPipelineOp pipeline) { runOnPipeline(pipeline); });
301 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.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createExplicitRegsPass()
Block * getParentStageInPipeline(ScheduledPipelineOp pipeline, Operation *op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.