MLIR  18.0.0git
VectorDropLeadUnitDim.cpp
Go to the documentation of this file.
1 //===- VectorDropLeadUnitDim.cpp - Conversion within the Vector dialect ---===//
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 
14 #include "mlir/IR/Builders.h"
15 #include "mlir/IR/TypeUtilities.h"
16 
17 #define DEBUG_TYPE "vector-drop-unit-dim"
18 
19 using namespace mlir;
20 using namespace mlir::vector;
21 
22 // Trims leading one dimensions from `oldType` and returns the result type.
23 // Returns `vector<1xT>` if `oldType` only has one element.
24 static VectorType trimLeadingOneDims(VectorType oldType) {
25  ArrayRef<int64_t> oldShape = oldType.getShape();
26  ArrayRef<int64_t> newShape = oldShape;
27 
28  ArrayRef<bool> oldScalableDims = oldType.getScalableDims();
29  ArrayRef<bool> newScalableDims = oldScalableDims;
30 
31  while (!newShape.empty() && newShape.front() == 1 &&
32  !newScalableDims.front()) {
33  newShape = newShape.drop_front(1);
34  newScalableDims = newScalableDims.drop_front(1);
35  }
36 
37  // Make sure we have at least 1 dimension per vector type requirements.
38  if (newShape.empty()) {
39  newShape = oldShape.take_back();
40  newScalableDims = oldType.getScalableDims().take_back();
41  }
42  return VectorType::get(newShape, oldType.getElementType(), newScalableDims);
43 }
44 
45 /// Return a smallVector of size `rank` containing all zeros.
46 static SmallVector<int64_t> splatZero(int64_t rank) {
47  return SmallVector<int64_t>(rank, 0);
48 }
49 namespace {
50 
51 // Casts away leading one dimensions in vector.extract_strided_slice's vector
52 // input by inserting vector.broadcast.
53 struct CastAwayExtractStridedSliceLeadingOneDim
54  : public OpRewritePattern<vector::ExtractStridedSliceOp> {
56 
57  LogicalResult matchAndRewrite(vector::ExtractStridedSliceOp extractOp,
58  PatternRewriter &rewriter) const override {
59  // vector.extract_strided_slice requires the input and output vector to have
60  // the same rank. Here we drop leading one dimensions from the input vector
61  // type to make sure we don't cause mismatch.
62  VectorType oldSrcType = extractOp.getSourceVectorType();
63  VectorType newSrcType = trimLeadingOneDims(oldSrcType);
64 
65  if (newSrcType.getRank() == oldSrcType.getRank())
66  return failure();
67 
68  int64_t dropCount = oldSrcType.getRank() - newSrcType.getRank();
69 
70  VectorType oldDstType = extractOp.getType();
71  VectorType newDstType =
72  VectorType::get(oldDstType.getShape().drop_front(dropCount),
73  oldDstType.getElementType());
74 
75  Location loc = extractOp.getLoc();
76 
77  Value newSrcVector = rewriter.create<vector::ExtractOp>(
78  loc, extractOp.getVector(), splatZero(dropCount));
79 
80  // The offsets/sizes/strides attribute can have a less number of elements
81  // than the input vector's rank: it is meant for the leading dimensions.
82  auto newOffsets = rewriter.getArrayAttr(
83  extractOp.getOffsets().getValue().drop_front(dropCount));
84  auto newSizes = rewriter.getArrayAttr(
85  extractOp.getSizes().getValue().drop_front(dropCount));
86  auto newStrides = rewriter.getArrayAttr(
87  extractOp.getStrides().getValue().drop_front(dropCount));
88 
89  auto newExtractOp = rewriter.create<vector::ExtractStridedSliceOp>(
90  loc, newDstType, newSrcVector, newOffsets, newSizes, newStrides);
91 
92  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(extractOp, oldDstType,
93  newExtractOp);
94 
95  return success();
96  }
97 };
98 
99 // Casts away leading one dimensions in vector.insert_strided_slice's vector
100 // inputs by inserting vector.broadcast.
101 struct CastAwayInsertStridedSliceLeadingOneDim
102  : public OpRewritePattern<vector::InsertStridedSliceOp> {
104 
105  LogicalResult matchAndRewrite(vector::InsertStridedSliceOp insertOp,
106  PatternRewriter &rewriter) const override {
107  VectorType oldSrcType = insertOp.getSourceVectorType();
108  VectorType newSrcType = trimLeadingOneDims(oldSrcType);
109  VectorType oldDstType = insertOp.getDestVectorType();
110  VectorType newDstType = trimLeadingOneDims(oldDstType);
111 
112  int64_t srcDropCount = oldSrcType.getRank() - newSrcType.getRank();
113  int64_t dstDropCount = oldDstType.getRank() - newDstType.getRank();
114  if (srcDropCount == 0 && dstDropCount == 0)
115  return failure();
116 
117  // Trim leading one dimensions from both operands.
118  Location loc = insertOp.getLoc();
119 
120  Value newSrcVector = rewriter.create<vector::ExtractOp>(
121  loc, insertOp.getSource(), splatZero(srcDropCount));
122  Value newDstVector = rewriter.create<vector::ExtractOp>(
123  loc, insertOp.getDest(), splatZero(dstDropCount));
124 
125  auto newOffsets = rewriter.getArrayAttr(
126  insertOp.getOffsets().getValue().take_back(newDstType.getRank()));
127  auto newStrides = rewriter.getArrayAttr(
128  insertOp.getStrides().getValue().take_back(newSrcType.getRank()));
129 
130  auto newInsertOp = rewriter.create<vector::InsertStridedSliceOp>(
131  loc, newDstType, newSrcVector, newDstVector, newOffsets, newStrides);
132 
133  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(insertOp, oldDstType,
134  newInsertOp);
135 
136  return success();
137  }
138 };
139 
140 // Casts away leading one dimensions in vector.insert's vector inputs by
141 // inserting vector.broadcast.
142 struct CastAwayInsertLeadingOneDim : public OpRewritePattern<vector::InsertOp> {
144 
145  LogicalResult matchAndRewrite(vector::InsertOp insertOp,
146  PatternRewriter &rewriter) const override {
147  Type oldSrcType = insertOp.getSourceType();
148  Type newSrcType = oldSrcType;
149  int64_t oldSrcRank = 0, newSrcRank = 0;
150  if (auto type = dyn_cast<VectorType>(oldSrcType)) {
151  newSrcType = trimLeadingOneDims(type);
152  oldSrcRank = type.getRank();
153  newSrcRank = cast<VectorType>(newSrcType).getRank();
154  }
155 
156  VectorType oldDstType = insertOp.getDestVectorType();
157  VectorType newDstType = trimLeadingOneDims(oldDstType);
158 
159  int64_t srcDropCount = oldSrcRank - newSrcRank;
160  int64_t dstDropCount = oldDstType.getRank() - newDstType.getRank();
161  if (srcDropCount == 0 && dstDropCount == 0)
162  return failure();
163 
164  // Trim leading one dimensions from both operands.
165  Location loc = insertOp.getLoc();
166 
167  Value newSrcVector = insertOp.getSource();
168  if (oldSrcRank != 0) {
169  newSrcVector = rewriter.create<vector::ExtractOp>(
170  loc, insertOp.getSource(), splatZero(srcDropCount));
171  }
172  Value newDstVector = rewriter.create<vector::ExtractOp>(
173  loc, insertOp.getDest(), splatZero(dstDropCount));
174 
175  // New position rank needs to be computed in two steps: (1) if destination
176  // type has leading unit dims, we also trim the position array accordingly,
177  // then (2) if source type also has leading unit dims, we need to append
178  // zeroes to the position array accordingly.
179  unsigned oldPosRank = insertOp.getPosition().size();
180  unsigned newPosRank = std::max<int64_t>(0, oldPosRank - dstDropCount);
181  SmallVector<int64_t> newPositions =
182  llvm::to_vector(insertOp.getPosition().take_back(newPosRank));
183  newPositions.resize(newDstType.getRank() - newSrcRank, 0);
184 
185  auto newInsertOp = rewriter.create<vector::InsertOp>(
186  loc, newDstType, newSrcVector, newDstVector, newPositions);
187 
188  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(insertOp, oldDstType,
189  newInsertOp);
190 
191  return success();
192  }
193 };
194 
195 // Turns vector.transfer_read on vector with leading 1 dimensions into
196 // vector.shape_cast followed by vector.transfer_read on vector without leading
197 // 1 dimensions.
198 struct CastAwayTransferReadLeadingOneDim
199  : public OpRewritePattern<vector::TransferReadOp> {
201 
202  LogicalResult matchAndRewrite(vector::TransferReadOp read,
203  PatternRewriter &rewriter) const override {
204  // TODO: support 0-d corner case.
205  if (read.getTransferRank() == 0)
206  return failure();
207 
208  if (read.getMask())
209  return failure();
210 
211  auto shapedType = cast<ShapedType>(read.getSource().getType());
212  if (shapedType.getElementType() != read.getVectorType().getElementType())
213  return failure();
214 
215  VectorType oldType = read.getVectorType();
216  VectorType newType = trimLeadingOneDims(oldType);
217 
218  if (newType == oldType)
219  return failure();
220 
221  AffineMap oldMap = read.getPermutationMap();
222  ArrayRef<AffineExpr> newResults =
223  oldMap.getResults().take_back(newType.getRank());
224  AffineMap newMap =
225  AffineMap::get(oldMap.getNumDims(), oldMap.getNumSymbols(), newResults,
226  rewriter.getContext());
227 
228  ArrayAttr inBoundsAttr;
229  if (read.getInBounds())
230  inBoundsAttr = rewriter.getArrayAttr(
231  read.getInBoundsAttr().getValue().take_back(newType.getRank()));
232 
233  auto newRead = rewriter.create<vector::TransferReadOp>(
234  read.getLoc(), newType, read.getSource(), read.getIndices(),
235  AffineMapAttr::get(newMap), read.getPadding(), /*mask=*/Value(),
236  inBoundsAttr);
237  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(read, oldType, newRead);
238 
239  return success();
240  }
241 };
242 
243 // Turns vector.transfer_write on vector with leading 1 dimensions into
244 // vector.shape_cast followed by vector.transfer_write on vector without leading
245 // 1 dimensions.
246 struct CastAwayTransferWriteLeadingOneDim
247  : public OpRewritePattern<vector::TransferWriteOp> {
249 
250  LogicalResult matchAndRewrite(vector::TransferWriteOp write,
251  PatternRewriter &rewriter) const override {
252  // TODO: support 0-d corner case.
253  if (write.getTransferRank() == 0)
254  return failure();
255 
256  if (write.getMask())
257  return failure();
258 
259  auto shapedType = dyn_cast<ShapedType>(write.getSource().getType());
260  if (shapedType.getElementType() != write.getVectorType().getElementType())
261  return failure();
262 
263  VectorType oldType = write.getVectorType();
264  VectorType newType = trimLeadingOneDims(oldType);
265  if (newType == oldType)
266  return failure();
267  int64_t dropDim = oldType.getRank() - newType.getRank();
268 
269  AffineMap oldMap = write.getPermutationMap();
270  ArrayRef<AffineExpr> newResults =
271  oldMap.getResults().take_back(newType.getRank());
272  AffineMap newMap =
273  AffineMap::get(oldMap.getNumDims(), oldMap.getNumSymbols(), newResults,
274  rewriter.getContext());
275 
276  ArrayAttr inBoundsAttr;
277  if (write.getInBounds())
278  inBoundsAttr = rewriter.getArrayAttr(
279  write.getInBoundsAttr().getValue().take_back(newType.getRank()));
280 
281  auto newVector = rewriter.create<vector::ExtractOp>(
282  write.getLoc(), write.getVector(), splatZero(dropDim));
283  rewriter.replaceOpWithNewOp<vector::TransferWriteOp>(
284  write, newVector, write.getSource(), write.getIndices(),
285  AffineMapAttr::get(newMap), inBoundsAttr);
286 
287  return success();
288  }
289 };
290 
291 } // namespace
292 
294 mlir::vector::castAwayContractionLeadingOneDim(vector::ContractionOp contractOp,
295  RewriterBase &rewriter) {
296  VectorType oldAccType = dyn_cast<VectorType>(contractOp.getAccType());
297  if (oldAccType == nullptr)
298  return failure();
299  if (oldAccType.getRank() < 2)
300  return failure();
301  if (oldAccType.getShape()[0] != 1)
302  return failure();
303  // currently we support only dropping one dim but the pattern can be applied
304  // greedily to drop more.
305  int64_t dropDim = 1;
306 
307  auto oldIndexingMaps = contractOp.getIndexingMapsArray();
308  SmallVector<AffineMap> newIndexingMaps;
309 
310  auto oldIteratorTypes = contractOp.getIteratorTypes();
311  SmallVector<Attribute> newIteratorTypes;
312 
313  int64_t dimToDrop = oldIndexingMaps[2].getDimPosition(0);
314 
315  if (!isParallelIterator(oldIteratorTypes[dimToDrop]))
316  // only parallel type iterators can be dropped.
317  return failure();
318 
319  for (const auto &it : llvm::enumerate(oldIteratorTypes)) {
320  int64_t currDim = it.index();
321  if (currDim == dimToDrop)
322  continue;
323  newIteratorTypes.push_back(it.value());
324  }
325 
326  SmallVector<Value> operands = {contractOp.getLhs(), contractOp.getRhs(),
327  contractOp.getAcc()};
328  SmallVector<Value> newOperands;
329 
330  for (const auto &it : llvm::enumerate(oldIndexingMaps)) {
331  // Check if the dim to be dropped exists as a leading dim in the operand
332  // if it does then we use vector.extract to drop it.
333  bool validExtract = false;
334  SmallVector<AffineExpr> results;
335  auto map = it.value();
336  int64_t orginalZeroDim = it.value().getDimPosition(0);
337  if (orginalZeroDim != dimToDrop) {
338  // There are two reasons to be in this path, 1. We need to
339  // tranpose the operand to make the dim to be dropped
340  // leading. 2. The dim to be dropped does not exist and in
341  // that case we dont want to add a unit tranpose but we must
342  // check all the indices to make sure this is the case.
343  bool tranposeNeeded = false;
345  SmallVector<AffineExpr> transposeResults;
346 
347  for (int64_t i = 0, e = map.getNumResults(); i < e; ++i) {
348  int64_t currDim = map.getDimPosition(i);
349  if (currDim == dimToDrop) {
350  tranposeNeeded = true;
351  perm.insert(perm.begin(), i);
352  auto targetExpr = rewriter.getAffineDimExpr(currDim);
353  transposeResults.insert(transposeResults.begin(), targetExpr);
354  } else {
355  perm.push_back(i);
356  auto targetExpr = rewriter.getAffineDimExpr(currDim);
357  transposeResults.push_back(targetExpr);
358  }
359  }
360  // Do the tranpose now if needed so that we can drop the
361  // correct dim using extract later.
362  if (tranposeNeeded) {
363  map = AffineMap::get(map.getNumDims(), 0, transposeResults,
364  contractOp.getContext());
365  operands[it.index()] = rewriter.create<vector::TransposeOp>(
366  contractOp.getLoc(), operands[it.index()], perm);
367  }
368  }
369  // We have taken care to have the dim to be dropped be
370  // the leading dim. If its still not leading that means it
371  // does not exist in this operand and hence we do not need
372  // an extract.
373  if (map.getDimPosition(0) == dimToDrop)
374  validExtract = true;
375 
376  for (int64_t i = 0, e = map.getNumResults(); i < e; ++i) {
377  int64_t currDim = map.getDimPosition(i);
378  if (currDim == dimToDrop)
379  // This is the dim we are dropping.
380  continue;
381  auto targetExpr = rewriter.getAffineDimExpr(
382  currDim < dimToDrop ? currDim : currDim - 1);
383  results.push_back(targetExpr);
384  }
385  newIndexingMaps.push_back(AffineMap::get(map.getNumDims() - 1, 0, results,
386  contractOp.getContext()));
387  // Extract if its a valid extraction, otherwise use the operand
388  // without extraction.
389  newOperands.push_back(
390  validExtract ? rewriter.create<vector::ExtractOp>(contractOp.getLoc(),
391  operands[it.index()],
392  splatZero(dropDim))
393  : operands[it.index()]);
394  }
395  auto newContractOp = rewriter.create<vector::ContractionOp>(
396  contractOp.getLoc(), newOperands[0], newOperands[1], newOperands[2],
397  rewriter.getAffineMapArrayAttr(newIndexingMaps),
398  rewriter.getArrayAttr(newIteratorTypes), contractOp.getKind());
399  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(
400  contractOp, contractOp->getResultTypes()[0], newContractOp);
401  return success();
402 }
403 
404 namespace {
405 
406 /// Turns vector.contract on vector with leading 1 dimensions into
407 /// vector.extract followed by vector.contract on vector without leading
408 /// 1 dimensions. Also performs tranpose of lhs and rhs operands if required
409 /// prior to extract.
410 struct CastAwayContractionLeadingOneDim
411  : public OpRewritePattern<vector::ContractionOp> {
413 
414  LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
415  PatternRewriter &rewriter) const override {
416  return castAwayContractionLeadingOneDim(contractOp, rewriter);
417  }
418 };
419 
420 /// Looks at elementwise operations on vectors with at least one leading
421 /// dimension equal 1, e.g. vector<1x[4]x1xf32> (but not vector<2x[4]x1xf32>),
422 /// and cast aways the leading one dimensions (_plural_) and then broadcasts
423 /// the results.
424 ///
425 /// Example before:
426 /// %1 = arith.mulf %arg0, %arg1 : vector<1x4x1xf32>
427 /// Example after:
428 /// %2 = arith.mulf %0, %1 : vector<4x1xf32>
429 /// %3 = vector.broadcast %2 : vector<4x1xf32> to vector<1x4x1xf32>
430 ///
431 /// Does support scalable vectors.
432 class CastAwayElementwiseLeadingOneDim : public RewritePattern {
433 public:
434  CastAwayElementwiseLeadingOneDim(MLIRContext *context,
435  PatternBenefit benefit = 1)
436  : RewritePattern(MatchAnyOpTypeTag(), benefit, context) {}
437 
438  LogicalResult matchAndRewrite(Operation *op,
439  PatternRewriter &rewriter) const override {
441  return failure();
442  auto vecType = dyn_cast<VectorType>(op->getResultTypes()[0]);
443  if (!vecType)
444  return failure();
445  VectorType newVecType = trimLeadingOneDims(vecType);
446  if (newVecType == vecType)
447  return failure();
448  int64_t dropDim = vecType.getRank() - newVecType.getRank();
449  SmallVector<Value, 4> newOperands;
450  for (Value operand : op->getOperands()) {
451  if (auto opVecType = dyn_cast<VectorType>(operand.getType())) {
452  newOperands.push_back(rewriter.create<vector::ExtractOp>(
453  op->getLoc(), operand, splatZero(dropDim)));
454  } else {
455  newOperands.push_back(operand);
456  }
457  }
458  Operation *newOp =
459  rewriter.create(op->getLoc(), op->getName().getIdentifier(),
460  newOperands, newVecType, op->getAttrs());
461  rewriter.replaceOpWithNewOp<vector::BroadcastOp>(op, vecType,
462  newOp->getResult(0));
463  return success();
464  }
465 };
466 
467 } // namespace
468 
470  RewritePatternSet &patterns, PatternBenefit benefit) {
471  patterns
472  .add<CastAwayExtractStridedSliceLeadingOneDim,
473  CastAwayInsertStridedSliceLeadingOneDim, CastAwayInsertLeadingOneDim,
474  CastAwayTransferReadLeadingOneDim,
475  CastAwayTransferWriteLeadingOneDim, CastAwayElementwiseLeadingOneDim,
476  CastAwayContractionLeadingOneDim>(patterns.getContext(), benefit);
477  populateShapeCastFoldingPatterns(patterns, benefit);
478 }
static SmallVector< int64_t > splatZero(int64_t rank)
Return a smallVector of size rank containing all zeros.
static VectorType trimLeadingOneDims(VectorType oldType)
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:44
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumSymbols() const
Definition: AffineMap.cpp:341
unsigned getNumDims() const
Definition: AffineMap.cpp:337
ArrayRef< AffineExpr > getResults() const
Definition: AffineMap.cpp:350
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
Definition: AffineMap.cpp:225
AffineExpr getAffineDimExpr(unsigned position)
Definition: Builders.cpp:353
MLIRContext * getContext() const
Definition: Builders.h:55
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition: Builders.cpp:273
ArrayAttr getAffineMapArrayAttr(ArrayRef< AffineMap > values)
Definition: Builders.cpp:325
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:446
StringAttr getIdentifier() const
Return the name of this operation as a StringAttr.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Definition: Operation.h:469
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
result_type_range getResultTypes()
Definition: Operation.h:423
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition: Operation.h:373
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:399
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
Definition: PatternMatch.h:33
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:727
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
RewritePattern is the common base class for all DAG to DAG replacements.
Definition: PatternMatch.h:245
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:399
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replaces the result op with a new op that is created without verification.
Definition: PatternMatch.h:539
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
Definition: Operation.cpp:1344
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:285
LogicalResult castAwayContractionLeadingOneDim(vector::ContractionOp contractOp, RewriterBase &rewriter)
Cast away the leading unit dim, if exists, for the given contract op.
void populateShapeCastFoldingPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Collect a set of vector.shape_cast folding patterns.
bool isParallelIterator(Attribute attr)
Returns true if attr has "parallel" iterator type semantics.
Definition: VectorOps.h:125
void populateCastAwayVectorLeadingOneDimPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Collect a set of leading one dimension removal patterns.
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Definition: PatternMatch.h:357
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
Patterns must specify the root operation name they match against, and can also specify the benefit of...
Definition: PatternMatch.h:361