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 {
20class UnrealizedConversionCastOp;
21class VectorType;
22class OpOperand;
23class OpResult;
24class OpBuilder;
25class ValueRange;
26class TypeConverter;
27class OpFoldResult;
28
29namespace xegpu {
30class DistributeLayoutAttr;
31class LayoutAttr;
32class TensorDescType;
33
34namespace uArch {
35struct uArch;
36} // namespace uArch
37} // namespace xegpu
38
39namespace xegpu {
40/// Flatten a set of ValueRange into a single SmallVector<Value>
41SmallVector<Value> flattenValues(ArrayRef<ValueRange> values);
42
43/// If tensor descriptor has a layout attribute it is used in SIMT mode.
44/// In this mode, the distributed vector shape is determined as follows:
45/// Definitions:
46/// lane_data_size = lane_data[0] × lane_data[1]
47/// subgroup_size = lane_layout[0] × lane_layout[1]
48/// distribution_unit_size = subgroup_size × lane_data_size
49///
50/// Case 1: Regular loads/stores.
51/// The following conditions must be met:
52/// * tensor_desc[0] == lane_layout[0]
53/// Distributed vector is a 1D vector with shape:
54/// [chunk_size]
55///
56/// Case 2: Block loads/stores
57/// Additional definitions:
58/// tensor_size = tensor_desc[0] * .. * tensor_desc[r-1] * array_length
59/// n_distribution_units = tensor_size / distribution_unit_size
60/// fragment_size = n_distribution_units * lane_data_size
61/// Given above definitions, the following conditions must be met:
62/// * tensor_desc[0] % (lane_layout[0] × lane_data[0]) == 0
63/// * tensor_desc[1] % (lane_layout[1] × lane_data[1]) == 0
64/// Distributed vector is a 1D vector with shape:
65/// [fragment_size]
66FailureOr<VectorType> getDistributedVectorType(xegpu::TensorDescType tdescTy);
67
68/// Helper to get the distributed vector type for a given vector type according
69/// to a given LayoutAttr.
70FailureOr<VectorType> getDistributedVectorType(VectorType originalType,
71 LayoutAttr layout);
72
73/// Helper function to get distributed vector type for a source vector type
74/// according to the lane_layout. We simply divide each dimension of tensor
75/// descriptor shape by corresponding lane_layout dimension. If
76/// array_length > 1, that is appended to the front of the distributed shape.
77///
78/// Examples:
79/// | original vector shape | lane_layout | distributed vector shape |
80/// |-----------------------|-------------|--------------------------|
81/// | 32x16 | [1, 16] | 32x1 |
82/// | 32x16 | [2, 8] | 16x2 |
83/// | 2x32x16 | [1, 16] | 2x32x1 |
84FailureOr<VectorType>
85getDistVecTypeBasedOnLaneLayout(DistributeLayoutAttr layout,
86 VectorType originalType);
87
88/// Extract a set of small vectors from a value with a given shape using
89/// vector.extract_stride_slice
91 Location loc, Value value,
93
94/// Create a vector of shape from a set of values using
95/// vector.insert_stride_slice.
97 ValueRange values,
99
100/// Retrieves the chip string from the XeVM target attribute of the parent
101/// GPU module operation. Returns the chip identifier if found, or nullopt
102/// if no GPU module parent or XeVM target attribute exists.
103std::optional<std::string> getChipStr(Operation *op);
104
105/// Returns the number of subgroups the kernel enclosing `op` runs, derived from
106/// the `known_block_size` of its parent `gpu.func`. Fails when there is no such
107/// parent, when the attribute is absent, when a block dimension is not a
108/// positive power of two, or when the block does not cover a whole subgroup.
109FailureOr<int64_t> getNumSubgroupsFromBlockSize(Operation *op,
110 int64_t subgroupSize);
111
112/// Generates element-wise addition ops of two arrays with same length.
116
117/// Generates element-wise addition ops of two arrays with automatic alignment.
118/// When the input arrays have different sizes, the shorter array is
119/// right-aligned with the longer array, and the unmatched leading elements from
120/// the longer array are preserved unchanged. This is commonly used for offset
121/// computation where higher-dimensional offsets need to be added to
122/// lower-dimensional adjustments.
123///
124/// Example:
125/// lhs = [l1, l2, l3], rhs = [r1, r2]
126/// Result: [11, l2+r1, l3+r2]
130
131/// Given an `input` value representing per-lane data, this function returns the
132/// result after performing a reduction on the input over all lanes (number of
133/// lanes given by `size`). This uses butterfly shuffles to perform the
134/// reduction in a log2(size) number of steps.
135/// NOTE: Implementation taken from TestVectorTransforms.cpp
136/// For float kinds, `fastmath` is set on every combining operation.
137Value subgroupReduction(Location loc, OpBuilder &builder, Value input,
138 vector::CombiningKind kind, uint32_t size,
139 arith::FastMathFlagsAttr fastmath = nullptr);
140
141/// Given a `src` and an `acc` argumments from a vector::MultiDimReductionOp,
142/// lower to a set of vector::ReductionOp ops over 1D slices extracted from
143/// `src`. The reduction is performed along `reductionDim`. The result is a
144/// vector with the same shape as `acc`. `fastmath` holds the fast-math flags
145/// of the vector::MultiDimReductionOp. Each new vector::ReductionOp gets them.
146/// TODO: Only 2D to 1D reduction is supported for now.
149 vector::CombiningKind kind, int64_t reductionDim,
150 Location loc, PatternRewriter &rewriter,
151 arith::FastMathFlagsAttr fastmath = nullptr);
152
153/// Creates a constant filled with the neutral (identity) value for the
154/// given reduction kind. For example: 0 for ADD/OR/XOR, 1 for MUL, all ones
155/// for AND, and max/min signed/unsigned int for MINSI/MINUI/MAXSI/MAXUI.
156/// For float min/max kinds, the value must fit the element type and be
157/// allowed by \p fastmath:
158/// - A quiet NaN for the kinds that ignore NaN operands, if the type has NaN
159/// and `nnan` is not set.
160/// - Otherwise the infinity that never wins, if the type has it and `ninf`
161/// is not set.
162/// - Otherwise the lowest (for max) or highest (for min) finite value.
163/// If \p type is a VectorType, returns a splat vector constant; otherwise
164/// returns a scalar constant. Returns nullptr if the element type is
165/// incompatible with the requested reduction kind.
167 vector::CombiningKind kind,
168 arith::FastMathFlagsAttr fastmath = nullptr);
169
170/// Lowers cross-lane reductions to shuffle operations on a 2D vector.
171/// Extracts slices along the reduction dimension, performs subgroup reductions
172/// with shuffles across reductionSize work-items, and inserts the results back
173/// into an accumulator vector. `fastmath` holds the fast-math flags of the
174/// reduction being lowered. For float kinds, they are set on every combining
175/// operation: the shuffle reductions (see subgroupReduction) and the combine
176/// with each accumulator element.
179 vector::CombiningKind kind, int64_t reductionDim, int64_t reductionSize,
180 Location loc, PatternRewriter &rewriter,
181 arith::FastMathFlagsAttr fastmath = nullptr);
182
183/// Helper Function to find a proper instruction multiple for the user-supplied
184/// sg-level data shape (diven by `dim`). `candidates` are uArch allowed shapes.
185/// `candidateMultiples` are uArch multiples of such shapes (i.e. block count or
186/// array length).
187template <typename T>
188int getLargestDivisor(T dim, ArrayRef<T> candidates,
189 ArrayRef<T> candidateMultiples = {});
190
191/// Retrieves the DistributeLayoutAttr associated with a given Value, or nullptr
192/// if none is found. For TensorDescType values it is extracted from the
193/// TensorDescType itself; for an op result, from the attributes of the defining
194/// operation.
195///
196/// A block argument carries no attribute of its own, so it is resolved through
197/// the operand that feeds it:
198/// - an iter_arg of a loop, including scf.while's "before" arguments, resolves
199/// through its tied init operand;
200/// - an scf.while "after" argument is fed by scf.condition rather than by an
201/// init operand. Only a pass-through before region is handled: the forwarded
202/// value must be a "before" argument, and the layout comes from that
203/// argument's tied init operand. If the before region forwards anything
204/// computed, nullptr is returned.
205DistributeLayoutAttr getDistributeLayoutAttr(const Value value);
206
207/// Retrieves the DistributeLayoutAttr associated with a given OpOperand. It
208/// will first check the operand_layout_{id} of the owner operation. If not
209/// found, it will check the operand itself and its defining op.
210DistributeLayoutAttr getDistributeLayoutAttr(const OpOperand &opr);
211
212/// [to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult
213/// user should use setAnchorLayout instead
215 const DistributeLayoutAttr layout);
216
217/// [to-be-deprecated] Sets the DistributeLayoutAttr for a given OpOperand
218/// user should use setAnchorLayout instead
219void setDistributeLayoutAttr(const OpOperand &opr,
220 const DistributeLayoutAttr layout);
221
222/// Return the attribute name for the OpOperand to attach DistributeLayoutAttr
223std::string getTemporaryLayoutName(const OpOperand &operand);
224
225/// Return the attribute name for the OpResult to attach DistributeLayoutAttr
226std::string getTemporaryLayoutName(const OpResult result);
227
228/// get and set distribute layout attribute for non-anchor operations
229/// (and offsets/masks of load/store ops before we get rid of their temp attrs)
230template <typename T,
231 typename = std::enable_if_t<std::is_same_v<T, OpOperand> ||
232 std::is_same_v<T, OpResult>>>
233DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult);
234
235template <typename T,
236 typename = std::enable_if_t<std::is_same_v<T, OpOperand> ||
237 std::is_same_v<T, OpResult>>>
238void setTemporaryLayout(const T &operandOrResult,
239 const DistributeLayoutAttr layout);
240
241/// Returns the innermost 2 entries of `vals` if it is at least 2D and all of
242/// its leading entries are unit; std::nullopt otherwise.
243std::optional<SmallVector<int64_t>>
245
246/// Helper function to check if the layout is packed. Layout is packed if
247/// lane_data[rank-2] != 1 (data packed from col dimension).
248/// TODO: Move to target info.
249bool requirePacked(const DistributeLayoutAttr layout);
250
251/// Helper function to check if the layout requires a transpose effect.
252bool requireTranspose(const DistributeLayoutAttr layout,
253 const uArch::uArch *uArch);
254
255/// Returns true if `type` has a static shape and static strides.
256bool hasStaticShapeAndStrides(MemRefType type);
257
258/// Returns `baseAddr + elemOffset * bitWidth / 8`, i.e. advances the byte
259/// address `baseAddr` by `elemOffset` elements of `memrefTy`'s element type.
260/// Sub-byte element types (e.g. i4) are supported. `baseAddr` and `elemOffset`
261/// must have the same index or integer type, which is also the result type.
262Value addElemOffsetInBytes(OpBuilder &builder, Location loc, Value baseAddr,
263 Value elemOffset, MemRefType memrefTy);
264
265// Check if dst shape is an expansion of src shape by inserting unit dimensions.
267 SmallVector<int64_t> &expandedUnitDims);
268
269// Checks if dst shape is a non-unit expansion of src shape where each
270// dimension in src is split into one or more consecutive dimensions in dst.
272 SmallVector<SmallVector<int64_t>> &splitDimGroups);
273
274/// Callback type for computing sub-shape and count for 1:N (or 1:1
275/// shape-changing) VectorType conversion. Given a VectorType and its
276/// DistributeLayoutAttr, returns (subShape, count). A count <= 0 signals
277/// "no conversion needed"; count == 1 is a 1:1 shape-changing conversion;
278/// count > 1 produces `count` copies of `subShape`.
279using SubShapeAndCountFn = std::function<std::pair<SmallVector<int64_t>, int>(
280 VectorType, DistributeLayoutAttr)>;
281
282/// Pre-computes distributed VectorType mappings for every value carried
283/// through an SCF loop under `topLevelOp` (1:1 shape-changing or 1:N): the
284/// region block args (`scf.while` before/after args, `scf.for` iter_args), the
285/// loop results, and the terminator operands feeding them. Each is derived from
286/// a single source -- the layout of the feeding value (loop init or
287/// `scf.condition` operand) -- and keyed by `Value`, because the SCF converters
288/// detach/replace the loop body mid-conversion, after which a layout query on a
289/// block arg returns null. Recording results and terminator operands lets a 1:N
290/// pass resolve them from the map after stripping the loop op's transient
291/// layout attrs. `scf.if` has no loop-carried block args and needs no entry.
294 SubShapeAndCountFn getSubShapeAndCount);
295
296/// Adds a context-aware VectorType conversion to `converter` (1:1
297/// shape-changing or 1:N, depending on `getSubShapeAndCount`'s returned
298/// count). `getSubShapeAndCount` computes (subShape, count) for a VectorType
299/// and its layout; count <= 0 means no conversion needed. `loopArgTypes`
300/// (typically obtained from `precomputeLoopBlockArgTypes`) provides the
301/// pre-computed types for SCF loop block arguments (`scf.while`,
302/// `scf.for`); pass an empty map if the IR has no such loops.
304 SubShapeAndCountFn getSubShapeAndCount,
305 DenseMap<Value, SmallVector<Type>> loopArgTypes);
306
307/// Cleans up UnrealizedConversionCastOps inserted during SCF structural type
308/// conversion and/or XeGPU unrolling. Folds cancelling N:1->1:N and 1:N->N:1
309/// cast chains (inserting vector.shape_cast when shapes differ but element
310/// counts match). Unpaired pack (1:N) and unpack (N:1) casts between a single
311/// large VectorType and N identically-typed smaller VectorTypes are lowered
312/// to vector.extract_strided_slice / vector.insert_strided_slice. Dead casts
313/// are erased. Casts in `existingCasts` are preserved.
315 Operation *root,
316 const llvm::SmallSetVector<UnrealizedConversionCastOp, 8> &existingCasts);
317
318// Checks if dst shape is a collapse of src shape where each dimension in dst is
319// produced by one or more consecutive dimensions in src whose product equals
320// the dst dimension. Populates collapseDims with groups of src indices that are
321// collapsed into each dst dimension. Leading or trailing unit dst dimensions
322// (with no backing src dim) result in empty groups. Example: src=[8,16,32],
323// dst=[1,4096] -> true, collapseDims=[[],[0,1,2]].
325 SmallVector<SmallVector<int64_t>> &collapseDims);
326} // namespace xegpu
327} // namespace mlir
328
329#endif // MLIR_DIALECT_XEGPU_UTILS_XEGPUUTILS_H_
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:256
This is a value defined by a result of an operation.
Definition Value.h:456
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:392
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)
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
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...
FailureOr< int64_t > getNumSubgroupsFromBlockSize(Operation *op, int64_t subgroupSize)
Returns the number of subgroups the kernel enclosing op runs, derived from the known_block_size of it...
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.
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, or nullptr if none is found.
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.
Value addElemOffsetInBytes(OpBuilder &builder, Location loc, Value baseAddr, Value elemOffset, MemRefType memrefTy)
Returns baseAddr + elemOffset * bitWidth / 8, i.e.
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,...
Value lowerToVectorReductions(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, Location loc, PatternRewriter &rewriter, arith::FastMathFlagsAttr fastmath=nullptr)
Given a src and an acc argumments from a vector::MultiDimReductionOp, lower to a set of vector::Reduc...
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.
Value createReductionNeutralValue(OpBuilder &builder, Location loc, Type type, vector::CombiningKind kind, arith::FastMathFlagsAttr fastmath=nullptr)
Creates a constant filled with the neutral (identity) value for the given reduction kind.
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, arith::FastMathFlagsAttr fastmath=nullptr)
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:279
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.
Value subgroupReduction(Location loc, OpBuilder &builder, Value input, vector::CombiningKind kind, uint32_t size, arith::FastMathFlagsAttr fastmath=nullptr)
Given an input value representing per-lane data, this function returns the result after performing a ...
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:496
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:123