Skip to content

[mlir][xegpu] Add definitons of MatrixDescType and related ops. #153273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
31 changes: 31 additions & 0 deletions mlir/include/mlir/Dialect/XeGPU/IR/XeGPUAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -527,4 +527,35 @@ def XeGPU_RangeAttr : XeGPUAttr<"Range", "range"> {
let genVerifyDecl = 1;
}

def XeGPU_MemLayoutAttr : XeGPUAttr<"MemLayout", "mem_layout"> {
let summary = [{Specifies memory layouts with named attributes.}];

let description = [{
This attribute stores a collection of named attributes that describe
memory layout properties such as stride, block, etc.
}];

let parameters = (ins "DictionaryAttr": $attrs);
let hasCustomAssemblyFormat = 1;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove extra line


let extraClassDeclaration = [{
/// Get a specific attribute by name
Attribute getAttr(StringRef name) const {
return getAttrs().get(name);
}

/// Check if a specific attribute exists
bool hasAttr(StringRef name) const {
return getAttrs().contains(name);
}

ArrayAttr getStrides() {
return getAttrs().getAs<ArrayAttr>("stride");
}

}];

}

#endif // MLIR_DIALECT_XEGPU_IR_XEGPUATTRS_TD
146 changes: 146 additions & 0 deletions mlir/include/mlir/Dialect/XeGPU/IR/XeGPUOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1101,4 +1101,150 @@ def XeGPU_ConvertLayoutOp: XeGPU_Op<"convert_layout", [Pure, AllTypesMatch<["sou
let hasCanonicalizer = 1;
}

def isSharedPred : CPred<"isSharedMemory(llvm::cast<mlir::MemRefType>($_self))">;
class StaticShared1DMemRefOf<list<Type> allowedTypes> :
ConfinedType<MemRefRankOf<allowedTypes, [1]>, [HasStaticShapePred, isSharedPred],
"statically shaped " # MemRefOf<allowedTypes>.summary # " for shared memory",
"mlir::MemRefType">;

class SizeInBits<string name> :
StrFunc<"llvm::cast<mlir::ShapedType>($" # name # ".getType()).getNumElements()"
"*llvm::cast<mlir::ShapedType>($" # name # ".getType()).getElementTypeBitWidth()">;
class AllMemSizesMatch<list<string> names> :
AllMatchSameOperatorTrait<names, SizeInBits<"_self">.result,
"size in bits">;

def XeGPU_CreateMemDescOp: XeGPU_Op<"create_mem_desc", [Pure,
AllMemSizesMatch<["source", "mem_desc"]>]> {
let summary = "Create a memory descriptor.";
let description = [{
Creates a memory descriptor from a shared local memory (SLM) buffer, and xegpu
specific memory layout. The resulting memory descriptor has to have the same size
as the underlying shared local memory.

Arguments:
- `source` : a 1D statically shaped memref with element type i8, representing the raw SLM buffer.
Results:
- `mem_desc` : the memory descriptor.
}];
let arguments = (ins StaticShared1DMemRefOf<[I8]>:$source);
let results = (outs XeGPU_MemDesc:$mem_desc);
let assemblyFormat = "$source prop-dict attr-dict `` `:` type($source) `->` qualified(type($mem_desc))";
}

def XeGPU_LoadMatrixOp: XeGPU_Op<"load_matrix", [MemoryEffects<[MemRead]>,
AllElementTypesMatch<["mem_desc", "res"]>,
AllRanksMatch<["mem_desc", "res"]>]> {
let arguments = (ins XeGPU_MemDesc:$mem_desc,
Variadic<Index>: $offsets,
DenseI64ArrayAttr: $const_offsets,
OptionalAttr<LayoutTrait>:$layout
);
let results = (outs XeGPU_ValueType:$res);
let assemblyFormat = [{
$mem_desc `` custom<DynamicIndexList>($offsets, $const_offsets)
prop-dict attr-dict `` `:` type(operands) `->` type(results)
}];

let description = [{
This operation reads a block of data from shared local memory (SLM)
using the provided memory descriptor.

Arguments:
- `mem_desc`: the memory descriptor identifying the SLM region.
- `offsets`: the coordinates within the matrix to read from.
- `layout`: [optional] An attribute for guiding distributions among
subgroups and/or work-items. It currently can accept either
LayoutAttr or SliceAttr.
Results:
- `res`: the matrix elements loaded from SLM.
}];

let builders = [
OpBuilder<(ins "Type":$res, "TypedValue<MemDescType>": $mem_desc,
"llvm::ArrayRef<OpFoldResult>": $offsets, "LayoutTrait": $layout)>,
];
let extraClassDeclaration = [{
SmallVector<OpFoldResult> getMixedOffsets() {
return getMixedValues(getConstOffsets(), getOffsets(), getContext());
}
}];

let hasVerifier = 1;
}

def XeGPU_StoreMatrixOp: XeGPU_Op<"store_matrix", [MemoryEffects<[MemWrite]>,
AllElementTypesMatch<["mem_desc", "data"]>,
AllRanksMatch<["mem_desc", "data"]>]> {
let arguments = (ins
XeGPU_ValueType:$data,
XeGPU_MemDesc:$mem_desc,
Variadic<Index>: $offsets,
DenseI64ArrayAttr: $const_offsets,
OptionalAttr<LayoutTrait>:$layout
);
let assemblyFormat = [{ $data `,` $mem_desc `` custom<DynamicIndexList>($offsets, $const_offsets)
prop-dict attr-dict `` `:` type(operands)}];
let description = [{
This operation writes the `data` fragment into the shared local memory region
identified by `mem_desc`.

Arguments:
- `mem_desc`: the memory descriptor specifying the SLM region.
- `offsets`: the coordinates within the matrix where the data will be written.
- `data`: the values to be stored in the matrix.
- `layout`: [optional] An attribute for guiding distributions among
subgroups and/or work-items. It currently can accept either
LayoutAttr or SliceAttr.
}];
let builders = [
OpBuilder<(ins "Value" : $data, "TypedValue<MemDescType>": $mem_desc,
"llvm::ArrayRef<OpFoldResult>": $offsets, "LayoutTrait": $layout)>,
];
let extraClassDeclaration = [{
SmallVector<OpFoldResult> getMixedOffsets() {
return getMixedValues(getConstOffsets(), getOffsets(), getContext());
}
}];

let hasVerifier = 1;
}

def XeGPU_MemDescSubviewOp: XeGPU_Op<"mem_desc_subview",
[Pure, ViewLikeOpInterface, AllElementTypesMatch<["src", "res"]>]> {
let description = [{
Creates a subview of a memory descriptor. The resulting memory descriptor can have
a lower rank than the source; in this case, the result dimensions correspond to the
higher-order dimensions of the source memory descriptor.

Arguments:
- `src` : a memory descriptor.
- `offsets` : the coordinates within the matrix the subview will be created from.

Results:
- `res` : a memory descriptor with smaller size.

}];
let arguments = (ins XeGPU_MemDesc:$src,
Variadic<Index>:$offsets,
DenseI64ArrayAttr:$const_offsets);
let results = (outs XeGPU_MemDesc:$res);
let assemblyFormat = [{$src `` custom<DynamicIndexList>($offsets, $const_offsets) prop-dict
attr-dict `` `:` qualified(type($src)) `->` qualified(type($res))}];
let builders = [
OpBuilder<(ins "Type": $res, "Value":$src, "llvm::ArrayRef<OpFoldResult>": $offsets)>
];

let extraClassDeclaration = [{
mlir::Value getViewSource() { return getSrc(); }

SmallVector<OpFoldResult> getMixedOffsets() {
return getMixedValues(getConstOffsets(), getOffsets(), getContext());
}
}];

let hasVerifier = 1;
}


#endif // MLIR_DIALECT_XEGPU_IR_XEGPUOPS_TD
49 changes: 49 additions & 0 deletions mlir/include/mlir/Dialect/XeGPU/IR/XeGPUTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,53 @@ def XeGPU_Nbarrier: XeGPUTypeDef<"Nbarrier", "nbarrier", [], "mlir::Type"> {
}];
}

