Skip to content

[MLIR][ArithToLLVM] Fix index_cast on memref types generating invalid LLVM IR#189227

Merged
joker-eph merged 1 commit into
llvm:mainfrom
joker-eph:fix/issue-92377
Apr 1, 2026
Merged

[MLIR][ArithToLLVM] Fix index_cast on memref types generating invalid LLVM IR#189227
joker-eph merged 1 commit into
llvm:mainfrom
joker-eph:fix/issue-92377

Conversation

@joker-eph
Copy link
Copy Markdown
Contributor

arith.index_cast and arith.index_castui accept memref operands (via IndexCastTypeConstraint), but IndexCastOpLowering::matchAndRewrite did not handle this case. When the operand was a memref, the conversion framework substituted the converted LLVM struct type, and the lowering incorrectly attempted to emit llvm.sext/llvm.zext/llvm.trunc on a struct value, producing invalid LLVM IR.

Since LLVM uses opaque pointers, all memrefs with integer or index element types lower to the same \!llvm.struct<(ptr, ptr, i64, ...)> type, making arith.index_cast on memrefs a no-op at the LLVM level. Add a check that treats the memref case as an identity conversion (same as the same-bit-width path).

Fixes #92377

Assisted-by: Claude Code

… LLVM IR

`arith.index_cast` and `arith.index_castui` accept memref operands (via
`IndexCastTypeConstraint`), but `IndexCastOpLowering::matchAndRewrite` did
not handle this case. When the operand was a memref, the conversion
framework substituted the converted LLVM struct type, and the lowering
incorrectly attempted to emit `llvm.sext`/`llvm.zext`/`llvm.trunc` on a
struct value, producing invalid LLVM IR.

Since LLVM uses opaque pointers, all memrefs with integer or index element
types lower to the same `\!llvm.struct<(ptr, ptr, i64, ...)>` type, making
`arith.index_cast` on memrefs a no-op at the LLVM level. Add a check that
treats the memref case as an identity conversion (same as the
same-bit-width path).

Fixes llvm#92377

Assisted-by: Claude Code
@joker-eph joker-eph requested a review from amd-eochoalo March 29, 2026 11:43
@joker-eph joker-eph requested a review from kuhar as a code owner March 29, 2026 11:43
@llvmbot llvmbot added the mlir label Mar 29, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 29, 2026

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

Changes

arith.index_cast and arith.index_castui accept memref operands (via IndexCastTypeConstraint), but IndexCastOpLowering::matchAndRewrite did not handle this case. When the operand was a memref, the conversion framework substituted the converted LLVM struct type, and the lowering incorrectly attempted to emit llvm.sext/llvm.zext/llvm.trunc on a struct value, producing invalid LLVM IR.

Since LLVM uses opaque pointers, all memrefs with integer or index element types lower to the same \!llvm.struct&lt;(ptr, ptr, i64, ...)&gt; type, making arith.index_cast on memrefs a no-op at the LLVM level. Add a check that treats the memref case as an identity conversion (same as the same-bit-width path).

Fixes #92377

Assisted-by: Claude Code


Full diff: https://github.com/llvm/llvm-project/pull/189227.diff

2 Files Affected:

  • (modified) mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp (+8)
  • (modified) mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir (+24)
diff --git a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
index 11aae4de26c1e..f9ea8dba105a4 100644
--- a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
+++ b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
@@ -368,6 +368,14 @@ LogicalResult IndexCastOpLowering<OpTy, ExtCastTy>::matchAndRewrite(
     return success();
   }
 
+  // Memref index_cast is a no-op at the LLVM level since LLVM uses opaque
+  // pointers and memrefs of different integer/index element types all convert
+  // to the same LLVM struct type.
+  if (isa<MemRefType>(op.getIn().getType())) {
+    rewriter.replaceOp(op, adaptor.getIn());
+    return success();
+  }
+
   bool isNonNeg = false;
   if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>)
     isNonNeg = op.getNonNeg();
