MLIR 24.0.0git
PrepareVectorContractLoops.cpp
Go to the documentation of this file.
1//===- PrepareVectorContractLoops.cpp -------------------------------------===//
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
16#include "llvm/ADT/SmallVectorExtras.h"
17#include "llvm/Support/DebugLog.h"
18
19#define DEBUG_TYPE "x86-prepare-vector-contract-loops"
20
21using namespace mlir;
22
23static vector::ContractionOp getCandidate(scf::ForOp loop) {
24 if (loop.getNumRegionIterArgs() != 1) {
25 LDBG() << "reject loop at " << loop.getLoc() << ": expected one iter_arg";
26 return {};
27 }
28
29 auto yield = cast<scf::YieldOp>(loop.getBody()->getTerminator());
30 for (Operation &op : loop.getBody()->without_terminator()) {
31 auto contract = dyn_cast<vector::ContractionOp>(&op);
32 if (!contract)
33 continue;
34 if (contract.getKind() != vector::CombiningKind::ADD ||
35 contract.getAcc() != loop.getRegionIterArgs().front() ||
36 !contract.getAcc().hasOneUse() || !contract.getResult().hasOneUse() ||
37 yield->getOperand(0) != contract.getResult()) {
38 LDBG() << "reject contraction at " << contract.getLoc()
39 << ": not a single loop-carried accumulation";
40 continue;
41 }
42
43 auto iterators = contract.getIteratorTypesArray();
44 auto maps = contract.getIndexingMapsArray();
45 MLIRContext *ctx = contract.getContext();
46 auto m = getAffineDimExpr(0, ctx);
47 auto n = getAffineDimExpr(1, ctx);
48 auto k = getAffineDimExpr(2, ctx);
49 auto par = vector::IteratorType::parallel;
50 auto red = vector::IteratorType::reduction;
51 if (llvm::equal(iterators, ArrayRef{par, par, red}) &&
52 maps[0] == AffineMap::get(3, 0, {m, k}, ctx) &&
53 maps[1] == AffineMap::get(3, 0, {k, n}, ctx) &&
54 maps[2] == AffineMap::get(3, 0, {m, n}, ctx))
55 return contract;
56 LDBG() << "reject contraction at " << contract.getLoc()
57 << ": noncanonical matmul layout or iterators";
58 }
59 return {};
60}
61
62// Look through reshapes/broadcasts without changing the row-major element
63// order. A broadcast is safe to skip if it adds unit dimensions only.
65 while (isa_and_present<vector::ShapeCastOp, vector::BroadcastOp>(
66 v.getDefiningOp())) {
67 Value source = v.getDefiningOp()->getOperand(0);
68 auto sourceType = dyn_cast<VectorType>(source.getType());
69 if (!sourceType || sourceType.getNumElements() !=
70 cast<VectorType>(v.getType()).getNumElements())
71 break;
72 v = source;
73 }
74 return v;
75}
76
77// Find the source and VNNI lane j of a split: v[i] = src[factor * i + j].
78// A split step of width s keeps every s-th element. Match either form below
79// (unit dimensions may also be present):
80//
81// %even, %odd = vector.deinterleave %src // s = 2
82// : vector<4x8xbf16> -> vector<4x4xbf16>
83//
84// or:
85//
86// %packed = vector.shape_cast %src
87// : vector<4x8xbf16> to vector<4x4x2xbf16>
88// %split = vector.transpose %packed, [2, 0, 1]
89// : vector<4x4x2xbf16> to vector<2x4x4xbf16>
90// %even = vector.extract %split[0]
91// : vector<4x4xbf16> from vector<2x4x4xbf16>
92// %odd = vector.extract %split[1]
93// : vector<4x4xbf16> from vector<2x4x4xbf16>
94//
95// If s < factor, the split's input must itself come from splits of src
96// totaling factor / s. For example, for factor = 4, a 4-way transpose/extract
97// split of src matches, as do two levels of binary splits:
98//
99// %even, %odd = vector.deinterleave %src // lanes {0, 2} and {1, 3}
100// %l1, %l3 = vector.deinterleave %odd // %l3[i] = src[4 * i + 3]
101//
102// Splits closer to src give the low lane bits; result j of the split that
103// produces v gives the high bits.
104static std::optional<std::pair<Value, int64_t>> matchSplit(Value v,
105 int64_t factor) {
106 v = skipReshapes(v);
107 if (factor == 1)
108 return std::pair(v, int64_t(0));
109
110 auto matchSource =
111 [&](Value source, int64_t ways,
112 int64_t j) -> std::optional<std::pair<Value, int64_t>> {
113 if (factor % ways != 0)
114 return std::nullopt;
115 auto lane = matchSplit(source, factor / ways);
116 if (!lane)
117 return std::nullopt;
118 lane->second += factor / ways * j;
119 return lane;
120 };
121 if (auto deinterleave = v.getDefiningOp<vector::DeinterleaveOp>())
122 return matchSource(deinterleave.getSource(), 2,
123 cast<OpResult>(v).getResultNumber());
124
125 auto extract = v.getDefiningOp<vector::ExtractOp>();
126 auto transpose =
127 extract ? extract.getSource().getDefiningOp<vector::TransposeOp>()
128 : vector::TransposeOp();
129 auto type = dyn_cast<VectorType>(v.getType());
130 if (!transpose || !type || extract.hasDynamicPosition() ||
131 transpose.getSourceVectorType().isScalable())
132 return std::nullopt;
133
134 ArrayRef<int64_t> shape = transpose.getSourceVectorType().getShape();
135 auto isNonUnit = [&](int64_t dim) { return shape[dim] != 1; };
137 llvm::filter_to_vector(llvm::seq<int64_t>(0, shape.size()), isNonUnit);
138 if (order.empty())
139 return std::nullopt;
140 int64_t ways = shape[order.back()];
141
142 std::rotate(order.begin(), std::prev(order.end()), order.end());
143 ArrayRef<int64_t> perm = transpose.getPermutation();
144 if (llvm::filter_to_vector(perm, isNonUnit) != order)
145 return std::nullopt;
146
147 // The split dimension is now first among the non-unit dimensions. Keeping
148 // exactly 1 / ways of the elements means the extract indexes that dimension;
149 // any other dimensions it indexes must be unit dimensions.
150 if (ways * type.getNumElements() !=
151 transpose.getSourceVectorType().getNumElements())
152 return std::nullopt;
153
154 int64_t j =
155 extract
156 .getStaticPosition()[llvm::find(perm, order.front()) - perm.begin()];
157 if (j < 0 || j >= ways)
158 return std::nullopt;
159
160 return matchSource(transpose.getVector(), ways, j);
161}
162
163// Find the inputs in VNNI-lane order for a join. A join step of width s
164// interleaves s inputs. Match either form below:
165//
166// %joined = vector.interleave %even, %odd // s = 2
167// : vector<4x1xbf16> -> vector<4x2xbf16>
168//
169// or s slice inserts in any order (shown for s = 2):
170//
171// %poison = ub.poison : vector<4x2xbf16>
172// %partial = vector.insert_strided_slice %odd, %poison
173// offsets = [0, 1], strides = [1, 1]
174// : vector<4x1xbf16> into vector<4x2xbf16>
175// %joined = vector.insert_strided_slice %even, %partial
176// offsets = [0, 0], strides = [1, 1]
177// : vector<4x1xbf16> into vector<4x2xbf16>
178//
179// If s < factor, each input must itself be a join of width factor / s
180// (possibly built from smaller joins).
181static std::optional<SmallVector<Value, 4>> matchJoin(Value v, int64_t factor) {
182 v = skipReshapes(v);
183 if (factor == 1)
184 return SmallVector<Value, 4>{v};
185
187 if (auto interleave = v.getDefiningOp<vector::InterleaveOp>()) {
188 parts = {interleave.getLhs(), interleave.getRhs()};
189 } else if (auto insert = v.getDefiningOp<vector::InsertStridedSliceOp>()) {
190 int64_t ways = insert.getDestVectorType().getShape().back();
191 if (ways < 2 || factor % ways != 0)
192 return std::nullopt;
193 parts.resize(ways);
194 // All slices must be complete and disjoint so the original destination
195 // contributes no elements to the result.
196 for (int64_t i = 0; i < ways; ++i) {
197 auto insert = v.getDefiningOp<vector::InsertStridedSliceOp>();
198 if (!insert)
199 return std::nullopt;
200 ArrayRef<int64_t> shape = insert.getDestVectorType().getShape();
201 SmallVector<int64_t> slice(shape.drop_back());
202 slice.push_back(1);
203 int64_t j =
204 extractFromIntegerArrayAttr<int64_t>(insert.getOffsets()).back();
205 if (insert.getSourceVectorType().getShape() != ArrayRef(slice) ||
206 parts[j])
207 return std::nullopt;
208 parts[j] = insert.getValueToStore();
209 v = insert.getDest();
210 }
211 } else {
212 return std::nullopt;
213 }
214
215 int64_t ways = parts.size();
216 if (factor % ways != 0)
217 return std::nullopt;
218 SmallVector<Value, 4> lanes(factor);
219 for (auto [j, part] : llvm::enumerate(parts)) {
220 auto inner = matchJoin(part, factor / ways);
221 if (!inner)
222 return std::nullopt;
223 for (auto [i, lane] : llvm::enumerate(*inner))
224 lanes[ways * i + j] = lane;
225 }
226 return lanes;
227}
228
229// Find the packed RHS so the contraction can use it without unpacking.
230// For a K x N RHS and VNNI factor f, require for each VNNI lane j:
231// rhs[f * r + j][c] = src[r][c][j],
232// where 0 <= j < f and src is viewed as K/f x N x f.
233// Match transpose/shape_cast unpacking (shown for f = 2):
234//
235// %packed = vector.shape_cast %src
236// : vector<4x6xbf16> to vector<4x3x2xbf16>
237// %transposed = vector.transpose %packed, [0, 2, 1]
238// : vector<4x3x2xbf16> to vector<4x2x3xbf16>
239// %rhs = vector.shape_cast %transposed
240// : vector<4x2x3xbf16> to vector<8x3xbf16>
241//
242// or split/transpose/join/transpose unpacking (shown for f = 2):
243//
244// %even, %odd = vector.deinterleave %src
245// : vector<4x6xbf16> -> vector<4x3xbf16>
246// %even_t = vector.transpose %even, [1, 0]
247// : vector<4x3xbf16> to vector<3x4xbf16>
248// %odd_t = vector.transpose %odd, [1, 0]
249// : vector<4x3xbf16> to vector<3x4xbf16>
250// %joined = vector.interleave %even_t, %odd_t
251// : vector<3x4xbf16> -> vector<3x8xbf16>
252// %rhs = vector.transpose %joined, [1, 0]
253// : vector<3x8xbf16> to vector<8x3xbf16>
254//
255// For f = 4, splits and joins may each be one 4-way transpose/extract or
256// slice-insert step, or two levels of binary steps. With binary steps, the
257// second-level splits produce VNNI lanes 0/2 and 1/3:
258//
259// %even, %odd = vector.deinterleave %src // lanes {0, 2} and {1, 3}
260// %l0, %l2 = vector.deinterleave %even
261// %l1, %l3 = vector.deinterleave %odd
262// // Transpose each lane %lj to %tj.
263// %even_t = vector.interleave %t0, %t2
264// %odd_t = vector.interleave %t1, %t3
265// %joined = vector.interleave %even_t, %odd_t
266//
267// Any binary split or join may instead use the transpose/extract or
268// slice-insert form.
269static Value matchUnpackedRhs(Value rhs, int64_t factor) {
270 auto type = cast<VectorType>(rhs.getType());
271 int64_t k = type.getDimSize(0) / factor, n = type.getDimSize(1);
272 auto transpose = skipReshapes(rhs).getDefiningOp<vector::TransposeOp>();
273 if (!transpose)
274 return {};
275
276 ArrayRef<int64_t> shape = transpose.getSourceVectorType().getShape();
277 ArrayRef<int64_t> perm = transpose.getPermutation();
278 if (shape.size() >= 3) {
279 size_t leading = shape.size() - 3;
280 auto expected = llvm::to_vector(llvm::seq<int64_t>(0, shape.size()));
281 std::swap(expected[leading + 1], expected[leading + 2]);
282 bool isUnpacking =
283 llvm::all_of(shape.take_front(leading),
284 [](int64_t dim) { return dim == 1; }) &&
285 shape.drop_front(leading) == ArrayRef<int64_t>{k, n, factor} &&
286 perm == ArrayRef(expected);
287 return isUnpacking ? skipReshapes(transpose.getVector()) : Value();
288 }
289
290 const int64_t swap[] = {1, 0};
291 if (perm != ArrayRef(swap) || shape != ArrayRef<int64_t>{n, factor * k})
292 return {};
293
294 auto lanes = matchJoin(transpose.getVector(), factor);
295 if (!lanes)
296 return {};
297
298 Value src;
299 for (auto [j, lane] : llvm::enumerate(*lanes)) {
300 auto laneTranspose =
301 skipReshapes(lane).getDefiningOp<vector::TransposeOp>();
302 if (!laneTranspose || laneTranspose.getPermutation() != ArrayRef(swap) ||
303 laneTranspose.getSourceVectorType().getShape() !=
304 ArrayRef<int64_t>{k, n})
305 return {};
306
307 auto source = matchSplit(laneTranspose.getVector(), factor);
308 if (!source || source->second != int64_t(j) ||
309 (src && source->first != src))
310 return {};
311
312 src = source->first;
313 }
314 return src;
315}
316
317static bool isSimpleReadOutsideLoop(vector::TransferReadOp read,
318 scf::ForOp loop) {
319 return read && read->getParentOp() == loop &&
320 isa<MemRefType>(read.getBase().getType()) &&
321 loop.isDefinedOutsideOfLoop(read.getBase()) &&
322 read.getPermutationMap().isMinorIdentity() && !read.getMask() &&
323 !read.hasOutOfBoundsDim();
324}
325
326namespace {
327struct ExpandedRead {
328 vector::TransferReadOp read;
329 MemRefType type;
330 SmallVector<ReassociationIndices> reassociation;
331 int64_t lastIndex;
332 // Static view of a dynamic last dimension, or null.
333 MemRefType view;
334};
335} // namespace
336
337static std::optional<ExpandedRead>
338getExpandableRead(vector::TransferReadOp read, unsigned factor,
339 scf::ForOp loop) {
340 if (!isSimpleReadOutsideLoop(read, loop))
341 return std::nullopt;
342 auto type = cast<MemRefType>(read.getBase().getType());
343 if (type.getElementType() != read.getVectorType().getElementType() ||
344 type.getRank() < 2)
345 return std::nullopt;
346 auto lastIndex = getConstantIntValue(read.getIndices().back());
347 if (!lastIndex || *lastIndex < 0 || *lastIndex % factor != 0)
348 return std::nullopt;
349
350 MemRefType view;
351 if (type.isDynamicDim(type.getRank() - 1)) {
352 SmallVector<int64_t> strides;
353 int64_t offset;
354 if (read.getVectorType().isScalable() ||
355 failed(type.getStridesAndOffset(strides, offset)))
356 return std::nullopt;
357 // The full dimension has a dynamic size, but this in-bounds read ends at
358 // a known index. Create a view whose last dimension ends there and give
359 // the divisibility check below a static size to work with.
360 SmallVector<int64_t> shape(type.getShape());
361 shape.back() = *lastIndex + read.getVectorType().getShape().back();
362 view = type = MemRefType::get(
363 shape, type.getElementType(),
364 StridedLayoutAttr::get(type.getContext(), offset, strides),
365 type.getMemorySpace());
366 }
367 if (type.getShape().back() % factor != 0)
368 return std::nullopt;
369
370 SmallVector<int64_t> shape(type.getShape());
371 shape.back() /= factor;
372 shape.push_back(factor);
374 for (int64_t i = 0; i < type.getRank(); ++i)
375 reassociation.push_back(i == type.getRank() - 1
376 ? ReassociationIndices{i, i + 1}
378 FailureOr<MemRefType> expanded =
379 memref::ExpandShapeOp::computeExpandedType(type, shape, reassociation);
380 if (failed(expanded))
381 return std::nullopt;
382 return ExpandedRead{read, *expanded, reassociation, *lastIndex / factor,
383 view};
384}
385
387 ExpandedRead &info, VectorType resultType) {
388 OpBuilder::InsertionGuard guard(rewriter);
389 rewriter.setInsertionPoint(info.read->getParentOp());
390 Value base = info.read.getBase();
391 if (info.view) {
392 // Unlike memref.subview, memref.reinterpret_cast is valid even when
393 // the loop runs zero times (which makes the view out of bounds).
394 auto metadata =
395 memref::ExtractStridedMetadataOp::create(rewriter, loc, base);
396 SmallVector<OpFoldResult> sizes = metadata.getConstifiedMixedSizes();
397 sizes.back() = rewriter.getIndexAttr(info.view.getShape().back());
398 base = memref::ReinterpretCastOp::create(
399 rewriter, loc, info.view, base, metadata.getConstifiedMixedOffset(),
400 sizes, metadata.getConstifiedMixedStrides());
401 }
402 Value expanded = memref::ExpandShapeOp::create(rewriter, loc, info.type, base,
403 info.reassociation);
404 Value lastIndex =
405 arith::ConstantIndexOp::create(rewriter, loc, info.lastIndex);
406 Value zero = arith::ConstantIndexOp::create(rewriter, loc, 0);
407 rewriter.setInsertionPoint(info.read);
408 SmallVector<Value> indices(info.read.getIndices());
409 indices.back() = lastIndex;
410 indices.push_back(zero);
411 auto packed = vector::TransferReadOp::create(
412 rewriter, loc, resultType, expanded, indices, info.read.getPadding());
413 packed.setInBoundsAttr(
414 rewriter.getBoolArrayAttr(SmallVector<bool>(resultType.getRank(), true)));
415 return packed;
416}
417
418namespace {
419// Fold RHS unpacking into a VNNI contraction:
420// - Match a packed RHS read unpacked for a flat matmul.
421// - Split the LHS memref's K dimension and reread it in VNNI layout.
422// A dynamic K dimension is first narrowed to the read's static extent.
423// - Contract the packed reads directly over K and the VNNI dimension.
424// For bf16, 32x32 LHS and RHS become 32x16x2 LHS and 16x32x2 RHS.
425struct FoldVNNIUnpacking : OpRewritePattern<vector::ContractionOp> {
427
428 LogicalResult matchAndRewrite(vector::ContractionOp contract,
429 PatternRewriter &rewriter) const override {
430 auto loop = dyn_cast<scf::ForOp>(contract->getParentOp());
431 if (!loop)
432 return rewriter.notifyMatchFailure(contract,
433 "not directly in a for loop");
434 if (getCandidate(loop) != contract)
435 return rewriter.notifyMatchFailure(
436 contract, "not the loop's canonical contraction");
437
438 auto lhsType = contract.getLhsType();
439 auto rhsType = contract.getRhsType();
440 Type element = lhsType.getElementType();
441 assert(lhsType.getRank() == 2 && rhsType.getRank() == 2 &&
442 lhsType.getDimSize(1) == rhsType.getDimSize(0) &&
443 element == rhsType.getElementType() &&
444 "expected canonical matmul contraction");
445 if (lhsType.isScalable() || rhsType.isScalable())
446 return rewriter.notifyMatchFailure(contract, "scalable operand vectors");
447 if (!(element.isBF16() || element.isInteger(8)))
448 return rewriter.notifyMatchFailure(contract,
449 "expected bf16 or i8 operands");
450 unsigned factor = 32 / element.getIntOrFloatBitWidth();
451 if (lhsType.getDimSize(1) % factor != 0)
452 return rewriter.notifyMatchFailure(
453 contract, "K dimension is not divisible by VNNI factor");
454
455 Value packedSource = matchUnpackedRhs(contract.getRhs(), factor);
456 if (!packedSource)
457 return rewriter.notifyMatchFailure(contract,
458 "RHS does not unpack a packed vector");
459 VectorType rhsPackedType =
460 VectorType::get({lhsType.getDimSize(1) / factor, rhsType.getDimSize(1),
461 int64_t(factor)},
462 element);
463 auto lhsRead = contract.getLhs().getDefiningOp<vector::TransferReadOp>();
464 auto lhs = getExpandableRead(lhsRead, factor, loop);
465 auto rhsRead = packedSource.getDefiningOp<vector::TransferReadOp>();
466 if (!lhs)
467 return rewriter.notifyMatchFailure(
468 contract, "LHS read cannot be expanded into VNNI layout");
469 if (!isSimpleReadOutsideLoop(rhsRead, loop))
470 return rewriter.notifyMatchFailure(contract,
471 "RHS is not a simple transfer read");
472 std::optional<ExpandedRead> splitRhs;
473 if (rhsRead.getVectorType() != rhsPackedType) {
474 auto flatType = rhsRead.getVectorType();
475 if (flatType.getRank() != 2 ||
476 flatType.getDimSize(0) != rhsPackedType.getDimSize(0) ||
477 flatType.getDimSize(1) % factor != 0 ||
478 flatType.getDimSize(1) / factor != rhsPackedType.getDimSize(1))
479 return rewriter.notifyMatchFailure(
480 contract, "flat RHS shape is not VNNI compatible");
481 if (!(splitRhs = getExpandableRead(rhsRead, factor, loop)))
482 return rewriter.notifyMatchFailure(
483 contract, "RHS read cannot be expanded into VNNI layout");
484 } else {
485 if (getConstantIntValue(rhsRead.getIndices().back()) != 0)
486 return rewriter.notifyMatchFailure(
487 contract, "packed RHS has nonzero inner offset");
488 }
489
490 Location loc = contract.getLoc();
491 VectorType lhsPackedType =
492 VectorType::get({lhsType.getDimSize(0), lhsType.getDimSize(1) / factor,
493 int64_t(factor)},
494 element);
495 Value packedLhs = buildExpandedRead(rewriter, loc, *lhs, lhsPackedType);
496 Value packedRhs =
497 splitRhs ? buildExpandedRead(rewriter, loc, *splitRhs, rhsPackedType)
498 : rhsRead.getResult();
499 rewriter.setInsertionPoint(contract);
500 auto ctx = rewriter.getContext();
501 auto m = rewriter.getAffineDimExpr(0);
502 auto n = rewriter.getAffineDimExpr(1);
503 auto k = rewriter.getAffineDimExpr(2);
504 auto v = rewriter.getAffineDimExpr(3);
505 auto vnniMaps =
506 rewriter.getAffineMapArrayAttr({AffineMap::get(4, 0, {m, k, v}, ctx),
507 AffineMap::get(4, 0, {k, n, v}, ctx),
508 AffineMap::get(4, 0, {m, n}, ctx)});
509 auto iterators = rewriter.getArrayAttr(
510 {vector::IteratorTypeAttr::get(ctx, vector::IteratorType::parallel),
511 vector::IteratorTypeAttr::get(ctx, vector::IteratorType::parallel),
512 vector::IteratorTypeAttr::get(ctx, vector::IteratorType::reduction),
513 vector::IteratorTypeAttr::get(ctx, vector::IteratorType::reduction)});
514 rewriter.replaceOpWithNewOp<vector::ContractionOp>(
515 contract, packedLhs, packedRhs, contract.getAcc(), vnniMaps, iterators,
516 contract.getKind(), contract.getFastmath());
517 LDBG() << "Replaced contract with VNNI-compatible contraction";
518 return success();
519 }
520};
521} // namespace
522
524 RewritePatternSet &patterns) {
525 patterns.add<FoldVNNIUnpacking>(patterns.getContext());
526}
return success()
lhs
static bool isSimpleReadOutsideLoop(vector::TransferReadOp read, scf::ForOp loop)
static Value buildExpandedRead(PatternRewriter &rewriter, Location loc, ExpandedRead &info, VectorType resultType)
static Value skipReshapes(Value v)
static Value matchUnpackedRhs(Value rhs, int64_t factor)
static std::optional< ExpandedRead > getExpandableRead(vector::TransferReadOp read, unsigned factor, scf::ForOp loop)
static vector::ContractionOp getCandidate(scf::ForOp loop)
static std::optional< SmallVector< Value, 4 > > matchJoin(Value v, int64_t factor)
static std::optional< std::pair< Value, int64_t > > matchSplit(Value v, int64_t factor)
static void contract(RootOrderingGraph &graph, ArrayRef< Value > cycle, const DenseMap< Value, unsigned > &parentDepths, DenseMap< Value, Value > &actualSource, DenseMap< Value, Value > &actualTarget)
Contracts the specified cycle in the given graph in-place.
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
IntegerAttr getIndexAttr(int64_t value)
Definition Builders.cpp:116
AffineExpr getAffineDimExpr(unsigned position)
Definition Builders.cpp:373
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Definition Builders.cpp:275
MLIRContext * getContext() const
Definition Builders.h:56
ArrayAttr getBoolArrayAttr(ArrayRef< bool > values)
Definition Builders.cpp:279
ArrayAttr getAffineMapArrayAttr(ArrayRef< AffineMap > values)
Definition Builders.cpp:327
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
RAII guard to reset the insertion point of the builder when destroyed.
Definition Builders.h:351
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Definition Builders.h:401
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Value getOperand(unsigned idx)
Definition Operation.h:377
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition Types.cpp:58
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
bool isBF16() const
Definition Types.cpp:37
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:105
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Definition ArithOps.cpp:434
void populatePrepareVectorContractLoopsPatterns(RewritePatternSet &patterns)
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
SmallVector< int64_t, 2 > ReassociationIndices
Definition Utils.h:27
SmallVector< IntTy > extractFromIntegerArrayAttr(Attribute attr)
Extract integer values from the assumed ArrayAttr of IntegerAttr.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
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...
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.