15#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
16#include "mlir/IR/PatternMatch.h"
17#include "mlir/IR/Visitors.h"
18#include "mlir/Pass/Pass.h"
19#include "llvm/Support/Debug.h"
21#define DEBUG_TYPE "llhd-process-lowering"
25#define GEN_PASS_DEF_PROCESSLOWERING
26#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h.inc"
35struct ProcessLoweringPass
36 :
public circt::llhd::impl::ProcessLoweringBase<ProcessLoweringPass> {
37 void runOnOperation()
override;
40static LogicalResult isProcValidToLower(llhd::ProcessOp op) {
41 if (op.getBody().getBlocks().size() != 2) {
43 llvm::dbgs() <<
"process-lowering only supports processes with "
44 "two basic blocks where the first "
45 "contains a 'cf.br' terminator and the second one is "
46 "terminated by a 'llhd.wait' operation\n";
51 Block &first = op.getBody().front();
52 Block &last = op.getBody().back();
54 if (!last.getArguments().empty()) {
56 llvm::dbgs() <<
"the second block (containing the "
57 "llhd.wait) is not allowed to have arguments\n";
62 if (!isa<cf::BranchOp>(first.getTerminator())) {
64 llvm::dbgs() <<
"the first block has to "
65 "be terminated by a cf.br operation\n";
70 if (
auto wait = dyn_cast<llhd::WaitOp>(last.getTerminator())) {
74 llvm::dbgs() <<
"llhd.wait terminators with optional time "
75 "argument cannot be lowered to structural LLHD\n";
80 SmallVector<Value> observedSignals;
81 for (Value obs : wait.getObserved())
82 if (auto prb = obs.getDefiningOp<llhd::PrbOp>())
83 if (!op.getBody().
isAncestor(prb->getParentRegion()))
84 observedSignals.push_back(prb.getSignal());
88 WalkResult result = op.walk([&](Operation *operation) -> WalkResult {
91 for (Value operand : operation->getOperands()) {
92 if (op.getBody().isAncestor(operand.getParentRegion()))
94 if (llvm::is_contained(wait.getObserved(), operand))
96 if (llvm::is_contained(observedSignals, operand))
98 if (
auto *defOp = operand.getDefiningOp();
99 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
102 if (
auto *defOp = bitcastOp.getInput().getDefiningOp();
103 defOp && defOp->hasTrait<OpTrait::ConstantLike>())
107 llvm::dbgs() <<
"the wait terminator is required to "
108 "have values used in the process as arguments\n";
113 return WalkResult::advance();
116 return failure(result.wasInterrupted());
120 llvm::dbgs() <<
"the second block must be "
121 "terminated by llhd.wait\n";
126void ProcessLoweringPass::runOnOperation() {
127 ModuleOp
module = getOperation();
129 module.walk([](llhd::ProcessOp op) {
130 LLVM_DEBUG({ llvm::dbgs() << "\n=== Process\n"; });
132 if (failed(isProcValidToLower(op)))
138 if (op.getBody().getBlocks().size() == 2) {
139 Block &first = op.getBody().front();
140 Block &second = op.getBody().back();
142 first.getTerminator()->erase();
144 first.getOperations().splice(first.end(), second.getOperations());
146 second.dropAllReferences();
147 second.dropAllDefinedValueUses();
152 op.getBody().front().getTerminator()->erase();
154 IRRewriter rewriter(op);
155 rewriter.inlineBlockBefore(&op.getBody().front(), op);
158 LLVM_DEBUG({ llvm::dbgs() <<
"Process lowered successfully!\n"; });
static bool isAncestor(Block *block, Block *other)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.