diff --git a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
index 6a6016c4f5b16..75601e215744c 100644
--- a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
+++ b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
@@ -160,6 +160,30 @@ func.func @index_castui_nneg_not_set(%arg0: i1) {
 
 // -----
 
+// Memref index_cast is a no-op at the LLVM level since LLVM uses opaque
+// pointers and all memrefs with integer or index element types convert to the
+// same struct type. Verify that no sext/zext/trunc is generated.
+
+// CHECK-LABEL: @memref_index_cast
+// CHECK-NOT: llvm.sext
+// CHECK-NOT: llvm.trunc
+func.func @memref_index_cast(%arg0: memref<3xi32>) -> memref<3xindex> {
+  %0 = arith.index_cast %arg0 : memref<3xi32> to memref<3xindex>
+  return %0 : memref<3xindex>
+}
+
+// -----
+
+// CHECK-LABEL: @memref_index_castui
+// CHECK-NOT: llvm.zext
+// CHECK-NOT: llvm.trunc
+func.func @memref_index_castui(%arg0: memref<3xi32>) -> memref<3xindex> {
+  %0 = arith.index_castui %arg0 : memref<3xi32> to memref<3xindex>
+  return %0 : memref<3xindex>
+}
+
+// -----
+
 // Checking conversion of signed integer types to floating point.
 // CHECK-LABEL: @sitofp
 func.func @sitofp(%arg0 : i32, %arg1 : i64) {

@ftynse
Copy link
Copy Markdown
Member

ftynse commented Apr 1, 2026

Though I'm rather surprised that we can even arith.index_cast a memref. This feels dangerous from the strict aliasing perspective.

@joker-eph
Copy link
Copy Markdown
Contributor Author

Do we have some documentation on strict aliasing expectations on Memref? (by this you mean "type based aliasing" I assume).

I looked at https://mlir.llvm.org/docs/Dialects/MemRef/ but there is no mention of alias (almost).

@joker-eph joker-eph merged commit 249e871 into llvm:main Apr 1, 2026
12 checks passed
@ftynse
Copy link
Copy Markdown
Member

ftynse commented Apr 1, 2026

I don't think there are such expectations, hence just expressing surprise rather than blocking the patch

@joker-eph
Copy link
Copy Markdown
Contributor Author

Yeah I was asking because maybe we should document it (one way or another)

joaovam pushed a commit to joaovam/llvm-project that referenced this pull request Apr 2, 2026
… LLVM IR (llvm#189227)

`arith.index_cast` and `arith.index_castui` accept memref operands (via
`IndexCastTypeConstraint`), but `IndexCastOpLowering::matchAndRewrite`
did not handle this case. When the operand was a memref, the conversion
framework substituted the converted LLVM struct type, and the lowering
incorrectly attempted to emit `llvm.sext`/`llvm.zext`/`llvm.trunc` on a
struct value, producing invalid LLVM IR.

Since LLVM uses opaque pointers, all memrefs with integer or index
element types lower to the same `\!llvm.struct<(ptr, ptr, i64, ...)>`
type, making `arith.index_cast` on memrefs a no-op at the LLVM level.
Add a check that treats the memref case as an identity conversion (same
as the same-bit-width path).

Fixes llvm#92377

Assisted-by: Claude Code
zwu-2025 pushed a commit to zwu-2025/llvm-project that referenced this pull request May 17, 2026
… LLVM IR (llvm#189227)

`arith.index_cast` and `arith.index_castui` accept memref operands (via
`IndexCastTypeConstraint`), but `IndexCastOpLowering::matchAndRewrite`
did not handle this case. When the operand was a memref, the conversion
framework substituted the converted LLVM struct type, and the lowering
incorrectly attempted to emit `llvm.sext`/`llvm.zext`/`llvm.trunc` on a
struct value, producing invalid LLVM IR.

Since LLVM uses opaque pointers, all memrefs with integer or index
element types lower to the same `\!llvm.struct<(ptr, ptr, i64, ...)>`
type, making `arith.index_cast` on memrefs a no-op at the LLVM level.
Add a check that treats the memref case as an identity conversion (same
as the same-bit-width path).

Fixes llvm#92377

Assisted-by: Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MLIR] ArithToLLVM fails to convert arith.index_cast operations with memref operands

3 participants