17 #include "mlir/Transforms/DialectConversion.h"
19 using namespace circt;
24 struct ReblockPass :
public IbisReblockBase<ReblockPass> {
25 void runOnOperation()
override;
28 LogicalResult reblock(ArrayRef<Operation *> ops, Operation *blockTerminator);
31 SmallVector<Operation *> opsToErase;
36 static bool isSBlockTerminator(Operation *op) {
37 return op->hasTrait<OpTrait::IsTerminator>() ||
38 isa<ibis::InlineStaticBlockEndOp, InlineStaticBlockBeginOp>(op);
43 void ReblockPass::runOnOperation() {
44 MethodOp parent = getOperation();
46 llvm::SmallVector<Operation *> opsToBlock;
47 for (Block &block : parent.getRegion()) {
48 for (Operation &op : llvm::make_early_inc_range(block)) {
49 if (isSBlockTerminator(&op)) {
50 if (opsToBlock.empty())
52 if (failed(reblock(opsToBlock, &op)))
53 return signalPassFailure();
55 if (isa<InlineStaticBlockBeginOp>(op))
56 opsToBlock.push_back(&op);
58 opsToBlock.push_back(&op);
62 llvm::for_each(opsToErase, [](Operation *op) { op->erase(); });
65 LogicalResult ReblockPass::reblock(ArrayRef<Operation *> ops,
66 Operation *blockTerminator) {
70 ibis::InlineStaticBlockBeginOp blockBeginOp;
71 if (isa<InlineStaticBlockEndOp>(blockTerminator)) {
72 blockBeginOp = dyn_cast<InlineStaticBlockBeginOp>(ops.front());
74 "Expected block begin op when a block end block was provided");
75 ops = ops.drop_front();
78 Operation *beginOp = ops.front();
79 auto startIt = ops.front()->getIterator();
80 Operation *endOp = ops.back();
81 auto terminatorIt = blockTerminator->getIterator();
82 Block *sblockParentBlock = beginOp->getBlock();
84 auto usedOutsideBlock = [&](OpOperand &use) {
85 Operation *owner = use.getOwner();
86 Block *useBlock = owner->getBlock();
87 if (useBlock != sblockParentBlock)
89 bool isBefore = owner->isBeforeInBlock(beginOp);
90 bool isAfter = isBefore ? false : endOp->isBeforeInBlock(owner);
91 return isBefore || isAfter;
94 llvm::MapVector<Value, llvm::SmallVector<OpOperand *>> returnValueUses;
95 for (
auto &op : llvm::make_range(startIt, terminatorIt)) {
96 for (Value result : op.getResults()) {
97 for (OpOperand &use : result.getUses())
98 if (usedOutsideBlock(use))
99 returnValueUses[result].push_back(&use);
104 llvm::SmallVector<Type> blockRetTypes;
105 llvm::SmallVector<Value> blockRetValues;
106 for (
auto &[v, _] : returnValueUses) {
107 blockRetTypes.push_back(v.getType());
108 blockRetValues.push_back(v);
111 auto b = OpBuilder(beginOp);
113 b.create<StaticBlockOp>(beginOp->getLoc(), blockRetTypes, ValueRange{});
118 ibisBlock->setAttrs(blockBeginOp->getAttrs());
121 BlockReturnOp blockReturn =
122 cast<BlockReturnOp>(ibisBlock.getBodyBlock()->getTerminator());
125 llvm::make_early_inc_range(llvm::make_range(startIt, terminatorIt)))
126 op.moveBefore(blockReturn);
129 blockReturn->setOperands(blockRetValues);
133 for (
auto [blockRet, innerDefAndUses] :
134 llvm::zip(ibisBlock.getResults(), returnValueUses)) {
135 auto &uses = std::get<1>(innerDefAndUses);
136 for (OpOperand *use : uses)
142 opsToErase.push_back(blockBeginOp);
143 opsToErase.push_back(blockTerminator);
150 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.