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