def XeGPU_MemDesc: XeGPUTypeDef<"MemDesc", "mem_desc", [ShapedTypeInterface], "mlir::Type"> {
let summary = "MemDesc describing the data in SLM";
let description = [{
MemDesc represents a block of data stored in shared local memory.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider "a block of data" => "multi-dimensional array buffer". MemDesc associates "structure" information to the buffer (block of data) so it can be viewed as multi-dimension array buffer.

By default, unless a layout attribute is provided, the data is stored
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this layout?
I assume this is not distribution layout as you said it is not part of matrix desc type.

Copy link
Contributor

@silee2 silee2 Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the tests, there is usage like
!xegpu.matrix_desc<16x64xf16, strided<[1, 16]>>
Is strided<[1,16]> the layout attribute?
Is that attribute type not some that can be represented by
MemRefLayoutAttrInterface used in MemRefType ?
https://github.com/llvm/llvm-project/blob/main/mlir/include/mlir/IR/BuiltinTypes.td#L796-#L801
Looks very similar to MemRefType. For example,
memref<12x4xf32, strided<[4, 1], offset: 5>>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to intel/mlir-extensions#1092 for the motivation and explanation of the slm memory layout of matrix descriptor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to the questions here. It just reads as a MemRef layout which is fine but could use explicit clarification as layout term becomes quite overloaded within the dialect now.

Could you add more description here? Or at least an example snippet.

contiguously in row-major order within the region.

Examples:
```mlir
// A block of data stored in column-major order.
!xegpu.mem_desc<128x128xf16, #xegpu.mem_layout<stride = [1, 128]>>

// A block of data stored in a blocked layout. Elements within the same block
// are stored contiguously in memory. Blocks are stored in row-major order.
!xegpu.mem_desc<128x128xf16, #xegpu.mem_layout<block = [8, 8]>>

// A block of data stored in column-major order with blocked layout.
!xegpu.mem_desc<128x128xf16, #xegpu.mem_layout<stride = [1, 128], block = [8, 8]>>
```
}];
let parameters = (ins ArrayRefParameter<"int64_t">: $shape,
"mlir::Type": $elementType,
OptionalParameter<"MemLayoutAttr">: $mem_layout);

let extraClassDeclaration = [{
bool hasRank() const { return true; }

MemDescType cloneWith(std::optional<llvm::ArrayRef<int64_t>> shape, Type elementType) const {
return MemDescType::get(getContext(), shape.value_or(getShape()), elementType, getMemLayout());
}

ArrayAttr getStrides() {
auto layout = getMemLayout();
if (layout && layout.hasAttr("stride")) {
return layout.getStrides();
}

// derive and return default strides
SmallVector<int64_t> defaultStrides;
llvm::append_range(defaultStrides, getShape().drop_front());
llvm::append_values(defaultStrides, 1);
Builder builder(getContext());
return builder.getI64ArrayAttr(defaultStrides);
}
}];

let hasCustomAssemblyFormat = true;
}

#endif // MLIR_DIALECT_XEGPU_IR_XEGPUTYPES_TD
2 changes: 2 additions & 0 deletions mlir/lib/Dialect/XeGPU/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ add_mlir_dialect_library(MLIRXeGPUDialect
MLIRAffineUtils
MLIRArithUtils
MLIRDialectUtils
MLIRGPUDialect
MLIRXeVMDialect
MLIRIR
MLIRViewLikeInterface
MLIRVectorDialect
Expand Down
Loading