1*684dfe8aSAlex Zinenko //===- Pattern.cpp - Conversion pattern to the LLVM dialect ---------------===// 2*684dfe8aSAlex Zinenko // 3*684dfe8aSAlex Zinenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*684dfe8aSAlex Zinenko // See https://llvm.org/LICENSE.txt for license information. 5*684dfe8aSAlex Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*684dfe8aSAlex Zinenko // 7*684dfe8aSAlex Zinenko //===----------------------------------------------------------------------===// 8*684dfe8aSAlex Zinenko 9*684dfe8aSAlex Zinenko #include "mlir/Conversion/LLVMCommon/Pattern.h" 10*684dfe8aSAlex Zinenko #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 11*684dfe8aSAlex Zinenko #include "mlir/Dialect/LLVMIR/LLVMTypes.h" 12*684dfe8aSAlex Zinenko #include "mlir/IR/AffineMap.h" 13*684dfe8aSAlex Zinenko 14*684dfe8aSAlex Zinenko using namespace mlir; 15*684dfe8aSAlex Zinenko 16*684dfe8aSAlex Zinenko //===----------------------------------------------------------------------===// 17*684dfe8aSAlex Zinenko // ConvertToLLVMPattern 18*684dfe8aSAlex Zinenko //===----------------------------------------------------------------------===// 19*684dfe8aSAlex Zinenko 20*684dfe8aSAlex Zinenko ConvertToLLVMPattern::ConvertToLLVMPattern(StringRef rootOpName, 21*684dfe8aSAlex Zinenko MLIRContext *context, 22*684dfe8aSAlex Zinenko LLVMTypeConverter &typeConverter, 23*684dfe8aSAlex Zinenko PatternBenefit benefit) 24*684dfe8aSAlex Zinenko : ConversionPattern(typeConverter, rootOpName, benefit, context) {} 25*684dfe8aSAlex Zinenko 26*684dfe8aSAlex Zinenko LLVMTypeConverter *ConvertToLLVMPattern::getTypeConverter() const { 27*684dfe8aSAlex Zinenko return static_cast<LLVMTypeConverter *>( 28*684dfe8aSAlex Zinenko ConversionPattern::getTypeConverter()); 29*684dfe8aSAlex Zinenko } 30*684dfe8aSAlex Zinenko 31*684dfe8aSAlex Zinenko LLVM::LLVMDialect &ConvertToLLVMPattern::getDialect() const { 32*684dfe8aSAlex Zinenko return *getTypeConverter()->getDialect(); 33*684dfe8aSAlex Zinenko } 34*684dfe8aSAlex Zinenko 35*684dfe8aSAlex Zinenko Type ConvertToLLVMPattern::getIndexType() const { 36*684dfe8aSAlex Zinenko return getTypeConverter()->getIndexType(); 37*684dfe8aSAlex Zinenko } 38*684dfe8aSAlex Zinenko 39*684dfe8aSAlex Zinenko Type ConvertToLLVMPattern::getIntPtrType(unsigned addressSpace) const { 40*684dfe8aSAlex Zinenko return IntegerType::get(&getTypeConverter()->getContext(), 41*684dfe8aSAlex Zinenko getTypeConverter()->getPointerBitwidth(addressSpace)); 42*684dfe8aSAlex Zinenko } 43*684dfe8aSAlex Zinenko 44*684dfe8aSAlex Zinenko Type ConvertToLLVMPattern::getVoidType() const { 45*684dfe8aSAlex Zinenko return LLVM::LLVMVoidType::get(&getTypeConverter()->getContext()); 46*684dfe8aSAlex Zinenko } 47*684dfe8aSAlex Zinenko 48*684dfe8aSAlex Zinenko Type ConvertToLLVMPattern::getVoidPtrType() const { 49*684dfe8aSAlex Zinenko return LLVM::LLVMPointerType::get( 50*684dfe8aSAlex Zinenko IntegerType::get(&getTypeConverter()->getContext(), 8)); 51*684dfe8aSAlex Zinenko } 52*684dfe8aSAlex Zinenko 53*684dfe8aSAlex Zinenko Value ConvertToLLVMPattern::createIndexAttrConstant(OpBuilder &builder, 54*684dfe8aSAlex Zinenko Location loc, 55*684dfe8aSAlex Zinenko Type resultType, 56*684dfe8aSAlex Zinenko int64_t value) { 57*684dfe8aSAlex Zinenko return builder.create<LLVM::ConstantOp>( 58*684dfe8aSAlex Zinenko loc, resultType, builder.getIntegerAttr(builder.getIndexType(), value)); 59*684dfe8aSAlex Zinenko } 60*684dfe8aSAlex Zinenko 61*684dfe8aSAlex Zinenko Value ConvertToLLVMPattern::createIndexConstant( 62*684dfe8aSAlex Zinenko ConversionPatternRewriter &builder, Location loc, uint64_t value) const { 63*684dfe8aSAlex Zinenko return createIndexAttrConstant(builder, loc, getIndexType(), value); 64*684dfe8aSAlex Zinenko } 65*684dfe8aSAlex Zinenko 66*684dfe8aSAlex Zinenko Value ConvertToLLVMPattern::getStridedElementPtr( 67*684dfe8aSAlex Zinenko Location loc, MemRefType type, Value memRefDesc, ValueRange indices, 68*684dfe8aSAlex Zinenko ConversionPatternRewriter &rewriter) const { 69*684dfe8aSAlex Zinenko 70*684dfe8aSAlex Zinenko int64_t offset; 71*684dfe8aSAlex Zinenko SmallVector<int64_t, 4> strides; 72*684dfe8aSAlex Zinenko auto successStrides = getStridesAndOffset(type, strides, offset); 73*684dfe8aSAlex Zinenko assert(succeeded(successStrides) && "unexpected non-strided memref"); 74*684dfe8aSAlex Zinenko (void)successStrides; 75*684dfe8aSAlex Zinenko 76*684dfe8aSAlex Zinenko MemRefDescriptor memRefDescriptor(memRefDesc); 77*684dfe8aSAlex Zinenko Value base = memRefDescriptor.alignedPtr(rewriter, loc); 78*684dfe8aSAlex Zinenko 79*684dfe8aSAlex Zinenko Value index; 80*684dfe8aSAlex Zinenko if (offset != 0) // Skip if offset is zero. 81*684dfe8aSAlex Zinenko index = MemRefType::isDynamicStrideOrOffset(offset) 82*684dfe8aSAlex Zinenko ? memRefDescriptor.offset(rewriter, loc) 83*684dfe8aSAlex Zinenko : createIndexConstant(rewriter, loc, offset); 84*684dfe8aSAlex Zinenko 85*684dfe8aSAlex Zinenko for (int i = 0, e = indices.size(); i < e; ++i) { 86*684dfe8aSAlex Zinenko Value increment = indices[i]; 87*684dfe8aSAlex Zinenko if (strides[i] != 1) { // Skip if stride is 1. 88*684dfe8aSAlex Zinenko Value stride = MemRefType::isDynamicStrideOrOffset(strides[i]) 89*684dfe8aSAlex Zinenko ? memRefDescriptor.stride(rewriter, loc, i) 90*684dfe8aSAlex Zinenko : createIndexConstant(rewriter, loc, strides[i]); 91*684dfe8aSAlex Zinenko increment = rewriter.create<LLVM::MulOp>(loc, increment, stride); 92*684dfe8aSAlex Zinenko } 93*684dfe8aSAlex Zinenko index = 94*684dfe8aSAlex Zinenko index ? rewriter.create<LLVM::AddOp>(loc, index, increment) : increment; 95*684dfe8aSAlex Zinenko } 96*684dfe8aSAlex Zinenko 97*684dfe8aSAlex Zinenko Type elementPtrType = memRefDescriptor.getElementPtrType(); 98*684dfe8aSAlex Zinenko return index ? rewriter.create<LLVM::GEPOp>(loc, elementPtrType, base, index) 99*684dfe8aSAlex Zinenko : base; 100*684dfe8aSAlex Zinenko } 101*684dfe8aSAlex Zinenko 102*684dfe8aSAlex Zinenko // Check if the MemRefType `type` is supported by the lowering. We currently 103*684dfe8aSAlex Zinenko // only support memrefs with identity maps. 104*684dfe8aSAlex Zinenko bool ConvertToLLVMPattern::isConvertibleAndHasIdentityMaps( 105*684dfe8aSAlex Zinenko MemRefType type) const { 106*684dfe8aSAlex Zinenko if (!typeConverter->convertType(type.getElementType())) 107*684dfe8aSAlex Zinenko return false; 108*684dfe8aSAlex Zinenko return type.getAffineMaps().empty() || 109*684dfe8aSAlex Zinenko llvm::all_of(type.getAffineMaps(), 110*684dfe8aSAlex Zinenko [](AffineMap map) { return map.isIdentity(); }); 111*684dfe8aSAlex Zinenko } 112*684dfe8aSAlex Zinenko 113*684dfe8aSAlex Zinenko Type ConvertToLLVMPattern::getElementPtrType(MemRefType type) const { 114*684dfe8aSAlex Zinenko auto elementType = type.getElementType(); 115*684dfe8aSAlex Zinenko auto structElementType = typeConverter->convertType(elementType); 116*684dfe8aSAlex Zinenko return LLVM::LLVMPointerType::get(structElementType, 117*684dfe8aSAlex Zinenko type.getMemorySpaceAsInt()); 118*684dfe8aSAlex Zinenko } 119*684dfe8aSAlex Zinenko 120*684dfe8aSAlex Zinenko void ConvertToLLVMPattern::getMemRefDescriptorSizes( 121*684dfe8aSAlex Zinenko Location loc, MemRefType memRefType, ValueRange dynamicSizes, 122*684dfe8aSAlex Zinenko ConversionPatternRewriter &rewriter, SmallVectorImpl<Value> &sizes, 123*684dfe8aSAlex Zinenko SmallVectorImpl<Value> &strides, Value &sizeBytes) const { 124*684dfe8aSAlex Zinenko assert(isConvertibleAndHasIdentityMaps(memRefType) && 125*684dfe8aSAlex Zinenko "layout maps must have been normalized away"); 126*684dfe8aSAlex Zinenko assert(count(memRefType.getShape(), ShapedType::kDynamicSize) == 127*684dfe8aSAlex Zinenko static_cast<ssize_t>(dynamicSizes.size()) && 128*684dfe8aSAlex Zinenko "dynamicSizes size doesn't match dynamic sizes count in memref shape"); 129*684dfe8aSAlex Zinenko 130*684dfe8aSAlex Zinenko sizes.reserve(memRefType.getRank()); 131*684dfe8aSAlex Zinenko unsigned dynamicIndex = 0; 132*684dfe8aSAlex Zinenko for (int64_t size : memRefType.getShape()) { 133*684dfe8aSAlex Zinenko sizes.push_back(size == ShapedType::kDynamicSize 134*684dfe8aSAlex Zinenko ? dynamicSizes[dynamicIndex++] 135*684dfe8aSAlex Zinenko : createIndexConstant(rewriter, loc, size)); 136*684dfe8aSAlex Zinenko } 137*684dfe8aSAlex Zinenko 138*684dfe8aSAlex Zinenko // Strides: iterate sizes in reverse order and multiply. 139*684dfe8aSAlex Zinenko int64_t stride = 1; 140*684dfe8aSAlex Zinenko Value runningStride = createIndexConstant(rewriter, loc, 1); 141*684dfe8aSAlex Zinenko strides.resize(memRefType.getRank()); 142*684dfe8aSAlex Zinenko for (auto i = memRefType.getRank(); i-- > 0;) { 143*684dfe8aSAlex Zinenko strides[i] = runningStride; 144*684dfe8aSAlex Zinenko 145*684dfe8aSAlex Zinenko int64_t size = memRefType.getShape()[i]; 146*684dfe8aSAlex Zinenko if (size == 0) 147*684dfe8aSAlex Zinenko continue; 148*684dfe8aSAlex Zinenko bool useSizeAsStride = stride == 1; 149*684dfe8aSAlex Zinenko if (size == ShapedType::kDynamicSize) 150*684dfe8aSAlex Zinenko stride = ShapedType::kDynamicSize; 151*684dfe8aSAlex Zinenko if (stride != ShapedType::kDynamicSize) 152*684dfe8aSAlex Zinenko stride *= size; 153*684dfe8aSAlex Zinenko 154*684dfe8aSAlex Zinenko if (useSizeAsStride) 155*684dfe8aSAlex Zinenko runningStride = sizes[i]; 156*684dfe8aSAlex Zinenko else if (stride == ShapedType::kDynamicSize) 157*684dfe8aSAlex Zinenko runningStride = 158*684dfe8aSAlex Zinenko rewriter.create<LLVM::MulOp>(loc, runningStride, sizes[i]); 159*684dfe8aSAlex Zinenko else 160*684dfe8aSAlex Zinenko runningStride = createIndexConstant(rewriter, loc, stride); 161*684dfe8aSAlex Zinenko } 162*684dfe8aSAlex Zinenko 163*684dfe8aSAlex Zinenko // Buffer size in bytes. 164*684dfe8aSAlex Zinenko Type elementPtrType = getElementPtrType(memRefType); 165*684dfe8aSAlex Zinenko Value nullPtr = rewriter.create<LLVM::NullOp>(loc, elementPtrType); 166*684dfe8aSAlex Zinenko Value gepPtr = rewriter.create<LLVM::GEPOp>( 167*684dfe8aSAlex Zinenko loc, elementPtrType, ArrayRef<Value>{nullPtr, runningStride}); 168*684dfe8aSAlex Zinenko sizeBytes = rewriter.create<LLVM::PtrToIntOp>(loc, getIndexType(), gepPtr); 169*684dfe8aSAlex Zinenko } 170*684dfe8aSAlex Zinenko 171*684dfe8aSAlex Zinenko Value ConvertToLLVMPattern::getSizeInBytes( 172*684dfe8aSAlex Zinenko Location loc, Type type, ConversionPatternRewriter &rewriter) const { 173*684dfe8aSAlex Zinenko // Compute the size of an individual element. This emits the MLIR equivalent 174*684dfe8aSAlex Zinenko // of the following sizeof(...) implementation in LLVM IR: 175*684dfe8aSAlex Zinenko // %0 = getelementptr %elementType* null, %indexType 1 176*684dfe8aSAlex Zinenko // %1 = ptrtoint %elementType* %0 to %indexType 177*684dfe8aSAlex Zinenko // which is a common pattern of getting the size of a type in bytes. 178*684dfe8aSAlex Zinenko auto convertedPtrType = 179*684dfe8aSAlex Zinenko LLVM::LLVMPointerType::get(typeConverter->convertType(type)); 180*684dfe8aSAlex Zinenko auto nullPtr = rewriter.create<LLVM::NullOp>(loc, convertedPtrType); 181*684dfe8aSAlex Zinenko auto gep = rewriter.create<LLVM::GEPOp>( 182*684dfe8aSAlex Zinenko loc, convertedPtrType, 183*684dfe8aSAlex Zinenko ArrayRef<Value>{nullPtr, createIndexConstant(rewriter, loc, 1)}); 184*684dfe8aSAlex Zinenko return rewriter.create<LLVM::PtrToIntOp>(loc, getIndexType(), gep); 185*684dfe8aSAlex Zinenko } 186*684dfe8aSAlex Zinenko 187*684dfe8aSAlex Zinenko Value ConvertToLLVMPattern::getNumElements( 188*684dfe8aSAlex Zinenko Location loc, ArrayRef<Value> shape, 189*684dfe8aSAlex Zinenko ConversionPatternRewriter &rewriter) const { 190*684dfe8aSAlex Zinenko // Compute the total number of memref elements. 191*684dfe8aSAlex Zinenko Value numElements = 192*684dfe8aSAlex Zinenko shape.empty() ? createIndexConstant(rewriter, loc, 1) : shape.front(); 193*684dfe8aSAlex Zinenko for (unsigned i = 1, e = shape.size(); i < e; ++i) 194*684dfe8aSAlex Zinenko numElements = rewriter.create<LLVM::MulOp>(loc, numElements, shape[i]); 195*684dfe8aSAlex Zinenko return numElements; 196*684dfe8aSAlex Zinenko } 197*684dfe8aSAlex Zinenko 198*684dfe8aSAlex Zinenko /// Creates and populates the memref descriptor struct given all its fields. 199*684dfe8aSAlex Zinenko MemRefDescriptor ConvertToLLVMPattern::createMemRefDescriptor( 200*684dfe8aSAlex Zinenko Location loc, MemRefType memRefType, Value allocatedPtr, Value alignedPtr, 201*684dfe8aSAlex Zinenko ArrayRef<Value> sizes, ArrayRef<Value> strides, 202*684dfe8aSAlex Zinenko ConversionPatternRewriter &rewriter) const { 203*684dfe8aSAlex Zinenko auto structType = typeConverter->convertType(memRefType); 204*684dfe8aSAlex Zinenko auto memRefDescriptor = MemRefDescriptor::undef(rewriter, loc, structType); 205*684dfe8aSAlex Zinenko 206*684dfe8aSAlex Zinenko // Field 1: Allocated pointer, used for malloc/free. 207*684dfe8aSAlex Zinenko memRefDescriptor.setAllocatedPtr(rewriter, loc, allocatedPtr); 208*684dfe8aSAlex Zinenko 209*684dfe8aSAlex Zinenko // Field 2: Actual aligned pointer to payload. 210*684dfe8aSAlex Zinenko memRefDescriptor.setAlignedPtr(rewriter, loc, alignedPtr); 211*684dfe8aSAlex Zinenko 212*684dfe8aSAlex Zinenko // Field 3: Offset in aligned pointer. 213*684dfe8aSAlex Zinenko memRefDescriptor.setOffset(rewriter, loc, 214*684dfe8aSAlex Zinenko createIndexConstant(rewriter, loc, 0)); 215*684dfe8aSAlex Zinenko 216*684dfe8aSAlex Zinenko // Fields 4: Sizes. 217*684dfe8aSAlex Zinenko for (auto en : llvm::enumerate(sizes)) 218*684dfe8aSAlex Zinenko memRefDescriptor.setSize(rewriter, loc, en.index(), en.value()); 219*684dfe8aSAlex Zinenko 220*684dfe8aSAlex Zinenko // Field 5: Strides. 221*684dfe8aSAlex Zinenko for (auto en : llvm::enumerate(strides)) 222*684dfe8aSAlex Zinenko memRefDescriptor.setStride(rewriter, loc, en.index(), en.value()); 223*684dfe8aSAlex Zinenko 224*684dfe8aSAlex Zinenko return memRefDescriptor; 225*684dfe8aSAlex Zinenko } 226*684dfe8aSAlex Zinenko 227*684dfe8aSAlex Zinenko //===----------------------------------------------------------------------===// 228*684dfe8aSAlex Zinenko // Detail methods 229*684dfe8aSAlex Zinenko //===----------------------------------------------------------------------===// 230*684dfe8aSAlex Zinenko 231*684dfe8aSAlex Zinenko /// Replaces the given operation "op" with a new operation of type "targetOp" 232*684dfe8aSAlex Zinenko /// and given operands. 233*684dfe8aSAlex Zinenko LogicalResult LLVM::detail::oneToOneRewrite( 234*684dfe8aSAlex Zinenko Operation *op, StringRef targetOp, ValueRange operands, 235*684dfe8aSAlex Zinenko LLVMTypeConverter &typeConverter, ConversionPatternRewriter &rewriter) { 236*684dfe8aSAlex Zinenko unsigned numResults = op->getNumResults(); 237*684dfe8aSAlex Zinenko 238*684dfe8aSAlex Zinenko Type packedType; 239*684dfe8aSAlex Zinenko if (numResults != 0) { 240*684dfe8aSAlex Zinenko packedType = typeConverter.packFunctionResults(op->getResultTypes()); 241*684dfe8aSAlex Zinenko if (!packedType) 242*684dfe8aSAlex Zinenko return failure(); 243*684dfe8aSAlex Zinenko } 244*684dfe8aSAlex Zinenko 245*684dfe8aSAlex Zinenko // Create the operation through state since we don't know its C++ type. 246*684dfe8aSAlex Zinenko OperationState state(op->getLoc(), targetOp); 247*684dfe8aSAlex Zinenko state.addTypes(packedType); 248*684dfe8aSAlex Zinenko state.addOperands(operands); 249*684dfe8aSAlex Zinenko state.addAttributes(op->getAttrs()); 250*684dfe8aSAlex Zinenko Operation *newOp = rewriter.createOperation(state); 251*684dfe8aSAlex Zinenko 252*684dfe8aSAlex Zinenko // If the operation produced 0 or 1 result, return them immediately. 253*684dfe8aSAlex Zinenko if (numResults == 0) 254*684dfe8aSAlex Zinenko return rewriter.eraseOp(op), success(); 255*684dfe8aSAlex Zinenko if (numResults == 1) 256*684dfe8aSAlex Zinenko return rewriter.replaceOp(op, newOp->getResult(0)), success(); 257*684dfe8aSAlex Zinenko 258*684dfe8aSAlex Zinenko // Otherwise, it had been converted to an operation producing a structure. 259*684dfe8aSAlex Zinenko // Extract individual results from the structure and return them as list. 260*684dfe8aSAlex Zinenko SmallVector<Value, 4> results; 261*684dfe8aSAlex Zinenko results.reserve(numResults); 262*684dfe8aSAlex Zinenko for (unsigned i = 0; i < numResults; ++i) { 263*684dfe8aSAlex Zinenko auto type = typeConverter.convertType(op->getResult(i).getType()); 264*684dfe8aSAlex Zinenko results.push_back(rewriter.create<LLVM::ExtractValueOp>( 265*684dfe8aSAlex Zinenko op->getLoc(), type, newOp->getResult(0), rewriter.getI64ArrayAttr(i))); 266*684dfe8aSAlex Zinenko } 267*684dfe8aSAlex Zinenko rewriter.replaceOp(op, results); 268*684dfe8aSAlex Zinenko return success(); 269*684dfe8aSAlex Zinenko } 270