[Mlir-commits] [mlir] [mlir][XeGPU][Transform] Add gather/scatter coalescing analysis. (PR #201684)
Jianhui Li
llvmlistbot at llvm.org
Wed Jun 24 20:02:54 PDT 2026
================
@@ -446,6 +450,195 @@ struct TestXeGPULayoutInterface
}
};
+struct TestXeGPUCoalesceGatherScatter
+ : public PassWrapper<TestXeGPUCoalesceGatherScatter, OperationPass<>> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestXeGPUCoalesceGatherScatter)
+
+ StringRef getArgument() const final {
+ return "test-xegpu-coalesce-gather-scatter";
+ }
+
+ StringRef getDescription() const final {
+ return "Test the XeGPU contiguity analysis and its coalescing consumer.";
+ }
+
+ void getDependentDialects(::mlir::DialectRegistry ®istry) const override {
+ registry.insert<arith::ArithDialect>();
+ registry.insert<vector::VectorDialect>();
+ registry.insert<xegpu::XeGPUDialect>();
+ }
+
+ TestXeGPUCoalesceGatherScatter() = default;
+ TestXeGPUCoalesceGatherScatter(const TestXeGPUCoalesceGatherScatter &pass)
+ : PassWrapper(pass) {}
+
+ Option<unsigned> maxChunkSize{
+ *this, "max-chunk-size",
+ llvm::cl::desc("Upper bound on the produced lane_data FCD."),
+ llvm::cl::init(8)};
+
+ Option<bool> analyzeOnly{
+ *this, "analyze-only",
+ llvm::cl::desc("Only run the analysis (stamp contiguous_chunk "
+ "attributes); do not apply."),
+ llvm::cl::init(false)};
+
+ void runOnOperation() override {
+ xegpu::runCoalesceGatherScatterAnalysis(getOperation());
+ if (analyzeOnly)
+ return;
+ getOperation()->walk([&](Operation *op) {
+ if (auto load = dyn_cast<xegpu::LoadGatherOp>(op))
+ applyContiguousChunk(load, maxChunkSize);
+ else if (auto store = dyn_cast<xegpu::StoreScatterOp>(op))
+ applyContiguousChunk(store, maxChunkSize);
+ });
+ }
+
+private:
+ /// Largest power-of-two `<= bound` that divides `numLanes`.
+ static int64_t largestPow2Divisor(int64_t numLanes, int64_t bound) {
+ if (bound < 2 || numLanes < 2)
+ return 1;
+ int64_t f = std::min<int64_t>(bound, numLanes);
+ // Round down to power of 2.
+ if (!llvm::isPowerOf2_64(f))
+ f = static_cast<int64_t>(llvm::bit_floor(static_cast<uint64_t>(f)));
+ while (f >= 2) {
+ if (numLanes % f == 0)
+ return f;
+ f /= 2;
+ }
+ return 1;
+ }
+
+ /// Look up the subgroup size from the enclosing gpu.module's xevm.target.
+ /// Falls back to 16 when no target chip is found or the chip is unknown,
+ /// matching the typical Intel Xe2 default.
+ static unsigned lookupSubgroupSize(Operation *op) {
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
+ return uArch ? static_cast<unsigned>(uArch->getSubgroupSize()) : 16u;
----------------
Jianhui-Li wrote:
why 16u in case of no uArch? In layout propagation, in case of no uArch info, we exit the pass.
The abstraction/utility here has little value (just 2 lines) and encode different behavior, why not just copy paste the code pattern?
https://github.com/llvm/llvm-project/pull/201684
More information about the Mlir-commits
mailing list