1*930c74f1SLei Zhang //===- SPIRVToLLVM.cpp - SPIR-V to LLVM Patterns --------------------------===//
2*930c74f1SLei Zhang //
3*930c74f1SLei Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*930c74f1SLei Zhang // See https://llvm.org/LICENSE.txt for license information.
5*930c74f1SLei Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*930c74f1SLei Zhang //
7*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
8*930c74f1SLei Zhang //
9*930c74f1SLei Zhang // This file implements patterns to convert SPIR-V dialect to LLVM dialect.
10*930c74f1SLei Zhang //
11*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
12*930c74f1SLei Zhang 
13*930c74f1SLei Zhang #include "mlir/Conversion/SPIRVToLLVM/SPIRVToLLVM.h"
14*930c74f1SLei Zhang #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
15*930c74f1SLei Zhang #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
16*930c74f1SLei Zhang #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
17*930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
18*930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
19*930c74f1SLei Zhang #include "mlir/Dialect/SPIRV/Utils/LayoutUtils.h"
20*930c74f1SLei Zhang #include "mlir/Dialect/StandardOps/IR/Ops.h"
21*930c74f1SLei Zhang #include "mlir/IR/BuiltinOps.h"
22*930c74f1SLei Zhang #include "mlir/IR/PatternMatch.h"
23*930c74f1SLei Zhang #include "mlir/Support/LogicalResult.h"
24*930c74f1SLei Zhang #include "mlir/Transforms/DialectConversion.h"
25*930c74f1SLei Zhang #include "llvm/Support/Debug.h"
26*930c74f1SLei Zhang #include "llvm/Support/FormatVariadic.h"
27*930c74f1SLei Zhang 
28*930c74f1SLei Zhang #define DEBUG_TYPE "spirv-to-llvm-pattern"
29*930c74f1SLei Zhang 
30*930c74f1SLei Zhang using namespace mlir;
31*930c74f1SLei Zhang 
32*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
33*930c74f1SLei Zhang // Utility functions
34*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
35*930c74f1SLei Zhang 
36*930c74f1SLei Zhang /// Returns true if the given type is a signed integer or vector type.
37*930c74f1SLei Zhang static bool isSignedIntegerOrVector(Type type) {
38*930c74f1SLei Zhang   if (type.isSignedInteger())
39*930c74f1SLei Zhang     return true;
40*930c74f1SLei Zhang   if (auto vecType = type.dyn_cast<VectorType>())
41*930c74f1SLei Zhang     return vecType.getElementType().isSignedInteger();
42*930c74f1SLei Zhang   return false;
43*930c74f1SLei Zhang }
44*930c74f1SLei Zhang 
45*930c74f1SLei Zhang /// Returns true if the given type is an unsigned integer or vector type
46*930c74f1SLei Zhang static bool isUnsignedIntegerOrVector(Type type) {
47*930c74f1SLei Zhang   if (type.isUnsignedInteger())
48*930c74f1SLei Zhang     return true;
49*930c74f1SLei Zhang   if (auto vecType = type.dyn_cast<VectorType>())
50*930c74f1SLei Zhang     return vecType.getElementType().isUnsignedInteger();
51*930c74f1SLei Zhang   return false;
52*930c74f1SLei Zhang }
53*930c74f1SLei Zhang 
54*930c74f1SLei Zhang /// Returns the bit width of integer, float or vector of float or integer values
55*930c74f1SLei Zhang static unsigned getBitWidth(Type type) {
56*930c74f1SLei Zhang   assert((type.isIntOrFloat() || type.isa<VectorType>()) &&
57*930c74f1SLei Zhang          "bitwidth is not supported for this type");
58*930c74f1SLei Zhang   if (type.isIntOrFloat())
59*930c74f1SLei Zhang     return type.getIntOrFloatBitWidth();
60*930c74f1SLei Zhang   auto vecType = type.dyn_cast<VectorType>();
61*930c74f1SLei Zhang   auto elementType = vecType.getElementType();
62*930c74f1SLei Zhang   assert(elementType.isIntOrFloat() &&
63*930c74f1SLei Zhang          "only integers and floats have a bitwidth");
64*930c74f1SLei Zhang   return elementType.getIntOrFloatBitWidth();
65*930c74f1SLei Zhang }
66*930c74f1SLei Zhang 
67*930c74f1SLei Zhang /// Returns the bit width of LLVMType integer or vector.
68*930c74f1SLei Zhang static unsigned getLLVMTypeBitWidth(LLVM::LLVMType type) {
69*930c74f1SLei Zhang   auto vectorType = type.dyn_cast<LLVM::LLVMVectorType>();
70*930c74f1SLei Zhang   return (vectorType ? vectorType.getElementType() : type)
71*930c74f1SLei Zhang       .cast<LLVM::LLVMIntegerType>()
72*930c74f1SLei Zhang       .getBitWidth();
73*930c74f1SLei Zhang }
74*930c74f1SLei Zhang 
75*930c74f1SLei Zhang /// Creates `IntegerAttribute` with all bits set for given type
76*930c74f1SLei Zhang static IntegerAttr minusOneIntegerAttribute(Type type, Builder builder) {
77*930c74f1SLei Zhang   if (auto vecType = type.dyn_cast<VectorType>()) {
78*930c74f1SLei Zhang     auto integerType = vecType.getElementType().cast<IntegerType>();
79*930c74f1SLei Zhang     return builder.getIntegerAttr(integerType, -1);
80*930c74f1SLei Zhang   }
81*930c74f1SLei Zhang   auto integerType = type.cast<IntegerType>();
82*930c74f1SLei Zhang   return builder.getIntegerAttr(integerType, -1);
83*930c74f1SLei Zhang }
84*930c74f1SLei Zhang 
85*930c74f1SLei Zhang /// Creates `llvm.mlir.constant` with all bits set for the given type.
86*930c74f1SLei Zhang static Value createConstantAllBitsSet(Location loc, Type srcType, Type dstType,
87*930c74f1SLei Zhang                                       PatternRewriter &rewriter) {
88*930c74f1SLei Zhang   if (srcType.isa<VectorType>()) {
89*930c74f1SLei Zhang     return rewriter.create<LLVM::ConstantOp>(
90*930c74f1SLei Zhang         loc, dstType,
91*930c74f1SLei Zhang         SplatElementsAttr::get(srcType.cast<ShapedType>(),
92*930c74f1SLei Zhang                                minusOneIntegerAttribute(srcType, rewriter)));
93*930c74f1SLei Zhang   }
94*930c74f1SLei Zhang   return rewriter.create<LLVM::ConstantOp>(
95*930c74f1SLei Zhang       loc, dstType, minusOneIntegerAttribute(srcType, rewriter));
96*930c74f1SLei Zhang }
97*930c74f1SLei Zhang 
98*930c74f1SLei Zhang /// Creates `llvm.mlir.constant` with a floating-point scalar or vector value.
99*930c74f1SLei Zhang static Value createFPConstant(Location loc, Type srcType, Type dstType,
100*930c74f1SLei Zhang                               PatternRewriter &rewriter, double value) {
101*930c74f1SLei Zhang   if (auto vecType = srcType.dyn_cast<VectorType>()) {
102*930c74f1SLei Zhang     auto floatType = vecType.getElementType().cast<FloatType>();
103*930c74f1SLei Zhang     return rewriter.create<LLVM::ConstantOp>(
104*930c74f1SLei Zhang         loc, dstType,
105*930c74f1SLei Zhang         SplatElementsAttr::get(vecType,
106*930c74f1SLei Zhang                                rewriter.getFloatAttr(floatType, value)));
107*930c74f1SLei Zhang   }
108*930c74f1SLei Zhang   auto floatType = srcType.cast<FloatType>();
109*930c74f1SLei Zhang   return rewriter.create<LLVM::ConstantOp>(
110*930c74f1SLei Zhang       loc, dstType, rewriter.getFloatAttr(floatType, value));
111*930c74f1SLei Zhang }
112*930c74f1SLei Zhang 
113*930c74f1SLei Zhang /// Utility function for bitfield ops:
114*930c74f1SLei Zhang ///   - `BitFieldInsert`
115*930c74f1SLei Zhang ///   - `BitFieldSExtract`
116*930c74f1SLei Zhang ///   - `BitFieldUExtract`
117*930c74f1SLei Zhang /// Truncates or extends the value. If the bitwidth of the value is the same as
118*930c74f1SLei Zhang /// `dstType` bitwidth, the value remains unchanged.
119*930c74f1SLei Zhang static Value optionallyTruncateOrExtend(Location loc, Value value, Type dstType,
120*930c74f1SLei Zhang                                         PatternRewriter &rewriter) {
121*930c74f1SLei Zhang   auto srcType = value.getType();
122*930c74f1SLei Zhang   auto llvmType = dstType.cast<LLVM::LLVMType>();
123*930c74f1SLei Zhang   unsigned targetBitWidth = getLLVMTypeBitWidth(llvmType);
124*930c74f1SLei Zhang   unsigned valueBitWidth =
125*930c74f1SLei Zhang       srcType.isa<LLVM::LLVMType>()
126*930c74f1SLei Zhang           ? getLLVMTypeBitWidth(srcType.cast<LLVM::LLVMType>())
127*930c74f1SLei Zhang           : getBitWidth(srcType);
128*930c74f1SLei Zhang 
129*930c74f1SLei Zhang   if (valueBitWidth < targetBitWidth)
130*930c74f1SLei Zhang     return rewriter.create<LLVM::ZExtOp>(loc, llvmType, value);
131*930c74f1SLei Zhang   // If the bit widths of `Count` and `Offset` are greater than the bit width
132*930c74f1SLei Zhang   // of the target type, they are truncated. Truncation is safe since `Count`
133*930c74f1SLei Zhang   // and `Offset` must be no more than 64 for op behaviour to be defined. Hence,
134*930c74f1SLei Zhang   // both values can be expressed in 8 bits.
135*930c74f1SLei Zhang   if (valueBitWidth > targetBitWidth)
136*930c74f1SLei Zhang     return rewriter.create<LLVM::TruncOp>(loc, llvmType, value);
137*930c74f1SLei Zhang   return value;
138*930c74f1SLei Zhang }
139*930c74f1SLei Zhang 
140*930c74f1SLei Zhang /// Broadcasts the value to vector with `numElements` number of elements.
141*930c74f1SLei Zhang static Value broadcast(Location loc, Value toBroadcast, unsigned numElements,
142*930c74f1SLei Zhang                        LLVMTypeConverter &typeConverter,
143*930c74f1SLei Zhang                        ConversionPatternRewriter &rewriter) {
144*930c74f1SLei Zhang   auto vectorType = VectorType::get(numElements, toBroadcast.getType());
145*930c74f1SLei Zhang   auto llvmVectorType = typeConverter.convertType(vectorType);
146*930c74f1SLei Zhang   auto llvmI32Type = typeConverter.convertType(rewriter.getIntegerType(32));
147*930c74f1SLei Zhang   Value broadcasted = rewriter.create<LLVM::UndefOp>(loc, llvmVectorType);
148*930c74f1SLei Zhang   for (unsigned i = 0; i < numElements; ++i) {
149*930c74f1SLei Zhang     auto index = rewriter.create<LLVM::ConstantOp>(
150*930c74f1SLei Zhang         loc, llvmI32Type, rewriter.getI32IntegerAttr(i));
151*930c74f1SLei Zhang     broadcasted = rewriter.create<LLVM::InsertElementOp>(
152*930c74f1SLei Zhang         loc, llvmVectorType, broadcasted, toBroadcast, index);
153*930c74f1SLei Zhang   }
154*930c74f1SLei Zhang   return broadcasted;
155*930c74f1SLei Zhang }
156*930c74f1SLei Zhang 
157*930c74f1SLei Zhang /// Broadcasts the value. If `srcType` is a scalar, the value remains unchanged.
158*930c74f1SLei Zhang static Value optionallyBroadcast(Location loc, Value value, Type srcType,
159*930c74f1SLei Zhang                                  LLVMTypeConverter &typeConverter,
160*930c74f1SLei Zhang                                  ConversionPatternRewriter &rewriter) {
161*930c74f1SLei Zhang   if (auto vectorType = srcType.dyn_cast<VectorType>()) {
162*930c74f1SLei Zhang     unsigned numElements = vectorType.getNumElements();
163*930c74f1SLei Zhang     return broadcast(loc, value, numElements, typeConverter, rewriter);
164*930c74f1SLei Zhang   }
165*930c74f1SLei Zhang   return value;
166*930c74f1SLei Zhang }
167*930c74f1SLei Zhang 
168*930c74f1SLei Zhang /// Utility function for bitfield ops: `BitFieldInsert`, `BitFieldSExtract` and
169*930c74f1SLei Zhang /// `BitFieldUExtract`.
170*930c74f1SLei Zhang /// Broadcast `Offset` and `Count` to match the type of `Base`. If `Base` is of
171*930c74f1SLei Zhang /// a vector type, construct a vector that has:
172*930c74f1SLei Zhang ///  - same number of elements as `Base`
173*930c74f1SLei Zhang ///  - each element has the type that is the same as the type of `Offset` or
174*930c74f1SLei Zhang ///    `Count`
175*930c74f1SLei Zhang ///  - each element has the same value as `Offset` or `Count`
176*930c74f1SLei Zhang /// Then cast `Offset` and `Count` if their bit width is different
177*930c74f1SLei Zhang /// from `Base` bit width.
178*930c74f1SLei Zhang static Value processCountOrOffset(Location loc, Value value, Type srcType,
179*930c74f1SLei Zhang                                   Type dstType, LLVMTypeConverter &converter,
180*930c74f1SLei Zhang                                   ConversionPatternRewriter &rewriter) {
181*930c74f1SLei Zhang   Value broadcasted =
182*930c74f1SLei Zhang       optionallyBroadcast(loc, value, srcType, converter, rewriter);
183*930c74f1SLei Zhang   return optionallyTruncateOrExtend(loc, broadcasted, dstType, rewriter);
184*930c74f1SLei Zhang }
185*930c74f1SLei Zhang 
186*930c74f1SLei Zhang /// Converts SPIR-V struct with a regular (according to `VulkanLayoutUtils`)
187*930c74f1SLei Zhang /// offset to LLVM struct. Otherwise, the conversion is not supported.
188*930c74f1SLei Zhang static Optional<Type>
189*930c74f1SLei Zhang convertStructTypeWithOffset(spirv::StructType type,
190*930c74f1SLei Zhang                             LLVMTypeConverter &converter) {
191*930c74f1SLei Zhang   if (type != VulkanLayoutUtils::decorateType(type))
192*930c74f1SLei Zhang     return llvm::None;
193*930c74f1SLei Zhang 
194*930c74f1SLei Zhang   auto elementsVector = llvm::to_vector<8>(
195*930c74f1SLei Zhang       llvm::map_range(type.getElementTypes(), [&](Type elementType) {
196*930c74f1SLei Zhang         return converter.convertType(elementType).cast<LLVM::LLVMType>();
197*930c74f1SLei Zhang       }));
198*930c74f1SLei Zhang   return LLVM::LLVMStructType::getLiteral(type.getContext(), elementsVector,
199*930c74f1SLei Zhang                                           /*isPacked=*/false);
200*930c74f1SLei Zhang }
201*930c74f1SLei Zhang 
202*930c74f1SLei Zhang /// Converts SPIR-V struct with no offset to packed LLVM struct.
203*930c74f1SLei Zhang static Type convertStructTypePacked(spirv::StructType type,
204*930c74f1SLei Zhang                                     LLVMTypeConverter &converter) {
205*930c74f1SLei Zhang   auto elementsVector = llvm::to_vector<8>(
206*930c74f1SLei Zhang       llvm::map_range(type.getElementTypes(), [&](Type elementType) {
207*930c74f1SLei Zhang         return converter.convertType(elementType).cast<LLVM::LLVMType>();
208*930c74f1SLei Zhang       }));
209*930c74f1SLei Zhang   return LLVM::LLVMStructType::getLiteral(type.getContext(), elementsVector,
210*930c74f1SLei Zhang                                           /*isPacked=*/true);
211*930c74f1SLei Zhang }
212*930c74f1SLei Zhang 
213*930c74f1SLei Zhang /// Creates LLVM dialect constant with the given value.
214*930c74f1SLei Zhang static Value createI32ConstantOf(Location loc, PatternRewriter &rewriter,
215*930c74f1SLei Zhang                                  unsigned value) {
216*930c74f1SLei Zhang   return rewriter.create<LLVM::ConstantOp>(
217*930c74f1SLei Zhang       loc, LLVM::LLVMIntegerType::get(rewriter.getContext(), 32),
218*930c74f1SLei Zhang       rewriter.getIntegerAttr(rewriter.getI32Type(), value));
219*930c74f1SLei Zhang }
220*930c74f1SLei Zhang 
221*930c74f1SLei Zhang /// Utility for `spv.Load` and `spv.Store` conversion.
222*930c74f1SLei Zhang static LogicalResult replaceWithLoadOrStore(Operation *op,
223*930c74f1SLei Zhang                                             ConversionPatternRewriter &rewriter,
224*930c74f1SLei Zhang                                             LLVMTypeConverter &typeConverter,
225*930c74f1SLei Zhang                                             unsigned alignment, bool isVolatile,
226*930c74f1SLei Zhang                                             bool isNonTemporal) {
227*930c74f1SLei Zhang   if (auto loadOp = dyn_cast<spirv::LoadOp>(op)) {
228*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(loadOp.getType());
229*930c74f1SLei Zhang     if (!dstType)
230*930c74f1SLei Zhang       return failure();
231*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::LoadOp>(
232*930c74f1SLei Zhang         loadOp, dstType, loadOp.ptr(), alignment, isVolatile, isNonTemporal);
233*930c74f1SLei Zhang     return success();
234*930c74f1SLei Zhang   }
235*930c74f1SLei Zhang   auto storeOp = cast<spirv::StoreOp>(op);
236*930c74f1SLei Zhang   rewriter.replaceOpWithNewOp<LLVM::StoreOp>(storeOp, storeOp.value(),
237*930c74f1SLei Zhang                                              storeOp.ptr(), alignment,
238*930c74f1SLei Zhang                                              isVolatile, isNonTemporal);
239*930c74f1SLei Zhang   return success();
240*930c74f1SLei Zhang }
241*930c74f1SLei Zhang 
242*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
243*930c74f1SLei Zhang // Type conversion
244*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
245*930c74f1SLei Zhang 
246*930c74f1SLei Zhang /// Converts SPIR-V array type to LLVM array. Natural stride (according to
247*930c74f1SLei Zhang /// `VulkanLayoutUtils`) is also mapped to LLVM array. This has to be respected
248*930c74f1SLei Zhang /// when converting ops that manipulate array types.
249*930c74f1SLei Zhang static Optional<Type> convertArrayType(spirv::ArrayType type,
250*930c74f1SLei Zhang                                        TypeConverter &converter) {
251*930c74f1SLei Zhang   unsigned stride = type.getArrayStride();
252*930c74f1SLei Zhang   Type elementType = type.getElementType();
253*930c74f1SLei Zhang   auto sizeInBytes = elementType.cast<spirv::SPIRVType>().getSizeInBytes();
254*930c74f1SLei Zhang   if (stride != 0 &&
255*930c74f1SLei Zhang       !(sizeInBytes.hasValue() && sizeInBytes.getValue() == stride))
256*930c74f1SLei Zhang     return llvm::None;
257*930c74f1SLei Zhang 
258*930c74f1SLei Zhang   auto llvmElementType =
259*930c74f1SLei Zhang       converter.convertType(elementType).cast<LLVM::LLVMType>();
260*930c74f1SLei Zhang   unsigned numElements = type.getNumElements();
261*930c74f1SLei Zhang   return LLVM::LLVMArrayType::get(llvmElementType, numElements);
262*930c74f1SLei Zhang }
263*930c74f1SLei Zhang 
264*930c74f1SLei Zhang /// Converts SPIR-V pointer type to LLVM pointer. Pointer's storage class is not
265*930c74f1SLei Zhang /// modelled at the moment.
266*930c74f1SLei Zhang static Type convertPointerType(spirv::PointerType type,
267*930c74f1SLei Zhang                                TypeConverter &converter) {
268*930c74f1SLei Zhang   auto pointeeType =
269*930c74f1SLei Zhang       converter.convertType(type.getPointeeType()).cast<LLVM::LLVMType>();
270*930c74f1SLei Zhang   return LLVM::LLVMPointerType::get(pointeeType);
271*930c74f1SLei Zhang }
272*930c74f1SLei Zhang 
273*930c74f1SLei Zhang /// Converts SPIR-V runtime array to LLVM array. Since LLVM allows indexing over
274*930c74f1SLei Zhang /// the bounds, the runtime array is converted to a 0-sized LLVM array. There is
275*930c74f1SLei Zhang /// no modelling of array stride at the moment.
276*930c74f1SLei Zhang static Optional<Type> convertRuntimeArrayType(spirv::RuntimeArrayType type,
277*930c74f1SLei Zhang                                               TypeConverter &converter) {
278*930c74f1SLei Zhang   if (type.getArrayStride() != 0)
279*930c74f1SLei Zhang     return llvm::None;
280*930c74f1SLei Zhang   auto elementType =
281*930c74f1SLei Zhang       converter.convertType(type.getElementType()).cast<LLVM::LLVMType>();
282*930c74f1SLei Zhang   return LLVM::LLVMArrayType::get(elementType, 0);
283*930c74f1SLei Zhang }
284*930c74f1SLei Zhang 
285*930c74f1SLei Zhang /// Converts SPIR-V struct to LLVM struct. There is no support of structs with
286*930c74f1SLei Zhang /// member decorations. Also, only natural offset is supported.
287*930c74f1SLei Zhang static Optional<Type> convertStructType(spirv::StructType type,
288*930c74f1SLei Zhang                                         LLVMTypeConverter &converter) {
289*930c74f1SLei Zhang   SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
290*930c74f1SLei Zhang   type.getMemberDecorations(memberDecorations);
291*930c74f1SLei Zhang   if (!memberDecorations.empty())
292*930c74f1SLei Zhang     return llvm::None;
293*930c74f1SLei Zhang   if (type.hasOffset())
294*930c74f1SLei Zhang     return convertStructTypeWithOffset(type, converter);
295*930c74f1SLei Zhang   return convertStructTypePacked(type, converter);
296*930c74f1SLei Zhang }
297*930c74f1SLei Zhang 
298*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
299*930c74f1SLei Zhang // Operation conversion
300*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
301*930c74f1SLei Zhang 
302*930c74f1SLei Zhang namespace {
303*930c74f1SLei Zhang 
304*930c74f1SLei Zhang class AccessChainPattern : public SPIRVToLLVMConversion<spirv::AccessChainOp> {
305*930c74f1SLei Zhang public:
306*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::AccessChainOp>::SPIRVToLLVMConversion;
307*930c74f1SLei Zhang 
308*930c74f1SLei Zhang   LogicalResult
309*930c74f1SLei Zhang   matchAndRewrite(spirv::AccessChainOp op, ArrayRef<Value> operands,
310*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
311*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(op.component_ptr().getType());
312*930c74f1SLei Zhang     if (!dstType)
313*930c74f1SLei Zhang       return failure();
314*930c74f1SLei Zhang     // To use GEP we need to add a first 0 index to go through the pointer.
315*930c74f1SLei Zhang     auto indices = llvm::to_vector<4>(op.indices());
316*930c74f1SLei Zhang     Type indexType = op.indices().front().getType();
317*930c74f1SLei Zhang     auto llvmIndexType = typeConverter.convertType(indexType);
318*930c74f1SLei Zhang     if (!llvmIndexType)
319*930c74f1SLei Zhang       return failure();
320*930c74f1SLei Zhang     Value zero = rewriter.create<LLVM::ConstantOp>(
321*930c74f1SLei Zhang         op.getLoc(), llvmIndexType, rewriter.getIntegerAttr(indexType, 0));
322*930c74f1SLei Zhang     indices.insert(indices.begin(), zero);
323*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::GEPOp>(op, dstType, op.base_ptr(),
324*930c74f1SLei Zhang                                              indices);
325*930c74f1SLei Zhang     return success();
326*930c74f1SLei Zhang   }
327*930c74f1SLei Zhang };
328*930c74f1SLei Zhang 
329*930c74f1SLei Zhang class AddressOfPattern : public SPIRVToLLVMConversion<spirv::AddressOfOp> {
330*930c74f1SLei Zhang public:
331*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::AddressOfOp>::SPIRVToLLVMConversion;
332*930c74f1SLei Zhang 
333*930c74f1SLei Zhang   LogicalResult
334*930c74f1SLei Zhang   matchAndRewrite(spirv::AddressOfOp op, ArrayRef<Value> operands,
335*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
336*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(op.pointer().getType());
337*930c74f1SLei Zhang     if (!dstType)
338*930c74f1SLei Zhang       return failure();
339*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::AddressOfOp>(
340*930c74f1SLei Zhang         op, dstType.cast<LLVM::LLVMType>(), op.variable());
341*930c74f1SLei Zhang     return success();
342*930c74f1SLei Zhang   }
343*930c74f1SLei Zhang };
344*930c74f1SLei Zhang 
345*930c74f1SLei Zhang class BitFieldInsertPattern
346*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::BitFieldInsertOp> {
347*930c74f1SLei Zhang public:
348*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::BitFieldInsertOp>::SPIRVToLLVMConversion;
349*930c74f1SLei Zhang 
350*930c74f1SLei Zhang   LogicalResult
351*930c74f1SLei Zhang   matchAndRewrite(spirv::BitFieldInsertOp op, ArrayRef<Value> operands,
352*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
353*930c74f1SLei Zhang     auto srcType = op.getType();
354*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
355*930c74f1SLei Zhang     if (!dstType)
356*930c74f1SLei Zhang       return failure();
357*930c74f1SLei Zhang     Location loc = op.getLoc();
358*930c74f1SLei Zhang 
359*930c74f1SLei Zhang     // Process `Offset` and `Count`: broadcast and extend/truncate if needed.
360*930c74f1SLei Zhang     Value offset = processCountOrOffset(loc, op.offset(), srcType, dstType,
361*930c74f1SLei Zhang                                         typeConverter, rewriter);
362*930c74f1SLei Zhang     Value count = processCountOrOffset(loc, op.count(), srcType, dstType,
363*930c74f1SLei Zhang                                        typeConverter, rewriter);
364*930c74f1SLei Zhang 
365*930c74f1SLei Zhang     // Create a mask with bits set outside [Offset, Offset + Count - 1].
366*930c74f1SLei Zhang     Value minusOne = createConstantAllBitsSet(loc, srcType, dstType, rewriter);
367*930c74f1SLei Zhang     Value maskShiftedByCount =
368*930c74f1SLei Zhang         rewriter.create<LLVM::ShlOp>(loc, dstType, minusOne, count);
369*930c74f1SLei Zhang     Value negated = rewriter.create<LLVM::XOrOp>(loc, dstType,
370*930c74f1SLei Zhang                                                  maskShiftedByCount, minusOne);
371*930c74f1SLei Zhang     Value maskShiftedByCountAndOffset =
372*930c74f1SLei Zhang         rewriter.create<LLVM::ShlOp>(loc, dstType, negated, offset);
373*930c74f1SLei Zhang     Value mask = rewriter.create<LLVM::XOrOp>(
374*930c74f1SLei Zhang         loc, dstType, maskShiftedByCountAndOffset, minusOne);
375*930c74f1SLei Zhang 
376*930c74f1SLei Zhang     // Extract unchanged bits from the `Base`  that are outside of
377*930c74f1SLei Zhang     // [Offset, Offset + Count - 1]. Then `or` with shifted `Insert`.
378*930c74f1SLei Zhang     Value baseAndMask =
379*930c74f1SLei Zhang         rewriter.create<LLVM::AndOp>(loc, dstType, op.base(), mask);
380*930c74f1SLei Zhang     Value insertShiftedByOffset =
381*930c74f1SLei Zhang         rewriter.create<LLVM::ShlOp>(loc, dstType, op.insert(), offset);
382*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::OrOp>(op, dstType, baseAndMask,
383*930c74f1SLei Zhang                                             insertShiftedByOffset);
384*930c74f1SLei Zhang     return success();
385*930c74f1SLei Zhang   }
386*930c74f1SLei Zhang };
387*930c74f1SLei Zhang 
388*930c74f1SLei Zhang /// Converts SPIR-V ConstantOp with scalar or vector type.
389*930c74f1SLei Zhang class ConstantScalarAndVectorPattern
390*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::ConstantOp> {
391*930c74f1SLei Zhang public:
392*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ConstantOp>::SPIRVToLLVMConversion;
393*930c74f1SLei Zhang 
394*930c74f1SLei Zhang   LogicalResult
395*930c74f1SLei Zhang   matchAndRewrite(spirv::ConstantOp constOp, ArrayRef<Value> operands,
396*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
397*930c74f1SLei Zhang     auto srcType = constOp.getType();
398*930c74f1SLei Zhang     if (!srcType.isa<VectorType>() && !srcType.isIntOrFloat())
399*930c74f1SLei Zhang       return failure();
400*930c74f1SLei Zhang 
401*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
402*930c74f1SLei Zhang     if (!dstType)
403*930c74f1SLei Zhang       return failure();
404*930c74f1SLei Zhang 
405*930c74f1SLei Zhang     // SPIR-V constant can be a signed/unsigned integer, which has to be
406*930c74f1SLei Zhang     // casted to signless integer when converting to LLVM dialect. Removing the
407*930c74f1SLei Zhang     // sign bit may have unexpected behaviour. However, it is better to handle
408*930c74f1SLei Zhang     // it case-by-case, given that the purpose of the conversion is not to
409*930c74f1SLei Zhang     // cover all possible corner cases.
410*930c74f1SLei Zhang     if (isSignedIntegerOrVector(srcType) ||
411*930c74f1SLei Zhang         isUnsignedIntegerOrVector(srcType)) {
412*930c74f1SLei Zhang       auto signlessType = rewriter.getIntegerType(getBitWidth(srcType));
413*930c74f1SLei Zhang 
414*930c74f1SLei Zhang       if (srcType.isa<VectorType>()) {
415*930c74f1SLei Zhang         auto dstElementsAttr = constOp.value().cast<DenseIntElementsAttr>();
416*930c74f1SLei Zhang         rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
417*930c74f1SLei Zhang             constOp, dstType,
418*930c74f1SLei Zhang             dstElementsAttr.mapValues(
419*930c74f1SLei Zhang                 signlessType, [&](const APInt &value) { return value; }));
420*930c74f1SLei Zhang         return success();
421*930c74f1SLei Zhang       }
422*930c74f1SLei Zhang       auto srcAttr = constOp.value().cast<IntegerAttr>();
423*930c74f1SLei Zhang       auto dstAttr = rewriter.getIntegerAttr(signlessType, srcAttr.getValue());
424*930c74f1SLei Zhang       rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(constOp, dstType, dstAttr);
425*930c74f1SLei Zhang       return success();
426*930c74f1SLei Zhang     }
427*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(constOp, dstType, operands,
428*930c74f1SLei Zhang                                                   constOp.getAttrs());
429*930c74f1SLei Zhang     return success();
430*930c74f1SLei Zhang   }
431*930c74f1SLei Zhang };
432*930c74f1SLei Zhang 
433*930c74f1SLei Zhang class BitFieldSExtractPattern
434*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::BitFieldSExtractOp> {
435*930c74f1SLei Zhang public:
436*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::BitFieldSExtractOp>::SPIRVToLLVMConversion;
437*930c74f1SLei Zhang 
438*930c74f1SLei Zhang   LogicalResult
439*930c74f1SLei Zhang   matchAndRewrite(spirv::BitFieldSExtractOp op, ArrayRef<Value> operands,
440*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
441*930c74f1SLei Zhang     auto srcType = op.getType();
442*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
443*930c74f1SLei Zhang     if (!dstType)
444*930c74f1SLei Zhang       return failure();
445*930c74f1SLei Zhang     Location loc = op.getLoc();
446*930c74f1SLei Zhang 
447*930c74f1SLei Zhang     // Process `Offset` and `Count`: broadcast and extend/truncate if needed.
448*930c74f1SLei Zhang     Value offset = processCountOrOffset(loc, op.offset(), srcType, dstType,
449*930c74f1SLei Zhang                                         typeConverter, rewriter);
450*930c74f1SLei Zhang     Value count = processCountOrOffset(loc, op.count(), srcType, dstType,
451*930c74f1SLei Zhang                                        typeConverter, rewriter);
452*930c74f1SLei Zhang 
453*930c74f1SLei Zhang     // Create a constant that holds the size of the `Base`.
454*930c74f1SLei Zhang     IntegerType integerType;
455*930c74f1SLei Zhang     if (auto vecType = srcType.dyn_cast<VectorType>())
456*930c74f1SLei Zhang       integerType = vecType.getElementType().cast<IntegerType>();
457*930c74f1SLei Zhang     else
458*930c74f1SLei Zhang       integerType = srcType.cast<IntegerType>();
459*930c74f1SLei Zhang 
460*930c74f1SLei Zhang     auto baseSize = rewriter.getIntegerAttr(integerType, getBitWidth(srcType));
461*930c74f1SLei Zhang     Value size =
462*930c74f1SLei Zhang         srcType.isa<VectorType>()
463*930c74f1SLei Zhang             ? rewriter.create<LLVM::ConstantOp>(
464*930c74f1SLei Zhang                   loc, dstType,
465*930c74f1SLei Zhang                   SplatElementsAttr::get(srcType.cast<ShapedType>(), baseSize))
466*930c74f1SLei Zhang             : rewriter.create<LLVM::ConstantOp>(loc, dstType, baseSize);
467*930c74f1SLei Zhang 
468*930c74f1SLei Zhang     // Shift `Base` left by [sizeof(Base) - (Count + Offset)], so that the bit
469*930c74f1SLei Zhang     // at Offset + Count - 1 is the most significant bit now.
470*930c74f1SLei Zhang     Value countPlusOffset =
471*930c74f1SLei Zhang         rewriter.create<LLVM::AddOp>(loc, dstType, count, offset);
472*930c74f1SLei Zhang     Value amountToShiftLeft =
473*930c74f1SLei Zhang         rewriter.create<LLVM::SubOp>(loc, dstType, size, countPlusOffset);
474*930c74f1SLei Zhang     Value baseShiftedLeft = rewriter.create<LLVM::ShlOp>(
475*930c74f1SLei Zhang         loc, dstType, op.base(), amountToShiftLeft);
476*930c74f1SLei Zhang 
477*930c74f1SLei Zhang     // Shift the result right, filling the bits with the sign bit.
478*930c74f1SLei Zhang     Value amountToShiftRight =
479*930c74f1SLei Zhang         rewriter.create<LLVM::AddOp>(loc, dstType, offset, amountToShiftLeft);
480*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::AShrOp>(op, dstType, baseShiftedLeft,
481*930c74f1SLei Zhang                                               amountToShiftRight);
482*930c74f1SLei Zhang     return success();
483*930c74f1SLei Zhang   }
484*930c74f1SLei Zhang };
485*930c74f1SLei Zhang 
486*930c74f1SLei Zhang class BitFieldUExtractPattern
487*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::BitFieldUExtractOp> {
488*930c74f1SLei Zhang public:
489*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::BitFieldUExtractOp>::SPIRVToLLVMConversion;
490*930c74f1SLei Zhang 
491*930c74f1SLei Zhang   LogicalResult
492*930c74f1SLei Zhang   matchAndRewrite(spirv::BitFieldUExtractOp op, ArrayRef<Value> operands,
493*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
494*930c74f1SLei Zhang     auto srcType = op.getType();
495*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
496*930c74f1SLei Zhang     if (!dstType)
497*930c74f1SLei Zhang       return failure();
498*930c74f1SLei Zhang     Location loc = op.getLoc();
499*930c74f1SLei Zhang 
500*930c74f1SLei Zhang     // Process `Offset` and `Count`: broadcast and extend/truncate if needed.
501*930c74f1SLei Zhang     Value offset = processCountOrOffset(loc, op.offset(), srcType, dstType,
502*930c74f1SLei Zhang                                         typeConverter, rewriter);
503*930c74f1SLei Zhang     Value count = processCountOrOffset(loc, op.count(), srcType, dstType,
504*930c74f1SLei Zhang                                        typeConverter, rewriter);
505*930c74f1SLei Zhang 
506*930c74f1SLei Zhang     // Create a mask with bits set at [0, Count - 1].
507*930c74f1SLei Zhang     Value minusOne = createConstantAllBitsSet(loc, srcType, dstType, rewriter);
508*930c74f1SLei Zhang     Value maskShiftedByCount =
509*930c74f1SLei Zhang         rewriter.create<LLVM::ShlOp>(loc, dstType, minusOne, count);
510*930c74f1SLei Zhang     Value mask = rewriter.create<LLVM::XOrOp>(loc, dstType, maskShiftedByCount,
511*930c74f1SLei Zhang                                               minusOne);
512*930c74f1SLei Zhang 
513*930c74f1SLei Zhang     // Shift `Base` by `Offset` and apply the mask on it.
514*930c74f1SLei Zhang     Value shiftedBase =
515*930c74f1SLei Zhang         rewriter.create<LLVM::LShrOp>(loc, dstType, op.base(), offset);
516*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::AndOp>(op, dstType, shiftedBase, mask);
517*930c74f1SLei Zhang     return success();
518*930c74f1SLei Zhang   }
519*930c74f1SLei Zhang };
520*930c74f1SLei Zhang 
521*930c74f1SLei Zhang class BranchConversionPattern : public SPIRVToLLVMConversion<spirv::BranchOp> {
522*930c74f1SLei Zhang public:
523*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::BranchOp>::SPIRVToLLVMConversion;
524*930c74f1SLei Zhang 
525*930c74f1SLei Zhang   LogicalResult
526*930c74f1SLei Zhang   matchAndRewrite(spirv::BranchOp branchOp, ArrayRef<Value> operands,
527*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
528*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::BrOp>(branchOp, operands,
529*930c74f1SLei Zhang                                             branchOp.getTarget());
530*930c74f1SLei Zhang     return success();
531*930c74f1SLei Zhang   }
532*930c74f1SLei Zhang };
533*930c74f1SLei Zhang 
534*930c74f1SLei Zhang class BranchConditionalConversionPattern
535*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::BranchConditionalOp> {
536*930c74f1SLei Zhang public:
537*930c74f1SLei Zhang   using SPIRVToLLVMConversion<
538*930c74f1SLei Zhang       spirv::BranchConditionalOp>::SPIRVToLLVMConversion;
539*930c74f1SLei Zhang 
540*930c74f1SLei Zhang   LogicalResult
541*930c74f1SLei Zhang   matchAndRewrite(spirv::BranchConditionalOp op, ArrayRef<Value> operands,
542*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
543*930c74f1SLei Zhang     // If branch weights exist, map them to 32-bit integer vector.
544*930c74f1SLei Zhang     ElementsAttr branchWeights = nullptr;
545*930c74f1SLei Zhang     if (auto weights = op.branch_weights()) {
546*930c74f1SLei Zhang       VectorType weightType = VectorType::get(2, rewriter.getI32Type());
547*930c74f1SLei Zhang       branchWeights =
548*930c74f1SLei Zhang           DenseElementsAttr::get(weightType, weights.getValue().getValue());
549*930c74f1SLei Zhang     }
550*930c74f1SLei Zhang 
551*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::CondBrOp>(
552*930c74f1SLei Zhang         op, op.condition(), op.getTrueBlockArguments(),
553*930c74f1SLei Zhang         op.getFalseBlockArguments(), branchWeights, op.getTrueBlock(),
554*930c74f1SLei Zhang         op.getFalseBlock());
555*930c74f1SLei Zhang     return success();
556*930c74f1SLei Zhang   }
557*930c74f1SLei Zhang };
558*930c74f1SLei Zhang 
559*930c74f1SLei Zhang /// Converts `spv.CompositeExtract` to `llvm.extractvalue` if the container type
560*930c74f1SLei Zhang /// is an aggregate type (struct or array). Otherwise, converts to
561*930c74f1SLei Zhang /// `llvm.extractelement` that operates on vectors.
562*930c74f1SLei Zhang class CompositeExtractPattern
563*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::CompositeExtractOp> {
564*930c74f1SLei Zhang public:
565*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::CompositeExtractOp>::SPIRVToLLVMConversion;
566*930c74f1SLei Zhang 
567*930c74f1SLei Zhang   LogicalResult
568*930c74f1SLei Zhang   matchAndRewrite(spirv::CompositeExtractOp op, ArrayRef<Value> operands,
569*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
570*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(op.getType());
571*930c74f1SLei Zhang     if (!dstType)
572*930c74f1SLei Zhang       return failure();
573*930c74f1SLei Zhang 
574*930c74f1SLei Zhang     Type containerType = op.composite().getType();
575*930c74f1SLei Zhang     if (containerType.isa<VectorType>()) {
576*930c74f1SLei Zhang       Location loc = op.getLoc();
577*930c74f1SLei Zhang       IntegerAttr value = op.indices()[0].cast<IntegerAttr>();
578*930c74f1SLei Zhang       Value index = createI32ConstantOf(loc, rewriter, value.getInt());
579*930c74f1SLei Zhang       rewriter.replaceOpWithNewOp<LLVM::ExtractElementOp>(
580*930c74f1SLei Zhang           op, dstType, op.composite(), index);
581*930c74f1SLei Zhang       return success();
582*930c74f1SLei Zhang     }
583*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::ExtractValueOp>(
584*930c74f1SLei Zhang         op, dstType, op.composite(), op.indices());
585*930c74f1SLei Zhang     return success();
586*930c74f1SLei Zhang   }
587*930c74f1SLei Zhang };
588*930c74f1SLei Zhang 
589*930c74f1SLei Zhang /// Converts `spv.CompositeInsert` to `llvm.insertvalue` if the container type
590*930c74f1SLei Zhang /// is an aggregate type (struct or array). Otherwise, converts to
591*930c74f1SLei Zhang /// `llvm.insertelement` that operates on vectors.
592*930c74f1SLei Zhang class CompositeInsertPattern
593*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::CompositeInsertOp> {
594*930c74f1SLei Zhang public:
595*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::CompositeInsertOp>::SPIRVToLLVMConversion;
596*930c74f1SLei Zhang 
597*930c74f1SLei Zhang   LogicalResult
598*930c74f1SLei Zhang   matchAndRewrite(spirv::CompositeInsertOp op, ArrayRef<Value> operands,
599*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
600*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(op.getType());
601*930c74f1SLei Zhang     if (!dstType)
602*930c74f1SLei Zhang       return failure();
603*930c74f1SLei Zhang 
604*930c74f1SLei Zhang     Type containerType = op.composite().getType();
605*930c74f1SLei Zhang     if (containerType.isa<VectorType>()) {
606*930c74f1SLei Zhang       Location loc = op.getLoc();
607*930c74f1SLei Zhang       IntegerAttr value = op.indices()[0].cast<IntegerAttr>();
608*930c74f1SLei Zhang       Value index = createI32ConstantOf(loc, rewriter, value.getInt());
609*930c74f1SLei Zhang       rewriter.replaceOpWithNewOp<LLVM::InsertElementOp>(
610*930c74f1SLei Zhang           op, dstType, op.composite(), op.object(), index);
611*930c74f1SLei Zhang       return success();
612*930c74f1SLei Zhang     }
613*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::InsertValueOp>(
614*930c74f1SLei Zhang         op, dstType, op.composite(), op.object(), op.indices());
615*930c74f1SLei Zhang     return success();
616*930c74f1SLei Zhang   }
617*930c74f1SLei Zhang };
618*930c74f1SLei Zhang 
619*930c74f1SLei Zhang /// Converts SPIR-V operations that have straightforward LLVM equivalent
620*930c74f1SLei Zhang /// into LLVM dialect operations.
621*930c74f1SLei Zhang template <typename SPIRVOp, typename LLVMOp>
622*930c74f1SLei Zhang class DirectConversionPattern : public SPIRVToLLVMConversion<SPIRVOp> {
623*930c74f1SLei Zhang public:
624*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
625*930c74f1SLei Zhang 
626*930c74f1SLei Zhang   LogicalResult
627*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp operation, ArrayRef<Value> operands,
628*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
629*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(operation.getType());
630*930c74f1SLei Zhang     if (!dstType)
631*930c74f1SLei Zhang       return failure();
632*930c74f1SLei Zhang     rewriter.template replaceOpWithNewOp<LLVMOp>(operation, dstType, operands,
633*930c74f1SLei Zhang                                                  operation.getAttrs());
634*930c74f1SLei Zhang     return success();
635*930c74f1SLei Zhang   }
636*930c74f1SLei Zhang };
637*930c74f1SLei Zhang 
638*930c74f1SLei Zhang /// Converts `spv.ExecutionMode` into a global struct constant that holds
639*930c74f1SLei Zhang /// execution mode information.
640*930c74f1SLei Zhang class ExecutionModePattern
641*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::ExecutionModeOp> {
642*930c74f1SLei Zhang public:
643*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ExecutionModeOp>::SPIRVToLLVMConversion;
644*930c74f1SLei Zhang 
645*930c74f1SLei Zhang   LogicalResult
646*930c74f1SLei Zhang   matchAndRewrite(spirv::ExecutionModeOp op, ArrayRef<Value> operands,
647*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
648*930c74f1SLei Zhang     // First, create the global struct's name that would be associated with
649*930c74f1SLei Zhang     // this entry point's execution mode. We set it to be:
650*930c74f1SLei Zhang     //   __spv__{SPIR-V module name}_{function name}_execution_mode_info
651*930c74f1SLei Zhang     ModuleOp module = op->getParentOfType<ModuleOp>();
652*930c74f1SLei Zhang     std::string moduleName;
653*930c74f1SLei Zhang     if (module.getName().hasValue())
654*930c74f1SLei Zhang       moduleName = "_" + module.getName().getValue().str();
655*930c74f1SLei Zhang     else
656*930c74f1SLei Zhang       moduleName = "";
657*930c74f1SLei Zhang     std::string executionModeInfoName = llvm::formatv(
658*930c74f1SLei Zhang         "__spv_{0}_{1}_execution_mode_info", moduleName, op.fn().str());
659*930c74f1SLei Zhang 
660*930c74f1SLei Zhang     MLIRContext *context = rewriter.getContext();
661*930c74f1SLei Zhang     OpBuilder::InsertionGuard guard(rewriter);
662*930c74f1SLei Zhang     rewriter.setInsertionPointToStart(module.getBody());
663*930c74f1SLei Zhang 
664*930c74f1SLei Zhang     // Create a struct type, corresponding to the C struct below.
665*930c74f1SLei Zhang     // struct {
666*930c74f1SLei Zhang     //   int32_t executionMode;
667*930c74f1SLei Zhang     //   int32_t values[];          // optional values
668*930c74f1SLei Zhang     // };
669*930c74f1SLei Zhang     auto llvmI32Type = LLVM::LLVMIntegerType::get(context, 32);
670*930c74f1SLei Zhang     SmallVector<LLVM::LLVMType, 2> fields;
671*930c74f1SLei Zhang     fields.push_back(llvmI32Type);
672*930c74f1SLei Zhang     ArrayAttr values = op.values();
673*930c74f1SLei Zhang     if (!values.empty()) {
674*930c74f1SLei Zhang       auto arrayType = LLVM::LLVMArrayType::get(llvmI32Type, values.size());
675*930c74f1SLei Zhang       fields.push_back(arrayType);
676*930c74f1SLei Zhang     }
677*930c74f1SLei Zhang     auto structType = LLVM::LLVMStructType::getLiteral(context, fields);
678*930c74f1SLei Zhang 
679*930c74f1SLei Zhang     // Create `llvm.mlir.global` with initializer region containing one block.
680*930c74f1SLei Zhang     auto global = rewriter.create<LLVM::GlobalOp>(
681*930c74f1SLei Zhang         UnknownLoc::get(context), structType, /*isConstant=*/true,
682*930c74f1SLei Zhang         LLVM::Linkage::External, executionModeInfoName, Attribute());
683*930c74f1SLei Zhang     Location loc = global.getLoc();
684*930c74f1SLei Zhang     Region &region = global.getInitializerRegion();
685*930c74f1SLei Zhang     Block *block = rewriter.createBlock(&region);
686*930c74f1SLei Zhang 
687*930c74f1SLei Zhang     // Initialize the struct and set the execution mode value.
688*930c74f1SLei Zhang     rewriter.setInsertionPoint(block, block->begin());
689*930c74f1SLei Zhang     Value structValue = rewriter.create<LLVM::UndefOp>(loc, structType);
690*930c74f1SLei Zhang     IntegerAttr executionModeAttr = op.execution_modeAttr();
691*930c74f1SLei Zhang     Value executionMode =
692*930c74f1SLei Zhang         rewriter.create<LLVM::ConstantOp>(loc, llvmI32Type, executionModeAttr);
693*930c74f1SLei Zhang     structValue = rewriter.create<LLVM::InsertValueOp>(
694*930c74f1SLei Zhang         loc, structType, structValue, executionMode,
695*930c74f1SLei Zhang         ArrayAttr::get({rewriter.getIntegerAttr(rewriter.getI32Type(), 0)},
696*930c74f1SLei Zhang                        context));
697*930c74f1SLei Zhang 
698*930c74f1SLei Zhang     // Insert extra operands if they exist into execution mode info struct.
699*930c74f1SLei Zhang     for (unsigned i = 0, e = values.size(); i < e; ++i) {
700*930c74f1SLei Zhang       auto attr = values.getValue()[i];
701*930c74f1SLei Zhang       Value entry = rewriter.create<LLVM::ConstantOp>(loc, llvmI32Type, attr);
702*930c74f1SLei Zhang       structValue = rewriter.create<LLVM::InsertValueOp>(
703*930c74f1SLei Zhang           loc, structType, structValue, entry,
704*930c74f1SLei Zhang           ArrayAttr::get({rewriter.getIntegerAttr(rewriter.getI32Type(), 1),
705*930c74f1SLei Zhang                           rewriter.getIntegerAttr(rewriter.getI32Type(), i)},
706*930c74f1SLei Zhang                          context));
707*930c74f1SLei Zhang     }
708*930c74f1SLei Zhang     rewriter.create<LLVM::ReturnOp>(loc, ArrayRef<Value>({structValue}));
709*930c74f1SLei Zhang     rewriter.eraseOp(op);
710*930c74f1SLei Zhang     return success();
711*930c74f1SLei Zhang   }
712*930c74f1SLei Zhang };
713*930c74f1SLei Zhang 
714*930c74f1SLei Zhang /// Converts `spv.globalVariable` to `llvm.mlir.global`. Note that SPIR-V global
715*930c74f1SLei Zhang /// returns a pointer, whereas in LLVM dialect the global holds an actual value.
716*930c74f1SLei Zhang /// This difference is handled by `spv.mlir.addressof` and
717*930c74f1SLei Zhang /// `llvm.mlir.addressof`ops that both return a pointer.
718*930c74f1SLei Zhang class GlobalVariablePattern
719*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::GlobalVariableOp> {
720*930c74f1SLei Zhang public:
721*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::GlobalVariableOp>::SPIRVToLLVMConversion;
722*930c74f1SLei Zhang 
723*930c74f1SLei Zhang   LogicalResult
724*930c74f1SLei Zhang   matchAndRewrite(spirv::GlobalVariableOp op, ArrayRef<Value> operands,
725*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
726*930c74f1SLei Zhang     // Currently, there is no support of initialization with a constant value in
727*930c74f1SLei Zhang     // SPIR-V dialect. Specialization constants are not considered as well.
728*930c74f1SLei Zhang     if (op.initializer())
729*930c74f1SLei Zhang       return failure();
730*930c74f1SLei Zhang 
731*930c74f1SLei Zhang     auto srcType = op.type().cast<spirv::PointerType>();
732*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType.getPointeeType());
733*930c74f1SLei Zhang     if (!dstType)
734*930c74f1SLei Zhang       return failure();
735*930c74f1SLei Zhang 
736*930c74f1SLei Zhang     // Limit conversion to the current invocation only or `StorageBuffer`
737*930c74f1SLei Zhang     // required by SPIR-V runner.
738*930c74f1SLei Zhang     // This is okay because multiple invocations are not supported yet.
739*930c74f1SLei Zhang     auto storageClass = srcType.getStorageClass();
740*930c74f1SLei Zhang     if (storageClass != spirv::StorageClass::Input &&
741*930c74f1SLei Zhang         storageClass != spirv::StorageClass::Private &&
742*930c74f1SLei Zhang         storageClass != spirv::StorageClass::Output &&
743*930c74f1SLei Zhang         storageClass != spirv::StorageClass::StorageBuffer) {
744*930c74f1SLei Zhang       return failure();
745*930c74f1SLei Zhang     }
746*930c74f1SLei Zhang 
747*930c74f1SLei Zhang     // LLVM dialect spec: "If the global value is a constant, storing into it is
748*930c74f1SLei Zhang     // not allowed.". This corresponds to SPIR-V 'Input' storage class that is
749*930c74f1SLei Zhang     // read-only.
750*930c74f1SLei Zhang     bool isConstant = storageClass == spirv::StorageClass::Input;
751*930c74f1SLei Zhang     // SPIR-V spec: "By default, functions and global variables are private to a
752*930c74f1SLei Zhang     // module and cannot be accessed by other modules. However, a module may be
753*930c74f1SLei Zhang     // written to export or import functions and global (module scope)
754*930c74f1SLei Zhang     // variables.". Therefore, map 'Private' storage class to private linkage,
755*930c74f1SLei Zhang     // 'Input' and 'Output' to external linkage.
756*930c74f1SLei Zhang     auto linkage = storageClass == spirv::StorageClass::Private
757*930c74f1SLei Zhang                        ? LLVM::Linkage::Private
758*930c74f1SLei Zhang                        : LLVM::Linkage::External;
759*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::GlobalOp>(
760*930c74f1SLei Zhang         op, dstType.cast<LLVM::LLVMType>(), isConstant, linkage, op.sym_name(),
761*930c74f1SLei Zhang         Attribute());
762*930c74f1SLei Zhang     return success();
763*930c74f1SLei Zhang   }
764*930c74f1SLei Zhang };
765*930c74f1SLei Zhang 
766*930c74f1SLei Zhang /// Converts SPIR-V cast ops that do not have straightforward LLVM
767*930c74f1SLei Zhang /// equivalent in LLVM dialect.
768*930c74f1SLei Zhang template <typename SPIRVOp, typename LLVMExtOp, typename LLVMTruncOp>
769*930c74f1SLei Zhang class IndirectCastPattern : public SPIRVToLLVMConversion<SPIRVOp> {
770*930c74f1SLei Zhang public:
771*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
772*930c74f1SLei Zhang 
773*930c74f1SLei Zhang   LogicalResult
774*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp operation, ArrayRef<Value> operands,
775*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
776*930c74f1SLei Zhang 
777*930c74f1SLei Zhang     Type fromType = operation.operand().getType();
778*930c74f1SLei Zhang     Type toType = operation.getType();
779*930c74f1SLei Zhang 
780*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(toType);
781*930c74f1SLei Zhang     if (!dstType)
782*930c74f1SLei Zhang       return failure();
783*930c74f1SLei Zhang 
784*930c74f1SLei Zhang     if (getBitWidth(fromType) < getBitWidth(toType)) {
785*930c74f1SLei Zhang       rewriter.template replaceOpWithNewOp<LLVMExtOp>(operation, dstType,
786*930c74f1SLei Zhang                                                       operands);
787*930c74f1SLei Zhang       return success();
788*930c74f1SLei Zhang     }
789*930c74f1SLei Zhang     if (getBitWidth(fromType) > getBitWidth(toType)) {
790*930c74f1SLei Zhang       rewriter.template replaceOpWithNewOp<LLVMTruncOp>(operation, dstType,
791*930c74f1SLei Zhang                                                         operands);
792*930c74f1SLei Zhang       return success();
793*930c74f1SLei Zhang     }
794*930c74f1SLei Zhang     return failure();
795*930c74f1SLei Zhang   }
796*930c74f1SLei Zhang };
797*930c74f1SLei Zhang 
798*930c74f1SLei Zhang class FunctionCallPattern
799*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::FunctionCallOp> {
800*930c74f1SLei Zhang public:
801*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::FunctionCallOp>::SPIRVToLLVMConversion;
802*930c74f1SLei Zhang 
803*930c74f1SLei Zhang   LogicalResult
804*930c74f1SLei Zhang   matchAndRewrite(spirv::FunctionCallOp callOp, ArrayRef<Value> operands,
805*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
806*930c74f1SLei Zhang     if (callOp.getNumResults() == 0) {
807*930c74f1SLei Zhang       rewriter.replaceOpWithNewOp<LLVM::CallOp>(callOp, llvm::None, operands,
808*930c74f1SLei Zhang                                                 callOp.getAttrs());
809*930c74f1SLei Zhang       return success();
810*930c74f1SLei Zhang     }
811*930c74f1SLei Zhang 
812*930c74f1SLei Zhang     // Function returns a single result.
813*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(callOp.getType(0));
814*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::CallOp>(callOp, dstType, operands,
815*930c74f1SLei Zhang                                               callOp.getAttrs());
816*930c74f1SLei Zhang     return success();
817*930c74f1SLei Zhang   }
818*930c74f1SLei Zhang };
819*930c74f1SLei Zhang 
820*930c74f1SLei Zhang /// Converts SPIR-V floating-point comparisons to llvm.fcmp "predicate"
821*930c74f1SLei Zhang template <typename SPIRVOp, LLVM::FCmpPredicate predicate>
822*930c74f1SLei Zhang class FComparePattern : public SPIRVToLLVMConversion<SPIRVOp> {
823*930c74f1SLei Zhang public:
824*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
825*930c74f1SLei Zhang 
826*930c74f1SLei Zhang   LogicalResult
827*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp operation, ArrayRef<Value> operands,
828*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
829*930c74f1SLei Zhang 
830*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(operation.getType());
831*930c74f1SLei Zhang     if (!dstType)
832*930c74f1SLei Zhang       return failure();
833*930c74f1SLei Zhang 
834*930c74f1SLei Zhang     rewriter.template replaceOpWithNewOp<LLVM::FCmpOp>(
835*930c74f1SLei Zhang         operation, dstType,
836*930c74f1SLei Zhang         rewriter.getI64IntegerAttr(static_cast<int64_t>(predicate)),
837*930c74f1SLei Zhang         operation.operand1(), operation.operand2());
838*930c74f1SLei Zhang     return success();
839*930c74f1SLei Zhang   }
840*930c74f1SLei Zhang };
841*930c74f1SLei Zhang 
842*930c74f1SLei Zhang /// Converts SPIR-V integer comparisons to llvm.icmp "predicate"
843*930c74f1SLei Zhang template <typename SPIRVOp, LLVM::ICmpPredicate predicate>
844*930c74f1SLei Zhang class IComparePattern : public SPIRVToLLVMConversion<SPIRVOp> {
845*930c74f1SLei Zhang public:
846*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
847*930c74f1SLei Zhang 
848*930c74f1SLei Zhang   LogicalResult
849*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp operation, ArrayRef<Value> operands,
850*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
851*930c74f1SLei Zhang 
852*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(operation.getType());
853*930c74f1SLei Zhang     if (!dstType)
854*930c74f1SLei Zhang       return failure();
855*930c74f1SLei Zhang 
856*930c74f1SLei Zhang     rewriter.template replaceOpWithNewOp<LLVM::ICmpOp>(
857*930c74f1SLei Zhang         operation, dstType,
858*930c74f1SLei Zhang         rewriter.getI64IntegerAttr(static_cast<int64_t>(predicate)),
859*930c74f1SLei Zhang         operation.operand1(), operation.operand2());
860*930c74f1SLei Zhang     return success();
861*930c74f1SLei Zhang   }
862*930c74f1SLei Zhang };
863*930c74f1SLei Zhang 
864*930c74f1SLei Zhang class InverseSqrtPattern
865*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::GLSLInverseSqrtOp> {
866*930c74f1SLei Zhang public:
867*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::GLSLInverseSqrtOp>::SPIRVToLLVMConversion;
868*930c74f1SLei Zhang 
869*930c74f1SLei Zhang   LogicalResult
870*930c74f1SLei Zhang   matchAndRewrite(spirv::GLSLInverseSqrtOp op, ArrayRef<Value> operands,
871*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
872*930c74f1SLei Zhang     auto srcType = op.getType();
873*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
874*930c74f1SLei Zhang     if (!dstType)
875*930c74f1SLei Zhang       return failure();
876*930c74f1SLei Zhang 
877*930c74f1SLei Zhang     Location loc = op.getLoc();
878*930c74f1SLei Zhang     Value one = createFPConstant(loc, srcType, dstType, rewriter, 1.0);
879*930c74f1SLei Zhang     Value sqrt = rewriter.create<LLVM::SqrtOp>(loc, dstType, op.operand());
880*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::FDivOp>(op, dstType, one, sqrt);
881*930c74f1SLei Zhang     return success();
882*930c74f1SLei Zhang   }
883*930c74f1SLei Zhang };
884*930c74f1SLei Zhang 
885*930c74f1SLei Zhang /// Converts `spv.Load` and `spv.Store` to LLVM dialect.
886*930c74f1SLei Zhang template <typename SPIRVop>
887*930c74f1SLei Zhang class LoadStorePattern : public SPIRVToLLVMConversion<SPIRVop> {
888*930c74f1SLei Zhang public:
889*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVop>::SPIRVToLLVMConversion;
890*930c74f1SLei Zhang 
891*930c74f1SLei Zhang   LogicalResult
892*930c74f1SLei Zhang   matchAndRewrite(SPIRVop op, ArrayRef<Value> operands,
893*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
894*930c74f1SLei Zhang 
895*930c74f1SLei Zhang     if (!op.memory_access().hasValue()) {
896*930c74f1SLei Zhang       replaceWithLoadOrStore(op, rewriter, this->typeConverter, /*alignment=*/0,
897*930c74f1SLei Zhang                              /*isVolatile=*/false, /*isNonTemporal=*/false);
898*930c74f1SLei Zhang       return success();
899*930c74f1SLei Zhang     }
900*930c74f1SLei Zhang     auto memoryAccess = op.memory_access().getValue();
901*930c74f1SLei Zhang     switch (memoryAccess) {
902*930c74f1SLei Zhang     case spirv::MemoryAccess::Aligned:
903*930c74f1SLei Zhang     case spirv::MemoryAccess::None:
904*930c74f1SLei Zhang     case spirv::MemoryAccess::Nontemporal:
905*930c74f1SLei Zhang     case spirv::MemoryAccess::Volatile: {
906*930c74f1SLei Zhang       unsigned alignment =
907*930c74f1SLei Zhang           memoryAccess == spirv::MemoryAccess::Aligned ? *op.alignment() : 0;
908*930c74f1SLei Zhang       bool isNonTemporal = memoryAccess == spirv::MemoryAccess::Nontemporal;
909*930c74f1SLei Zhang       bool isVolatile = memoryAccess == spirv::MemoryAccess::Volatile;
910*930c74f1SLei Zhang       replaceWithLoadOrStore(op, rewriter, this->typeConverter, alignment,
911*930c74f1SLei Zhang                              isVolatile, isNonTemporal);
912*930c74f1SLei Zhang       return success();
913*930c74f1SLei Zhang     }
914*930c74f1SLei Zhang     default:
915*930c74f1SLei Zhang       // There is no support of other memory access attributes.
916*930c74f1SLei Zhang       return failure();
917*930c74f1SLei Zhang     }
918*930c74f1SLei Zhang   }
919*930c74f1SLei Zhang };
920*930c74f1SLei Zhang 
921*930c74f1SLei Zhang /// Converts `spv.Not` and `spv.LogicalNot` into LLVM dialect.
922*930c74f1SLei Zhang template <typename SPIRVOp>
923*930c74f1SLei Zhang class NotPattern : public SPIRVToLLVMConversion<SPIRVOp> {
924*930c74f1SLei Zhang public:
925*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
926*930c74f1SLei Zhang 
927*930c74f1SLei Zhang   LogicalResult
928*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp notOp, ArrayRef<Value> operands,
929*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
930*930c74f1SLei Zhang 
931*930c74f1SLei Zhang     auto srcType = notOp.getType();
932*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(srcType);
933*930c74f1SLei Zhang     if (!dstType)
934*930c74f1SLei Zhang       return failure();
935*930c74f1SLei Zhang 
936*930c74f1SLei Zhang     Location loc = notOp.getLoc();
937*930c74f1SLei Zhang     IntegerAttr minusOne = minusOneIntegerAttribute(srcType, rewriter);
938*930c74f1SLei Zhang     auto mask = srcType.template isa<VectorType>()
939*930c74f1SLei Zhang                     ? rewriter.create<LLVM::ConstantOp>(
940*930c74f1SLei Zhang                           loc, dstType,
941*930c74f1SLei Zhang                           SplatElementsAttr::get(
942*930c74f1SLei Zhang                               srcType.template cast<VectorType>(), minusOne))
943*930c74f1SLei Zhang                     : rewriter.create<LLVM::ConstantOp>(loc, dstType, minusOne);
944*930c74f1SLei Zhang     rewriter.template replaceOpWithNewOp<LLVM::XOrOp>(notOp, dstType,
945*930c74f1SLei Zhang                                                       notOp.operand(), mask);
946*930c74f1SLei Zhang     return success();
947*930c74f1SLei Zhang   }
948*930c74f1SLei Zhang };
949*930c74f1SLei Zhang 
950*930c74f1SLei Zhang /// A template pattern that erases the given `SPIRVOp`.
951*930c74f1SLei Zhang template <typename SPIRVOp>
952*930c74f1SLei Zhang class ErasePattern : public SPIRVToLLVMConversion<SPIRVOp> {
953*930c74f1SLei Zhang public:
954*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
955*930c74f1SLei Zhang 
956*930c74f1SLei Zhang   LogicalResult
957*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp op, ArrayRef<Value> operands,
958*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
959*930c74f1SLei Zhang     rewriter.eraseOp(op);
960*930c74f1SLei Zhang     return success();
961*930c74f1SLei Zhang   }
962*930c74f1SLei Zhang };
963*930c74f1SLei Zhang 
964*930c74f1SLei Zhang class ReturnPattern : public SPIRVToLLVMConversion<spirv::ReturnOp> {
965*930c74f1SLei Zhang public:
966*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ReturnOp>::SPIRVToLLVMConversion;
967*930c74f1SLei Zhang 
968*930c74f1SLei Zhang   LogicalResult
969*930c74f1SLei Zhang   matchAndRewrite(spirv::ReturnOp returnOp, ArrayRef<Value> operands,
970*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
971*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(returnOp, ArrayRef<Type>(),
972*930c74f1SLei Zhang                                                 ArrayRef<Value>());
973*930c74f1SLei Zhang     return success();
974*930c74f1SLei Zhang   }
975*930c74f1SLei Zhang };
976*930c74f1SLei Zhang 
977*930c74f1SLei Zhang class ReturnValuePattern : public SPIRVToLLVMConversion<spirv::ReturnValueOp> {
978*930c74f1SLei Zhang public:
979*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ReturnValueOp>::SPIRVToLLVMConversion;
980*930c74f1SLei Zhang 
981*930c74f1SLei Zhang   LogicalResult
982*930c74f1SLei Zhang   matchAndRewrite(spirv::ReturnValueOp returnValueOp, ArrayRef<Value> operands,
983*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
984*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(returnValueOp, ArrayRef<Type>(),
985*930c74f1SLei Zhang                                                 operands);
986*930c74f1SLei Zhang     return success();
987*930c74f1SLei Zhang   }
988*930c74f1SLei Zhang };
989*930c74f1SLei Zhang 
990*930c74f1SLei Zhang /// Converts `spv.loop` to LLVM dialect. All blocks within selection should be
991*930c74f1SLei Zhang /// reachable for conversion to succeed.
992*930c74f1SLei Zhang /// The structure of the loop in LLVM dialect will be the following:
993*930c74f1SLei Zhang ///
994*930c74f1SLei Zhang ///      +------------------------------------+
995*930c74f1SLei Zhang ///      | <code before spv.loop>             |
996*930c74f1SLei Zhang ///      | llvm.br ^header                    |
997*930c74f1SLei Zhang ///      +------------------------------------+
998*930c74f1SLei Zhang ///                           |
999*930c74f1SLei Zhang ///   +----------------+      |
1000*930c74f1SLei Zhang ///   |                |      |
1001*930c74f1SLei Zhang ///   |                V      V
1002*930c74f1SLei Zhang ///   |  +------------------------------------+
1003*930c74f1SLei Zhang ///   |  | ^header:                           |
1004*930c74f1SLei Zhang ///   |  |   <header code>                    |
1005*930c74f1SLei Zhang ///   |  |   llvm.cond_br %cond, ^body, ^exit |
1006*930c74f1SLei Zhang ///   |  +------------------------------------+
1007*930c74f1SLei Zhang ///   |                    |
1008*930c74f1SLei Zhang ///   |                    |----------------------+
1009*930c74f1SLei Zhang ///   |                    |                      |
1010*930c74f1SLei Zhang ///   |                    V                      |
1011*930c74f1SLei Zhang ///   |  +------------------------------------+   |
1012*930c74f1SLei Zhang ///   |  | ^body:                             |   |
1013*930c74f1SLei Zhang ///   |  |   <body code>                      |   |
1014*930c74f1SLei Zhang ///   |  |   llvm.br ^continue                |   |
1015*930c74f1SLei Zhang ///   |  +------------------------------------+   |
1016*930c74f1SLei Zhang ///   |                    |                      |
1017*930c74f1SLei Zhang ///   |                    V                      |
1018*930c74f1SLei Zhang ///   |  +------------------------------------+   |
1019*930c74f1SLei Zhang ///   |  | ^continue:                         |   |
1020*930c74f1SLei Zhang ///   |  |   <continue code>                  |   |
1021*930c74f1SLei Zhang ///   |  |   llvm.br ^header                  |   |
1022*930c74f1SLei Zhang ///   |  +------------------------------------+   |
1023*930c74f1SLei Zhang ///   |               |                           |
1024*930c74f1SLei Zhang ///   +---------------+    +----------------------+
1025*930c74f1SLei Zhang ///                        |
1026*930c74f1SLei Zhang ///                        V
1027*930c74f1SLei Zhang ///      +------------------------------------+
1028*930c74f1SLei Zhang ///      | ^exit:                             |
1029*930c74f1SLei Zhang ///      |   llvm.br ^remaining               |
1030*930c74f1SLei Zhang ///      +------------------------------------+
1031*930c74f1SLei Zhang ///                        |
1032*930c74f1SLei Zhang ///                        V
1033*930c74f1SLei Zhang ///      +------------------------------------+
1034*930c74f1SLei Zhang ///      | ^remaining:                        |
1035*930c74f1SLei Zhang ///      |   <code after spv.loop>            |
1036*930c74f1SLei Zhang ///      +------------------------------------+
1037*930c74f1SLei Zhang ///
1038*930c74f1SLei Zhang class LoopPattern : public SPIRVToLLVMConversion<spirv::LoopOp> {
1039*930c74f1SLei Zhang public:
1040*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::LoopOp>::SPIRVToLLVMConversion;
1041*930c74f1SLei Zhang 
1042*930c74f1SLei Zhang   LogicalResult
1043*930c74f1SLei Zhang   matchAndRewrite(spirv::LoopOp loopOp, ArrayRef<Value> operands,
1044*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1045*930c74f1SLei Zhang     // There is no support of loop control at the moment.
1046*930c74f1SLei Zhang     if (loopOp.loop_control() != spirv::LoopControl::None)
1047*930c74f1SLei Zhang       return failure();
1048*930c74f1SLei Zhang 
1049*930c74f1SLei Zhang     Location loc = loopOp.getLoc();
1050*930c74f1SLei Zhang 
1051*930c74f1SLei Zhang     // Split the current block after `spv.loop`. The remaining ops will be used
1052*930c74f1SLei Zhang     // in `endBlock`.
1053*930c74f1SLei Zhang     Block *currentBlock = rewriter.getBlock();
1054*930c74f1SLei Zhang     auto position = Block::iterator(loopOp);
1055*930c74f1SLei Zhang     Block *endBlock = rewriter.splitBlock(currentBlock, position);
1056*930c74f1SLei Zhang 
1057*930c74f1SLei Zhang     // Remove entry block and create a branch in the current block going to the
1058*930c74f1SLei Zhang     // header block.
1059*930c74f1SLei Zhang     Block *entryBlock = loopOp.getEntryBlock();
1060*930c74f1SLei Zhang     assert(entryBlock->getOperations().size() == 1);
1061*930c74f1SLei Zhang     auto brOp = dyn_cast<spirv::BranchOp>(entryBlock->getOperations().front());
1062*930c74f1SLei Zhang     if (!brOp)
1063*930c74f1SLei Zhang       return failure();
1064*930c74f1SLei Zhang     Block *headerBlock = loopOp.getHeaderBlock();
1065*930c74f1SLei Zhang     rewriter.setInsertionPointToEnd(currentBlock);
1066*930c74f1SLei Zhang     rewriter.create<LLVM::BrOp>(loc, brOp.getBlockArguments(), headerBlock);
1067*930c74f1SLei Zhang     rewriter.eraseBlock(entryBlock);
1068*930c74f1SLei Zhang 
1069*930c74f1SLei Zhang     // Branch from merge block to end block.
1070*930c74f1SLei Zhang     Block *mergeBlock = loopOp.getMergeBlock();
1071*930c74f1SLei Zhang     Operation *terminator = mergeBlock->getTerminator();
1072*930c74f1SLei Zhang     ValueRange terminatorOperands = terminator->getOperands();
1073*930c74f1SLei Zhang     rewriter.setInsertionPointToEnd(mergeBlock);
1074*930c74f1SLei Zhang     rewriter.create<LLVM::BrOp>(loc, terminatorOperands, endBlock);
1075*930c74f1SLei Zhang 
1076*930c74f1SLei Zhang     rewriter.inlineRegionBefore(loopOp.body(), endBlock);
1077*930c74f1SLei Zhang     rewriter.replaceOp(loopOp, endBlock->getArguments());
1078*930c74f1SLei Zhang     return success();
1079*930c74f1SLei Zhang   }
1080*930c74f1SLei Zhang };
1081*930c74f1SLei Zhang 
1082*930c74f1SLei Zhang /// Converts `spv.selection` with `spv.BranchConditional` in its header block.
1083*930c74f1SLei Zhang /// All blocks within selection should be reachable for conversion to succeed.
1084*930c74f1SLei Zhang class SelectionPattern : public SPIRVToLLVMConversion<spirv::SelectionOp> {
1085*930c74f1SLei Zhang public:
1086*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::SelectionOp>::SPIRVToLLVMConversion;
1087*930c74f1SLei Zhang 
1088*930c74f1SLei Zhang   LogicalResult
1089*930c74f1SLei Zhang   matchAndRewrite(spirv::SelectionOp op, ArrayRef<Value> operands,
1090*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1091*930c74f1SLei Zhang     // There is no support for `Flatten` or `DontFlatten` selection control at
1092*930c74f1SLei Zhang     // the moment. This are just compiler hints and can be performed during the
1093*930c74f1SLei Zhang     // optimization passes.
1094*930c74f1SLei Zhang     if (op.selection_control() != spirv::SelectionControl::None)
1095*930c74f1SLei Zhang       return failure();
1096*930c74f1SLei Zhang 
1097*930c74f1SLei Zhang     // `spv.selection` should have at least two blocks: one selection header
1098*930c74f1SLei Zhang     // block and one merge block. If no blocks are present, or control flow
1099*930c74f1SLei Zhang     // branches straight to merge block (two blocks are present), the op is
1100*930c74f1SLei Zhang     // redundant and it is erased.
1101*930c74f1SLei Zhang     if (op.body().getBlocks().size() <= 2) {
1102*930c74f1SLei Zhang       rewriter.eraseOp(op);
1103*930c74f1SLei Zhang       return success();
1104*930c74f1SLei Zhang     }
1105*930c74f1SLei Zhang 
1106*930c74f1SLei Zhang     Location loc = op.getLoc();
1107*930c74f1SLei Zhang 
1108*930c74f1SLei Zhang     // Split the current block after `spv.selection`. The remaining ops will be
1109*930c74f1SLei Zhang     // used in `continueBlock`.
1110*930c74f1SLei Zhang     auto *currentBlock = rewriter.getInsertionBlock();
1111*930c74f1SLei Zhang     rewriter.setInsertionPointAfter(op);
1112*930c74f1SLei Zhang     auto position = rewriter.getInsertionPoint();
1113*930c74f1SLei Zhang     auto *continueBlock = rewriter.splitBlock(currentBlock, position);
1114*930c74f1SLei Zhang 
1115*930c74f1SLei Zhang     // Extract conditional branch information from the header block. By SPIR-V
1116*930c74f1SLei Zhang     // dialect spec, it should contain `spv.BranchConditional` or `spv.Switch`
1117*930c74f1SLei Zhang     // op. Note that `spv.Switch op` is not supported at the moment in the
1118*930c74f1SLei Zhang     // SPIR-V dialect. Remove this block when finished.
1119*930c74f1SLei Zhang     auto *headerBlock = op.getHeaderBlock();
1120*930c74f1SLei Zhang     assert(headerBlock->getOperations().size() == 1);
1121*930c74f1SLei Zhang     auto condBrOp = dyn_cast<spirv::BranchConditionalOp>(
1122*930c74f1SLei Zhang         headerBlock->getOperations().front());
1123*930c74f1SLei Zhang     if (!condBrOp)
1124*930c74f1SLei Zhang       return failure();
1125*930c74f1SLei Zhang     rewriter.eraseBlock(headerBlock);
1126*930c74f1SLei Zhang 
1127*930c74f1SLei Zhang     // Branch from merge block to continue block.
1128*930c74f1SLei Zhang     auto *mergeBlock = op.getMergeBlock();
1129*930c74f1SLei Zhang     Operation *terminator = mergeBlock->getTerminator();
1130*930c74f1SLei Zhang     ValueRange terminatorOperands = terminator->getOperands();
1131*930c74f1SLei Zhang     rewriter.setInsertionPointToEnd(mergeBlock);
1132*930c74f1SLei Zhang     rewriter.create<LLVM::BrOp>(loc, terminatorOperands, continueBlock);
1133*930c74f1SLei Zhang 
1134*930c74f1SLei Zhang     // Link current block to `true` and `false` blocks within the selection.
1135*930c74f1SLei Zhang     Block *trueBlock = condBrOp.getTrueBlock();
1136*930c74f1SLei Zhang     Block *falseBlock = condBrOp.getFalseBlock();
1137*930c74f1SLei Zhang     rewriter.setInsertionPointToEnd(currentBlock);
1138*930c74f1SLei Zhang     rewriter.create<LLVM::CondBrOp>(loc, condBrOp.condition(), trueBlock,
1139*930c74f1SLei Zhang                                     condBrOp.trueTargetOperands(), falseBlock,
1140*930c74f1SLei Zhang                                     condBrOp.falseTargetOperands());
1141*930c74f1SLei Zhang 
1142*930c74f1SLei Zhang     rewriter.inlineRegionBefore(op.body(), continueBlock);
1143*930c74f1SLei Zhang     rewriter.replaceOp(op, continueBlock->getArguments());
1144*930c74f1SLei Zhang     return success();
1145*930c74f1SLei Zhang   }
1146*930c74f1SLei Zhang };
1147*930c74f1SLei Zhang 
1148*930c74f1SLei Zhang /// Converts SPIR-V shift ops to LLVM shift ops. Since LLVM dialect
1149*930c74f1SLei Zhang /// puts a restriction on `Shift` and `Base` to have the same bit width,
1150*930c74f1SLei Zhang /// `Shift` is zero or sign extended to match this specification. Cases when
1151*930c74f1SLei Zhang /// `Shift` bit width > `Base` bit width are considered to be illegal.
1152*930c74f1SLei Zhang template <typename SPIRVOp, typename LLVMOp>
1153*930c74f1SLei Zhang class ShiftPattern : public SPIRVToLLVMConversion<SPIRVOp> {
1154*930c74f1SLei Zhang public:
1155*930c74f1SLei Zhang   using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1156*930c74f1SLei Zhang 
1157*930c74f1SLei Zhang   LogicalResult
1158*930c74f1SLei Zhang   matchAndRewrite(SPIRVOp operation, ArrayRef<Value> operands,
1159*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1160*930c74f1SLei Zhang 
1161*930c74f1SLei Zhang     auto dstType = this->typeConverter.convertType(operation.getType());
1162*930c74f1SLei Zhang     if (!dstType)
1163*930c74f1SLei Zhang       return failure();
1164*930c74f1SLei Zhang 
1165*930c74f1SLei Zhang     Type op1Type = operation.operand1().getType();
1166*930c74f1SLei Zhang     Type op2Type = operation.operand2().getType();
1167*930c74f1SLei Zhang 
1168*930c74f1SLei Zhang     if (op1Type == op2Type) {
1169*930c74f1SLei Zhang       rewriter.template replaceOpWithNewOp<LLVMOp>(operation, dstType,
1170*930c74f1SLei Zhang                                                    operands);
1171*930c74f1SLei Zhang       return success();
1172*930c74f1SLei Zhang     }
1173*930c74f1SLei Zhang 
1174*930c74f1SLei Zhang     Location loc = operation.getLoc();
1175*930c74f1SLei Zhang     Value extended;
1176*930c74f1SLei Zhang     if (isUnsignedIntegerOrVector(op2Type)) {
1177*930c74f1SLei Zhang       extended = rewriter.template create<LLVM::ZExtOp>(loc, dstType,
1178*930c74f1SLei Zhang                                                         operation.operand2());
1179*930c74f1SLei Zhang     } else {
1180*930c74f1SLei Zhang       extended = rewriter.template create<LLVM::SExtOp>(loc, dstType,
1181*930c74f1SLei Zhang                                                         operation.operand2());
1182*930c74f1SLei Zhang     }
1183*930c74f1SLei Zhang     Value result = rewriter.template create<LLVMOp>(
1184*930c74f1SLei Zhang         loc, dstType, operation.operand1(), extended);
1185*930c74f1SLei Zhang     rewriter.replaceOp(operation, result);
1186*930c74f1SLei Zhang     return success();
1187*930c74f1SLei Zhang   }
1188*930c74f1SLei Zhang };
1189*930c74f1SLei Zhang 
1190*930c74f1SLei Zhang class TanPattern : public SPIRVToLLVMConversion<spirv::GLSLTanOp> {
1191*930c74f1SLei Zhang public:
1192*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::GLSLTanOp>::SPIRVToLLVMConversion;
1193*930c74f1SLei Zhang 
1194*930c74f1SLei Zhang   LogicalResult
1195*930c74f1SLei Zhang   matchAndRewrite(spirv::GLSLTanOp tanOp, ArrayRef<Value> operands,
1196*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1197*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(tanOp.getType());
1198*930c74f1SLei Zhang     if (!dstType)
1199*930c74f1SLei Zhang       return failure();
1200*930c74f1SLei Zhang 
1201*930c74f1SLei Zhang     Location loc = tanOp.getLoc();
1202*930c74f1SLei Zhang     Value sin = rewriter.create<LLVM::SinOp>(loc, dstType, tanOp.operand());
1203*930c74f1SLei Zhang     Value cos = rewriter.create<LLVM::CosOp>(loc, dstType, tanOp.operand());
1204*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::FDivOp>(tanOp, dstType, sin, cos);
1205*930c74f1SLei Zhang     return success();
1206*930c74f1SLei Zhang   }
1207*930c74f1SLei Zhang };
1208*930c74f1SLei Zhang 
1209*930c74f1SLei Zhang /// Convert `spv.Tanh` to
1210*930c74f1SLei Zhang ///
1211*930c74f1SLei Zhang ///   exp(2x) - 1
1212*930c74f1SLei Zhang ///   -----------
1213*930c74f1SLei Zhang ///   exp(2x) + 1
1214*930c74f1SLei Zhang ///
1215*930c74f1SLei Zhang class TanhPattern : public SPIRVToLLVMConversion<spirv::GLSLTanhOp> {
1216*930c74f1SLei Zhang public:
1217*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::GLSLTanhOp>::SPIRVToLLVMConversion;
1218*930c74f1SLei Zhang 
1219*930c74f1SLei Zhang   LogicalResult
1220*930c74f1SLei Zhang   matchAndRewrite(spirv::GLSLTanhOp tanhOp, ArrayRef<Value> operands,
1221*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1222*930c74f1SLei Zhang     auto srcType = tanhOp.getType();
1223*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
1224*930c74f1SLei Zhang     if (!dstType)
1225*930c74f1SLei Zhang       return failure();
1226*930c74f1SLei Zhang 
1227*930c74f1SLei Zhang     Location loc = tanhOp.getLoc();
1228*930c74f1SLei Zhang     Value two = createFPConstant(loc, srcType, dstType, rewriter, 2.0);
1229*930c74f1SLei Zhang     Value multiplied =
1230*930c74f1SLei Zhang         rewriter.create<LLVM::FMulOp>(loc, dstType, two, tanhOp.operand());
1231*930c74f1SLei Zhang     Value exponential = rewriter.create<LLVM::ExpOp>(loc, dstType, multiplied);
1232*930c74f1SLei Zhang     Value one = createFPConstant(loc, srcType, dstType, rewriter, 1.0);
1233*930c74f1SLei Zhang     Value numerator =
1234*930c74f1SLei Zhang         rewriter.create<LLVM::FSubOp>(loc, dstType, exponential, one);
1235*930c74f1SLei Zhang     Value denominator =
1236*930c74f1SLei Zhang         rewriter.create<LLVM::FAddOp>(loc, dstType, exponential, one);
1237*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<LLVM::FDivOp>(tanhOp, dstType, numerator,
1238*930c74f1SLei Zhang                                               denominator);
1239*930c74f1SLei Zhang     return success();
1240*930c74f1SLei Zhang   }
1241*930c74f1SLei Zhang };
1242*930c74f1SLei Zhang 
1243*930c74f1SLei Zhang class VariablePattern : public SPIRVToLLVMConversion<spirv::VariableOp> {
1244*930c74f1SLei Zhang public:
1245*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::VariableOp>::SPIRVToLLVMConversion;
1246*930c74f1SLei Zhang 
1247*930c74f1SLei Zhang   LogicalResult
1248*930c74f1SLei Zhang   matchAndRewrite(spirv::VariableOp varOp, ArrayRef<Value> operands,
1249*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1250*930c74f1SLei Zhang     auto srcType = varOp.getType();
1251*930c74f1SLei Zhang     // Initialization is supported for scalars and vectors only.
1252*930c74f1SLei Zhang     auto pointerTo = srcType.cast<spirv::PointerType>().getPointeeType();
1253*930c74f1SLei Zhang     auto init = varOp.initializer();
1254*930c74f1SLei Zhang     if (init && !pointerTo.isIntOrFloat() && !pointerTo.isa<VectorType>())
1255*930c74f1SLei Zhang       return failure();
1256*930c74f1SLei Zhang 
1257*930c74f1SLei Zhang     auto dstType = typeConverter.convertType(srcType);
1258*930c74f1SLei Zhang     if (!dstType)
1259*930c74f1SLei Zhang       return failure();
1260*930c74f1SLei Zhang 
1261*930c74f1SLei Zhang     Location loc = varOp.getLoc();
1262*930c74f1SLei Zhang     Value size = createI32ConstantOf(loc, rewriter, 1);
1263*930c74f1SLei Zhang     if (!init) {
1264*930c74f1SLei Zhang       rewriter.replaceOpWithNewOp<LLVM::AllocaOp>(varOp, dstType, size);
1265*930c74f1SLei Zhang       return success();
1266*930c74f1SLei Zhang     }
1267*930c74f1SLei Zhang     Value allocated = rewriter.create<LLVM::AllocaOp>(loc, dstType, size);
1268*930c74f1SLei Zhang     rewriter.create<LLVM::StoreOp>(loc, init, allocated);
1269*930c74f1SLei Zhang     rewriter.replaceOp(varOp, allocated);
1270*930c74f1SLei Zhang     return success();
1271*930c74f1SLei Zhang   }
1272*930c74f1SLei Zhang };
1273*930c74f1SLei Zhang 
1274*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1275*930c74f1SLei Zhang // FuncOp conversion
1276*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1277*930c74f1SLei Zhang 
1278*930c74f1SLei Zhang class FuncConversionPattern : public SPIRVToLLVMConversion<spirv::FuncOp> {
1279*930c74f1SLei Zhang public:
1280*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::FuncOp>::SPIRVToLLVMConversion;
1281*930c74f1SLei Zhang 
1282*930c74f1SLei Zhang   LogicalResult
1283*930c74f1SLei Zhang   matchAndRewrite(spirv::FuncOp funcOp, ArrayRef<Value> operands,
1284*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1285*930c74f1SLei Zhang 
1286*930c74f1SLei Zhang     // Convert function signature. At the moment LLVMType converter is enough
1287*930c74f1SLei Zhang     // for currently supported types.
1288*930c74f1SLei Zhang     auto funcType = funcOp.getType();
1289*930c74f1SLei Zhang     TypeConverter::SignatureConversion signatureConverter(
1290*930c74f1SLei Zhang         funcType.getNumInputs());
1291*930c74f1SLei Zhang     auto llvmType = typeConverter.convertFunctionSignature(
1292*930c74f1SLei Zhang         funcOp.getType(), /*isVariadic=*/false, signatureConverter);
1293*930c74f1SLei Zhang     if (!llvmType)
1294*930c74f1SLei Zhang       return failure();
1295*930c74f1SLei Zhang 
1296*930c74f1SLei Zhang     // Create a new `LLVMFuncOp`
1297*930c74f1SLei Zhang     Location loc = funcOp.getLoc();
1298*930c74f1SLei Zhang     StringRef name = funcOp.getName();
1299*930c74f1SLei Zhang     auto newFuncOp = rewriter.create<LLVM::LLVMFuncOp>(loc, name, llvmType);
1300*930c74f1SLei Zhang 
1301*930c74f1SLei Zhang     // Convert SPIR-V Function Control to equivalent LLVM function attribute
1302*930c74f1SLei Zhang     MLIRContext *context = funcOp.getContext();
1303*930c74f1SLei Zhang     switch (funcOp.function_control()) {
1304*930c74f1SLei Zhang #define DISPATCH(functionControl, llvmAttr)                                    \
1305*930c74f1SLei Zhang   case functionControl:                                                        \
1306*930c74f1SLei Zhang     newFuncOp->setAttr("passthrough", ArrayAttr::get({llvmAttr}, context));    \
1307*930c74f1SLei Zhang     break;
1308*930c74f1SLei Zhang 
1309*930c74f1SLei Zhang       DISPATCH(spirv::FunctionControl::Inline,
1310*930c74f1SLei Zhang                StringAttr::get("alwaysinline", context));
1311*930c74f1SLei Zhang       DISPATCH(spirv::FunctionControl::DontInline,
1312*930c74f1SLei Zhang                StringAttr::get("noinline", context));
1313*930c74f1SLei Zhang       DISPATCH(spirv::FunctionControl::Pure,
1314*930c74f1SLei Zhang                StringAttr::get("readonly", context));
1315*930c74f1SLei Zhang       DISPATCH(spirv::FunctionControl::Const,
1316*930c74f1SLei Zhang                StringAttr::get("readnone", context));
1317*930c74f1SLei Zhang 
1318*930c74f1SLei Zhang #undef DISPATCH
1319*930c74f1SLei Zhang 
1320*930c74f1SLei Zhang     // Default: if `spirv::FunctionControl::None`, then no attributes are
1321*930c74f1SLei Zhang     // needed.
1322*930c74f1SLei Zhang     default:
1323*930c74f1SLei Zhang       break;
1324*930c74f1SLei Zhang     }
1325*930c74f1SLei Zhang 
1326*930c74f1SLei Zhang     rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
1327*930c74f1SLei Zhang                                 newFuncOp.end());
1328*930c74f1SLei Zhang     if (failed(rewriter.convertRegionTypes(&newFuncOp.getBody(), typeConverter,
1329*930c74f1SLei Zhang                                            &signatureConverter))) {
1330*930c74f1SLei Zhang       return failure();
1331*930c74f1SLei Zhang     }
1332*930c74f1SLei Zhang     rewriter.eraseOp(funcOp);
1333*930c74f1SLei Zhang     return success();
1334*930c74f1SLei Zhang   }
1335*930c74f1SLei Zhang };
1336*930c74f1SLei Zhang 
1337*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1338*930c74f1SLei Zhang // ModuleOp conversion
1339*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1340*930c74f1SLei Zhang 
1341*930c74f1SLei Zhang class ModuleConversionPattern : public SPIRVToLLVMConversion<spirv::ModuleOp> {
1342*930c74f1SLei Zhang public:
1343*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ModuleOp>::SPIRVToLLVMConversion;
1344*930c74f1SLei Zhang 
1345*930c74f1SLei Zhang   LogicalResult
1346*930c74f1SLei Zhang   matchAndRewrite(spirv::ModuleOp spvModuleOp, ArrayRef<Value> operands,
1347*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1348*930c74f1SLei Zhang 
1349*930c74f1SLei Zhang     auto newModuleOp =
1350*930c74f1SLei Zhang         rewriter.create<ModuleOp>(spvModuleOp.getLoc(), spvModuleOp.getName());
1351*930c74f1SLei Zhang     rewriter.inlineRegionBefore(spvModuleOp.body(), newModuleOp.getBody());
1352*930c74f1SLei Zhang 
1353*930c74f1SLei Zhang     // Remove the terminator block that was automatically added by builder
1354*930c74f1SLei Zhang     rewriter.eraseBlock(&newModuleOp.getBodyRegion().back());
1355*930c74f1SLei Zhang     rewriter.eraseOp(spvModuleOp);
1356*930c74f1SLei Zhang     return success();
1357*930c74f1SLei Zhang   }
1358*930c74f1SLei Zhang };
1359*930c74f1SLei Zhang 
1360*930c74f1SLei Zhang class ModuleEndConversionPattern
1361*930c74f1SLei Zhang     : public SPIRVToLLVMConversion<spirv::ModuleEndOp> {
1362*930c74f1SLei Zhang public:
1363*930c74f1SLei Zhang   using SPIRVToLLVMConversion<spirv::ModuleEndOp>::SPIRVToLLVMConversion;
1364*930c74f1SLei Zhang 
1365*930c74f1SLei Zhang   LogicalResult
1366*930c74f1SLei Zhang   matchAndRewrite(spirv::ModuleEndOp moduleEndOp, ArrayRef<Value> operands,
1367*930c74f1SLei Zhang                   ConversionPatternRewriter &rewriter) const override {
1368*930c74f1SLei Zhang 
1369*930c74f1SLei Zhang     rewriter.replaceOpWithNewOp<ModuleTerminatorOp>(moduleEndOp);
1370*930c74f1SLei Zhang     return success();
1371*930c74f1SLei Zhang   }
1372*930c74f1SLei Zhang };
1373*930c74f1SLei Zhang 
1374*930c74f1SLei Zhang } // namespace
1375*930c74f1SLei Zhang 
1376*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1377*930c74f1SLei Zhang // Pattern population
1378*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1379*930c74f1SLei Zhang 
1380*930c74f1SLei Zhang void mlir::populateSPIRVToLLVMTypeConversion(LLVMTypeConverter &typeConverter) {
1381*930c74f1SLei Zhang   typeConverter.addConversion([&](spirv::ArrayType type) {
1382*930c74f1SLei Zhang     return convertArrayType(type, typeConverter);
1383*930c74f1SLei Zhang   });
1384*930c74f1SLei Zhang   typeConverter.addConversion([&](spirv::PointerType type) {
1385*930c74f1SLei Zhang     return convertPointerType(type, typeConverter);
1386*930c74f1SLei Zhang   });
1387*930c74f1SLei Zhang   typeConverter.addConversion([&](spirv::RuntimeArrayType type) {
1388*930c74f1SLei Zhang     return convertRuntimeArrayType(type, typeConverter);
1389*930c74f1SLei Zhang   });
1390*930c74f1SLei Zhang   typeConverter.addConversion([&](spirv::StructType type) {
1391*930c74f1SLei Zhang     return convertStructType(type, typeConverter);
1392*930c74f1SLei Zhang   });
1393*930c74f1SLei Zhang }
1394*930c74f1SLei Zhang 
1395*930c74f1SLei Zhang void mlir::populateSPIRVToLLVMConversionPatterns(
1396*930c74f1SLei Zhang     MLIRContext *context, LLVMTypeConverter &typeConverter,
1397*930c74f1SLei Zhang     OwningRewritePatternList &patterns) {
1398*930c74f1SLei Zhang   patterns.insert<
1399*930c74f1SLei Zhang       // Arithmetic ops
1400*930c74f1SLei Zhang       DirectConversionPattern<spirv::IAddOp, LLVM::AddOp>,
1401*930c74f1SLei Zhang       DirectConversionPattern<spirv::IMulOp, LLVM::MulOp>,
1402*930c74f1SLei Zhang       DirectConversionPattern<spirv::ISubOp, LLVM::SubOp>,
1403*930c74f1SLei Zhang       DirectConversionPattern<spirv::FAddOp, LLVM::FAddOp>,
1404*930c74f1SLei Zhang       DirectConversionPattern<spirv::FDivOp, LLVM::FDivOp>,
1405*930c74f1SLei Zhang       DirectConversionPattern<spirv::FMulOp, LLVM::FMulOp>,
1406*930c74f1SLei Zhang       DirectConversionPattern<spirv::FNegateOp, LLVM::FNegOp>,
1407*930c74f1SLei Zhang       DirectConversionPattern<spirv::FRemOp, LLVM::FRemOp>,
1408*930c74f1SLei Zhang       DirectConversionPattern<spirv::FSubOp, LLVM::FSubOp>,
1409*930c74f1SLei Zhang       DirectConversionPattern<spirv::SDivOp, LLVM::SDivOp>,
1410*930c74f1SLei Zhang       DirectConversionPattern<spirv::SRemOp, LLVM::SRemOp>,
1411*930c74f1SLei Zhang       DirectConversionPattern<spirv::UDivOp, LLVM::UDivOp>,
1412*930c74f1SLei Zhang       DirectConversionPattern<spirv::UModOp, LLVM::URemOp>,
1413*930c74f1SLei Zhang 
1414*930c74f1SLei Zhang       // Bitwise ops
1415*930c74f1SLei Zhang       BitFieldInsertPattern, BitFieldUExtractPattern, BitFieldSExtractPattern,
1416*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitCountOp, LLVM::CtPopOp>,
1417*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitReverseOp, LLVM::BitReverseOp>,
1418*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitwiseAndOp, LLVM::AndOp>,
1419*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitwiseOrOp, LLVM::OrOp>,
1420*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitwiseXorOp, LLVM::XOrOp>,
1421*930c74f1SLei Zhang       NotPattern<spirv::NotOp>,
1422*930c74f1SLei Zhang 
1423*930c74f1SLei Zhang       // Cast ops
1424*930c74f1SLei Zhang       DirectConversionPattern<spirv::BitcastOp, LLVM::BitcastOp>,
1425*930c74f1SLei Zhang       DirectConversionPattern<spirv::ConvertFToSOp, LLVM::FPToSIOp>,
1426*930c74f1SLei Zhang       DirectConversionPattern<spirv::ConvertFToUOp, LLVM::FPToUIOp>,
1427*930c74f1SLei Zhang       DirectConversionPattern<spirv::ConvertSToFOp, LLVM::SIToFPOp>,
1428*930c74f1SLei Zhang       DirectConversionPattern<spirv::ConvertUToFOp, LLVM::UIToFPOp>,
1429*930c74f1SLei Zhang       IndirectCastPattern<spirv::FConvertOp, LLVM::FPExtOp, LLVM::FPTruncOp>,
1430*930c74f1SLei Zhang       IndirectCastPattern<spirv::SConvertOp, LLVM::SExtOp, LLVM::TruncOp>,
1431*930c74f1SLei Zhang       IndirectCastPattern<spirv::UConvertOp, LLVM::ZExtOp, LLVM::TruncOp>,
1432*930c74f1SLei Zhang 
1433*930c74f1SLei Zhang       // Comparison ops
1434*930c74f1SLei Zhang       IComparePattern<spirv::IEqualOp, LLVM::ICmpPredicate::eq>,
1435*930c74f1SLei Zhang       IComparePattern<spirv::INotEqualOp, LLVM::ICmpPredicate::ne>,
1436*930c74f1SLei Zhang       FComparePattern<spirv::FOrdEqualOp, LLVM::FCmpPredicate::oeq>,
1437*930c74f1SLei Zhang       FComparePattern<spirv::FOrdGreaterThanOp, LLVM::FCmpPredicate::ogt>,
1438*930c74f1SLei Zhang       FComparePattern<spirv::FOrdGreaterThanEqualOp, LLVM::FCmpPredicate::oge>,
1439*930c74f1SLei Zhang       FComparePattern<spirv::FOrdLessThanEqualOp, LLVM::FCmpPredicate::ole>,
1440*930c74f1SLei Zhang       FComparePattern<spirv::FOrdLessThanOp, LLVM::FCmpPredicate::olt>,
1441*930c74f1SLei Zhang       FComparePattern<spirv::FOrdNotEqualOp, LLVM::FCmpPredicate::one>,
1442*930c74f1SLei Zhang       FComparePattern<spirv::FUnordEqualOp, LLVM::FCmpPredicate::ueq>,
1443*930c74f1SLei Zhang       FComparePattern<spirv::FUnordGreaterThanOp, LLVM::FCmpPredicate::ugt>,
1444*930c74f1SLei Zhang       FComparePattern<spirv::FUnordGreaterThanEqualOp,
1445*930c74f1SLei Zhang                       LLVM::FCmpPredicate::uge>,
1446*930c74f1SLei Zhang       FComparePattern<spirv::FUnordLessThanEqualOp, LLVM::FCmpPredicate::ule>,
1447*930c74f1SLei Zhang       FComparePattern<spirv::FUnordLessThanOp, LLVM::FCmpPredicate::ult>,
1448*930c74f1SLei Zhang       FComparePattern<spirv::FUnordNotEqualOp, LLVM::FCmpPredicate::une>,
1449*930c74f1SLei Zhang       IComparePattern<spirv::SGreaterThanOp, LLVM::ICmpPredicate::sgt>,
1450*930c74f1SLei Zhang       IComparePattern<spirv::SGreaterThanEqualOp, LLVM::ICmpPredicate::sge>,
1451*930c74f1SLei Zhang       IComparePattern<spirv::SLessThanEqualOp, LLVM::ICmpPredicate::sle>,
1452*930c74f1SLei Zhang       IComparePattern<spirv::SLessThanOp, LLVM::ICmpPredicate::slt>,
1453*930c74f1SLei Zhang       IComparePattern<spirv::UGreaterThanOp, LLVM::ICmpPredicate::ugt>,
1454*930c74f1SLei Zhang       IComparePattern<spirv::UGreaterThanEqualOp, LLVM::ICmpPredicate::uge>,
1455*930c74f1SLei Zhang       IComparePattern<spirv::ULessThanEqualOp, LLVM::ICmpPredicate::ule>,
1456*930c74f1SLei Zhang       IComparePattern<spirv::ULessThanOp, LLVM::ICmpPredicate::ult>,
1457*930c74f1SLei Zhang 
1458*930c74f1SLei Zhang       // Constant op
1459*930c74f1SLei Zhang       ConstantScalarAndVectorPattern,
1460*930c74f1SLei Zhang 
1461*930c74f1SLei Zhang       // Control Flow ops
1462*930c74f1SLei Zhang       BranchConversionPattern, BranchConditionalConversionPattern,
1463*930c74f1SLei Zhang       FunctionCallPattern, LoopPattern, SelectionPattern,
1464*930c74f1SLei Zhang       ErasePattern<spirv::MergeOp>,
1465*930c74f1SLei Zhang 
1466*930c74f1SLei Zhang       // Entry points and execution mode are handled separately.
1467*930c74f1SLei Zhang       ErasePattern<spirv::EntryPointOp>, ExecutionModePattern,
1468*930c74f1SLei Zhang 
1469*930c74f1SLei Zhang       // GLSL extended instruction set ops
1470*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLCeilOp, LLVM::FCeilOp>,
1471*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLCosOp, LLVM::CosOp>,
1472*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLExpOp, LLVM::ExpOp>,
1473*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLFAbsOp, LLVM::FAbsOp>,
1474*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLFloorOp, LLVM::FFloorOp>,
1475*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLFMaxOp, LLVM::MaxNumOp>,
1476*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLFMinOp, LLVM::MinNumOp>,
1477*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLLogOp, LLVM::LogOp>,
1478*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLSinOp, LLVM::SinOp>,
1479*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLSMaxOp, LLVM::SMaxOp>,
1480*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLSMinOp, LLVM::SMinOp>,
1481*930c74f1SLei Zhang       DirectConversionPattern<spirv::GLSLSqrtOp, LLVM::SqrtOp>,
1482*930c74f1SLei Zhang       InverseSqrtPattern, TanPattern, TanhPattern,
1483*930c74f1SLei Zhang 
1484*930c74f1SLei Zhang       // Logical ops
1485*930c74f1SLei Zhang       DirectConversionPattern<spirv::LogicalAndOp, LLVM::AndOp>,
1486*930c74f1SLei Zhang       DirectConversionPattern<spirv::LogicalOrOp, LLVM::OrOp>,
1487*930c74f1SLei Zhang       IComparePattern<spirv::LogicalEqualOp, LLVM::ICmpPredicate::eq>,
1488*930c74f1SLei Zhang       IComparePattern<spirv::LogicalNotEqualOp, LLVM::ICmpPredicate::ne>,
1489*930c74f1SLei Zhang       NotPattern<spirv::LogicalNotOp>,
1490*930c74f1SLei Zhang 
1491*930c74f1SLei Zhang       // Memory ops
1492*930c74f1SLei Zhang       AccessChainPattern, AddressOfPattern, GlobalVariablePattern,
1493*930c74f1SLei Zhang       LoadStorePattern<spirv::LoadOp>, LoadStorePattern<spirv::StoreOp>,
1494*930c74f1SLei Zhang       VariablePattern,
1495*930c74f1SLei Zhang 
1496*930c74f1SLei Zhang       // Miscellaneous ops
1497*930c74f1SLei Zhang       CompositeExtractPattern, CompositeInsertPattern,
1498*930c74f1SLei Zhang       DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,
1499*930c74f1SLei Zhang       DirectConversionPattern<spirv::UndefOp, LLVM::UndefOp>,
1500*930c74f1SLei Zhang 
1501*930c74f1SLei Zhang       // Shift ops
1502*930c74f1SLei Zhang       ShiftPattern<spirv::ShiftRightArithmeticOp, LLVM::AShrOp>,
1503*930c74f1SLei Zhang       ShiftPattern<spirv::ShiftRightLogicalOp, LLVM::LShrOp>,
1504*930c74f1SLei Zhang       ShiftPattern<spirv::ShiftLeftLogicalOp, LLVM::ShlOp>,
1505*930c74f1SLei Zhang 
1506*930c74f1SLei Zhang       // Return ops
1507*930c74f1SLei Zhang       ReturnPattern, ReturnValuePattern>(context, typeConverter);
1508*930c74f1SLei Zhang }
1509*930c74f1SLei Zhang 
1510*930c74f1SLei Zhang void mlir::populateSPIRVToLLVMFunctionConversionPatterns(
1511*930c74f1SLei Zhang     MLIRContext *context, LLVMTypeConverter &typeConverter,
1512*930c74f1SLei Zhang     OwningRewritePatternList &patterns) {
1513*930c74f1SLei Zhang   patterns.insert<FuncConversionPattern>(context, typeConverter);
1514*930c74f1SLei Zhang }
1515*930c74f1SLei Zhang 
1516*930c74f1SLei Zhang void mlir::populateSPIRVToLLVMModuleConversionPatterns(
1517*930c74f1SLei Zhang     MLIRContext *context, LLVMTypeConverter &typeConverter,
1518*930c74f1SLei Zhang     OwningRewritePatternList &patterns) {
1519*930c74f1SLei Zhang   patterns.insert<ModuleConversionPattern, ModuleEndConversionPattern>(
1520*930c74f1SLei Zhang       context, typeConverter);
1521*930c74f1SLei Zhang }
1522*930c74f1SLei Zhang 
1523*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1524*930c74f1SLei Zhang // Pre-conversion hooks
1525*930c74f1SLei Zhang //===----------------------------------------------------------------------===//
1526*930c74f1SLei Zhang 
1527*930c74f1SLei Zhang /// Hook for descriptor set and binding number encoding.
1528*930c74f1SLei Zhang static constexpr StringRef kBinding = "binding";
1529*930c74f1SLei Zhang static constexpr StringRef kDescriptorSet = "descriptor_set";
1530*930c74f1SLei Zhang void mlir::encodeBindAttribute(ModuleOp module) {
1531*930c74f1SLei Zhang   auto spvModules = module.getOps<spirv::ModuleOp>();
1532*930c74f1SLei Zhang   for (auto spvModule : spvModules) {
1533*930c74f1SLei Zhang     spvModule.walk([&](spirv::GlobalVariableOp op) {
1534*930c74f1SLei Zhang       IntegerAttr descriptorSet =
1535*930c74f1SLei Zhang           op->getAttrOfType<IntegerAttr>(kDescriptorSet);
1536*930c74f1SLei Zhang       IntegerAttr binding = op->getAttrOfType<IntegerAttr>(kBinding);
1537*930c74f1SLei Zhang       // For every global variable in the module, get the ones with descriptor
1538*930c74f1SLei Zhang       // set and binding numbers.
1539*930c74f1SLei Zhang       if (descriptorSet && binding) {
1540*930c74f1SLei Zhang         // Encode these numbers into the variable's symbolic name. If the
1541*930c74f1SLei Zhang         // SPIR-V module has a name, add it at the beginning.
1542*930c74f1SLei Zhang         auto moduleAndName = spvModule.getName().hasValue()
1543*930c74f1SLei Zhang                                  ? spvModule.getName().getValue().str() + "_" +
1544*930c74f1SLei Zhang                                        op.sym_name().str()
1545*930c74f1SLei Zhang                                  : op.sym_name().str();
1546*930c74f1SLei Zhang         std::string name =
1547*930c74f1SLei Zhang             llvm::formatv("{0}_descriptor_set{1}_binding{2}", moduleAndName,
1548*930c74f1SLei Zhang                           std::to_string(descriptorSet.getInt()),
1549*930c74f1SLei Zhang                           std::to_string(binding.getInt()));
1550*930c74f1SLei Zhang 
1551*930c74f1SLei Zhang         // Replace all symbol uses and set the new symbol name. Finally, remove
1552*930c74f1SLei Zhang         // descriptor set and binding attributes.
1553*930c74f1SLei Zhang         if (failed(SymbolTable::replaceAllSymbolUses(op, name, spvModule)))
1554*930c74f1SLei Zhang           op.emitError("unable to replace all symbol uses for ") << name;
1555*930c74f1SLei Zhang         SymbolTable::setSymbolName(op, name);
1556*930c74f1SLei Zhang         op.removeAttr(kDescriptorSet);
1557*930c74f1SLei Zhang         op.removeAttr(kBinding);
1558*930c74f1SLei Zhang       }
1559*930c74f1SLei Zhang     });
1560*930c74f1SLei Zhang   }
1561*930c74f1SLei Zhang }
1562