15 #include "llvm/Support/Debug.h"
18 using namespace circt;
19 using namespace pipeline;
26 operator Value()
const {
return v; }
27 operator Attribute()
const {
return name; }
28 operator llvm::StringRef()
const {
return name.getValue(); }
31 class ExplicitRegsPass :
public ExplicitRegsBase<ExplicitRegsPass> {
33 void runOnOperation()
override;
36 void runOnPipeline(ScheduledPipelineOp p);
41 NamedValue routeThroughStage(Value v, Block *stage);
45 int64_t stageDistance(Block *from, Block *to);
57 operator NamedValue() {
return NamedValue{v, name}; }
65 DenseMap<Block *, llvm::MapVector<Value, RoutedValue>> stageRegOrPassMap;
68 llvm::DenseMap<Block *, unsigned> stageMap;
70 std::shared_ptr<BackedgeBuilder> bb;
71 ScheduledPipelineOp parent;
76 int64_t ExplicitRegsPass::stageDistance(Block *from, Block *to) {
77 int64_t fromStage = stageMap[from];
78 int64_t toStage = stageMap[to];
79 return toStage - fromStage;
83 Operation *definingOp = v.getDefiningOp();
85 auto setNameFn = [&](Value other, StringRef name) {
90 if (OpAsmOpInterface asmInterface = dyn_cast<OpAsmOpInterface>(definingOp))
91 asmInterface.getAsmResultNames(setNameFn);
93 else if (
auto nameHint =
94 definingOp->getAttrOfType<StringAttr>(
"sv.namehint"))
101 auto asmInterface = cast<OpAsmOpInterface>(parent.getOperation());
102 asmInterface.getAsmBlockArgumentNames(parent.getBody(), setNameFn);
110 NamedValue ExplicitRegsPass::routeThroughStage(Value v, Block *stage) {
112 Block *definingStage = retVal.getParentBlock();
115 if (definingStage == stage) {
121 auto regIt = stageRegOrPassMap[stage].find(retVal);
122 if (regIt != stageRegOrPassMap[stage].
end()) {
125 return regIt->second;
130 auto *definingOp = retVal.getDefiningOp();
131 if (definingOp && definingOp->hasTrait<OpTrait::ConstantLike>())
136 int64_t valueLatency = 0;
137 if (
auto latencyOp = dyn_cast_or_null<LatencyOp>(definingOp))
138 valueLatency = latencyOp.getLatency();
142 bool isReg = valueLatency < stageDistance(definingStage, stage);
143 auto valueBackedge = bb->get(retVal.getType());
144 auto stageRegBE = stageRegOrPassMap[stage].insert(
145 {retVal, RoutedValue{valueBackedge, isReg,
147 retVal = valueBackedge;
150 Block *stagePred = stage->getSinglePredecessor();
151 assert(stagePred &&
"Expected stage to have a single predecessor");
152 auto namedV = routeThroughStage(v, stagePred);
154 stageRegBE.first->second.name = namedV.name;
156 return NamedValue{retVal, namedV.name};
159 void ExplicitRegsPass::runOnPipeline(ScheduledPipelineOp pipeline) {
160 OpBuilder b(pipeline.getContext());
162 bb = std::make_shared<BackedgeBuilder>(b, pipeline.getLoc());
166 llvm::DenseSet<Value> extLikeInputs;
167 for (
auto extInput : pipeline.getExtInputs())
168 extLikeInputs.insert(extInput);
169 extLikeInputs.insert(pipeline.getClock());
170 extLikeInputs.insert(pipeline.getReset());
171 if (pipeline.hasStall())
172 extLikeInputs.insert(pipeline.getStall());
175 stageMap = pipeline.getStageMap();
176 for (Block *stage : pipeline.getOrderedStages()) {
179 stage->walk([&](Operation *op) {
182 for (OpOperand &operand : op->getOpOperands()) {
183 if (extLikeInputs.contains(operand.get())) {
192 Value reroutedValue = routeThroughStage(operand.get(), stage);
193 if (reroutedValue != operand.get())
194 op->setOperand(operand.getOperandNumber(), reroutedValue);
199 auto *ctx = &getContext();
205 for (
auto &it : stageRegOrPassMap) {
206 Block *stage = it.first;
207 auto ®OrPassMap = it.second;
211 llvm::MapVector<Value, Value> regInsMap, passInsMap;
212 llvm::SmallVector<Attribute> regNames, passNames;
213 Block *predecessorStage = stage->getSinglePredecessor();
214 auto predStageRegOrPassMap = stageRegOrPassMap.find(predecessorStage);
215 assert(predecessorStage &&
"Stage should always have a single predecessor");
216 for (
auto &[value, backedge] : regOrPassMap) {
218 regNames.push_back(backedge.name);
220 passNames.push_back(backedge.name);
222 if (predStageRegOrPassMap != stageRegOrPassMap.end()) {
225 auto predRegIt = predStageRegOrPassMap->second.find(value);
226 if (predRegIt != predStageRegOrPassMap->second.end()) {
227 if (backedge.isReg) {
228 regInsMap[value] = predRegIt->second.v;
230 passInsMap[value] = predRegIt->second.v;
238 regInsMap[value] = value;
240 passInsMap[value] = value;
245 llvm::SmallVector<Value> regIns, passIns;
246 llvm::transform(regInsMap, std::back_inserter(regIns),
247 [](
auto &pair) {
return pair.second; });
248 llvm::transform(passInsMap, std::back_inserter(passIns),
249 [](
auto &pair) {
return pair.second; });
251 StageOp terminator = cast<StageOp>(predecessorStage->getTerminator());
252 b.setInsertionPoint(terminator);
253 llvm::SmallVector<llvm::SmallVector<Value>> clockGates;
254 b.create<StageOp>(terminator.getLoc(), terminator.getNextStage(), regIns,
255 passIns, clockGates, b.getArrayAttr(regNames),
256 b.getArrayAttr(passNames));
265 auto addArgAndRewriteBE = [&](llvm::MapVector<Value, Value> &map) {
266 for (
auto origToActualValue : map) {
267 Value origValue = origToActualValue.first;
268 stage->insertArgument(argIdx, origValue.getType(),
270 auto *backedgeIt = regOrPassMap.find(origValue);
271 assert(backedgeIt != regOrPassMap.end() &&
272 "Expected to find backedge for value");
273 backedgeIt->second.v.setValue(stage->getArgument(argIdx));
277 addArgAndRewriteBE(regInsMap);
278 addArgAndRewriteBE(passInsMap);
282 stageRegOrPassMap.clear();
285 void ExplicitRegsPass::runOnOperation() {
286 getOperation()->walk(
287 [&](ScheduledPipelineOp pipeline) { runOnPipeline(pipeline); });
291 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.