MLIR 23.0.0git
AsyncToLLVM.cpp
Go to the documentation of this file.
1//===- AsyncToLLVM.cpp - Convert Async to LLVM dialect --------------------===//
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
10
22#include "mlir/Pass/Pass.h"
24#include "llvm/ADT/TypeSwitch.h"
25
26namespace mlir {
27#define GEN_PASS_DEF_CONVERTASYNCTOLLVMPASS
28#include "mlir/Conversion/Passes.h.inc"
29} // namespace mlir
30
31#define DEBUG_TYPE "convert-async-to-llvm"
32
33using namespace mlir;
34using namespace mlir::async;
35
36//===----------------------------------------------------------------------===//
37// Async Runtime C API declaration.
38//===----------------------------------------------------------------------===//
39
40static constexpr const char *kAddRef = "mlirAsyncRuntimeAddRef";
41static constexpr const char *kDropRef = "mlirAsyncRuntimeDropRef";
42static constexpr const char *kCreateToken = "mlirAsyncRuntimeCreateToken";
43static constexpr const char *kCreateValue = "mlirAsyncRuntimeCreateValue";
44static constexpr const char *kCreateGroup = "mlirAsyncRuntimeCreateGroup";
45static constexpr const char *kEmplaceToken = "mlirAsyncRuntimeEmplaceToken";
46static constexpr const char *kEmplaceValue = "mlirAsyncRuntimeEmplaceValue";
47static constexpr const char *kSetTokenError = "mlirAsyncRuntimeSetTokenError";
48static constexpr const char *kSetValueError = "mlirAsyncRuntimeSetValueError";
49static constexpr const char *kIsTokenError = "mlirAsyncRuntimeIsTokenError";
50static constexpr const char *kIsValueError = "mlirAsyncRuntimeIsValueError";
51static constexpr const char *kIsGroupError = "mlirAsyncRuntimeIsGroupError";
52static constexpr const char *kAwaitToken = "mlirAsyncRuntimeAwaitToken";
53static constexpr const char *kAwaitValue = "mlirAsyncRuntimeAwaitValue";
54static constexpr const char *kAwaitGroup = "mlirAsyncRuntimeAwaitAllInGroup";
55static constexpr const char *kExecute = "mlirAsyncRuntimeExecute";
56static constexpr const char *kGetValueStorage =
57 "mlirAsyncRuntimeGetValueStorage";
58static constexpr const char *kAddTokenToGroup =
59 "mlirAsyncRuntimeAddTokenToGroup";
60static constexpr const char *kAwaitTokenAndExecute =
61 "mlirAsyncRuntimeAwaitTokenAndExecute";
62static constexpr const char *kAwaitValueAndExecute =
63 "mlirAsyncRuntimeAwaitValueAndExecute";
64static constexpr const char *kAwaitAllAndExecute =
65 "mlirAsyncRuntimeAwaitAllInGroupAndExecute";
66static constexpr const char *kGetNumWorkerThreads =
67 "mlirAsyncRuntimGetNumWorkerThreads";
68
69namespace {
70/// Async Runtime API function types.
71///
72/// Because we can't create API function signature for type parametrized
73/// async.getValue type, we use opaque pointers (!llvm.ptr) instead. After
74/// lowering all async data types become opaque pointers at runtime.
75struct AsyncAPI {
76 // All async types are lowered to opaque LLVM pointers at runtime.
77 static LLVM::LLVMPointerType opaquePointerType(MLIRContext *ctx) {
78 return LLVM::LLVMPointerType::get(ctx);
79 }
80
81 static mlir::TokenType tokenType(MLIRContext *ctx) {
82 return mlir::TokenType::get(ctx);
83 }
84
85 static FunctionType addOrDropRefFunctionType(MLIRContext *ctx) {
86 auto ref = opaquePointerType(ctx);
87 auto count = IntegerType::get(ctx, 64);
88 return FunctionType::get(ctx, {ref, count}, {});
89 }
90
91 static FunctionType createTokenFunctionType(MLIRContext *ctx) {
92 return FunctionType::get(ctx, {}, {async::TokenType::get(ctx)});
93 }
94
95 static FunctionType createValueFunctionType(MLIRContext *ctx) {
96 auto i64 = IntegerType::get(ctx, 64);
97 auto value = opaquePointerType(ctx);
98 return FunctionType::get(ctx, {i64}, {value});
99 }
100
101 static FunctionType createGroupFunctionType(MLIRContext *ctx) {
102 auto i64 = IntegerType::get(ctx, 64);
103 return FunctionType::get(ctx, {i64}, {GroupType::get(ctx)});
104 }
105
106 static FunctionType getValueStorageFunctionType(MLIRContext *ctx) {
107 auto ptrType = opaquePointerType(ctx);
108 return FunctionType::get(ctx, {ptrType}, {ptrType});
109 }
110
111 static FunctionType emplaceTokenFunctionType(MLIRContext *ctx) {
112 return FunctionType::get(ctx, {async::TokenType::get(ctx)}, {});
113 }
114
115 static FunctionType emplaceValueFunctionType(MLIRContext *ctx) {
116 auto value = opaquePointerType(ctx);
117 return FunctionType::get(ctx, {value}, {});
118 }
119
120 static FunctionType setTokenErrorFunctionType(MLIRContext *ctx) {
121 return FunctionType::get(ctx, {async::TokenType::get(ctx)}, {});
122 }
123
124 static FunctionType setValueErrorFunctionType(MLIRContext *ctx) {
125 auto value = opaquePointerType(ctx);
126 return FunctionType::get(ctx, {value}, {});
127 }
128
129 static FunctionType isTokenErrorFunctionType(MLIRContext *ctx) {
130 auto i1 = IntegerType::get(ctx, 1);
131 return FunctionType::get(ctx, {async::TokenType::get(ctx)}, {i1});
132 }
133
134 static FunctionType isValueErrorFunctionType(MLIRContext *ctx) {
135 auto value = opaquePointerType(ctx);
136 auto i1 = IntegerType::get(ctx, 1);
137 return FunctionType::get(ctx, {value}, {i1});
138 }
139
140 static FunctionType isGroupErrorFunctionType(MLIRContext *ctx) {
141 auto i1 = IntegerType::get(ctx, 1);
142 return FunctionType::get(ctx, {GroupType::get(ctx)}, {i1});
143 }
144
145 static FunctionType awaitTokenFunctionType(MLIRContext *ctx) {
146 return FunctionType::get(ctx, {async::TokenType::get(ctx)}, {});
147 }
148
149 static FunctionType awaitValueFunctionType(MLIRContext *ctx) {
150 auto value = opaquePointerType(ctx);
151 return FunctionType::get(ctx, {value}, {});
152 }
153
154 static FunctionType awaitGroupFunctionType(MLIRContext *ctx) {
155 return FunctionType::get(ctx, {GroupType::get(ctx)}, {});
156 }
157
158 static FunctionType executeFunctionType(MLIRContext *ctx) {
159 auto ptrType = opaquePointerType(ctx);
160 return FunctionType::get(ctx, {ptrType, ptrType}, {});
161 }
162
163 static FunctionType addTokenToGroupFunctionType(MLIRContext *ctx) {
164 auto i64 = IntegerType::get(ctx, 64);
165 return FunctionType::get(
166 ctx, {async::TokenType::get(ctx), GroupType::get(ctx)}, {i64});
167 }
168
169 static FunctionType awaitTokenAndExecuteFunctionType(MLIRContext *ctx) {
170 auto ptrType = opaquePointerType(ctx);
171 return FunctionType::get(
172 ctx, {async::TokenType::get(ctx), ptrType, ptrType}, {});
173 }
174
175 static FunctionType awaitValueAndExecuteFunctionType(MLIRContext *ctx) {
176 auto ptrType = opaquePointerType(ctx);
177 return FunctionType::get(ctx, {ptrType, ptrType, ptrType}, {});
178 }
179
180 static FunctionType awaitAllAndExecuteFunctionType(MLIRContext *ctx) {
181 auto ptrType = opaquePointerType(ctx);
182 return FunctionType::get(ctx, {GroupType::get(ctx), ptrType, ptrType}, {});
183 }
184
185 static FunctionType getNumWorkerThreads(MLIRContext *ctx) {
186 return FunctionType::get(ctx, {}, {IndexType::get(ctx)});
187 }
188
189 // Auxiliary coroutine resume intrinsic wrapper.
190 static Type resumeFunctionType(MLIRContext *ctx) {
191 auto voidTy = LLVM::LLVMVoidType::get(ctx);
192 auto ptrType = opaquePointerType(ctx);
193 return LLVM::LLVMFunctionType::get(voidTy, {ptrType}, false);
194 }
195};
196} // namespace
197
198/// Adds Async Runtime C API declarations to the module.
199static void addAsyncRuntimeApiDeclarations(ModuleOp module) {
200 auto builder =
201 ImplicitLocOpBuilder::atBlockEnd(module.getLoc(), module.getBody());
202
203 auto addFuncDecl = [&](StringRef name, FunctionType type) {
204 if (module.lookupSymbol(name))
205 return;
206 func::FuncOp::create(builder, name, type).setPrivate();
207 };
208
209 MLIRContext *ctx = module.getContext();
210 addFuncDecl(kAddRef, AsyncAPI::addOrDropRefFunctionType(ctx));
211 addFuncDecl(kDropRef, AsyncAPI::addOrDropRefFunctionType(ctx));
212 addFuncDecl(kCreateToken, AsyncAPI::createTokenFunctionType(ctx));
213 addFuncDecl(kCreateValue, AsyncAPI::createValueFunctionType(ctx));
214 addFuncDecl(kCreateGroup, AsyncAPI::createGroupFunctionType(ctx));
215 addFuncDecl(kEmplaceToken, AsyncAPI::emplaceTokenFunctionType(ctx));
216 addFuncDecl(kEmplaceValue, AsyncAPI::emplaceValueFunctionType(ctx));
217 addFuncDecl(kSetTokenError, AsyncAPI::setTokenErrorFunctionType(ctx));
218 addFuncDecl(kSetValueError, AsyncAPI::setValueErrorFunctionType(ctx));
219 addFuncDecl(kIsTokenError, AsyncAPI::isTokenErrorFunctionType(ctx));
220 addFuncDecl(kIsValueError, AsyncAPI::isValueErrorFunctionType(ctx));
221 addFuncDecl(kIsGroupError, AsyncAPI::isGroupErrorFunctionType(ctx));
222 addFuncDecl(kAwaitToken, AsyncAPI::awaitTokenFunctionType(ctx));
223 addFuncDecl(kAwaitValue, AsyncAPI::awaitValueFunctionType(ctx));
224 addFuncDecl(kAwaitGroup, AsyncAPI::awaitGroupFunctionType(ctx));
225 addFuncDecl(kExecute, AsyncAPI::executeFunctionType(ctx));
226 addFuncDecl(kGetValueStorage, AsyncAPI::getValueStorageFunctionType(ctx));
227 addFuncDecl(kAddTokenToGroup, AsyncAPI::addTokenToGroupFunctionType(ctx));
228 addFuncDecl(kAwaitTokenAndExecute,
229 AsyncAPI::awaitTokenAndExecuteFunctionType(ctx));
230 addFuncDecl(kAwaitValueAndExecute,
231 AsyncAPI::awaitValueAndExecuteFunctionType(ctx));
232 addFuncDecl(kAwaitAllAndExecute,
233 AsyncAPI::awaitAllAndExecuteFunctionType(ctx));
234 addFuncDecl(kGetNumWorkerThreads, AsyncAPI::getNumWorkerThreads(ctx));
235}
236
237//===----------------------------------------------------------------------===//
238// Coroutine resume function wrapper.
239//===----------------------------------------------------------------------===//
240
241static constexpr const char *kResume = "__resume";
242
243/// A function that takes a coroutine handle and calls a `llvm.coro.resume`
244/// intrinsics. We need this function to be able to pass it to the async
245/// runtime execute API.
246static void addResumeFunction(ModuleOp module) {
247 if (module.lookupSymbol(kResume))
248 return;
249
250 MLIRContext *ctx = module.getContext();
251 auto loc = module.getLoc();
252 auto moduleBuilder = ImplicitLocOpBuilder::atBlockEnd(loc, module.getBody());
253
254 auto voidTy = LLVM::LLVMVoidType::get(ctx);
255 Type ptrType = AsyncAPI::opaquePointerType(ctx);
256
257 auto resumeOp = LLVM::LLVMFuncOp::create(
258 moduleBuilder, kResume, LLVM::LLVMFunctionType::get(voidTy, {ptrType}));
259 resumeOp.setPrivate();
260
261 auto *block = resumeOp.addEntryBlock(moduleBuilder);
262 auto blockBuilder = ImplicitLocOpBuilder::atBlockEnd(loc, block);
263
264 LLVM::CoroResumeOp::create(blockBuilder, resumeOp.getArgument(0));
265 LLVM::ReturnOp::create(blockBuilder, ValueRange());
266}
267
268//===----------------------------------------------------------------------===//
269// Convert Async dialect types to LLVM types.
270//===----------------------------------------------------------------------===//
271
272namespace {
273/// AsyncRuntimeTypeConverter only converts types from the Async dialect to
274/// their runtime type (opaque pointers) and does not convert any other types.
275class AsyncRuntimeTypeConverter : public TypeConverter {
276public:
277 AsyncRuntimeTypeConverter(const LowerToLLVMOptions &options) {
278 addConversion([](Type type) { return type; });
279 addConversion([](Type type) { return convertAsyncTypes(type); });
280
281 // Use UnrealizedConversionCast as the bridge so that we don't need to pull
282 // in patterns for other dialects.
283 auto addUnrealizedCast = [](OpBuilder &builder, Type type,
284 ValueRange inputs, Location loc) -> Value {
285 auto cast =
286 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
287 return cast.getResult(0);
288 };
289
290 addSourceMaterialization(addUnrealizedCast);
291 addTargetMaterialization(addUnrealizedCast);
292 }
293
294 static std::optional<Type> convertAsyncTypes(Type type) {
295 if (isa<async::TokenType, GroupType, ValueType>(type))
296 return AsyncAPI::opaquePointerType(type.getContext());
297
298 if (isa<CoroIdType, CoroStateType>(type))
299 return AsyncAPI::tokenType(type.getContext());
300 if (isa<CoroHandleType>(type))
301 return AsyncAPI::opaquePointerType(type.getContext());
302
303 return std::nullopt;
304 }
305};
306
307/// Base class for conversion patterns requiring AsyncRuntimeTypeConverter
308/// as type converter. Allows access to it via the 'getTypeConverter'
309/// convenience method.
310template <typename SourceOp>
311class AsyncOpConversionPattern : public OpConversionPattern<SourceOp> {
312
313 using Base = OpConversionPattern<SourceOp>;
314
315public:
316 AsyncOpConversionPattern(const AsyncRuntimeTypeConverter &typeConverter,
317 MLIRContext *context)
318 : Base(typeConverter, context) {}
319
320 /// Returns the 'AsyncRuntimeTypeConverter' of the pattern.
321 const AsyncRuntimeTypeConverter *getTypeConverter() const {
322 return static_cast<const AsyncRuntimeTypeConverter *>(
323 Base::getTypeConverter());
324 }
325};
326
327} // namespace
328
329//===----------------------------------------------------------------------===//
330// Convert async.coro.id to @llvm.coro.id intrinsic.
331//===----------------------------------------------------------------------===//
332
333namespace {
334class CoroIdOpConversion : public AsyncOpConversionPattern<CoroIdOp> {
335public:
336 using AsyncOpConversionPattern::AsyncOpConversionPattern;
337
338 LogicalResult
339 matchAndRewrite(CoroIdOp op, OpAdaptor adaptor,
340 ConversionPatternRewriter &rewriter) const override {
341 auto token = AsyncAPI::tokenType(op->getContext());
342 auto ptrType = AsyncAPI::opaquePointerType(op->getContext());
343 auto loc = op->getLoc();
344
345 // Constants for initializing coroutine frame.
346 auto constZero =
347 LLVM::ConstantOp::create(rewriter, loc, rewriter.getI32Type(), 0);
348 auto nullPtr = LLVM::ZeroOp::create(rewriter, loc, ptrType);
349
350 // Get coroutine id: @llvm.coro.id.
351 rewriter.replaceOpWithNewOp<LLVM::CoroIdOp>(
352 op, token, ValueRange({constZero, nullPtr, nullPtr, nullPtr}));
353
354 return success();
355 }
356};
357} // namespace
358
359//===----------------------------------------------------------------------===//
360// Convert async.coro.begin to @llvm.coro.begin intrinsic.
361//===----------------------------------------------------------------------===//
362
363namespace {
364class CoroBeginOpConversion : public AsyncOpConversionPattern<CoroBeginOp> {
365public:
366 using AsyncOpConversionPattern::AsyncOpConversionPattern;
367
368 LogicalResult
369 matchAndRewrite(CoroBeginOp op, OpAdaptor adaptor,
370 ConversionPatternRewriter &rewriter) const override {
371 auto ptrType = AsyncAPI::opaquePointerType(op->getContext());
372 auto loc = op->getLoc();
373
374 // Get coroutine frame size: @llvm.coro.size.i64.
375 Value coroSize =
376 LLVM::CoroSizeOp::create(rewriter, loc, rewriter.getI64Type());
377 // Get coroutine frame alignment: @llvm.coro.align.i64.
378 Value coroAlign =
379 LLVM::CoroAlignOp::create(rewriter, loc, rewriter.getI64Type());
380
381 // Round up the size to be multiple of the alignment. Since aligned_alloc
382 // requires the size parameter be an integral multiple of the alignment
383 // parameter.
384 auto makeConstant = [&](uint64_t c) {
385 return LLVM::ConstantOp::create(rewriter, op->getLoc(),
386 rewriter.getI64Type(), c);
387 };
388 coroSize = LLVM::AddOp::create(rewriter, op->getLoc(), coroSize, coroAlign);
389 coroSize =
390 LLVM::SubOp::create(rewriter, op->getLoc(), coroSize, makeConstant(1));
391 Value negCoroAlign =
392 LLVM::SubOp::create(rewriter, op->getLoc(), makeConstant(0), coroAlign);
393 coroSize =
394 LLVM::AndOp::create(rewriter, op->getLoc(), coroSize, negCoroAlign);
395
396 // Allocate memory for the coroutine frame.
397 auto allocFuncOp = LLVM::lookupOrCreateAlignedAllocFn(
398 rewriter, op->getParentOfType<ModuleOp>(), rewriter.getI64Type());
399 if (failed(allocFuncOp))
400 return failure();
401 auto coroAlloc = LLVM::CallOp::create(rewriter, loc, allocFuncOp.value(),
402 ValueRange{coroAlign, coroSize});
403
404 // Begin a coroutine: @llvm.coro.begin.
405 auto coroId = CoroBeginOpAdaptor(adaptor.getOperands()).getId();
406 rewriter.replaceOpWithNewOp<LLVM::CoroBeginOp>(
407 op, ptrType, ValueRange({coroId, coroAlloc.getResult()}));
408
409 return success();
410 }
411};
412} // namespace
413
414//===----------------------------------------------------------------------===//
415// Convert async.coro.free to @llvm.coro.free intrinsic.
416//===----------------------------------------------------------------------===//
417
418namespace {
419class CoroFreeOpConversion : public AsyncOpConversionPattern<CoroFreeOp> {
420public:
421 using AsyncOpConversionPattern::AsyncOpConversionPattern;
422
423 LogicalResult
424 matchAndRewrite(CoroFreeOp op, OpAdaptor adaptor,
425 ConversionPatternRewriter &rewriter) const override {
426 auto ptrType = AsyncAPI::opaquePointerType(op->getContext());
427 auto loc = op->getLoc();
428
429 // Get a pointer to the coroutine frame memory: @llvm.coro.free.
430 auto coroMem =
431 LLVM::CoroFreeOp::create(rewriter, loc, ptrType, adaptor.getOperands());
432
433 // Free the memory.
434 auto freeFuncOp =
435 LLVM::lookupOrCreateFreeFn(rewriter, op->getParentOfType<ModuleOp>());
436 if (failed(freeFuncOp))
437 return failure();
438 rewriter.replaceOpWithNewOp<LLVM::CallOp>(op, freeFuncOp.value(),
439 ValueRange(coroMem.getResult()));
440
441 return success();
442 }
443};
444} // namespace
445
446//===----------------------------------------------------------------------===//
447// Convert async.coro.end to @llvm.coro.end intrinsic.
448//===----------------------------------------------------------------------===//
449
450namespace {
451class CoroEndOpConversion : public OpConversionPattern<CoroEndOp> {
452public:
453 using OpConversionPattern::OpConversionPattern;
454
455 LogicalResult
456 matchAndRewrite(CoroEndOp op, OpAdaptor adaptor,
457 ConversionPatternRewriter &rewriter) const override {
458 // We are not in the block that is part of the unwind sequence.
459 auto constFalse =
460 LLVM::ConstantOp::create(rewriter, op->getLoc(), rewriter.getI1Type(),
461 rewriter.getBoolAttr(false));
462 auto noneToken = LLVM::NoneTokenOp::create(rewriter, op->getLoc());
463
464 // Mark the end of a coroutine: @llvm.coro.end.
465 auto coroHdl = adaptor.getHandle();
466 LLVM::CoroEndOp::create(rewriter, op->getLoc(), rewriter.getI1Type(),
467 ValueRange({coroHdl, constFalse, noneToken}));
468 rewriter.eraseOp(op);
469
470 return success();
471 }
472};
473} // namespace
474
475//===----------------------------------------------------------------------===//
476// Convert async.coro.save to @llvm.coro.save intrinsic.
477//===----------------------------------------------------------------------===//
478
479namespace {
480class CoroSaveOpConversion : public OpConversionPattern<CoroSaveOp> {
481public:
482 using OpConversionPattern::OpConversionPattern;
483
484 LogicalResult
485 matchAndRewrite(CoroSaveOp op, OpAdaptor adaptor,
486 ConversionPatternRewriter &rewriter) const override {
487 // Save the coroutine state: @llvm.coro.save
488 rewriter.replaceOpWithNewOp<LLVM::CoroSaveOp>(
489 op, AsyncAPI::tokenType(op->getContext()), adaptor.getOperands());
490
491 return success();
492 }
493};
494} // namespace
495
496//===----------------------------------------------------------------------===//
497// Convert async.coro.suspend to @llvm.coro.suspend intrinsic.
498//===----------------------------------------------------------------------===//
499
500namespace {
501
502/// Convert async.coro.suspend to the @llvm.coro.suspend intrinsic call, and
503/// branch to the appropriate block based on the return code.
504///
505/// Before:
506///
507/// ^suspended:
508/// "opBefore"(...)
509/// async.coro.suspend %state, ^suspend, ^resume, ^cleanup
510/// ^resume:
511/// "op"(...)
512/// ^cleanup: ...
513/// ^suspend: ...
514///
515/// After:
516///
517/// ^suspended:
518/// "opBefore"(...)
519/// %suspend = llmv.intr.coro.suspend ...
520/// switch %suspend [-1: ^suspend, 0: ^resume, 1: ^cleanup]
521/// ^resume:
522/// "op"(...)
523/// ^cleanup: ...
524/// ^suspend: ...
525///
526class CoroSuspendOpConversion : public OpConversionPattern<CoroSuspendOp> {
527public:
528 using OpConversionPattern::OpConversionPattern;
529
530 LogicalResult
531 matchAndRewrite(CoroSuspendOp op, OpAdaptor adaptor,
532 ConversionPatternRewriter &rewriter) const override {
533 auto i8 = rewriter.getIntegerType(8);
534 auto i32 = rewriter.getI32Type();
535 auto loc = op->getLoc();
536
537 // This is not a final suspension point.
538 auto constFalse = LLVM::ConstantOp::create(
539 rewriter, loc, rewriter.getI1Type(), rewriter.getBoolAttr(false));
540
541 // Suspend a coroutine: @llvm.coro.suspend
542 auto coroState = adaptor.getState();
543 auto coroSuspend = LLVM::CoroSuspendOp::create(
544 rewriter, loc, i8, ValueRange({coroState, constFalse}));
545
546 // Cast return code to i32.
547
548 // After a suspension point decide if we should branch into resume, cleanup
549 // or suspend block of the coroutine (see @llvm.coro.suspend return code
550 // documentation).
551 llvm::SmallVector<int32_t, 2> caseValues = {0, 1};
552 llvm::SmallVector<Block *, 2> caseDest = {op.getResumeDest(),
553 op.getCleanupDest()};
554 rewriter.replaceOpWithNewOp<LLVM::SwitchOp>(
555 op, LLVM::SExtOp::create(rewriter, loc, i32, coroSuspend.getResult()),
556 /*defaultDestination=*/op.getSuspendDest(),
557 /*defaultOperands=*/ValueRange(),
558 /*caseValues=*/caseValues,
559 /*caseDestinations=*/caseDest,
560 /*caseOperands=*/ArrayRef<ValueRange>({ValueRange(), ValueRange()}),
561 /*branchWeights=*/ArrayRef<int32_t>());
562
563 return success();
564 }
565};
566} // namespace
567
568//===----------------------------------------------------------------------===//
569// Convert async.runtime.create to the corresponding runtime API call.
570//
571// To allocate storage for the async values we use getelementptr trick:
572// http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt
573//===----------------------------------------------------------------------===//
574
575namespace {
576class RuntimeCreateOpLowering : public ConvertOpToLLVMPattern<RuntimeCreateOp> {
577public:
579
580 LogicalResult
581 matchAndRewrite(RuntimeCreateOp op, OpAdaptor adaptor,
582 ConversionPatternRewriter &rewriter) const override {
583 const TypeConverter *converter = getTypeConverter();
584 Type resultType = op->getResultTypes()[0];
585
586 // Tokens creation maps to a simple function call.
587 if (isa<async::TokenType>(resultType)) {
588 rewriter.replaceOpWithNewOp<func::CallOp>(
589 op, kCreateToken, converter->convertType(resultType));
590 return success();
591 }
592
593 // To create a value we need to compute the storage requirement.
594 if (auto value = dyn_cast<ValueType>(resultType)) {
595 // Returns the size requirements for the async value storage.
596 auto sizeOf = [&](ValueType valueType) -> Value {
597 auto loc = op->getLoc();
598 auto i64 = rewriter.getI64Type();
599
600 auto storedType = converter->convertType(valueType.getValueType());
601 auto storagePtrType =
602 AsyncAPI::opaquePointerType(rewriter.getContext());
603
604 // %Size = getelementptr %T* null, int 1
605 // %SizeI = ptrtoint %T* %Size to i64
606 auto nullPtr = LLVM::ZeroOp::create(rewriter, loc, storagePtrType);
607 auto gep =
608 LLVM::GEPOp::create(rewriter, loc, storagePtrType, storedType,
609 nullPtr, ArrayRef<LLVM::GEPArg>{1});
610 return LLVM::PtrToIntOp::create(rewriter, loc, i64, gep);
611 };
612
613 rewriter.replaceOpWithNewOp<func::CallOp>(op, kCreateValue, resultType,
614 sizeOf(value));
615
616 return success();
617 }
618
619 return rewriter.notifyMatchFailure(op, "unsupported async type");
620 }
621};
622} // namespace
623
624//===----------------------------------------------------------------------===//
625// Convert async.runtime.create_group to the corresponding runtime API call.
626//===----------------------------------------------------------------------===//
627
628namespace {
629class RuntimeCreateGroupOpLowering
630 : public ConvertOpToLLVMPattern<RuntimeCreateGroupOp> {
631public:
633
634 LogicalResult
635 matchAndRewrite(RuntimeCreateGroupOp op, OpAdaptor adaptor,
636 ConversionPatternRewriter &rewriter) const override {
637 const TypeConverter *converter = getTypeConverter();
638 Type resultType = op.getResult().getType();
639
640 rewriter.replaceOpWithNewOp<func::CallOp>(
641 op, kCreateGroup, converter->convertType(resultType),
642 adaptor.getOperands());
643 return success();
644 }
645};
646} // namespace
647
648//===----------------------------------------------------------------------===//
649// Convert async.runtime.set_available to the corresponding runtime API call.
650//===----------------------------------------------------------------------===//
651
652namespace {
653class RuntimeSetAvailableOpLowering
654 : public OpConversionPattern<RuntimeSetAvailableOp> {
655public:
656 using OpConversionPattern::OpConversionPattern;
657
658 LogicalResult
659 matchAndRewrite(RuntimeSetAvailableOp op, OpAdaptor adaptor,
660 ConversionPatternRewriter &rewriter) const override {
661 StringRef apiFuncName =
662 TypeSwitch<Type, StringRef>(op.getOperand().getType())
663 .Case<async::TokenType>([](Type) { return kEmplaceToken; })
664 .Case<ValueType>([](Type) { return kEmplaceValue; });
665
666 rewriter.replaceOpWithNewOp<func::CallOp>(op, apiFuncName, TypeRange(),
667 adaptor.getOperands());
668
669 return success();
670 }
671};
672} // namespace
673
674//===----------------------------------------------------------------------===//
675// Convert async.runtime.set_error to the corresponding runtime API call.
676//===----------------------------------------------------------------------===//
677
678namespace {
679class RuntimeSetErrorOpLowering
680 : public OpConversionPattern<RuntimeSetErrorOp> {
681public:
682 using OpConversionPattern::OpConversionPattern;
683
684 LogicalResult
685 matchAndRewrite(RuntimeSetErrorOp op, OpAdaptor adaptor,
686 ConversionPatternRewriter &rewriter) const override {
687 StringRef apiFuncName =
688 TypeSwitch<Type, StringRef>(op.getOperand().getType())
689 .Case<async::TokenType>([](Type) { return kSetTokenError; })
690 .Case<ValueType>([](Type) { return kSetValueError; });
691
692 rewriter.replaceOpWithNewOp<func::CallOp>(op, apiFuncName, TypeRange(),
693 adaptor.getOperands());
694
695 return success();
696 }
697};
698} // namespace
699
700//===----------------------------------------------------------------------===//
701// Convert async.runtime.is_error to the corresponding runtime API call.
702//===----------------------------------------------------------------------===//
703
704namespace {
705class RuntimeIsErrorOpLowering : public OpConversionPattern<RuntimeIsErrorOp> {
706public:
707 using OpConversionPattern::OpConversionPattern;
708
709 LogicalResult
710 matchAndRewrite(RuntimeIsErrorOp op, OpAdaptor adaptor,
711 ConversionPatternRewriter &rewriter) const override {
712 StringRef apiFuncName =
713 TypeSwitch<Type, StringRef>(op.getOperand().getType())
714 .Case<async::TokenType>([](Type) { return kIsTokenError; })
715 .Case<GroupType>([](Type) { return kIsGroupError; })
716 .Case<ValueType>([](Type) { return kIsValueError; });
717
718 rewriter.replaceOpWithNewOp<func::CallOp>(
719 op, apiFuncName, rewriter.getI1Type(), adaptor.getOperands());
720 return success();
721 }
722};
723} // namespace
724
725//===----------------------------------------------------------------------===//
726// Convert async.runtime.await to the corresponding runtime API call.
727//===----------------------------------------------------------------------===//
728
729namespace {
730class RuntimeAwaitOpLowering : public OpConversionPattern<RuntimeAwaitOp> {
731public:
732 using OpConversionPattern::OpConversionPattern;
733
734 LogicalResult
735 matchAndRewrite(RuntimeAwaitOp op, OpAdaptor adaptor,
736 ConversionPatternRewriter &rewriter) const override {
737 StringRef apiFuncName =
738 TypeSwitch<Type, StringRef>(op.getOperand().getType())
739 .Case<async::TokenType>([](Type) { return kAwaitToken; })
740 .Case<ValueType>([](Type) { return kAwaitValue; })
741 .Case<GroupType>([](Type) { return kAwaitGroup; });
742
743 func::CallOp::create(rewriter, op->getLoc(), apiFuncName, TypeRange(),
744 adaptor.getOperands());
745 rewriter.eraseOp(op);
746
747 return success();
748 }
749};
750} // namespace
751
752//===----------------------------------------------------------------------===//
753// Convert async.runtime.await_and_resume to the corresponding runtime API call.
754//===----------------------------------------------------------------------===//
755
756namespace {
757class RuntimeAwaitAndResumeOpLowering
758 : public AsyncOpConversionPattern<RuntimeAwaitAndResumeOp> {
759public:
760 using AsyncOpConversionPattern::AsyncOpConversionPattern;
761
762 LogicalResult
763 matchAndRewrite(RuntimeAwaitAndResumeOp op, OpAdaptor adaptor,
764 ConversionPatternRewriter &rewriter) const override {
765 StringRef apiFuncName =
766 TypeSwitch<Type, StringRef>(op.getOperand().getType())
767 .Case<async::TokenType>([](Type) { return kAwaitTokenAndExecute; })
768 .Case<ValueType>([](Type) { return kAwaitValueAndExecute; })
769 .Case<GroupType>([](Type) { return kAwaitAllAndExecute; });
770
771 Value operand = adaptor.getOperand();
772 Value handle = adaptor.getHandle();
773
774 // A pointer to coroutine resume intrinsic wrapper.
775 addResumeFunction(op->getParentOfType<ModuleOp>());
776 auto resumePtr = LLVM::AddressOfOp::create(
777 rewriter, op->getLoc(),
778 AsyncAPI::opaquePointerType(rewriter.getContext()), kResume);
779
780 func::CallOp::create(rewriter, op->getLoc(), apiFuncName, TypeRange(),
781 ValueRange({operand, handle, resumePtr.getRes()}));
782 rewriter.eraseOp(op);
783
784 return success();
785 }
786};
787} // namespace
788
789//===----------------------------------------------------------------------===//
790// Convert async.runtime.resume to the corresponding runtime API call.
791//===----------------------------------------------------------------------===//
792
793namespace {
794class RuntimeResumeOpLowering
795 : public AsyncOpConversionPattern<RuntimeResumeOp> {
796public:
797 using AsyncOpConversionPattern::AsyncOpConversionPattern;
798
799 LogicalResult
800 matchAndRewrite(RuntimeResumeOp op, OpAdaptor adaptor,
801 ConversionPatternRewriter &rewriter) const override {
802 // A pointer to coroutine resume intrinsic wrapper.
803 addResumeFunction(op->getParentOfType<ModuleOp>());
804 auto resumePtr = LLVM::AddressOfOp::create(
805 rewriter, op->getLoc(),
806 AsyncAPI::opaquePointerType(rewriter.getContext()), kResume);
807
808 // Call async runtime API to execute a coroutine in the managed thread.
809 auto coroHdl = adaptor.getHandle();
810 rewriter.replaceOpWithNewOp<func::CallOp>(
811 op, TypeRange(), kExecute, ValueRange({coroHdl, resumePtr.getRes()}));
812
813 return success();
814 }
815};
816} // namespace
817
818//===----------------------------------------------------------------------===//
819// Convert async.runtime.store to the corresponding runtime API call.
820//===----------------------------------------------------------------------===//
821
822namespace {
823class RuntimeStoreOpLowering : public ConvertOpToLLVMPattern<RuntimeStoreOp> {
824public:
826
827 LogicalResult
828 matchAndRewrite(RuntimeStoreOp op, OpAdaptor adaptor,
829 ConversionPatternRewriter &rewriter) const override {
830 Location loc = op->getLoc();
831
832 // Get a pointer to the async value storage from the runtime.
833 auto ptrType = AsyncAPI::opaquePointerType(rewriter.getContext());
834 auto storage = adaptor.getStorage();
835 auto storagePtr = func::CallOp::create(rewriter, loc, kGetValueStorage,
836 TypeRange(ptrType), storage);
837
838 // Cast from i8* to the LLVM pointer type.
839 auto valueType = op.getValue().getType();
840 auto llvmValueType = getTypeConverter()->convertType(valueType);
841 if (!llvmValueType)
842 return rewriter.notifyMatchFailure(
843 op, "failed to convert stored value type to LLVM type");
844
845 Value castedStoragePtr = storagePtr.getResult(0);
846 // Store the yielded value into the async value storage.
847 auto value = adaptor.getValue();
848 LLVM::StoreOp::create(rewriter, loc, value, castedStoragePtr);
849
850 // Erase the original runtime store operation.
851 rewriter.eraseOp(op);
852
853 return success();
854 }
855};
856} // namespace
857
858//===----------------------------------------------------------------------===//
859// Convert async.runtime.load to the corresponding runtime API call.
860//===----------------------------------------------------------------------===//
861
862namespace {
863class RuntimeLoadOpLowering : public ConvertOpToLLVMPattern<RuntimeLoadOp> {
864public:
866
867 LogicalResult
868 matchAndRewrite(RuntimeLoadOp op, OpAdaptor adaptor,
869 ConversionPatternRewriter &rewriter) const override {
870 Location loc = op->getLoc();
871
872 // Get a pointer to the async value storage from the runtime.
873 auto ptrType = AsyncAPI::opaquePointerType(rewriter.getContext());
874 auto storage = adaptor.getStorage();
875 auto storagePtr = func::CallOp::create(rewriter, loc, kGetValueStorage,
876 TypeRange(ptrType), storage);
877
878 // Cast from i8* to the LLVM pointer type.
879 auto valueType = op.getResult().getType();
880 auto llvmValueType = getTypeConverter()->convertType(valueType);
881 if (!llvmValueType)
882 return rewriter.notifyMatchFailure(
883 op, "failed to convert loaded value type to LLVM type");
884
885 Value castedStoragePtr = storagePtr.getResult(0);
886
887 // Load from the casted pointer.
888 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, llvmValueType,
889 castedStoragePtr);
890
891 return success();
892 }
893};
894} // namespace
895
896//===----------------------------------------------------------------------===//
897// Convert async.runtime.add_to_group to the corresponding runtime API call.
898//===----------------------------------------------------------------------===//
899
900namespace {
901class RuntimeAddToGroupOpLowering
902 : public OpConversionPattern<RuntimeAddToGroupOp> {
903public:
904 using OpConversionPattern::OpConversionPattern;
905
906 LogicalResult
907 matchAndRewrite(RuntimeAddToGroupOp op, OpAdaptor adaptor,
908 ConversionPatternRewriter &rewriter) const override {
909 // Currently we can only add tokens to the group.
910 if (!isa<async::TokenType>(op.getOperand().getType()))
911 return rewriter.notifyMatchFailure(op, "only token type is supported");
912
913 // Replace with a runtime API function call.
914 rewriter.replaceOpWithNewOp<func::CallOp>(
915 op, kAddTokenToGroup, rewriter.getI64Type(), adaptor.getOperands());
916
917 return success();
918 }
919};
920} // namespace
921
922//===----------------------------------------------------------------------===//
923// Convert async.runtime.num_worker_threads to the corresponding runtime API
924// call.
925//===----------------------------------------------------------------------===//
926
927namespace {
928class RuntimeNumWorkerThreadsOpLowering
929 : public OpConversionPattern<RuntimeNumWorkerThreadsOp> {
930public:
931 using OpConversionPattern::OpConversionPattern;
932
933 LogicalResult
934 matchAndRewrite(RuntimeNumWorkerThreadsOp op, OpAdaptor adaptor,
935 ConversionPatternRewriter &rewriter) const override {
936
937 // Replace with a runtime API function call.
938 rewriter.replaceOpWithNewOp<func::CallOp>(op, kGetNumWorkerThreads,
939 rewriter.getIndexType());
940
941 return success();
942 }
943};
944} // namespace
945
946//===----------------------------------------------------------------------===//
947// Async reference counting ops lowering (`async.runtime.add_ref` and
948// `async.runtime.drop_ref` to the corresponding API calls).
949//===----------------------------------------------------------------------===//
950
951namespace {
952template <typename RefCountingOp>
953class RefCountingOpLowering : public OpConversionPattern<RefCountingOp> {
954public:
955 explicit RefCountingOpLowering(const TypeConverter &converter,
956 MLIRContext *ctx, StringRef apiFunctionName)
957 : OpConversionPattern<RefCountingOp>(converter, ctx),
958 apiFunctionName(apiFunctionName) {}
959
960 LogicalResult
961 matchAndRewrite(RefCountingOp op, typename RefCountingOp::Adaptor adaptor,
962 ConversionPatternRewriter &rewriter) const override {
963 auto count =
964 arith::ConstantOp::create(rewriter, op->getLoc(), rewriter.getI64Type(),
965 rewriter.getI64IntegerAttr(op.getCount()));
966
967 auto operand = adaptor.getOperand();
968 rewriter.replaceOpWithNewOp<func::CallOp>(op, TypeRange(), apiFunctionName,
969 ValueRange({operand, count}));
970
971 return success();
972 }
973
974private:
975 StringRef apiFunctionName;
976};
977
978class RuntimeAddRefOpLowering : public RefCountingOpLowering<RuntimeAddRefOp> {
979public:
980 explicit RuntimeAddRefOpLowering(const TypeConverter &converter,
981 MLIRContext *ctx)
982 : RefCountingOpLowering(converter, ctx, kAddRef) {}
983};
984
985class RuntimeDropRefOpLowering
986 : public RefCountingOpLowering<RuntimeDropRefOp> {
987public:
988 explicit RuntimeDropRefOpLowering(const TypeConverter &converter,
989 MLIRContext *ctx)
990 : RefCountingOpLowering(converter, ctx, kDropRef) {}
991};
992} // namespace
993
994//===----------------------------------------------------------------------===//
995// Convert return operations that return async values from async regions.
996//===----------------------------------------------------------------------===//
997
998namespace {
999class ReturnOpOpConversion : public OpConversionPattern<func::ReturnOp> {
1000public:
1001 using OpConversionPattern::OpConversionPattern;
1002
1003 LogicalResult
1004 matchAndRewrite(func::ReturnOp op, OpAdaptor adaptor,
1005 ConversionPatternRewriter &rewriter) const override {
1006 rewriter.replaceOpWithNewOp<func::ReturnOp>(op, adaptor.getOperands());
1007 return success();
1008 }
1009};
1010} // namespace
1011
1012//===----------------------------------------------------------------------===//
1013
1014namespace {
1015struct ConvertAsyncToLLVMPass
1016 : public impl::ConvertAsyncToLLVMPassBase<ConvertAsyncToLLVMPass> {
1017 using Base::Base;
1018
1019 void runOnOperation() override;
1020};
1021} // namespace
1022
1023void ConvertAsyncToLLVMPass::runOnOperation() {
1024 ModuleOp module = getOperation();
1025 MLIRContext *ctx = module->getContext();
1026
1027 LowerToLLVMOptions options(ctx);
1028
1029 // Add declarations for most functions required by the coroutines lowering.
1030 // We delay adding the resume function until it's needed because it currently
1031 // fails to compile unless '-O0' is specified.
1033
1034 // Lower async.runtime and async.coro operations to Async Runtime API and
1035 // LLVM coroutine intrinsics.
1036
1037 // Convert async dialect types and operations to LLVM dialect.
1038 AsyncRuntimeTypeConverter converter(options);
1039 RewritePatternSet patterns(ctx);
1040
1041 // We use conversion to LLVM type to lower async.runtime load and store
1042 // operations.
1043 LLVMTypeConverter llvmConverter(ctx, options);
1044 llvmConverter.addConversion([&](Type type) {
1045 return AsyncRuntimeTypeConverter::convertAsyncTypes(type);
1046 });
1047
1048 // Convert async types in function signatures and function calls.
1049 populateFunctionOpInterfaceTypeConversionPattern<func::FuncOp>(patterns,
1050 converter);
1052
1053 // Convert return operations inside async.execute regions.
1054 patterns.add<ReturnOpOpConversion>(converter, ctx);
1056 // Lower async.runtime operations to the async runtime API calls.
1057 patterns.add<RuntimeSetAvailableOpLowering, RuntimeSetErrorOpLowering,
1058 RuntimeIsErrorOpLowering, RuntimeAwaitOpLowering,
1059 RuntimeAwaitAndResumeOpLowering, RuntimeResumeOpLowering,
1060 RuntimeAddToGroupOpLowering, RuntimeNumWorkerThreadsOpLowering,
1061 RuntimeAddRefOpLowering, RuntimeDropRefOpLowering>(converter,
1062 ctx);
1063
1064 // Lower async.runtime operations that rely on LLVM type converter to convert
1065 // from async value payload type to the LLVM type.
1066 patterns.add<RuntimeCreateOpLowering, RuntimeCreateGroupOpLowering,
1067 RuntimeStoreOpLowering, RuntimeLoadOpLowering>(llvmConverter);
1068
1069 // Lower async coroutine operations to LLVM coroutine intrinsics.
1070 patterns
1071 .add<CoroIdOpConversion, CoroBeginOpConversion, CoroFreeOpConversion,
1072 CoroEndOpConversion, CoroSaveOpConversion, CoroSuspendOpConversion>(
1073 converter, ctx);
1074
1076 target.addLegalOp<arith::ConstantOp, func::ConstantOp,
1077 UnrealizedConversionCastOp>();
1078 target.addLegalDialect<LLVM::LLVMDialect>();
1079
1080 // All operations from Async dialect must be lowered to the runtime API and
1081 // LLVM intrinsics calls.
1082 target.addIllegalDialect<AsyncDialect>();
1083
1084 // Add dynamic legality constraints to apply conversions defined above.
1085 target.addDynamicallyLegalOp<func::FuncOp>([&](func::FuncOp op) {
1086 return converter.isSignatureLegal(op.getFunctionType());
1087 });
1088 target.addDynamicallyLegalOp<func::ReturnOp>([&](func::ReturnOp op) {
1089 return converter.isLegal(op.getOperandTypes());
1090 });
1091 target.addDynamicallyLegalOp<func::CallOp>([&](func::CallOp op) {
1092 return converter.isSignatureLegal(op.getCalleeType());
1093 });
1094
1095 if (failed(applyPartialConversion(module, target, std::move(patterns))))
1096 signalPassFailure();
1097}
1098
1099//===----------------------------------------------------------------------===//
1100// Patterns for structural type conversions for the Async dialect operations.
1101//===----------------------------------------------------------------------===//
1102
1103namespace {
1104class ConvertExecuteOpTypes : public OpConversionPattern<ExecuteOp> {
1105public:
1106 using OpConversionPattern::OpConversionPattern;
1107 LogicalResult
1108 matchAndRewrite(ExecuteOp op, OpAdaptor adaptor,
1109 ConversionPatternRewriter &rewriter) const override {
1110 ExecuteOp newOp =
1111 cast<ExecuteOp>(rewriter.cloneWithoutRegions(*op.getOperation()));
1112 rewriter.inlineRegionBefore(op.getRegion(), newOp.getRegion(),
1113 newOp.getRegion().end());
1114
1115 // Set operands and update block argument and result types.
1116 newOp->setOperands(adaptor.getOperands());
1117 if (failed(rewriter.convertRegionTypes(&newOp.getRegion(), *typeConverter)))
1118 return failure();
1119 for (auto result : newOp.getResults())
1120 result.setType(typeConverter->convertType(result.getType()));
1121
1122 rewriter.replaceOp(op, newOp.getResults());
1123 return success();
1124 }
1125};
1126
1127// Dummy pattern to trigger the appropriate type conversion / materialization.
1128class ConvertAwaitOpTypes : public OpConversionPattern<AwaitOp> {
1129public:
1130 using OpConversionPattern::OpConversionPattern;
1131 LogicalResult
1132 matchAndRewrite(AwaitOp op, OpAdaptor adaptor,
1133 ConversionPatternRewriter &rewriter) const override {
1134 rewriter.replaceOpWithNewOp<AwaitOp>(op, adaptor.getOperands().front());
1135 return success();
1136 }
1137};
1138
1139// Dummy pattern to trigger the appropriate type conversion / materialization.
1140class ConvertYieldOpTypes : public OpConversionPattern<async::YieldOp> {
1141public:
1142 using OpConversionPattern::OpConversionPattern;
1143 LogicalResult
1144 matchAndRewrite(async::YieldOp op, OpAdaptor adaptor,
1145 ConversionPatternRewriter &rewriter) const override {
1146 rewriter.replaceOpWithNewOp<async::YieldOp>(op, adaptor.getOperands());
1147 return success();
1148 }
1149};
1150} // namespace
1151
1153 TypeConverter &typeConverter, RewritePatternSet &patterns,
1155 typeConverter.addConversion([&](async::TokenType type) { return type; });
1156 typeConverter.addConversion([&](ValueType type) {
1157 Type converted = typeConverter.convertType(type.getValueType());
1158 return converted ? ValueType::get(converted) : converted;
1159 });
1160
1161 patterns.add<ConvertExecuteOpTypes, ConvertAwaitOpTypes, ConvertYieldOpTypes>(
1162 typeConverter, patterns.getContext());
1163
1164 target.addDynamicallyLegalOp<AwaitOp, ExecuteOp, async::YieldOp>(
1165 [&](Operation *op) { return typeConverter.isLegal(op); });
1166}
return success()
static constexpr const char * kAwaitValueAndExecute
static constexpr const char * kCreateValue
static constexpr const char * kCreateGroup
static constexpr const char * kCreateToken
static constexpr const char * kEmplaceValue
static void addResumeFunction(ModuleOp module)
A function that takes a coroutine handle and calls a llvm.coro.resume intrinsics.
static constexpr const char * kEmplaceToken
static void addAsyncRuntimeApiDeclarations(ModuleOp module)
Adds Async Runtime C API declarations to the module.
static constexpr const char * kResume
static constexpr const char * kAddRef
static constexpr const char * kAwaitTokenAndExecute
static constexpr const char * kAwaitValue
static constexpr const char * kSetTokenError
static constexpr const char * kExecute
static constexpr const char * kAddTokenToGroup
static constexpr const char * kIsGroupError
static constexpr const char * kSetValueError
static constexpr const char * kIsTokenError
static constexpr const char * kAwaitGroup
static constexpr const char * kAwaitAllAndExecute
static constexpr const char * kGetNumWorkerThreads
static constexpr const char * kDropRef
static constexpr const char * kIsValueError
static constexpr const char * kAwaitToken
static constexpr const char * kGetValueStorage
static llvm::ManagedStatic< PassManagerOptions > options
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition Pattern.h:227
ConvertOpToLLVMPattern(const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
Definition Pattern.h:233
static ImplicitLocOpBuilder atBlockEnd(Location loc, 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:649
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
MLIRContext * getContext() const
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
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition Types.cpp:35
FailureOr< LLVM::LLVMFuncOp > lookupOrCreateFreeFn(OpBuilder &b, Operation *moduleOp, SymbolTableCollection *symbolTables=nullptr)
FailureOr< LLVM::LLVMFuncOp > lookupOrCreateAlignedAllocFn(OpBuilder &b, Operation *moduleOp, Type indexType, SymbolTableCollection *symbolTables=nullptr)
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
void populateCallOpTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter, PatternBenefit benefit=1)
Add a pattern to the given pattern list to convert the operand and result types of a CallOp with the ...
void populateAsyncStructuralTypeConversionsAndLegality(TypeConverter &typeConverter, RewritePatternSet &patterns, ConversionTarget &target)
Populates patterns for async structural type conversions.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:139