15 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
16 #include "mlir/Dialect/Func/IR/FuncOps.h"
17 #include "mlir/IR/Dominance.h"
18 #include "mlir/Pass/Pass.h"
23 #define GEN_PASS_DEF_MEMORYTOBLOCKARGUMENT
24 #include "circt/Dialect/LLHD/Transforms/Passes.h.inc"
28 using namespace circt;
31 struct MemoryToBlockArgumentPass
32 :
public circt::llhd::impl::MemoryToBlockArgumentBase<
33 MemoryToBlockArgumentPass> {
34 void runOnOperation()
override;
35 void runOnProcess(llhd::ProcessOp operation);
42 std::set<Block *> &df) {
43 mlir::DominanceInfo dom(op);
44 for (Block &block : op->getRegion(0).getBlocks()) {
45 for (Block *pred : block.getPredecessors()) {
46 if (dom.dominates(frontierOf, pred) &&
47 !dom.properlyDominates(frontierOf, &block) &&
48 block.getOps<llhd::VarOp>().empty()) {
57 static void getDFClosure(SmallVectorImpl<Block *> &initialSet, Operation *op,
58 std::set<Block *> &closure) {
60 for (Block *block : initialSet) {
65 for (Block *block : closure) {
75 Block *successsor, Value toAppend) {
76 if (
auto wait = dyn_cast<llhd::WaitOp>(terminator)) {
77 wait.getDestOpsMutable().append(toAppend);
78 }
else if (
auto br = dyn_cast<mlir::cf::BranchOp>(terminator)) {
79 br.getDestOperandsMutable().append(toAppend);
80 }
else if (
auto condBr = dyn_cast<mlir::cf::CondBranchOp>(terminator)) {
81 if (condBr.getFalseDest() == successsor) {
82 condBr.getFalseDestOperandsMutable().append(toAppend);
84 condBr.getTrueDestOperandsMutable().append(toAppend);
87 llvm_unreachable(
"unsupported terminator op");
91 void MemoryToBlockArgumentPass::runOnOperation() {
92 for (
auto proc : getOperation().getOps<llhd::ProcessOp>())
96 void MemoryToBlockArgumentPass::runOnProcess(llhd::ProcessOp operation) {
97 OpBuilder builder(operation);
101 WalkResult result = operation.getBody().walk([](Operation *op) -> WalkResult {
102 if (op->getNumRegions() > 0 &&
103 !op->hasTrait<OpTrait::IsIsolatedFromAbove>())
104 return WalkResult::interrupt();
105 return WalkResult::advance();
107 if (result.wasInterrupted())
113 SmallVector<Value, 16> vars(operation->getRegion(0).getOps<llhd::VarOp>());
117 for (
auto *var = vars.begin(); var != vars.end(); ++var) {
118 for (Operation *user : var->getUsers()) {
119 if (!isa<llhd::LoadOp>(user) && !isa<llhd::StoreOp>(user)) {
127 for (Value var : vars) {
128 SmallVector<Block *, 16> defBlocks;
130 var.getDefiningOp<llhd::VarOp>().getOperation()->getBlock());
131 operation->walk([&](llhd::StoreOp op) {
132 if (op.getPointer() == var)
133 defBlocks.push_back(op.getOperation()->getBlock());
136 std::sort(defBlocks.begin(), defBlocks.end());
137 defBlocks.erase(std::unique(defBlocks.begin(), defBlocks.end()),
141 std::set<Block *> joinPoints;
144 for (Block *jp : joinPoints) {
146 BlockArgument phi = jp->addArgument(
147 cast<llhd::PtrType>(var.getType()).getElementType(), var.getLoc());
151 for (Block *pred : jp->getPredecessors()) {
153 builder.setInsertionPoint(pred->getTerminator());
154 Value load = builder.create<llhd::LoadOp>(
155 pred->getTerminator()->getLoc(),
156 cast<llhd::PtrType>(var.getType()).getElementType(), var);
162 builder.setInsertionPointToStart(jp);
163 builder.create<llhd::StoreOp>(jp->front().getLoc(), var, phi);
168 DenseMap<Block *, Value> outputMap;
169 SmallPtrSet<Block *, 32> workQueue;
170 SmallPtrSet<Block *, 32> workDone;
172 workQueue.insert(&operation->getRegion(0).front());
174 while (!workQueue.empty()) {
176 Block *block = *workQueue.begin();
177 workQueue.erase(block);
180 Value currStoredValue;
184 for (Block *pred : block->getPredecessors()) {
192 if (!currStoredValue && outputMap.count(pred)) {
193 currStoredValue = outputMap[pred];
199 for (
auto op = block->begin(); op != block->end(); ++op) {
202 if (
auto store = dyn_cast<llhd::StoreOp>(op)) {
203 if (store.getPointer() == var) {
204 currStoredValue = store.getValue();
206 store.getOperation()->dropAllReferences();
212 }
else if (
auto varOp = dyn_cast<llhd::VarOp>(op)) {
213 if (varOp.getResult() == var)
214 currStoredValue = varOp.getInit();
218 }
else if (
auto load = dyn_cast<llhd::LoadOp>(op)) {
219 if (load.getPointer() == var && currStoredValue) {
221 load.getResult().replaceAllUsesWith(currStoredValue);
222 load.getOperation()->dropAllReferences();
229 outputMap.insert(std::make_pair(block, currStoredValue));
231 workDone.insert(block);
235 for (Block *succ : block->getSuccessors()) {
236 if (!workDone.count(succ))
237 workQueue.insert(succ);
244 for (Value var : vars) {
245 Operation *op = var.getDefiningOp();
246 op->dropAllDefinedValueUses();
247 op->dropAllReferences();
252 std::unique_ptr<OperationPass<hw::HWModuleOp>>
254 return std::make_unique<MemoryToBlockArgumentPass>();
MlirType uint64_t numElements
static void addBlockOperandToTerminator(Operation *terminator, Block *successsor, Value toAppend)
Add a block argument to a given terminator.
static void getDominanceFrontier(Block *frontierOf, Operation *op, std::set< Block * > &df)
Add the dominance fontier blocks of 'frontierOf' to the 'df' set.
static void getDFClosure(SmallVectorImpl< Block * > &initialSet, Operation *op, std::set< Block * > &closure)
Add the blocks in the closure of the dominance fontier relation of all the block in 'initialSet' to '...
std::unique_ptr< OperationPass< hw::HWModuleOp > > createMemoryToBlockArgumentPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.