MLIR 24.0.0git
GPUToLLVMConversion.cpp
Go to the documentation of this file.
1//===- ConvertLaunchFuncToGpuRuntimeCalls.cpp - MLIR GPU lowering passes --===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a pass to convert gpu.launch_func op into a sequence of
10// GPU runtime calls. As most of GPU runtimes does not have a stable published
11// ABI, this pass uses a slim runtime layer that builds on top of the public
12// API from GPU runtime headers.
13//
14//===----------------------------------------------------------------------===//
15
17
34#include "mlir/IR/Attributes.h"
35#include "mlir/IR/Builders.h"
36#include "mlir/IR/BuiltinOps.h"
39
40#include "llvm/ADT/STLExtras.h"
41
42#define DEBUG_TYPE "gpu-to-llvm"
43
44namespace mlir {
45#define GEN_PASS_DEF_GPUTOLLVMCONVERSIONPASS
46#include "mlir/Conversion/Passes.h.inc"
47} // namespace mlir
48
49using namespace mlir;
50
51namespace {
52class GpuToLLVMConversionPass
53 : public impl::GpuToLLVMConversionPassBase<GpuToLLVMConversionPass> {
54public:
55 using Base::Base;
56 void getDependentDialects(DialectRegistry &registry) const final {
57 Base::getDependentDialects(registry);
59 }
60 // Run the dialect converter on the module.
61 void runOnOperation() override;
62};
63
64template <typename OpTy>
65class ConvertOpToGpuRuntimeCallPattern : public ConvertOpToLLVMPattern<OpTy> {
66public:
67 explicit ConvertOpToGpuRuntimeCallPattern(
68 const LLVMTypeConverter &typeConverter, PatternBenefit benefit = 1)
69 : ConvertOpToLLVMPattern<OpTy>(typeConverter, benefit) {}
70
71protected:
72 Value getNumElements(ConversionPatternRewriter &rewriter, Location loc,
73 MemRefType type, MemRefDescriptor desc) const {
74 Type indexType = ConvertToLLVMPattern::getIndexType();
75 if (type.hasStaticShape())
77 rewriter, loc, indexType, type.getNumElements());
78 // Compute the number of elements by multiplying all the dim sizes.
79 uint64_t rank = type.getRank();
80 Value numElements = desc.size(rewriter, loc, /*pos=*/0);
81 for (unsigned i = 1; i < rank; i++)
82 numElements = LLVM::MulOp::create(rewriter, loc, numElements,
83 desc.size(rewriter, loc, /*pos=*/i));
84 return numElements;
85 }
86
87 MLIRContext *context = &this->getTypeConverter()->getContext();
88
89 Type llvmVoidType = LLVM::LLVMVoidType::get(context);
90 LLVM::LLVMPointerType llvmPointerType = LLVM::LLVMPointerType::get(context);
91 Type llvmInt8Type = IntegerType::get(context, 8);
92 Type llvmInt16Type = IntegerType::get(context, 16);
93 Type llvmInt32Type = IntegerType::get(context, 32);
94 Type llvmInt64Type = IntegerType::get(context, 64);
95 Type llvmFloat32Type = Float32Type::get(context);
96 Type llvmIntPtrType = IntegerType::get(
97 context, this->getTypeConverter()->getPointerBitwidth(0));
98
99 FunctionCallBuilder streamCreateCallBuilder = {
100 "mgpuStreamCreate", llvmPointerType /* void *stream */, {}};
101 FunctionCallBuilder streamDestroyCallBuilder = {
102 "mgpuStreamDestroy", llvmVoidType, {llvmPointerType /* void *stream */}};
103 FunctionCallBuilder streamSynchronizeCallBuilder = {
104 "mgpuStreamSynchronize",
105 llvmVoidType,
106 {llvmPointerType /* void *stream */}};
107 FunctionCallBuilder streamWaitEventCallBuilder = {
108 "mgpuStreamWaitEvent",
109 llvmVoidType,
110 {llvmPointerType /* void *stream */, llvmPointerType /* void *event */}};
111 FunctionCallBuilder eventCreateCallBuilder = {
112 "mgpuEventCreate", llvmPointerType /* void *event */, {}};
113 FunctionCallBuilder eventDestroyCallBuilder = {
114 "mgpuEventDestroy", llvmVoidType, {llvmPointerType /* void *event */}};
115 FunctionCallBuilder eventSynchronizeCallBuilder = {
116 "mgpuEventSynchronize",
117 llvmVoidType,
118 {llvmPointerType /* void *event */}};
119 FunctionCallBuilder eventRecordCallBuilder = {
120 "mgpuEventRecord",
121 llvmVoidType,
122 {llvmPointerType /* void *event */, llvmPointerType /* void *stream */}};
123 FunctionCallBuilder hostRegisterCallBuilder = {
124 "mgpuMemHostRegisterMemRef",
125 llvmVoidType,
126 {llvmIntPtrType /* intptr_t rank */,
127 llvmPointerType /* void *memrefDesc */,
128 llvmIntPtrType /* intptr_t elementSizeBytes */}};
129 FunctionCallBuilder hostUnregisterCallBuilder = {
130 "mgpuMemHostUnregisterMemRef",
131 llvmVoidType,
132 {llvmIntPtrType /* intptr_t rank */,
133 llvmPointerType /* void *memrefDesc */,
134 llvmIntPtrType /* intptr_t elementSizeBytes */}};
135 FunctionCallBuilder allocCallBuilder = {
136 "mgpuMemAlloc",
137 llvmPointerType /* void * */,
138 {llvmIntPtrType /* intptr_t sizeBytes */,
139 llvmPointerType /* void *stream */,
140 llvmInt8Type /* bool isHostShared */}};
141 FunctionCallBuilder deallocCallBuilder = {
142 "mgpuMemFree",
143 llvmVoidType,
144 {llvmPointerType /* void *ptr */, llvmPointerType /* void *stream */}};
145 FunctionCallBuilder memcpyCallBuilder = {
146 "mgpuMemcpy",
147 llvmVoidType,
148 {llvmPointerType /* void *dst */, llvmPointerType /* void *src */,
149 llvmIntPtrType /* intptr_t sizeBytes */,
150 llvmPointerType /* void *stream */}};
151 FunctionCallBuilder memset16CallBuilder = {
152 "mgpuMemset16",
153 llvmVoidType,
154 {llvmPointerType /* void *dst */,
155 llvmInt16Type /* unsigned short value */,
156 llvmIntPtrType /* intptr_t sizeBytes */,
157 llvmPointerType /* void *stream */}};
158 FunctionCallBuilder memset32CallBuilder = {
159 "mgpuMemset32",
160 llvmVoidType,
161 {llvmPointerType /* void *dst */, llvmInt32Type /* unsigned int value */,
162 llvmIntPtrType /* intptr_t sizeBytes */,
163 llvmPointerType /* void *stream */}};
164 FunctionCallBuilder setDefaultDeviceCallBuilder = {
165 "mgpuSetDefaultDevice",
166 llvmVoidType,
167 {llvmInt32Type /* uint32_t devIndex */}};
168 FunctionCallBuilder createDnVecCallBuilder = {
169 "mgpuCreateDnVec",
170 llvmPointerType,
171 {llvmIntPtrType, llvmPointerType, llvmInt32Type,
172 llvmPointerType /* void *stream */}};
173 FunctionCallBuilder destroyDnVecCallBuilder = {
174 "mgpuDestroyDnVec",
175 llvmVoidType,
176 {llvmPointerType, llvmPointerType /* void *stream */}};
177 FunctionCallBuilder createDnMatCallBuilder = {
178 "mgpuCreateDnMat",
179 llvmPointerType,
180 {llvmIntPtrType, llvmIntPtrType, llvmPointerType, llvmInt32Type,
181 llvmPointerType /* void *stream */}};
182 FunctionCallBuilder destroyDnMatCallBuilder = {
183 "mgpuDestroyDnMat",
184 llvmVoidType,
185 {llvmPointerType, llvmPointerType /* void *stream */}};
186 FunctionCallBuilder createCooCallBuilder = {
187 "mgpuCreateCoo",
188 llvmPointerType,
189 {llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
190 llvmPointerType, llvmPointerType, llvmInt32Type, llvmInt32Type,
191 llvmPointerType /* void *stream */}};
192 FunctionCallBuilder createCooAoSCallBuilder = {
193 "mgpuCreateCooAoS", // deprecated in cuSPARSE 11.2
194 llvmPointerType,
195 {llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
196 llvmPointerType, llvmInt32Type, llvmInt32Type,
197 llvmPointerType /* void *stream */}};
198 FunctionCallBuilder createCsrCallBuilder = {
199 "mgpuCreateCsr",
200 llvmPointerType,
201 {llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
202 llvmPointerType, llvmPointerType, llvmInt32Type, llvmInt32Type,
203 llvmInt32Type, llvmPointerType /* void *stream */}};
204 FunctionCallBuilder createCscCallBuilder = {
205 "mgpuCreateCsc",
206 llvmPointerType,
207 {llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
208 llvmPointerType, llvmPointerType, llvmInt32Type, llvmInt32Type,
209 llvmInt32Type, llvmPointerType /* void *stream */}};
210 FunctionCallBuilder createBsrCallBuilder = {
211 "mgpuCreateBsr",
212 llvmPointerType,
213 {llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmIntPtrType,
214 llvmIntPtrType, llvmPointerType, llvmPointerType, llvmPointerType,
215 llvmInt32Type, llvmInt32Type, llvmInt32Type,
216 llvmPointerType /* void *stream */}};
217 FunctionCallBuilder destroySpMatCallBuilder = {
218 "mgpuDestroySpMat",
219 llvmVoidType,
220 {llvmPointerType, llvmPointerType /* void *stream */}};
221 FunctionCallBuilder spMVBufferSizeCallBuilder = {
222 "mgpuSpMVBufferSize",
223 llvmIntPtrType,
224 {llvmInt32Type, llvmPointerType, llvmPointerType, llvmPointerType,
225 llvmInt32Type, llvmPointerType /* void *stream */}};
226 FunctionCallBuilder spMVCallBuilder = {
227 "mgpuSpMV",
228 llvmVoidType,
229 {llvmInt32Type, llvmPointerType, llvmPointerType, llvmPointerType,
230 llvmInt32Type, llvmPointerType, llvmPointerType /* void *stream */}};
231 FunctionCallBuilder createSpMMBufferSizeCallBuilder = {
232 "mgpuSpMMBufferSize",
233 llvmIntPtrType,
234 {llvmInt32Type, llvmInt32Type, llvmPointerType, llvmPointerType,
235 llvmPointerType, llvmInt32Type, llvmPointerType /* void *stream */}};
236 FunctionCallBuilder createSpMMCallBuilder = {
237 "mgpuSpMM",
238 llvmVoidType,
239 {llvmInt32Type, llvmInt32Type, llvmPointerType, llvmPointerType,
240 llvmPointerType, llvmInt32Type, llvmPointerType,
241 llvmPointerType /* void *stream */}};
242 FunctionCallBuilder createSDDMMBufferSizeCallBuilder = {
243 "mgpuSDDMMBufferSize",
244 llvmIntPtrType,
245 {llvmInt32Type, llvmInt32Type, llvmPointerType, llvmPointerType,
246 llvmPointerType, llvmInt32Type, llvmPointerType /* void *stream */}};
247 FunctionCallBuilder createSDDMMCallBuilder = {
248 "mgpuSDDMM",
249 llvmVoidType,
250 {llvmInt32Type, llvmInt32Type, llvmPointerType, llvmPointerType,
251 llvmPointerType, llvmInt32Type, llvmPointerType,
252 llvmPointerType /* void *stream */}};
253 FunctionCallBuilder createLtDnMatCallBuilder = {
254 "mgpuCreateCuSparseLtDnMat",
255 llvmVoidType,
256 {llvmPointerType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
257 llvmInt32Type, llvmPointerType /* void *stream */}};
258 FunctionCallBuilder destroyCuSparseLtSpMatBuilder = {
259 "mgpuDestroyCuSparseLtSpMat",
260 llvmVoidType,
261 {llvmPointerType, llvmPointerType /* void *stream */}};
262 FunctionCallBuilder destroyCuSparseLtDnMatBuilder = {
263 "mgpuDestroyCuSparseLtDnMat",
264 llvmVoidType,
265 {llvmPointerType, llvmPointerType /* void *stream */}};
266 FunctionCallBuilder create2To4SpMatCallBuilder = {
267 "mgpuCusparseLtCreate2To4SpMat",
268 llvmVoidType,
269 {llvmPointerType, llvmIntPtrType, llvmIntPtrType, llvmPointerType,
270 llvmInt32Type, llvmPointerType /* void *stream */}};
271 FunctionCallBuilder createCuSparseLtSpMMBufferSizeBuilder = {
272 "mgpuCuSparseLtSpMMBufferSize",
273 llvmVoidType,
274 {llvmPointerType, llvmInt32Type, llvmInt32Type, llvmPointerType,
275 llvmPointerType, llvmPointerType, llvmInt32Type, llvmInt32Type,
276 llvmPointerType /*void *stream*/}};
277 FunctionCallBuilder createCuSparseLtSpMMBuilder = {
278 "mgpuCuSparseLtSpMM",
279 llvmVoidType,
280 {llvmPointerType, llvmPointerType, llvmPointerType, llvmPointerType,
281 llvmPointerType, llvmPointerType, llvmPointerType /*void *stream*/}};
282 FunctionCallBuilder createSpGEMMCreateDescrBuilder = {
283 "mgpuSpGEMMCreateDescr",
284 llvmPointerType,
285 {llvmPointerType /*void *stream*/}};
286 FunctionCallBuilder createSpGEMMDestroyDescrBuilder = {
287 "mgpuSpGEMMDestroyDescr",
288 llvmVoidType,
289 {llvmPointerType /*s*/, llvmPointerType /*void *stream*/}};
290 FunctionCallBuilder createSpGEMMWorkEstimationBuilder = {
291 "mgpuSpGEMMWorkEstimation",
292 llvmIntPtrType,
293 {llvmPointerType /*s*/, llvmInt32Type /*ma*/, llvmInt32Type /*mb*/,
294 llvmPointerType /*a*/, llvmPointerType /*b*/, llvmPointerType /*c*/,
295 llvmInt32Type /*ctp*/, llvmIntPtrType /*bs*/, llvmPointerType /*buf*/,
296 llvmPointerType /*void *stream*/}};
297 FunctionCallBuilder createSpGEMMComputeBuilder = {
298 "mgpuSpGEMMCompute",
299 llvmIntPtrType,
300 {llvmPointerType /*s*/, llvmInt32Type /*ma*/, llvmInt32Type /*mb*/,
301 llvmPointerType /*a*/, llvmPointerType /*b*/, llvmPointerType /*c*/,
302 llvmInt32Type /*ctp*/, llvmIntPtrType /*bs*/, llvmPointerType /*buf*/,
303 llvmPointerType /*void *stream*/}};
304 FunctionCallBuilder createSpGEMMCopyBuilder = {
305 "mgpuSpGEMMCopy",
306 llvmVoidType,
307 {llvmPointerType /*s*/, llvmInt32Type /*ma*/, llvmInt32Type /*mb*/,
308 llvmPointerType /*a*/, llvmPointerType /*b*/, llvmPointerType /*c*/,
309 llvmInt32Type /*ctp*/, llvmPointerType /*void *stream*/}};
310 FunctionCallBuilder createSpMatGetSizeBuilder = {
311 "mgpuSpMatGetSize",
312 llvmVoidType,
313 {llvmPointerType /*mc*/, llvmPointerType /*rc*/, llvmPointerType /*cc*/,
314 llvmPointerType /*nc*/, llvmPointerType /*void *stream*/}};
315 FunctionCallBuilder createSetCsrPointersBuilder = {
316 "mgpuSetCsrPointers",
317 llvmVoidType,
318 {llvmPointerType /*spmat*/, llvmPointerType /*pos*/,
319 llvmPointerType /*crd*/, llvmPointerType /*val*/,
320 llvmPointerType /*void *stream*/}};
321};
322
323/// A rewrite pattern to convert gpu.host_register operations into a GPU runtime
324/// call. Currently it supports CUDA and ROCm (HIP).
325class ConvertHostRegisterOpToGpuRuntimeCallPattern
326 : public ConvertOpToGpuRuntimeCallPattern<gpu::HostRegisterOp> {
327public:
328 ConvertHostRegisterOpToGpuRuntimeCallPattern(
329 const LLVMTypeConverter &typeConverter)
330 : ConvertOpToGpuRuntimeCallPattern<gpu::HostRegisterOp>(typeConverter) {}
331
332private:
333 LogicalResult
334 matchAndRewrite(gpu::HostRegisterOp hostRegisterOp, OpAdaptor adaptor,
335 ConversionPatternRewriter &rewriter) const override;
336};
337
338class ConvertHostUnregisterOpToGpuRuntimeCallPattern
339 : public ConvertOpToGpuRuntimeCallPattern<gpu::HostUnregisterOp> {
340public:
341 ConvertHostUnregisterOpToGpuRuntimeCallPattern(
342 const LLVMTypeConverter &typeConverter)
343 : ConvertOpToGpuRuntimeCallPattern<gpu::HostUnregisterOp>(typeConverter) {
344 }
345
346private:
347 LogicalResult
348 matchAndRewrite(gpu::HostUnregisterOp hostUnregisterOp, OpAdaptor adaptor,
349 ConversionPatternRewriter &rewriter) const override;
350};
351
352/// A rewrite pattern to convert gpu.alloc operations into a GPU runtime
353/// call. Currently it supports CUDA and ROCm (HIP).
354class ConvertAllocOpToGpuRuntimeCallPattern
355 : public ConvertOpToGpuRuntimeCallPattern<gpu::AllocOp> {
356public:
357 ConvertAllocOpToGpuRuntimeCallPattern(const LLVMTypeConverter &typeConverter)
358 : ConvertOpToGpuRuntimeCallPattern<gpu::AllocOp>(typeConverter) {}
359
360private:
361 LogicalResult
362 matchAndRewrite(gpu::AllocOp allocOp, OpAdaptor adaptor,
363 ConversionPatternRewriter &rewriter) const override;
364};
365
366/// A rewrite pattern to convert gpu.dealloc operations into a GPU runtime
367/// call. Currently it supports CUDA and ROCm (HIP).
368class ConvertDeallocOpToGpuRuntimeCallPattern
369 : public ConvertOpToGpuRuntimeCallPattern<gpu::DeallocOp> {
370public:
371 ConvertDeallocOpToGpuRuntimeCallPattern(
372 const LLVMTypeConverter &typeConverter)
373 : ConvertOpToGpuRuntimeCallPattern<gpu::DeallocOp>(typeConverter) {}
374
375private:
376 LogicalResult
377 matchAndRewrite(gpu::DeallocOp deallocOp, OpAdaptor adaptor,
378 ConversionPatternRewriter &rewriter) const override;
379};
380
381class ConvertAsyncYieldToGpuRuntimeCallPattern
382 : public ConvertOpToGpuRuntimeCallPattern<async::YieldOp> {
383public:
384 ConvertAsyncYieldToGpuRuntimeCallPattern(
385 const LLVMTypeConverter &typeConverter, PatternBenefit benefit = 1)
386 : ConvertOpToGpuRuntimeCallPattern<async::YieldOp>(typeConverter,
387 benefit) {}
388
389private:
390 LogicalResult
391 matchAndRewrite(async::YieldOp yieldOp, OpAdaptor adaptor,
392 ConversionPatternRewriter &rewriter) const override;
393};
394
395/// A rewrite pattern to convert gpu.wait operations into a GPU runtime
396/// call. Currently it supports CUDA and ROCm (HIP).
397class ConvertWaitOpToGpuRuntimeCallPattern
398 : public ConvertOpToGpuRuntimeCallPattern<gpu::WaitOp> {
399public:
400 ConvertWaitOpToGpuRuntimeCallPattern(const LLVMTypeConverter &typeConverter)
401 : ConvertOpToGpuRuntimeCallPattern<gpu::WaitOp>(typeConverter) {}
402
403private:
404 LogicalResult
405 matchAndRewrite(gpu::WaitOp waitOp, OpAdaptor adaptor,
406 ConversionPatternRewriter &rewriter) const override;
407};
408
409/// A rewrite pattern to convert gpu.wait async operations into a GPU runtime
410/// call. Currently it supports CUDA and ROCm (HIP).
411class ConvertWaitAsyncOpToGpuRuntimeCallPattern
412 : public ConvertOpToGpuRuntimeCallPattern<gpu::WaitOp> {
413public:
414 ConvertWaitAsyncOpToGpuRuntimeCallPattern(
415 const LLVMTypeConverter &typeConverter)
416 : ConvertOpToGpuRuntimeCallPattern<gpu::WaitOp>(typeConverter) {}
417
418private:
419 LogicalResult
420 matchAndRewrite(gpu::WaitOp waitOp, OpAdaptor adaptor,
421 ConversionPatternRewriter &rewriter) const override;
422};
423
424/// A rewrite patter to legalize gpu.launch_func with LLVM types.
425class LegalizeLaunchFuncOpPattern
426 : public ConvertOpToGpuRuntimeCallPattern<gpu::LaunchFuncOp> {
427public:
428 LegalizeLaunchFuncOpPattern(const LLVMTypeConverter &typeConverter,
429 bool kernelBarePtrCallConv,
430 bool kernelIntersperseSizeCallConv)
431 : ConvertOpToGpuRuntimeCallPattern<gpu::LaunchFuncOp>(typeConverter),
432 kernelBarePtrCallConv(kernelBarePtrCallConv),
433 kernelIntersperseSizeCallConv(kernelIntersperseSizeCallConv) {}
434
435private:
436 LogicalResult
437 matchAndRewrite(gpu::LaunchFuncOp launchOp, OpAdaptor adaptor,
438 ConversionPatternRewriter &rewriter) const override;
439
440 bool kernelBarePtrCallConv;
441 bool kernelIntersperseSizeCallConv;
442};
443
444/// A rewrite pattern to convert gpu.memcpy operations into a GPU runtime
445/// call. Currently it supports CUDA and ROCm (HIP).
446class ConvertMemcpyOpToGpuRuntimeCallPattern
447 : public ConvertOpToGpuRuntimeCallPattern<gpu::MemcpyOp> {
448public:
449 ConvertMemcpyOpToGpuRuntimeCallPattern(const LLVMTypeConverter &typeConverter)
450 : ConvertOpToGpuRuntimeCallPattern<gpu::MemcpyOp>(typeConverter) {}
451
452private:
453 LogicalResult
454 matchAndRewrite(gpu::MemcpyOp memcpyOp, OpAdaptor adaptor,
455 ConversionPatternRewriter &rewriter) const override;
456};
457
458/// A rewrite pattern to convert gpu.memset operations into a GPU runtime
459/// call. Currently it supports CUDA and ROCm (HIP).
460class ConvertMemsetOpToGpuRuntimeCallPattern
461 : public ConvertOpToGpuRuntimeCallPattern<gpu::MemsetOp> {
462public:
463 ConvertMemsetOpToGpuRuntimeCallPattern(const LLVMTypeConverter &typeConverter)
464 : ConvertOpToGpuRuntimeCallPattern<gpu::MemsetOp>(typeConverter) {}
465
466private:
467 LogicalResult
468 matchAndRewrite(gpu::MemsetOp memsetOp, OpAdaptor adaptor,
469 ConversionPatternRewriter &rewriter) const override;
470};
471
472/// A rewrite pattern to convert gpu.set_default_device to a GPU runtime call.
473/// Currently supports CUDA and ROCm (HIP)
474class ConvertSetDefaultDeviceOpToGpuRuntimeCallPattern
475 : public ConvertOpToGpuRuntimeCallPattern<gpu::SetDefaultDeviceOp> {
476public:
477 ConvertSetDefaultDeviceOpToGpuRuntimeCallPattern(
478 const LLVMTypeConverter &typeConverter)
479 : ConvertOpToGpuRuntimeCallPattern<gpu::SetDefaultDeviceOp>(
480 typeConverter) {}
481
482 LogicalResult
483 matchAndRewrite(gpu::SetDefaultDeviceOp op, OpAdaptor adaptor,
484 ConversionPatternRewriter &rewriter) const override;
485};
486
487/// Generic rewriting rule for operation on sparse matrices.
488/// Currently supports CUDA (by means of cuSparse and cuSparseLt).
489#define DECLARE_CONVERT_OP_TO_GPU_RUNTIME_CALL_PATTERN(op_name) \
490 class Convert##op_name##ToGpuRuntimeCallPattern \
491 : public ConvertOpToGpuRuntimeCallPattern<gpu::op_name> { \
492 public: \
493 Convert##op_name##ToGpuRuntimeCallPattern( \
494 const LLVMTypeConverter &typeConverter) \
495 : ConvertOpToGpuRuntimeCallPattern<gpu::op_name>(typeConverter) {} \
496 \
497 private: \
498 LogicalResult \
499 matchAndRewrite(gpu::op_name op, OpAdaptor adaptor, \
500 ConversionPatternRewriter &rewriter) const override; \
501 };
502
520DECLARE_CONVERT_OP_TO_GPU_RUNTIME_CALL_PATTERN(SpGEMMWorkEstimationOrComputeOp)
524
525} // namespace
526
527void GpuToLLVMConversionPass::runOnOperation() {
528 MLIRContext *context = &getContext();
529
530 // Perform progressive lowering of vector transfer operations.
531 {
532 RewritePatternSet patterns(&getContext());
533 // Vector transfer ops with rank > 1 should be lowered with VectorToSCF.
535 /*maxTransferRank=*/1);
536 // Transform N-D vector.from_elements to 1-D vector.from_elements before
537 // conversion.
538 vector::populateVectorFromElementsUnrollPatterns(patterns);
539 if (failed(applyPatternsGreedily(getOperation(), std::move(patterns))))
540 return signalPassFailure();
541 }
542
543 LowerToLLVMOptions options(context);
544 options.useBarePtrCallConv = hostBarePtrCallConv;
545 RewritePatternSet patterns(context);
546 ConversionTarget target(*context);
547 target.addLegalDialect<LLVM::LLVMDialect>();
548 LLVMTypeConverter converter(context, options);
549
550 // Populate all patterns from all dialects that implement the
551 // `ConvertToLLVMPatternInterface` interface.
552 std::vector<Dialect *> dialects = context->getLoadedDialects();
553 for (auto *iface :
554 llvm::make_isa_range<ConvertToLLVMPatternInterface>(dialects))
555 iface->populateConvertToLLVMConversionPatterns(target, converter, patterns);
556
557 // Preserve GPU modules and binaries. Modules are preserved as they can be
558 // converted later by `gpu-module-to-binary`.
559 target.addLegalOp<gpu::GPUModuleOp, gpu::BinaryOp>();
560 // Accept as legal LaunchFuncOps if the operands have been lowered.
561 target.addDynamicallyLegalOp<gpu::LaunchFuncOp>(
562 [&](gpu::LaunchFuncOp op) -> bool { return converter.isLegal(op); });
563
564 // These aren't covered by the ConvertToLLVMPatternInterface right now.
565 populateVectorToLLVMConversionPatterns(converter, patterns);
568 target);
569 populateGpuToLLVMConversionPatterns(converter, patterns,
570 kernelBarePtrCallConv,
571 kernelIntersperseSizeCallConv);
572
573 if (failed(
574 applyPartialConversion(getOperation(), target, std::move(patterns))))
575 signalPassFailure();
576}
577
579 ArrayRef<Value> arguments) const {
580 auto module = builder.getBlock()->getParent()->getParentOfType<ModuleOp>();
581 auto function = [&] {
582 if (auto function = module.lookupSymbol<LLVM::LLVMFuncOp>(functionName))
583 return function;
584 auto builder = OpBuilder::atBlockEnd(module.getBody());
585 return LLVM::LLVMFuncOp::create(builder, loc, functionName, functionType);
586 }();
587 return LLVM::CallOp::create(builder, loc, function, arguments);
588}
589
590// Corresponding to cusparseIndexType_t defined in cusparse.h.
591static int32_t getCuSparseIndexTypeFrom(Type type) {
592 if (type.isInteger(16))
593 return 1; // CUSPARSE_INDEX_16U
594 if (type.isInteger(32))
595 return 2; // CUSPARSE_INDEX_32I
596 return 3; // CUSPARSE_INDEX_64I
597}
598
599static int32_t getCuSparseLtDataTypeFrom(Type type) {
600 if (type.isF16())
601 return 0; // CUSPARSE_COMPUTE_16F,
602 if (type.isInteger(32))
603 return 1; // CUSPARSE_COMPUTE_32I
604 llvm_unreachable("unsupported type");
605 // TODO: add support to TF32
606}
607
608// Corresponding to cudaDataType_t defined in CUDA library_types.h.
609static int32_t getCuSparseDataTypeFrom(Type type) {
610 if (llvm::isa<ComplexType>(type)) {
611 // get the element type
612 auto elementType = cast<ComplexType>(type).getElementType();
613 if (elementType.isBF16())
614 return 15; // CUDA_C_16BF
615 if (elementType.isF16())
616 return 6; // CUDA_C_16F
617 if (elementType.isF32())
618 return 4; // CUDA_C_32F
619 if (elementType.isF64())
620 return 5; // CUDA_C_64F
621 if (elementType.isInteger(8))
622 return 7; // CUDA_C_8I
623 if (elementType.isInteger(16))
624 return 21; // CUDA_C_16I
625 if (elementType.isInteger(32))
626 return 11; // CUDA_C_32I
627 }
628 if (type.isBF16())
629 return 14; // CUDA_R_16BF
630 if (type.isF16())
631 return 2; // CUDA_R_16F
632 if (type.isF32())
633 return 0; // CUDA_R_32F
634 if (type.isF64())
635 return 1; // CUDA_R_64F
636 if (type.isInteger(8))
637 return 3; // CUDA_R_8I
638 if (type.isInteger(16))
639 return 20; // CUDA_R_16I
640 if (type.isInteger(32))
641 return 10; // CUDA_R_32I
642
643 llvm_unreachable("unsupported element type");
644}
645
646static gpu::Prune2To4SpMatFlag get2To4PruneFlag(Value spMat) {
647 return spMat.getDefiningOp<gpu::Create2To4SpMatOp>().getPruneFlag();
648}
649
650// TODO: We may want a run-time (of the mlir compiler) disablement/warning:
651// cusparseLt currently won't work for cuda architecture <8.0 and will trigger a
652// runtime (of the CUDA program) error , but it might be great if we could at
653// least output a warning when we found the target architecture is <8.0 and the
654// user still wants to use cusparseLt. to make sure when lowering gpu sparse
655// dialect to llvm calls, the cusparselt calls are disabled for cuda
656// architecture <8.0
657static bool is2To4Sparsity(Value spMat) {
658 if (auto op = spMat.getDefiningOp<gpu::Create2To4SpMatOp>())
659 return true;
660 if (auto op = spMat.getDefiningOp<gpu::CreateCooOp>())
661 return false;
662 if (auto op = spMat.getDefiningOp<gpu::CreateCooAoSOp>())
663 return false;
664 if (auto op = spMat.getDefiningOp<gpu::CreateCsrOp>())
665 return false;
666 if (auto op = spMat.getDefiningOp<gpu::CreateCscOp>())
667 return false;
668 if (auto op = spMat.getDefiningOp<gpu::CreateBsrOp>())
669 return false;
670 // Print the spMat defining op
671 spMat.getDefiningOp()->print(llvm::errs());
672 llvm_unreachable("cannot find spmat def");
673}
674
675static bool isSpMMCusparseLtOp(Value op) {
676 for (Operation *user : op.getUsers()) {
677 auto spmmOp = dyn_cast<gpu::SpMMOp>(user);
678 // If the other operator is 50% sparsity then we should use cusparseLt
679 if (!spmmOp)
680 continue;
681 if (is2To4Sparsity(spmmOp.getSpmatA()))
682 return true;
683 }
684 return false;
685}
686
687// Returns whether all operands are of LLVM type.
688static LogicalResult areAllLLVMTypes(Operation *op, ValueRange operands,
689 ConversionPatternRewriter &rewriter) {
690 if (!llvm::all_of(operands, [](Value value) {
691 return LLVM::isCompatibleType(value.getType());
692 }))
693 return rewriter.notifyMatchFailure(
694 op, "Cannot convert if operands aren't of LLVM type.");
695 return success();
696}
697
698static LogicalResult
699isAsyncWithOneDependency(ConversionPatternRewriter &rewriter,
700 gpu::AsyncOpInterface op) {
701 if (op.getAsyncDependencies().size() != 1)
702 return rewriter.notifyMatchFailure(
703 op, "Can only convert with exactly one async dependency.");
704
705 if (!op.getAsyncToken())
706 return rewriter.notifyMatchFailure(op, "Can convert only async version.");
707
708 return success();
709}
710
711LogicalResult ConvertHostRegisterOpToGpuRuntimeCallPattern::matchAndRewrite(
712 gpu::HostRegisterOp hostRegisterOp, OpAdaptor adaptor,
713 ConversionPatternRewriter &rewriter) const {
714 auto *op = hostRegisterOp.getOperation();
715 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)))
716 return failure();
717
718 Location loc = op->getLoc();
719
720 auto memRefType = hostRegisterOp.getValue().getType();
721 auto elementType = cast<UnrankedMemRefType>(memRefType).getElementType();
722 auto elementSize = getSizeInBytes(loc, elementType, rewriter);
723
724 auto arguments = getTypeConverter()->promoteOperands(
725 loc, op->getOperands(), adaptor.getOperands(), rewriter);
726 arguments.push_back(elementSize);
727 hostRegisterCallBuilder.create(loc, rewriter, arguments);
728
729 rewriter.eraseOp(op);
730 return success();
731}
732
733LogicalResult ConvertHostUnregisterOpToGpuRuntimeCallPattern::matchAndRewrite(
734 gpu::HostUnregisterOp hostUnregisterOp, OpAdaptor adaptor,
735 ConversionPatternRewriter &rewriter) const {
736 Operation *op = hostUnregisterOp.getOperation();
737 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)))
738 return failure();
739
740 Location loc = op->getLoc();
741
742 auto memRefType = hostUnregisterOp.getValue().getType();
743 auto elementType = cast<UnrankedMemRefType>(memRefType).getElementType();
744 auto elementSize = getSizeInBytes(loc, elementType, rewriter);
745
746 auto arguments = getTypeConverter()->promoteOperands(
747 loc, op->getOperands(), adaptor.getOperands(), rewriter);
748 arguments.push_back(elementSize);
749 hostUnregisterCallBuilder.create(loc, rewriter, arguments);
750
751 rewriter.eraseOp(op);
752 return success();
753}
754
755LogicalResult ConvertAllocOpToGpuRuntimeCallPattern::matchAndRewrite(
756 gpu::AllocOp allocOp, OpAdaptor adaptor,
757 ConversionPatternRewriter &rewriter) const {
758
759 MemRefType memRefType = allocOp.getType();
760
761 if (failed(areAllLLVMTypes(allocOp, adaptor.getOperands(), rewriter)) ||
762 !isConvertibleAndHasIdentityMaps(memRefType))
763 return failure();
764
765 auto loc = allocOp.getLoc();
766
767 bool isShared = allocOp.getHostShared();
768
769 if (isShared && allocOp.getAsyncToken())
770 return rewriter.notifyMatchFailure(
771 allocOp, "Host Shared allocation cannot be done async");
772 if (adaptor.getAsyncDependencies().size() > 1)
773 return rewriter.notifyMatchFailure(
774 allocOp, "Can convert with at most one async dependency.");
775
776 // Get shape of the memref as values: static sizes are constant
777 // values and dynamic sizes are passed to 'alloc' as operands.
778 SmallVector<Value, 4> shape;
779 SmallVector<Value, 4> strides;
780 Value sizeBytes;
781 getMemRefDescriptorSizes(loc, memRefType, adaptor.getDynamicSizes(), rewriter,
782 shape, strides, sizeBytes);
783
784 // Allocate the underlying buffer and store a pointer to it in the MemRef
785 // descriptor.
786 auto nullPtr = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPointerType);
787 Value stream = adaptor.getAsyncDependencies().empty()
788 ? nullPtr
789 : adaptor.getAsyncDependencies().front();
790
791 auto isHostShared = mlir::LLVM::ConstantOp::create(
792 rewriter, loc, llvmInt8Type, rewriter.getI8IntegerAttr(isShared));
793
794 Value allocatedPtr =
795 allocCallBuilder.create(loc, rewriter, {sizeBytes, stream, isHostShared})
796 .getResult();
797
798 // Cast the runtime-returned pointer to the memref's address space if it
799 // isn't there already, so it fits the descriptor's pointer slots.
800 unsigned dstAddrSpace =
801 *getTypeConverter()->getMemRefAddressSpace(memRefType);
802 unsigned srcAddrSpace =
803 cast<LLVM::LLVMPointerType>(allocatedPtr.getType()).getAddressSpace();
804 if (dstAddrSpace != srcAddrSpace) {
805 auto targetPtrTy =
806 LLVM::LLVMPointerType::get(rewriter.getContext(), dstAddrSpace);
807 allocatedPtr =
808 LLVM::AddrSpaceCastOp::create(rewriter, loc, targetPtrTy, allocatedPtr);
809 }
810
811 // No alignment.
812 Value alignedPtr = allocatedPtr;
813
814 // Create the MemRef descriptor.
815 auto memRefDescriptor = this->createMemRefDescriptor(
816 loc, memRefType, allocatedPtr, alignedPtr, shape, strides, rewriter);
817
818 if (allocOp.getAsyncToken()) {
819 // Async alloc: make dependent ops use the same stream.
820 rewriter.replaceOp(allocOp, {memRefDescriptor, stream});
821 } else {
822 rewriter.replaceOp(allocOp, {memRefDescriptor});
823 }
824
825 return success();
826}
827
828LogicalResult ConvertDeallocOpToGpuRuntimeCallPattern::matchAndRewrite(
829 gpu::DeallocOp deallocOp, OpAdaptor adaptor,
830 ConversionPatternRewriter &rewriter) const {
831 if (failed(areAllLLVMTypes(deallocOp, adaptor.getOperands(), rewriter)))
832 return failure();
833 if (adaptor.getAsyncDependencies().size() > 1)
834 return rewriter.notifyMatchFailure(
835 deallocOp, "Can convert with at most one async dependency.");
836
837 Location loc = deallocOp.getLoc();
838
839 Value pointer =
840 MemRefDescriptor(adaptor.getMemref()).allocatedPtr(rewriter, loc);
841 // The runtime frees a pointer in the default address space.
842 if (pointer.getType() != llvmPointerType)
843 pointer =
844 LLVM::AddrSpaceCastOp::create(rewriter, loc, llvmPointerType, pointer);
845 auto nullPtr = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPointerType);
846 Value stream = adaptor.getAsyncDependencies().empty()
847 ? nullPtr
848 : adaptor.getAsyncDependencies().front();
849 deallocCallBuilder.create(loc, rewriter, {pointer, stream});
850
851 if (deallocOp.getAsyncToken()) {
852 // Async dealloc: propagate the stream as the async token replacement.
853 rewriter.replaceOp(deallocOp, {stream});
854 } else {
855 // Sync dealloc: no results to replace, just remove the op.
856 rewriter.eraseOp(deallocOp);
857 }
858 return success();
859}
860
861static bool isGpuAsyncTokenType(Value value) {
862 return isa<gpu::AsyncTokenType>(value.getType());
863}
864
865// Converts !gpu.async.token operands of `async.yield` to runtime calls. The
866// !gpu.async.token are lowered to stream within the async.execute region, but
867// are passed as events between them. For each !gpu.async.token operand, we
868// create an event and record it on the stream.
869//
870// This pattern is registered with a higher benefit than the structural
871// async.yield rewriter from populateAsyncStructuralTypeConversionsAndLegality
872// so it wins when both match. Without that benefit override, the structural
873// pattern can win and silently retype gpu.async.token operands without
874// recording an event, leaving the host await to call cuEventSynchronize on
875// a stream pointer (a no-op that returns an error), racing the host against
876// the GPU.
877LogicalResult ConvertAsyncYieldToGpuRuntimeCallPattern::matchAndRewrite(
878 async::YieldOp yieldOp, OpAdaptor adaptor,
879 ConversionPatternRewriter &rewriter) const {
880 if (llvm::none_of(yieldOp.getOperands(), isGpuAsyncTokenType))
881 return rewriter.notifyMatchFailure(yieldOp, "no gpu async token operand");
882
883 Location loc = yieldOp.getLoc();
884 SmallVector<Value, 4> newOperands(adaptor.getOperands());
885 llvm::SmallDenseSet<Value> streams;
886 for (auto &operand : yieldOp->getOpOperands()) {
887 if (!isGpuAsyncTokenType(operand.get()))
888 continue;
889 auto idx = operand.getOperandNumber();
890 auto stream = adaptor.getOperands()[idx];
891 auto event = eventCreateCallBuilder.create(loc, rewriter, {}).getResult();
892 eventRecordCallBuilder.create(loc, rewriter, {event, stream});
893 newOperands[idx] = event;
894 streams.insert(stream);
895 }
896 for (auto stream : streams)
897 streamDestroyCallBuilder.create(loc, rewriter, {stream});
898
899 rewriter.modifyOpInPlace(yieldOp, [&] { yieldOp->setOperands(newOperands); });
900 return success();
901}
902
903// Returns whether `value` is the result of an LLVM::CallOp to `functionName`.
904static bool isDefinedByCallTo(Value value, StringRef functionName) {
905 assert(isa<LLVM::LLVMPointerType>(value.getType()));
906 if (auto defOp = value.getDefiningOp<LLVM::CallOp>())
907 return *defOp.getCallee() == functionName;
908 return false;
909}
910
911// Converts `gpu.wait` to runtime calls. The converted op synchronizes the host
912// with the stream/event operands. The operands are destroyed. That is, it
913// assumes that it is not used afterwards or elsewhere. Otherwise we will get a
914// runtime error. Eventually, we should guarantee this property.
915LogicalResult ConvertWaitOpToGpuRuntimeCallPattern::matchAndRewrite(
916 gpu::WaitOp waitOp, OpAdaptor adaptor,
917 ConversionPatternRewriter &rewriter) const {
918 if (waitOp.getAsyncToken())
919 return rewriter.notifyMatchFailure(waitOp, "Cannot convert async op.");
920
921 Location loc = waitOp.getLoc();
922
923 for (auto operand : adaptor.getOperands()) {
924 if (isDefinedByCallTo(operand, streamCreateCallBuilder.functionName)) {
925 // The converted operand's definition created a stream.
926 streamSynchronizeCallBuilder.create(loc, rewriter, {operand});
927 streamDestroyCallBuilder.create(loc, rewriter, {operand});
928 } else {
929 // Otherwise the converted operand is an event. This assumes that we use
930 // events in control flow code as well.
931 eventSynchronizeCallBuilder.create(loc, rewriter, {operand});
932 eventDestroyCallBuilder.create(loc, rewriter, {operand});
933 }
934 }
935
936 rewriter.eraseOp(waitOp);
937 return success();
938}
939
940// Converts `gpu.wait async` to runtime calls. The converted op creates a new
941// stream that is synchronized with stream/event operands. The operands are
942// destroyed. That is, it assumes that it is not used afterwards or elsewhere.
943// Otherwise we will get a runtime error. Eventually, we should guarantee this
944// property.
945LogicalResult ConvertWaitAsyncOpToGpuRuntimeCallPattern::matchAndRewrite(
946 gpu::WaitOp waitOp, OpAdaptor adaptor,
947 ConversionPatternRewriter &rewriter) const {
948 if (!waitOp.getAsyncToken())
949 return rewriter.notifyMatchFailure(waitOp, "Can only convert async op.");
950
951 Location loc = waitOp.getLoc();
952
953 auto insertionPoint = rewriter.saveInsertionPoint();
954 SmallVector<Value, 1> events;
955 for (auto pair :
956 llvm::zip(waitOp.getAsyncDependencies(), adaptor.getOperands())) {
957 auto operand = std::get<1>(pair);
958 if (isDefinedByCallTo(operand, streamCreateCallBuilder.functionName)) {
959 // The converted operand's definition created a stream. Insert an event
960 // into the stream just after the last use of the original token operand.
961 auto *defOp = std::get<0>(pair).getDefiningOp();
962 rewriter.setInsertionPointAfter(defOp);
963 auto event = eventCreateCallBuilder.create(loc, rewriter, {}).getResult();
964 eventRecordCallBuilder.create(loc, rewriter, {event, operand});
965 events.push_back(event);
966 } else {
967 // Otherwise the converted operand is an event. This assumes that we use
968 // events in control flow code as well.
969 events.push_back(operand);
970 }
971 }
972 rewriter.restoreInsertionPoint(insertionPoint);
973 auto stream = streamCreateCallBuilder.create(loc, rewriter, {}).getResult();
974 for (auto event : events)
975 streamWaitEventCallBuilder.create(loc, rewriter, {stream, event});
976 for (auto event : events)
977 eventDestroyCallBuilder.create(loc, rewriter, {event});
978 rewriter.replaceOp(waitOp, {stream});
979
980 return success();
981}
982
983// Legalize the op's operands.
984LogicalResult LegalizeLaunchFuncOpPattern::matchAndRewrite(
985 gpu::LaunchFuncOp launchOp, OpAdaptor adaptor,
986 ConversionPatternRewriter &rewriter) const {
987 if (failed(areAllLLVMTypes(launchOp, adaptor.getOperands(), rewriter)))
988 return failure();
989
990 // Fail when the synchronous version of the op has async dependencies. The
991 // lowering destroys the stream, and we do not want to check that there is no
992 // use of the stream after this op.
993 if (!launchOp.getAsyncToken() && !launchOp.getAsyncDependencies().empty())
994 return rewriter.notifyMatchFailure(
995 launchOp, "Cannot convert non-async op with async dependencies.");
996
997 Location loc = launchOp.getLoc();
998
999 Value stream = Value();
1000 if (!adaptor.getAsyncDependencies().empty()) {
1001 stream = adaptor.getAsyncDependencies().front();
1002 // Synchronize additional async dependencies onto the primary stream using
1003 // events, following the same approach as gpu.wait async lowering.
1004 if (adaptor.getAsyncDependencies().size() > 1) {
1005 auto insertionPoint = rewriter.saveInsertionPoint();
1006 SmallVector<Value, 4> events;
1007 for (auto [origDep, convertedDep] :
1008 llvm::zip(launchOp.getAsyncDependencies().drop_front(),
1009 adaptor.getAsyncDependencies().drop_front())) {
1010 if (!isDefinedByCallTo(convertedDep,
1011 streamCreateCallBuilder.functionName)) {
1012 events.push_back(convertedDep);
1013 continue;
1014 }
1015 Operation *defOp = origDep.getDefiningOp();
1016 rewriter.setInsertionPointAfter(defOp);
1017 Value event =
1018 eventCreateCallBuilder.create(loc, rewriter, {}).getResult();
1019 eventRecordCallBuilder.create(loc, rewriter, {event, convertedDep});
1020 events.push_back(event);
1021 }
1022 rewriter.restoreInsertionPoint(insertionPoint);
1023 for (Value event : events)
1024 streamWaitEventCallBuilder.create(loc, rewriter, {stream, event});
1025 for (Value event : events)
1026 eventDestroyCallBuilder.create(loc, rewriter, {event});
1027 }
1028 }
1029 // If the async keyword is present and there are no dependencies, then a
1030 // stream must be created to pass to subsequent operations.
1031 else if (launchOp.getAsyncToken())
1032 stream = streamCreateCallBuilder.create(loc, rewriter, {}).getResult();
1033
1034 // Lower the kernel operands to match kernel parameters.
1035 // Note: If `useBarePtrCallConv` is set in the type converter's options,
1036 // the value of `kernelBarePtrCallConv` will be ignored.
1037 OperandRange origArguments = launchOp.getKernelOperands();
1038 bool effectiveBarePtr = kernelBarePtrCallConv ||
1039 getTypeConverter()->getOptions().useBarePtrCallConv;
1040 if (effectiveBarePtr) {
1041 for (Value arg : origArguments) {
1042 if (isa<UnrankedMemRefType>(arg.getType()))
1043 return rewriter.notifyMatchFailure(
1044 loc, "unranked memref kernel argument is not supported with "
1045 "the bare-pointer calling convention");
1046 }
1047 }
1048 SmallVector<Value, 8> llvmArguments = getTypeConverter()->promoteOperands(
1049 loc, origArguments, adaptor.getKernelOperands(), rewriter,
1050 /*useBarePtrCallConv=*/kernelBarePtrCallConv);
1051 SmallVector<Value, 8> llvmArgumentsWithSizes;
1052
1053 // Intersperse size information if requested.
1054 if (kernelIntersperseSizeCallConv) {
1055 if (origArguments.size() != llvmArguments.size()) {
1056 // This shouldn't happen if the bare-pointer calling convention is used.
1057 return rewriter.notifyMatchFailure(
1058 launchOp,
1059 "Cannot add sizes to arguments with one-to-many LLVM IR expansion.");
1060 }
1061
1062 llvmArgumentsWithSizes.reserve(llvmArguments.size() * 2);
1063 for (auto [llvmArg, origArg] : zip_equal(llvmArguments, origArguments)) {
1064 auto memrefTy = dyn_cast<MemRefType>(origArg.getType());
1065 if (!memrefTy) {
1066 return rewriter.notifyMatchFailure(
1067 launchOp, "Operand to launch op is not a memref.");
1068 }
1069
1070 if (!memrefTy.hasStaticShape() ||
1071 !memrefTy.getElementType().isIntOrFloat()) {
1072 return rewriter.notifyMatchFailure(
1073 launchOp, "Operand to launch op is not a memref with a static "
1074 "shape and an integer or float element type.");
1075 }
1076
1077 unsigned bitwidth = memrefTy.getElementTypeBitWidth();
1078 if (bitwidth % 8 != 0) {
1079 return rewriter.notifyMatchFailure(
1080 launchOp, "Operand to launch op is not a memref with a "
1081 "byte-aligned element type.");
1082 }
1083
1084 uint64_t staticSize = static_cast<uint64_t>(bitwidth / 8) *
1085 static_cast<uint64_t>(memrefTy.getNumElements());
1086
1087 Value sizeArg =
1088 createIndexAttrConstant(rewriter, loc, getIndexType(), staticSize);
1089 llvmArgumentsWithSizes.push_back(llvmArg); // Presumably a bare pointer.
1090 llvmArgumentsWithSizes.push_back(sizeArg);
1091 }
1092 }
1093
1094 std::optional<gpu::KernelDim3> clusterSize = std::nullopt;
1095 if (launchOp.hasClusterSize()) {
1096 clusterSize =
1097 gpu::KernelDim3{adaptor.getClusterSizeX(), adaptor.getClusterSizeY(),
1098 adaptor.getClusterSizeZ()};
1099 }
1100 auto newLaunchOp = gpu::LaunchFuncOp::create(
1101 rewriter, launchOp.getLoc(), launchOp.getKernelAttr(),
1102 gpu::KernelDim3{adaptor.getGridSizeX(), adaptor.getGridSizeY(),
1103 adaptor.getGridSizeZ()},
1104 gpu::KernelDim3{adaptor.getBlockSizeX(), adaptor.getBlockSizeY(),
1105 adaptor.getBlockSizeZ()},
1106 adaptor.getDynamicSharedMemorySize(),
1107 llvmArgumentsWithSizes.empty() ? llvmArguments : llvmArgumentsWithSizes,
1108 nullptr, {}, stream, clusterSize);
1109 if (launchOp.getCooperative())
1110 newLaunchOp.setCooperative(true);
1111 if (launchOp.getAsyncToken())
1112 rewriter.replaceOp(launchOp, {stream});
1113 else
1114 rewriter.eraseOp(launchOp);
1115 return success();
1116}
1117
1119 ConversionPatternRewriter &rewriter,
1120 LLVM::LLVMPointerType destinationType,
1121 Value sourcePtr,
1122 const LLVMTypeConverter &typeConverter) {
1123 auto sourceTy = cast<LLVM::LLVMPointerType>(sourcePtr.getType());
1124 if (destinationType.getAddressSpace() != sourceTy.getAddressSpace())
1125 sourcePtr = LLVM::AddrSpaceCastOp::create(
1126 rewriter, loc,
1127 LLVM::LLVMPointerType::get(rewriter.getContext(),
1128 destinationType.getAddressSpace()),
1129 sourcePtr);
1130 return sourcePtr;
1131}
1132
1133LogicalResult ConvertMemcpyOpToGpuRuntimeCallPattern::matchAndRewrite(
1134 gpu::MemcpyOp memcpyOp, OpAdaptor adaptor,
1135 ConversionPatternRewriter &rewriter) const {
1136 auto memRefType = cast<MemRefType>(memcpyOp.getSrc().getType());
1137
1138 if (failed(areAllLLVMTypes(memcpyOp, adaptor.getOperands(), rewriter)) ||
1139 !isConvertibleAndHasIdentityMaps(memRefType) ||
1140 failed(isAsyncWithOneDependency(rewriter, memcpyOp)))
1141 return failure();
1142
1143 auto loc = memcpyOp.getLoc();
1144
1145 MemRefDescriptor srcDesc(adaptor.getSrc());
1146 Value numElements = getNumElements(rewriter, loc, memRefType, srcDesc);
1147
1148 Type elementPtrType = getElementPtrType(memRefType);
1149 Value nullPtr = LLVM::ZeroOp::create(rewriter, loc, elementPtrType);
1150 Value gepPtr = LLVM::GEPOp::create(
1151 rewriter, loc, elementPtrType,
1152 typeConverter->convertType(memRefType.getElementType()), nullPtr,
1153 numElements);
1154 auto sizeBytes =
1155 LLVM::PtrToIntOp::create(rewriter, loc, getIndexType(), gepPtr);
1156
1157 auto src = bitAndAddrspaceCast(loc, rewriter, llvmPointerType,
1158 srcDesc.alignedPtr(rewriter, loc),
1159 *getTypeConverter());
1160 auto dst = bitAndAddrspaceCast(
1161 loc, rewriter, llvmPointerType,
1162 MemRefDescriptor(adaptor.getDst()).alignedPtr(rewriter, loc),
1163 *getTypeConverter());
1164
1165 auto stream = adaptor.getAsyncDependencies().front();
1166 memcpyCallBuilder.create(loc, rewriter, {dst, src, sizeBytes, stream});
1167
1168 rewriter.replaceOp(memcpyOp, {stream});
1169
1170 return success();
1171}
1172
1173LogicalResult ConvertMemsetOpToGpuRuntimeCallPattern::matchAndRewrite(
1174 gpu::MemsetOp memsetOp, OpAdaptor adaptor,
1175 ConversionPatternRewriter &rewriter) const {
1176 auto memRefType = cast<MemRefType>(memsetOp.getDst().getType());
1177
1178 if (failed(areAllLLVMTypes(memsetOp, adaptor.getOperands(), rewriter)) ||
1179 !isConvertibleAndHasIdentityMaps(memRefType) ||
1180 failed(isAsyncWithOneDependency(rewriter, memsetOp)))
1181 return failure();
1182
1183 auto loc = memsetOp.getLoc();
1184
1185 Type valueType = adaptor.getValue().getType();
1186 unsigned bitWidth = valueType.getIntOrFloatBitWidth();
1187 // Ints and floats of 16 or 32 bit width are allowed.
1188 if (!valueType.isIntOrFloat() || (bitWidth != 16 && bitWidth != 32)) {
1189 return rewriter.notifyMatchFailure(
1190 memsetOp, "value must be a 16 or 32 bit int or float");
1191 }
1192
1193 unsigned valueTypeWidth = valueType.getIntOrFloatBitWidth();
1194 Type bitCastType = valueTypeWidth == 32 ? llvmInt32Type : llvmInt16Type;
1195
1196 MemRefDescriptor dstDesc(adaptor.getDst());
1197 Value numElements = getNumElements(rewriter, loc, memRefType, dstDesc);
1198
1199 auto value =
1200 LLVM::BitcastOp::create(rewriter, loc, bitCastType, adaptor.getValue());
1201 auto dst = bitAndAddrspaceCast(loc, rewriter, llvmPointerType,
1202 dstDesc.alignedPtr(rewriter, loc),
1203 *getTypeConverter());
1204
1205 auto stream = adaptor.getAsyncDependencies().front();
1206 FunctionCallBuilder builder =
1207 valueTypeWidth == 32 ? memset32CallBuilder : memset16CallBuilder;
1208 builder.create(loc, rewriter, {dst, value, numElements, stream});
1209
1210 rewriter.replaceOp(memsetOp, {stream});
1211 return success();
1212}
1213
1214LogicalResult ConvertSetDefaultDeviceOpToGpuRuntimeCallPattern::matchAndRewrite(
1215 gpu::SetDefaultDeviceOp op, OpAdaptor adaptor,
1216 ConversionPatternRewriter &rewriter) const {
1217 Location loc = op.getLoc();
1218 auto call = setDefaultDeviceCallBuilder.create(loc, rewriter,
1219 {adaptor.getDevIndex()});
1220 rewriter.replaceOp(op, call);
1221 return success();
1222}
1223
1224template <typename T>
1225static Value genConstInt32From(OpBuilder &builder, Location loc, T tValue) {
1226 Type llvmInt32Type = builder.getIntegerType(32);
1227 return LLVM::ConstantOp::create(builder, loc, llvmInt32Type,
1228 static_cast<int32_t>(tValue));
1229}
1230
1231LogicalResult ConvertCreateDnTensorOpToGpuRuntimeCallPattern::matchAndRewrite(
1232 gpu::CreateDnTensorOp op, OpAdaptor adaptor,
1233 ConversionPatternRewriter &rewriter) const {
1234 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1235 failed(isAsyncWithOneDependency(rewriter, op)))
1236 return failure();
1237 Location loc = op.getLoc();
1238 auto stream = adaptor.getAsyncDependencies().front();
1239 Value pTensor =
1240 MemRefDescriptor(adaptor.getMemref()).allocatedPtr(rewriter, loc);
1241 Type dType = op.getMemref().getType().getElementType();
1242 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1243
1244 SmallVector<Value, 4> dims;
1245 for (Value dim : adaptor.getDims()) {
1246 dims.push_back(dim);
1247 }
1248
1249 Value handle;
1250 // TODO: For now, we track the use of the handle and lower it to cusparse /
1251 // cusparseLt accordingly. If in a block, both cusparse and cusparseLt are
1252 // used, we require two separate Creation ops to be the correct logic. In
1253 // future, we may add support to using one handle in sparse tensor / GPU
1254 // dialect in both cusparse and cusparseLt. use the cusparseLt create call if
1255 // the dnmat is used with spmat with 2:4 sparsity
1256 if (dims.size() == 2) {
1257 if (isSpMMCusparseLtOp(op.getDnTensor())) {
1258 auto handleSz =
1259 createIndexAttrConstant(rewriter, loc, getIndexType(), 11032);
1260 handle = LLVM::AllocaOp::create(rewriter, loc, llvmPointerType,
1261 llvmInt8Type, handleSz, /*alignment=*/16);
1262 handle = LLVM::BitcastOp::create(rewriter, loc, llvmPointerType, handle);
1263
1264 createLtDnMatCallBuilder
1265 .create(loc, rewriter,
1266 {handle, dims[0], dims[1], pTensor, dtp, stream})
1267 .getResult();
1268 } else {
1269 handle =
1270 createDnMatCallBuilder
1271 .create(loc, rewriter, {dims[0], dims[1], pTensor, dtp, stream})
1272 .getResult();
1273 }
1274 } else {
1275 assert(dims.size() == 1 && "Only 1D and 2D tensors are supported");
1276 handle = createDnVecCallBuilder
1277 .create(loc, rewriter, {dims[0], pTensor, dtp, stream})
1278 .getResult();
1279 }
1280 rewriter.replaceOp(op, {handle, stream});
1281 return success();
1282}
1283
1284LogicalResult ConvertDestroyDnTensorOpToGpuRuntimeCallPattern::matchAndRewrite(
1285 gpu::DestroyDnTensorOp op, OpAdaptor adaptor,
1286 ConversionPatternRewriter &rewriter) const {
1287 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1288 failed(isAsyncWithOneDependency(rewriter, op)))
1289 return failure();
1290 Location loc = op.getLoc();
1291 auto stream = adaptor.getAsyncDependencies().front();
1292 auto definingOp = op.getDnTensor().getDefiningOp<gpu::CreateDnTensorOp>();
1293 SmallVector<Value, 4> dims;
1294 for (Value dim : definingOp.getDims()) {
1295 dims.push_back(dim);
1296 }
1297 if (dims.size() == 2) {
1298 // Use the cusparseLt destroy call if the dnmat is used with spmat with
1299 // 2:4 sparsity
1300 if (isSpMMCusparseLtOp(op.getDnTensor())) {
1301 destroyCuSparseLtDnMatBuilder.create(loc, rewriter,
1302 {adaptor.getDnTensor(), stream});
1303 } else {
1304 destroyDnMatCallBuilder.create(loc, rewriter,
1305 {adaptor.getDnTensor(), stream});
1306 }
1307 } else {
1308 assert(dims.size() == 1 && "Only 1D and 2D tensors are supported");
1309 destroyDnVecCallBuilder.create(loc, rewriter,
1310 {adaptor.getDnTensor(), stream});
1311 }
1312 rewriter.replaceOp(op, {stream});
1313 return success();
1314}
1315
1316LogicalResult ConvertCreateCooOpToGpuRuntimeCallPattern::matchAndRewrite(
1317 gpu::CreateCooOp op, OpAdaptor adaptor,
1318 ConversionPatternRewriter &rewriter) const {
1319 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1320 failed(isAsyncWithOneDependency(rewriter, op)))
1321 return failure();
1322 Location loc = op.getLoc();
1323 auto stream = adaptor.getAsyncDependencies().front();
1324 Value pRowIdxs =
1325 MemRefDescriptor(adaptor.getRowIdxs()).allocatedPtr(rewriter, loc);
1326 Value pColIdxs =
1327 MemRefDescriptor(adaptor.getColIdxs()).allocatedPtr(rewriter, loc);
1328 Value pValues =
1329 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1330 Type iType =
1331 llvm::cast<MemRefType>(op.getColIdxs().getType()).getElementType();
1332 Type dType =
1333 llvm::cast<MemRefType>(op.getValues().getType()).getElementType();
1334 auto itp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(iType));
1335 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1336 auto handle =
1337 createCooCallBuilder
1338 .create(loc, rewriter,
1339 {adaptor.getRows(), adaptor.getCols(), adaptor.getNnz(),
1340 pRowIdxs, pColIdxs, pValues, itp, dtp, stream})
1341 .getResult();
1342 rewriter.replaceOp(op, {handle, stream});
1343 return success();
1344}
1345
1346LogicalResult ConvertCreateCooAoSOpToGpuRuntimeCallPattern::matchAndRewrite(
1347 gpu::CreateCooAoSOp op, OpAdaptor adaptor,
1348 ConversionPatternRewriter &rewriter) const {
1349 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1350 failed(isAsyncWithOneDependency(rewriter, op)))
1351 return failure();
1352 Location loc = op.getLoc();
1353 auto stream = adaptor.getAsyncDependencies().front();
1354 Value pIdxs = MemRefDescriptor(adaptor.getIdxs()).allocatedPtr(rewriter, loc);
1355 Value pValues =
1356 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1357 Type iType = llvm::cast<MemRefType>(op.getIdxs().getType()).getElementType();
1358 Type dType =
1359 llvm::cast<MemRefType>(op.getValues().getType()).getElementType();
1360 auto itp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(iType));
1361 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1362 auto handle =
1363 createCooAoSCallBuilder
1364 .create(loc, rewriter,
1365 {adaptor.getRows(), adaptor.getCols(), adaptor.getNnz(),
1366 pIdxs, pValues, itp, dtp, stream})
1367 .getResult();
1368 rewriter.replaceOp(op, {handle, stream});
1369 return success();
1370}
1371
1372LogicalResult ConvertCreateCsrOpToGpuRuntimeCallPattern::matchAndRewrite(
1373 gpu::CreateCsrOp op, OpAdaptor adaptor,
1374 ConversionPatternRewriter &rewriter) const {
1375 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1376 failed(isAsyncWithOneDependency(rewriter, op)))
1377 return failure();
1378 Location loc = op.getLoc();
1379 auto stream = adaptor.getAsyncDependencies().front();
1380 Value pRowPos =
1381 MemRefDescriptor(adaptor.getRowPos()).allocatedPtr(rewriter, loc);
1382 Value pColIdxs =
1383 MemRefDescriptor(adaptor.getColIdxs()).allocatedPtr(rewriter, loc);
1384 Value pValues =
1385 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1386 Type pType =
1387 llvm::cast<MemRefType>(op.getRowPos().getType()).getElementType();
1388 Type iType =
1389 llvm::cast<MemRefType>(op.getColIdxs().getType()).getElementType();
1390 Type dType =
1391 llvm::cast<MemRefType>(op.getValues().getType()).getElementType();
1392 auto ptp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(pType));
1393 auto itp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(iType));
1394 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1395 auto handle =
1396 createCsrCallBuilder
1397 .create(loc, rewriter,
1398 {adaptor.getRows(), adaptor.getCols(), adaptor.getNnz(),
1399 pRowPos, pColIdxs, pValues, ptp, itp, dtp, stream})
1400 .getResult();
1401 rewriter.replaceOp(op, {handle, stream});
1402 return success();
1403}
1404
1405LogicalResult ConvertCreate2To4SpMatOpToGpuRuntimeCallPattern::matchAndRewrite(
1406 gpu::Create2To4SpMatOp op, OpAdaptor adaptor,
1407 ConversionPatternRewriter &rewriter) const {
1408 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1409 failed(isAsyncWithOneDependency(rewriter, op)))
1410 return failure();
1411 Location loc = op.getLoc();
1412 auto stream = adaptor.getAsyncDependencies().front();
1413 Value pMat =
1414 MemRefDescriptor(adaptor.getMemref()).allocatedPtr(rewriter, loc);
1415 Type dType =
1416 llvm::cast<MemRefType>(op.getMemref().getType()).getElementType();
1417 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1418
1419 // CUDA runner asserts the size is 44104 bytes.
1420 auto handleSz = createIndexAttrConstant(rewriter, loc, getIndexType(), 44104);
1421 Value handle = LLVM::AllocaOp::create(
1422 rewriter, loc, llvmPointerType, llvmInt8Type, handleSz, /*alignment=*/16);
1423 handle = LLVM::BitcastOp::create(rewriter, loc, llvmPointerType, handle);
1424
1425 create2To4SpMatCallBuilder
1426 .create(loc, rewriter,
1427 {handle, adaptor.getRows(), adaptor.getCols(), pMat, dtp, stream})
1428 .getResult();
1429 rewriter.replaceOp(op, {handle, stream});
1430 return success();
1431}
1432
1433LogicalResult ConvertDestroySpMatOpToGpuRuntimeCallPattern::matchAndRewrite(
1434 gpu::DestroySpMatOp op, OpAdaptor adaptor,
1435 ConversionPatternRewriter &rewriter) const {
1436 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1437 failed(isAsyncWithOneDependency(rewriter, op)))
1438 return failure();
1439 Location loc = op.getLoc();
1440 auto stream = adaptor.getAsyncDependencies().front();
1441 // Use the cusparseLt destroy call if the spmat is 2:4 sparsity
1442 if (is2To4Sparsity(op.getSpmat())) {
1443 destroyCuSparseLtSpMatBuilder.create(loc, rewriter,
1444 {adaptor.getSpmat(), stream});
1445
1446 } else {
1447 destroySpMatCallBuilder.create(loc, rewriter, {adaptor.getSpmat(), stream});
1448 }
1449 rewriter.replaceOp(op, {stream});
1450 return success();
1451}
1452
1453LogicalResult ConvertSpMVBufferSizeOpToGpuRuntimeCallPattern::matchAndRewrite(
1454 gpu::SpMVBufferSizeOp op, OpAdaptor adaptor,
1455 ConversionPatternRewriter &rewriter) const {
1456 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1457 failed(isAsyncWithOneDependency(rewriter, op)))
1458 return failure();
1459 Location loc = op.getLoc();
1460 auto modeA = genConstInt32From(rewriter, loc, op.getModeA());
1461 auto computeType = genConstInt32From(
1462 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1463 auto stream = adaptor.getAsyncDependencies().front();
1464 auto bufferSize = spMVBufferSizeCallBuilder
1465 .create(loc, rewriter,
1466 {modeA, adaptor.getSpmatA(), adaptor.getDnX(),
1467 adaptor.getDnY(), computeType, stream})
1468 .getResult();
1469 rewriter.replaceOp(op, {bufferSize, stream});
1470 return success();
1471}
1472
1473LogicalResult ConvertSpMVOpToGpuRuntimeCallPattern::matchAndRewrite(
1474 gpu::SpMVOp op, OpAdaptor adaptor,
1475 ConversionPatternRewriter &rewriter) const {
1476 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1477 failed(isAsyncWithOneDependency(rewriter, op)))
1478 return failure();
1479 Location loc = op.getLoc();
1480 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1481 auto computeType = genConstInt32From(
1482 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1483 auto stream = adaptor.getAsyncDependencies().front();
1484 Value pBuf =
1485 MemRefDescriptor(adaptor.getBuffer()).allocatedPtr(rewriter, loc);
1486 spMVCallBuilder.create(loc, rewriter,
1487 {modeA, adaptor.getSpmatA(), adaptor.getDnX(),
1488 adaptor.getDnY(), computeType, pBuf, stream});
1489 rewriter.replaceOp(op, {stream});
1490 return success();
1491}
1492
1493LogicalResult ConvertSpMMBufferSizeOpToGpuRuntimeCallPattern::matchAndRewrite(
1494 gpu::SpMMBufferSizeOp op, OpAdaptor adaptor,
1495 ConversionPatternRewriter &rewriter) const {
1496 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1497 failed(isAsyncWithOneDependency(rewriter, op)))
1498 return failure();
1499 Location loc = op.getLoc();
1500 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1501 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1502 auto stream = adaptor.getAsyncDependencies().front();
1503 Value bufferSize;
1504 if (is2To4Sparsity(op.getSpmatA())) {
1505 auto pruneFlag =
1506 genConstInt32From(rewriter, loc, get2To4PruneFlag(op.getSpmatA()));
1507 auto computeType = genConstInt32From(
1508 rewriter, loc, getCuSparseLtDataTypeFrom(adaptor.getComputeType()));
1509 auto three = createIndexAttrConstant(rewriter, loc, getIndexType(), 3);
1510 auto bufferSize =
1511 LLVM::AllocaOp::create(rewriter, loc, llvmPointerType, llvmPointerType,
1512 three, /*alignment=*/16);
1513 createCuSparseLtSpMMBufferSizeBuilder
1514 .create(loc, rewriter,
1515 {bufferSize, modeA, modeB, adaptor.getSpmatA(),
1516 adaptor.getDnmatB(), adaptor.getDnmatC(), computeType,
1517 pruneFlag, stream})
1518 .getResult();
1519
1520 auto bufferSizePtr1 = LLVM::GEPOp::create(
1521 rewriter, loc, llvmPointerType, llvmPointerType, bufferSize,
1522 ValueRange{createIndexAttrConstant(rewriter, loc, getIndexType(), 1)});
1523 auto bufferSizePtr2 = LLVM::GEPOp::create(
1524 rewriter, loc, llvmPointerType, llvmPointerType, bufferSize,
1525 ValueRange{createIndexAttrConstant(rewriter, loc, getIndexType(), 2)});
1526 auto bufferSize0 =
1527 LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, bufferSize);
1528 auto bufferSize1 =
1529 LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, bufferSizePtr1);
1530 auto bufferSize2 =
1531 LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, bufferSizePtr2);
1532
1533 rewriter.replaceOp(op, {bufferSize0, bufferSize1, bufferSize2, stream});
1534 } else {
1535 auto computeType = genConstInt32From(
1536 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1537 bufferSize =
1538 createSpMMBufferSizeCallBuilder
1539 .create(loc, rewriter,
1540 {modeA, modeB, adaptor.getSpmatA(), adaptor.getDnmatB(),
1541 adaptor.getDnmatC(), computeType, stream})
1542 .getResult();
1543 rewriter.replaceOp(op, {bufferSize, stream});
1544 }
1545 return success();
1546}
1547
1548LogicalResult ConvertSDDMMBufferSizeOpToGpuRuntimeCallPattern::matchAndRewrite(
1549 gpu::SDDMMBufferSizeOp op, OpAdaptor adaptor,
1550 ConversionPatternRewriter &rewriter) const {
1551 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1552 failed(isAsyncWithOneDependency(rewriter, op)))
1553 return failure();
1554 Location loc = op.getLoc();
1555 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1556 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1557 auto computeType = genConstInt32From(
1558 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1559 auto stream = adaptor.getAsyncDependencies().front();
1560 auto bufferSize =
1561 createSDDMMBufferSizeCallBuilder
1562 .create(loc, rewriter,
1563 {modeA, modeB, adaptor.getDnmatA(), adaptor.getDnmatB(),
1564 adaptor.getSpmatC(), computeType, stream})
1565 .getResult();
1566 rewriter.replaceOp(op, {bufferSize, stream});
1567 return success();
1568}
1569
1570LogicalResult ConvertSpMMOpToGpuRuntimeCallPattern::matchAndRewrite(
1571 gpu::SpMMOp op, OpAdaptor adaptor,
1572 ConversionPatternRewriter &rewriter) const {
1573 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1574 failed(isAsyncWithOneDependency(rewriter, op)))
1575 return failure();
1576 Location loc = op.getLoc();
1577 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1578 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1579 auto computeType = genConstInt32From(
1580 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1581
1582 auto stream = adaptor.getAsyncDependencies().front();
1583
1584 // Lower to cusparseLt if applicable
1585 if (is2To4Sparsity(op.getSpmatA())) {
1586 SmallVector<Value> pBufs;
1587 for (Value buffer : adaptor.getBuffers()) {
1588 Value pBuf = MemRefDescriptor(buffer).allocatedPtr(rewriter, loc);
1589 pBufs.push_back(pBuf);
1590 }
1591 createCuSparseLtSpMMBuilder.create(
1592 loc, rewriter,
1593 {adaptor.getSpmatA(), adaptor.getDnmatB(), adaptor.getDnmatC(),
1594 pBufs[0], pBufs[1], pBufs[2], stream});
1595 } else {
1596 Value pBuf = MemRefDescriptor(adaptor.getBuffers().front())
1597 .allocatedPtr(rewriter, loc);
1598 createSpMMCallBuilder.create(loc, rewriter,
1599 {modeA, modeB, adaptor.getSpmatA(),
1600 adaptor.getDnmatB(), adaptor.getDnmatC(),
1601 computeType, pBuf, stream});
1602 }
1603 rewriter.replaceOp(op, {stream});
1604 return success();
1605}
1606
1607template <typename T>
1609 converter.addConversion([&converter](T) -> Type {
1610 return LLVM::LLVMPointerType::get(&converter.getContext());
1611 });
1612}
1613
1614LogicalResult ConvertSDDMMOpToGpuRuntimeCallPattern::matchAndRewrite(
1615 gpu::SDDMMOp op, OpAdaptor adaptor,
1616 ConversionPatternRewriter &rewriter) const {
1617 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1618 failed(isAsyncWithOneDependency(rewriter, op)))
1619 return failure();
1620 Location loc = op.getLoc();
1621 auto computeType = genConstInt32From(
1622 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1623 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1624 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1625 auto stream = adaptor.getAsyncDependencies().front();
1626 Value pBuf =
1627 MemRefDescriptor(adaptor.getBuffer()).allocatedPtr(rewriter, loc);
1628 createSDDMMCallBuilder.create(loc, rewriter,
1629 {modeA, modeB, adaptor.getDnmatA(),
1630 adaptor.getDnmatB(), adaptor.getSpmatC(),
1631 computeType, pBuf, stream});
1632 rewriter.replaceOp(op, {stream});
1633 return success();
1634}
1635
1636LogicalResult
1637ConvertSpGEMMCreateDescrOpToGpuRuntimeCallPattern::matchAndRewrite(
1638 gpu::SpGEMMCreateDescrOp op, OpAdaptor adaptor,
1639 ConversionPatternRewriter &rewriter) const {
1640 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1641 failed(isAsyncWithOneDependency(rewriter, op)))
1642 return failure();
1643 Location loc = op.getLoc();
1644 auto stream = adaptor.getAsyncDependencies().front();
1645 Value descr = createSpGEMMCreateDescrBuilder.create(loc, rewriter, {stream})
1646 .getResult();
1647 rewriter.replaceOp(op, {descr, stream});
1648 return success();
1649}
1650
1651LogicalResult
1652ConvertSpGEMMDestroyDescrOpToGpuRuntimeCallPattern::matchAndRewrite(
1653 gpu::SpGEMMDestroyDescrOp op, OpAdaptor adaptor,
1654 ConversionPatternRewriter &rewriter) const {
1655 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1656 failed(isAsyncWithOneDependency(rewriter, op)))
1657 return failure();
1658 Location loc = op.getLoc();
1659 auto stream = adaptor.getAsyncDependencies().front();
1660 createSpGEMMDestroyDescrBuilder.create(loc, rewriter,
1661 {adaptor.getDesc(), stream});
1662 rewriter.replaceOp(op, {stream});
1663 return success();
1664}
1665
1666LogicalResult
1667ConvertSpGEMMWorkEstimationOrComputeOpToGpuRuntimeCallPattern::matchAndRewrite(
1668 gpu::SpGEMMWorkEstimationOrComputeOp op, OpAdaptor adaptor,
1669 ConversionPatternRewriter &rewriter) const {
1670 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1671 failed(isAsyncWithOneDependency(rewriter, op)))
1672 return failure();
1673 Location loc = op.getLoc();
1674 auto computeType = genConstInt32From(
1675 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1676 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1677 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1678 auto stream = adaptor.getAsyncDependencies().front();
1679
1680 Value pBuf =
1681 MemRefDescriptor(adaptor.getBuffer()).allocatedPtr(rewriter, loc);
1682 Value bufferSizeNew;
1683
1684 if (adaptor.getKind() ==
1685 gpu::SpGEMMWorkEstimationOrComputeKind::WORK_ESTIMATION) {
1686 bufferSizeNew =
1687 createSpGEMMWorkEstimationBuilder
1688 .create(loc, rewriter,
1689 {adaptor.getDesc(), modeA, modeB, adaptor.getSpmatA(),
1690 adaptor.getSpmatB(), adaptor.getSpmatC(), computeType,
1691 adaptor.getBufferSz(), pBuf, stream})
1692 .getResult();
1693 } else {
1694 bufferSizeNew =
1695 createSpGEMMComputeBuilder
1696 .create(loc, rewriter,
1697 {adaptor.getDesc(), modeA, modeB, adaptor.getSpmatA(),
1698 adaptor.getSpmatB(), adaptor.getSpmatC(), computeType,
1699 adaptor.getBufferSz(), pBuf, stream})
1700 .getResult();
1701 }
1702 rewriter.replaceOp(op, {bufferSizeNew, stream});
1703 return success();
1704}
1705
1706LogicalResult ConvertSpGEMMCopyOpToGpuRuntimeCallPattern::matchAndRewrite(
1707 gpu::SpGEMMCopyOp op, OpAdaptor adaptor,
1708 ConversionPatternRewriter &rewriter) const {
1709 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1710 failed(isAsyncWithOneDependency(rewriter, op)))
1711 return failure();
1712 Location loc = op.getLoc();
1713 auto computeType = genConstInt32From(
1714 rewriter, loc, getCuSparseDataTypeFrom(adaptor.getComputeType()));
1715 auto modeA = genConstInt32From(rewriter, loc, adaptor.getModeA());
1716 auto modeB = genConstInt32From(rewriter, loc, adaptor.getModeB());
1717 auto stream = adaptor.getAsyncDependencies().front();
1718 createSpGEMMCopyBuilder.create(loc, rewriter,
1719 {adaptor.getDesc(), modeA, modeB,
1720 adaptor.getSpmatA(), adaptor.getSpmatB(),
1721 adaptor.getSpmatC(), computeType, stream});
1722 rewriter.replaceOp(op, {stream});
1723 return success();
1724}
1725
1726LogicalResult ConvertSpMatGetSizeOpToGpuRuntimeCallPattern::matchAndRewrite(
1727 gpu::SpMatGetSizeOp op, OpAdaptor adaptor,
1728 ConversionPatternRewriter &rewriter) const {
1729 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1730 failed(isAsyncWithOneDependency(rewriter, op)))
1731 return failure();
1732 Location loc = op.getLoc();
1733 auto stream = adaptor.getAsyncDependencies().front();
1734
1735 auto three = createIndexAttrConstant(rewriter, loc, getIndexType(), 3);
1736 auto buffer = LLVM::AllocaOp::create(rewriter, loc, llvmPointerType,
1737 llvmInt64Type, three, /*alignment=*/16);
1738
1739 auto rowsPtr = LLVM::GEPOp::create(
1740 rewriter, loc, llvmPointerType, llvmPointerType, buffer,
1741 ValueRange{createIndexAttrConstant(rewriter, loc, getIndexType(), 0)});
1742 auto colsPtr = LLVM::GEPOp::create(
1743 rewriter, loc, llvmPointerType, llvmPointerType, buffer,
1744 ValueRange{createIndexAttrConstant(rewriter, loc, getIndexType(), 1)});
1745 auto nnzsPtr = LLVM::GEPOp::create(
1746 rewriter, loc, llvmPointerType, llvmPointerType, buffer,
1747 ValueRange{createIndexAttrConstant(rewriter, loc, getIndexType(), 2)});
1748 createSpMatGetSizeBuilder.create(
1749 loc, rewriter, {adaptor.getSpmat(), rowsPtr, colsPtr, nnzsPtr, stream});
1750 auto rows = LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, rowsPtr);
1751 auto cols = LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, colsPtr);
1752 auto nnzs = LLVM::LoadOp::create(rewriter, loc, llvmInt64Type, nnzsPtr);
1753
1754 rewriter.replaceOp(op, {rows, cols, nnzs, stream});
1755 return success();
1756}
1757
1758LogicalResult ConvertSetCsrPointersOpToGpuRuntimeCallPattern::matchAndRewrite(
1759 gpu::SetCsrPointersOp op, OpAdaptor adaptor,
1760 ConversionPatternRewriter &rewriter) const {
1761 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1762 failed(isAsyncWithOneDependency(rewriter, op)))
1763 return failure();
1764 Location loc = op.getLoc();
1765 auto stream = adaptor.getAsyncDependencies().front();
1766 Value pPos =
1767 MemRefDescriptor(adaptor.getPositions()).allocatedPtr(rewriter, loc);
1768 Value pCrd =
1769 MemRefDescriptor(adaptor.getCoordinates()).allocatedPtr(rewriter, loc);
1770 Value pVal =
1771 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1772 createSetCsrPointersBuilder.create(
1773 loc, rewriter, {adaptor.getSpmat(), pPos, pCrd, pVal, stream});
1774 rewriter.replaceOp(op, {stream});
1775 return success();
1776}
1777
1778LogicalResult ConvertCreateCscOpToGpuRuntimeCallPattern::matchAndRewrite(
1779 gpu::CreateCscOp op, OpAdaptor adaptor,
1780 ConversionPatternRewriter &rewriter) const {
1781 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1782 failed(isAsyncWithOneDependency(rewriter, op)))
1783 return failure();
1784 Location loc = op.getLoc();
1785 auto stream = adaptor.getAsyncDependencies().front();
1786 Value pColPos =
1787 MemRefDescriptor(adaptor.getColPos()).allocatedPtr(rewriter, loc);
1788 Value pRowIdxs =
1789 MemRefDescriptor(adaptor.getRowIdxs()).allocatedPtr(rewriter, loc);
1790 Value pValues =
1791 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1792 Type pType =
1793 llvm::cast<MemRefType>(op.getColPos().getType()).getElementType();
1794 Type iType =
1795 llvm::cast<MemRefType>(op.getRowIdxs().getType()).getElementType();
1796 Type dType =
1797 llvm::cast<MemRefType>(op.getValues().getType()).getElementType();
1798 auto ptp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(pType));
1799 auto itp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(iType));
1800 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1801 auto handle =
1802 createCscCallBuilder
1803 .create(loc, rewriter,
1804 {adaptor.getRows(), adaptor.getCols(), adaptor.getNnz(),
1805 pColPos, pRowIdxs, pValues, ptp, itp, dtp, stream})
1806 .getResult();
1807 rewriter.replaceOp(op, {handle, stream});
1808 return success();
1809}
1810
1811LogicalResult ConvertCreateBsrOpToGpuRuntimeCallPattern::matchAndRewrite(
1812 gpu::CreateBsrOp op, OpAdaptor adaptor,
1813 ConversionPatternRewriter &rewriter) const {
1814 if (failed(areAllLLVMTypes(op, adaptor.getOperands(), rewriter)) ||
1815 failed(isAsyncWithOneDependency(rewriter, op)))
1816 return failure();
1817 Location loc = op.getLoc();
1818 auto stream = adaptor.getAsyncDependencies().front();
1819 Value pRowPos =
1820 MemRefDescriptor(adaptor.getBRowPos()).allocatedPtr(rewriter, loc);
1821 Value pColIdxs =
1822 MemRefDescriptor(adaptor.getBColIdxs()).allocatedPtr(rewriter, loc);
1823 Value pValues =
1824 MemRefDescriptor(adaptor.getValues()).allocatedPtr(rewriter, loc);
1825 Type pType =
1826 llvm::cast<MemRefType>(op.getBRowPos().getType()).getElementType();
1827 Type iType =
1828 llvm::cast<MemRefType>(op.getBColIdxs().getType()).getElementType();
1829 Type dType =
1830 llvm::cast<MemRefType>(op.getValues().getType()).getElementType();
1831 auto ptp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(pType));
1832 auto itp = genConstInt32From(rewriter, loc, getCuSparseIndexTypeFrom(iType));
1833 auto dtp = genConstInt32From(rewriter, loc, getCuSparseDataTypeFrom(dType));
1834 auto handle =
1835 createBsrCallBuilder
1836 .create(loc, rewriter,
1837 {adaptor.getBrows(), adaptor.getBcols(), adaptor.getBnnz(),
1838 adaptor.getRBlockSize(), adaptor.getCBlockSize(), pRowPos,
1839 pColIdxs, pValues, ptp, itp, dtp, stream})
1840 .getResult();
1841 rewriter.replaceOp(op, {handle, stream});
1842 return success();
1843}
1844
1846 LLVMTypeConverter &converter, RewritePatternSet &patterns,
1847 bool kernelBarePtrCallConv, bool kernelIntersperseSizeCallConv) {
1852
1853 // Higher benefit so this pattern wins over the structural async.yield
1854 // rewriter from populateAsyncStructuralTypeConversionsAndLegality on yields
1855 // with gpu.async.token operands. The structural rewriter would silently
1856 // retype operands without recording an event on the underlying stream.
1857 patterns.add<ConvertAsyncYieldToGpuRuntimeCallPattern>(converter,
1858 /*benefit=*/2);
1859
1860 patterns.add<ConvertAllocOpToGpuRuntimeCallPattern,
1861 ConvertDeallocOpToGpuRuntimeCallPattern,
1862 ConvertHostRegisterOpToGpuRuntimeCallPattern,
1863 ConvertHostUnregisterOpToGpuRuntimeCallPattern,
1864 ConvertMemcpyOpToGpuRuntimeCallPattern,
1865 ConvertMemsetOpToGpuRuntimeCallPattern,
1866 ConvertSetDefaultDeviceOpToGpuRuntimeCallPattern,
1867 ConvertWaitAsyncOpToGpuRuntimeCallPattern,
1868 ConvertWaitOpToGpuRuntimeCallPattern,
1869 ConvertCreateDnTensorOpToGpuRuntimeCallPattern,
1870 ConvertDestroyDnTensorOpToGpuRuntimeCallPattern,
1871 ConvertCreateCooOpToGpuRuntimeCallPattern,
1872 ConvertCreateCooAoSOpToGpuRuntimeCallPattern,
1873 ConvertCreateCsrOpToGpuRuntimeCallPattern,
1874 ConvertCreateCscOpToGpuRuntimeCallPattern,
1875 ConvertCreateBsrOpToGpuRuntimeCallPattern,
1876 ConvertCreate2To4SpMatOpToGpuRuntimeCallPattern,
1877 ConvertDestroySpMatOpToGpuRuntimeCallPattern,
1878 ConvertSpMVBufferSizeOpToGpuRuntimeCallPattern,
1879 ConvertSpMVOpToGpuRuntimeCallPattern,
1880 ConvertSpMMBufferSizeOpToGpuRuntimeCallPattern,
1881 ConvertSDDMMBufferSizeOpToGpuRuntimeCallPattern,
1882 ConvertSpMMOpToGpuRuntimeCallPattern,
1883 ConvertSDDMMOpToGpuRuntimeCallPattern,
1884 ConvertSpGEMMCreateDescrOpToGpuRuntimeCallPattern,
1885 ConvertSpGEMMDestroyDescrOpToGpuRuntimeCallPattern,
1886 ConvertSpGEMMWorkEstimationOrComputeOpToGpuRuntimeCallPattern,
1887 ConvertSpGEMMCopyOpToGpuRuntimeCallPattern,
1888 ConvertSpMatGetSizeOpToGpuRuntimeCallPattern,
1889 ConvertSetCsrPointersOpToGpuRuntimeCallPattern>(converter);
1890 patterns.add<LegalizeLaunchFuncOpPattern>(converter, kernelBarePtrCallConv,
1891 kernelIntersperseSizeCallConv);
1892}
1893
1894//===----------------------------------------------------------------------===//
1895// GPUModuleOp convert to LLVM op interface
1896//===----------------------------------------------------------------------===//
1897
1898namespace {
1899struct GPUModuleOpConvertToLLVMInterface
1900 : public ConvertToLLVMOpInterface::ExternalModel<
1901 GPUModuleOpConvertToLLVMInterface, gpu::GPUModuleOp> {
1902 /// Get the conversion patterns from the target attribute.
1903 void getConvertToLLVMConversionAttrs(
1905};
1906} // namespace
1907
1908void GPUModuleOpConvertToLLVMInterface::getConvertToLLVMConversionAttrs(
1909 Operation *op, SmallVectorImpl<ConvertToLLVMAttrInterface> &attrs) const {
1910 auto module = cast<gpu::GPUModuleOp>(op);
1911 ArrayAttr targetsAttr = module.getTargetsAttr();
1912 // Fail if there are no target attributes or there is more than one target.
1913 if (!targetsAttr || targetsAttr.size() != 1)
1914 return;
1915 if (auto patternAttr = dyn_cast<ConvertToLLVMAttrInterface>(targetsAttr[0]))
1916 attrs.push_back(patternAttr);
1917}
1918
1920 registry.addExtension(+[](MLIRContext *ctx, gpu::GPUDialect *dialect) {
1921 gpu::GPUModuleOp::attachInterface<GPUModuleOpConvertToLLVMInterface>(*ctx);
1922 });
1923}
return success()
static void addOpaquePointerConversion(LLVMTypeConverter &converter)
static int32_t getCuSparseDataTypeFrom(Type type)
static LogicalResult areAllLLVMTypes(Operation *op, ValueRange operands, ConversionPatternRewriter &rewriter)
static Value genConstInt32From(OpBuilder &builder, Location loc, T tValue)
static gpu::Prune2To4SpMatFlag get2To4PruneFlag(Value spMat)
static bool isGpuAsyncTokenType(Value value)
#define DECLARE_CONVERT_OP_TO_GPU_RUNTIME_CALL_PATTERN(op_name)
Generic rewriting rule for operation on sparse matrices.
static int32_t getCuSparseLtDataTypeFrom(Type type)
static bool isDefinedByCallTo(Value value, StringRef functionName)
static Value bitAndAddrspaceCast(Location loc, ConversionPatternRewriter &rewriter, LLVM::LLVMPointerType destinationType, Value sourcePtr, const LLVMTypeConverter &typeConverter)
static bool isSpMMCusparseLtOp(Value op)
static int32_t getCuSparseIndexTypeFrom(Type type)
static bool is2To4Sparsity(Value spMat)
static LogicalResult isAsyncWithOneDependency(ConversionPatternRewriter &rewriter, gpu::AsyncOpInterface op)
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
ArrayAttr()
b getContext())
static llvm::Value * getSizeInBytes(DataLayout &dl, const mlir::Type &type, Operation *clauseOp, llvm::Value *basePointer, llvm::Type *baseType, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation)
static llvm::ManagedStatic< PassManagerOptions > options
IntegerType getIntegerType(unsigned width)
Definition Builders.cpp:75
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition Pattern.h:233
Type getIndexType() const
Gets the MLIR type wrapping the LLVM integer type whose bit width is defined by the used type convert...
Definition Pattern.cpp:38
static Value createIndexAttrConstant(OpBuilder &builder, Location loc, Type resultType, int64_t value)
Create a constant Op producing a value of resultType from an index-typed integer attribute.
Definition Pattern.cpp:64
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Conversion from types to the LLVM IR dialect.
MLIRContext & getContext() const
Returns the MLIR context.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
std::vector< Dialect * > getLoadedDialects()
Return information about all IR dialects loaded in the context.
Value size(OpBuilder &builder, Location loc, unsigned pos)
Builds IR extracting the pos-th size from the descriptor.
This class helps build Operations.
Definition Builders.h:210
static OpBuilder atBlockEnd(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to after the last operation in the block but still insid...
Definition Builders.h:249
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:405
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isF64() const
Definition Types.cpp:41
bool isF32() const
Definition Types.cpp:40
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition Types.cpp:58
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Definition Types.cpp:118
bool isF16() const
Definition Types.cpp:38
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
bool isBF16() const
Definition Types.cpp:37
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:392
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Definition Value.h:108
Type getType() const
Return the type of this value.
Definition Value.h:105
user_range getUsers() const
Definition Value.h:218
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition Value.cpp:18
Value createIndexAttrConstant(OpBuilder &builder, Location loc, Type resultType, int64_t value)
Creates an llvm.mlir.constant producing value as resultType, which is expected to be the converted in...
Definition Pattern.cpp:58
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
void registerConvertGpuToLLVMInterface(DialectRegistry &registry)
Registers the ConvertToLLVMOpInterface interface on the gpu::GPUModuleOP operation.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:744
void populateVectorTransferLoweringPatterns(RewritePatternSet &patterns, std::optional< unsigned > maxTransferRank=std::nullopt, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
Include the generated interface declarations.
void populateVectorToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, bool reassociateFPReductions=false, bool force32BitVectorIndices=false, bool useVectorAlignment=false, bool enableGEPInboundsNuw=false)
Collect a set of patterns to convert from the Vector dialect to LLVM.
LogicalResult applyPatternsGreedily(Region &region, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
void populateFinalizeMemRefToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect a set of patterns to convert memory-related operations from the MemRef dialect to the LLVM di...
void populateGpuToLLVMConversionPatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns, bool kernelBarePtrCallConv=false, bool kernelIntersperseSizeCallConv=false)
Collect a set of patterns to convert from the GPU dialect to LLVM and populate converter for gpu type...
void registerConvertToLLVMDependentDialectLoading(DialectRegistry &registry)
Register the extension that will load dependent dialects for LLVM conversion.
void populateAsyncStructuralTypeConversionsAndLegality(TypeConverter &typeConverter, RewritePatternSet &patterns, ConversionTarget &target)
Populates patterns for async structural type conversions.
LLVM::LLVMFunctionType functionType
LLVM::CallOp create(Location loc, OpBuilder &builder, ArrayRef< Value > arguments) const