[Mlir-commits] [mlir] [mlir][async] Fix crash when lowering async values of non-LLVM types (PR #216487)
Hamza Qureshi
llvmlistbot at llvm.org
Sat Aug 15 05:54:13 PDT 2026
https://github.com/hamzaqureshi5 created https://github.com/llvm/llvm-project/pull/216487
Fixes #216213
## The problem
`mlir-opt -convert-async-to-llvm` segfaults on valid input:
```mlir
func.func @test() -> !async.value<tensor<4xf32>> {
%0 = async.runtime.create : !async.value<tensor<4xf32>>
return %0 : !async.value<tensor<4xf32>>
}
```
To create an async value the lowering needs to know how much storage the payload takes, which it computes by emitting a GEP over the converted payload type:
```cpp
auto storedType = converter->convertType(valueType.getValueType());
...
LLVM::GEPOp::create(rewriter, loc, storagePtrType, storedType, ...);
```
`tensor<4xf32>` has no LLVM counterpart, so `convertType` returns a null `Type`. That null then reaches `TypeAttr::get`, which calls `Type::getContext()` on it, and the pass crashes.
## The fix
Check the converted type and bail out if the payload cannot be represented:
```cpp
Type storedType = converter->convertType(value.getValueType());
if (!storedType)
return rewriter.notifyMatchFailure(
op, "failed to convert async value type to LLVM type");
```
The `RuntimeStoreOp` and `RuntimeLoadOp` patterns in this same file already perform this check; `RuntimeCreateOpLowering` was missing it.
With the fix, the op is left unconverted and the conversion framework reports it normally:
```
error: failed to legalize operation 'async.runtime.create' that was explicitly marked illegal
```
## Testing
Added `mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm-invalid.mlir` covering two non-convertible payload types.
Verified with an assertions-enabled build:
- the reproducer segfaults before the fix and reports a clean error after
- the new test fails without the fix and passes with it
- async values with convertible payloads (`!async.value<f32>`) still lower to `mlirAsyncRuntimeCreateValue`
- `mlir/test/Conversion/AsyncToLLVM` and `mlir/test/Dialect/Async` are 18/18, no regressions
>From 78760cedf236604ffc8748613a5462acf079c24b Mon Sep 17 00:00:00 2001
From: hamzaqureshi5 <hamza7771.861 at gmail.com>
Date: Sat, 15 Aug 2026 17:52:19 +0500
Subject: [PATCH] [mlir][async] Fix crash when lowering async values of
non-LLVM types
RuntimeCreateOpLowering computes the storage requirement of an async value by
emitting a GEP over the converted payload type. The result of the type
conversion was used without checking it, so a payload type with no LLVM
counterpart produced a null Type that reached TypeAttr::get, and the pass
crashed instead of reporting a failure.
Bail out when the payload type cannot be converted, matching the checks the
RuntimeStoreOp and RuntimeLoadOp patterns in this file already perform.
Fixes #216213
---
.../Conversion/AsyncToLLVM/AsyncToLLVM.cpp | 12 +++++++++---
.../convert-runtime-to-llvm-invalid.mlir | 19 +++++++++++++++++++
2 files changed, 28 insertions(+), 3 deletions(-)
create mode 100644 mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm-invalid.mlir
diff --git a/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp b/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
index 46e53e71d35f5..a143876c1f357 100644
--- a/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
+++ b/mlir/lib/Conversion/AsyncToLLVM/AsyncToLLVM.cpp
@@ -592,12 +592,18 @@ class RuntimeCreateOpLowering : public ConvertOpToLLVMPattern<RuntimeCreateOp> {
// To create a value we need to compute the storage requirement.
if (auto value = dyn_cast<ValueType>(resultType)) {
+ // Computing the storage requirement emits a GEP over the stored type, so
+ // the payload type must have an LLVM counterpart.
+ Type storedType = converter->convertType(value.getValueType());
+ if (!storedType)
+ return rewriter.notifyMatchFailure(
+ op, "failed to convert async value type to LLVM type");
+
// Returns the size requirements for the async value storage.
- auto sizeOf = [&](ValueType valueType) -> Value {
+ auto sizeOf = [&]() -> Value {
auto loc = op->getLoc();
auto i64 = rewriter.getI64Type();
- auto storedType = converter->convertType(valueType.getValueType());
auto storagePtrType =
AsyncAPI::opaquePointerType(rewriter.getContext());
@@ -611,7 +617,7 @@ class RuntimeCreateOpLowering : public ConvertOpToLLVMPattern<RuntimeCreateOp> {
};
rewriter.replaceOpWithNewOp<func::CallOp>(op, kCreateValue, resultType,
- sizeOf(value));
+ sizeOf());
return success();
}
diff --git a/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm-invalid.mlir b/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm-invalid.mlir
new file mode 100644
index 0000000000000..f04ec00268831
--- /dev/null
+++ b/mlir/test/Conversion/AsyncToLLVM/convert-runtime-to-llvm-invalid.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-opt %s -convert-async-to-llvm -split-input-file -verify-diagnostics
+
+// Computing the storage size of an async value emits a GEP over the converted
+// payload type. Payload types without an LLVM counterpart must be rejected
+// instead of building the GEP with a null type.
+
+func.func @create_value_unsupported_payload() {
+ // expected-error @below {{failed to legalize operation 'async.runtime.create'}}
+ %0 = async.runtime.create : !async.value<tensor<4xf32>>
+ return
+}
+
+// -----
+
+func.func @create_value_unsupported_payload_index() {
+ // expected-error @below {{failed to legalize operation 'async.runtime.create'}}
+ %0 = async.runtime.create : !async.value<tensor<?xindex>>
+ return
+}
More information about the Mlir-commits
mailing list