11 #include "mlir/Pass/Pass.h"
19 #include "mlir/Transforms/DialectConversion.h"
23 #define GEN_PASS_DEF_IBISREBLOCK
24 #include "circt/Dialect/Ibis/IbisPasses.h.inc"
28 using namespace circt;
33 struct ReblockPass :
public circt::ibis::impl::IbisReblockBase<ReblockPass> {
34 void runOnOperation()
override;
37 LogicalResult reblock(ArrayRef<Operation *> ops, Operation *blockTerminator);
40 SmallVector<Operation *> opsToErase;
45 static bool isSBlockTerminator(Operation *op) {
46 return op->hasTrait<OpTrait::IsTerminator>() ||
47 isa<ibis::InlineStaticBlockEndOp, InlineStaticBlockBeginOp>(op);
52 void ReblockPass::runOnOperation() {
53 MethodOp parent = getOperation();
55 llvm::SmallVector<Operation *> opsToBlock;
56 for (Block &block : parent.getRegion()) {
57 for (Operation &op : llvm::make_early_inc_range(block)) {
58 if (isSBlockTerminator(&op)) {
59 if (opsToBlock.empty())
61 if (failed(reblock(opsToBlock, &op)))
62 return signalPassFailure();
64 if (isa<InlineStaticBlockBeginOp>(op))
65 opsToBlock.push_back(&op);
67 opsToBlock.push_back(&op);
71 llvm::for_each(opsToErase, [](Operation *op) { op->erase(); });
74 LogicalResult ReblockPass::reblock(ArrayRef<Operation *> ops,
75 Operation *blockTerminator) {
79 ibis::InlineStaticBlockBeginOp blockBeginOp;
80 if (isa<InlineStaticBlockEndOp>(blockTerminator)) {
81 blockBeginOp = dyn_cast<InlineStaticBlockBeginOp>(ops.front());
83 "Expected block begin op when a block end block was provided");
84 ops = ops.drop_front();
87 Operation *beginOp = ops.front();
88 auto startIt = ops.front()->getIterator();
89 Operation *endOp = ops.back();
90 auto terminatorIt = blockTerminator->getIterator();
91 Block *sblockParentBlock = beginOp->getBlock();
93 auto usedOutsideBlock = [&](OpOperand &use) {
94 Operation *owner = use.getOwner();
95 Block *useBlock = owner->getBlock();
96 if (useBlock != sblockParentBlock)
98 bool isBefore = owner->isBeforeInBlock(beginOp);
99 bool isAfter = isBefore ? false : endOp->isBeforeInBlock(owner);
100 return isBefore || isAfter;
103 llvm::MapVector<Value, llvm::SmallVector<OpOperand *>> returnValueUses;
104 for (
auto &op : llvm::make_range(startIt, terminatorIt)) {
105 for (Value result : op.getResults()) {
106 for (OpOperand &use : result.getUses())
107 if (usedOutsideBlock(use))
108 returnValueUses[result].push_back(&use);
113 llvm::SmallVector<Type> blockRetTypes;
114 llvm::SmallVector<Value> blockRetValues;
115 for (
auto &[v, _] : returnValueUses) {
116 blockRetTypes.push_back(v.getType());
117 blockRetValues.push_back(v);
120 auto b = OpBuilder(beginOp);
122 b.create<StaticBlockOp>(beginOp->getLoc(), blockRetTypes, ValueRange{});
127 ibisBlock->setAttrs(blockBeginOp->getAttrs());
130 BlockReturnOp blockReturn =
131 cast<BlockReturnOp>(ibisBlock.getBodyBlock()->getTerminator());
134 llvm::make_early_inc_range(llvm::make_range(startIt, terminatorIt)))
135 op.moveBefore(blockReturn);
138 blockReturn->setOperands(blockRetValues);
142 for (
auto [blockRet, innerDefAndUses] :
143 llvm::zip(ibisBlock.getResults(), returnValueUses)) {
144 auto &uses = std::get<1>(innerDefAndUses);
145 for (OpOperand *use : uses)
151 opsToErase.push_back(blockBeginOp);
152 opsToErase.push_back(blockTerminator);
159 return std::make_unique<ReblockPass>();
assert(baseType &&"element must be base type")
std::unique_ptr< mlir::Pass > createReblockPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.