MLIR 24.0.0git
XeGPUUtils.h
Go to the documentation of this file.
1//===- XeGPUUtils.h - Vector Utilities --------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MLIR_DIALECT_XEGPU_UTILS_XEGPUUTILS_H_
10#define MLIR_DIALECT_XEGPU_UTILS_XEGPUUTILS_H_
11
15#include "llvm/ADT/SetVector.h"
16#include <functional>
17#include <optional>
18
19namespace mlir {
20
21class UnrealizedConversionCastOp;
22class VectorType;
23class OpOperand;
24class OpResult;
25class OpBuilder;
26class ValueRange;
27class TypeConverter;
28class OpFoldResult;
29
30namespace xegpu {
31class DistributeLayoutAttr;
32class LayoutAttr;
33class TensorDescType;
34
35namespace uArch {
36struct uArch;
37} // namespace uArch
38} // namespace xegpu
39
40namespace xegpu {
41
42/// Flatten a set of ValueRange into a single SmallVector<Value>
43SmallVector<Value> flattenValues(ArrayRef<ValueRange> values);
44
45/// If tensor descriptor has a layout attribute it is used in SIMT mode.
46/// In this mode, the distributed vector shape is determined as follows:
47/// Definitions:
48/// lane_data_size = lane_data[0] × lane_data[1]
49/// subgroup_size = lane_layout[0] × lane_layout[1]
50/// distribution_unit_size = subgroup_size × lane_data_size
51///
52/// Case 1: Regular loads/stores.
53/// The following conditions must be met:
54/// * tensor_desc[0] == lane_layout[0]
55/// Distributed vector is a 1D vector with shape:
56/// [chunk_size]
57///
58/// Case 2: Block loads/stores
59/// Additional definitions:
60/// tensor_size = tensor_desc[0] * .. * tensor_desc[r-1] * array_length
61/// n_distribution_units = tensor_size / distribution_unit_size
62/// fragment_size = n_distribution_units * lane_data_size
63/// Given above definitions, the following conditions must be met:
64/// * tensor_desc[0] % (lane_layout[0] × lane_data[0]) == 0
65/// * tensor_desc[1] % (lane_layout[1] × lane_data[1]) == 0
66/// Distributed vector is a 1D vector with shape:
67/// [fragment_size]
68FailureOr<VectorType> getDistributedVectorType(xegpu::TensorDescType tdescTy);
69
70/// Helper to get the distributed vector type for a given vector type according
71/// to a given LayoutAttr.
72FailureOr<VectorType> getDistributedVectorType(VectorType originalType,
73 LayoutAttr layout);
74
75/// Helper function to get distributed vector type for a source vector type
76/// according to the lane_layout. We simply divide each dimension of tensor
77/// descriptor shape by corresponding lane_layout dimension. If
78/// array_length > 1, that is appended to the front of the distributed shape.
79///
80/// Examples:
81/// | original vector shape | lane_layout | distributed vector shape |
82/// |-----------------------|-------------|--------------------------|
83/// | 32x16 | [1, 16] | 32x1 |
84/// | 32x16 | [2, 8] | 16x2 |
85/// | 2x32x16 | [1, 16] | 2x32x1 |
86FailureOr<VectorType>
87getDistVecTypeBasedOnLaneLayout(DistributeLayoutAttr layout,
88 VectorType originalType);
89
90/// Extract a set of small vectors from a value with a given shape using
91/// vector.extract_stride_slice
93 Location loc, Value value,
95
96/// Create a vector of shape from a set of values using
97/// vector.insert_stride_slice.
99 ValueRange values,
101
102/// Retrieves the chip string from the XeVM target attribute of the parent
103/// GPU module operation. Returns the chip identifier if found, or nullopt
104/// if no GPU module parent or XeVM target attribute exists.
105std::optional<std::string> getChipStr(Operation *op);
106
107/// Generates element-wise addition ops of two arrays with same length.
111
112/// Generates element-wise addition ops of two arrays with automatic alignment.
113/// When the input arrays have different sizes, the shorter array is
114/// right-aligned with the longer array, and the unmatched leading elements from
115/// the longer array are preserved unchanged. This is commonly used for offset
116/// computation where higher-dimensional offsets need to be added to
117/// lower-dimensional adjustments.
118///
119/// Example:
120/// lhs = [l1, l2, l3], rhs = [r1, r2]
121/// Result: [11, l2+r1, l3+r2]
125
126/// Given an `input` value representing per-lane data, this function returns the
127/// result after performing a reduction on the input over all lanes (number of
128/// lanes given by `size`). This uses butterfly shuffles to perform the
129/// reduction in a log2(size) number of steps.
130/// NOTE: Implementation taken from TestVectorTransforms.cpp
131Value subgroupReduction(Location loc, OpBuilder &builder, Value input,
132 vector::CombiningKind kind, uint32_t size);
133
134/// Given a `src` and an `acc` argumments from a vector::MultiDimReductionOp,
135/// lower to a set of vector::ReductionOp ops over 1D slices extracted from
136/// `src`. The reduction is performed along `reductionDim`. The result is a
137/// vector with the same shape as `acc`.
138/// TODO: Only 2D to 1D reduction is supported for now.
141 vector::CombiningKind kind, int64_t reductionDim,
142 Location loc, PatternRewriter &rewriter);
143
144/// Creates a constant filled with the neutral (identity) value for the
145/// given reduction kind. For example: 0 for ADD/OR/XOR, 1 for MUL/AND,
146/// max/min signed/unsigned int for MINSI/MINUI/MAXSI/MAXUI, and +/-infinity
147/// for float min/max operations. If \p type is a VectorType, returns a splat
148/// vector constant; otherwise returns a scalar constant. Returns nullptr if
149/// the element type is incompatible with the requested reduction kind.
151 vector::CombiningKind kind);
152
153/// Lowers cross-lane reductions to shuffle operations on a 2D vector.
154/// Extracts slices along the reduction dimension, performs subgroup reductions
155/// with shuffles across reductionSize work-items, and inserts the results back
156/// into an accumulator vector.
159 vector::CombiningKind kind,
160 int64_t reductionDim,
161 int64_t reductionSize, Location loc,
162 PatternRewriter &rewriter);
163
164/// Helper Function to find a proper instruction multiple for the user-supplied
165/// sg-level data shape (diven by `dim`). `candidates` are uArch allowed shapes.
166/// `candidateMultiples` are uArch multiples of such shapes (i.e. block count or
167/// array length).
168template <typename T>
169int getLargestDivisor(T dim, ArrayRef<T> candidates,
170 ArrayRef<T> candidateMultiples = {});
171
172/// Retrieves the DistributeLayoutAttr associated with a given Value. For
173/// TensorDescType values, the DistributeLayoutAttr is extracted from the
174/// TensorDescType itself. For other values, it is obtained from the attributes
175/// of the defining operation. Returns nullptr if no DistributeLayoutAttr is
176/// found.
177DistributeLayoutAttr getDistributeLayoutAttr(const Value value);
178
179/// Retrieves the DistributeLayoutAttr associated with a given OpOperand. It
180/// will first check the operand_layout_{id} of the owner operation. If not
181/// found, it will check the operand itself and its defining op.
182DistributeLayoutAttr getDistributeLayoutAttr(const OpOperand &opr);
183
184/// [to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult
185/// user should use setAnchorLayout instead
187 const DistributeLayoutAttr layout);
188
189/// [to-be-deprecated] Sets the DistributeLayoutAttr for a given OpOperand
190/// user should use setAnchorLayout instead
191void setDistributeLayoutAttr(const OpOperand &opr,
192 const DistributeLayoutAttr layout);
193
194/// Return the attribute name for the OpOperand to attach DistributeLayoutAttr
195std::string getTemporaryLayoutName(const OpOperand &operand);
196
197/// Return the attribute name for the OpResult to attach DistributeLayoutAttr
198std::string getTemporaryLayoutName(const OpResult result);
199
200/// get and set distribute layout attribute for non-anchor operations
201/// (and offsets/masks of load/store ops before we get rid of their temp attrs)
202template <typename T,
203 typename = std::enable_if_t<std::is_same_v<T, OpOperand> ||
204 std::is_same_v<T, OpResult>>>
205DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult);
206
207template <typename T,
208 typename = std::enable_if_t<std::is_same_v<T, OpOperand> ||
209 std::is_same_v<T, OpResult>>>
210void setTemporaryLayout(const T &operandOrResult,
211 const DistributeLayoutAttr layout);
212
213/// Returns the innermost 2 entries of `vals` if it is at least 2D and all of
214/// its leading entries are unit; std::nullopt otherwise.
215std::optional<SmallVector<int64_t>>
217
218/// Helper function to check if the layout is packed. Layout is packed if
219/// lane_data[rank-2] != 1 (data packed from col dimension).
220/// TODO: Move to target info.
221bool requirePacked(const DistributeLayoutAttr layout);
222
223/// Helper function to check if the layout requires a transpose effect.
224bool requireTranspose(const DistributeLayoutAttr layout,
225 const uArch::uArch *uArch);
226
227/// Returns true if `type` has a static shape and static strides.
228bool hasStaticShapeAndStrides(MemRefType type);
229
230// Check if dst shape is an expansion of src shape by inserting unit dimensions.
232 SmallVector<int64_t> &expandedUnitDims);
233
234// Checks if dst shape is an expansion of src shape where each dimension in src
235// is split into one or more consecutive dimensions in dst
237 SmallVector<SmallVector<int64_t>> &splitDimGroups);
238
239/// Callback type for computing sub-shape and count for 1:N (or 1:1
240/// shape-changing) VectorType conversion. Given a VectorType and its
241/// DistributeLayoutAttr, returns (subShape, count). A count <= 0 signals
242/// "no conversion needed"; count == 1 is a 1:1 shape-changing conversion;
243/// count > 1 produces `count` copies of `subShape`.
244using SubShapeAndCountFn = std::function<std::pair<SmallVector<int64_t>, int>(
245 VectorType, DistributeLayoutAttr)>;
246
247/// Pre-computes distributed VectorType mappings for every value carried
248/// through an SCF loop under `topLevelOp` (1:1 shape-changing or 1:N): the
249/// region block args (`scf.while` before/after args, `scf.for` iter_args), the
250/// loop results, and the terminator operands feeding them. Each is derived from
251/// a single source -- the layout of the feeding value (loop init or
252/// `scf.condition` operand) -- and keyed by `Value`, because the SCF converters
253/// detach/replace the loop body mid-conversion, after which a layout query on a
254/// block arg returns null. Recording results and terminator operands lets a 1:N
255/// pass resolve them from the map after stripping the loop op's transient
256/// layout attrs. `scf.if` has no loop-carried block args and needs no entry.
259 SubShapeAndCountFn getSubShapeAndCount);
260
261/// Adds a context-aware VectorType conversion to `converter` (1:1
262/// shape-changing or 1:N, depending on `getSubShapeAndCount`'s returned
263/// count). `getSubShapeAndCount` computes (subShape, count) for a VectorType
264/// and its layout; count <= 0 means no conversion needed. `loopArgTypes`
265/// (typically obtained from `precomputeLoopBlockArgTypes`) provides the
266/// pre-computed types for SCF loop block arguments (`scf.while`,
267/// `scf.for`); pass an empty map if the IR has no such loops.
269 SubShapeAndCountFn getSubShapeAndCount,
270 DenseMap<Value, SmallVector<Type>> loopArgTypes);
271
272/// Cleans up UnrealizedConversionCastOps inserted during SCF structural type
273/// conversion and/or XeGPU unrolling. Folds cancelling N:1->1:N and 1:N->N:1
274/// cast chains (inserting vector.shape_cast when shapes differ but element
275/// counts match). Unpaired pack (1:N) and unpack (N:1) casts between a single
276/// large VectorType and N identically-typed smaller VectorTypes are lowered
277/// to vector.extract_strided_slice / vector.insert_strided_slice. Dead casts
278/// are erased. Casts in `existingCasts` are preserved.
280 Operation *root,
281 const llvm::SmallSetVector<UnrealizedConversionCastOp, 8> &existingCasts);
282
283// Checks if dst shape is a collapse of src shape where each dimension in dst is
284// produced by one or more consecutive dimensions in src whose product equals
285// the dst dimension. Populates collapseDims with groups of src indices that are
286// collapsed into each dst dimension. Leading or trailing unit dst dimensions
287// (with no backing src dim) result in empty groups. Example: src=[8,16,32],
288// dst=[1,4096] -> true, collapseDims=[[],[0,1,2]].
290 SmallVector<SmallVector<int64_t>> &collapseDims);
291
292} // namespace xegpu
293
294} // namespace mlir
295
296#endif // MLIR_DIALECT_XEGPU_UTILS_XEGPUUTILS_H_
lhs
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:210
This class represents a single result from folding an operation.
This class represents an operand of an operation.
Definition Value.h:254
This is a value defined by a result of an operation.
Definition Value.h:454
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
bool matchDimCollapse(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &collapseDims)
Value createVectorWithShapeFromValues(OpBuilder &builder, Location loc, ValueRange values, ArrayRef< int64_t > shape)
Create a vector of shape from a set of values using vector.insert_stride_slice.
bool requirePacked(const DistributeLayoutAttr layout)
Helper function to check if the layout is packed.
void setTemporaryLayout(const T &operandOrResult, const DistributeLayoutAttr layout)
Value createReductionNeutralValue(OpBuilder &builder, Location loc, Type type, vector::CombiningKind kind)
Creates a constant filled with the neutral (identity) value for the given reduction kind.
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
Value subgroupReduction(Location loc, OpBuilder &builder, Value input, vector::CombiningKind kind, uint32_t size)
Given an input value representing per-lane data, this function returns the result after performing a ...
bool matchUnitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< int64_t > &expandedUnitDims)
std::optional< SmallVector< int64_t > > getInner2DIfUnitLeadingDims(ArrayRef< int64_t > vals)
Returns the innermost 2 entries of vals if it is at least 2D and all of its leading entries are unit;...
int getLargestDivisor(T dim, ArrayRef< T > candidates, ArrayRef< T > candidateMultiples={})
Helper Function to find a proper instruction multiple for the user-supplied sg-level data shape (dive...
bool hasStaticShapeAndStrides(MemRefType type)
Returns true if type has a static shape and static strides.
FailureOr< VectorType > getDistVecTypeBasedOnLaneLayout(DistributeLayoutAttr layout, VectorType originalType)
Helper function to get distributed vector type for a source vector type according to the lane_layout.
Value lowerToVectorReductions(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, Location loc, PatternRewriter &rewriter)
Given a src and an acc argumments from a vector::MultiDimReductionOp, lower to a set of vector::Reduc...
bool requireTranspose(const DistributeLayoutAttr layout, const uArch::uArch *uArch)
Helper function to check if the layout requires a transpose effect.
bool matchSplitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &splitDimGroups)
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value.
DenseMap< Value, SmallVector< Type > > precomputeLoopBlockArgTypes(Operation *topLevelOp, SubShapeAndCountFn getSubShapeAndCount)
Pre-computes distributed VectorType mappings for every value carried through an SCF loop under topLev...
std::string getTemporaryLayoutName(const OpOperand &operand)
Return the attribute name for the OpOperand to attach DistributeLayoutAttr.
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
void addVectorTypeConversion(TypeConverter &converter, SubShapeAndCountFn getSubShapeAndCount, DenseMap< Value, SmallVector< Type > > loopArgTypes)
Adds a context-aware VectorType conversion to converter (1:1 shape-changing or 1:N,...
SmallVector< Value > extractVectorsWithShapeFromValue(OpBuilder &builder, Location loc, Value value, ArrayRef< int64_t > shape)
Extract a set of small vectors from a value with a given shape using vector.extract_stride_slice.
DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult)
get and set distribute layout attribute for non-anchor operations (and offsets/masks of load/store op...
Value lowerCrossLaneReductionToShuffles(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, int64_t reductionSize, Location loc, PatternRewriter &rewriter)
Lowers cross-lane reductions to shuffle operations on a 2D vector.
std::function< std::pair< SmallVector< int64_t >, int >( VectorType, DistributeLayoutAttr)> SubShapeAndCountFn
Callback type for computing sub-shape and count for 1:N (or 1:1 shape-changing) VectorType conversion...
Definition XeGPUUtils.h:244
void cleanupUnrealizedConversionCasts(Operation *root, const llvm::SmallSetVector< UnrealizedConversionCastOp, 8 > &existingCasts)
Cleans up UnrealizedConversionCastOps inserted during SCF structural type conversion and/or XeGPU unr...
SmallVector< Value > flattenValues(ArrayRef< ValueRange > values)
Flatten a set of ValueRange into a single SmallVector<Value>
SmallVector< OpFoldResult > addWithRightAligned(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with automatic alignment.
SmallVector< OpFoldResult > addElementwise(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with same length.
FailureOr< VectorType > getDistributedVectorType(xegpu::TensorDescType tdescTy)
If tensor descriptor has a layout attribute it is used in SIMT mode.
Include the generated interface declarations.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
Definition Value.h:494
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120