1*5c0c51a9SNicolas Vasilache //===- VectorToLLVM.cpp - Conversion from Vector to the LLVM dialect ------===// 2*5c0c51a9SNicolas Vasilache // 3*5c0c51a9SNicolas Vasilache // Copyright 2019 The MLIR Authors. 4*5c0c51a9SNicolas Vasilache // 5*5c0c51a9SNicolas Vasilache // Licensed under the Apache License, Version 2.0 (the "License"); 6*5c0c51a9SNicolas Vasilache // you may not use this file except in compliance with the License. 7*5c0c51a9SNicolas Vasilache // You may obtain a copy of the License at 8*5c0c51a9SNicolas Vasilache // 9*5c0c51a9SNicolas Vasilache // http://www.apache.org/licenses/LICENSE-2.0 10*5c0c51a9SNicolas Vasilache // 11*5c0c51a9SNicolas Vasilache // Unless required by applicable law or agreed to in writing, software 12*5c0c51a9SNicolas Vasilache // distributed under the License is distributed on an "AS IS" BASIS, 13*5c0c51a9SNicolas Vasilache // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*5c0c51a9SNicolas Vasilache // See the License for the specific language governing permissions and 15*5c0c51a9SNicolas Vasilache // limitations under the License. 16*5c0c51a9SNicolas Vasilache // ============================================================================= 17*5c0c51a9SNicolas Vasilache 18*5c0c51a9SNicolas Vasilache #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" 19*5c0c51a9SNicolas Vasilache #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h" 20*5c0c51a9SNicolas Vasilache #include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h" 21*5c0c51a9SNicolas Vasilache #include "mlir/Dialect/LLVMIR/LLVMDialect.h" 22*5c0c51a9SNicolas Vasilache #include "mlir/Dialect/VectorOps/VectorOps.h" 23*5c0c51a9SNicolas Vasilache #include "mlir/IR/Attributes.h" 24*5c0c51a9SNicolas Vasilache #include "mlir/IR/Builders.h" 25*5c0c51a9SNicolas Vasilache #include "mlir/IR/MLIRContext.h" 26*5c0c51a9SNicolas Vasilache #include "mlir/IR/Module.h" 27*5c0c51a9SNicolas Vasilache #include "mlir/IR/Operation.h" 28*5c0c51a9SNicolas Vasilache #include "mlir/IR/PatternMatch.h" 29*5c0c51a9SNicolas Vasilache #include "mlir/IR/StandardTypes.h" 30*5c0c51a9SNicolas Vasilache #include "mlir/IR/Types.h" 31*5c0c51a9SNicolas Vasilache #include "mlir/Pass/Pass.h" 32*5c0c51a9SNicolas Vasilache #include "mlir/Pass/PassManager.h" 33*5c0c51a9SNicolas Vasilache #include "mlir/Transforms/DialectConversion.h" 34*5c0c51a9SNicolas Vasilache #include "mlir/Transforms/Passes.h" 35*5c0c51a9SNicolas Vasilache 36*5c0c51a9SNicolas Vasilache #include "llvm/IR/DerivedTypes.h" 37*5c0c51a9SNicolas Vasilache #include "llvm/IR/Module.h" 38*5c0c51a9SNicolas Vasilache #include "llvm/IR/Type.h" 39*5c0c51a9SNicolas Vasilache #include "llvm/Support/Allocator.h" 40*5c0c51a9SNicolas Vasilache #include "llvm/Support/ErrorHandling.h" 41*5c0c51a9SNicolas Vasilache 42*5c0c51a9SNicolas Vasilache using namespace mlir; 43*5c0c51a9SNicolas Vasilache 44*5c0c51a9SNicolas Vasilache template <typename T> 45*5c0c51a9SNicolas Vasilache static LLVM::LLVMType getPtrToElementType(T containerType, 46*5c0c51a9SNicolas Vasilache LLVMTypeConverter &lowering) { 47*5c0c51a9SNicolas Vasilache return lowering.convertType(containerType.getElementType()) 48*5c0c51a9SNicolas Vasilache .template cast<LLVM::LLVMType>() 49*5c0c51a9SNicolas Vasilache .getPointerTo(); 50*5c0c51a9SNicolas Vasilache } 51*5c0c51a9SNicolas Vasilache 52*5c0c51a9SNicolas Vasilache class VectorExtractElementOpConversion : public LLVMOpLowering { 53*5c0c51a9SNicolas Vasilache public: 54*5c0c51a9SNicolas Vasilache explicit VectorExtractElementOpConversion(MLIRContext *context, 55*5c0c51a9SNicolas Vasilache LLVMTypeConverter &typeConverter) 56*5c0c51a9SNicolas Vasilache : LLVMOpLowering(vector::ExtractElementOp::getOperationName(), context, 57*5c0c51a9SNicolas Vasilache typeConverter) {} 58*5c0c51a9SNicolas Vasilache 59*5c0c51a9SNicolas Vasilache PatternMatchResult 60*5c0c51a9SNicolas Vasilache matchAndRewrite(Operation *op, ArrayRef<Value *> operands, 61*5c0c51a9SNicolas Vasilache ConversionPatternRewriter &rewriter) const override { 62*5c0c51a9SNicolas Vasilache auto loc = op->getLoc(); 63*5c0c51a9SNicolas Vasilache auto adaptor = vector::ExtractElementOpOperandAdaptor(operands); 64*5c0c51a9SNicolas Vasilache auto extractOp = cast<vector::ExtractElementOp>(op); 65*5c0c51a9SNicolas Vasilache auto vectorType = extractOp.vector()->getType().cast<VectorType>(); 66*5c0c51a9SNicolas Vasilache auto resultType = extractOp.getResult()->getType(); 67*5c0c51a9SNicolas Vasilache auto llvmResultType = lowering.convertType(resultType); 68*5c0c51a9SNicolas Vasilache 69*5c0c51a9SNicolas Vasilache auto positionArrayAttr = extractOp.position(); 70*5c0c51a9SNicolas Vasilache // One-shot extraction of vector from array (only requires extractvalue). 71*5c0c51a9SNicolas Vasilache if (resultType.isa<VectorType>()) { 72*5c0c51a9SNicolas Vasilache Value *extracted = rewriter.create<LLVM::ExtractValueOp>( 73*5c0c51a9SNicolas Vasilache loc, llvmResultType, adaptor.vector(), positionArrayAttr); 74*5c0c51a9SNicolas Vasilache rewriter.replaceOp(op, extracted); 75*5c0c51a9SNicolas Vasilache return matchSuccess(); 76*5c0c51a9SNicolas Vasilache } 77*5c0c51a9SNicolas Vasilache 78*5c0c51a9SNicolas Vasilache // Potential extraction of 1-D vector from struct. 79*5c0c51a9SNicolas Vasilache auto *context = op->getContext(); 80*5c0c51a9SNicolas Vasilache Value *extracted = adaptor.vector(); 81*5c0c51a9SNicolas Vasilache auto positionAttrs = positionArrayAttr.getValue(); 82*5c0c51a9SNicolas Vasilache auto i32Type = rewriter.getIntegerType(32); 83*5c0c51a9SNicolas Vasilache if (positionAttrs.size() > 1) { 84*5c0c51a9SNicolas Vasilache auto nDVectorType = vectorType; 85*5c0c51a9SNicolas Vasilache auto oneDVectorType = VectorType::get(nDVectorType.getShape().take_back(), 86*5c0c51a9SNicolas Vasilache nDVectorType.getElementType()); 87*5c0c51a9SNicolas Vasilache auto nMinusOnePositionAttrs = 88*5c0c51a9SNicolas Vasilache ArrayAttr::get(positionAttrs.drop_back(), context); 89*5c0c51a9SNicolas Vasilache extracted = rewriter.create<LLVM::ExtractValueOp>( 90*5c0c51a9SNicolas Vasilache loc, lowering.convertType(oneDVectorType), extracted, 91*5c0c51a9SNicolas Vasilache nMinusOnePositionAttrs); 92*5c0c51a9SNicolas Vasilache } 93*5c0c51a9SNicolas Vasilache 94*5c0c51a9SNicolas Vasilache // Remaining extraction of element from 1-D LLVM vector 95*5c0c51a9SNicolas Vasilache auto position = positionAttrs.back().cast<IntegerAttr>(); 96*5c0c51a9SNicolas Vasilache auto constant = rewriter.create<LLVM::ConstantOp>( 97*5c0c51a9SNicolas Vasilache loc, lowering.convertType(i32Type), position); 98*5c0c51a9SNicolas Vasilache extracted = 99*5c0c51a9SNicolas Vasilache rewriter.create<LLVM::ExtractElementOp>(loc, extracted, constant); 100*5c0c51a9SNicolas Vasilache rewriter.replaceOp(op, extracted); 101*5c0c51a9SNicolas Vasilache 102*5c0c51a9SNicolas Vasilache return matchSuccess(); 103*5c0c51a9SNicolas Vasilache } 104*5c0c51a9SNicolas Vasilache }; 105*5c0c51a9SNicolas Vasilache 106*5c0c51a9SNicolas Vasilache class VectorOuterProductOpConversion : public LLVMOpLowering { 107*5c0c51a9SNicolas Vasilache public: 108*5c0c51a9SNicolas Vasilache explicit VectorOuterProductOpConversion(MLIRContext *context, 109*5c0c51a9SNicolas Vasilache LLVMTypeConverter &typeConverter) 110*5c0c51a9SNicolas Vasilache : LLVMOpLowering(vector::OuterProductOp::getOperationName(), context, 111*5c0c51a9SNicolas Vasilache typeConverter) {} 112*5c0c51a9SNicolas Vasilache 113*5c0c51a9SNicolas Vasilache PatternMatchResult 114*5c0c51a9SNicolas Vasilache matchAndRewrite(Operation *op, ArrayRef<Value *> operands, 115*5c0c51a9SNicolas Vasilache ConversionPatternRewriter &rewriter) const override { 116*5c0c51a9SNicolas Vasilache auto loc = op->getLoc(); 117*5c0c51a9SNicolas Vasilache auto adaptor = vector::OuterProductOpOperandAdaptor(operands); 118*5c0c51a9SNicolas Vasilache auto *ctx = op->getContext(); 119*5c0c51a9SNicolas Vasilache auto vLHS = adaptor.lhs()->getType().cast<LLVM::LLVMType>(); 120*5c0c51a9SNicolas Vasilache auto vRHS = adaptor.rhs()->getType().cast<LLVM::LLVMType>(); 121*5c0c51a9SNicolas Vasilache auto rankLHS = vLHS.getUnderlyingType()->getVectorNumElements(); 122*5c0c51a9SNicolas Vasilache auto rankRHS = vRHS.getUnderlyingType()->getVectorNumElements(); 123*5c0c51a9SNicolas Vasilache auto llvmArrayOfVectType = lowering.convertType( 124*5c0c51a9SNicolas Vasilache cast<vector::OuterProductOp>(op).getResult()->getType()); 125*5c0c51a9SNicolas Vasilache Value *desc = rewriter.create<LLVM::UndefOp>(loc, llvmArrayOfVectType); 126*5c0c51a9SNicolas Vasilache Value *a = adaptor.lhs(), *b = adaptor.rhs(); 127*5c0c51a9SNicolas Vasilache Value *acc = adaptor.acc().empty() ? nullptr : adaptor.acc().front(); 128*5c0c51a9SNicolas Vasilache SmallVector<Value *, 8> lhs, accs; 129*5c0c51a9SNicolas Vasilache lhs.reserve(rankLHS); 130*5c0c51a9SNicolas Vasilache accs.reserve(rankLHS); 131*5c0c51a9SNicolas Vasilache for (unsigned d = 0, e = rankLHS; d < e; ++d) { 132*5c0c51a9SNicolas Vasilache // shufflevector explicitly requires i32. 133*5c0c51a9SNicolas Vasilache auto attr = rewriter.getI32IntegerAttr(d); 134*5c0c51a9SNicolas Vasilache SmallVector<Attribute, 4> bcastAttr(rankRHS, attr); 135*5c0c51a9SNicolas Vasilache auto bcastArrayAttr = ArrayAttr::get(bcastAttr, ctx); 136*5c0c51a9SNicolas Vasilache Value *aD = nullptr, *accD = nullptr; 137*5c0c51a9SNicolas Vasilache // 1. Broadcast the element a[d] into vector aD. 138*5c0c51a9SNicolas Vasilache aD = rewriter.create<LLVM::ShuffleVectorOp>(loc, a, a, bcastArrayAttr); 139*5c0c51a9SNicolas Vasilache // 2. If acc is present, extract 1-d vector acc[d] into accD. 140*5c0c51a9SNicolas Vasilache if (acc) 141*5c0c51a9SNicolas Vasilache accD = rewriter.create<LLVM::ExtractValueOp>( 142*5c0c51a9SNicolas Vasilache loc, vRHS, acc, rewriter.getI64ArrayAttr(d)); 143*5c0c51a9SNicolas Vasilache // 3. Compute aD outer b (plus accD, if relevant). 144*5c0c51a9SNicolas Vasilache Value *aOuterbD = 145*5c0c51a9SNicolas Vasilache accD ? rewriter.create<LLVM::FMulAddOp>(loc, vRHS, aD, b, accD) 146*5c0c51a9SNicolas Vasilache .getResult() 147*5c0c51a9SNicolas Vasilache : rewriter.create<LLVM::FMulOp>(loc, aD, b).getResult(); 148*5c0c51a9SNicolas Vasilache // 4. Insert as value `d` in the descriptor. 149*5c0c51a9SNicolas Vasilache desc = rewriter.create<LLVM::InsertValueOp>(loc, llvmArrayOfVectType, 150*5c0c51a9SNicolas Vasilache desc, aOuterbD, 151*5c0c51a9SNicolas Vasilache rewriter.getI64ArrayAttr(d)); 152*5c0c51a9SNicolas Vasilache } 153*5c0c51a9SNicolas Vasilache rewriter.replaceOp(op, desc); 154*5c0c51a9SNicolas Vasilache return matchSuccess(); 155*5c0c51a9SNicolas Vasilache } 156*5c0c51a9SNicolas Vasilache }; 157*5c0c51a9SNicolas Vasilache 158*5c0c51a9SNicolas Vasilache class VectorTypeCastOpConversion : public LLVMOpLowering { 159*5c0c51a9SNicolas Vasilache public: 160*5c0c51a9SNicolas Vasilache explicit VectorTypeCastOpConversion(MLIRContext *context, 161*5c0c51a9SNicolas Vasilache LLVMTypeConverter &typeConverter) 162*5c0c51a9SNicolas Vasilache : LLVMOpLowering(vector::TypeCastOp::getOperationName(), context, 163*5c0c51a9SNicolas Vasilache typeConverter) {} 164*5c0c51a9SNicolas Vasilache 165*5c0c51a9SNicolas Vasilache PatternMatchResult 166*5c0c51a9SNicolas Vasilache matchAndRewrite(Operation *op, ArrayRef<Value *> operands, 167*5c0c51a9SNicolas Vasilache ConversionPatternRewriter &rewriter) const override { 168*5c0c51a9SNicolas Vasilache auto loc = op->getLoc(); 169*5c0c51a9SNicolas Vasilache vector::TypeCastOp castOp = cast<vector::TypeCastOp>(op); 170*5c0c51a9SNicolas Vasilache MemRefType sourceMemRefType = 171*5c0c51a9SNicolas Vasilache castOp.getOperand()->getType().cast<MemRefType>(); 172*5c0c51a9SNicolas Vasilache MemRefType targetMemRefType = 173*5c0c51a9SNicolas Vasilache castOp.getResult()->getType().cast<MemRefType>(); 174*5c0c51a9SNicolas Vasilache 175*5c0c51a9SNicolas Vasilache // Only static shape casts supported atm. 176*5c0c51a9SNicolas Vasilache if (!sourceMemRefType.hasStaticShape() || 177*5c0c51a9SNicolas Vasilache !targetMemRefType.hasStaticShape()) 178*5c0c51a9SNicolas Vasilache return matchFailure(); 179*5c0c51a9SNicolas Vasilache 180*5c0c51a9SNicolas Vasilache auto llvmSourceDescriptorTy = 181*5c0c51a9SNicolas Vasilache operands[0]->getType().dyn_cast<LLVM::LLVMType>(); 182*5c0c51a9SNicolas Vasilache if (!llvmSourceDescriptorTy || !llvmSourceDescriptorTy.isStructTy()) 183*5c0c51a9SNicolas Vasilache return matchFailure(); 184*5c0c51a9SNicolas Vasilache MemRefDescriptor sourceMemRef(operands[0]); 185*5c0c51a9SNicolas Vasilache 186*5c0c51a9SNicolas Vasilache auto llvmTargetDescriptorTy = lowering.convertType(targetMemRefType) 187*5c0c51a9SNicolas Vasilache .dyn_cast_or_null<LLVM::LLVMType>(); 188*5c0c51a9SNicolas Vasilache if (!llvmTargetDescriptorTy || !llvmTargetDescriptorTy.isStructTy()) 189*5c0c51a9SNicolas Vasilache return matchFailure(); 190*5c0c51a9SNicolas Vasilache 191*5c0c51a9SNicolas Vasilache int64_t offset; 192*5c0c51a9SNicolas Vasilache SmallVector<int64_t, 4> strides; 193*5c0c51a9SNicolas Vasilache auto successStrides = 194*5c0c51a9SNicolas Vasilache getStridesAndOffset(sourceMemRefType, strides, offset); 195*5c0c51a9SNicolas Vasilache bool isContiguous = (strides.back() == 1); 196*5c0c51a9SNicolas Vasilache if (isContiguous) { 197*5c0c51a9SNicolas Vasilache auto sizes = sourceMemRefType.getShape(); 198*5c0c51a9SNicolas Vasilache for (int index = 0, e = strides.size() - 2; index < e; ++index) { 199*5c0c51a9SNicolas Vasilache if (strides[index] != strides[index + 1] * sizes[index + 1]) { 200*5c0c51a9SNicolas Vasilache isContiguous = false; 201*5c0c51a9SNicolas Vasilache break; 202*5c0c51a9SNicolas Vasilache } 203*5c0c51a9SNicolas Vasilache } 204*5c0c51a9SNicolas Vasilache } 205*5c0c51a9SNicolas Vasilache // Only contiguous source tensors supported atm. 206*5c0c51a9SNicolas Vasilache if (failed(successStrides) || !isContiguous) 207*5c0c51a9SNicolas Vasilache return matchFailure(); 208*5c0c51a9SNicolas Vasilache 209*5c0c51a9SNicolas Vasilache auto int64Ty = LLVM::LLVMType::getInt64Ty(lowering.getDialect()); 210*5c0c51a9SNicolas Vasilache 211*5c0c51a9SNicolas Vasilache // Create descriptor. 212*5c0c51a9SNicolas Vasilache auto desc = MemRefDescriptor::undef(rewriter, loc, llvmTargetDescriptorTy); 213*5c0c51a9SNicolas Vasilache Type llvmTargetElementTy = desc.getElementType(); 214*5c0c51a9SNicolas Vasilache // Set allocated ptr. 215*5c0c51a9SNicolas Vasilache Value *allocated = sourceMemRef.allocatedPtr(rewriter, loc); 216*5c0c51a9SNicolas Vasilache allocated = 217*5c0c51a9SNicolas Vasilache rewriter.create<LLVM::BitcastOp>(loc, llvmTargetElementTy, allocated); 218*5c0c51a9SNicolas Vasilache desc.setAllocatedPtr(rewriter, loc, allocated); 219*5c0c51a9SNicolas Vasilache // Set aligned ptr. 220*5c0c51a9SNicolas Vasilache Value *ptr = sourceMemRef.alignedPtr(rewriter, loc); 221*5c0c51a9SNicolas Vasilache ptr = rewriter.create<LLVM::BitcastOp>(loc, llvmTargetElementTy, ptr); 222*5c0c51a9SNicolas Vasilache desc.setAlignedPtr(rewriter, loc, ptr); 223*5c0c51a9SNicolas Vasilache // Fill offset 0. 224*5c0c51a9SNicolas Vasilache auto attr = rewriter.getIntegerAttr(rewriter.getIndexType(), 0); 225*5c0c51a9SNicolas Vasilache auto zero = rewriter.create<LLVM::ConstantOp>(loc, int64Ty, attr); 226*5c0c51a9SNicolas Vasilache desc.setOffset(rewriter, loc, zero); 227*5c0c51a9SNicolas Vasilache 228*5c0c51a9SNicolas Vasilache // Fill size and stride descriptors in memref. 229*5c0c51a9SNicolas Vasilache for (auto indexedSize : llvm::enumerate(targetMemRefType.getShape())) { 230*5c0c51a9SNicolas Vasilache int64_t index = indexedSize.index(); 231*5c0c51a9SNicolas Vasilache auto sizeAttr = 232*5c0c51a9SNicolas Vasilache rewriter.getIntegerAttr(rewriter.getIndexType(), indexedSize.value()); 233*5c0c51a9SNicolas Vasilache auto size = rewriter.create<LLVM::ConstantOp>(loc, int64Ty, sizeAttr); 234*5c0c51a9SNicolas Vasilache desc.setSize(rewriter, loc, index, size); 235*5c0c51a9SNicolas Vasilache auto strideAttr = 236*5c0c51a9SNicolas Vasilache rewriter.getIntegerAttr(rewriter.getIndexType(), strides[index]); 237*5c0c51a9SNicolas Vasilache auto stride = rewriter.create<LLVM::ConstantOp>(loc, int64Ty, strideAttr); 238*5c0c51a9SNicolas Vasilache desc.setStride(rewriter, loc, index, stride); 239*5c0c51a9SNicolas Vasilache } 240*5c0c51a9SNicolas Vasilache 241*5c0c51a9SNicolas Vasilache rewriter.replaceOp(op, {desc}); 242*5c0c51a9SNicolas Vasilache return matchSuccess(); 243*5c0c51a9SNicolas Vasilache } 244*5c0c51a9SNicolas Vasilache }; 245*5c0c51a9SNicolas Vasilache 246*5c0c51a9SNicolas Vasilache /// Populate the given list with patterns that convert from Vector to LLVM. 247*5c0c51a9SNicolas Vasilache void mlir::populateVectorToLLVMConversionPatterns( 248*5c0c51a9SNicolas Vasilache LLVMTypeConverter &converter, OwningRewritePatternList &patterns) { 249*5c0c51a9SNicolas Vasilache patterns.insert<VectorExtractElementOpConversion, 250*5c0c51a9SNicolas Vasilache VectorOuterProductOpConversion, VectorTypeCastOpConversion>( 251*5c0c51a9SNicolas Vasilache converter.getDialect()->getContext(), converter); 252*5c0c51a9SNicolas Vasilache } 253*5c0c51a9SNicolas Vasilache 254*5c0c51a9SNicolas Vasilache namespace { 255*5c0c51a9SNicolas Vasilache struct LowerVectorToLLVMPass : public ModulePass<LowerVectorToLLVMPass> { 256*5c0c51a9SNicolas Vasilache void runOnModule() override; 257*5c0c51a9SNicolas Vasilache }; 258*5c0c51a9SNicolas Vasilache } // namespace 259*5c0c51a9SNicolas Vasilache 260*5c0c51a9SNicolas Vasilache void LowerVectorToLLVMPass::runOnModule() { 261*5c0c51a9SNicolas Vasilache // Convert to the LLVM IR dialect using the converter defined above. 262*5c0c51a9SNicolas Vasilache OwningRewritePatternList patterns; 263*5c0c51a9SNicolas Vasilache LLVMTypeConverter converter(&getContext()); 264*5c0c51a9SNicolas Vasilache populateVectorToLLVMConversionPatterns(converter, patterns); 265*5c0c51a9SNicolas Vasilache populateStdToLLVMConversionPatterns(converter, patterns); 266*5c0c51a9SNicolas Vasilache 267*5c0c51a9SNicolas Vasilache ConversionTarget target(getContext()); 268*5c0c51a9SNicolas Vasilache target.addLegalDialect<LLVM::LLVMDialect>(); 269*5c0c51a9SNicolas Vasilache target.addDynamicallyLegalOp<FuncOp>( 270*5c0c51a9SNicolas Vasilache [&](FuncOp op) { return converter.isSignatureLegal(op.getType()); }); 271*5c0c51a9SNicolas Vasilache if (failed( 272*5c0c51a9SNicolas Vasilache applyPartialConversion(getModule(), target, patterns, &converter))) { 273*5c0c51a9SNicolas Vasilache signalPassFailure(); 274*5c0c51a9SNicolas Vasilache } 275*5c0c51a9SNicolas Vasilache } 276*5c0c51a9SNicolas Vasilache 277*5c0c51a9SNicolas Vasilache OpPassBase<ModuleOp> *mlir::createLowerVectorToLLVMPass() { 278*5c0c51a9SNicolas Vasilache return new LowerVectorToLLVMPass(); 279*5c0c51a9SNicolas Vasilache } 280*5c0c51a9SNicolas Vasilache 281*5c0c51a9SNicolas Vasilache static PassRegistration<LowerVectorToLLVMPass> 282*5c0c51a9SNicolas Vasilache pass("convert-vector-to-llvm", 283*5c0c51a9SNicolas Vasilache "Lower the operations from the vector dialect into the LLVM dialect"); 284