diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp index 7d9058c262562..8f3c0dac026a7 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp @@ -1585,6 +1585,9 @@ DeletionKind LLVM::MemmoveOp::rewire(const DestructurableMemorySlot &slot, std::optional> LLVM::LLVMStructType::getSubelementIndexMap() const { + // Empty structs have no sub-elements and cannot be destructured. + if (getBody().empty()) + return std::nullopt; Type i32 = IntegerType::get(getContext(), 32); DenseMap destructured; for (const auto &[index, elemType] : llvm::enumerate(getBody())) diff --git a/mlir/test/Dialect/LLVMIR/sroa.mlir b/mlir/test/Dialect/LLVMIR/sroa.mlir index 1674bbd8c796f..b019e66d5a430 100644 --- a/mlir/test/Dialect/LLVMIR/sroa.mlir +++ b/mlir/test/Dialect/LLVMIR/sroa.mlir @@ -448,3 +448,18 @@ llvm.func @out_of_bound_gep_array_access(%arg: i32) { llvm.store %arg, %2 : i32, !llvm.ptr llvm.return } + +// ----- + +// Regression test: SROA must not crash when processing an alloca of an empty +// struct type. Empty structs have no sub-elements and cannot be destructured, +// so the alloca must be left unchanged. +// https://github.com/llvm/llvm-project/issues/108366 +// CHECK-LABEL: llvm.func @empty_struct_not_destructured +llvm.func @empty_struct_not_destructured() -> !llvm.struct<()> { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: llvm.alloca %{{.*}} x !llvm.struct<()> + %1 = llvm.alloca %0 x !llvm.struct<()> : (i32) -> !llvm.ptr + %2 = llvm.load %1 : !llvm.ptr -> !llvm.struct<()> + llvm.return %2 : !llvm.struct<()> +}