18#include "mlir/IR/ImplicitLocOpBuilder.h"
19#include "mlir/Pass/Pass.h"
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Support/Debug.h"
24#define DEBUG_TYPE "reg-of-vec-to-mem"
32#define GEN_PASS_DEF_REGOFVECTOMEM
33#include "circt/Dialect/Seq/SeqPasses.h.inc"
51 hw::ArrayInjectOp writeAccess;
54class RegOfVecToMemPass :
public impl::RegOfVecToMemBase<RegOfVecToMemPass> {
56 void runOnOperation()
override;
59 bool analyzeMemoryPattern(FirRegOp
reg, MemoryPattern &
pattern);
60 bool createFirMemory(MemoryPattern &
pattern);
61 bool isArrayType(Type type);
62 std::optional<std::pair<uint64_t, uint64_t>> getArrayDimensions(Type type);
64 SmallVector<Operation *> opsToErase;
69bool RegOfVecToMemPass::isArrayType(Type type) {
70 return isa<hw::ArrayType, hw::UnpackedArrayType>(type);
73std::optional<std::pair<uint64_t, uint64_t>>
74RegOfVecToMemPass::getArrayDimensions(Type type) {
75 if (
auto arrayType = dyn_cast<hw::ArrayType>(type)) {
76 auto elemType = arrayType.getElementType();
77 if (
auto intType = dyn_cast<IntegerType>(elemType)) {
78 return std::make_pair(arrayType.getNumElements(), intType.getWidth());
84bool RegOfVecToMemPass::analyzeMemoryPattern(FirRegOp
reg,
86 LLVM_DEBUG(llvm::dbgs() <<
"Analyzing register: " <<
reg <<
"\n");
89 if (!isArrayType(
reg.getType()))
93 ArrayInjectOp writeAccess;
95 for (
auto *user :
reg.getResult().getUsers()) {
96 LLVM_DEBUG(llvm::dbgs() <<
" Register user: " << *user <<
"\n");
97 if (
auto arrayGet = dyn_cast<hw::ArrayGetOp>(user); !readAccess && arrayGet)
98 readAccess = arrayGet;
99 else if (
auto arrayInject = dyn_cast<hw::ArrayInjectOp>(user);
100 !writeAccess && arrayInject)
101 writeAccess = arrayInject;
102 else if (
auto mux = dyn_cast<comb::MuxOp>(user); !writeMux && mux)
107 if (!readAccess || !writeAccess || !writeMux)
114 auto nextValue =
reg.getNext();
119 LLVM_DEBUG(llvm::dbgs() <<
" Found driving mux: " << mux <<
"\n");
123 if (!mux.getResult().hasOneUse()) {
124 LLVM_DEBUG(llvm::dbgs() <<
" Mux has multiple uses, cannot transform\n");
129 Value writeResult = mux.getTrueValue();
130 Value currentMemory = mux.getFalseValue();
133 if (currentMemory !=
reg.getResult())
137 auto arrayInject = writeResult.getDefiningOp<hw::ArrayInjectOp>();
141 LLVM_DEBUG(llvm::dbgs() <<
" Found array_inject: " << arrayInject <<
"\n");
142 pattern.writeAccess = arrayInject;
143 pattern.writeAddr = arrayInject.getIndex();
144 pattern.writeData = arrayInject.getElement();
145 pattern.writeEnable = mux.getCond();
148 auto arrayGet = readAccess;
149 LLVM_DEBUG(llvm::dbgs() <<
" Found array_get: " << arrayGet <<
"\n");
151 pattern.readAddr = arrayGet.getIndex();
154 for (
auto *readUser : arrayGet.getResult().getUsers()) {
155 if (
auto outputReg = dyn_cast<FirRegOp>(readUser)) {
156 if (outputReg.getClk() ==
pattern.clock) {
157 LLVM_DEBUG(llvm::dbgs()
158 <<
" Found output register: " << outputReg <<
"\n");
165 bool success =
pattern.readAccess !=
nullptr;
166 LLVM_DEBUG(llvm::dbgs() <<
" Pattern analysis "
167 << (success ?
"succeeded" :
"failed") <<
"\n");
171bool RegOfVecToMemPass::createFirMemory(MemoryPattern &
pattern) {
172 LLVM_DEBUG(llvm::dbgs() <<
"Creating FirMemory for pattern\n");
174 auto dims = getArrayDimensions(
pattern.memReg.getType());
178 uint64_t depth = dims->first;
179 uint64_t width = dims->second;
181 LLVM_DEBUG(llvm::dbgs() <<
" Memory dimensions: " << depth <<
" x " << width
184 ImplicitLocOpBuilder builder(
pattern.memReg.getLoc(),
pattern.memReg);
188 FirMemType::get(builder.getContext(), depth, width, 1);
189 auto firMem = seq::FirMemOp::create(
190 builder, memType, 0, 1,
193 builder.getStringAttr(
"mem"), hw::InnerSymAttr{},
194 seq::FirMemInitAttr{}, StringAttr{},
198 Value readData = FirMemReadOp::create(
202 LLVM_DEBUG(llvm::dbgs() <<
" Created read port\n"
203 << firMem <<
"\n " << readData);
207 FirMemWriteOp::create(builder, firMem,
pattern.writeAddr,
pattern.clock,
210 LLVM_DEBUG(llvm::dbgs() <<
" Created write port\n");
215 pattern.outputReg.getNext().replaceAllUsesWith(readData);
218 pattern.readAccess.getResult().replaceAllUsesWith(readData);
221 opsToErase.push_back(
pattern.memReg);
223 opsToErase.push_back(
pattern.readAccess);
225 opsToErase.push_back(
pattern.writeAccess);
227 opsToErase.push_back(
pattern.writeMux);
232void RegOfVecToMemPass::runOnOperation() {
233 auto module = getOperation();
235 SmallVector<FirRegOp> arrayRegs;
238 module.walk([&](FirRegOp reg) {
239 if (isArrayType(reg.getType())) {
240 arrayRegs.push_back(reg);
245 for (
auto reg : arrayRegs) {
253 for (
auto *op : opsToErase) {
254 LLVM_DEBUG(llvm::dbgs()
255 <<
"Erasing operation: " << *op <<
" number of uses:"
RewritePatternSet pattern
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)