15#include "llvm/Support/CheckedArithmetic.h"
16#include "llvm/Support/MathExtras.h"
27 : ConversionPattern(typeConverter, rootOpName, benefit, context) {}
31 ConversionPattern::getTypeConverter());
60 return LLVM::ConstantOp::create(builder, loc, resultType,
72 ConversionPatternRewriter &rewriter,
Location loc, MemRefType type,
74 LLVM::GEPNoWrapFlags noWrapFlags)
const {
76 memRefDesc,
indices, noWrapFlags);
82 MemRefType type)
const {
83 if (!type.getLayout().isIdentity())
85 return static_cast<bool>(typeConverter->convertType(type));
90 if (failed(addressSpace))
92 return LLVM::LLVMPointerType::get(type.getContext(), *addressSpace);
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");
105 sizes.reserve(memRefType.getRank());
106 unsigned dynamicIndex = 0;
108 for (
int64_t size : memRefType.getShape()) {
110 size == ShapedType::kDynamic
111 ? dynamicSizes[dynamicIndex++]
117 bool overflowed =
false;
119 strides.resize(memRefType.getRank());
120 for (
auto i = memRefType.getRank(); i-- > 0;) {
121 strides[i] = overflowed ? LLVM::PoisonOp::create(rewriter, loc, indexType)
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);
134 stride = res.value();
138 runningStride = LLVM::PoisonOp::create(rewriter, loc, indexType);
139 else if (useSizeAsStride)
140 runningStride = sizes[i];
141 else if (stride == ShapedType::kDynamic)
143 LLVM::MulOp::create(rewriter, loc, runningStride, sizes[i]);
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);
156 size = runningStride;
161 Location loc,
Type type, ConversionPatternRewriter &rewriter)
const {
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,
172 return LLVM::PtrToIntOp::create(rewriter, loc,
getIndexType(), gep);
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");
183 Value numElements = memRefType.getRank() == 0
186 unsigned dynamicIndex = 0;
189 for (
int64_t staticSize : memRefType.getShape()) {
192 staticSize == ShapedType::kDynamic
193 ? dynamicSizes[dynamicIndex++]
195 numElements = LLVM::MulOp::create(rewriter, loc, numElements, size);
198 staticSize == ShapedType::kDynamic
199 ? dynamicSizes[dynamicIndex++]
210 ConversionPatternRewriter &rewriter)
const {
211 auto structType = typeConverter->convertType(memRefType);
215 memRefDescriptor.setAllocatedPtr(rewriter, loc, allocatedPtr);
218 memRefDescriptor.setAlignedPtr(rewriter, loc, alignedPtr);
222 memRefDescriptor.setOffset(
226 for (
const auto &en : llvm::enumerate(sizes))
227 memRefDescriptor.setSize(rewriter, loc, en.index(), en.value());
230 for (
const auto &en : llvm::enumerate(strides))
231 memRefDescriptor.setStride(rewriter, loc, en.index(), en.value());
233 return memRefDescriptor;
238 Value operand,
bool toDynamic)
const {
240 FailureOr<unsigned> addressSpace =
242 if (failed(addressSpace))
249 auto module = builder.getInsertionPoint()->getParentOfType<ModuleOp>();
250 FailureOr<LLVM::LLVMFuncOp> freeFunc, mallocFunc;
253 if (failed(mallocFunc))
258 if (failed(freeFunc))
267 Value memory = toDynamic
268 ? LLVM::CallOp::create(builder, loc, mallocFunc.value(),
271 : LLVM::AllocaOp::create(builder, loc,
getPtrType(),
276 LLVM::MemcpyOp::create(builder, loc, memory, source, allocationSize,
false);
278 LLVM::CallOp::create(builder, loc, freeFunc.value(), source);
290 updatedDesc.setRank(builder, loc, rank);
291 updatedDesc.setMemRefDescPtr(builder, loc, memory);
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])) {
303 operands[i], toDynamic);
306 operands[i] = updatedDesc;
322 ConversionPatternRewriter &rewriter) {
326 if (numResults != 0) {
327 resultTypes.push_back(
329 if (!resultTypes.back())
335 resultTypes, targetAttrs);
337 Operation *newOp = rewriter.create(state);
341 return rewriter.eraseOp(op),
success();
348 results.reserve(numResults);
349 for (
unsigned i = 0; i < numResults; ++i) {
350 results.push_back(LLVM::ExtractValueOp::create(rewriter, op->
getLoc(),
353 rewriter.replaceOp(op, results);
362 if (!llvm::all_of(operands, [](
Value value) {
372 auto callIntrOp = LLVM::CallIntrinsicOp::create(
373 rewriter, loc, resType, rewriter.
getStringAttr(intrinsic), operands);
376 auto copyAttr = [&](StringAttr name,
Attribute attr) {
377 if (callIntrOp->getInherentAttr(name).has_value())
378 callIntrOp->setInherentAttr(name, attr);
380 discardableAttrs.emplace_back(name, attr);
383 copyAttr(attr.getName(), attr.getValue());
387 callIntrOp->setDiscardableAttrs(discardableAttrs);
389 if (numResults <= 1) {
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));
411 auto vec = cast<VectorType>(type);
412 assert(!vec.isScalable() &&
"scalable vectors are not supported");
413 return vec.getNumElements() *
getBitWidth(vec.getElementType());
421 if (
auto arrayType = dyn_cast<LLVM::LLVMArrayType>(type))
423 if (
auto structType = dyn_cast<LLVM::LLVMStructType>(type))
424 return llvm::all_of(structType.getBody(), [&](
Type fieldType) {
425 return isFixedSizeAggregate(fieldType, dstType);
427 if (
auto vecTy = dyn_cast<VectorType>(type))
428 return !vecTy.isScalable();
435 return LLVM::ConstantOp::create(builder, loc, i32, value);
444 if (srcType == dstType) {
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);
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,
467 if (!srcType.
isIntOrFloat() && !isa<VectorType>(srcType)) {
474 if (srcBitWidth == dstBitWidth) {
475 Value cast = LLVM::BitcastOp::create(builder, loc, dstType, src);
480 if (dstBitWidth > srcBitWidth) {
482 if (srcType != smallerInt)
483 src = LLVM::BitcastOp::create(builder, loc, smallerInt, src);
486 Value res = LLVM::ZExtOp::create(builder, loc, largerInt, src);
490 int64_t numElements = llvm::divideCeil(srcBitWidth, dstBitWidth);
491 int64_t roundedBitWidth = numElements * dstBitWidth;
494 if (roundedBitWidth != srcBitWidth) {
496 if (srcType != srcInt)
497 src = LLVM::BitcastOp::create(builder, loc, srcInt, src);
499 src = LLVM::ZExtOp::create(builder, loc, roundedInt, src);
502 auto vecType = VectorType::get(numElements, dstType);
503 src = LLVM::BitcastOp::create(builder, loc, vecType, src);
505 for (
auto i : llvm::seq(numElements)) {
507 Value elem = LLVM::ExtractElementOp::create(builder, loc, src, idx);
515 bool permitVariablySizedScalars) {
518 if (!permitVariablySizedScalars &&
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())) {
535 result = LLVM::InsertValueOp::create(builder, loc,
result, elem, i);
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())) {
544 result = LLVM::InsertValueOp::create(builder, loc,
result, field,
551 if (!dstType.
isIntOrFloat() && !isa<VectorType>(dstType))
552 return src[offset++];
556 Value front = src[offset];
557 if (front.
getType() == dstType) {
565 if (srcBitWidth >= dstBitWidth) {
568 if (dstBitWidth < srcBitWidth) {
570 if (res.getType() != largerInt)
571 res = LLVM::BitcastOp::create(builder, loc, largerInt, res);
574 res = LLVM::TruncOp::create(builder, loc, smallerInt, res);
576 if (res.getType() != dstType)
577 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
584 int64_t numElements = llvm::divideCeil(dstBitWidth, elemBitWidth);
585 int64_t roundedBitWidth = numElements * elemBitWidth;
587 auto vecType = VectorType::get(numElements, front.
getType());
588 Value res = LLVM::PoisonOp::create(builder, loc, vecType);
589 for (
auto i : llvm::seq(numElements)) {
591 res = LLVM::InsertElementOp::create(builder, loc, vecType, res,
596 if (roundedBitWidth != dstBitWidth) {
598 res = LLVM::BitcastOp::create(builder, loc, roundedInt, res);
600 res = LLVM::TruncOp::create(builder, loc, dstInt, res);
601 if (dstType != dstInt)
602 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
604 if (res.getType() != dstType)
605 res = LLVM::BitcastOp::create(builder, loc, dstType, res);
613 assert(!src.empty() &&
"src range must not be empty");
616 assert(offset == src.size() &&
"not all decomposed values were consumed");
622 MemRefType type,
Value memRefDesc,
624 LLVM::GEPNoWrapFlags noWrapFlags) {
625 auto [strides, offset] = type.getStridesAndOffset();
632 Value base = memRefDescriptor.
bufferPtr(builder, loc, converter, type);
634 LLVM::IntegerOverflowFlags intOverflowFlags =
635 LLVM::IntegerOverflowFlags::none;
636 if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nusw)) {
637 intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nsw;
639 if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nuw)) {
640 intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nuw;
645 for (
int i = 0, e =
indices.size(); i < e; ++i) {
647 if (strides[i] != 1) {
648 Value stride = ShapedType::isDynamic(strides[i])
649 ? memRefDescriptor.
stride(builder, loc, i)
651 indexType, strides[i]);
652 increment = LLVM::MulOp::create(builder, loc, increment, stride,
662 ? LLVM::GEPOp::create(builder, loc, elementPtrType,
663 converter.convertType(type.getElementType()),
664 base,
index, noWrapFlags)
671 if (
auto floatType = dyn_cast<FloatType>(type))
673 if (
auto vecType = dyn_cast<VectorType>(type))
674 return dyn_cast<FloatType>(vecType.getElementType());
683 Type convertedType = typeConverter.convertType(floatType);
686 return !isa<FloatType>(convertedType);
695 return isUnsupportedFloatingPointType(typeConverter, r.getType());
static Value createI32Constant(ConversionPatternRewriter &rewriter, Location loc, int32_t value)
static unsigned getBitWidth(Type type)
static FloatType getFloatingPointType(Type type)
Return the given type if it's a floating point type.
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...
static Value composeValueImpl(OpBuilder &builder, Location loc, ValueRange src, size_t &offset, Type dstType)
Recursive implementation of composeValue.
static void decomposeValueImpl(OpBuilder &builder, Location loc, Value src, Type dstType, SmallVectorImpl< Value > &result)
Recursive implementation of decomposeValue.
Attributes are known-constant values of operations.
IntegerAttr getIntegerAttr(Type type, int64_t value)
IntegerType getIntegerType(unsigned width)
StringAttr getStringAttr(const Twine &bytes)
Type getVoidType() const
Gets the MLIR type wrapping the LLVM void type.
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.
ConvertToLLVMPattern(StringRef rootOpName, MLIRContext *context, const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
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.
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.
Type getPtrType(unsigned addressSpace=0) const
Get the MLIR type wrapping the LLVM ptr type.
Type getIndexType() const
Gets the MLIR type wrapping the LLVM integer type whose bit width is defined by the used type convert...
const LLVMTypeConverter * getTypeConverter() const
Value getNumElements(Location loc, MemRefType memRefType, ValueRange dynamicSizes, ConversionPatternRewriter &rewriter) const
Computes total number of elements for the given MemRef and dynamicSizes.
LLVM::LLVMDialect & getDialect() const
Returns the LLVM dialect.
Value getSizeInBytes(Location loc, Type type, ConversionPatternRewriter &rewriter) const
Computes the size of type in bytes.
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...
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...
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...
Type getElementPtrType(MemRefType type) const
Returns the type of a pointer to an element of the memref.
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.
bool isConvertibleAndHasIdentityMaps(MemRefType type) const
Returns if the given memref type is convertible to LLVM and has an identity layout map.
Type getVoidPtrType() const
Get the MLIR type wrapping the LLVM i8* type.
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...
MLIRContext is the top-level object for a collection of MLIR operations.
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.
This class helps build Operations.
This is a value defined by a result of an operation.
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.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
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.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
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.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
bool isUnsupportedFloatingPointType(const TypeConverter &typeConverter, Type type)
Return "true" if the given type is an unsupported floating point type.
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.
bool opHasUnsupportedFloatingPointTypes(Operation *op, const TypeConverter &typeConverter)
Return "true" if the given op has any unsupported floating point types (either operands or results).
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...
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...
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...
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...
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...
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.