MLIR 24.0.0git
Pattern.cpp
Go to the documentation of this file.
1//===- Pattern.cpp - Conversion pattern to the LLVM 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
13#include "mlir/IR/AffineMap.h"
15#include "llvm/Support/CheckedArithmetic.h"
16#include "llvm/Support/MathExtras.h"
17
18using namespace mlir;
19
20//===----------------------------------------------------------------------===//
21// ConvertToLLVMPattern
22//===----------------------------------------------------------------------===//
23
25 StringRef rootOpName, MLIRContext *context,
26 const LLVMTypeConverter &typeConverter, PatternBenefit benefit)
27 : ConversionPattern(typeConverter, rootOpName, benefit, context) {}
28
30 return static_cast<const LLVMTypeConverter *>(
31 ConversionPattern::getTypeConverter());
32}
33
34LLVM::LLVMDialect &ConvertToLLVMPattern::getDialect() const {
35 return *getTypeConverter()->getDialect();
36}
37
41
42Type ConvertToLLVMPattern::getIntPtrType(unsigned addressSpace) const {
43 return IntegerType::get(&getTypeConverter()->getContext(),
44 getTypeConverter()->getPointerBitwidth(addressSpace));
45}
46
48 return LLVM::LLVMVoidType::get(&getTypeConverter()->getContext());
49}
50
51Type ConvertToLLVMPattern::getPtrType(unsigned addressSpace) const {
52 return LLVM::LLVMPointerType::get(&getTypeConverter()->getContext(),
53 addressSpace);
54}
55
57
59 Type resultType, int64_t value) {
60 return LLVM::ConstantOp::create(builder, loc, resultType,
61 builder.getIntegerAttr(resultType, value));
62}
63
65 Location loc,
66 Type resultType,
67 int64_t value) {
68 return LLVM::createIndexAttrConstant(builder, loc, resultType, value);
69}
70
72 ConversionPatternRewriter &rewriter, Location loc, MemRefType type,
73 Value memRefDesc, ValueRange indices,
74 LLVM::GEPNoWrapFlags noWrapFlags) const {
75 return LLVM::getStridedElementPtr(rewriter, loc, *getTypeConverter(), type,
76 memRefDesc, indices, noWrapFlags);
77}
78
79// Check if the MemRefType `type` is supported by the lowering. We currently
80// only support memrefs with identity maps.
82 MemRefType type) const {
83 if (!type.getLayout().isIdentity())
84 return false;
85 return static_cast<bool>(typeConverter->convertType(type));
86}
87
89 auto addressSpace = getTypeConverter()->getMemRefAddressSpace(type);
90 if (failed(addressSpace))
91 return {};
92 return LLVM::LLVMPointerType::get(type.getContext(), *addressSpace);
93}
94
96 Location loc, MemRefType memRefType, ValueRange dynamicSizes,
97 ConversionPatternRewriter &rewriter, SmallVectorImpl<Value> &sizes,
98 SmallVectorImpl<Value> &strides, Value &size, bool sizeInBytes) const {
99 assert(isConvertibleAndHasIdentityMaps(memRefType) &&
100 "layout maps must have been normalized away");
101 assert(count(memRefType.getShape(), ShapedType::kDynamic) ==
102 static_cast<ssize_t>(dynamicSizes.size()) &&
103 "dynamicSizes size doesn't match dynamic sizes count in memref shape");
104
105 sizes.reserve(memRefType.getRank());
106 unsigned dynamicIndex = 0;
107 Type indexType = getIndexType();
108 for (int64_t size : memRefType.getShape()) {
109 sizes.push_back(
110 size == ShapedType::kDynamic
111 ? dynamicSizes[dynamicIndex++]
112 : createIndexAttrConstant(rewriter, loc, indexType, size));
113 }
114
115 // Strides: iterate sizes in reverse order and multiply.
116 int64_t stride = 1;
117 bool overflowed = false;
118 Value runningStride = createIndexAttrConstant(rewriter, loc, indexType, 1);
119 strides.resize(memRefType.getRank());
120 for (auto i = memRefType.getRank(); i-- > 0;) {
121 strides[i] = overflowed ? LLVM::PoisonOp::create(rewriter, loc, indexType)
122 : runningStride;
123
124 int64_t staticSize = memRefType.getShape()[i];
125 bool useSizeAsStride = stride == 1;
126 if (staticSize == ShapedType::kDynamic)
127 stride = ShapedType::kDynamic;
128 if (stride != ShapedType::kDynamic) {
129 std::optional<int64_t> res = llvm::checkedMul(stride, staticSize);
130
131 if (!res)
132 overflowed = true;
133 else
134 stride = res.value();
135 }
136
137 if (overflowed)
138 runningStride = LLVM::PoisonOp::create(rewriter, loc, indexType);
139 else if (useSizeAsStride)
140 runningStride = sizes[i];
141 else if (stride == ShapedType::kDynamic)
142 runningStride =
143 LLVM::MulOp::create(rewriter, loc, runningStride, sizes[i]);
144 else
145 runningStride = createIndexAttrConstant(rewriter, loc, indexType, stride);
146 }
147 if (sizeInBytes) {
148 // Buffer size in bytes.
149 Type elementType = typeConverter->convertType(memRefType.getElementType());
150 auto elementPtrType = LLVM::LLVMPointerType::get(rewriter.getContext());
151 Value nullPtr = LLVM::ZeroOp::create(rewriter, loc, elementPtrType);
152 Value gepPtr = LLVM::GEPOp::create(rewriter, loc, elementPtrType,
153 elementType, nullPtr, runningStride);
154 size = LLVM::PtrToIntOp::create(rewriter, loc, getIndexType(), gepPtr);
155 } else {
156 size = runningStride;
157 }
158}
159
161 Location loc, Type type, ConversionPatternRewriter &rewriter) const {
162 // Compute the size of an individual element. This emits the MLIR equivalent
163 // of the following sizeof(...) implementation in LLVM IR:
164 // %0 = getelementptr %elementType* null, %indexType 1
165 // %1 = ptrtoint %elementType* %0 to %indexType
166 // which is a common pattern of getting the size of a type in bytes.
167 Type llvmType = typeConverter->convertType(type);
168 auto convertedPtrType = LLVM::LLVMPointerType::get(rewriter.getContext());
169 auto nullPtr = LLVM::ZeroOp::create(rewriter, loc, convertedPtrType);
170 auto gep = LLVM::GEPOp::create(rewriter, loc, convertedPtrType, llvmType,
171 nullPtr, ArrayRef<LLVM::GEPArg>{1});
172 return LLVM::PtrToIntOp::create(rewriter, loc, getIndexType(), gep);
173}
174
176 Location loc, MemRefType memRefType, ValueRange dynamicSizes,
177 ConversionPatternRewriter &rewriter) const {
178 assert(count(memRefType.getShape(), ShapedType::kDynamic) ==
179 static_cast<ssize_t>(dynamicSizes.size()) &&
180 "dynamicSizes size doesn't match dynamic sizes count in memref shape");
181
182 Type indexType = getIndexType();
183 Value numElements = memRefType.getRank() == 0
184 ? createIndexAttrConstant(rewriter, loc, indexType, 1)
185 : nullptr;
186 unsigned dynamicIndex = 0;
187
188 // Compute the total number of memref elements.
189 for (int64_t staticSize : memRefType.getShape()) {
190 if (numElements) {
191 Value size =
192 staticSize == ShapedType::kDynamic
193 ? dynamicSizes[dynamicIndex++]
194 : createIndexAttrConstant(rewriter, loc, indexType, staticSize);
195 numElements = LLVM::MulOp::create(rewriter, loc, numElements, size);
196 } else {
197 numElements =
198 staticSize == ShapedType::kDynamic
199 ? dynamicSizes[dynamicIndex++]
200 : createIndexAttrConstant(rewriter, loc, indexType, staticSize);
201 }
202 }
203 return numElements;
204}
205
206/// Creates and populates the memref descriptor struct given all its fields.
208 Location loc, MemRefType memRefType, Value allocatedPtr, Value alignedPtr,
209 ArrayRef<Value> sizes, ArrayRef<Value> strides,
210 ConversionPatternRewriter &rewriter) const {
211 auto structType = typeConverter->convertType(memRefType);
212 auto memRefDescriptor = MemRefDescriptor::poison(rewriter, loc, structType);
213
214 // Field 1: Allocated pointer, used for malloc/free.
215 memRefDescriptor.setAllocatedPtr(rewriter, loc, allocatedPtr);
216
217 // Field 2: Actual aligned pointer to payload.
218 memRefDescriptor.setAlignedPtr(rewriter, loc, alignedPtr);
219
220 // Field 3: Offset in aligned pointer.
221 Type indexType = getIndexType();
222 memRefDescriptor.setOffset(
223 rewriter, loc, createIndexAttrConstant(rewriter, loc, indexType, 0));
224
225 // Fields 4: Sizes.
226 for (const auto &en : llvm::enumerate(sizes))
227 memRefDescriptor.setSize(rewriter, loc, en.index(), en.value());
228
229 // Field 5: Strides.
230 for (const auto &en : llvm::enumerate(strides))
231 memRefDescriptor.setStride(rewriter, loc, en.index(), en.value());
232
233 return memRefDescriptor;
234}
235
237 OpBuilder &builder, Location loc, UnrankedMemRefType memRefType,
238 Value operand, bool toDynamic) const {
239 // Convert memory space.
240 FailureOr<unsigned> addressSpace =
242 if (failed(addressSpace))
243 return {};
244
245 // Get frequently used types.
246 Type indexType = getTypeConverter()->getIndexType();
247
248 // Find the malloc and free, or declare them if necessary.
249 auto module = builder.getInsertionPoint()->getParentOfType<ModuleOp>();
250 FailureOr<LLVM::LLVMFuncOp> freeFunc, mallocFunc;
251 if (toDynamic) {
252 mallocFunc = LLVM::lookupOrCreateMallocFn(builder, module, indexType);
253 if (failed(mallocFunc))
254 return {};
255 }
256 if (!toDynamic) {
257 freeFunc = LLVM::lookupOrCreateFreeFn(builder, module);
258 if (failed(freeFunc))
259 return {};
260 }
261
262 UnrankedMemRefDescriptor desc(operand);
264 builder, loc, *getTypeConverter(), desc, *addressSpace);
265
266 // Allocate memory, copy, and free the source if necessary.
267 Value memory = toDynamic
268 ? LLVM::CallOp::create(builder, loc, mallocFunc.value(),
269 allocationSize)
270 .getResult()
271 : LLVM::AllocaOp::create(builder, loc, getPtrType(),
272 IntegerType::get(getContext(), 8),
273 allocationSize,
274 /*alignment=*/0);
275 Value source = desc.memRefDescPtr(builder, loc);
276 LLVM::MemcpyOp::create(builder, loc, memory, source, allocationSize, false);
277 if (!toDynamic)
278 LLVM::CallOp::create(builder, loc, freeFunc.value(), source);
279
280 // Create a new descriptor. The same descriptor can be returned multiple
281 // times, attempting to modify its pointer can lead to memory leaks
282 // (allocated twice and overwritten) or double frees (the caller does not
283 // know if the descriptor points to the same memory).
284 Type descriptorType = getTypeConverter()->convertType(memRefType);
285 if (!descriptorType)
286 return {};
287 auto updatedDesc =
288 UnrankedMemRefDescriptor::poison(builder, loc, descriptorType);
289 Value rank = desc.rank(builder, loc);
290 updatedDesc.setRank(builder, loc, rank);
291 updatedDesc.setMemRefDescPtr(builder, loc, memory);
292 return updatedDesc;
293}
294
296 OpBuilder &builder, Location loc, TypeRange origTypes,
297 SmallVectorImpl<Value> &operands, bool toDynamic) const {
298 assert(origTypes.size() == operands.size() &&
299 "expected as may original types as operands");
300 for (unsigned i = 0, e = operands.size(); i < e; ++i) {
301 if (auto memRefType = dyn_cast<UnrankedMemRefType>(origTypes[i])) {
302 Value updatedDesc = copyUnrankedDescriptor(builder, loc, memRefType,
303 operands[i], toDynamic);
304 if (!updatedDesc)
305 return failure();
306 operands[i] = updatedDesc;
307 }
308 }
309 return success();
310}
311
312//===----------------------------------------------------------------------===//
313// Detail methods
314//===----------------------------------------------------------------------===//
315
316/// Replaces the given operation "op" with a new operation of type "targetOp"
317/// and given operands.
319 Operation *op, StringRef targetOp, ValueRange operands,
320 ArrayRef<NamedAttribute> targetAttrs, Attribute propertiesAttr,
321 const LLVMTypeConverter &typeConverter,
322 ConversionPatternRewriter &rewriter) {
323 unsigned numResults = op->getNumResults();
324
325 SmallVector<Type> resultTypes;
326 if (numResults != 0) {
327 resultTypes.push_back(
328 typeConverter.packOperationResults(op->getResultTypes()));
329 if (!resultTypes.back())
330 return failure();
331 }
332
333 // Create the operation through state since we don't know its C++ type.
334 OperationState state(op->getLoc(), rewriter.getStringAttr(targetOp), operands,
335 resultTypes, targetAttrs);
336 state.propertiesAttr = propertiesAttr;
337 Operation *newOp = rewriter.create(state);
338
339 // If the operation produced 0 or 1 result, return them immediately.
340 if (numResults == 0)
341 return rewriter.eraseOp(op), success();
342 if (numResults == 1)
343 return rewriter.replaceOp(op, newOp->getResult(0)), success();
344
345 // Otherwise, it had been converted to an operation producing a structure.
346 // Extract individual results from the structure and return them as list.
347 SmallVector<Value, 4> results;
348 results.reserve(numResults);
349 for (unsigned i = 0; i < numResults; ++i) {
350 results.push_back(LLVM::ExtractValueOp::create(rewriter, op->getLoc(),
351 newOp->getResult(0), i));
352 }
353 rewriter.replaceOp(op, results);
354 return success();
355}
356
358 Operation *op, StringRef intrinsic, ValueRange operands,
359 const LLVMTypeConverter &typeConverter, RewriterBase &rewriter) {
360 auto loc = op->getLoc();
361
362 if (!llvm::all_of(operands, [](Value value) {
363 return LLVM::isCompatibleType(value.getType());
364 }))
365 return failure();
366
367 unsigned numResults = op->getNumResults();
368 Type resType;
369 if (numResults != 0)
370 resType = typeConverter.packOperationResults(op->getResultTypes());
371
372 auto callIntrOp = LLVM::CallIntrinsicOp::create(
373 rewriter, loc, resType, rewriter.getStringAttr(intrinsic), operands);
374 // Propagate attributes.
375 SmallVector<NamedAttribute> discardableAttrs;
376 auto copyAttr = [&](StringAttr name, Attribute attr) {
377 if (callIntrOp->getInherentAttr(name).has_value())
378 callIntrOp->setInherentAttr(name, attr);
379 else
380 discardableAttrs.emplace_back(name, attr);
381 };
383 copyAttr(attr.getName(), attr.getValue());
384 op->getName().walkInherentAttrs(op, [&](StringRef name, Attribute &attr) {
385 copyAttr(rewriter.getStringAttr(name), attr);
386 });
387 callIntrOp->setDiscardableAttrs(discardableAttrs);
388
389 if (numResults <= 1) {
390 // Directly replace the original op.
391 rewriter.replaceOp(op, callIntrOp);
392 return success();
393 }
394
395 // Extract individual results from packed structure and use them as
396 // replacements.
397 SmallVector<Value, 4> results;
398 results.reserve(numResults);
399 Value intrRes = callIntrOp.getResults();
400 for (unsigned i = 0; i < numResults; ++i)
401 results.push_back(LLVM::ExtractValueOp::create(rewriter, loc, intrRes, i));
402 rewriter.replaceOp(op, results);
403
404 return success();
405}
406
407static unsigned getBitWidth(Type type) {
408 if (type.isIntOrFloat())
409 return type.getIntOrFloatBitWidth();
410
411 auto vec = cast<VectorType>(type);
412 assert(!vec.isScalable() && "scalable vectors are not supported");
413 return vec.getNumElements() * getBitWidth(vec.getElementType());
414}
415
416/// Returns true if every leaf in `type` (recursing through LLVM arrays and
417/// structs) is either equal to `dstType` or has a fixed bit width.
418static bool isFixedSizeAggregate(Type type, Type dstType) {
419 if (type == dstType)
420 return true;
421 if (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(type))
422 return isFixedSizeAggregate(arrayType.getElementType(), dstType);
423 if (auto structType = dyn_cast<LLVM::LLVMStructType>(type))
424 return llvm::all_of(structType.getBody(), [&](Type fieldType) {
425 return isFixedSizeAggregate(fieldType, dstType);
426 });
427 if (auto vecTy = dyn_cast<VectorType>(type))
428 return !vecTy.isScalable();
429 return type.isIntOrFloat();
430}
431
433 int32_t value) {
434 Type i32 = builder.getI32Type();
435 return LLVM::ConstantOp::create(builder, loc, i32, value);
436}
437
438/// Recursive implementation of decomposeValue. When
439/// `permitVariablySizedScalars` is false, callers must ensure
440/// isFixedSizeAggregate() holds before calling this.
441static void decomposeValueImpl(OpBuilder &builder, Location loc, Value src,
443 Type srcType = src.getType();
444 if (srcType == dstType) {
445 result.push_back(src);
446 return;
447 }
448
449 if (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(srcType)) {
450 for (auto i : llvm::seq(arrayType.getNumElements())) {
451 Value elem = LLVM::ExtractValueOp::create(builder, loc, src, i);
452 decomposeValueImpl(builder, loc, elem, dstType, result);
453 }
454 return;
455 }
456
457 if (auto structType = dyn_cast<LLVM::LLVMStructType>(srcType)) {
458 for (auto [i, fieldType] : llvm::enumerate(structType.getBody())) {
459 Value field = LLVM::ExtractValueOp::create(builder, loc, src,
460 static_cast<int64_t>(i));
461 decomposeValueImpl(builder, loc, field, dstType, result);
462 }
463 return;
464 }
465
466 // Variably sized leaf types (e.g., ptr) — pass through as-is.
467 if (!srcType.isIntOrFloat() && !isa<VectorType>(srcType)) {
468 result.push_back(src);
469 return;
470 }
471
472 unsigned srcBitWidth = getBitWidth(srcType);
473 unsigned dstBitWidth = getBitWidth(dstType);
474 if (srcBitWidth == dstBitWidth) {
475 Value cast = LLVM::BitcastOp::create(builder, loc, dstType, src);
476 result.push_back(cast);
477 return;
478 }
479
480 if (dstBitWidth > srcBitWidth) {
481 auto smallerInt = builder.getIntegerType(srcBitWidth);
482 if (srcType != smallerInt)
483 src = LLVM::BitcastOp::create(builder, loc, smallerInt, src);
484
485 auto largerInt = builder.getIntegerType(dstBitWidth);
486 Value res = LLVM::ZExtOp::create(builder, loc, largerInt, src);
487 result.push_back(res);
488 return;
489 }
490 int64_t numElements = llvm::divideCeil(srcBitWidth, dstBitWidth);
491 int64_t roundedBitWidth = numElements * dstBitWidth;
492
493 // Pad out values that don't decompose evenly before creating a vector.
494 if (roundedBitWidth != srcBitWidth) {
495 auto srcInt = builder.getIntegerType(srcBitWidth);
496 if (srcType != srcInt)
497 src = LLVM::BitcastOp::create(builder, loc, srcInt, src);
498 auto roundedInt = builder.getIntegerType(roundedBitWidth);
499 src = LLVM::ZExtOp::create(builder, loc, roundedInt, src);
500 }
501
502 auto vecType = VectorType::get(numElements, dstType);
503 src = LLVM::BitcastOp::create(builder, loc, vecType, src);
504
505 for (auto i : llvm::seq(numElements)) {
506 Value idx = createI32Constant(builder, loc, i);
507 Value elem = LLVM::ExtractElementOp::create(builder, loc, src, idx);
508 result.push_back(elem);
509 }
510}
511
513 Value src, Type dstType,
515 bool permitVariablySizedScalars) {
516 // Check the type tree before emitting any IR, so that a failing pattern
517 // leaves the IR unmodified.
518 if (!permitVariablySizedScalars &&
519 !isFixedSizeAggregate(src.getType(), dstType))
520 return failure();
521
522 decomposeValueImpl(builder, loc, src, dstType, result);
523 return success();
524}
525
526/// Recursive implementation of composeValue. Consumes elements from `src`
527/// starting at `offset`, advancing it past the consumed elements.
529 size_t &offset, Type dstType) {
530 if (auto arrayType = dyn_cast<LLVM::LLVMArrayType>(dstType)) {
531 Value result = LLVM::PoisonOp::create(builder, loc, arrayType);
532 Type elemType = arrayType.getElementType();
533 for (auto i : llvm::seq(arrayType.getNumElements())) {
534 Value elem = composeValueImpl(builder, loc, src, offset, elemType);
535 result = LLVM::InsertValueOp::create(builder, loc, result, elem, i);
536 }
537 return result;
538 }
539
540 if (auto structType = dyn_cast<LLVM::LLVMStructType>(dstType)) {
541 Value result = LLVM::PoisonOp::create(builder, loc, structType);
542 for (auto [i, fieldType] : llvm::enumerate(structType.getBody())) {
543 Value field = composeValueImpl(builder, loc, src, offset, fieldType);
544 result = LLVM::InsertValueOp::create(builder, loc, result, field,
545 static_cast<int64_t>(i));
546 }
547 return result;
548 }
549
550 // Variably sized leaf types (e.g., ptr) — consume and return as-is.
551 if (!dstType.isIntOrFloat() && !isa<VectorType>(dstType))
552 return src[offset++];
553
554 unsigned dstBitWidth = getBitWidth(dstType);
555
556 Value front = src[offset];
557 if (front.getType() == dstType) {
558 ++offset;
559 return front;
560 }
561
562 // Single element wider than or equal to dst: bitcast/trunc.
563 if (front.getType().isIntOrFloat() || isa<VectorType>(front.getType())) {
564 unsigned srcBitWidth = getBitWidth(front.getType());
565 if (srcBitWidth >= dstBitWidth) {
566 ++offset;
567 Value res = front;
568 if (dstBitWidth < srcBitWidth) {
569 auto largerInt = builder.getIntegerType(srcBitWidth);
570 if (res.getType() != largerInt)
571 res = LLVM::BitcastOp::create(builder, loc, largerInt, res);
572
573 auto smallerInt = builder.getIntegerType(dstBitWidth);
574 res = LLVM::TruncOp::create(builder, loc, smallerInt, res);
575 }
576 if (res.getType() != dstType)
577 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
578 return res;
579 }
580 }
581
582 // Multiple elements narrower than dst: gather into a vector and bitcast.
583 unsigned elemBitWidth = getBitWidth(front.getType());
584 int64_t numElements = llvm::divideCeil(dstBitWidth, elemBitWidth);
585 int64_t roundedBitWidth = numElements * elemBitWidth;
586
587 auto vecType = VectorType::get(numElements, front.getType());
588 Value res = LLVM::PoisonOp::create(builder, loc, vecType);
589 for (auto i : llvm::seq(numElements)) {
590 Value idx = createI32Constant(builder, loc, i);
591 res = LLVM::InsertElementOp::create(builder, loc, vecType, res,
592 src[offset++], idx);
593 }
594
595 // Undo any padding decomposition might have introduced.
596 if (roundedBitWidth != dstBitWidth) {
597 auto roundedInt = builder.getIntegerType(roundedBitWidth);
598 res = LLVM::BitcastOp::create(builder, loc, roundedInt, res);
599 auto dstInt = builder.getIntegerType(dstBitWidth);
600 res = LLVM::TruncOp::create(builder, loc, dstInt, res);
601 if (dstType != dstInt)
602 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
603 } else {
604 if (res.getType() != dstType)
605 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
606 }
607
608 return res;
609}
610
612 Type dstType) {
613 assert(!src.empty() && "src range must not be empty");
614 size_t offset = 0;
615 Value result = composeValueImpl(builder, loc, src, offset, dstType);
616 assert(offset == src.size() && "not all decomposed values were consumed");
617 return result;
618}
619
621 const LLVMTypeConverter &converter,
622 MemRefType type, Value memRefDesc,
624 LLVM::GEPNoWrapFlags noWrapFlags) {
625 auto [strides, offset] = type.getStridesAndOffset();
626
627 MemRefDescriptor memRefDescriptor(memRefDesc);
628 // Use a canonical representation of the start address so that later
629 // optimizations have a longer sequence of instructions to CSE.
630 // If we don't do that we would sprinkle the memref.offset in various
631 // position of the different address computations.
632 Value base = memRefDescriptor.bufferPtr(builder, loc, converter, type);
633
634 LLVM::IntegerOverflowFlags intOverflowFlags =
635 LLVM::IntegerOverflowFlags::none;
636 if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nusw)) {
637 intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nsw;
638 }
639 if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nuw)) {
640 intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nuw;
641 }
642
643 Type indexType = converter.getIndexType();
644 Value index;
645 for (int i = 0, e = indices.size(); i < e; ++i) {
646 Value increment = indices[i];
647 if (strides[i] != 1) { // Skip if stride is 1.
648 Value stride = ShapedType::isDynamic(strides[i])
649 ? memRefDescriptor.stride(builder, loc, i)
650 : LLVM::createIndexAttrConstant(builder, loc,
651 indexType, strides[i]);
652 increment = LLVM::MulOp::create(builder, loc, increment, stride,
653 intOverflowFlags);
654 }
655 index = index ? LLVM::AddOp::create(builder, loc, index, increment,
656 intOverflowFlags)
657 : increment;
658 }
659
660 Type elementPtrType = memRefDescriptor.getElementPtrType();
661 return index
662 ? LLVM::GEPOp::create(builder, loc, elementPtrType,
663 converter.convertType(type.getElementType()),
664 base, index, noWrapFlags)
665 : base;
666}
667
668/// Return the given type if it's a floating point type. If the given type is
669/// a vector type, return its element type if it's a floating point type.
670static FloatType getFloatingPointType(Type type) {
671 if (auto floatType = dyn_cast<FloatType>(type))
672 return floatType;
673 if (auto vecType = dyn_cast<VectorType>(type))
674 return dyn_cast<FloatType>(vecType.getElementType());
675 return nullptr;
676}
677
679 const TypeConverter &typeConverter, Type type) {
680 FloatType floatType = getFloatingPointType(type);
681 if (!floatType)
682 return false;
683 Type convertedType = typeConverter.convertType(floatType);
684 if (!convertedType)
685 return true;
686 return !isa<FloatType>(convertedType);
687}
688
690 Operation *op, const TypeConverter &typeConverter) {
691 for (Value operand : op->getOperands())
692 if (isUnsupportedFloatingPointType(typeConverter, operand.getType()))
693 return true;
694 return llvm::any_of(op->getResults(), [&typeConverter](OpResult r) {
695 return isUnsupportedFloatingPointType(typeConverter, r.getType());
696 });
697}
static Value createI32Constant(ConversionPatternRewriter &rewriter, Location loc, int32_t value)
return success()
static unsigned getBitWidth(Type type)
Definition Pattern.cpp:407
static FloatType getFloatingPointType(Type type)
Return the given type if it's a floating point type.
Definition Pattern.cpp:670
static bool isFixedSizeAggregate(Type type, Type dstType)
Returns true if every leaf in type (recursing through LLVM arrays and structs) is either equal to dst...
Definition Pattern.cpp:418
static Value composeValueImpl(OpBuilder &builder, Location loc, ValueRange src, size_t &offset, Type dstType)
Recursive implementation of composeValue.
Definition Pattern.cpp:528
static void decomposeValueImpl(OpBuilder &builder, Location loc, Value src, Type dstType, SmallVectorImpl< Value > &result)
Recursive implementation of decomposeValue.
Definition Pattern.cpp:441
b getContext())
Attributes are known-constant values of operations.
Definition Attributes.h:25
IntegerAttr getIntegerAttr(Type type, int64_t value)
Definition Builders.cpp:237
IntegerType getI32Type()
Definition Builders.cpp:71
IntegerType getIntegerType(unsigned width)
Definition Builders.cpp:75
StringAttr getStringAttr(const Twine &bytes)
Definition Builders.cpp:271
Type getVoidType() const
Gets the MLIR type wrapping the LLVM void type.
Definition Pattern.cpp:47
MemRefDescriptor createMemRefDescriptor(Location loc, MemRefType memRefType, Value allocatedPtr, Value alignedPtr, ArrayRef< Value > sizes, ArrayRef< Value > strides, ConversionPatternRewriter &rewriter) const
Creates and populates a canonical memref descriptor struct.
Definition Pattern.cpp:207
ConvertToLLVMPattern(StringRef rootOpName, MLIRContext *context, const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
Definition Pattern.cpp:24
Value getStridedElementPtr(ConversionPatternRewriter &rewriter, Location loc, MemRefType type, Value memRefDesc, ValueRange indices, LLVM::GEPNoWrapFlags noWrapFlags=LLVM::GEPNoWrapFlags::none) const
Convenience wrapper for the corresponding helper utility.
Definition Pattern.cpp:71
void getMemRefDescriptorSizes(Location loc, MemRefType memRefType, ValueRange dynamicSizes, ConversionPatternRewriter &rewriter, SmallVectorImpl< Value > &sizes, SmallVectorImpl< Value > &strides, Value &size, bool sizeInBytes=true) const
Computes sizes, strides and buffer size of memRefType with identity layout.
Definition Pattern.cpp:95
Type getPtrType(unsigned addressSpace=0) const
Get the MLIR type wrapping the LLVM ptr type.
Definition Pattern.cpp:51
Type getIndexType() const
Gets the MLIR type wrapping the LLVM integer type whose bit width is defined by the used type convert...
Definition Pattern.cpp:38
const LLVMTypeConverter * getTypeConverter() const
Definition Pattern.cpp:29
Value getNumElements(Location loc, MemRefType memRefType, ValueRange dynamicSizes, ConversionPatternRewriter &rewriter) const
Computes total number of elements for the given MemRef and dynamicSizes.
Definition Pattern.cpp:175
LLVM::LLVMDialect & getDialect() const
Returns the LLVM dialect.
Definition Pattern.cpp:34
Value getSizeInBytes(Location loc, Type type, ConversionPatternRewriter &rewriter) const
Computes the size of type in bytes.
Definition Pattern.cpp:160
Type getIntPtrType(unsigned addressSpace=0) const
Gets the MLIR type wrapping the LLVM integer type whose bit width corresponds to that of a LLVM point...
Definition Pattern.cpp:42
Value copyUnrankedDescriptor(OpBuilder &builder, Location loc, UnrankedMemRefType memRefType, Value operand, bool toDynamic) const
Copies the given unranked memory descriptor to heap-allocated memory (if toDynamic is true) or to sta...
Definition Pattern.cpp:236
LogicalResult copyUnrankedDescriptors(OpBuilder &builder, Location loc, TypeRange origTypes, SmallVectorImpl< Value > &operands, bool toDynamic) const
Copies the memory descriptor for any operands that were unranked descriptors originally to heap-alloc...
Definition Pattern.cpp:295
Type getElementPtrType(MemRefType type) const
Returns the type of a pointer to an element of the memref.
Definition Pattern.cpp:88
static Value createIndexAttrConstant(OpBuilder &builder, Location loc, Type resultType, int64_t value)
Create a constant Op producing a value of resultType from an index-typed integer attribute.
Definition Pattern.cpp:64
bool isConvertibleAndHasIdentityMaps(MemRefType type) const
Returns if the given memref type is convertible to LLVM and has an identity layout map.
Definition Pattern.cpp:81
Type getVoidPtrType() const
Get the MLIR type wrapping the LLVM i8* type.
Definition Pattern.cpp:56
Conversion from types to the LLVM IR dialect.
Type packOperationResults(TypeRange types) const
Convert a non-empty list of types of values produced by an operation into an LLVM-compatible type.
FailureOr< unsigned > getMemRefAddressSpace(BaseMemRefType type) const
Return the LLVM address space corresponding to the memory space of the memref type type or failure if...
LLVM::LLVMDialect * getDialect() const
Returns the LLVM dialect.
Type getIndexType() const
Gets the LLVM representation of the index type.
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:63
Helper class to produce LLVM dialect operations extracting or inserting elements of a MemRef descript...
Value bufferPtr(OpBuilder &builder, Location loc, const LLVMTypeConverter &converter, MemRefType type)
Builds IR for getting the start address of the buffer represented by this memref: memref....
LLVM::LLVMPointerType getElementPtrType()
Returns the (LLVM) pointer type this descriptor contains.
Value stride(OpBuilder &builder, Location loc, unsigned pos)
Builds IR extracting the pos-th size from the descriptor.
static MemRefDescriptor poison(OpBuilder &builder, Location loc, Type descriptorType)
Builds IR creating a poison value of the descriptor type.
NamedAttribute represents a combination of a name and an Attribute value.
Definition Attributes.h:164
This class helps build Operations.
Definition Builders.h:210
This is a value defined by a result of an operation.
Definition Value.h:454
void walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) const
Visit the inherent attributes stored in the properties of op.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition Operation.h:432
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
Definition Operation.h:553
result_type_range getResultTypes()
Definition Operation.h:453
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
result_range getResults()
Definition Operation.h:440
unsigned getNumResults()
Return the number of results held by this operation.
Definition Operation.h:429
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Definition Types.cpp:118
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
static Value computeSize(OpBuilder &builder, Location loc, const LLVMTypeConverter &typeConverter, UnrankedMemRefDescriptor desc, unsigned addressSpace)
Builds and returns IR computing the size in bytes (suitable for opaque allocation).
Value memRefDescPtr(OpBuilder &builder, Location loc) const
Builds IR extracting ranked memref descriptor ptr.
static UnrankedMemRefDescriptor poison(OpBuilder &builder, Location loc, Type descriptorType)
Builds IR creating an undef value of the descriptor type.
Value rank(OpBuilder &builder, Location loc) const
Builds IR extracting the rank from the descriptor.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
bool isUnsupportedFloatingPointType(const TypeConverter &typeConverter, Type type)
Return "true" if the given type is an unsupported floating point type.
Definition Pattern.cpp:678
LogicalResult oneToOneRewrite(Operation *op, StringRef targetOp, ValueRange operands, ArrayRef< NamedAttribute > targetAttrs, Attribute propertiesAttr, const LLVMTypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Replaces the given operation "op" with a new operation of type "targetOp" and given operands.
Definition Pattern.cpp:318
bool opHasUnsupportedFloatingPointTypes(Operation *op, const TypeConverter &typeConverter)
Return "true" if the given op has any unsupported floating point types (either operands or results).
Definition Pattern.cpp:689
LogicalResult intrinsicRewrite(Operation *op, StringRef intrinsic, ValueRange operands, const LLVMTypeConverter &typeConverter, RewriterBase &rewriter)
Replaces the given operation "op" with a call to an LLVM intrinsic with the specified name "intrinsic...
Definition Pattern.cpp:357
FailureOr< LLVM::LLVMFuncOp > lookupOrCreateFreeFn(OpBuilder &b, Operation *moduleOp, SymbolTableCollection *symbolTables=nullptr)
Value getStridedElementPtr(OpBuilder &builder, Location loc, const LLVMTypeConverter &converter, MemRefType type, Value memRefDesc, ValueRange indices, LLVM::GEPNoWrapFlags noWrapFlags=LLVM::GEPNoWrapFlags::none)
Performs the index computation to get to the element at indices of the memory pointed to by memRefDes...
Definition Pattern.cpp:620
LogicalResult decomposeValue(OpBuilder &builder, Location loc, Value src, Type dstType, SmallVectorImpl< Value > &result, bool permitVariablySizedScalars=false)
Decomposes a src value into a set of values of type dstType through series of bitcasts and vector ops...
Definition Pattern.cpp:512
Value createIndexAttrConstant(OpBuilder &builder, Location loc, Type resultType, int64_t value)
Creates an llvm.mlir.constant producing value as resultType, which is expected to be the converted in...
Definition Pattern.cpp:58
Value composeValue(OpBuilder &builder, Location loc, ValueRange src, Type dstType)
Composes a set of src values into a single value of type dstType through series of bitcasts and vecto...
Definition Pattern.cpp:611
FailureOr< LLVM::LLVMFuncOp > lookupOrCreateMallocFn(OpBuilder &b, Operation *moduleOp, Type indexType, SymbolTableCollection *symbolTables=nullptr)
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Include the generated interface declarations.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.