xref: /llvm-project/mlir/lib/Conversion/MemRefToSPIRV/MapMemRefStorageClassPass.cpp (revision 1079fc4f543c42bb09a33d2d79d90edd9c0bac91)
1713f85d5SLei Zhang //===- MapMemRefStorageCLassPass.cpp --------------------------------------===//
2713f85d5SLei Zhang //
3713f85d5SLei Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4713f85d5SLei Zhang // See https://llvm.org/LICENSE.txt for license information.
5713f85d5SLei Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6713f85d5SLei Zhang //
7713f85d5SLei Zhang //===----------------------------------------------------------------------===//
8713f85d5SLei Zhang //
9713f85d5SLei Zhang // This file implements a pass to map numeric MemRef memory spaces to
10713f85d5SLei Zhang // symbolic ones defined in the SPIR-V specification.
11713f85d5SLei Zhang //
12713f85d5SLei Zhang //===----------------------------------------------------------------------===//
13713f85d5SLei Zhang 
14039b969bSMichele Scuttari #include "mlir/Conversion/MemRefToSPIRV/MemRefToSPIRVPass.h"
1567d0d7acSMichele Scuttari 
1667d0d7acSMichele Scuttari #include "mlir/Conversion/MemRefToSPIRV/MemRefToSPIRV.h"
17a29fffc4SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
18713f85d5SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
1915135553SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h"
201dc48a91SStanley Winata #include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
217f6d4455SJakub Kuderski #include "mlir/IR/Attributes.h"
2247e953e9SLei Zhang #include "mlir/IR/BuiltinAttributes.h"
23713f85d5SLei Zhang #include "mlir/IR/BuiltinTypes.h"
24b91bba89SJakub Kuderski #include "mlir/IR/Operation.h"
25b91bba89SJakub Kuderski #include "mlir/IR/Visitors.h"
2634a35a8bSMartin Erhart #include "mlir/Interfaces/FunctionInterfaces.h"
277f6d4455SJakub Kuderski #include "llvm/ADT/SmallVectorExtras.h"
28713f85d5SLei Zhang #include "llvm/ADT/StringExtras.h"
29713f85d5SLei Zhang #include "llvm/Support/Debug.h"
30b91bba89SJakub Kuderski #include <optional>
31713f85d5SLei Zhang 
3267d0d7acSMichele Scuttari namespace mlir {
3367d0d7acSMichele Scuttari #define GEN_PASS_DEF_MAPMEMREFSTORAGECLASS
3467d0d7acSMichele Scuttari #include "mlir/Conversion/Passes.h.inc"
3567d0d7acSMichele Scuttari } // namespace mlir
3667d0d7acSMichele Scuttari 
37713f85d5SLei Zhang #define DEBUG_TYPE "mlir-map-memref-storage-class"
38713f85d5SLei Zhang 
39713f85d5SLei Zhang using namespace mlir;
40713f85d5SLei Zhang 
41713f85d5SLei Zhang //===----------------------------------------------------------------------===//
421f7544a6SLei Zhang // Mappings
43713f85d5SLei Zhang //===----------------------------------------------------------------------===//
44713f85d5SLei Zhang 
451f7544a6SLei Zhang /// Mapping between SPIR-V storage classes to memref memory spaces.
461f7544a6SLei Zhang ///
471f7544a6SLei Zhang /// Note: memref does not have a defined semantics for each memory space; it
481f7544a6SLei Zhang /// depends on the context where it is used. There are no particular reasons
491f7544a6SLei Zhang /// behind the number assignments; we try to follow NVVM conventions and largely
501f7544a6SLei Zhang /// give common storage classes a smaller number.
5135a56e5dSStanley Winata #define VULKAN_STORAGE_SPACE_MAP_LIST(MAP_FN)                                  \
521f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::StorageBuffer, 0)                                \
531f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Generic, 1)                                      \
541f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Workgroup, 3)                                    \
551f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Uniform, 4)                                      \
561f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Private, 5)                                      \
571f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Function, 6)                                     \
581f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::PushConstant, 7)                                 \
591f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::UniformConstant, 8)                              \
601f7544a6SLei Zhang   MAP_FN(spirv::StorageClass::Input, 9)                                        \
617f6d4455SJakub Kuderski   MAP_FN(spirv::StorageClass::Output, 10)                                      \
627f6d4455SJakub Kuderski   MAP_FN(spirv::StorageClass::PhysicalStorageBuffer, 11)
631f7544a6SLei Zhang 
640de16fafSRamkumar Ramachandra std::optional<spirv::StorageClass>
mapMemorySpaceToVulkanStorageClass(Attribute memorySpaceAttr)6547e953e9SLei Zhang spirv::mapMemorySpaceToVulkanStorageClass(Attribute memorySpaceAttr) {
6647e953e9SLei Zhang   // Handle null memory space attribute specially.
6747e953e9SLei Zhang   if (!memorySpaceAttr)
6847e953e9SLei Zhang     return spirv::StorageClass::StorageBuffer;
6947e953e9SLei Zhang 
7047e953e9SLei Zhang   // Unknown dialect custom attributes are not supported by default.
7147e953e9SLei Zhang   // Downstream callers should plug in more specialized ones.
725550c821STres Popp   auto intAttr = dyn_cast<IntegerAttr>(memorySpaceAttr);
7347e953e9SLei Zhang   if (!intAttr)
741a36588eSKazu Hirata     return std::nullopt;
7547e953e9SLei Zhang   unsigned memorySpace = intAttr.getInt();
7647e953e9SLei Zhang 
7715135553SLei Zhang #define STORAGE_SPACE_MAP_FN(storage, space)                                   \
7815135553SLei Zhang   case space:                                                                  \
7915135553SLei Zhang     return storage;
801f7544a6SLei Zhang 
8115135553SLei Zhang   switch (memorySpace) {
8235a56e5dSStanley Winata     VULKAN_STORAGE_SPACE_MAP_LIST(STORAGE_SPACE_MAP_FN)
8315135553SLei Zhang   default:
8415135553SLei Zhang     break;
8515135553SLei Zhang   }
861a36588eSKazu Hirata   return std::nullopt;
871f7544a6SLei Zhang 
881f7544a6SLei Zhang #undef STORAGE_SPACE_MAP_FN
89713f85d5SLei Zhang }
90713f85d5SLei Zhang 
910de16fafSRamkumar Ramachandra std::optional<unsigned>
mapVulkanStorageClassToMemorySpace(spirv::StorageClass storageClass)9215135553SLei Zhang spirv::mapVulkanStorageClassToMemorySpace(spirv::StorageClass storageClass) {
9315135553SLei Zhang #define STORAGE_SPACE_MAP_FN(storage, space)                                   \
9415135553SLei Zhang   case storage:                                                                \
9515135553SLei Zhang     return space;
9615135553SLei Zhang 
9715135553SLei Zhang   switch (storageClass) {
9835a56e5dSStanley Winata     VULKAN_STORAGE_SPACE_MAP_LIST(STORAGE_SPACE_MAP_FN)
9915135553SLei Zhang   default:
10015135553SLei Zhang     break;
10115135553SLei Zhang   }
1021a36588eSKazu Hirata   return std::nullopt;
10315135553SLei Zhang 
10415135553SLei Zhang #undef STORAGE_SPACE_MAP_FN
10515135553SLei Zhang }
10615135553SLei Zhang 
10735a56e5dSStanley Winata #undef VULKAN_STORAGE_SPACE_MAP_LIST
10835a56e5dSStanley Winata 
10935a56e5dSStanley Winata #define OPENCL_STORAGE_SPACE_MAP_LIST(MAP_FN)                                  \
11035a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::CrossWorkgroup, 0)                               \
11135a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::Generic, 1)                                      \
11235a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::Workgroup, 3)                                    \
11335a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::UniformConstant, 4)                              \
11435a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::Private, 5)                                      \
11535a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::Function, 6)                                     \
11635a56e5dSStanley Winata   MAP_FN(spirv::StorageClass::Image, 7)
11735a56e5dSStanley Winata 
1180de16fafSRamkumar Ramachandra std::optional<spirv::StorageClass>
mapMemorySpaceToOpenCLStorageClass(Attribute memorySpaceAttr)11947e953e9SLei Zhang spirv::mapMemorySpaceToOpenCLStorageClass(Attribute memorySpaceAttr) {
12047e953e9SLei Zhang   // Handle null memory space attribute specially.
12147e953e9SLei Zhang   if (!memorySpaceAttr)
12247e953e9SLei Zhang     return spirv::StorageClass::CrossWorkgroup;
12347e953e9SLei Zhang 
12447e953e9SLei Zhang   // Unknown dialect custom attributes are not supported by default.
12547e953e9SLei Zhang   // Downstream callers should plug in more specialized ones.
1265550c821STres Popp   auto intAttr = dyn_cast<IntegerAttr>(memorySpaceAttr);
12747e953e9SLei Zhang   if (!intAttr)
1281a36588eSKazu Hirata     return std::nullopt;
12947e953e9SLei Zhang   unsigned memorySpace = intAttr.getInt();
13047e953e9SLei Zhang 
13135a56e5dSStanley Winata #define STORAGE_SPACE_MAP_FN(storage, space)                                   \
13235a56e5dSStanley Winata   case space:                                                                  \
13335a56e5dSStanley Winata     return storage;
13435a56e5dSStanley Winata 
13535a56e5dSStanley Winata   switch (memorySpace) {
13635a56e5dSStanley Winata     OPENCL_STORAGE_SPACE_MAP_LIST(STORAGE_SPACE_MAP_FN)
13735a56e5dSStanley Winata   default:
13835a56e5dSStanley Winata     break;
13935a56e5dSStanley Winata   }
1401a36588eSKazu Hirata   return std::nullopt;
14135a56e5dSStanley Winata 
14235a56e5dSStanley Winata #undef STORAGE_SPACE_MAP_FN
14335a56e5dSStanley Winata }
14435a56e5dSStanley Winata 
1450de16fafSRamkumar Ramachandra std::optional<unsigned>
mapOpenCLStorageClassToMemorySpace(spirv::StorageClass storageClass)14635a56e5dSStanley Winata spirv::mapOpenCLStorageClassToMemorySpace(spirv::StorageClass storageClass) {
14735a56e5dSStanley Winata #define STORAGE_SPACE_MAP_FN(storage, space)                                   \
14835a56e5dSStanley Winata   case storage:                                                                \
14935a56e5dSStanley Winata     return space;
15035a56e5dSStanley Winata 
15135a56e5dSStanley Winata   switch (storageClass) {
15235a56e5dSStanley Winata     OPENCL_STORAGE_SPACE_MAP_LIST(STORAGE_SPACE_MAP_FN)
15335a56e5dSStanley Winata   default:
15435a56e5dSStanley Winata     break;
15535a56e5dSStanley Winata   }
1561a36588eSKazu Hirata   return std::nullopt;
15735a56e5dSStanley Winata 
15835a56e5dSStanley Winata #undef STORAGE_SPACE_MAP_FN
15935a56e5dSStanley Winata }
16035a56e5dSStanley Winata 
16135a56e5dSStanley Winata #undef OPENCL_STORAGE_SPACE_MAP_LIST
16215135553SLei Zhang 
163713f85d5SLei Zhang //===----------------------------------------------------------------------===//
164713f85d5SLei Zhang // Type Converter
165713f85d5SLei Zhang //===----------------------------------------------------------------------===//
166713f85d5SLei Zhang 
MemorySpaceToStorageClassConverter(const spirv::MemorySpaceToStorageClassMap & memorySpaceMap)167713f85d5SLei Zhang spirv::MemorySpaceToStorageClassConverter::MemorySpaceToStorageClassConverter(
168713f85d5SLei Zhang     const spirv::MemorySpaceToStorageClassMap &memorySpaceMap)
169713f85d5SLei Zhang     : memorySpaceMap(memorySpaceMap) {
170713f85d5SLei Zhang   // Pass through for all other types.
171713f85d5SLei Zhang   addConversion([](Type type) { return type; });
172713f85d5SLei Zhang 
1730de16fafSRamkumar Ramachandra   addConversion([this](BaseMemRefType memRefType) -> std::optional<Type> {
1740de16fafSRamkumar Ramachandra     std::optional<spirv::StorageClass> storage =
17547e953e9SLei Zhang         this->memorySpaceMap(memRefType.getMemorySpace());
17615135553SLei Zhang     if (!storage) {
177b83d0d46SLei Zhang       LLVM_DEBUG(llvm::dbgs()
178b83d0d46SLei Zhang                  << "cannot convert " << memRefType
179b83d0d46SLei Zhang                  << " due to being unable to find memory space in map\n");
1801a36588eSKazu Hirata       return std::nullopt;
181713f85d5SLei Zhang     }
182713f85d5SLei Zhang 
183713f85d5SLei Zhang     auto storageAttr =
18415135553SLei Zhang         spirv::StorageClassAttr::get(memRefType.getContext(), *storage);
1855550c821STres Popp     if (auto rankedType = dyn_cast<MemRefType>(memRefType)) {
186713f85d5SLei Zhang       return MemRefType::get(memRefType.getShape(), memRefType.getElementType(),
187713f85d5SLei Zhang                              rankedType.getLayout(), storageAttr);
188713f85d5SLei Zhang     }
189713f85d5SLei Zhang     return UnrankedMemRefType::get(memRefType.getElementType(), storageAttr);
190713f85d5SLei Zhang   });
191713f85d5SLei Zhang 
192713f85d5SLei Zhang   addConversion([this](FunctionType type) {
1937f6d4455SJakub Kuderski     auto inputs = llvm::map_to_vector(
1947f6d4455SJakub Kuderski         type.getInputs(), [this](Type ty) { return convertType(ty); });
1957f6d4455SJakub Kuderski     auto results = llvm::map_to_vector(
1967f6d4455SJakub Kuderski         type.getResults(), [this](Type ty) { return convertType(ty); });
197713f85d5SLei Zhang     return FunctionType::get(type.getContext(), inputs, results);
198713f85d5SLei Zhang   });
199713f85d5SLei Zhang }
200713f85d5SLei Zhang 
201713f85d5SLei Zhang //===----------------------------------------------------------------------===//
202713f85d5SLei Zhang // Conversion Target
203713f85d5SLei Zhang //===----------------------------------------------------------------------===//
204713f85d5SLei Zhang 
205713f85d5SLei Zhang /// Returns true if the given `type` is considered as legal for SPIR-V
206713f85d5SLei Zhang /// conversion.
isLegalType(Type type)207713f85d5SLei Zhang static bool isLegalType(Type type) {
2085550c821STres Popp   if (auto memRefType = dyn_cast<BaseMemRefType>(type)) {
209713f85d5SLei Zhang     Attribute spaceAttr = memRefType.getMemorySpace();
210345d574bSMehdi Amini     return isa_and_nonnull<spirv::StorageClassAttr>(spaceAttr);
211713f85d5SLei Zhang   }
212713f85d5SLei Zhang   return true;
213713f85d5SLei Zhang }
214713f85d5SLei Zhang 
215713f85d5SLei Zhang /// Returns true if the given `attr` is considered as legal for SPIR-V
216713f85d5SLei Zhang /// conversion.
isLegalAttr(Attribute attr)217713f85d5SLei Zhang static bool isLegalAttr(Attribute attr) {
2185550c821STres Popp   if (auto typeAttr = dyn_cast<TypeAttr>(attr))
219713f85d5SLei Zhang     return isLegalType(typeAttr.getValue());
220713f85d5SLei Zhang   return true;
221713f85d5SLei Zhang }
222713f85d5SLei Zhang 
223713f85d5SLei Zhang /// Returns true if the given `op` is considered as legal for SPIR-V conversion.
isLegalOp(Operation * op)224713f85d5SLei Zhang static bool isLegalOp(Operation *op) {
225b83d0d46SLei Zhang   if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
226b83d0d46SLei Zhang     return llvm::all_of(funcOp.getArgumentTypes(), isLegalType) &&
2276ca1a09fSChristopher Bate            llvm::all_of(funcOp.getResultTypes(), isLegalType) &&
2286ca1a09fSChristopher Bate            llvm::all_of(funcOp.getFunctionBody().getArgumentTypes(),
2296ca1a09fSChristopher Bate                         isLegalType);
230713f85d5SLei Zhang   }
231713f85d5SLei Zhang 
232713f85d5SLei Zhang   auto attrs = llvm::map_range(op->getAttrs(), [](const NamedAttribute &attr) {
233713f85d5SLei Zhang     return attr.getValue();
234713f85d5SLei Zhang   });
235713f85d5SLei Zhang 
236713f85d5SLei Zhang   return llvm::all_of(op->getOperandTypes(), isLegalType) &&
237713f85d5SLei Zhang          llvm::all_of(op->getResultTypes(), isLegalType) &&
238713f85d5SLei Zhang          llvm::all_of(attrs, isLegalAttr);
239713f85d5SLei Zhang }
240713f85d5SLei Zhang 
241713f85d5SLei Zhang std::unique_ptr<ConversionTarget>
getMemorySpaceToStorageClassTarget(MLIRContext & context)242713f85d5SLei Zhang spirv::getMemorySpaceToStorageClassTarget(MLIRContext &context) {
243713f85d5SLei Zhang   auto target = std::make_unique<ConversionTarget>(context);
244713f85d5SLei Zhang   target->markUnknownOpDynamicallyLegal(isLegalOp);
245713f85d5SLei Zhang   return target;
246713f85d5SLei Zhang }
247713f85d5SLei Zhang 
convertMemRefTypesAndAttrs(Operation * op,MemorySpaceToStorageClassConverter & typeConverter)248b91bba89SJakub Kuderski void spirv::convertMemRefTypesAndAttrs(
249b91bba89SJakub Kuderski     Operation *op, MemorySpaceToStorageClassConverter &typeConverter) {
250b91bba89SJakub Kuderski   AttrTypeReplacer replacer;
251b91bba89SJakub Kuderski   replacer.addReplacement([&typeConverter](BaseMemRefType origType)
252b91bba89SJakub Kuderski                               -> std::optional<BaseMemRefType> {
253b91bba89SJakub Kuderski     return typeConverter.convertType<BaseMemRefType>(origType);
254b91bba89SJakub Kuderski   });
255713f85d5SLei Zhang 
256b91bba89SJakub Kuderski   replacer.recursivelyReplaceElementsIn(op, /*replaceAttrs=*/true,
257b91bba89SJakub Kuderski                                         /*replaceLocs=*/false,
258b91bba89SJakub Kuderski                                         /*replaceTypes=*/true);
259713f85d5SLei Zhang }
260713f85d5SLei Zhang 
261713f85d5SLei Zhang //===----------------------------------------------------------------------===//
262713f85d5SLei Zhang // Conversion Pass
263713f85d5SLei Zhang //===----------------------------------------------------------------------===//
264713f85d5SLei Zhang 
265713f85d5SLei Zhang namespace {
266713f85d5SLei Zhang class MapMemRefStorageClassPass final
26767d0d7acSMichele Scuttari     : public impl::MapMemRefStorageClassBase<MapMemRefStorageClassPass> {
268713f85d5SLei Zhang public:
2697f6d4455SJakub Kuderski   MapMemRefStorageClassPass() = default;
2707f6d4455SJakub Kuderski 
MapMemRefStorageClassPass(const spirv::MemorySpaceToStorageClassMap & memorySpaceMap)271713f85d5SLei Zhang   explicit MapMemRefStorageClassPass(
272713f85d5SLei Zhang       const spirv::MemorySpaceToStorageClassMap &memorySpaceMap)
273713f85d5SLei Zhang       : memorySpaceMap(memorySpaceMap) {}
274713f85d5SLei Zhang 
initializeOptions(StringRef options,function_ref<LogicalResult (const Twine &)> errorHandler)275*1079fc4fSIvan Butygin   LogicalResult initializeOptions(
276*1079fc4fSIvan Butygin       StringRef options,
277*1079fc4fSIvan Butygin       function_ref<LogicalResult(const Twine &)> errorHandler) override {
278*1079fc4fSIvan Butygin     if (failed(Pass::initializeOptions(options, errorHandler)))
279713f85d5SLei Zhang       return failure();
280713f85d5SLei Zhang 
2817f6d4455SJakub Kuderski     if (clientAPI == "opencl")
28235a56e5dSStanley Winata       memorySpaceMap = spirv::mapMemorySpaceToOpenCLStorageClass;
2837f6d4455SJakub Kuderski     else if (clientAPI != "vulkan")
284*1079fc4fSIvan Butygin       return errorHandler(llvm::Twine("Invalid clienAPI: ") + clientAPI);
285713f85d5SLei Zhang 
286713f85d5SLei Zhang     return success();
287713f85d5SLei Zhang   }
288713f85d5SLei Zhang 
runOnOperation()2897f6d4455SJakub Kuderski   void runOnOperation() override {
290713f85d5SLei Zhang     MLIRContext *context = &getContext();
291b83d0d46SLei Zhang     Operation *op = getOperation();
292713f85d5SLei Zhang 
293b91bba89SJakub Kuderski     spirv::MemorySpaceToStorageClassMap spaceToStorage = memorySpaceMap;
2941dc48a91SStanley Winata     if (spirv::TargetEnvAttr attr = spirv::lookupTargetEnv(op)) {
2951dc48a91SStanley Winata       spirv::TargetEnv targetEnv(attr);
2961dc48a91SStanley Winata       if (targetEnv.allows(spirv::Capability::Kernel)) {
297b91bba89SJakub Kuderski         spaceToStorage = spirv::mapMemorySpaceToOpenCLStorageClass;
2981dc48a91SStanley Winata       } else if (targetEnv.allows(spirv::Capability::Shader)) {
299b91bba89SJakub Kuderski         spaceToStorage = spirv::mapMemorySpaceToVulkanStorageClass;
3001dc48a91SStanley Winata       }
3011dc48a91SStanley Winata     }
3021dc48a91SStanley Winata 
303b91bba89SJakub Kuderski     spirv::MemorySpaceToStorageClassConverter converter(spaceToStorage);
304b91bba89SJakub Kuderski     // Perform the replacement.
305b91bba89SJakub Kuderski     spirv::convertMemRefTypesAndAttrs(op, converter);
306b91bba89SJakub Kuderski 
307b91bba89SJakub Kuderski     // Check if there are any illegal ops remaining.
3087f6d4455SJakub Kuderski     std::unique_ptr<ConversionTarget> target =
3097f6d4455SJakub Kuderski         spirv::getMemorySpaceToStorageClassTarget(*context);
310b91bba89SJakub Kuderski     op->walk([&target, this](Operation *childOp) {
311b91bba89SJakub Kuderski       if (target->isIllegal(childOp)) {
312b91bba89SJakub Kuderski         childOp->emitOpError("failed to legalize memory space");
313b91bba89SJakub Kuderski         signalPassFailure();
314b91bba89SJakub Kuderski         return WalkResult::interrupt();
315b91bba89SJakub Kuderski       }
316b91bba89SJakub Kuderski       return WalkResult::advance();
317b91bba89SJakub Kuderski     });
318713f85d5SLei Zhang   }
319713f85d5SLei Zhang 
3207f6d4455SJakub Kuderski private:
3217f6d4455SJakub Kuderski   spirv::MemorySpaceToStorageClassMap memorySpaceMap =
3227f6d4455SJakub Kuderski       spirv::mapMemorySpaceToVulkanStorageClass;
3237f6d4455SJakub Kuderski };
3247f6d4455SJakub Kuderski } // namespace
3257f6d4455SJakub Kuderski 
createMapMemRefStorageClassPass()326b83d0d46SLei Zhang std::unique_ptr<OperationPass<>> mlir::createMapMemRefStorageClassPass() {
327713f85d5SLei Zhang   return std::make_unique<MapMemRefStorageClassPass>();
328713f85d5SLei Zhang }
329