17#include "mlir/IR/PatternMatch.h"
18#include "llvm/Support/Debug.h"
22#define GEN_PASS_DEF_LINEARSCANREGISTERALLOCATIONPASS
23#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
30#define DEBUG_TYPE "rtg-linear-scan-register-allocation"
35struct RegisterLiveRange {
36 rtg::RegisterAttrInterface fixedReg;
37 rtg::VirtualRegisterOp regOp;
42class LinearScanRegisterAllocationPass
43 :
public circt::rtg::impl::LinearScanRegisterAllocationPassBase<
44 LinearScanRegisterAllocationPass> {
46 void runOnOperation()
override;
52 RegisterLiveRange *reg) {
54 llvm::sort(active, [](
auto *a,
auto *b) {
return a->end < b->end; });
56 for (
auto *iter = active.begin(); iter != active.end(); ++iter) {
58 if (a->end >= reg->start)
65void LinearScanRegisterAllocationPass::runOnOperation() {
66 LLVM_DEBUG(llvm::dbgs() <<
"=== Processing "
67 << OpWithFlags(getOperation(),
68 OpPrintingFlags().skipRegions())
71 if (getOperation()->getNumRegions() != 1 ||
72 getOperation()->getRegion(0).getBlocks().size() != 1) {
73 getOperation()->emitError(
"expected a single region with a single block");
74 return signalPassFailure();
77 DenseMap<Operation *, unsigned> opIndices;
80 llvm::enumerate(getOperation()->getRegion(0).getBlocks().front())) {
87 SmallVector<std::unique_ptr<RegisterLiveRange>> regRanges;
88 SmallVector<RegisterLiveRange *> active;
89 for (
auto &op : getOperation()->getRegion(0).getBlocks().front()) {
90 if (!isa<rtg::FixedRegisterOp, rtg::VirtualRegisterOp>(&op))
97 if (
auto regOp = dyn_cast<rtg::VirtualRegisterOp>(&op))
100 if (
auto regOp = dyn_cast<rtg::FixedRegisterOp>(&op))
101 lr.fixedReg = regOp.getReg();
103 for (
auto *user : op.getUsers()) {
104 if (!isa<rtg::InstructionOpInterface, rtg::ValidateOp>(user)) {
105 user->emitError(
"only operations implementing 'InstructionOpInterface' "
106 "and 'rtg.validate' are allowed to use registers");
107 return signalPassFailure();
111 unsigned idx = opIndices.at(user);
112 lr.start = std::min(lr.start, idx);
113 lr.end = std::max(lr.end, idx);
116 regRanges.emplace_back(std::make_unique<RegisterLiveRange>(lr));
124 active.push_back(regRanges.back().get());
128 llvm::sort(regRanges, [](
const auto &a,
const auto &b) {
129 return a->start < b->start || (a->start == b->start && !a->regOp);
132 for (
auto &lr : regRanges) {
142 cast<rtg::VirtualRegisterConfigAttr>(lr->regOp.getAllowedRegsAttr());
143 rtg::RegisterAttrInterface availableReg;
144 for (
auto reg : configAttr.getAllowedRegs()) {
145 if (llvm::none_of(active, [&](
auto *r) {
return r->fixedReg ==
reg; })) {
146 availableReg = cast<rtg::RegisterAttrInterface>(reg);
152 ++numRegistersSpilled;
153 lr->regOp->emitError(
154 "need to spill this register, but not supported yet");
155 return signalPassFailure();
158 lr->fixedReg = availableReg;
159 active.push_back(lr.get());
163 for (
auto ®Range : regRanges) {
164 llvm::dbgs() <<
"Start: " << regRange->start <<
", End: " << regRange->end
165 <<
", Selected: " << regRange->fixedReg <<
"\n";
167 llvm::dbgs() <<
"\n";
170 for (
auto ® : regRanges) {
175 IRRewriter rewriter(
reg->regOp);
176 rewriter.replaceOpWithNewOp<rtg::FixedRegisterOp>(
reg->regOp,
static void expireOldInterval(SmallVector< RegisterLiveRange * > &active, RegisterLiveRange *reg)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)