1930c74f1SLei Zhang //===- GPUToSPIRV.cpp - GPU to SPIR-V Patterns ----------------------------===//
2930c74f1SLei Zhang //
3930c74f1SLei Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4930c74f1SLei Zhang // See https://llvm.org/LICENSE.txt for license information.
5930c74f1SLei Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6930c74f1SLei Zhang //
7930c74f1SLei Zhang //===----------------------------------------------------------------------===//
8930c74f1SLei Zhang //
9930c74f1SLei Zhang // This file implements patterns to convert GPU dialect to SPIR-V dialect.
10930c74f1SLei Zhang //
11930c74f1SLei Zhang //===----------------------------------------------------------------------===//
12930c74f1SLei Zhang 
13930c74f1SLei Zhang #include "mlir/Conversion/GPUToSPIRV/GPUToSPIRV.h"
14d7ef488bSMogball #include "mlir/Dialect/GPU/IR/GPUDialect.h"
15930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
16c809c9bdSLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h"
17930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
18930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
19930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h"
20930c74f1SLei Zhang #include "mlir/IR/BuiltinOps.h"
217c3ae48fSLei Zhang #include "mlir/Transforms/DialectConversion.h"
22930c74f1SLei Zhang 
23930c74f1SLei Zhang using namespace mlir;
24930c74f1SLei Zhang 
25930c74f1SLei Zhang static constexpr const char kSPIRVModule[] = "__spv__";
26930c74f1SLei Zhang 
27930c74f1SLei Zhang namespace {
28930c74f1SLei Zhang /// Pattern lowering GPU block/thread size/id to loading SPIR-V invocation
29930c74f1SLei Zhang /// builtin variables.
30930c74f1SLei Zhang template <typename SourceOp, spirv::BuiltIn builtin>
317c3ae48fSLei Zhang class LaunchConfigConversion : public OpConversionPattern<SourceOp> {
32930c74f1SLei Zhang public:
337c3ae48fSLei Zhang   using OpConversionPattern<SourceOp>::OpConversionPattern;
34930c74f1SLei Zhang 
35930c74f1SLei Zhang   LogicalResult
36b54c724bSRiver Riddle   matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor,
37930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
38930c74f1SLei Zhang };
39930c74f1SLei Zhang 
40930c74f1SLei Zhang /// Pattern lowering subgroup size/id to loading SPIR-V invocation
41930c74f1SLei Zhang /// builtin variables.
42930c74f1SLei Zhang template <typename SourceOp, spirv::BuiltIn builtin>
437c3ae48fSLei Zhang class SingleDimLaunchConfigConversion : public OpConversionPattern<SourceOp> {
44930c74f1SLei Zhang public:
457c3ae48fSLei Zhang   using OpConversionPattern<SourceOp>::OpConversionPattern;
46930c74f1SLei Zhang 
47930c74f1SLei Zhang   LogicalResult
48b54c724bSRiver Riddle   matchAndRewrite(SourceOp op, typename SourceOp::Adaptor adaptor,
49930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
50930c74f1SLei Zhang };
51930c74f1SLei Zhang 
52930c74f1SLei Zhang /// This is separate because in Vulkan workgroup size is exposed to shaders via
53930c74f1SLei Zhang /// a constant with WorkgroupSize decoration. So here we cannot generate a
54930c74f1SLei Zhang /// builtin variable; instead the information in the `spv.entry_point_abi`
55930c74f1SLei Zhang /// attribute on the surrounding FuncOp is used to replace the gpu::BlockDimOp.
567c3ae48fSLei Zhang class WorkGroupSizeConversion : public OpConversionPattern<gpu::BlockDimOp> {
57930c74f1SLei Zhang public:
WorkGroupSizeConversion(TypeConverter & typeConverter,MLIRContext * context)584df95441SIvan Butygin   WorkGroupSizeConversion(TypeConverter &typeConverter, MLIRContext *context)
594df95441SIvan Butygin       : OpConversionPattern(typeConverter, context, /*benefit*/ 10) {}
60930c74f1SLei Zhang 
61930c74f1SLei Zhang   LogicalResult
62b54c724bSRiver Riddle   matchAndRewrite(gpu::BlockDimOp op, OpAdaptor adaptor,
63930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
64930c74f1SLei Zhang };
65930c74f1SLei Zhang 
66930c74f1SLei Zhang /// Pattern to convert a kernel function in GPU dialect within a spv.module.
677c3ae48fSLei Zhang class GPUFuncOpConversion final : public OpConversionPattern<gpu::GPUFuncOp> {
68930c74f1SLei Zhang public:
697c3ae48fSLei Zhang   using OpConversionPattern<gpu::GPUFuncOp>::OpConversionPattern;
70930c74f1SLei Zhang 
71930c74f1SLei Zhang   LogicalResult
72b54c724bSRiver Riddle   matchAndRewrite(gpu::GPUFuncOp funcOp, OpAdaptor adaptor,
73930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
74930c74f1SLei Zhang 
75930c74f1SLei Zhang private:
76930c74f1SLei Zhang   SmallVector<int32_t, 3> workGroupSizeAsInt32;
77930c74f1SLei Zhang };
78930c74f1SLei Zhang 
79930c74f1SLei Zhang /// Pattern to convert a gpu.module to a spv.module.
807c3ae48fSLei Zhang class GPUModuleConversion final : public OpConversionPattern<gpu::GPUModuleOp> {
81930c74f1SLei Zhang public:
827c3ae48fSLei Zhang   using OpConversionPattern<gpu::GPUModuleOp>::OpConversionPattern;
83930c74f1SLei Zhang 
84930c74f1SLei Zhang   LogicalResult
85b54c724bSRiver Riddle   matchAndRewrite(gpu::GPUModuleOp moduleOp, OpAdaptor adaptor,
86930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
87930c74f1SLei Zhang };
88930c74f1SLei Zhang 
8956f60a1cSLei Zhang class GPUModuleEndConversion final
9056f60a1cSLei Zhang     : public OpConversionPattern<gpu::ModuleEndOp> {
9156f60a1cSLei Zhang public:
9256f60a1cSLei Zhang   using OpConversionPattern::OpConversionPattern;
9356f60a1cSLei Zhang 
9456f60a1cSLei Zhang   LogicalResult
matchAndRewrite(gpu::ModuleEndOp endOp,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const95b54c724bSRiver Riddle   matchAndRewrite(gpu::ModuleEndOp endOp, OpAdaptor adaptor,
9656f60a1cSLei Zhang                   ConversionPatternRewriter &rewriter) const override {
9756f60a1cSLei Zhang     rewriter.eraseOp(endOp);
9856f60a1cSLei Zhang     return success();
9956f60a1cSLei Zhang   }
10056f60a1cSLei Zhang };
10156f60a1cSLei Zhang 
102930c74f1SLei Zhang /// Pattern to convert a gpu.return into a SPIR-V return.
103930c74f1SLei Zhang // TODO: This can go to DRR when GPU return has operands.
1047c3ae48fSLei Zhang class GPUReturnOpConversion final : public OpConversionPattern<gpu::ReturnOp> {
105930c74f1SLei Zhang public:
1067c3ae48fSLei Zhang   using OpConversionPattern<gpu::ReturnOp>::OpConversionPattern;
107930c74f1SLei Zhang 
108930c74f1SLei Zhang   LogicalResult
109b54c724bSRiver Riddle   matchAndRewrite(gpu::ReturnOp returnOp, OpAdaptor adaptor,
110930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override;
111930c74f1SLei Zhang };
112930c74f1SLei Zhang 
113c809c9bdSLei Zhang /// Pattern to convert a gpu.barrier op into a spv.ControlBarrier op.
114c809c9bdSLei Zhang class GPUBarrierConversion final : public OpConversionPattern<gpu::BarrierOp> {
115c809c9bdSLei Zhang public:
116c809c9bdSLei Zhang   using OpConversionPattern::OpConversionPattern;
117c809c9bdSLei Zhang 
118c809c9bdSLei Zhang   LogicalResult
119c809c9bdSLei Zhang   matchAndRewrite(gpu::BarrierOp barrierOp, OpAdaptor adaptor,
120c809c9bdSLei Zhang                   ConversionPatternRewriter &rewriter) const override;
121c809c9bdSLei Zhang };
122c809c9bdSLei Zhang 
123930c74f1SLei Zhang } // namespace
124930c74f1SLei Zhang 
125930c74f1SLei Zhang //===----------------------------------------------------------------------===//
126930c74f1SLei Zhang // Builtins.
127930c74f1SLei Zhang //===----------------------------------------------------------------------===//
128930c74f1SLei Zhang 
129930c74f1SLei Zhang template <typename SourceOp, spirv::BuiltIn builtin>
matchAndRewrite(SourceOp op,typename SourceOp::Adaptor adaptor,ConversionPatternRewriter & rewriter) const130930c74f1SLei Zhang LogicalResult LaunchConfigConversion<SourceOp, builtin>::matchAndRewrite(
131b54c724bSRiver Riddle     SourceOp op, typename SourceOp::Adaptor adaptor,
132930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
1331e35a769SButygin   auto *typeConverter = this->template getTypeConverter<SPIRVTypeConverter>();
1341e35a769SButygin   auto indexType = typeConverter->getIndexType();
1351e35a769SButygin 
136930c74f1SLei Zhang   // SPIR-V invocation builtin variables are a vector of type <3xi32>
1371e35a769SButygin   auto spirvBuiltin =
1381e35a769SButygin       spirv::getBuiltinVariableValue(op, builtin, indexType, rewriter);
139930c74f1SLei Zhang   rewriter.replaceOpWithNewOp<spirv::CompositeExtractOp>(
1401e35a769SButygin       op, indexType, spirvBuiltin,
141aae51255SMogball       rewriter.getI32ArrayAttr({static_cast<int32_t>(op.dimension())}));
142930c74f1SLei Zhang   return success();
143930c74f1SLei Zhang }
144930c74f1SLei Zhang 
145930c74f1SLei Zhang template <typename SourceOp, spirv::BuiltIn builtin>
146930c74f1SLei Zhang LogicalResult
matchAndRewrite(SourceOp op,typename SourceOp::Adaptor adaptor,ConversionPatternRewriter & rewriter) const147930c74f1SLei Zhang SingleDimLaunchConfigConversion<SourceOp, builtin>::matchAndRewrite(
148b54c724bSRiver Riddle     SourceOp op, typename SourceOp::Adaptor adaptor,
149930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
1501e35a769SButygin   auto *typeConverter = this->template getTypeConverter<SPIRVTypeConverter>();
1511e35a769SButygin   auto indexType = typeConverter->getIndexType();
1521e35a769SButygin 
1531e35a769SButygin   auto spirvBuiltin =
1541e35a769SButygin       spirv::getBuiltinVariableValue(op, builtin, indexType, rewriter);
155930c74f1SLei Zhang   rewriter.replaceOp(op, spirvBuiltin);
156930c74f1SLei Zhang   return success();
157930c74f1SLei Zhang }
158930c74f1SLei Zhang 
matchAndRewrite(gpu::BlockDimOp op,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const159930c74f1SLei Zhang LogicalResult WorkGroupSizeConversion::matchAndRewrite(
160b54c724bSRiver Riddle     gpu::BlockDimOp op, OpAdaptor adaptor,
161930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
162930c74f1SLei Zhang   auto workGroupSizeAttr = spirv::lookupLocalWorkGroupSize(op);
1634df95441SIvan Butygin   if (!workGroupSizeAttr)
1644df95441SIvan Butygin     return failure();
1654df95441SIvan Butygin 
166aae51255SMogball   auto val = workGroupSizeAttr
167aae51255SMogball                  .getValues<int32_t>()[static_cast<int32_t>(op.dimension())];
1687c3ae48fSLei Zhang   auto convertedType =
1697c3ae48fSLei Zhang       getTypeConverter()->convertType(op.getResult().getType());
170930c74f1SLei Zhang   if (!convertedType)
171930c74f1SLei Zhang     return failure();
172930c74f1SLei Zhang   rewriter.replaceOpWithNewOp<spirv::ConstantOp>(
173930c74f1SLei Zhang       op, convertedType, IntegerAttr::get(convertedType, val));
174930c74f1SLei Zhang   return success();
175930c74f1SLei Zhang }
176930c74f1SLei Zhang 
177930c74f1SLei Zhang //===----------------------------------------------------------------------===//
178930c74f1SLei Zhang // GPUFuncOp
179930c74f1SLei Zhang //===----------------------------------------------------------------------===//
180930c74f1SLei Zhang 
181930c74f1SLei Zhang // Legalizes a GPU function as an entry SPIR-V function.
182930c74f1SLei Zhang static spirv::FuncOp
lowerAsEntryFunction(gpu::GPUFuncOp funcOp,TypeConverter & typeConverter,ConversionPatternRewriter & rewriter,spirv::EntryPointABIAttr entryPointInfo,ArrayRef<spirv::InterfaceVarABIAttr> argABIInfo)1837c3ae48fSLei Zhang lowerAsEntryFunction(gpu::GPUFuncOp funcOp, TypeConverter &typeConverter,
184930c74f1SLei Zhang                      ConversionPatternRewriter &rewriter,
185930c74f1SLei Zhang                      spirv::EntryPointABIAttr entryPointInfo,
186930c74f1SLei Zhang                      ArrayRef<spirv::InterfaceVarABIAttr> argABIInfo) {
1874a3460a7SRiver Riddle   auto fnType = funcOp.getFunctionType();
188930c74f1SLei Zhang   if (fnType.getNumResults()) {
189930c74f1SLei Zhang     funcOp.emitError("SPIR-V lowering only supports entry functions"
190930c74f1SLei Zhang                      "with no return values right now");
191930c74f1SLei Zhang     return nullptr;
192930c74f1SLei Zhang   }
193930c74f1SLei Zhang   if (!argABIInfo.empty() && fnType.getNumInputs() != argABIInfo.size()) {
194930c74f1SLei Zhang     funcOp.emitError(
195930c74f1SLei Zhang         "lowering as entry functions requires ABI info for all arguments "
196930c74f1SLei Zhang         "or none of them");
197930c74f1SLei Zhang     return nullptr;
198930c74f1SLei Zhang   }
199930c74f1SLei Zhang   // Update the signature to valid SPIR-V types and add the ABI
200930c74f1SLei Zhang   // attributes. These will be "materialized" by using the
201930c74f1SLei Zhang   // LowerABIAttributesPass.
202930c74f1SLei Zhang   TypeConverter::SignatureConversion signatureConverter(fnType.getNumInputs());
203930c74f1SLei Zhang   {
2044a3460a7SRiver Riddle     for (const auto &argType :
2054a3460a7SRiver Riddle          enumerate(funcOp.getFunctionType().getInputs())) {
206930c74f1SLei Zhang       auto convertedType = typeConverter.convertType(argType.value());
207930c74f1SLei Zhang       signatureConverter.addInputs(argType.index(), convertedType);
208930c74f1SLei Zhang     }
209930c74f1SLei Zhang   }
210930c74f1SLei Zhang   auto newFuncOp = rewriter.create<spirv::FuncOp>(
211930c74f1SLei Zhang       funcOp.getLoc(), funcOp.getName(),
212930c74f1SLei Zhang       rewriter.getFunctionType(signatureConverter.getConvertedTypes(),
213930c74f1SLei Zhang                                llvm::None));
21456774bddSMarius Brehler   for (const auto &namedAttr : funcOp->getAttrs()) {
2157ceffae1SRiver Riddle     if (namedAttr.getName() == FunctionOpInterface::getTypeAttrName() ||
2160c7890c8SRiver Riddle         namedAttr.getName() == SymbolTable::getSymbolAttrName())
217930c74f1SLei Zhang       continue;
2180c7890c8SRiver Riddle     newFuncOp->setAttr(namedAttr.getName(), namedAttr.getValue());
219930c74f1SLei Zhang   }
220930c74f1SLei Zhang 
221930c74f1SLei Zhang   rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
222930c74f1SLei Zhang                               newFuncOp.end());
223930c74f1SLei Zhang   if (failed(rewriter.convertRegionTypes(&newFuncOp.getBody(), typeConverter,
224930c74f1SLei Zhang                                          &signatureConverter)))
225930c74f1SLei Zhang     return nullptr;
226930c74f1SLei Zhang   rewriter.eraseOp(funcOp);
227930c74f1SLei Zhang 
2286dd07fa5SLei Zhang   // Set the attributes for argument and the function.
2296dd07fa5SLei Zhang   StringRef argABIAttrName = spirv::getInterfaceVarABIAttrName();
2306dd07fa5SLei Zhang   for (auto argIndex : llvm::seq<unsigned>(0, argABIInfo.size())) {
2316dd07fa5SLei Zhang     newFuncOp.setArgAttr(argIndex, argABIAttrName, argABIInfo[argIndex]);
2326dd07fa5SLei Zhang   }
2336dd07fa5SLei Zhang   newFuncOp->setAttr(spirv::getEntryPointABIAttrName(), entryPointInfo);
2346dd07fa5SLei Zhang 
235930c74f1SLei Zhang   return newFuncOp;
236930c74f1SLei Zhang }
237930c74f1SLei Zhang 
238930c74f1SLei Zhang /// Populates `argABI` with spv.interface_var_abi attributes for lowering
239930c74f1SLei Zhang /// gpu.func to spv.func if no arguments have the attributes set
240930c74f1SLei Zhang /// already. Returns failure if any argument has the ABI attribute set already.
241930c74f1SLei Zhang static LogicalResult
getDefaultABIAttrs(MLIRContext * context,gpu::GPUFuncOp funcOp,SmallVectorImpl<spirv::InterfaceVarABIAttr> & argABI)242930c74f1SLei Zhang getDefaultABIAttrs(MLIRContext *context, gpu::GPUFuncOp funcOp,
243930c74f1SLei Zhang                    SmallVectorImpl<spirv::InterfaceVarABIAttr> &argABI) {
244930c74f1SLei Zhang   spirv::TargetEnvAttr targetEnv = spirv::lookupTargetEnvOrDefault(funcOp);
245930c74f1SLei Zhang   if (!spirv::needsInterfaceVarABIAttrs(targetEnv))
246930c74f1SLei Zhang     return success();
247930c74f1SLei Zhang 
248930c74f1SLei Zhang   for (auto argIndex : llvm::seq<unsigned>(0, funcOp.getNumArguments())) {
249930c74f1SLei Zhang     if (funcOp.getArgAttrOfType<spirv::InterfaceVarABIAttr>(
250930c74f1SLei Zhang             argIndex, spirv::getInterfaceVarABIAttrName()))
251930c74f1SLei Zhang       return failure();
252930c74f1SLei Zhang     // Vulkan's interface variable requirements needs scalars to be wrapped in a
253930c74f1SLei Zhang     // struct. The struct held in storage buffer.
254930c74f1SLei Zhang     Optional<spirv::StorageClass> sc;
255930c74f1SLei Zhang     if (funcOp.getArgument(argIndex).getType().isIntOrIndexOrFloat())
256930c74f1SLei Zhang       sc = spirv::StorageClass::StorageBuffer;
257930c74f1SLei Zhang     argABI.push_back(spirv::getInterfaceVarABIAttr(0, argIndex, sc, context));
258930c74f1SLei Zhang   }
259930c74f1SLei Zhang   return success();
260930c74f1SLei Zhang }
261930c74f1SLei Zhang 
matchAndRewrite(gpu::GPUFuncOp funcOp,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const262930c74f1SLei Zhang LogicalResult GPUFuncOpConversion::matchAndRewrite(
263b54c724bSRiver Riddle     gpu::GPUFuncOp funcOp, OpAdaptor adaptor,
264930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
265930c74f1SLei Zhang   if (!gpu::GPUDialect::isKernel(funcOp))
266930c74f1SLei Zhang     return failure();
267930c74f1SLei Zhang 
268930c74f1SLei Zhang   SmallVector<spirv::InterfaceVarABIAttr, 4> argABI;
269930c74f1SLei Zhang   if (failed(getDefaultABIAttrs(rewriter.getContext(), funcOp, argABI))) {
270930c74f1SLei Zhang     argABI.clear();
271930c74f1SLei Zhang     for (auto argIndex : llvm::seq<unsigned>(0, funcOp.getNumArguments())) {
272930c74f1SLei Zhang       // If the ABI is already specified, use it.
273930c74f1SLei Zhang       auto abiAttr = funcOp.getArgAttrOfType<spirv::InterfaceVarABIAttr>(
274930c74f1SLei Zhang           argIndex, spirv::getInterfaceVarABIAttrName());
275930c74f1SLei Zhang       if (!abiAttr) {
276930c74f1SLei Zhang         funcOp.emitRemark(
277930c74f1SLei Zhang             "match failure: missing 'spv.interface_var_abi' attribute at "
278930c74f1SLei Zhang             "argument ")
279930c74f1SLei Zhang             << argIndex;
280930c74f1SLei Zhang         return failure();
281930c74f1SLei Zhang       }
282930c74f1SLei Zhang       argABI.push_back(abiAttr);
283930c74f1SLei Zhang     }
284930c74f1SLei Zhang   }
285930c74f1SLei Zhang 
286930c74f1SLei Zhang   auto entryPointAttr = spirv::lookupEntryPointABI(funcOp);
287930c74f1SLei Zhang   if (!entryPointAttr) {
288930c74f1SLei Zhang     funcOp.emitRemark("match failure: missing 'spv.entry_point_abi' attribute");
289930c74f1SLei Zhang     return failure();
290930c74f1SLei Zhang   }
291930c74f1SLei Zhang   spirv::FuncOp newFuncOp = lowerAsEntryFunction(
2927c3ae48fSLei Zhang       funcOp, *getTypeConverter(), rewriter, entryPointAttr, argABI);
293930c74f1SLei Zhang   if (!newFuncOp)
294930c74f1SLei Zhang     return failure();
295195730a6SRiver Riddle   newFuncOp->removeAttr(
296195730a6SRiver Riddle       rewriter.getStringAttr(gpu::GPUDialect::getKernelFuncAttrName()));
297930c74f1SLei Zhang   return success();
298930c74f1SLei Zhang }
299930c74f1SLei Zhang 
300930c74f1SLei Zhang //===----------------------------------------------------------------------===//
301930c74f1SLei Zhang // ModuleOp with gpu.module.
302930c74f1SLei Zhang //===----------------------------------------------------------------------===//
303930c74f1SLei Zhang 
matchAndRewrite(gpu::GPUModuleOp moduleOp,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const304930c74f1SLei Zhang LogicalResult GPUModuleConversion::matchAndRewrite(
305b54c724bSRiver Riddle     gpu::GPUModuleOp moduleOp, OpAdaptor adaptor,
306930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
307930c74f1SLei Zhang   spirv::TargetEnvAttr targetEnv = spirv::lookupTargetEnvOrDefault(moduleOp);
308930c74f1SLei Zhang   spirv::AddressingModel addressingModel = spirv::getAddressingModel(targetEnv);
309930c74f1SLei Zhang   FailureOr<spirv::MemoryModel> memoryModel = spirv::getMemoryModel(targetEnv);
310930c74f1SLei Zhang   if (failed(memoryModel))
311930c74f1SLei Zhang     return moduleOp.emitRemark("match failure: could not selected memory model "
312930c74f1SLei Zhang                                "based on 'spv.target_env'");
313930c74f1SLei Zhang 
314930c74f1SLei Zhang   // Add a keyword to the module name to avoid symbolic conflict.
315930c74f1SLei Zhang   std::string spvModuleName = (kSPIRVModule + moduleOp.getName()).str();
316930c74f1SLei Zhang   auto spvModule = rewriter.create<spirv::ModuleOp>(
317*6d5fc1e3SKazu Hirata       moduleOp.getLoc(), addressingModel, *memoryModel, llvm::None,
318930c74f1SLei Zhang       StringRef(spvModuleName));
319930c74f1SLei Zhang 
320930c74f1SLei Zhang   // Move the region from the module op into the SPIR-V module.
32156f60a1cSLei Zhang   Region &spvModuleRegion = spvModule.getRegion();
322930c74f1SLei Zhang   rewriter.inlineRegionBefore(moduleOp.body(), spvModuleRegion,
323930c74f1SLei Zhang                               spvModuleRegion.begin());
32456f60a1cSLei Zhang   // The spv.module build method adds a block. Remove that.
325930c74f1SLei Zhang   rewriter.eraseBlock(&spvModuleRegion.back());
326930c74f1SLei Zhang   rewriter.eraseOp(moduleOp);
327930c74f1SLei Zhang   return success();
328930c74f1SLei Zhang }
329930c74f1SLei Zhang 
330930c74f1SLei Zhang //===----------------------------------------------------------------------===//
331930c74f1SLei Zhang // GPU return inside kernel functions to SPIR-V return.
332930c74f1SLei Zhang //===----------------------------------------------------------------------===//
333930c74f1SLei Zhang 
matchAndRewrite(gpu::ReturnOp returnOp,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const334930c74f1SLei Zhang LogicalResult GPUReturnOpConversion::matchAndRewrite(
335b54c724bSRiver Riddle     gpu::ReturnOp returnOp, OpAdaptor adaptor,
336930c74f1SLei Zhang     ConversionPatternRewriter &rewriter) const {
337b54c724bSRiver Riddle   if (!adaptor.getOperands().empty())
338930c74f1SLei Zhang     return failure();
339930c74f1SLei Zhang 
340930c74f1SLei Zhang   rewriter.replaceOpWithNewOp<spirv::ReturnOp>(returnOp);
341930c74f1SLei Zhang   return success();
342930c74f1SLei Zhang }
343930c74f1SLei Zhang 
344930c74f1SLei Zhang //===----------------------------------------------------------------------===//
345c809c9bdSLei Zhang // Barrier.
346c809c9bdSLei Zhang //===----------------------------------------------------------------------===//
347c809c9bdSLei Zhang 
matchAndRewrite(gpu::BarrierOp barrierOp,OpAdaptor adaptor,ConversionPatternRewriter & rewriter) const348c809c9bdSLei Zhang LogicalResult GPUBarrierConversion::matchAndRewrite(
349c809c9bdSLei Zhang     gpu::BarrierOp barrierOp, OpAdaptor adaptor,
350c809c9bdSLei Zhang     ConversionPatternRewriter &rewriter) const {
351c809c9bdSLei Zhang   MLIRContext *context = getContext();
352c809c9bdSLei Zhang   // Both execution and memory scope should be workgroup.
353c809c9bdSLei Zhang   auto scope = spirv::ScopeAttr::get(context, spirv::Scope::Workgroup);
354c809c9bdSLei Zhang   // Require acquire and release memory semantics for workgroup memory.
355c809c9bdSLei Zhang   auto memorySemantics = spirv::MemorySemanticsAttr::get(
356c809c9bdSLei Zhang       context, spirv::MemorySemantics::WorkgroupMemory |
357c809c9bdSLei Zhang                    spirv::MemorySemantics::AcquireRelease);
358c809c9bdSLei Zhang   rewriter.replaceOpWithNewOp<spirv::ControlBarrierOp>(barrierOp, scope, scope,
359c809c9bdSLei Zhang                                                        memorySemantics);
360c809c9bdSLei Zhang   return success();
361c809c9bdSLei Zhang }
362c809c9bdSLei Zhang 
363c809c9bdSLei Zhang //===----------------------------------------------------------------------===//
364930c74f1SLei Zhang // GPU To SPIRV Patterns.
365930c74f1SLei Zhang //===----------------------------------------------------------------------===//
366930c74f1SLei Zhang 
populateGPUToSPIRVPatterns(SPIRVTypeConverter & typeConverter,RewritePatternSet & patterns)3673a506b31SChris Lattner void mlir::populateGPUToSPIRVPatterns(SPIRVTypeConverter &typeConverter,
368dc4e913bSChris Lattner                                       RewritePatternSet &patterns) {
369dc4e913bSChris Lattner   patterns.add<
370c809c9bdSLei Zhang       GPUBarrierConversion, GPUFuncOpConversion, GPUModuleConversion,
371c809c9bdSLei Zhang       GPUModuleEndConversion, GPUReturnOpConversion,
372930c74f1SLei Zhang       LaunchConfigConversion<gpu::BlockIdOp, spirv::BuiltIn::WorkgroupId>,
373930c74f1SLei Zhang       LaunchConfigConversion<gpu::GridDimOp, spirv::BuiltIn::NumWorkgroups>,
3744df95441SIvan Butygin       LaunchConfigConversion<gpu::BlockDimOp, spirv::BuiltIn::WorkgroupSize>,
375930c74f1SLei Zhang       LaunchConfigConversion<gpu::ThreadIdOp,
376930c74f1SLei Zhang                              spirv::BuiltIn::LocalInvocationId>,
3779f864a54SIvan Butygin       LaunchConfigConversion<gpu::GlobalIdOp,
3789f864a54SIvan Butygin                              spirv::BuiltIn::GlobalInvocationId>,
379930c74f1SLei Zhang       SingleDimLaunchConfigConversion<gpu::SubgroupIdOp,
380930c74f1SLei Zhang                                       spirv::BuiltIn::SubgroupId>,
381930c74f1SLei Zhang       SingleDimLaunchConfigConversion<gpu::NumSubgroupsOp,
382930c74f1SLei Zhang                                       spirv::BuiltIn::NumSubgroups>,
383930c74f1SLei Zhang       SingleDimLaunchConfigConversion<gpu::SubgroupSizeOp,
384930c74f1SLei Zhang                                       spirv::BuiltIn::SubgroupSize>,
3851d909c9aSChris Lattner       WorkGroupSizeConversion>(typeConverter, patterns.getContext());
386930c74f1SLei Zhang }
387