CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
315 lines
10 KiB
C++
315 lines
10 KiB
C++
//===- TestIRVisitors.cpp - Pass to test the IR visitors ------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/IR/BuiltinOps.h"
|
|
#include "mlir/IR/Iterators.h"
|
|
#include "mlir/Interfaces/FunctionInterfaces.h"
|
|
#include "mlir/Pass/Pass.h"
|
|
|
|
using namespace mlir;
|
|
|
|
static void printRegion(Region *region) {
|
|
llvm::outs() << "region " << region->getRegionNumber() << " from operation '"
|
|
<< region->getParentOp()->getName() << "'";
|
|
}
|
|
|
|
static void printBlock(Block *block) {
|
|
llvm::outs() << "block ";
|
|
block->printAsOperand(llvm::outs(), /*printType=*/false);
|
|
llvm::outs() << " from ";
|
|
printRegion(block->getParent());
|
|
}
|
|
|
|
static void printOperation(Operation *op) {
|
|
llvm::outs() << "op '" << op->getName() << "'";
|
|
}
|
|
|
|
/// Tests pure callbacks.
|
|
static void testPureCallbacks(Operation *op) {
|
|
auto opPure = [](Operation *op) {
|
|
llvm::outs() << "Visiting ";
|
|
printOperation(op);
|
|
llvm::outs() << "\n";
|
|
};
|
|
auto blockPure = [](Block *block) {
|
|
llvm::outs() << "Visiting ";
|
|
printBlock(block);
|
|
llvm::outs() << "\n";
|
|
};
|
|
auto regionPure = [](Region *region) {
|
|
llvm::outs() << "Visiting ";
|
|
printRegion(region);
|
|
llvm::outs() << "\n";
|
|
};
|
|
|
|
llvm::outs() << "Op pre-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PreOrder>(opPure);
|
|
llvm::outs() << "Block pre-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PreOrder>(blockPure);
|
|
llvm::outs() << "Region pre-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PreOrder>(regionPure);
|
|
|
|
llvm::outs() << "Op post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder>(opPure);
|
|
llvm::outs() << "Block post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder>(blockPure);
|
|
llvm::outs() << "Region post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder>(regionPure);
|
|
|
|
llvm::outs() << "Op reverse post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder, ReverseIterator>(opPure);
|
|
llvm::outs() << "Block reverse post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder, ReverseIterator>(blockPure);
|
|
llvm::outs() << "Region reverse post-order visits"
|
|
<< "\n";
|
|
op->walk<WalkOrder::PostOrder, ReverseIterator>(regionPure);
|
|
|
|
// This test case tests "SkipGraphRegion = true", so start the walk with
|
|
// functions.
|
|
op->walk([&](FunctionOpInterface funcOp) {
|
|
llvm::outs() << "Op forward dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ForwardDominanceIterator</*SkipGraphRegion=*/true>>(opPure);
|
|
llvm::outs() << "Block forward dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ForwardDominanceIterator</*SkipGraphRegion=*/true>>(blockPure);
|
|
llvm::outs() << "Region forward dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ForwardDominanceIterator</*SkipGraphRegion=*/true>>(
|
|
regionPure);
|
|
|
|
llvm::outs() << "Op reverse dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ReverseDominanceIterator</*SkipGraphRegion=*/true>>(opPure);
|
|
llvm::outs() << "Block reverse dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ReverseDominanceIterator</*SkipGraphRegion=*/true>>(blockPure);
|
|
llvm::outs() << "Region reverse dominance post-order visits"
|
|
<< "\n";
|
|
funcOp->walk<WalkOrder::PostOrder,
|
|
ReverseDominanceIterator</*SkipGraphRegion=*/true>>(
|
|
regionPure);
|
|
});
|
|
}
|
|
|
|
/// Tests erasure callbacks that skip the walk.
|
|
static void testSkipErasureCallbacks(Operation *op) {
|
|
auto skipOpErasure = [](Operation *op) {
|
|
// Do not erase module and module children operations. Otherwise, there
|
|
// wouldn't be too much to test in pre-order.
|
|
if (isa<ModuleOp>(op) || isa<ModuleOp>(op->getParentOp()))
|
|
return WalkResult::advance();
|
|
|
|
llvm::outs() << "Erasing ";
|
|
printOperation(op);
|
|
llvm::outs() << "\n";
|
|
op->dropAllUses();
|
|
op->erase();
|
|
return WalkResult::skip();
|
|
};
|
|
auto skipBlockErasure = [](Block *block) {
|
|
// Do not erase module and module children blocks. Otherwise there wouldn't
|
|
// be too much to test in pre-order.
|
|
Operation *parentOp = block->getParentOp();
|
|
if (isa<ModuleOp>(parentOp) || isa<ModuleOp>(parentOp->getParentOp()))
|
|
return WalkResult::advance();
|
|
|
|
if (block->use_empty()) {
|
|
llvm::outs() << "Erasing ";
|
|
printBlock(block);
|
|
llvm::outs() << "\n";
|
|
block->erase();
|
|
return WalkResult::skip();
|
|
}
|
|
llvm::outs() << "Cannot erase ";
|
|
printBlock(block);
|
|
llvm::outs() << ", still has uses\n";
|
|
return WalkResult::advance();
|
|
|
|
};
|
|
|
|
llvm::outs() << "Op pre-order erasures (skip)"
|
|
<< "\n";
|
|
Operation *cloned = op->clone();
|
|
cloned->walk<WalkOrder::PreOrder>(skipOpErasure);
|
|
cloned->erase();
|
|
|
|
llvm::outs() << "Block pre-order erasures (skip)"
|
|
<< "\n";
|
|
cloned = op->clone();
|
|
cloned->walk<WalkOrder::PreOrder>(skipBlockErasure);
|
|
cloned->erase();
|
|
|
|
llvm::outs() << "Op post-order erasures (skip)"
|
|
<< "\n";
|
|
cloned = op->clone();
|
|
cloned->walk<WalkOrder::PostOrder>(skipOpErasure);
|
|
cloned->erase();
|
|
|
|
llvm::outs() << "Block post-order erasures (skip)"
|
|
<< "\n";
|
|
cloned = op->clone();
|
|
cloned->walk<WalkOrder::PostOrder>(skipBlockErasure);
|
|
cloned->erase();
|
|
}
|
|
|
|
/// Tests callbacks that erase the op or block but don't return 'Skip'. This
|
|
/// callbacks are only valid in post-order.
|
|
static void testNoSkipErasureCallbacks(Operation *op) {
|
|
auto noSkipOpErasure = [](Operation *op) {
|
|
llvm::outs() << "Erasing ";
|
|
printOperation(op);
|
|
llvm::outs() << "\n";
|
|
op->dropAllUses();
|
|
op->erase();
|
|
};
|
|
auto noSkipBlockErasure = [](Block *block) {
|
|
if (block->use_empty()) {
|
|
llvm::outs() << "Erasing ";
|
|
printBlock(block);
|
|
llvm::outs() << "\n";
|
|
|
|
// Only drop uses from operations within the same parent region. This
|
|
// avoids erasing operations with their uses still intact and eliminates
|
|
// such crashes.
|
|
// Note: We do not drop the use when the parent region is different for
|
|
// it, because this means that the use's region holding op is a child of
|
|
// the region holding op containing the current block and was expected to
|
|
// be visited and erased first - we should correctly fail here.
|
|
Region *blockParentRegion = block->getParent();
|
|
for (Operation &op : *block) {
|
|
for (OpOperand &use : llvm::make_early_inc_range(op.getUses())) {
|
|
// Early continue if the parent regions are not same.
|
|
if (blockParentRegion != use.getOwner()->getParentRegion())
|
|
continue;
|
|
use.drop();
|
|
}
|
|
}
|
|
|
|
// Also drop uses of block arguments that are consumed within the same
|
|
// region. This handles cases like function entry blocks whose arguments
|
|
// are used by ops in sibling blocks.
|
|
for (BlockArgument arg : block->getArguments()) {
|
|
for (OpOperand &use : llvm::make_early_inc_range(arg.getUses())) {
|
|
if (blockParentRegion != use.getOwner()->getParentRegion())
|
|
continue;
|
|
use.drop();
|
|
}
|
|
}
|
|
|
|
block->erase();
|
|
} else {
|
|
llvm::outs() << "Cannot erase ";
|
|
printBlock(block);
|
|
llvm::outs() << ", still has uses\n";
|
|
}
|
|
};
|
|
|
|
llvm::outs() << "Op post-order erasures (no skip)"
|
|
<< "\n";
|
|
Operation *cloned = op->clone();
|
|
cloned->walk<WalkOrder::PostOrder>(noSkipOpErasure);
|
|
|
|
llvm::outs() << "Block post-order erasures (no skip)"
|
|
<< "\n";
|
|
cloned = op->clone();
|
|
cloned->walk<WalkOrder::PostOrder>(noSkipBlockErasure);
|
|
cloned->erase();
|
|
}
|
|
|
|
/// Invoke region/block walks on regions/blocks.
|
|
static void testBlockAndRegionWalkers(Operation *op) {
|
|
auto blockPure = [](Block *block) {
|
|
llvm::outs() << "Visiting ";
|
|
printBlock(block);
|
|
llvm::outs() << "\n";
|
|
};
|
|
auto regionPure = [](Region *region) {
|
|
llvm::outs() << "Visiting ";
|
|
printRegion(region);
|
|
llvm::outs() << "\n";
|
|
};
|
|
|
|
llvm::outs() << "Invoke block pre-order visits on blocks\n";
|
|
op->walk([&](Operation *op) {
|
|
if (!op->hasAttr("walk_blocks"))
|
|
return;
|
|
for (Region ®ion : op->getRegions()) {
|
|
for (Block &block : region.getBlocks()) {
|
|
block.walk<WalkOrder::PreOrder>(blockPure);
|
|
}
|
|
}
|
|
});
|
|
|
|
llvm::outs() << "Invoke block post-order visits on blocks\n";
|
|
op->walk([&](Operation *op) {
|
|
if (!op->hasAttr("walk_blocks"))
|
|
return;
|
|
for (Region ®ion : op->getRegions()) {
|
|
for (Block &block : region.getBlocks()) {
|
|
block.walk<WalkOrder::PostOrder>(blockPure);
|
|
}
|
|
}
|
|
});
|
|
|
|
llvm::outs() << "Invoke region pre-order visits on region\n";
|
|
op->walk([&](Operation *op) {
|
|
if (!op->hasAttr("walk_regions"))
|
|
return;
|
|
for (Region ®ion : op->getRegions()) {
|
|
region.walk<WalkOrder::PreOrder>(regionPure);
|
|
}
|
|
});
|
|
|
|
llvm::outs() << "Invoke region post-order visits on region\n";
|
|
op->walk([&](Operation *op) {
|
|
if (!op->hasAttr("walk_regions"))
|
|
return;
|
|
for (Region ®ion : op->getRegions()) {
|
|
region.walk<WalkOrder::PostOrder>(regionPure);
|
|
}
|
|
});
|
|
}
|
|
|
|
namespace {
|
|
/// This pass exercises the different configurations of the IR visitors.
|
|
struct TestIRVisitorsPass
|
|
: public PassWrapper<TestIRVisitorsPass, OperationPass<>> {
|
|
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestIRVisitorsPass)
|
|
|
|
StringRef getArgument() const final { return "test-ir-visitors"; }
|
|
StringRef getDescription() const final { return "Test various visitors."; }
|
|
void runOnOperation() override {
|
|
Operation *op = getOperation();
|
|
testPureCallbacks(op);
|
|
testBlockAndRegionWalkers(op);
|
|
testSkipErasureCallbacks(op);
|
|
testNoSkipErasureCallbacks(op);
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
namespace mlir {
|
|
namespace test {
|
|
void registerTestIRVisitorsPass() { PassRegistration<TestIRVisitorsPass>(); }
|
|
} // namespace test
|
|
} // namespace mlir
|