MLIR  20.0.0git
XeGPUOps.cpp
Go to the documentation of this file.
1 //===- XeGPUOps.cpp - MLIR XeGPU ops implementation -------------*- 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 
12 #include "mlir/IR/Builders.h"
13 #include "mlir/IR/TypeUtilities.h"
14 
15 #include "llvm/Support/Debug.h"
16 
17 #define DEBUG_TYPE "xegpu"
18 
19 namespace mlir {
20 namespace xegpu {
21 
23  SmallVector<int64_t> &shape) {
24  SmallVector<int64_t> old = shape;
25  for (size_t i = 0; i < trans.size(); i++)
26  shape[i] = old[trans[i]];
27 }
28 
29 template <typename T>
30 static std::string makeString(T array, bool breakline = false) {
31  std::string buf;
32  buf.clear();
33  llvm::raw_string_ostream os(buf);
34  os << "[";
35  for (size_t i = 1; i < array.size(); i++) {
36  os << array[i - 1] << ", ";
37  if (breakline)
38  os << "\n\t\t";
39  }
40  os << array.back() << "]";
41  return buf;
42 }
43 
46  if (auto ty = llvm::dyn_cast<ShapedType>(type))
47  shape = SmallVector<int64_t>(ty.getShape());
48  else
49  shape.push_back(1);
50  return shape;
51 }
52 
53 static int64_t getRankOf(Value val) {
54  auto type = val.getType();
55  if (auto ty = llvm::dyn_cast<ShapedType>(type))
56  return ty.getRank();
57  return 0;
58 }
59 
60 static bool isReadHintOrNone(const CachePolicyAttr &attr) {
61  if (!attr)
62  return true;
63  auto kind = attr.getValue();
64  return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
65  kind == CachePolicy::STREAMING || kind == CachePolicy::READ_INVALIDATE;
66 }
67 
68 static bool isWriteHintOrNone(const CachePolicyAttr &attr) {
69  if (!attr)
70  return true;
71  auto kind = attr.getValue();
72  return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
73  kind == CachePolicy::WRITE_BACK || kind == CachePolicy::WRITE_THROUGH;
74 }
75 
76 //===----------------------------------------------------------------------===//
77 // XeGPU_CreateNdDescOp
78 //===----------------------------------------------------------------------===//
79 void CreateNdDescOp::build(OpBuilder &builder, OperationState &state,
80  Type tdesc, TypedValue<MemRefType> source,
82  [[maybe_unused]] auto ty = source.getType();
83  assert(ty.hasStaticShape() && offsets.size() == (size_t)ty.getRank());
84 
85  llvm::SmallVector<int64_t> staticOffsets;
86  llvm::SmallVector<Value> dynamicOffsets;
87  dispatchIndexOpFoldResults(offsets, dynamicOffsets, staticOffsets);
88 
89  build(builder, state, tdesc, source, dynamicOffsets /* dynamic offsets */,
90  ValueRange({}) /* empty dynamic shape */,
91  ValueRange({}) /* empty dynamic strides */,
92  staticOffsets /* const offsets */, {} /* empty const shape*/,
93  {} /* empty const strides*/);
94 }
95 
96 void CreateNdDescOp::build(OpBuilder &builder, OperationState &state,
97  Type tdesc, TypedValue<MemRefType> source,
101  assert(shape.size() && offsets.size() && strides.size() &&
102  shape.size() == strides.size() && shape.size() == offsets.size());
103 
104  llvm::SmallVector<int64_t> staticOffsets;
105  llvm::SmallVector<int64_t> staticShape;
106  llvm::SmallVector<int64_t> staticStrides;
107  llvm::SmallVector<Value> dynamicOffsets;
108  llvm::SmallVector<Value> dynamicShape;
109  llvm::SmallVector<Value> dynamicStrides;
110 
111  dispatchIndexOpFoldResults(offsets, dynamicOffsets, staticOffsets);
112  dispatchIndexOpFoldResults(shape, dynamicShape, staticShape);
113  dispatchIndexOpFoldResults(strides, dynamicStrides, staticStrides);
114 
115  auto staticOffsetsAttr = builder.getDenseI64ArrayAttr(staticOffsets);
116  auto staticShapeAttr = builder.getDenseI64ArrayAttr(staticShape);
117  auto staticStridesAttr = builder.getDenseI64ArrayAttr(staticStrides);
118 
119  build(builder, state, tdesc, source, dynamicOffsets, dynamicShape,
120  dynamicStrides, staticOffsetsAttr, staticShapeAttr, staticStridesAttr);
121 }
122 
123 void CreateNdDescOp::build(OpBuilder &builder, OperationState &state,
124  Type tdesc, TypedValue<IntegerType> source,
128  assert(shape.size() && offsets.size() && strides.size() &&
129  shape.size() == strides.size() && shape.size() == offsets.size());
130 
131  llvm::SmallVector<int64_t> staticOffsets;
132  llvm::SmallVector<int64_t> staticShape;
133  llvm::SmallVector<int64_t> staticStrides;
134  llvm::SmallVector<Value> dynamicOffsets;
135  llvm::SmallVector<Value> dynamicShape;
136  llvm::SmallVector<Value> dynamicStrides;
137 
138  dispatchIndexOpFoldResults(offsets, dynamicOffsets, staticOffsets);
139  dispatchIndexOpFoldResults(shape, dynamicShape, staticShape);
140  dispatchIndexOpFoldResults(strides, dynamicStrides, staticStrides);
141 
142  auto staticOffsetsAttr = builder.getDenseI64ArrayAttr(staticOffsets);
143  auto staticShapeAttr = builder.getDenseI64ArrayAttr(staticShape);
144  auto staticStridesAttr = builder.getDenseI64ArrayAttr(staticStrides);
145 
146  build(builder, state, tdesc, source, dynamicOffsets, dynamicShape,
147  dynamicStrides, staticOffsetsAttr, staticShapeAttr, staticStridesAttr);
148 }
149 
150 LogicalResult CreateNdDescOp::verify() {
151  auto rank = (int64_t)getMixedOffsets().size();
152  bool invalidRank = false;
153  bool invalidElemTy = false;
154 
155  // Memory space of created TensorDesc should match with the source.
156  // Both source and TensorDesc are considered for global memory by default,
157  // if the memory scope attr is not specified. If source is an integer,
158  // it is considered as ptr to global memory.
159  auto srcMemorySpace = getSourceMemorySpace();
160  auto tdescMemorySpace = static_cast<unsigned>(getType().getMemorySpace());
161  if (srcMemorySpace != tdescMemorySpace)
162  return emitOpError("Memory space mismatch.")
163  << " Source: " << srcMemorySpace
164  << ", TensorDesc: " << tdescMemorySpace;
165 
166  // check source type matches the rank if it is a memref.
167  // It also should have the same ElementType as TensorDesc.
168  auto memrefTy = dyn_cast<MemRefType>(getSourceType());
169  if (memrefTy) {
170  invalidRank |= (memrefTy.getRank() != rank);
171  invalidElemTy |= memrefTy.getElementType() != getElementType();
172  }
173 
174  // mismatches among shape, strides, and offsets are
175  // already handeled by OffsetSizeAndStrideOpInterface.
176  // So they are not check here.
177  if (invalidRank)
178  return emitOpError(
179  "Expecting the rank of shape, strides, offsets, and source (if source "
180  "is a memref) should match with each other.");
181 
182  // check result TensorDesc rank
183  invalidRank = (getType().getRank() > 2 || getType().getRank() > rank);
184 
185  if (invalidRank)
186  return emitOpError(
187  "Expecting the TensorDesc rank is up to 2 and not greater than the "
188  "ranks of shape, strides, offsets or the memref source.");
189 
190  if (invalidElemTy)
191  return emitOpError("TensorDesc should have the same element "
192  "type with the source if it is a memref.\n");
193 
194  if (getType().isScattered())
195  return emitOpError("Expects a non-scattered TensorDesc.\n");
196 
197  if (getType().getRank() == 2 &&
198  tdescMemorySpace == static_cast<unsigned>(MemorySpace::SLM))
199  return emitOpError("SLM is not supported for 2D Block TensorDesc.\n");
200 
201  return success();
202 }
203 
204 //===----------------------------------------------------------------------===//
205 // XeGPU_PrefetchNdOp
206 //===----------------------------------------------------------------------===//
207 LogicalResult PrefetchNdOp::verify() {
208  auto tdescTy = getTensorDescType();
209  if (tdescTy.isScattered())
210  return emitOpError("Expects a non-scattered TensorDesc.\n");
211 
212  if (!isReadHintOrNone(getL1HintAttr()))
213  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
214 
215  if (!isReadHintOrNone(getL2HintAttr()))
216  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
217 
218  if (!isReadHintOrNone(getL3HintAttr()))
219  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
220 
221  return success();
222 }
223 
224 //===----------------------------------------------------------------------===//
225 // XeGPU_LoadNdOp
226 //===----------------------------------------------------------------------===//
227 LogicalResult LoadNdOp::verify() {
228  auto tdescTy = getTensorDescType();
229  auto valueTy = getType();
230 
231  if (tdescTy.getRank() > 2)
232  return emitOpError("Expecting a 1D/2D TensorDesc.\n");
233 
234  if (tdescTy.isScattered())
235  return emitOpError("Expects a non-scattered TensorDesc.\n");
236 
237  if (!valueTy)
238  return emitOpError("Invalid result, it should be a VectorType.\n");
239 
240  if (!isReadHintOrNone(getL1HintAttr()))
241  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
242 
243  if (!isReadHintOrNone(getL2HintAttr()))
244  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
245 
246  if (!isReadHintOrNone(getL3HintAttr()))
247  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
248 
249  auto array_len = tdescTy.getArrayLength();
250  auto tdescShape = getShapeOf(tdescTy);
251  auto valueShape = getShapeOf(valueTy);
252 
253  if (getTranspose()) {
254  auto trans = getTranspose().value();
255 
256  // Make sure the transpose value is valid.
257  bool valid = std::all_of(trans.begin(), trans.end(), [&](int t) {
258  return t >= 0 && t < tdescTy.getRank();
259  });
260 
261  if (valid)
262  transpose(trans, tdescShape);
263  else
264  emitWarning("Invalid transpose attr. It is ignored.");
265  }
266 
267  if (getPacked()) {
268  if (tdescTy.getRank() == 2) {
269  const int axis = 0;
270  auto vnni_factor = valueShape.back();
271  tdescShape[axis] /= vnni_factor;
272  tdescShape.push_back(vnni_factor);
273  } else {
274  emitWarning("Invalid Packed Attr. It is ignored (available for 2D "
275  "TensorDesc only).");
276  }
277  }
278 
279  if (array_len > 1) {
280  auto it = tdescShape.begin();
281  tdescShape.insert(it, array_len);
282  }
283 
284  if (tdescShape != valueShape)
285  return emitOpError() << "Result shape doesn't match TensorDesc shape."
286  << "The expected shape is " << makeString(tdescShape)
287  << ". But the given shape is "
288  << makeString(valueShape) << ".\n";
289  return success();
290 }
291 
292 //===----------------------------------------------------------------------===//
293 // XeGPU_StoreNdOp
294 //===----------------------------------------------------------------------===//
295 LogicalResult StoreNdOp::verify() {
296  auto dstTy = getTensorDescType(); // Tile
297  auto valTy = getValueType(); // Vector
298 
299  if (dstTy.getRank() > 2)
300  return emitOpError("Expecting a 1D/2D TensorDesc.\n");
301 
302  if (dstTy.isScattered())
303  return emitOpError("Expects a non-scattered TensorDesc.\n");
304 
305  if (!valTy)
306  return emitOpError("Exepcting a VectorType result.\n");
307 
308  if (!isWriteHintOrNone(getL1HintAttr()))
309  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
310 
311  if (!isWriteHintOrNone(getL2HintAttr()))
312  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
313 
314  if (!isWriteHintOrNone(getL3HintAttr()))
315  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
316 
317  return success();
318 }
319 
320 //===----------------------------------------------------------------------===//
321 // XeGPU_UpdateNDOffsetOp
322 //===----------------------------------------------------------------------===//
323 LogicalResult UpdateNdOffsetOp::verify() {
324  auto ty = getTensorDescType();
325  if (ty.isScattered())
326  return emitOpError("Expects a non-scattered TensorDesc.\n");
327 
328  // number of offsets specified must match the rank of the tensor descriptor
329  if (ty.getRank() != (int64_t)getNumOffsets()) {
330  return emitOpError("Invalid number of offsets.");
331  }
332  return success();
333 }
334 
335 //===----------------------------------------------------------------------===//
336 // XeGPU_CreateDescOp
337 //===----------------------------------------------------------------------===//
338 
339 void CreateDescOp::build(OpBuilder &builder, OperationState &state,
340  TensorDescType TensorDesc, Value source,
342  auto loc = source.getLoc();
343  int64_t size = static_cast<int64_t>(offsets.size());
344  auto type = VectorType::get(size, builder.getIndexType());
345  auto values = getValueOrCreateConstantIndexOp(builder, loc, offsets);
346  auto offset = builder.create<vector::FromElementsOp>(loc, type, values);
347  build(builder, state, TensorDesc, source, offset);
348 }
349 
350 void CreateDescOp::build(OpBuilder &builder, OperationState &state,
351  TensorDescType TensorDesc, Value source,
352  llvm::ArrayRef<int64_t> offsets) {
353  auto ofrs = getAsIndexOpFoldResult(builder.getContext(), offsets);
354  build(builder, state, TensorDesc, source, ofrs);
355 }
356 
357 LogicalResult CreateDescOp::verify() {
358  auto tdescTy = getTensorDescType();
359 
360  if (getRankOf(getSource()) > 1)
361  return emitOpError(
362  "Expecting the source is a 1D memref or pointer (uint64_t).");
363 
364  if (!tdescTy.isScattered())
365  return emitOpError("Expects a scattered TensorDesc.\n");
366 
367  // Memory space of created TensorDesc should match with the source.
368  // Both source and TensorDesc are considered for global memory by default,
369  // if the memory scope attr is not specified. If source is an integer,
370  // it is considered as ptr to global memory.
371  auto srcMemorySpace = getSourceMemorySpace();
372  auto tdescMemorySpace = static_cast<unsigned>(tdescTy.getMemorySpace());
373  if (srcMemorySpace != tdescMemorySpace)
374  return emitOpError("Memory space mismatch.")
375  << " Source: " << srcMemorySpace
376  << ", TensorDesc: " << tdescMemorySpace;
377 
378  auto chunkSize = tdescTy.getChunkSize();
379 
380  // check chunk_size
381  llvm::SmallVector<int64_t> supportedChunkSizes = {1, 2, 3, 4, 8,
382  16, 32, 64, 128, 256};
383  if (!llvm::is_contained(supportedChunkSizes, chunkSize))
384  return emitOpError("Invalid chunk_size. Supported values are 1, 2, 3, 4, "
385  "8, 16, 32, 64, 128, or 256.");
386 
387  // check total size
388  auto elemBits = tdescTy.getElementType().getIntOrFloatBitWidth();
389  auto bitsPerLane = elemBits * chunkSize;
390  if (chunkSize > 1 && bitsPerLane % 32) {
391  // For 8-bit and 16-bit data, the hardware only supports chunk size of 1.
392  // For 32-bit data, the hardware can support larger larger chunk size. So
393  // we can bitcast 8-bit/16-bit data to 32-bit data for better performance.
394  // But this requires the total size is 32 bit aligned to make the
395  // optimization work.
396  return emitOpError(
397  "access size (chunk_size * sizeof(elemTy)) should be 32-bit aligned.");
398  }
399 
400  auto lscConstraints = 512 * 8; // each access is upto 512 bytes.
401  if (elemBits * tdescTy.getNumElements() > lscConstraints)
402  return emitOpError("total access size (simd_lanes * chunk_size * "
403  "sizeof(elemTy)) is upto 512 bytes.");
404 
405  SmallVector<int64_t> shape({(int64_t)getNumOffsets()});
406  if (chunkSize != 1)
407  shape.push_back(chunkSize);
408 
409  auto tdescShape = getShapeOf(tdescTy);
410  if (shape != tdescShape)
411  return emitOpError("Incorrect TensorDesc shape. ")
412  << "Expected is " << makeString(shape) << "\n";
413 
414  return success();
415 }
416 
417 //===----------------------------------------------------------------------===//
418 // XeGPU_PrefetchOp
419 //===----------------------------------------------------------------------===//
420 LogicalResult PrefetchOp::verify() {
421  auto tdescTy = getTensorDescType();
422  if (!tdescTy.isScattered())
423  return emitOpError("Expects a scattered TensorDesc.\n");
424 
425  if (!isReadHintOrNone(getL1HintAttr()))
426  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
427 
428  if (!isReadHintOrNone(getL2HintAttr()))
429  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
430 
431  if (!isReadHintOrNone(getL3HintAttr()))
432  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
433 
434  return success();
435 }
436 
437 //===----------------------------------------------------------------------===//
438 // XeGPU_LoadGatherOp
439 //===----------------------------------------------------------------------===//
440 LogicalResult LoadGatherOp::verify() {
441  auto tdescTy = getTensorDescType();
442  auto maskTy = getMaskType();
443  auto valueTy = getValueType();
444 
445  if (!tdescTy.isScattered())
446  return emitOpError("Expects a scattered TensorDesc.\n");
447 
448  if (!isReadHintOrNone(getL1HintAttr()))
449  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
450 
451  if (!isReadHintOrNone(getL2HintAttr()))
452  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
453 
454  if (!isReadHintOrNone(getL3HintAttr()))
455  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
456 
457  auto tdescElemTy = tdescTy.getElementType();
458  auto valueElemTy = getElementType();
459  if (tdescElemTy != valueElemTy)
460  return emitOpError(
461  "Value should have the same element type as TensorDesc.");
462 
463  auto maskShape = getShapeOf(maskTy);
464  auto valueShape = getShapeOf(valueTy);
465  auto tdescShape = getShapeOf(tdescTy);
466 
467  if (tdescShape[0] != maskShape[0])
468  return emitOpError("dim-0 of the Mask and TensorDesc should be the same.");
469 
470  if (tdescTy.getRank() == 2) {
471  if (!getTransposeAttr())
472  return emitOpError("load_gather has to be transposed.");
473  transpose({1, 0}, tdescShape);
474  }
475 
476  if (valueShape != tdescShape)
477  return emitOpError("Unexpected result shape")
478  << "(Expected shape: " << makeString(tdescShape)
479  << ", Given shape: " << makeString(valueShape) << ").\n";
480 
481  return success();
482 }
483 
484 //===----------------------------------------------------------------------===//
485 // XeGPU_StoreScatterOp
486 //===----------------------------------------------------------------------===//
487 LogicalResult StoreScatterOp::verify() {
488  auto tdescTy = getTensorDescType();
489  if (!tdescTy.isScattered())
490  return emitOpError("Expects a scattered TensorDesc.\n");
491 
492  if (!isWriteHintOrNone(getL1HintAttr()))
493  return emitOpError("invlid l1_hint: ") << getL1HintAttr();
494 
495  if (!isWriteHintOrNone(getL2HintAttr()))
496  return emitOpError("invlid l2_hint: ") << getL2HintAttr();
497 
498  if (!isWriteHintOrNone(getL3HintAttr()))
499  return emitOpError("invlid l3_hint: ") << getL3HintAttr();
500 
501  auto maskTy = getMaskType();
502  auto valueTy = getValueType();
503  auto maskShape = getShapeOf(maskTy);
504  auto tdescShape = getShapeOf(tdescTy);
505  auto valueShape = getShapeOf(valueTy);
506  if (tdescShape[0] != maskShape[0])
507  return emitOpError("dim-0 of the Mask and TensorDesc should be the same.");
508 
509  if (tdescTy.getRank() == 2) {
510  if (!getTransposeAttr())
511  return emitOpError("load_gather has to be transposed.");
512  transpose({1, 0}, tdescShape);
513  }
514 
515  if (valueShape != tdescShape)
516  return emitOpError("Unexpected value shape")
517  << "(Expected shape: " << makeString(tdescShape)
518  << ", Given shape: " << makeString(valueShape) << ").\n";
519 
520  return success();
521 }
522 
523 //===----------------------------------------------------------------------===//
524 // XeGPU_UpdateOffsetOp
525 //===----------------------------------------------------------------------===//
526 void UpdateOffsetOp::build(OpBuilder &builder, OperationState &state,
527  mlir::Value tensorDesc,
529  auto tdescTy = mlir::dyn_cast<TensorDescType>(tensorDesc.getType());
530  assert(tdescTy && "Expecting the source is a TensorDescType value.");
531  auto loc = tensorDesc.getLoc();
532  int64_t size = static_cast<int64_t>(offsets.size());
533  auto type = VectorType::get({size}, builder.getIndexType());
534  auto values = getValueOrCreateConstantIndexOp(builder, loc, offsets);
535  auto offset = builder.create<vector::FromElementsOp>(loc, type, values);
536  build(builder, state, tdescTy, tensorDesc, offset);
537 }
538 
539 void UpdateOffsetOp::build(OpBuilder &builder, OperationState &state,
540  Value tensorDesc, llvm::ArrayRef<int64_t> offsets) {
541  auto ofrs = getAsIndexOpFoldResult(builder.getContext(), offsets);
542  build(builder, state, tensorDesc, ofrs);
543 }
544 
545 //===----------------------------------------------------------------------===//
546 // XeGPU_DpasOp
547 //===----------------------------------------------------------------------===//
548 LogicalResult DpasOp::verify() {
549  int64_t lhsRank = getLhsType().getRank();
550  int64_t rhsRank = getRhsType().getRank();
551 
552  if (lhsRank != 2 || (rhsRank != 2 && rhsRank != 3))
553  return emitOpError("expecting lhs to be a 2D vector, and rhs to be either "
554  "2D or 3D (packed) vector.");
555 
556  auto lhsShape = getLhsType().getShape();
557  auto rhsShape = getRhsType().getShape();
558  auto bK = rhsRank == 3 ? rhsShape[0] * rhsShape[2] : rhsShape[0];
559  if (bK != lhsShape[1])
560  return emitOpError("K-dimension mismatch.");
561 
562  return success();
563 }
564 
565 } // namespace xegpu
566 } // namespace mlir
567 
568 #include <mlir/Dialect/XeGPU/IR/XeGPUEnums.cpp.inc>
569 #define GET_OP_CLASSES
570 #include <mlir/Dialect/XeGPU/IR/XeGPU.cpp.inc>
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Definition: SPIRVOps.cpp:215
This class helps build Operations.
Definition: Builders.h:216
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:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:129
Location getLoc() const
Return the location of this value.
Definition: Value.cpp:26
static std::string makeString(T array, bool breakline=false)
Definition: XeGPUOps.cpp:30
static int64_t getRankOf(Value val)
Definition: XeGPUOps.cpp:53
static bool isWriteHintOrNone(const CachePolicyAttr &attr)
Definition: XeGPUOps.cpp:68
static bool isReadHintOrNone(const CachePolicyAttr &attr)
Definition: XeGPUOps.cpp:60
static void transpose(llvm::ArrayRef< int64_t > trans, SmallVector< int64_t > &shape)
Definition: XeGPUOps.cpp:22
static SmallVector< int64_t > getShapeOf(Type type)
Definition: XeGPUOps.cpp:44
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
OpFoldResult getAsIndexOpFoldResult(MLIRContext *ctx, int64_t val)
Convert int64_t to integer attributes of index type and return them as OpFoldResult.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition: Utils.cpp:305
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:498
void dispatchIndexOpFoldResults(ArrayRef< OpFoldResult > ofrs, SmallVectorImpl< Value > &dynamicVec, SmallVectorImpl< int64_t > &staticVec)
Helper function to dispatch multiple OpFoldResults according to the behavior of dispatchIndexOpFoldRe...
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
Definition: Utils.cpp:112
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:425
This represents an operation in an abstracted form, suitable for use with the builder APIs.