[Mlir-commits] [mlir] [MLIR][XeGPU] Enable `isa<>` check for uarch (PR #204577)
Artem Kroviakov
llvmlistbot at llvm.org
Thu Jun 25 06:22:48 PDT 2026
https://github.com/akroviakov updated https://github.com/llvm/llvm-project/pull/204577
>From a615e5f8fcbba5cf88afe4b633abef4972535832 Mon Sep 17 00:00:00 2001
From: Artem Kroviakov <artem.kroviakov at intel.com>
Date: Thu, 18 Jun 2026 12:28:30 +0000
Subject: [PATCH 1/5] [MLIR][XeGPU] Enable isa<> check for uarch
---
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h | 26 +++++-----
.../mlir/Dialect/XeGPU/uArch/uArchBase.h | 47 ++++++++++++++++---
mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp | 4 +-
3 files changed, 54 insertions(+), 23 deletions(-)
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
index ff80a77b28d37..46747af25c38e 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
@@ -31,13 +31,17 @@ namespace xegpu {
namespace uArch {
struct Xe2Plus : public uArch {
- Xe2Plus(StringRef archName, StringRef archDescription,
- llvm::ArrayRef<const Instruction *> instructionRegistry,
+ Xe2Plus(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
const XeCoreInfo &xeCore)
- : uArch(archName, archDescription, instructionRegistry), xeCore(xeCore) {}
+ : uArch(kind, instructionRegistry), xeCore(xeCore) {}
int getSubgroupSize() const override { return 16; }
unsigned getGeneralPackedFormatBitSize() const override { return 32; }
+ static bool classof(const uArch *u) {
+ return u->getKind() >= Kind::Xe2Plus_First &&
+ u->getKind() <= Kind::Xe2Plus_Last;
+ }
+
protected:
XeCoreInfo xeCore;
};
@@ -315,11 +319,10 @@ struct PVCuArch final : public Xe2Plus {
}
PVCuArch()
- : Xe2Plus("pvc", // archName
- "Ponte Vecchio Architecture", // archDescription
- getInstructionRegistryArr(),
+ : Xe2Plus(Kind::PVC, getInstructionRegistryArr(),
XeCoreInfo(8, SharedMemory(512 * 1024, 4), 8, 8) // xeCore
) {}
+ static bool classof(const uArch *u) { return u->getKind() == Kind::PVC; }
static const uArch *getInstance() {
static const PVCuArch instance;
return reinterpret_cast<const uArch *>(&instance);
@@ -341,11 +344,10 @@ struct BMGuArch : public Xe2Plus {
}
BMGuArch()
- : Xe2Plus("bmg", // archName
- "Battlemage Architecture", // archDescription
- getInstructionRegistryArr(),
+ : Xe2Plus(Kind::BMG, getInstructionRegistryArr(),
XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
) {}
+ static bool classof(const uArch *u) { return u->getKind() == Kind::BMG; }
static const uArch *getInstance() {
static const BMGuArch instance;
return reinterpret_cast<const uArch *>(&instance);
@@ -368,13 +370,12 @@ struct CRIuArch : public Xe2Plus {
}
CRIuArch()
- : Xe2Plus("cri", // archName
- "Crescent Island Architecture", // archDescription
- getInstructionRegistryArr(),
+ : Xe2Plus(Kind::CRI, getInstructionRegistryArr(),
// Using bmg config as placeholder
// TODO: Update to actual XeCore and SharedMemory config
XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
) {}
+ static bool classof(const uArch *u) { return u->getKind() == Kind::CRI; }
static const uArch *getInstance() {
static const CRIuArch instance;
return reinterpret_cast<const uArch *>(&instance);
@@ -390,7 +391,6 @@ inline const uArch *getUArch(llvm::StringRef archName) {
return CRIuArch::getInstance();
return nullptr;
}
-
} // namespace uArch
} // namespace xegpu
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
index 61db4605e85fa..1702c7b46e0eb 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
@@ -25,6 +25,7 @@
#include "mlir/IR/Types.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
namespace mlir {
namespace xegpu {
@@ -153,16 +154,49 @@ struct CacheInfo {
};
struct uArch {
+ enum class Kind {
+ // Xe2 family
+ Xe2Plus_First,
+ PVC = Xe2Plus_First,
+ BMG,
+ CRI,
+ Xe2Plus_Last = CRI,
+ };
+
// Constructor
- uArch(StringRef name, StringRef description,
- llvm::ArrayRef<const Instruction *> instructionRegistry)
- : name(name), description(description) {
+ uArch(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry)
+ : kind(kind) {
for (const Instruction *instr : instructionRegistry)
this->instructionRegistry[instr->getInstructionKind()] = instr;
}
virtual ~uArch() = default;
- StringRef getName() const { return name; }
- StringRef getDescription() const { return description; }
+ Kind getKind() const { return kind; }
+ StringRef getName() const { return getUArchName(kind); }
+ StringRef getDescription() const { return getUArchDescription(kind); }
+
+ static StringRef getUArchName(Kind k) {
+ switch (k) {
+ case Kind::PVC:
+ return "pvc";
+ case Kind::BMG:
+ return "bmg";
+ case Kind::CRI:
+ return "cri";
+ }
+ llvm_unreachable("Unknown uArch::Kind");
+ }
+
+ static StringRef getUArchDescription(Kind k) {
+ switch (k) {
+ case Kind::PVC:
+ return "Ponte Vecchio Architecture";
+ case Kind::BMG:
+ return "Battlemage Architecture";
+ case Kind::CRI:
+ return "Crescent Island Architecture";
+ }
+ llvm_unreachable("Unknown uArch::Kind");
+ }
virtual int getSubgroupSize() const = 0;
virtual unsigned getGeneralPackedFormatBitSize() const = 0;
@@ -178,8 +212,7 @@ struct uArch {
}
protected:
- StringRef name;
- StringRef description;
+ Kind kind;
llvm::SmallDenseMap<InstructionKind, const Instruction *, 32>
instructionRegistry;
};
diff --git a/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp b/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
index 735dd93e2ac14..24999f85c1268 100644
--- a/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
+++ b/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
@@ -786,9 +786,7 @@ bool xegpu::requireTranspose(const xegpu::DistributeLayoutAttr layout,
const xegpu::uArch::uArch *uArch) {
// Return false for unsupported targets.
// TODO: Add more support or move to target info.
- if (uArch->getName().equals_insensitive("pvc") &&
- uArch->getName().equals_insensitive("bmg") &&
- uArch->getName().equals_insensitive("cri"))
+ if (!isa<xegpu::uArch::Xe2Plus>(uArch))
return false;
if (!layout)
return false;
>From 6101a6fd410ccb3057041c83bfb44cf1e90d989e Mon Sep 17 00:00:00 2001
From: Artem Kroviakov <artem.kroviakov at intel.com>
Date: Thu, 18 Jun 2026 16:49:42 +0000
Subject: [PATCH 2/5] Split to Xe2 and Xe3
---
.../XeGPU/Transforms/XeGPULayoutImpl.h | 2 +-
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h | 66 +-
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h | 603 ++++++++++++++++++
.../mlir/Dialect/XeGPU/uArch/uArchBase.h | 20 +-
.../mlir/Dialect/XeGPU/uArch/uArchCommon.h | 38 ++
.../Conversion/XeGPUToXeVM/XeGPUToXeVM.cpp | 2 +-
mlir/lib/Dialect/XeGPU/IR/XeGPUDialect.cpp | 2 +-
.../XeGPUArrayLengthOptimization.cpp | 2 +-
.../Transforms/XeGPUPeepHoleOptimizer.cpp | 2 +-
.../XeGPU/Transforms/XeGPUPropagateLayout.cpp | 2 +-
.../Transforms/XeGPUSgToLaneDistribute.cpp | 2 +-
mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp | 4 +-
12 files changed, 676 insertions(+), 69 deletions(-)
create mode 100644 mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
create mode 100644 mlir/include/mlir/Dialect/XeGPU/uArch/uArchCommon.h
diff --git a/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h b/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
index bf61f0ced6048..027a70d9579ab 100644
--- a/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
+++ b/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
@@ -11,7 +11,7 @@
#include "mlir/Dialect/XeGPU/IR/XeGPU.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
index 46747af25c38e..ed8ae5289882a 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
@@ -30,16 +30,15 @@ namespace mlir {
namespace xegpu {
namespace uArch {
-struct Xe2Plus : public uArch {
- Xe2Plus(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
- const XeCoreInfo &xeCore)
+struct Xe2 : public uArch {
+ Xe2(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
+ const XeCoreInfo &xeCore)
: uArch(kind, instructionRegistry), xeCore(xeCore) {}
int getSubgroupSize() const override { return 16; }
unsigned getGeneralPackedFormatBitSize() const override { return 32; }
static bool classof(const uArch *u) {
- return u->getKind() >= Kind::Xe2Plus_First &&
- u->getKind() <= Kind::Xe2Plus_Last;
+ return u->getKind() >= Kind::Xe2_First && u->getKind() <= Kind::Xe2_Last;
}
protected:
@@ -292,19 +291,11 @@ struct SubgroupScaledMatrixMultiplyAcc : public Instruction,
const unsigned packedFormatBitSizeB;
};
-struct SpirvLoadGatherInstruction : public LoadGatherInstructionInterface {
- int32_t getMaxLaneLoadSize(int32_t bitWidth) const override { return 16; }
-};
-
-struct SpirvStoreScatterInstruction : public StoreScatterInstructionInterface {
- int32_t getMaxLaneStoreSize(int32_t bitWidth) const override { return 16; }
-};
-
//===----------------------------------------------------------------------===//
// uArch instances
//===----------------------------------------------------------------------===//
-struct PVCuArch final : public Xe2Plus {
+struct PVCuArch final : public Xe2 {
static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
static const Subgroup2DBlockLoadInstruction loadNdInst;
@@ -319,8 +310,8 @@ struct PVCuArch final : public Xe2Plus {
}
PVCuArch()
- : Xe2Plus(Kind::PVC, getInstructionRegistryArr(),
- XeCoreInfo(8, SharedMemory(512 * 1024, 4), 8, 8) // xeCore
+ : Xe2(Kind::PVC, getInstructionRegistryArr(),
+ XeCoreInfo(8, SharedMemory(512 * 1024, 4), 8, 8) // xeCore
) {}
static bool classof(const uArch *u) { return u->getKind() == Kind::PVC; }
static const uArch *getInstance() {
@@ -329,7 +320,7 @@ struct PVCuArch final : public Xe2Plus {
}
};
-struct BMGuArch : public Xe2Plus {
+struct BMGuArch : public Xe2 {
static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
static const Subgroup2DBlockLoadInstruction loadNdInst;
@@ -344,8 +335,8 @@ struct BMGuArch : public Xe2Plus {
}
BMGuArch()
- : Xe2Plus(Kind::BMG, getInstructionRegistryArr(),
- XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
+ : Xe2(Kind::BMG, getInstructionRegistryArr(),
+ XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
) {}
static bool classof(const uArch *u) { return u->getKind() == Kind::BMG; }
static const uArch *getInstance() {
@@ -354,43 +345,6 @@ struct BMGuArch : public Xe2Plus {
}
};
-struct CRIuArch : public Xe2Plus {
- static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
- static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
- static const SubgroupScaledMatrixMultiplyAcc dpasMxInst{16, 32};
- static const Subgroup2DBlockLoadInstruction loadNdInst;
- static const Subgroup2DBlockStoreInstruction storeNdInst;
- static const Subgroup2DBlockPrefetchInstruction prefetchNdInst;
- static const SpirvStoreScatterInstruction storeScatterInst;
- static const SpirvLoadGatherInstruction loadGatherInst;
- static const Instruction *arr[] = {
- &dpasInst, &dpasMxInst, &loadNdInst, &storeNdInst,
- &prefetchNdInst, &storeScatterInst, &loadGatherInst};
- return arr;
- }
-
- CRIuArch()
- : Xe2Plus(Kind::CRI, getInstructionRegistryArr(),
- // Using bmg config as placeholder
- // TODO: Update to actual XeCore and SharedMemory config
- XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
- ) {}
- static bool classof(const uArch *u) { return u->getKind() == Kind::CRI; }
- static const uArch *getInstance() {
- static const CRIuArch instance;
- return reinterpret_cast<const uArch *>(&instance);
- }
-};
-
-inline const uArch *getUArch(llvm::StringRef archName) {
- if (archName.equals_insensitive("pvc"))
- return PVCuArch::getInstance();
- if (archName.equals_insensitive("bmg"))
- return BMGuArch::getInstance();
- if (archName.equals_insensitive("cri"))
- return CRIuArch::getInstance();
- return nullptr;
-}
} // namespace uArch
} // namespace xegpu
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
new file mode 100644
index 0000000000000..a831196d2a8df
--- /dev/null
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
@@ -0,0 +1,603 @@
+//===--- IntelGpuXe3.h ------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// Xe2 uArch definition. Xe3 is the second generation of Intel Xe GPUs.
+// This file defines the uArch details for Xe3 and its derived architectures.
+// This includes Crescent Island Architecture.
+//
+//===----------------------------------------------------------------------===//
+#ifndef MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
+#define MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
+
+#include "mlir/Dialect/XeGPU/uArch/uArchBase.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/TypeUtilities.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DebugLog.h"
+#include <map>
+#include <string>
+
+using namespace mlir;
+using namespace mlir::xegpu::uArch;
+
+namespace mlir {
+namespace xegpu {
+namespace uArch {
+
+struct Xe3 : public uArch {
+ Xe3(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
+ const XeCoreInfo &xeCore)
+ : uArch(kind, instructionRegistry), xeCore(xeCore) {}
+ int getSubgroupSize() const override { return 16; }
+ unsigned getGeneralPackedFormatBitSize() const override { return 32; }
+
+ static bool classof(const uArch *u) {
+ return u->getKind() >= Kind::Xe3_First && u->getKind() <= Kind::Xe3_Last;
+ }
+
+protected:
+ XeCoreInfo xeCore;
+};
+
+//===----------------------------------------------------------------------===//
+// uArch instructions
+//===----------------------------------------------------------------------===//
+struct CriSubgroup2DBlockStoreInstruction : public Instruction {
+ CriSubgroup2DBlockStoreInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockStore,
+ InstructionScope::Subgroup) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockStore;
+ }
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
+ std::optional<
+ std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
+ getBlockWidthHeightCount(Type elemTy) const {
+ const static int kHeight[] = {1, 2, 4, 8};
+ const static int kWidth16[] = {16};
+ const static int kWidth32[] = {16};
+ const static int kCount[] = {1};
+ const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
+ if (elemByteSize == 1)
+ return std::make_tuple(llvm::ArrayRef<int>(kWidth32),
+ llvm::ArrayRef<int>(kHeight),
+ llvm::ArrayRef<int>(kCount));
+ else if (elemByteSize == 2 || elemByteSize == 4)
+ return std::make_tuple(llvm::ArrayRef<int>(kWidth16),
+ llvm::ArrayRef<int>(kHeight),
+ llvm::ArrayRef<int>(kCount));
+ return std::nullopt;
+ }
+
+ int32_t getPackedFormatBitSize() const { return 16; }
+};
+
+struct CriSubgroup2DBlockLoadInstruction : public Instruction {
+ CriSubgroup2DBlockLoadInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockLoad,
+ InstructionScope::Subgroup) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockLoad;
+ }
+
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
+ std::optional<
+ std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
+ getBlockWidthHeightCount(Type elemTy, bool hasTransform, bool hasTranspose,
+ bool upConv = false) const {
+ static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
+ static const int kHeightAtLeast8[] = {8, 16, 32};
+ static const int kHeightAtLeast16[] = {16, 32};
+ static const int kHeightAtLeast32[] = {32};
+
+ static const int kWidth32[] = {32};
+ static const int kWidth16[] = {16};
+ static const int kWidth8[] = {8};
+
+ static const int32_t kCount1[] = {1};
+ static const int32_t kCount2[] = {1, 2};
+ static const int32_t kCount4[] = {1, 2, 4};
+ static const int32_t kCount4Only[] = {4};
+ // (elemBytes, transform, transpose, upConvert)
+ using Key = std::tuple<int, uint8_t, uint8_t, uint8_t>;
+ // (widths, heights, counts)
+ using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
+ llvm::ArrayRef<int32_t>>;
+ static const llvm::DenseMap<Key, Value> kMap = {
+ {{1, false, false, false}, {kWidth32, kHeightAtLeast1, kCount2}},
+ {{1, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
+ {{2, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
+ {{4, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
+ // Block Loads with Transform:
+ {{1, true, false, false}, {kWidth16, kHeightAtLeast32, kCount4}},
+ {{2, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
+ // Block Loads with Transpose:
+ {{4, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
+ };
+ const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
+ auto it = kMap.find({elemByteSize, hasTransform, hasTranspose, upConv});
+ if (it != kMap.end())
+ return it->second;
+ return std::nullopt;
+ }
+
+ int32_t getPackedFormatBitSize() const { return 16; }
+};
+
+struct CriSubgroup2DBlockPrefetchInstruction : public Instruction {
+ CriSubgroup2DBlockPrefetchInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockPrefetch,
+ InstructionScope::Subgroup) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockPrefetch;
+ }
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_buffer_prefetch.html#_add_a_new_section_6_15_x_sub_group_prefetch_functions
+ std::optional<
+ std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
+ getBlockWidthHeightCount(Type elemTy) const {
+ static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
+
+ static const int kWidth32[] = {32};
+ static const int kWidth16[] = {16};
+
+ static const int32_t kCount1[] = {1};
+ static const int32_t kCount2[] = {1, 2};
+ // elemBytes
+ using Key = int;
+ // (widths, heights, counts)
+ using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
+ llvm::ArrayRef<int32_t>>;
+ static const llvm::DenseMap<Key, Value> kMap = {
+ {1, {kWidth32, kHeightAtLeast1, kCount2}},
+ {2, {kWidth16, kHeightAtLeast1, kCount2}},
+ {4, {kWidth16, kHeightAtLeast1, kCount1}},
+ };
+ const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
+ auto it = kMap.find(elemByteSize);
+ if (it != kMap.end())
+ return it->second;
+ return std::nullopt;
+ }
+ int32_t getPackedFormatBitSize() const { return 16; }
+};
+
+struct CriSubgroupMatrixMultiplyAcc : public Instruction,
+ public MMAInstructionInterface {
+ CriSubgroupMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
+ unsigned packedFormatBitSizeB)
+ : Instruction(InstructionKind::SubgroupMatrixMultiplyAcc,
+ InstructionScope::Subgroup),
+ packedFormatBitSizeA(packedFormatBitSizeA),
+ packedFormatBitSizeB(packedFormatBitSizeB) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() ==
+ InstructionKind::SubgroupMatrixMultiplyAcc;
+ }
+ // Source:
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_matrix_multiply_accumulate.html
+
+ // Override all virtuals from MatrixOpInterface
+ virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+ getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
+ virtual llvm::SmallVector<Type, 8>
+ getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
+ virtual bool
+ checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
+ std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape,
+ std::pair<uint32_t, uint32_t> DShape, Type AType,
+ Type BType, Type CType, Type DType) override;
+ virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
+ Type DType) override;
+ virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
+ std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape,
+ std::pair<uint32_t, uint32_t> DShape, Type AType,
+ Type BType, Type CType, Type DType) override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedM(Type type) const override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedK(Type type) const override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedN(Type type) const override;
+
+ unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
+ unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
+ bool isLaneLayoutRowMajorOrder() const override { return true; }
+
+protected:
+ const unsigned packedFormatBitSizeA;
+ const unsigned packedFormatBitSizeB;
+};
+
+struct CriSubgroupScaledMatrixMultiplyAcc : public Instruction,
+ public MMAInstructionInterface {
+ CriSubgroupScaledMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
+ unsigned packedFormatBitSizeB)
+ : Instruction(InstructionKind::SubgroupScaledMatrixMultiplyAcc,
+ InstructionScope::Subgroup),
+ packedFormatBitSizeA(packedFormatBitSizeA),
+ packedFormatBitSizeB(packedFormatBitSizeB) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() ==
+ InstructionKind::SubgroupScaledMatrixMultiplyAcc;
+ }
+ // Source:
+ // https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_subgroup_scaled_matrix_multiply_accumulate.asciidoc
+
+ // Override all virtuals from MatrixOpInterface
+ virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+ getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
+ virtual llvm::SmallVector<Type, 8>
+ getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
+ virtual bool
+ checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
+ std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape,
+ std::pair<uint32_t, uint32_t> DShape, Type AType,
+ Type BType, Type CType, Type DType) override;
+ virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
+ Type DType) override;
+ virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
+ std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape,
+ std::pair<uint32_t, uint32_t> DShape, Type AType,
+ Type BType, Type CType, Type DType) override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedM(Type type) const override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedK(Type type) const override;
+ virtual llvm::SmallVector<uint32_t, 8>
+ getSupportedN(Type type) const override;
+
+ unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
+ unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
+ bool isLaneLayoutRowMajorOrder() const override { return true; }
+
+protected:
+ const unsigned packedFormatBitSizeA;
+ const unsigned packedFormatBitSizeB;
+};
+
+//===----------------------------------------------------------------------===//
+// uArch instances
+//===----------------------------------------------------------------------===//
+
+struct CRIuArch : public Xe3 {
+ static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
+ static const CriSubgroupMatrixMultiplyAcc dpasInst{16, 32};
+ static const CriSubgroupScaledMatrixMultiplyAcc dpasMxInst{16, 32};
+ static const CriSubgroup2DBlockLoadInstruction loadNdInst;
+ static const CriSubgroup2DBlockStoreInstruction storeNdInst;
+ static const CriSubgroup2DBlockPrefetchInstruction prefetchNdInst;
+ static const SpirvStoreScatterInstruction storeScatterInst;
+ static const SpirvLoadGatherInstruction loadGatherInst;
+ static const Instruction *arr[] = {
+ &dpasInst, &dpasMxInst, &loadNdInst, &storeNdInst,
+ &prefetchNdInst, &storeScatterInst, &loadGatherInst};
+ return arr;
+ }
+
+ CRIuArch()
+ : Xe3(Kind::CRI, getInstructionRegistryArr(),
+ // Using bmg config as placeholder
+ // TODO: Update to actual XeCore and SharedMemory config
+ XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
+ ) {}
+ static bool classof(const uArch *u) { return u->getKind() == Kind::CRI; }
+ static const uArch *getInstance() {
+ static const CRIuArch instance;
+ return reinterpret_cast<const uArch *>(&instance);
+ }
+};
+
+} // namespace uArch
+} // namespace xegpu
+} // namespace mlir
+
+//===----------------------------------------------------------------------===//
+// Instruction implementations
+//===----------------------------------------------------------------------===//
+
+inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+CriSubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
+ MMAOpndKind matrixType) {
+ auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
+ const llvm::SmallVector<uint32_t, 8> &b)
+ -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
+ llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
+ for (unsigned x : a) {
+ for (unsigned y : b) {
+ result.emplace_back(x, y);
+ }
+ }
+ return result;
+ };
+
+ auto M = getSupportedM(dataType);
+ auto K = getSupportedK(dataType);
+ auto N = getSupportedN(dataType);
+ llvm::SmallVector<std::pair<unsigned, unsigned>, 16> resultMatrix;
+
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ resultMatrix = combineVectors(M, K);
+ break;
+ case MMAOpndKind::MatrixB:
+ resultMatrix = combineVectors(K, N);
+ break;
+ case MMAOpndKind::MatrixC:
+ resultMatrix = combineVectors(M, N);
+ break;
+ case MMAOpndKind::MatrixD:
+ resultMatrix = combineVectors(M, N);
+ break;
+ }
+ return resultMatrix;
+}
+
+inline llvm::SmallVector<Type, 8>
+CriSubgroupMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) {
+ Type bf16Type = BFloat16Type::get(&context);
+ Type f16Type = Float16Type::get(&context);
+ Type tf32Type = FloatTF32Type::get(&context);
+ Type f32Type = Float32Type::get(&context);
+
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ return {bf16Type, f16Type, tf32Type};
+ case MMAOpndKind::MatrixB:
+ return {bf16Type, f16Type, tf32Type};
+ case MMAOpndKind::MatrixC:
+ return {bf16Type, f16Type, f32Type};
+ case MMAOpndKind::MatrixD:
+ return {bf16Type, f16Type, f32Type};
+ }
+ return {};
+}
+
+inline bool CriSubgroupMatrixMultiplyAcc::checkSupportedTypes(Type AType,
+ Type BType,
+ Type CType,
+ Type DType) {
+ if (AType.isF16() || BType.isF16()) {
+ if (AType != BType || (CType && (!CType.isF32() && !CType.isF16())) ||
+ (!DType.isF32() && !DType.isF16())) {
+ LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
+ return false;
+ }
+ } else if (AType.isBF16() || BType.isBF16()) {
+ if (AType != BType || (CType && (!CType.isF32() && !CType.isBF16())) ||
+ (!DType.isF32() && !DType.isBF16())) {
+ LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
+ return false;
+ }
+ } else if (AType.isTF32() || BType.isTF32()) {
+ if (AType != BType || (CType && (!CType.isF32() && !DType.isF32())) ||
+ (!DType.isF32())) {
+ LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
+ return false;
+ }
+ } else if (!(AType.isInteger(2) || AType.isInteger(4) ||
+ AType.isInteger(8)) &&
+ !(BType.isInteger(2) || BType.isInteger(4) ||
+ BType.isInteger(8))) {
+ LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
+ return false;
+ }
+
+ return true;
+}
+
+inline bool CriSubgroupMatrixMultiplyAcc::checkSupportedShapesAndTypes(
+ std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
+ Type AType, Type BType, Type CType, Type DType) {
+ auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
+ auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
+ auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
+ auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
+ return llvm::is_contained(supportedAShapes, AShape) &&
+ llvm::is_contained(supportedBShapes, BShape) &&
+ llvm::is_contained(supportedCShapes, CShape) &&
+ llvm::is_contained(supportedDShapes, DShape) &&
+ checkSupportedTypes(AType, BType, CType, DType);
+}
+
+inline bool CriSubgroupMatrixMultiplyAcc::validate(
+ std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
+ Type AType, Type BType, Type CType, Type DType) {
+ return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
+ BType, CType, DType);
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupMatrixMultiplyAcc::getSupportedM(Type type) const {
+ return {1, 2, 3, 4, 5, 6, 7, 8};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupMatrixMultiplyAcc::getSupportedK(Type type) const {
+ // assert if data type is not int or float type
+ assert(type.isIntOrFloat() && "Matrix type must be int or float");
+ auto bitWidth = type.getIntOrFloatBitWidth();
+ uint32_t kSize = 0;
+ switch (bitWidth) {
+ case 2:
+ kSize = 64;
+ break;
+ case 4:
+ kSize = 64;
+ break;
+ case 8:
+ kSize = 32;
+ break;
+ case 16:
+ kSize = 16;
+ break;
+ case 32:
+ kSize = 8;
+ break;
+ default:
+ llvm_unreachable("Invalid int or float");
+ }
+ return {kSize};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupMatrixMultiplyAcc::getSupportedN(Type type) const {
+ return {16};
+}
+
+//===----------------------------------------------------------------------===//
+// SubgroupScaledMatrixMultiplyAcc implementations
+//===----------------------------------------------------------------------===//
+
+inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+CriSubgroupScaledMatrixMultiplyAcc::getSupportedShapes(Type dataType,
+ MMAOpndKind matrixType) {
+ auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
+ const llvm::SmallVector<uint32_t, 8> &b)
+ -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
+ llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
+ for (unsigned x : a) {
+ for (unsigned y : b) {
+ result.emplace_back(x, y);
+ }
+ }
+ return result;
+ };
+
+ // Avoid calling getSupportedK for C/D types (which are f32/bf16
+ // and not valid for the K-dimension bit-width calculation).
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ return combineVectors(getSupportedM(dataType), getSupportedK(dataType));
+ case MMAOpndKind::MatrixB:
+ return combineVectors(getSupportedK(dataType), getSupportedN(dataType));
+ case MMAOpndKind::MatrixC:
+ case MMAOpndKind::MatrixD:
+ return combineVectors(getSupportedM(dataType), getSupportedN(dataType));
+ }
+ return {};
+}
+
+inline llvm::SmallVector<Type, 8>
+CriSubgroupScaledMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) {
+ Type f8E4M3FNType = Float8E4M3FNType::get(&context);
+ Type f8E5M2Type = Float8E5M2Type::get(&context);
+ Type f4E2M1FNType = Float4E2M1FNType::get(&context);
+ Type bf16Type = BFloat16Type::get(&context);
+ Type f32Type = Float32Type::get(&context);
+
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
+ case MMAOpndKind::MatrixB:
+ return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
+ case MMAOpndKind::MatrixC:
+ return {bf16Type, f32Type};
+ case MMAOpndKind::MatrixD:
+ return {bf16Type, f32Type};
+ }
+ return {};
+}
+
+inline bool CriSubgroupScaledMatrixMultiplyAcc::checkSupportedTypes(
+ Type AType, Type BType, Type CType, Type DType) {
+ auto isSupportedLowPrecision = [](Type t) {
+ return t.isF8E4M3FN() || t.isF8E5M2() || llvm::isa<Float4E2M1FNType>(t);
+ };
+ auto isSupportedAccum = [](Type t) { return t.isF32() || t.isBF16(); };
+
+ if (!isSupportedLowPrecision(AType) || !isSupportedLowPrecision(BType)) {
+ LDBG() << "Unsupported scaled dpas: A and B must be FP8 or FP4 types.";
+ return false;
+ }
+
+ // A and B must have the same bit width for K dimension compatibility.
+ if (AType.getIntOrFloatBitWidth() != BType.getIntOrFloatBitWidth()) {
+ LDBG() << "Unsupported scaled dpas: A and B must have the same bit width.";
+ return false;
+ }
+
+ if (CType && !isSupportedAccum(CType)) {
+ LDBG() << "Unsupported scaled dpas: C must be f32 or bf16.";
+ return false;
+ }
+
+ if (!isSupportedAccum(DType)) {
+ LDBG() << "Unsupported scaled dpas: D must be f32 or bf16.";
+ return false;
+ }
+
+ return true;
+}
+
+inline bool CriSubgroupScaledMatrixMultiplyAcc::checkSupportedShapesAndTypes(
+ std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
+ Type AType, Type BType, Type CType, Type DType) {
+ auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
+ auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
+ auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
+ auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
+ return llvm::is_contained(supportedAShapes, AShape) &&
+ llvm::is_contained(supportedBShapes, BShape) &&
+ llvm::is_contained(supportedCShapes, CShape) &&
+ llvm::is_contained(supportedDShapes, DShape) &&
+ checkSupportedTypes(AType, BType, CType, DType);
+}
+
+inline bool CriSubgroupScaledMatrixMultiplyAcc::validate(
+ std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
+ std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
+ Type AType, Type BType, Type CType, Type DType) {
+ return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
+ BType, CType, DType);
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupScaledMatrixMultiplyAcc::getSupportedM(Type type) const {
+ return {8};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupScaledMatrixMultiplyAcc::getSupportedK(Type type) const {
+ assert(type.isIntOrFloat() && "Matrix type must be int or float");
+ auto bitWidth = type.getIntOrFloatBitWidth();
+ uint32_t kSize = 0;
+ switch (bitWidth) {
+ case 4:
+ kSize = 64; // FP4: scale K by 4 (base 16-bit K=16 -> 64)
+ break;
+ case 8:
+ kSize = 32; // FP8: scale K by 2 (base 16-bit K=16 -> 32)
+ break;
+ default:
+ // Scaled dpas only supports FP8 (8-bit) and FP4 (4-bit) types for A/B
+ // matrices. Return empty so callers can gracefully reject unsupported
+ // types instead of aborting.
+ return {};
+ }
+ return {kSize};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+CriSubgroupScaledMatrixMultiplyAcc::getSupportedN(Type type) const {
+ return {16};
+}
+
+#endif // MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
index 1702c7b46e0eb..2bb45e38b0fe2 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
@@ -156,11 +156,13 @@ struct CacheInfo {
struct uArch {
enum class Kind {
// Xe2 family
- Xe2Plus_First,
- PVC = Xe2Plus_First,
+ Xe2_First,
+ PVC = Xe2_First,
BMG,
- CRI,
- Xe2Plus_Last = CRI,
+ Xe2_Last = BMG,
+ Xe3_First,
+ CRI = Xe3_First,
+ Xe3_Last = CRI
};
// Constructor
@@ -182,6 +184,8 @@ struct uArch {
return "bmg";
case Kind::CRI:
return "cri";
+ default:
+ return "";
}
llvm_unreachable("Unknown uArch::Kind");
}
@@ -333,6 +337,14 @@ struct StoreScatterInstructionInterface : public Instruction {
virtual ~StoreScatterInstructionInterface() = default;
};
+struct SpirvLoadGatherInstruction : public LoadGatherInstructionInterface {
+ int32_t getMaxLaneLoadSize(int32_t bitWidth) const override { return 16; }
+};
+
+struct SpirvStoreScatterInstruction : public StoreScatterInstructionInterface {
+ int32_t getMaxLaneStoreSize(int32_t bitWidth) const override { return 16; }
+};
+
} // namespace uArch
} // namespace xegpu
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchCommon.h b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchCommon.h
new file mode 100644
index 0000000000000..82cfb5538f23f
--- /dev/null
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchCommon.h
@@ -0,0 +1,38 @@
+//===- uArchCommon.h --------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// Common functionality related to uArch instances.
+//
+//
+//===----------------------------------------------------------------------===//
+#ifndef MLIR_DIALECT_XEGPU_UARCH_UARCHCOMMON_H
+#define MLIR_DIALECT_XEGPU_UARCH_UARCHCOMMON_H
+
+#include "IntelGpuXe2.h"
+#include "IntelGpuXe3.h"
+
+namespace mlir {
+namespace xegpu {
+namespace uArch {
+
+inline const uArch *getUArch(llvm::StringRef archName) {
+ if (archName.equals_insensitive("pvc"))
+ return PVCuArch::getInstance();
+ if (archName.equals_insensitive("bmg"))
+ return BMGuArch::getInstance();
+ if (archName.equals_insensitive("cri"))
+ return CRIuArch::getInstance();
+ return nullptr;
+}
+
+} // namespace uArch
+} // namespace xegpu
+} // namespace mlir
+
+#endif // MLIR_DIALECT_XEGPU_UARCH_UARCHCOMMON_H
diff --git a/mlir/lib/Conversion/XeGPUToXeVM/XeGPUToXeVM.cpp b/mlir/lib/Conversion/XeGPUToXeVM/XeGPUToXeVM.cpp
index c7d593c74f264..6144d7c0c1a15 100644
--- a/mlir/lib/Conversion/XeGPUToXeVM/XeGPUToXeVM.cpp
+++ b/mlir/lib/Conversion/XeGPUToXeVM/XeGPUToXeVM.cpp
@@ -23,7 +23,7 @@
#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include "mlir/Dialect/XeGPU/IR/XeGPU.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/LLVM.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/mlir/lib/Dialect/XeGPU/IR/XeGPUDialect.cpp b/mlir/lib/Dialect/XeGPU/IR/XeGPUDialect.cpp
index 5d55342afea15..f9c258aba5bc7 100644
--- a/mlir/lib/Dialect/XeGPU/IR/XeGPUDialect.cpp
+++ b/mlir/lib/Dialect/XeGPU/IR/XeGPUDialect.cpp
@@ -12,7 +12,7 @@
#include "mlir/Dialect/LLVMIR/XeVMDialect.h"
#include "mlir/Dialect/Utils/IndexingUtils.h"
#include "mlir/Dialect/XeGPU/IR/XeGPU.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/DialectImplementation.h"
#include "llvm/ADT/SmallVectorExtras.h"
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUArrayLengthOptimization.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUArrayLengthOptimization.cpp
index 53da46cbdee73..590d1804167a5 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUArrayLengthOptimization.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUArrayLengthOptimization.cpp
@@ -10,8 +10,8 @@
#include "mlir/Dialect/XeGPU/IR/XeGPU.h"
#include "mlir/Dialect/XeGPU/Transforms/Transforms.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
#include "mlir/Dialect/XeGPU/uArch/uArchBase.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/PatternMatch.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
index 566d0eb433606..1ed418d446886 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
@@ -18,8 +18,8 @@
#include "mlir/Dialect/XeGPU/Transforms/Transforms.h"
#include "mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
#include "mlir/Dialect/XeGPU/uArch/uArchBase.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/Types.h"
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
index 8600492e4bf41..57cf1d0669cb1 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
@@ -17,7 +17,7 @@
#include "mlir/Dialect/XeGPU/Transforms/Passes.h"
#include "mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
index 75a87f84b3da8..766754af76cb7 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
@@ -16,7 +16,7 @@
#include "mlir/Dialect/XeGPU/Transforms/Transforms.h"
#include "mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h"
#include "mlir/Dialect/XeGPU/Utils/XeGPUUtils.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
diff --git a/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp b/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
index 24999f85c1268..1aad2aa77741b 100644
--- a/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
+++ b/mlir/lib/Dialect/XeGPU/Utils/XeGPUUtils.cpp
@@ -18,7 +18,7 @@
#include "mlir/Dialect/Utils/IndexingUtils.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include "mlir/Dialect/XeGPU/IR/XeGPU.h"
-#include "mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h"
+#include "mlir/Dialect/XeGPU/uArch/uArchCommon.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Operation.h"
@@ -786,7 +786,7 @@ bool xegpu::requireTranspose(const xegpu::DistributeLayoutAttr layout,
const xegpu::uArch::uArch *uArch) {
// Return false for unsupported targets.
// TODO: Add more support or move to target info.
- if (!isa<xegpu::uArch::Xe2Plus>(uArch))
+ if (!isa<xegpu::uArch::Xe2>(uArch) && !isa<xegpu::uArch::Xe3>(uArch))
return false;
if (!layout)
return false;
>From 324cee8a6ca1c74d2e49dc5765e37b32ca803531 Mon Sep 17 00:00:00 2001
From: Artem Kroviakov <artem.kroviakov at intel.com>
Date: Thu, 25 Jun 2026 09:47:23 +0000
Subject: [PATCH 3/5] Fix uarch tables
---
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h | 67 +++++++++++++------
1 file changed, 45 insertions(+), 22 deletions(-)
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
index a831196d2a8df..982dbdbea5473 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
@@ -48,7 +48,8 @@ struct Xe3 : public uArch {
//===----------------------------------------------------------------------===//
// uArch instructions
//===----------------------------------------------------------------------===//
-struct CriSubgroup2DBlockStoreInstruction : public Instruction {
+struct CriSubgroup2DBlockStoreInstruction : public Instruction,
+ public BlockIOInstructionInterface {
CriSubgroup2DBlockStoreInstruction()
: Instruction(InstructionKind::Subgroup2DBlockStore,
InstructionScope::Subgroup) {}
@@ -57,9 +58,12 @@ struct CriSubgroup2DBlockStoreInstruction : public Instruction {
}
// Source :
// https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
+ // Stores ignore the transform / transpose / upConv flags.
std::optional<
std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy) const {
+ getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
+ bool /*hasTranspose*/ = false,
+ bool /*upConv*/ = false) const override {
const static int kHeight[] = {1, 2, 4, 8};
const static int kWidth16[] = {16};
const static int kWidth32[] = {16};
@@ -76,10 +80,11 @@ struct CriSubgroup2DBlockStoreInstruction : public Instruction {
return std::nullopt;
}
- int32_t getPackedFormatBitSize() const { return 16; }
+ int32_t getPackedFormatBitSize() const override { return 16; }
};
-struct CriSubgroup2DBlockLoadInstruction : public Instruction {
+struct CriSubgroup2DBlockLoadInstruction : public Instruction,
+ public BlockIOInstructionInterface {
CriSubgroup2DBlockLoadInstruction()
: Instruction(InstructionKind::Subgroup2DBlockLoad,
InstructionScope::Subgroup) {}
@@ -91,48 +96,64 @@ struct CriSubgroup2DBlockLoadInstruction : public Instruction {
// https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
std::optional<
std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool hasTransform, bool hasTranspose,
- bool upConv = false) const {
+ getBlockWidthHeightCount(Type elemTy, bool hasTransform = false,
+ bool hasTranspose = false,
+ bool upConv = false) const override {
static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
static const int kHeightAtLeast8[] = {8, 16, 32};
static const int kHeightAtLeast16[] = {16, 32};
- static const int kHeightAtLeast32[] = {32};
+ static const int kHeight32[] = {32};
+ static const int kHeight64[] = {64};
+ static const int kWidth64[] = {64};
static const int kWidth32[] = {32};
static const int kWidth16[] = {16};
+ static const int kWidthAtLeast16[] = {16, 32};
+ static const int kWidthAtLeast32[] = {32, 64};
static const int kWidth8[] = {8};
static const int32_t kCount1[] = {1};
static const int32_t kCount2[] = {1, 2};
static const int32_t kCount4[] = {1, 2, 4};
static const int32_t kCount4Only[] = {4};
- // (elemBytes, transform, transpose, upConvert)
+ // (elemBits, transform, transpose, upConvert)
using Key = std::tuple<int, uint8_t, uint8_t, uint8_t>;
// (widths, heights, counts)
using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
llvm::ArrayRef<int32_t>>;
+ // The table is keyed on element bit width so sub-byte elements can be
+ // expressed directly. 4-bit elements are packed two-per-byte, so their
+ // widths (or heights, when transformed) are double the 8-bit rows.
static const llvm::DenseMap<Key, Value> kMap = {
- {{1, false, false, false}, {kWidth32, kHeightAtLeast1, kCount2}},
- {{1, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
- {{2, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
- {{4, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
+ {{8, false, false, false}, {kWidthAtLeast16, kHeightAtLeast1, kCount2}},
+ {{8, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
+ {{16, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
+ {{32, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
// Block Loads with Transform:
- {{1, true, false, false}, {kWidth16, kHeightAtLeast32, kCount4}},
- {{2, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
+ {{8, true, false, false}, {kWidth16, kHeight32, kCount4}},
+ {{16, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
// Block Loads with Transpose:
- {{4, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
- };
- const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
- auto it = kMap.find({elemByteSize, hasTransform, hasTranspose, upConv});
+ {{8, false, true, false}, {kWidth32, kHeightAtLeast16, kCount1}},
+ {{16, false, true, false}, {kWidth16, kHeightAtLeast16, kCount1}},
+ {{32, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
+ // 4-bit elements (sub-byte):
+ {{4, false, false, false}, {kWidthAtLeast32, kHeightAtLeast1, kCount2}},
+ {{4, false, false, true}, {kWidth32, kHeightAtLeast8, kCount4Only}},
+ {{4, true, false, false}, {kWidth16, kHeight64, kCount4}},
+ {{4, false, true, false}, {kWidth64, kHeightAtLeast16, kCount1}}};
+ int elemBitSize = elemTy.getIntOrFloatBitWidth();
+ auto it = kMap.find({elemBitSize, hasTransform, hasTranspose, upConv});
if (it != kMap.end())
return it->second;
return std::nullopt;
}
- int32_t getPackedFormatBitSize() const { return 16; }
+ int32_t getPackedFormatBitSize() const override { return 16; }
};
-struct CriSubgroup2DBlockPrefetchInstruction : public Instruction {
+struct CriSubgroup2DBlockPrefetchInstruction
+ : public Instruction,
+ public BlockIOInstructionInterface {
CriSubgroup2DBlockPrefetchInstruction()
: Instruction(InstructionKind::Subgroup2DBlockPrefetch,
InstructionScope::Subgroup) {}
@@ -143,7 +164,9 @@ struct CriSubgroup2DBlockPrefetchInstruction : public Instruction {
// https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_buffer_prefetch.html#_add_a_new_section_6_15_x_sub_group_prefetch_functions
std::optional<
std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy) const {
+ getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
+ bool /*hasTranspose*/ = false,
+ bool /*upConv*/ = false) const {
static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
static const int kWidth32[] = {32};
@@ -167,7 +190,7 @@ struct CriSubgroup2DBlockPrefetchInstruction : public Instruction {
return it->second;
return std::nullopt;
}
- int32_t getPackedFormatBitSize() const { return 16; }
+ int32_t getPackedFormatBitSize() const override { return 16; }
};
struct CriSubgroupMatrixMultiplyAcc : public Instruction,
>From 01aa010cb66cbef33f9ffcba28963d19fca9df84 Mon Sep 17 00:00:00 2001
From: Artem Kroviakov <artem.kroviakov at intel.com>
Date: Thu, 25 Jun 2026 10:06:38 +0000
Subject: [PATCH 4/5] Cleanup
---
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h | 9 ++-------
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h | 9 +++------
.../mlir/Dialect/XeGPU/uArch/uArchBase.h | 17 -----------------
3 files changed, 5 insertions(+), 30 deletions(-)
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
index ed8ae5289882a..dea5240248089 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
@@ -20,7 +20,6 @@
#include "mlir/IR/TypeUtilities.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DebugLog.h"
-#include <map>
#include <string>
using namespace mlir;
@@ -316,7 +315,7 @@ struct PVCuArch final : public Xe2 {
static bool classof(const uArch *u) { return u->getKind() == Kind::PVC; }
static const uArch *getInstance() {
static const PVCuArch instance;
- return reinterpret_cast<const uArch *>(&instance);
+ return &instance;
}
};
@@ -341,7 +340,7 @@ struct BMGuArch : public Xe2 {
static bool classof(const uArch *u) { return u->getKind() == Kind::BMG; }
static const uArch *getInstance() {
static const BMGuArch instance;
- return reinterpret_cast<const uArch *>(&instance);
+ return &instance;
}
};
@@ -381,8 +380,6 @@ SubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
resultMatrix = combineVectors(K, N);
break;
case MMAOpndKind::MatrixC:
- resultMatrix = combineVectors(M, N);
- break;
case MMAOpndKind::MatrixD:
resultMatrix = combineVectors(M, N);
break;
@@ -480,8 +477,6 @@ SubgroupMatrixMultiplyAcc::getSupportedK(Type type) const {
uint32_t kSize = 0;
switch (bitWidth) {
case 2:
- kSize = 64;
- break;
case 4:
kSize = 64;
break;
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
index 982dbdbea5473..ca16d8ebdddd5 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// \file
-// Xe2 uArch definition. Xe3 is the second generation of Intel Xe GPUs.
+// Xe3 uArch definition. Xe3 is the second generation of Intel Xe GPUs.
// This file defines the uArch details for Xe3 and its derived architectures.
// This includes Crescent Island Architecture.
//
@@ -20,7 +20,6 @@
#include "mlir/IR/TypeUtilities.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DebugLog.h"
-#include <map>
#include <string>
using namespace mlir;
@@ -166,7 +165,7 @@ struct CriSubgroup2DBlockPrefetchInstruction
std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
bool /*hasTranspose*/ = false,
- bool /*upConv*/ = false) const {
+ bool /*upConv*/ = false) const override {
static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
static const int kWidth32[] = {32};
@@ -319,7 +318,7 @@ struct CRIuArch : public Xe3 {
static bool classof(const uArch *u) { return u->getKind() == Kind::CRI; }
static const uArch *getInstance() {
static const CRIuArch instance;
- return reinterpret_cast<const uArch *>(&instance);
+ return &instance;
}
};
@@ -359,8 +358,6 @@ CriSubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
resultMatrix = combineVectors(K, N);
break;
case MMAOpndKind::MatrixC:
- resultMatrix = combineVectors(M, N);
- break;
case MMAOpndKind::MatrixD:
resultMatrix = combineVectors(M, N);
break;
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
index 2bb45e38b0fe2..d5239cc0fdf67 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
@@ -14,12 +14,6 @@
#ifndef MLIR_DIALECT_XEGPU_UARCH_UARCHBASE_H
#define MLIR_DIALECT_XEGPU_UARCH_UARCHBASE_H
-#include <any>
-#include <functional>
-#include <iostream>
-#include <map>
-#include <mutex>
-#include <optional>
#include <shared_mutex>
#include <tuple>
@@ -31,8 +25,6 @@ namespace mlir {
namespace xegpu {
namespace uArch {
-constexpr unsigned generalPackedFormatBitSize{32};
-
// An enum class to represent the scope of an instruction
enum class InstructionScope { Lane, Subgroup, Workgroup, Cluster };
enum class InstructionKind {
@@ -82,18 +74,10 @@ struct Instruction {
llvm_unreachable("Unknown InstructionKind");
}
- static std::optional<InstructionKind>
- parseInstructionKind(llvm::StringRef str) {
- if (str.equals_insensitive("dpas"))
- return InstructionKind::SubgroupMatrixMultiplyAcc;
- return std::nullopt;
- }
-
protected:
const InstructionKind instKind; // Specific InstructionKind (e.g., DPAS)
const InstructionScope scope; // scope of the instruction (e.g., lane,
// subgroup, workgroup, cluster)
- // @TODO: Add more fields as needed
};
enum class RegisterFileMode : uint8_t { Small, Large };
@@ -187,7 +171,6 @@ struct uArch {
default:
return "";
}
- llvm_unreachable("Unknown uArch::Kind");
}
static StringRef getUArchDescription(Kind k) {
>From ae6ca13f443f2cb8343a21ffa7311e42054024e9 Mon Sep 17 00:00:00 2001
From: Artem Kroviakov <artem.kroviakov at intel.com>
Date: Thu, 25 Jun 2026 13:22:29 +0000
Subject: [PATCH 5/5] Deduplicate common instructions, reduce bloat
---
.../XeGPU/Transforms/XeGPULayoutImpl.h | 4 +-
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h | 611 +-----------------
.../mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h | 589 +----------------
.../mlir/Dialect/XeGPU/uArch/uArchBase.h | 556 +++++++++++-----
.../XeGPU/Transforms/XeGPULayoutImpl.cpp | 46 +-
.../Transforms/XeGPUPeepHoleOptimizer.cpp | 13 +-
.../XeGPU/Transforms/XeGPUPropagateLayout.cpp | 49 +-
.../Transforms/XeGPUSgToLaneDistribute.cpp | 18 +-
8 files changed, 514 insertions(+), 1372 deletions(-)
diff --git a/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h b/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
index 027a70d9579ab..5f313e480c918 100644
--- a/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
+++ b/mlir/include/mlir/Dialect/XeGPU/Transforms/XeGPULayoutImpl.h
@@ -256,7 +256,7 @@ DistributeLayoutAttr setupStoreMatrixAnchorLayout(LayoutKind layoutKind,
std::optional<DistributeLayoutAttr> completeScatterLoadLaneLayoutFromInstData(
DistributeLayoutAttr userSpecifiedLayout,
DistributeLayoutAttr consumerLayout, Type elemTy,
- const xegpu::uArch::LoadGatherInstructionInterface *uArchInstruction,
+ const xegpu::uArch::LoadGatherInstruction *uArchInstruction,
const int subgroupSize);
/// Like completeScatterLoadLaneLayoutFromInstData, but for scatter stores
@@ -265,7 +265,7 @@ std::optional<DistributeLayoutAttr> completeScatterLoadLaneLayoutFromInstData(
/// with no consumer layout to reuse.
std::optional<DistributeLayoutAttr> completeScatterStoreLaneLayoutFromInstData(
DistributeLayoutAttr specifiedLayout, Type elemTy,
- const xegpu::uArch::StoreScatterInstructionInterface *uArchInstruction,
+ const xegpu::uArch::StoreScatterInstruction *uArchInstruction,
const int subgroupSize);
/// Completes a user-provided 2D-block store_nd / prefetch_nd anchor that has
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
index dea5240248089..ae042e71e362f 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe2.h
@@ -16,302 +16,45 @@
#define MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE2_H
#include "mlir/Dialect/XeGPU/uArch/uArchBase.h"
-#include "mlir/IR/BuiltinTypes.h"
-#include "mlir/IR/TypeUtilities.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/DebugLog.h"
-#include <string>
-
-using namespace mlir;
-using namespace mlir::xegpu::uArch;
namespace mlir {
namespace xegpu {
namespace uArch {
struct Xe2 : public uArch {
- Xe2(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
- const XeCoreInfo &xeCore)
- : uArch(kind, instructionRegistry), xeCore(xeCore) {}
+ Xe2(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry)
+ : uArch(kind, instructionRegistry) {}
int getSubgroupSize() const override { return 16; }
unsigned getGeneralPackedFormatBitSize() const override { return 32; }
static bool classof(const uArch *u) {
return u->getKind() >= Kind::Xe2_First && u->getKind() <= Kind::Xe2_Last;
}
-
-protected:
- XeCoreInfo xeCore;
-};
-
-//===----------------------------------------------------------------------===//
-// uArch instructions
-//===----------------------------------------------------------------------===//
-struct Subgroup2DBlockStoreInstruction : public Instruction,
- public BlockIOInstructionInterface {
- Subgroup2DBlockStoreInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockStore,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockStore;
- }
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
- // Stores ignore the transform / transpose / upConv flags.
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
- bool /*hasTranspose*/ = false,
- bool /*upConv*/ = false) const override {
- const static int kHeight[] = {1, 2, 4, 8};
- const static int kWidth16[] = {16};
- const static int kWidth32[] = {16};
- const static int kCount[] = {1};
- const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
- if (elemByteSize == 1)
- return std::make_tuple(llvm::ArrayRef<int>(kWidth32),
- llvm::ArrayRef<int>(kHeight),
- llvm::ArrayRef<int>(kCount));
- else if (elemByteSize == 2 || elemByteSize == 4)
- return std::make_tuple(llvm::ArrayRef<int>(kWidth16),
- llvm::ArrayRef<int>(kHeight),
- llvm::ArrayRef<int>(kCount));
- return std::nullopt;
- }
-
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct Subgroup2DBlockLoadInstruction : public Instruction,
- public BlockIOInstructionInterface {
- Subgroup2DBlockLoadInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockLoad,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockLoad;
- }
-
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool hasTransform = false,
- bool hasTranspose = false,
- bool upConv = false) const override {
- static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
- static const int kHeightAtLeast8[] = {8, 16, 32};
- static const int kHeightAtLeast16[] = {16, 32};
- static const int kHeight32[] = {32};
- static const int kHeight64[] = {64};
-
- static const int kWidth64[] = {64};
- static const int kWidth32[] = {32};
- static const int kWidth16[] = {16};
- static const int kWidthAtLeast16[] = {16, 32};
- static const int kWidthAtLeast32[] = {32, 64};
- static const int kWidth8[] = {8};
-
- static const int32_t kCount1[] = {1};
- static const int32_t kCount2[] = {1, 2};
- static const int32_t kCount4[] = {1, 2, 4};
- static const int32_t kCount4Only[] = {4};
- // (elemBits, transform, transpose, upConvert)
- using Key = std::tuple<int, uint8_t, uint8_t, uint8_t>;
- // (widths, heights, counts)
- using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
- llvm::ArrayRef<int32_t>>;
- // The table is keyed on element bit width so sub-byte elements can be
- // expressed directly. 4-bit elements are packed two-per-byte, so their
- // widths (or heights, when transformed) are double the 8-bit rows.
- static const llvm::DenseMap<Key, Value> kMap = {
- {{8, false, false, false}, {kWidthAtLeast16, kHeightAtLeast1, kCount2}},
- {{8, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
- {{16, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
- {{32, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
- // Block Loads with Transform:
- {{8, true, false, false}, {kWidth16, kHeight32, kCount4}},
- {{16, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
- // Block Loads with Transpose:
- {{8, false, true, false}, {kWidth32, kHeightAtLeast16, kCount1}},
- {{16, false, true, false}, {kWidth16, kHeightAtLeast16, kCount1}},
- {{32, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
- // 4-bit elements (sub-byte):
- {{4, false, false, false}, {kWidthAtLeast32, kHeightAtLeast1, kCount2}},
- {{4, false, false, true}, {kWidth32, kHeightAtLeast8, kCount4Only}},
- {{4, true, false, false}, {kWidth16, kHeight64, kCount4}},
- {{4, false, true, false}, {kWidth64, kHeightAtLeast16, kCount1}}};
- int elemBitSize = elemTy.getIntOrFloatBitWidth();
- auto it = kMap.find({elemBitSize, hasTransform, hasTranspose, upConv});
- if (it != kMap.end())
- return it->second;
- return std::nullopt;
- }
-
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct Subgroup2DBlockPrefetchInstruction : public Instruction,
- public BlockIOInstructionInterface {
- Subgroup2DBlockPrefetchInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockPrefetch,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockPrefetch;
- }
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_buffer_prefetch.html#_add_a_new_section_6_15_x_sub_group_prefetch_functions
- // Prefetches ignore the transform / transpose / upConv flags.
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
- bool /*hasTranspose*/ = false,
- bool /*upConv*/ = false) const override {
- static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
-
- static const int kWidth32[] = {32};
- static const int kWidth16[] = {16};
-
- static const int32_t kCount1[] = {1};
- static const int32_t kCount2[] = {1, 2};
- // elemBytes
- using Key = int;
- // (widths, heights, counts)
- using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
- llvm::ArrayRef<int32_t>>;
- static const llvm::DenseMap<Key, Value> kMap = {
- {1, {kWidth32, kHeightAtLeast1, kCount2}},
- {2, {kWidth16, kHeightAtLeast1, kCount2}},
- {4, {kWidth16, kHeightAtLeast1, kCount1}},
- };
- const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
- auto it = kMap.find(elemByteSize);
- if (it != kMap.end())
- return it->second;
- return std::nullopt;
- }
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct SubgroupMatrixMultiplyAcc : public Instruction,
- public MMAInstructionInterface {
- SubgroupMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
- unsigned packedFormatBitSizeB)
- : Instruction(InstructionKind::SubgroupMatrixMultiplyAcc,
- InstructionScope::Subgroup),
- packedFormatBitSizeA(packedFormatBitSizeA),
- packedFormatBitSizeB(packedFormatBitSizeB) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() ==
- InstructionKind::SubgroupMatrixMultiplyAcc;
- }
- // Source:
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_matrix_multiply_accumulate.html
-
- // Override all virtuals from MatrixOpInterface
- virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
- getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
- virtual llvm::SmallVector<Type, 8>
- getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
- virtual bool
- checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
- Type DType) override;
- virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedM(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedK(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedN(Type type) const override;
-
- unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
- unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
- bool isLaneLayoutRowMajorOrder() const override { return true; }
-
-protected:
- const unsigned packedFormatBitSizeA;
- const unsigned packedFormatBitSizeB;
-};
-
-struct SubgroupScaledMatrixMultiplyAcc : public Instruction,
- public MMAInstructionInterface {
- SubgroupScaledMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
- unsigned packedFormatBitSizeB)
- : Instruction(InstructionKind::SubgroupScaledMatrixMultiplyAcc,
- InstructionScope::Subgroup),
- packedFormatBitSizeA(packedFormatBitSizeA),
- packedFormatBitSizeB(packedFormatBitSizeB) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() ==
- InstructionKind::SubgroupScaledMatrixMultiplyAcc;
- }
- // Source:
- // https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_subgroup_scaled_matrix_multiply_accumulate.asciidoc
-
- // Override all virtuals from MatrixOpInterface
- virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
- getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
- virtual llvm::SmallVector<Type, 8>
- getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
- virtual bool
- checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
- Type DType) override;
- virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedM(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedK(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedN(Type type) const override;
-
- unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
- unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
- bool isLaneLayoutRowMajorOrder() const override { return true; }
-
-protected:
- const unsigned packedFormatBitSizeA;
- const unsigned packedFormatBitSizeB;
};
//===----------------------------------------------------------------------===//
// uArch instances
+//
+// PVC and BMG share the same Khronos-extension instruction set.
//===----------------------------------------------------------------------===//
-struct PVCuArch final : public Xe2 {
- static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
- static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
- static const Subgroup2DBlockLoadInstruction loadNdInst;
- static const Subgroup2DBlockStoreInstruction storeNdInst;
- static const Subgroup2DBlockPrefetchInstruction prefetchNdInst;
- static const SpirvStoreScatterInstruction storeScatterInst;
- static const SpirvLoadGatherInstruction loadGatherInst;
- static const Instruction *arr[] = {&dpasInst, &loadNdInst,
- &storeNdInst, &prefetchNdInst,
- &storeScatterInst, &loadGatherInst};
- return arr;
- }
+namespace detail {
+inline llvm::ArrayRef<const Instruction *> getXe2InstructionRegistry() {
+ static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
+ static const Subgroup2DBlockLoadInstruction loadNdInst;
+ static const Subgroup2DBlockStoreInstruction storeNdInst;
+ static const Subgroup2DBlockPrefetchInstruction prefetchNdInst;
+ static const StoreScatterInstruction storeScatterInst;
+ static const LoadGatherInstruction loadGatherInst;
+ static const Instruction *arr[] = {&dpasInst, &loadNdInst,
+ &storeNdInst, &prefetchNdInst,
+ &storeScatterInst, &loadGatherInst};
+ return arr;
+}
+} // namespace detail
- PVCuArch()
- : Xe2(Kind::PVC, getInstructionRegistryArr(),
- XeCoreInfo(8, SharedMemory(512 * 1024, 4), 8, 8) // xeCore
- ) {}
+struct PVCuArch final : public Xe2 {
+ PVCuArch() : Xe2(Kind::PVC, detail::getXe2InstructionRegistry()) {}
static bool classof(const uArch *u) { return u->getKind() == Kind::PVC; }
static const uArch *getInstance() {
static const PVCuArch instance;
@@ -319,24 +62,8 @@ struct PVCuArch final : public Xe2 {
}
};
-struct BMGuArch : public Xe2 {
- static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
- static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
- static const Subgroup2DBlockLoadInstruction loadNdInst;
- static const Subgroup2DBlockStoreInstruction storeNdInst;
- static const Subgroup2DBlockPrefetchInstruction prefetchNdInst;
- static const SpirvStoreScatterInstruction storeScatterInst;
- static const SpirvLoadGatherInstruction loadGatherInst;
- static const Instruction *arr[] = {&dpasInst, &loadNdInst,
- &storeNdInst, &prefetchNdInst,
- &storeScatterInst, &loadGatherInst};
- return arr;
- }
-
- BMGuArch()
- : Xe2(Kind::BMG, getInstructionRegistryArr(),
- XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
- ) {}
+struct BMGuArch final : public Xe2 {
+ BMGuArch() : Xe2(Kind::BMG, detail::getXe2InstructionRegistry()) {}
static bool classof(const uArch *u) { return u->getKind() == Kind::BMG; }
static const uArch *getInstance() {
static const BMGuArch instance;
@@ -348,298 +75,4 @@ struct BMGuArch : public Xe2 {
} // namespace xegpu
} // namespace mlir
-//===----------------------------------------------------------------------===//
-// Instruction implementations
-//===----------------------------------------------------------------------===//
-
-inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
-SubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
- MMAOpndKind matrixType) {
- auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
- const llvm::SmallVector<uint32_t, 8> &b)
- -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
- llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
- for (unsigned x : a) {
- for (unsigned y : b) {
- result.emplace_back(x, y);
- }
- }
- return result;
- };
-
- auto M = getSupportedM(dataType);
- auto K = getSupportedK(dataType);
- auto N = getSupportedN(dataType);
- llvm::SmallVector<std::pair<unsigned, unsigned>, 16> resultMatrix;
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- resultMatrix = combineVectors(M, K);
- break;
- case MMAOpndKind::MatrixB:
- resultMatrix = combineVectors(K, N);
- break;
- case MMAOpndKind::MatrixC:
- case MMAOpndKind::MatrixD:
- resultMatrix = combineVectors(M, N);
- break;
- }
- return resultMatrix;
-}
-
-inline llvm::SmallVector<Type, 8>
-SubgroupMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
- MMAOpndKind matrixType) {
- Type bf16Type = BFloat16Type::get(&context);
- Type f16Type = Float16Type::get(&context);
- Type tf32Type = FloatTF32Type::get(&context);
- Type f32Type = Float32Type::get(&context);
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return {bf16Type, f16Type, tf32Type};
- case MMAOpndKind::MatrixB:
- return {bf16Type, f16Type, tf32Type};
- case MMAOpndKind::MatrixC:
- return {bf16Type, f16Type, f32Type};
- case MMAOpndKind::MatrixD:
- return {bf16Type, f16Type, f32Type};
- }
- return {};
-}
-
-inline bool SubgroupMatrixMultiplyAcc::checkSupportedTypes(Type AType,
- Type BType,
- Type CType,
- Type DType) {
- if (AType.isF16() || BType.isF16()) {
- if (AType != BType || (CType && (!CType.isF32() && !CType.isF16())) ||
- (!DType.isF32() && !DType.isF16())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (AType.isBF16() || BType.isBF16()) {
- if (AType != BType || (CType && (!CType.isF32() && !CType.isBF16())) ||
- (!DType.isF32() && !DType.isBF16())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (AType.isTF32() || BType.isTF32()) {
- if (AType != BType || (CType && (!CType.isF32() && !DType.isF32())) ||
- (!DType.isF32())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (!(AType.isInteger(2) || AType.isInteger(4) ||
- AType.isInteger(8)) &&
- !(BType.isInteger(2) || BType.isInteger(4) ||
- BType.isInteger(8))) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
-
- return true;
-}
-
-inline bool SubgroupMatrixMultiplyAcc::checkSupportedShapesAndTypes(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
- auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
- auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
- auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
- return llvm::is_contained(supportedAShapes, AShape) &&
- llvm::is_contained(supportedBShapes, BShape) &&
- llvm::is_contained(supportedCShapes, CShape) &&
- llvm::is_contained(supportedDShapes, DShape) &&
- checkSupportedTypes(AType, BType, CType, DType);
-}
-
-inline bool SubgroupMatrixMultiplyAcc::validate(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
- BType, CType, DType);
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupMatrixMultiplyAcc::getSupportedM(Type type) const {
- return {1, 2, 3, 4, 5, 6, 7, 8};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupMatrixMultiplyAcc::getSupportedK(Type type) const {
- // assert if data type is not int or float type
- assert(type.isIntOrFloat() && "Matrix type must be int or float");
- auto bitWidth = type.getIntOrFloatBitWidth();
- uint32_t kSize = 0;
- switch (bitWidth) {
- case 2:
- case 4:
- kSize = 64;
- break;
- case 8:
- kSize = 32;
- break;
- case 16:
- kSize = 16;
- break;
- case 32:
- kSize = 8;
- break;
- default:
- llvm_unreachable("Invalid int or float");
- }
- return {kSize};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupMatrixMultiplyAcc::getSupportedN(Type type) const {
- return {16};
-}
-
-//===----------------------------------------------------------------------===//
-// SubgroupScaledMatrixMultiplyAcc implementations
-//===----------------------------------------------------------------------===//
-
-inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
-SubgroupScaledMatrixMultiplyAcc::getSupportedShapes(Type dataType,
- MMAOpndKind matrixType) {
- auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
- const llvm::SmallVector<uint32_t, 8> &b)
- -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
- llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
- for (unsigned x : a) {
- for (unsigned y : b) {
- result.emplace_back(x, y);
- }
- }
- return result;
- };
-
- // Avoid calling getSupportedK for C/D types (which are f32/bf16
- // and not valid for the K-dimension bit-width calculation).
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return combineVectors(getSupportedM(dataType), getSupportedK(dataType));
- case MMAOpndKind::MatrixB:
- return combineVectors(getSupportedK(dataType), getSupportedN(dataType));
- case MMAOpndKind::MatrixC:
- case MMAOpndKind::MatrixD:
- return combineVectors(getSupportedM(dataType), getSupportedN(dataType));
- }
- return {};
-}
-
-inline llvm::SmallVector<Type, 8>
-SubgroupScaledMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
- MMAOpndKind matrixType) {
- Type f8E4M3FNType = Float8E4M3FNType::get(&context);
- Type f8E5M2Type = Float8E5M2Type::get(&context);
- Type f4E2M1FNType = Float4E2M1FNType::get(&context);
- Type bf16Type = BFloat16Type::get(&context);
- Type f32Type = Float32Type::get(&context);
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
- case MMAOpndKind::MatrixB:
- return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
- case MMAOpndKind::MatrixC:
- return {bf16Type, f32Type};
- case MMAOpndKind::MatrixD:
- return {bf16Type, f32Type};
- }
- return {};
-}
-
-inline bool SubgroupScaledMatrixMultiplyAcc::checkSupportedTypes(Type AType,
- Type BType,
- Type CType,
- Type DType) {
- auto isSupportedLowPrecision = [](Type t) {
- return t.isF8E4M3FN() || t.isF8E5M2() || llvm::isa<Float4E2M1FNType>(t);
- };
- auto isSupportedAccum = [](Type t) { return t.isF32() || t.isBF16(); };
-
- if (!isSupportedLowPrecision(AType) || !isSupportedLowPrecision(BType)) {
- LDBG() << "Unsupported scaled dpas: A and B must be FP8 or FP4 types.";
- return false;
- }
-
- // A and B must have the same bit width for K dimension compatibility.
- if (AType.getIntOrFloatBitWidth() != BType.getIntOrFloatBitWidth()) {
- LDBG() << "Unsupported scaled dpas: A and B must have the same bit width.";
- return false;
- }
-
- if (CType && !isSupportedAccum(CType)) {
- LDBG() << "Unsupported scaled dpas: C must be f32 or bf16.";
- return false;
- }
-
- if (!isSupportedAccum(DType)) {
- LDBG() << "Unsupported scaled dpas: D must be f32 or bf16.";
- return false;
- }
-
- return true;
-}
-
-inline bool SubgroupScaledMatrixMultiplyAcc::checkSupportedShapesAndTypes(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
- auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
- auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
- auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
- return llvm::is_contained(supportedAShapes, AShape) &&
- llvm::is_contained(supportedBShapes, BShape) &&
- llvm::is_contained(supportedCShapes, CShape) &&
- llvm::is_contained(supportedDShapes, DShape) &&
- checkSupportedTypes(AType, BType, CType, DType);
-}
-
-inline bool SubgroupScaledMatrixMultiplyAcc::validate(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
- BType, CType, DType);
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupScaledMatrixMultiplyAcc::getSupportedM(Type type) const {
- return {8};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupScaledMatrixMultiplyAcc::getSupportedK(Type type) const {
- assert(type.isIntOrFloat() && "Matrix type must be int or float");
- auto bitWidth = type.getIntOrFloatBitWidth();
- uint32_t kSize = 0;
- switch (bitWidth) {
- case 4:
- kSize = 64; // FP4: scale K by 4 (base 16-bit K=16 -> 64)
- break;
- case 8:
- kSize = 32; // FP8: scale K by 2 (base 16-bit K=16 -> 32)
- break;
- default:
- // Scaled dpas only supports FP8 (8-bit) and FP4 (4-bit) types for A/B
- // matrices. Return empty so callers can gracefully reject unsupported
- // types instead of aborting.
- return {};
- }
- return {kSize};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-SubgroupScaledMatrixMultiplyAcc::getSupportedN(Type type) const {
- return {16};
-}
-
#endif // MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE2_H
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
index ca16d8ebdddd5..6cd777519d950 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/IntelGpuXe3.h
@@ -7,314 +7,53 @@
//===----------------------------------------------------------------------===//
//
// \file
-// Xe3 uArch definition. Xe3 is the second generation of Intel Xe GPUs.
-// This file defines the uArch details for Xe3 and its derived architectures.
-// This includes Crescent Island Architecture.
+// Xe3 uArch definition. Xe3 is the third generation of Intel Xe GPUs and
+// includes Crescent Island (CRI). The base instruction set comes from the
+// shared Khronos OpenCL extensions defined in uArchBase.h; Xe3 only adds the
+// scaled DPAS extension. Subclass and override here only when a CRI-specific
+// instruction diverges from the SPIRV defaults.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
#define MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
#include "mlir/Dialect/XeGPU/uArch/uArchBase.h"
-#include "mlir/IR/BuiltinTypes.h"
-#include "mlir/IR/TypeUtilities.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/DebugLog.h"
-#include <string>
-
-using namespace mlir;
-using namespace mlir::xegpu::uArch;
namespace mlir {
namespace xegpu {
namespace uArch {
struct Xe3 : public uArch {
- Xe3(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry,
- const XeCoreInfo &xeCore)
- : uArch(kind, instructionRegistry), xeCore(xeCore) {}
+ Xe3(Kind kind, llvm::ArrayRef<const Instruction *> instructionRegistry)
+ : uArch(kind, instructionRegistry) {}
int getSubgroupSize() const override { return 16; }
unsigned getGeneralPackedFormatBitSize() const override { return 32; }
static bool classof(const uArch *u) {
return u->getKind() >= Kind::Xe3_First && u->getKind() <= Kind::Xe3_Last;
}
-
-protected:
- XeCoreInfo xeCore;
-};
-
-//===----------------------------------------------------------------------===//
-// uArch instructions
-//===----------------------------------------------------------------------===//
-struct CriSubgroup2DBlockStoreInstruction : public Instruction,
- public BlockIOInstructionInterface {
- CriSubgroup2DBlockStoreInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockStore,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockStore;
- }
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
- // Stores ignore the transform / transpose / upConv flags.
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
- bool /*hasTranspose*/ = false,
- bool /*upConv*/ = false) const override {
- const static int kHeight[] = {1, 2, 4, 8};
- const static int kWidth16[] = {16};
- const static int kWidth32[] = {16};
- const static int kCount[] = {1};
- const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
- if (elemByteSize == 1)
- return std::make_tuple(llvm::ArrayRef<int>(kWidth32),
- llvm::ArrayRef<int>(kHeight),
- llvm::ArrayRef<int>(kCount));
- else if (elemByteSize == 2 || elemByteSize == 4)
- return std::make_tuple(llvm::ArrayRef<int>(kWidth16),
- llvm::ArrayRef<int>(kHeight),
- llvm::ArrayRef<int>(kCount));
- return std::nullopt;
- }
-
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct CriSubgroup2DBlockLoadInstruction : public Instruction,
- public BlockIOInstructionInterface {
- CriSubgroup2DBlockLoadInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockLoad,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockLoad;
- }
-
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool hasTransform = false,
- bool hasTranspose = false,
- bool upConv = false) const override {
- static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
- static const int kHeightAtLeast8[] = {8, 16, 32};
- static const int kHeightAtLeast16[] = {16, 32};
- static const int kHeight32[] = {32};
- static const int kHeight64[] = {64};
-
- static const int kWidth64[] = {64};
- static const int kWidth32[] = {32};
- static const int kWidth16[] = {16};
- static const int kWidthAtLeast16[] = {16, 32};
- static const int kWidthAtLeast32[] = {32, 64};
- static const int kWidth8[] = {8};
-
- static const int32_t kCount1[] = {1};
- static const int32_t kCount2[] = {1, 2};
- static const int32_t kCount4[] = {1, 2, 4};
- static const int32_t kCount4Only[] = {4};
- // (elemBits, transform, transpose, upConvert)
- using Key = std::tuple<int, uint8_t, uint8_t, uint8_t>;
- // (widths, heights, counts)
- using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
- llvm::ArrayRef<int32_t>>;
- // The table is keyed on element bit width so sub-byte elements can be
- // expressed directly. 4-bit elements are packed two-per-byte, so their
- // widths (or heights, when transformed) are double the 8-bit rows.
- static const llvm::DenseMap<Key, Value> kMap = {
- {{8, false, false, false}, {kWidthAtLeast16, kHeightAtLeast1, kCount2}},
- {{8, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
- {{16, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
- {{32, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
- // Block Loads with Transform:
- {{8, true, false, false}, {kWidth16, kHeight32, kCount4}},
- {{16, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
- // Block Loads with Transpose:
- {{8, false, true, false}, {kWidth32, kHeightAtLeast16, kCount1}},
- {{16, false, true, false}, {kWidth16, kHeightAtLeast16, kCount1}},
- {{32, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
- // 4-bit elements (sub-byte):
- {{4, false, false, false}, {kWidthAtLeast32, kHeightAtLeast1, kCount2}},
- {{4, false, false, true}, {kWidth32, kHeightAtLeast8, kCount4Only}},
- {{4, true, false, false}, {kWidth16, kHeight64, kCount4}},
- {{4, false, true, false}, {kWidth64, kHeightAtLeast16, kCount1}}};
- int elemBitSize = elemTy.getIntOrFloatBitWidth();
- auto it = kMap.find({elemBitSize, hasTransform, hasTranspose, upConv});
- if (it != kMap.end())
- return it->second;
- return std::nullopt;
- }
-
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct CriSubgroup2DBlockPrefetchInstruction
- : public Instruction,
- public BlockIOInstructionInterface {
- CriSubgroup2DBlockPrefetchInstruction()
- : Instruction(InstructionKind::Subgroup2DBlockPrefetch,
- InstructionScope::Subgroup) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::Subgroup2DBlockPrefetch;
- }
- // Source :
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_buffer_prefetch.html#_add_a_new_section_6_15_x_sub_group_prefetch_functions
- std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
- getBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/ = false,
- bool /*hasTranspose*/ = false,
- bool /*upConv*/ = false) const override {
- static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
-
- static const int kWidth32[] = {32};
- static const int kWidth16[] = {16};
-
- static const int32_t kCount1[] = {1};
- static const int32_t kCount2[] = {1, 2};
- // elemBytes
- using Key = int;
- // (widths, heights, counts)
- using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
- llvm::ArrayRef<int32_t>>;
- static const llvm::DenseMap<Key, Value> kMap = {
- {1, {kWidth32, kHeightAtLeast1, kCount2}},
- {2, {kWidth16, kHeightAtLeast1, kCount2}},
- {4, {kWidth16, kHeightAtLeast1, kCount1}},
- };
- const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
- auto it = kMap.find(elemByteSize);
- if (it != kMap.end())
- return it->second;
- return std::nullopt;
- }
- int32_t getPackedFormatBitSize() const override { return 16; }
-};
-
-struct CriSubgroupMatrixMultiplyAcc : public Instruction,
- public MMAInstructionInterface {
- CriSubgroupMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
- unsigned packedFormatBitSizeB)
- : Instruction(InstructionKind::SubgroupMatrixMultiplyAcc,
- InstructionScope::Subgroup),
- packedFormatBitSizeA(packedFormatBitSizeA),
- packedFormatBitSizeB(packedFormatBitSizeB) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() ==
- InstructionKind::SubgroupMatrixMultiplyAcc;
- }
- // Source:
- // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_matrix_multiply_accumulate.html
-
- // Override all virtuals from MatrixOpInterface
- virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
- getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
- virtual llvm::SmallVector<Type, 8>
- getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
- virtual bool
- checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
- Type DType) override;
- virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedM(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedK(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedN(Type type) const override;
-
- unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
- unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
- bool isLaneLayoutRowMajorOrder() const override { return true; }
-
-protected:
- const unsigned packedFormatBitSizeA;
- const unsigned packedFormatBitSizeB;
-};
-
-struct CriSubgroupScaledMatrixMultiplyAcc : public Instruction,
- public MMAInstructionInterface {
- CriSubgroupScaledMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
- unsigned packedFormatBitSizeB)
- : Instruction(InstructionKind::SubgroupScaledMatrixMultiplyAcc,
- InstructionScope::Subgroup),
- packedFormatBitSizeA(packedFormatBitSizeA),
- packedFormatBitSizeB(packedFormatBitSizeB) {}
- static bool classof(const Instruction *B) {
- return B->getInstructionKind() ==
- InstructionKind::SubgroupScaledMatrixMultiplyAcc;
- }
- // Source:
- // https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_subgroup_scaled_matrix_multiply_accumulate.asciidoc
-
- // Override all virtuals from MatrixOpInterface
- virtual llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
- getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
- virtual llvm::SmallVector<Type, 8>
- getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) override;
- virtual bool
- checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
- Type DType) override;
- virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedM(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedK(Type type) const override;
- virtual llvm::SmallVector<uint32_t, 8>
- getSupportedN(Type type) const override;
-
- unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
- unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
- bool isLaneLayoutRowMajorOrder() const override { return true; }
-
-protected:
- const unsigned packedFormatBitSizeA;
- const unsigned packedFormatBitSizeB;
};
//===----------------------------------------------------------------------===//
// uArch instances
//===----------------------------------------------------------------------===//
-struct CRIuArch : public Xe3 {
- static llvm::ArrayRef<const Instruction *> getInstructionRegistryArr() {
- static const CriSubgroupMatrixMultiplyAcc dpasInst{16, 32};
- static const CriSubgroupScaledMatrixMultiplyAcc dpasMxInst{16, 32};
- static const CriSubgroup2DBlockLoadInstruction loadNdInst;
- static const CriSubgroup2DBlockStoreInstruction storeNdInst;
- static const CriSubgroup2DBlockPrefetchInstruction prefetchNdInst;
- static const SpirvStoreScatterInstruction storeScatterInst;
- static const SpirvLoadGatherInstruction loadGatherInst;
+struct CRIuArch final : public Xe3 {
+ static llvm::ArrayRef<const Instruction *> getCriInstructionRegistry() {
+ static const SubgroupMatrixMultiplyAcc dpasInst{16, 32};
+ static const SubgroupScaledMatrixMultiplyAcc dpasMxInst{16, 32};
+ static const Subgroup2DBlockLoadInstruction loadNdInst;
+ static const Subgroup2DBlockStoreInstruction storeNdInst;
+ static const Subgroup2DBlockPrefetchInstruction prefetchNdInst;
+ static const StoreScatterInstruction storeScatterInst;
+ static const LoadGatherInstruction loadGatherInst;
static const Instruction *arr[] = {
&dpasInst, &dpasMxInst, &loadNdInst, &storeNdInst,
&prefetchNdInst, &storeScatterInst, &loadGatherInst};
return arr;
}
- CRIuArch()
- : Xe3(Kind::CRI, getInstructionRegistryArr(),
- // Using bmg config as placeholder
- // TODO: Update to actual XeCore and SharedMemory config
- XeCoreInfo(8, SharedMemory(256 * 1024, 4), 8, 8) // xeCore
- ) {}
+ CRIuArch() : Xe3(Kind::CRI, getCriInstructionRegistry()) {}
static bool classof(const uArch *u) { return u->getKind() == Kind::CRI; }
static const uArch *getInstance() {
static const CRIuArch instance;
@@ -326,298 +65,4 @@ struct CRIuArch : public Xe3 {
} // namespace xegpu
} // namespace mlir
-//===----------------------------------------------------------------------===//
-// Instruction implementations
-//===----------------------------------------------------------------------===//
-
-inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
-CriSubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
- MMAOpndKind matrixType) {
- auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
- const llvm::SmallVector<uint32_t, 8> &b)
- -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
- llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
- for (unsigned x : a) {
- for (unsigned y : b) {
- result.emplace_back(x, y);
- }
- }
- return result;
- };
-
- auto M = getSupportedM(dataType);
- auto K = getSupportedK(dataType);
- auto N = getSupportedN(dataType);
- llvm::SmallVector<std::pair<unsigned, unsigned>, 16> resultMatrix;
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- resultMatrix = combineVectors(M, K);
- break;
- case MMAOpndKind::MatrixB:
- resultMatrix = combineVectors(K, N);
- break;
- case MMAOpndKind::MatrixC:
- case MMAOpndKind::MatrixD:
- resultMatrix = combineVectors(M, N);
- break;
- }
- return resultMatrix;
-}
-
-inline llvm::SmallVector<Type, 8>
-CriSubgroupMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
- MMAOpndKind matrixType) {
- Type bf16Type = BFloat16Type::get(&context);
- Type f16Type = Float16Type::get(&context);
- Type tf32Type = FloatTF32Type::get(&context);
- Type f32Type = Float32Type::get(&context);
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return {bf16Type, f16Type, tf32Type};
- case MMAOpndKind::MatrixB:
- return {bf16Type, f16Type, tf32Type};
- case MMAOpndKind::MatrixC:
- return {bf16Type, f16Type, f32Type};
- case MMAOpndKind::MatrixD:
- return {bf16Type, f16Type, f32Type};
- }
- return {};
-}
-
-inline bool CriSubgroupMatrixMultiplyAcc::checkSupportedTypes(Type AType,
- Type BType,
- Type CType,
- Type DType) {
- if (AType.isF16() || BType.isF16()) {
- if (AType != BType || (CType && (!CType.isF32() && !CType.isF16())) ||
- (!DType.isF32() && !DType.isF16())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (AType.isBF16() || BType.isBF16()) {
- if (AType != BType || (CType && (!CType.isF32() && !CType.isBF16())) ||
- (!DType.isF32() && !DType.isBF16())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (AType.isTF32() || BType.isTF32()) {
- if (AType != BType || (CType && (!CType.isF32() && !DType.isF32())) ||
- (!DType.isF32())) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
- } else if (!(AType.isInteger(2) || AType.isInteger(4) ||
- AType.isInteger(8)) &&
- !(BType.isInteger(2) || BType.isInteger(4) ||
- BType.isInteger(8))) {
- LDBG() << "Unsupported dpas combinations of Dst, Acc, A and B matrices.";
- return false;
- }
-
- return true;
-}
-
-inline bool CriSubgroupMatrixMultiplyAcc::checkSupportedShapesAndTypes(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
- auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
- auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
- auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
- return llvm::is_contained(supportedAShapes, AShape) &&
- llvm::is_contained(supportedBShapes, BShape) &&
- llvm::is_contained(supportedCShapes, CShape) &&
- llvm::is_contained(supportedDShapes, DShape) &&
- checkSupportedTypes(AType, BType, CType, DType);
-}
-
-inline bool CriSubgroupMatrixMultiplyAcc::validate(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
- BType, CType, DType);
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupMatrixMultiplyAcc::getSupportedM(Type type) const {
- return {1, 2, 3, 4, 5, 6, 7, 8};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupMatrixMultiplyAcc::getSupportedK(Type type) const {
- // assert if data type is not int or float type
- assert(type.isIntOrFloat() && "Matrix type must be int or float");
- auto bitWidth = type.getIntOrFloatBitWidth();
- uint32_t kSize = 0;
- switch (bitWidth) {
- case 2:
- kSize = 64;
- break;
- case 4:
- kSize = 64;
- break;
- case 8:
- kSize = 32;
- break;
- case 16:
- kSize = 16;
- break;
- case 32:
- kSize = 8;
- break;
- default:
- llvm_unreachable("Invalid int or float");
- }
- return {kSize};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupMatrixMultiplyAcc::getSupportedN(Type type) const {
- return {16};
-}
-
-//===----------------------------------------------------------------------===//
-// SubgroupScaledMatrixMultiplyAcc implementations
-//===----------------------------------------------------------------------===//
-
-inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
-CriSubgroupScaledMatrixMultiplyAcc::getSupportedShapes(Type dataType,
- MMAOpndKind matrixType) {
- auto combineVectors = [](const llvm::SmallVector<uint32_t, 8> &a,
- const llvm::SmallVector<uint32_t, 8> &b)
- -> llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> {
- llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
- for (unsigned x : a) {
- for (unsigned y : b) {
- result.emplace_back(x, y);
- }
- }
- return result;
- };
-
- // Avoid calling getSupportedK for C/D types (which are f32/bf16
- // and not valid for the K-dimension bit-width calculation).
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return combineVectors(getSupportedM(dataType), getSupportedK(dataType));
- case MMAOpndKind::MatrixB:
- return combineVectors(getSupportedK(dataType), getSupportedN(dataType));
- case MMAOpndKind::MatrixC:
- case MMAOpndKind::MatrixD:
- return combineVectors(getSupportedM(dataType), getSupportedN(dataType));
- }
- return {};
-}
-
-inline llvm::SmallVector<Type, 8>
-CriSubgroupScaledMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
- MMAOpndKind matrixType) {
- Type f8E4M3FNType = Float8E4M3FNType::get(&context);
- Type f8E5M2Type = Float8E5M2Type::get(&context);
- Type f4E2M1FNType = Float4E2M1FNType::get(&context);
- Type bf16Type = BFloat16Type::get(&context);
- Type f32Type = Float32Type::get(&context);
-
- switch (matrixType) {
- case MMAOpndKind::MatrixA:
- return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
- case MMAOpndKind::MatrixB:
- return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
- case MMAOpndKind::MatrixC:
- return {bf16Type, f32Type};
- case MMAOpndKind::MatrixD:
- return {bf16Type, f32Type};
- }
- return {};
-}
-
-inline bool CriSubgroupScaledMatrixMultiplyAcc::checkSupportedTypes(
- Type AType, Type BType, Type CType, Type DType) {
- auto isSupportedLowPrecision = [](Type t) {
- return t.isF8E4M3FN() || t.isF8E5M2() || llvm::isa<Float4E2M1FNType>(t);
- };
- auto isSupportedAccum = [](Type t) { return t.isF32() || t.isBF16(); };
-
- if (!isSupportedLowPrecision(AType) || !isSupportedLowPrecision(BType)) {
- LDBG() << "Unsupported scaled dpas: A and B must be FP8 or FP4 types.";
- return false;
- }
-
- // A and B must have the same bit width for K dimension compatibility.
- if (AType.getIntOrFloatBitWidth() != BType.getIntOrFloatBitWidth()) {
- LDBG() << "Unsupported scaled dpas: A and B must have the same bit width.";
- return false;
- }
-
- if (CType && !isSupportedAccum(CType)) {
- LDBG() << "Unsupported scaled dpas: C must be f32 or bf16.";
- return false;
- }
-
- if (!isSupportedAccum(DType)) {
- LDBG() << "Unsupported scaled dpas: D must be f32 or bf16.";
- return false;
- }
-
- return true;
-}
-
-inline bool CriSubgroupScaledMatrixMultiplyAcc::checkSupportedShapesAndTypes(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- auto supportedAShapes = getSupportedShapes(AType, MMAOpndKind::MatrixA);
- auto supportedBShapes = getSupportedShapes(BType, MMAOpndKind::MatrixB);
- auto supportedCShapes = getSupportedShapes(CType, MMAOpndKind::MatrixC);
- auto supportedDShapes = getSupportedShapes(DType, MMAOpndKind::MatrixD);
- return llvm::is_contained(supportedAShapes, AShape) &&
- llvm::is_contained(supportedBShapes, BShape) &&
- llvm::is_contained(supportedCShapes, CShape) &&
- llvm::is_contained(supportedDShapes, DShape) &&
- checkSupportedTypes(AType, BType, CType, DType);
-}
-
-inline bool CriSubgroupScaledMatrixMultiplyAcc::validate(
- std::pair<uint32_t, uint32_t> AShape, std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape, std::pair<uint32_t, uint32_t> DShape,
- Type AType, Type BType, Type CType, Type DType) {
- return checkSupportedShapesAndTypes(AShape, BShape, CShape, DShape, AType,
- BType, CType, DType);
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupScaledMatrixMultiplyAcc::getSupportedM(Type type) const {
- return {8};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupScaledMatrixMultiplyAcc::getSupportedK(Type type) const {
- assert(type.isIntOrFloat() && "Matrix type must be int or float");
- auto bitWidth = type.getIntOrFloatBitWidth();
- uint32_t kSize = 0;
- switch (bitWidth) {
- case 4:
- kSize = 64; // FP4: scale K by 4 (base 16-bit K=16 -> 64)
- break;
- case 8:
- kSize = 32; // FP8: scale K by 2 (base 16-bit K=16 -> 32)
- break;
- default:
- // Scaled dpas only supports FP8 (8-bit) and FP4 (4-bit) types for A/B
- // matrices. Return empty so callers can gracefully reject unsupported
- // types instead of aborting.
- return {};
- }
- return {kSize};
-}
-
-inline llvm::SmallVector<uint32_t, 8>
-CriSubgroupScaledMatrixMultiplyAcc::getSupportedN(Type type) const {
- return {16};
-}
-
#endif // MLIR_DIALECT_XEGPU_UARCH_INTELGPUXE3_H
diff --git a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
index d5239cc0fdf67..e1879bb3ffe1c 100644
--- a/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
+++ b/mlir/include/mlir/Dialect/XeGPU/uArch/uArchBase.h
@@ -7,19 +7,28 @@
//===----------------------------------------------------------------------===//
//
// \file
-// Base uArch definition for different architectures.
-//
+// Base uArch definition for different architectures, plus the SPIRV / Khronos
+// OpenCL extension instruction defaults shared across Intel Xe uArchs.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_XEGPU_UARCH_UARCHBASE_H
#define MLIR_DIALECT_XEGPU_UARCH_UARCHBASE_H
-#include <shared_mutex>
+#include <cassert>
+#include <optional>
#include <tuple>
+#include <utility>
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/TypeUtilities.h"
#include "mlir/IR/Types.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/DebugLog.h"
+#include "llvm/Support/ErrorHandling.h"
namespace mlir {
namespace xegpu {
@@ -38,7 +47,6 @@ enum class InstructionKind {
Subgroup2DBlockPrefetch, // Subgroup-level 2D block prefetch instruction
StoreScatter, // Lane-level store (scalar, vector)
LoadGather, // Lane-level load (scalar, vector)
- // @TODO: Add more instructions as needed
};
// A struct to represent basic information about an instruction.
@@ -80,63 +88,6 @@ struct Instruction {
// subgroup, workgroup, cluster)
};
-enum class RegisterFileMode : uint8_t { Small, Large };
-enum class RegisterFileType : uint8_t { GRF, ARF };
-
-// A struct to represent register file information
-struct RegisterFileInfo {
- // Constructor
- RegisterFileInfo() = default;
- RegisterFileInfo(uint32_t size,
- const llvm::SmallVector<RegisterFileMode, 4> &mode,
- const llvm::SmallVector<uint32_t, 4> &numRegs)
- : size(size), mode(mode), numRegsPerThreadPerMode(numRegs) {}
-
- // Get methods
- uint32_t getSize() const { return size; }
-
- const llvm::SmallVector<RegisterFileMode, 4> &getModes() const {
- return mode;
- }
-
- const llvm::SmallVector<uint32_t, 4> &getNumRegsPerThreadPerMode() const {
- return numRegsPerThreadPerMode;
- }
-
-protected:
- uint32_t size; // size per register in bits
- llvm::SmallVector<RegisterFileMode, 4>
- mode; // e.g., "small", "large" GRF modes
- llvm::SmallVector<uint32_t, 4>
- numRegsPerThreadPerMode; // number of registers per thread per mode
-};
-
-enum class CacheHierarchyLevel { L1 = 1, L2 = 2, L3 = 3 };
-
-// A struct to represent cache information
-struct CacheInfo {
- // Constructor
- CacheInfo() = default;
- CacheInfo(uint32_t size, uint32_t line_size,
- CacheHierarchyLevel hierarchy_level)
- : size(size), line_size(line_size), hierarchy_level(hierarchy_level) {}
-
- virtual ~CacheInfo() = default;
-
- // Get methods
- uint32_t getSize() const { return size; }
- uint32_t getLineSize() const { return line_size; }
- CacheHierarchyLevel getHierarchyLevel() const { return hierarchy_level; }
-
-protected:
- uint32_t size;
- uint32_t line_size;
- CacheHierarchyLevel hierarchy_level;
- // @TODO: Add more fields as needed (e.g., associativity, num_banks,
- // bank_size, num_ports, port_width, bank_conflicts, hierarchy_level,
- // latency, throughput, bandwidth)
-};
-
struct uArch {
enum class Kind {
// Xe2 family
@@ -157,33 +108,7 @@ struct uArch {
}
virtual ~uArch() = default;
Kind getKind() const { return kind; }
- StringRef getName() const { return getUArchName(kind); }
- StringRef getDescription() const { return getUArchDescription(kind); }
-
- static StringRef getUArchName(Kind k) {
- switch (k) {
- case Kind::PVC:
- return "pvc";
- case Kind::BMG:
- return "bmg";
- case Kind::CRI:
- return "cri";
- default:
- return "";
- }
- }
- static StringRef getUArchDescription(Kind k) {
- switch (k) {
- case Kind::PVC:
- return "Ponte Vecchio Architecture";
- case Kind::BMG:
- return "Battlemage Architecture";
- case Kind::CRI:
- return "Crescent Island Architecture";
- }
- llvm_unreachable("Unknown uArch::Kind");
- }
virtual int getSubgroupSize() const = 0;
virtual unsigned getGeneralPackedFormatBitSize() const = 0;
@@ -204,35 +129,6 @@ struct uArch {
instructionRegistry;
};
-// A struct to represent shared memory information
-struct SharedMemory {
- // Constructor
- SharedMemory(uint32_t size, uint32_t alignment)
- : size(size), alignment(alignment) {}
-
- // Get methods
- uint32_t getSize() const { return size; }
- uint32_t getAlignment() const { return alignment; }
-
-protected:
- uint32_t size; // in bytes
- uint32_t alignment; // in bytes
- // @TODO: Add more fields as needed (e.g., latency, throughput, bandwidth)
-};
-
-struct XeCoreInfo {
- uint32_t num_threads;
- SharedMemory shared_memory;
- uint32_t num_vector_units;
- uint32_t num_matrix_units;
-
- XeCoreInfo(uint32_t num_threads, const SharedMemory &shared_memory,
- uint32_t num_vector_units, uint32_t num_matrix_units)
- : num_threads(num_threads), shared_memory(shared_memory),
- num_vector_units(num_vector_units), num_matrix_units(num_matrix_units) {
- }
-};
-
//===----------------------------------------------------------------------===//
// Interfaces
//===----------------------------------------------------------------------===//
@@ -256,19 +152,7 @@ struct MMAInstructionInterface {
// this method.
virtual llvm::SmallVector<Type, 8>
getSupportedTypes(MLIRContext &context, MMAOpndKind matrixType) = 0;
- virtual bool
- checkSupportedShapesAndTypes(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) = 0;
- virtual bool checkSupportedTypes(Type AType, Type BType, Type CType,
- Type DType) = 0;
- virtual bool validate(std::pair<uint32_t, uint32_t> AShape,
- std::pair<uint32_t, uint32_t> BShape,
- std::pair<uint32_t, uint32_t> CShape,
- std::pair<uint32_t, uint32_t> DShape, Type AType,
- Type BType, Type CType, Type DType) = 0;
+
virtual llvm::SmallVector<uint32_t, 8> getSupportedM(Type type) const = 0;
virtual llvm::SmallVector<uint32_t, 8> getSupportedK(Type type) const = 0;
virtual llvm::SmallVector<uint32_t, 8> getSupportedN(Type type) const = 0;
@@ -282,52 +166,426 @@ struct MMAInstructionInterface {
// transform / transpose / upConv flags are only meaningful for loads; store
// and prefetch implementations ignore them.
struct BlockIOInstructionInterface {
+ using BlockShapes =
+ std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>;
+
// Returns the supported (widths, heights, counts) for the given element
// type, or std::nullopt if the element type is unsupported.
- virtual std::optional<
- std::tuple<llvm::ArrayRef<int>, llvm::ArrayRef<int>, llvm::ArrayRef<int>>>
+ std::optional<BlockShapes>
getBlockWidthHeightCount(Type elemTy, bool hasTransform = false,
bool hasTranspose = false,
- bool upConv = false) const = 0;
+ bool upConv = false) const {
+ return computeBlockWidthHeightCount(elemTy, hasTransform, hasTranspose,
+ upConv);
+ }
+
// Bit size of the packed format used by this block instruction.
virtual int32_t getPackedFormatBitSize() const = 0;
virtual ~BlockIOInstructionInterface() = default;
+
+protected:
+ virtual std::optional<BlockShapes>
+ computeBlockWidthHeightCount(Type elemTy, bool hasTransform,
+ bool hasTranspose, bool upConv) const = 0;
+};
+
+//===----------------------------------------------------------------------===//
+// Common virtual ISA instructions (shared across architectures)
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SPIRV
+//===----------------------------------------------------------------------===//
+template <InstructionKind Kind>
+struct ScatterIoInstructionInterface : public Instruction {
+ static_assert(Kind == InstructionKind::LoadGather ||
+ Kind == InstructionKind::StoreScatter,
+ "ScatterIO only supports LoadGather / StoreScatter");
+
+ ScatterIoInstructionInterface() : Instruction(Kind, InstructionScope::Lane) {}
+
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() == Kind;
+ }
+
+ virtual int32_t getMaxLaneAccessSizeBytes() const = 0;
+ virtual ~ScatterIoInstructionInterface() = default;
+};
+struct LoadGatherInstruction
+ : public ScatterIoInstructionInterface<InstructionKind::LoadGather> {
+ int32_t getMaxLaneAccessSizeBytes() const override { return 16; }
+};
+
+struct StoreScatterInstruction
+ : public ScatterIoInstructionInterface<InstructionKind::StoreScatter> {
+ int32_t getMaxLaneAccessSizeBytes() const override { return 16; }
};
//===----------------------------------------------------------------------===//
-// Common instructions (shared across architectures)
+// SPIRV / OpenCL-extension subgroup instructions
+//
+// These come from cl_intel_subgroup_2d_block_io and
+// cl_intel_subgroup_matrix_multiply_accumulate. A uArch only needs to
+// subclass when it diverges from the extension defaults.
//===----------------------------------------------------------------------===//
-struct LoadGatherInstructionInterface : public Instruction {
- LoadGatherInstructionInterface()
- : Instruction(InstructionKind::LoadGather, InstructionScope::Lane) {}
+struct Subgroup2DBlockStoreInstruction : public Instruction,
+ public BlockIOInstructionInterface {
+ Subgroup2DBlockStoreInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockStore,
+ InstructionScope::Subgroup) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockStore;
+ }
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
+ // Stores ignore the transform / transpose / upConv flags.
+ int32_t getPackedFormatBitSize() const override { return 16; }
+
+protected:
+ std::optional<BlockShapes>
+ computeBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/,
+ bool /*hasTranspose*/,
+ bool /*upConv*/) const override {
+ static const int kHeight[] = {1, 2, 4, 8};
+ static const int kWidth16[] = {16};
+ static const int kCount[] = {1};
+ const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
+ if (elemByteSize == 1 || elemByteSize == 2 || elemByteSize == 4)
+ return std::make_tuple(llvm::ArrayRef<int>(kWidth16),
+ llvm::ArrayRef<int>(kHeight),
+ llvm::ArrayRef<int>(kCount));
+ return std::nullopt;
+ }
+};
+
+struct Subgroup2DBlockLoadInstruction : public Instruction,
+ public BlockIOInstructionInterface {
+ Subgroup2DBlockLoadInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockLoad,
+ InstructionScope::Subgroup) {}
static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::LoadGather;
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockLoad;
}
- virtual int32_t getMaxLaneLoadSize(int32_t bitWidth) const = 0;
- virtual ~LoadGatherInstructionInterface() = default;
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_2d_block_io.html#_add_a_new_section_5_2_x_cl_intel_subgroup_2d_block_io
+ int32_t getPackedFormatBitSize() const override { return 16; }
+
+protected:
+ std::optional<BlockShapes>
+ computeBlockWidthHeightCount(Type elemTy, bool hasTransform,
+ bool hasTranspose, bool upConv) const override {
+ static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
+ static const int kHeightAtLeast8[] = {8, 16, 32};
+ static const int kHeightAtLeast16[] = {16, 32};
+ static const int kHeight32[] = {32};
+ static const int kHeight64[] = {64};
+
+ static const int kWidth64[] = {64};
+ static const int kWidth32[] = {32};
+ static const int kWidth16[] = {16};
+ static const int kWidthAtLeast16[] = {16, 32};
+ static const int kWidthAtLeast32[] = {32, 64};
+ static const int kWidth8[] = {8};
+
+ static const int32_t kCount1[] = {1};
+ static const int32_t kCount2[] = {1, 2};
+ static const int32_t kCount4[] = {1, 2, 4};
+ static const int32_t kCount4Only[] = {4};
+ // (elemBits, transform, transpose, upConvert)
+ using Key = std::tuple<int, uint8_t, uint8_t, uint8_t>;
+ // (widths, heights, counts)
+ using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
+ llvm::ArrayRef<int32_t>>;
+ // The table is keyed on element bit width so sub-byte elements can be
+ // expressed directly. 4-bit elements are packed two-per-byte, so their
+ // widths (or heights, when transformed) are double the 8-bit rows.
+ static const llvm::DenseMap<Key, Value> kMap = {
+ {{8, false, false, false}, {kWidthAtLeast16, kHeightAtLeast1, kCount2}},
+ {{8, false, false, true}, {kWidth16, kHeightAtLeast8, kCount4Only}},
+ {{16, false, false, false}, {kWidth16, kHeightAtLeast1, kCount2}},
+ {{32, false, false, false}, {kWidth16, kHeightAtLeast1, kCount1}},
+ // Block Loads with Transform:
+ {{8, true, false, false}, {kWidth16, kHeight32, kCount4}},
+ {{16, true, false, false}, {kWidth16, kHeightAtLeast16, kCount2}},
+ // Block Loads with Transpose:
+ {{8, false, true, false}, {kWidth32, kHeightAtLeast16, kCount1}},
+ {{16, false, true, false}, {kWidth16, kHeightAtLeast16, kCount1}},
+ {{32, false, true, false}, {kWidth8, kHeightAtLeast16, kCount1}},
+ // 4-bit elements (sub-byte):
+ {{4, false, false, false}, {kWidthAtLeast32, kHeightAtLeast1, kCount2}},
+ {{4, false, false, true}, {kWidth32, kHeightAtLeast8, kCount4Only}},
+ {{4, true, false, false}, {kWidth16, kHeight64, kCount4}},
+ {{4, false, true, false}, {kWidth64, kHeightAtLeast16, kCount1}}};
+ int elemBitSize = elemTy.getIntOrFloatBitWidth();
+ auto it = kMap.find({elemBitSize, hasTransform, hasTranspose, upConv});
+ if (it != kMap.end())
+ return it->second;
+ return std::nullopt;
+ }
};
-struct StoreScatterInstructionInterface : public Instruction {
- StoreScatterInstructionInterface()
- : Instruction(InstructionKind::StoreScatter, InstructionScope::Lane) {}
+struct Subgroup2DBlockPrefetchInstruction : public Instruction,
+ public BlockIOInstructionInterface {
+ Subgroup2DBlockPrefetchInstruction()
+ : Instruction(InstructionKind::Subgroup2DBlockPrefetch,
+ InstructionScope::Subgroup) {}
static bool classof(const Instruction *B) {
- return B->getInstructionKind() == InstructionKind::StoreScatter;
+ return B->getInstructionKind() == InstructionKind::Subgroup2DBlockPrefetch;
}
+ // Source :
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_buffer_prefetch.html#_add_a_new_section_6_15_x_sub_group_prefetch_functions
+ // Prefetches ignore the transform / transpose / upConv flags.
+ int32_t getPackedFormatBitSize() const override { return 16; }
- virtual int32_t getMaxLaneStoreSize(int32_t bitWidth) const = 0;
- virtual ~StoreScatterInstructionInterface() = default;
+protected:
+ std::optional<BlockShapes>
+ computeBlockWidthHeightCount(Type elemTy, bool /*hasTransform*/,
+ bool /*hasTranspose*/,
+ bool /*upConv*/) const override {
+ static const int kHeightAtLeast1[] = {1, 2, 4, 8, 16, 32};
+
+ static const int kWidth32[] = {32};
+ static const int kWidth16[] = {16};
+
+ static const int32_t kCount1[] = {1};
+ static const int32_t kCount2[] = {1, 2};
+ // elemBytes
+ using Key = int;
+ // (widths, heights, counts)
+ using Value = std::tuple<llvm::ArrayRef<int32_t>, llvm::ArrayRef<int32_t>,
+ llvm::ArrayRef<int32_t>>;
+ static const llvm::DenseMap<Key, Value> kMap = {
+ {1, {kWidth32, kHeightAtLeast1, kCount2}},
+ {2, {kWidth16, kHeightAtLeast1, kCount2}},
+ {4, {kWidth16, kHeightAtLeast1, kCount1}},
+ };
+ const int elemByteSize = elemTy.getIntOrFloatBitWidth() / 8;
+ auto it = kMap.find(elemByteSize);
+ if (it != kMap.end())
+ return it->second;
+ return std::nullopt;
+ }
};
-struct SpirvLoadGatherInstruction : public LoadGatherInstructionInterface {
- int32_t getMaxLaneLoadSize(int32_t bitWidth) const override { return 16; }
+struct SubgroupMatrixMultiplyAcc : public Instruction,
+ public MMAInstructionInterface {
+ SubgroupMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
+ unsigned packedFormatBitSizeB)
+ : Instruction(InstructionKind::SubgroupMatrixMultiplyAcc,
+ InstructionScope::Subgroup),
+ packedFormatBitSizeA(packedFormatBitSizeA),
+ packedFormatBitSizeB(packedFormatBitSizeB) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() ==
+ InstructionKind::SubgroupMatrixMultiplyAcc;
+ }
+ // Source:
+ // https://registry.khronos.org/OpenCL/extensions/intel/cl_intel_subgroup_matrix_multiply_accumulate.html
+
+ llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+ getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
+ llvm::SmallVector<Type, 8> getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) override;
+
+ llvm::SmallVector<uint32_t, 8> getSupportedM(Type type) const override;
+ llvm::SmallVector<uint32_t, 8> getSupportedK(Type type) const override;
+ llvm::SmallVector<uint32_t, 8> getSupportedN(Type type) const override;
+
+ unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
+ unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
+ bool isLaneLayoutRowMajorOrder() const override { return true; }
+
+protected:
+ const unsigned packedFormatBitSizeA;
+ const unsigned packedFormatBitSizeB;
};
-struct SpirvStoreScatterInstruction : public StoreScatterInstructionInterface {
- int32_t getMaxLaneStoreSize(int32_t bitWidth) const override { return 16; }
+struct SubgroupScaledMatrixMultiplyAcc : public Instruction,
+ public MMAInstructionInterface {
+ SubgroupScaledMatrixMultiplyAcc(unsigned packedFormatBitSizeA,
+ unsigned packedFormatBitSizeB)
+ : Instruction(InstructionKind::SubgroupScaledMatrixMultiplyAcc,
+ InstructionScope::Subgroup),
+ packedFormatBitSizeA(packedFormatBitSizeA),
+ packedFormatBitSizeB(packedFormatBitSizeB) {}
+ static bool classof(const Instruction *B) {
+ return B->getInstructionKind() ==
+ InstructionKind::SubgroupScaledMatrixMultiplyAcc;
+ }
+ // Source:
+ // https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_subgroup_scaled_matrix_multiply_accumulate.asciidoc
+
+ llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+ getSupportedShapes(Type dataType, MMAOpndKind matrixType) override;
+ llvm::SmallVector<Type, 8> getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) override;
+
+ llvm::SmallVector<uint32_t, 8> getSupportedM(Type type) const override;
+ llvm::SmallVector<uint32_t, 8> getSupportedK(Type type) const override;
+ llvm::SmallVector<uint32_t, 8> getSupportedN(Type type) const override;
+
+ unsigned getPackedFormatBitSizeA() const { return packedFormatBitSizeA; }
+ unsigned getPackedFormatBitSizeB() const { return packedFormatBitSizeB; }
+ bool isLaneLayoutRowMajorOrder() const override { return true; }
+
+protected:
+ const unsigned packedFormatBitSizeA;
+ const unsigned packedFormatBitSizeB;
};
+//===----------------------------------------------------------------------===//
+// Inline implementations
+//===----------------------------------------------------------------------===//
+
+namespace util {
+inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+crossProduct(const llvm::SmallVector<uint32_t, 8> &a,
+ const llvm::SmallVector<uint32_t, 8> &b) {
+ llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16> result;
+ for (unsigned x : a)
+ for (unsigned y : b)
+ result.emplace_back(x, y);
+ return result;
+}
+} // namespace util
+
+inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+SubgroupMatrixMultiplyAcc::getSupportedShapes(Type dataType,
+ MMAOpndKind matrixType) {
+ auto M = getSupportedM(dataType);
+ auto K = getSupportedK(dataType);
+ auto N = getSupportedN(dataType);
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ return util::crossProduct(M, K);
+ case MMAOpndKind::MatrixB:
+ return util::crossProduct(K, N);
+ case MMAOpndKind::MatrixC:
+ case MMAOpndKind::MatrixD:
+ return util::crossProduct(M, N);
+ }
+ return {};
+}
+
+inline llvm::SmallVector<Type, 8>
+SubgroupMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) {
+ Type bf16Type = BFloat16Type::get(&context);
+ Type f16Type = Float16Type::get(&context);
+ Type tf32Type = FloatTF32Type::get(&context);
+ Type f32Type = Float32Type::get(&context);
+
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ case MMAOpndKind::MatrixB:
+ return {bf16Type, f16Type, tf32Type};
+ case MMAOpndKind::MatrixC:
+ case MMAOpndKind::MatrixD:
+ return {bf16Type, f16Type, f32Type};
+ }
+ return {};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupMatrixMultiplyAcc::getSupportedM(Type type) const {
+ return {1, 2, 3, 4, 5, 6, 7, 8};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupMatrixMultiplyAcc::getSupportedK(Type type) const {
+ assert(type.isIntOrFloat() && "Matrix type must be int or float");
+ auto bitWidth = type.getIntOrFloatBitWidth();
+ uint32_t kSize = 0;
+ switch (bitWidth) {
+ case 4:
+ kSize = 64;
+ break;
+ case 8:
+ kSize = 32;
+ break;
+ case 16:
+ kSize = 16;
+ break;
+ case 32:
+ kSize = 8;
+ break;
+ default:
+ llvm_unreachable("Invalid int or float");
+ }
+ return {kSize};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupMatrixMultiplyAcc::getSupportedN(Type type) const {
+ return {16};
+}
+
+inline llvm::SmallVector<std::pair<uint32_t, uint32_t>, 16>
+SubgroupScaledMatrixMultiplyAcc::getSupportedShapes(Type dataType,
+ MMAOpndKind matrixType) {
+ // Avoid calling getSupportedK for C/D types (which are f32/bf16
+ // and not valid for the K-dimension bit-width calculation).
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ return util::crossProduct(getSupportedM(dataType), getSupportedK(dataType));
+ case MMAOpndKind::MatrixB:
+ return util::crossProduct(getSupportedK(dataType), getSupportedN(dataType));
+ case MMAOpndKind::MatrixC:
+ case MMAOpndKind::MatrixD:
+ return util::crossProduct(getSupportedM(dataType), getSupportedN(dataType));
+ }
+ return {};
+}
+
+inline llvm::SmallVector<Type, 8>
+SubgroupScaledMatrixMultiplyAcc::getSupportedTypes(MLIRContext &context,
+ MMAOpndKind matrixType) {
+ Type f8E4M3FNType = Float8E4M3FNType::get(&context);
+ Type f8E5M2Type = Float8E5M2Type::get(&context);
+ Type f4E2M1FNType = Float4E2M1FNType::get(&context);
+ Type bf16Type = BFloat16Type::get(&context);
+ Type f32Type = Float32Type::get(&context);
+
+ switch (matrixType) {
+ case MMAOpndKind::MatrixA:
+ case MMAOpndKind::MatrixB:
+ return {f8E4M3FNType, f8E5M2Type, f4E2M1FNType};
+ case MMAOpndKind::MatrixC:
+ case MMAOpndKind::MatrixD:
+ return {bf16Type, f32Type};
+ }
+ return {};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupScaledMatrixMultiplyAcc::getSupportedM(Type type) const {
+ return {8};
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupScaledMatrixMultiplyAcc::getSupportedK(Type type) const {
+ assert(type.isIntOrFloat() && "Matrix type must be int or float");
+ auto bitWidth = type.getIntOrFloatBitWidth();
+ switch (bitWidth) {
+ case 4:
+ return {64}; // FP4: scale K by 4 (base 16-bit K=16 -> 64)
+ case 8:
+ return {32}; // FP8: scale K by 2 (base 16-bit K=16 -> 32)
+ default:
+ // Scaled dpas only supports FP8 (8-bit) and FP4 (4-bit) types for A/B
+ // matrices. Return empty so callers can gracefully reject unsupported
+ // types instead of aborting.
+ return {};
+ }
+}
+
+inline llvm::SmallVector<uint32_t, 8>
+SubgroupScaledMatrixMultiplyAcc::getSupportedN(Type type) const {
+ return {16};
+}
+
} // namespace uArch
} // namespace xegpu
} // namespace mlir
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPULayoutImpl.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPULayoutImpl.cpp
index 574eeabac1836..61cd253508357 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPULayoutImpl.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPULayoutImpl.cpp
@@ -1710,13 +1710,11 @@ xegpu::DistributeLayoutAttr xegpu::setupLoadGatherAnchorLayout(
const int subgroupSize = uArch->getSubgroupSize();
ArrayRef<int64_t> resShape = resVecTy.getShape();
auto context = resVecTy.getContext();
- auto elemBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
- const auto *uArchInstruction =
- dyn_cast<xegpu::uArch::LoadGatherInstructionInterface>(
- uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
- int maxChunkSize = std::min(
- uArchInstruction->getMaxLaneLoadSize(elemBitWidth), contigChunkSize);
+ const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
+ uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
+ int maxChunkSize =
+ std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
return setupGenericLoadAnchorLayout(layoutKind, context, consumerLayout,
maxChunkSize, resShape, subgroupSize);
@@ -1733,13 +1731,11 @@ xegpu::setupLoadMatrixAnchorLayout(xegpu::LayoutKind layoutKind,
const int subgroupSize = uArch->getSubgroupSize();
ArrayRef<int64_t> resShape = resVecTy.getShape();
auto context = resVecTy.getContext();
- auto elemBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
- const auto *uArchInstruction =
- dyn_cast<xegpu::uArch::LoadGatherInstructionInterface>(
- uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
- int maxChunkSize = std::min(
- uArchInstruction->getMaxLaneLoadSize(elemBitWidth), contigChunkSize);
+ const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
+ uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
+ int maxChunkSize =
+ std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
return setupGenericLoadAnchorLayout(layoutKind, context, consumerLayout,
maxChunkSize, resShape, subgroupSize);
}
@@ -1786,13 +1782,12 @@ xegpu::setupStoreScatterAnchorLayout(xegpu::LayoutKind layoutKind,
const int subgroupSize = uArch->getSubgroupSize();
ArrayRef<int64_t> srcShape = srcVecTy.getShape();
auto context = srcVecTy.getContext();
- auto elemBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
const auto *uArchInstruction =
- dyn_cast<xegpu::uArch::StoreScatterInstructionInterface>(
+ dyn_cast<xegpu::uArch::StoreScatterInstruction>(
uArch->getInstruction(xegpu::uArch::InstructionKind::StoreScatter));
- int maxChunkSize = std::min(
- uArchInstruction->getMaxLaneStoreSize(elemBitWidth), contigChunkSize);
+ int maxChunkSize =
+ std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
return setupGenericStoreAnchorLayout(layoutKind, context, maxChunkSize,
srcShape, subgroupSize);
}
@@ -1806,13 +1801,12 @@ xegpu::setupStoreMatrixAnchorLayout(xegpu::LayoutKind layoutKind,
const int subgroupSize = uArch->getSubgroupSize();
ArrayRef<int64_t> srcShape = srcVecTy.getShape();
auto context = srcVecTy.getContext();
- auto elemBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
const auto *uArchInstruction =
- dyn_cast<xegpu::uArch::StoreScatterInstructionInterface>(
+ dyn_cast<xegpu::uArch::StoreScatterInstruction>(
uArch->getInstruction(xegpu::uArch::InstructionKind::StoreScatter));
- int maxChunkSize = std::min(
- uArchInstruction->getMaxLaneStoreSize(elemBitWidth), contigChunkSize);
+ int maxChunkSize =
+ std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
return setupGenericStoreAnchorLayout(layoutKind, context, maxChunkSize,
srcShape, subgroupSize);
@@ -1831,13 +1825,13 @@ xegpu::setupStoreMatrixAnchorLayout(xegpu::LayoutKind layoutKind,
/// - Otherwise a standard scatter-style factorization is computed via
/// `computeScatterIOLaneLayoutAndData`, bounded by `maxChunkSize` — the
/// per-lane load width reported by the uArch's LoadGather instruction
-/// (`getMaxLaneLoadSize`).
+/// (`getMaxLaneAccessSizeBytes`).
///
std::optional<xegpu::DistributeLayoutAttr>
xegpu::completeScatterLoadLaneLayoutFromInstData(
xegpu::DistributeLayoutAttr specifiedLayout,
xegpu::DistributeLayoutAttr consumerLayout, Type elemTy,
- const xegpu::uArch::LoadGatherInstructionInterface *uArchInstruction,
+ const xegpu::uArch::LoadGatherInstruction *uArchInstruction,
const int subgroupSize) {
if (!specifiedLayout)
return specifiedLayout;
@@ -1851,8 +1845,7 @@ xegpu::completeScatterLoadLaneLayoutFromInstData(
// Reuse the load-side setup with inst_data as the destination shape.
auto *context = specifiedLayout.getContext();
- auto elemBitWidth = elemTy.getIntOrFloatBitWidth();
- int maxChunkSize = uArchInstruction->getMaxLaneLoadSize(elemBitWidth);
+ int maxChunkSize = uArchInstruction->getMaxLaneAccessSizeBytes();
if (consumerLayout) {
auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
@@ -1876,7 +1869,7 @@ xegpu::completeScatterLoadLaneLayoutFromInstData(
std::optional<xegpu::DistributeLayoutAttr>
xegpu::completeScatterStoreLaneLayoutFromInstData(
xegpu::DistributeLayoutAttr specifiedLayout, Type elemTy,
- const xegpu::uArch::StoreScatterInstructionInterface *uArchInstruction,
+ const xegpu::uArch::StoreScatterInstruction *uArchInstruction,
const int subgroupSize) {
if (!specifiedLayout)
return specifiedLayout;
@@ -1890,8 +1883,7 @@ xegpu::completeScatterStoreLaneLayoutFromInstData(
// Reuse the store-side setup with inst_data as the source shape.
auto *context = specifiedLayout.getContext();
- auto elemBitWidth = elemTy.getIntOrFloatBitWidth();
- int maxChunkSize = uArchInstruction->getMaxLaneStoreSize(elemBitWidth);
+ int maxChunkSize = uArchInstruction->getMaxLaneAccessSizeBytes();
auto [defLaneLayout, defLaneData] = computeScatterIOLaneLayoutAndData(
specifiedInstData, subgroupSize, maxChunkSize);
if (!isValidLaneLayout(specifiedInstData, defLaneLayout, defLaneData))
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
index 1ed418d446886..1bf04f1f095a8 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPeepHoleOptimizer.cpp
@@ -106,8 +106,9 @@ static bool canBeOptimizedForTranspose(xegpu::TensorDescType tdescType) {
/// Check if a tensor desc type can be optimized for transpose, if so return the
/// new optimized tensor desc type with a valid transpose layout.
-static xegpu::TensorDescType tryOptimize(xegpu::TensorDescType tdescType,
- const uArch *targetuArch) {
+static xegpu::TensorDescType
+tryOptimize(xegpu::TensorDescType tdescType,
+ const xegpu::uArch::uArch *targetuArch) {
if (!canBeOptimizedForTranspose(tdescType))
return tdescType;
auto laneData = getMaybeLaneData(tdescType)
@@ -124,8 +125,10 @@ static xegpu::TensorDescType tryOptimize(xegpu::TensorDescType tdescType,
Type newElemTy = IntegerType::get(tdescType.getContext(), newBitWidth);
// Supported shape is the max transpose shape that can be supported by
// hardware that is less than or equal to required shape.
- auto *blockLoadTarget = dyn_cast<Subgroup2DBlockLoadInstruction>(
- targetuArch->getInstruction(InstructionKind::Subgroup2DBlockLoad));
+ auto *blockLoadTarget =
+ dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
+ targetuArch->getInstruction(
+ xegpu::uArch::InstructionKind::Subgroup2DBlockLoad));
auto maybeHWParams = blockLoadTarget->getBlockWidthHeightCount(
newElemTy, /** has transform */ false, /** has transpose */ true);
// If no HW params found, return the original type.
@@ -261,7 +264,7 @@ class XeGPUCreateNdDescOpPattern final
chipStr.value() == "cri") &&
"Expecting target chip to be pvc, bmg or cri for transpose "
"optimization.");
- const uArch *targetuArch = xegpu::uArch::getUArch(chipStr.value());
+ const auto *targetuArch = xegpu::uArch::getUArch(chipStr.value());
auto convertType = tryOptimize(tdescTy, targetuArch);
if (convertType == tdescTy)
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
index 57cf1d0669cb1..64d0d8063b7ff 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUPropagateLayout.cpp
@@ -452,7 +452,7 @@ void LayoutInfoPropagation::visitPrefetchNdOp(
ArrayRef<const LayoutInfoLattice *> results) {
LayoutInfo prefetchLayout;
- const uArch *uArch = getUArch(getChipStr(prefetch).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(prefetch).value_or(""));
if (!uArch)
return;
xegpu::DistributeLayoutAttr anchorLayout = prefetch.getLayoutAttr();
@@ -518,7 +518,8 @@ void LayoutInfoPropagation::visitVectorMultiReductionOp(
VectorType sourceTy = reduction.getSourceVectorType();
SmallVector<int64_t> reductionDims(reduction.getReductionDims());
- const uArch *uArch = getUArch(xegpu::getChipStr(reduction).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(reduction).value_or(""));
if (!uArch)
return;
@@ -556,7 +557,8 @@ void LayoutInfoPropagation::visitVectorReductionOp(
ArrayRef<const LayoutInfoLattice *> results) {
VectorType sourceTy = reduction.getSourceVectorType();
- const uArch *uArch = getUArch(xegpu::getChipStr(reduction).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(reduction).value_or(""));
if (!uArch)
return;
@@ -631,7 +633,7 @@ void LayoutInfoPropagation::visitDpasOp(
LayoutInfo dpasBLayout;
LayoutInfo dpasCDLayout;
- const uArch *uArch = getUArch(getChipStr(dpas).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(dpas).value_or(""));
if (!uArch)
return;
VectorType aTy = dpas.getLhsType();
@@ -725,7 +727,7 @@ void LayoutInfoPropagation::visitDpasMxOp(
xegpu::DistributeLayoutAttr anchorLayoutB = dpasMx.getLayoutBAttr();
xegpu::DistributeLayoutAttr anchorLayoutCD = dpasMx.getLayoutCdAttr();
- const uArch *uArch = getUArch(getChipStr(dpasMx).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(dpasMx).value_or(""));
if (!uArch)
return;
@@ -866,7 +868,7 @@ void LayoutInfoPropagation::visitStoreNdOp(
xegpu::StoreNdOp store, ArrayRef<LayoutInfoLattice *> operands,
ArrayRef<const LayoutInfoLattice *> results) {
LayoutInfo storeLayout;
- const uArch *uArch = getUArch(getChipStr(store).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(store).value_or(""));
if (!uArch)
return;
xegpu::DistributeLayoutAttr anchorLayout = store.getLayoutAttr();
@@ -921,7 +923,7 @@ void LayoutInfoPropagation::visitLoadNdOp(
ArrayRef<const LayoutInfoLattice *> results) {
LayoutInfo loadLayout;
- const uArch *uArch = getUArch(getChipStr(load).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(load).value_or(""));
if (!uArch)
return;
LayoutInfo valueLayout = results[0]->getValue();
@@ -1061,7 +1063,8 @@ void LayoutInfoPropagation::visitVectorBitcastOp(
auto consumerLayoutAttr =
dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
- const uArch *uArch = getUArch(xegpu::getChipStr(bitcast).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(bitcast).value_or(""));
if (!uArch)
return;
auto requiredResLayoutAttr = setupBitCastResultLayout(
@@ -1095,7 +1098,8 @@ void LayoutInfoPropagation::visitVectorInterleaveOp(
auto consumerLayoutAttr =
dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
- const uArch *uArch = getUArch(xegpu::getChipStr(interleave).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(interleave).value_or(""));
if (!uArch)
return;
@@ -1150,8 +1154,8 @@ void LayoutInfoPropagation::visitInsertStridedSliceOp(
auto consumerLayoutAttr =
dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
- const uArch *uArch =
- getUArch(xegpu::getChipStr(insertStridedSlice).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(
+ xegpu::getChipStr(insertStridedSlice).value_or(""));
if (!uArch)
return;
@@ -1174,7 +1178,7 @@ void LayoutInfoPropagation::visitLoadGatherOp(
ArrayRef<const LayoutInfoLattice *> results) {
xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
xegpu::DistributeLayoutAttr anchorLayoutAttr = load.getLayoutAttr();
- const uArch *uArch = getUArch(getChipStr(load).value_or(""));
+ const auto *uArch = xegpu::uArch::getUArch(getChipStr(load).value_or(""));
if (!uArch)
return;
VectorType resVecTy = load.getValueType();
@@ -1191,7 +1195,7 @@ void LayoutInfoPropagation::visitLoadGatherOp(
if (layoutKind == xegpu::LayoutKind::InstData &&
!consumerLayoutAttr.getEffectiveLaneLayoutAsInt().empty()) {
const auto uArchInstruction =
- dyn_cast<xegpu::uArch::LoadGatherInstructionInterface>(
+ dyn_cast<xegpu::uArch::LoadGatherInstruction>(
uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
if (!uArchInstruction)
return;
@@ -1238,7 +1242,8 @@ void LayoutInfoPropagation::visitStoreScatterOp(
xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
xegpu::DistributeLayoutAttr anchorLayoutAttr = storeScatter.getLayoutAttr();
- const uArch *uArch = getUArch(getChipStr(storeScatter).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(getChipStr(storeScatter).value_or(""));
if (!uArch)
return;
VectorType srcVecTy = storeScatter.getValueType();
@@ -1248,9 +1253,8 @@ void LayoutInfoPropagation::visitStoreScatterOp(
requiredAnchorLayoutAttr = anchorLayoutAttr;
if (layoutKind == xegpu::LayoutKind::InstData) {
const auto uArchInstruction =
- dyn_cast<xegpu::uArch::StoreScatterInstructionInterface>(
- uArch->getInstruction(
- xegpu::uArch::InstructionKind::StoreScatter));
+ dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
+ xegpu::uArch::InstructionKind::StoreScatter));
if (!uArchInstruction)
return;
auto completed = xegpu::completeScatterStoreLaneLayoutFromInstData(
@@ -1308,7 +1312,8 @@ void LayoutInfoPropagation::visitLoadMatrixOp(
if (!hasParamsOfLayoutKind(anchorLayout)) {
VectorType resVecTy =
llvm::cast<VectorType>(loadMatrixOp.getRes().getType());
- const uArch *uArch = getUArch(getChipStr(loadMatrixOp).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(getChipStr(loadMatrixOp).value_or(""));
if (!uArch)
return;
int chunkSize =
@@ -1326,16 +1331,16 @@ void LayoutInfoPropagation::visitStoreMatrixOp(
xegpu::DistributeLayoutAttr anchorLayoutAttr = storeMatrix.getLayoutAttr();
LayoutInfo layout;
VectorType srcVecTy = llvm::cast<VectorType>(storeMatrix.getData().getType());
- const uArch *uArch = getUArch(getChipStr(storeMatrix).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(getChipStr(storeMatrix).value_or(""));
if (!uArch)
return;
if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
requiredAnchorLayoutAttr = anchorLayoutAttr;
if (layoutKind == xegpu::LayoutKind::InstData) {
const auto uArchInstruction =
- dyn_cast<xegpu::uArch::StoreScatterInstructionInterface>(
- uArch->getInstruction(
- xegpu::uArch::InstructionKind::StoreScatter));
+ dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
+ xegpu::uArch::InstructionKind::StoreScatter));
if (!uArchInstruction)
return;
auto completed = xegpu::completeScatterStoreLaneLayoutFromInstData(
diff --git a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
index 766754af76cb7..23d3877ea63dd 100644
--- a/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
+++ b/mlir/lib/Dialect/XeGPU/Transforms/XeGPUSgToLaneDistribute.cpp
@@ -152,7 +152,8 @@ struct SgToLaneLoadNd : public OpConversionPattern<xegpu::LoadNdOp> {
if (op.getTensorDescType().getLayout() != layout)
return rewriter.notifyMatchFailure(
op, "conflicting layout attributes on tensor descriptor and anchor");
- auto uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (!uArch)
return rewriter.notifyMatchFailure(
op, "xegpu::LoadNdOp require target attribute attached to "
@@ -259,7 +260,8 @@ struct SgToLaneDpas : public OpConversionPattern<xegpu::DpasOp> {
"lane layout");
// Validate bit widths match uArch packed format requirements
- const uArch *uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (uArch) {
const auto *uArchInstruction =
dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(
@@ -543,7 +545,8 @@ struct SgToLaneVectorReduction
// Get the subgroup size from the layout.
int64_t sgSize = layout.getEffectiveLaneLayoutAsInt()[0];
- const uArch *uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (!uArch)
return rewriter.notifyMatchFailure(
op, "xegpu::ReductionOp require target attribute attached to "
@@ -1214,7 +1217,8 @@ struct SgToLaneVectorExtractStridedSlice
return rewriter.notifyMatchFailure(
op, "only single dimension distribution is supported");
int64_t distDim = distributedDims[0];
- const uArch *uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (!uArch)
return rewriter.notifyMatchFailure(
op, "target attribute required to determine subgroup size");
@@ -1418,7 +1422,8 @@ struct SgToLaneVectorInsertStridedSlice
op, "only single dimension distribution is supported");
int64_t destDistDim = destDistributedDims[0];
- const uArch *uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (!uArch)
return rewriter.notifyMatchFailure(
op, "target attribute required to determine subgroup size");
@@ -1681,7 +1686,8 @@ struct SgToLaneDpasMx : public OpConversionPattern<xegpu::DpasMxOp> {
LogicalResult
matchAndRewrite(xegpu::DpasMxOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
- const uArch *uArch = getUArch(xegpu::getChipStr(op).value_or(""));
+ const auto *uArch =
+ xegpu::uArch::getUArch(xegpu::getChipStr(op).value_or(""));
if (!uArch)
return failure();
if (!uArch->isSupportedInstruction(
More information about the Mlir-commits
mailing list