Skip to content

Reland "[mlir][Affine] Handle null parent op in getAffineParallelInductionVarOwner" #142785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 4, 2025

Conversation

hanhanW
Copy link
Contributor

@hanhanW hanhanW commented Jun 4, 2025

Below is the original commit description. Furthermore, it applies a fix for CMakeList.txt

The issue occurs during a downstream pass which does dialect conversion, where both FuncOpConversion and SubviewFolder are run together. The original starting IR is:

module {
  func.func @foo(%arg0: memref<100x100xf32>, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> memref<?x?xf32, strided<[100, 1], offset: ?>> {
    %subview = memref.subview %arg0[%arg1, %arg2] [%arg3, %arg4] [1, 1] : memref<100x100xf32> to memref<?x?xf32, strided<[100, 1], offset: ?>>
    return %subview : memref<?x?xf32, strided<[100, 1], offset: ?>>
  }
}

After FuncOpConversion runs, the IR looks like:

"builtin.module"() ({
  "llvm.func"() <{CConv = #llvm.cconv<ccc>, function_type = !llvm.func<struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)> (ptr, ptr, i64, i64, i64, i64, i64, i64, i64, i64, i64)>, linkage = #llvm.linkage<external>, sym_name = "foo", visibility_ = 0 : i64}> ({
  ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: i64, %arg8: i64, %arg9: i64, %arg10: i64):
    %0 = "memref.subview"(<<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>) <{operandSegmentSizes = array<i32: 1, 2, 2, 0>, static_offsets = array<i64: -9223372036854775808, -9223372036854775808>, static_sizes = array<i64: -9223372036854775808, -9223372036854775808>, static_strides = array<i64: 1, 1>}> : (memref<100x100xf32>, index, index, index, index) -> memref<?x?xf32, strided<[100, 1], offset: ?>>
    "func.return"(%0) : (memref<?x?xf32, strided<[100, 1], offset: ?>>) -> ()
  }) : () -> ()
  "func.func"() <{function_type = (memref<100x100xf32>, index, index, index, index) -> memref<?x?xf32, strided<[100, 1], offset: ?>>, sym_name = "foo"}> ({
  }) : () -> ()
}) {llvm.data_layout = "", llvm.target_triple = ""} : () -> ()

The <<UNKNOWN SSA VALUE>>'s here are block arguments of a separate unlinked block, which is disconnected from the rest of the IR (so not only is the IR verifier-invalid, it can't even be parsed). This IR is created by signature conversion in the dialect conversion infra.

Now SubviewFolder is applied, and the utility function here is called on one of these disconnected block arguments, causing a crash.

The TestMemRefToLLVMWithTransforms pass is introduced to exercise the bug, and it can be reused by other contributors in the future.

Co-authored-by: Rahul Kayaith rkayaith@gmail.com

hanhanW added 2 commits June 4, 2025 07:26
Signed-off-by: hanhanW <hanhan0912@gmail.com>
@hanhanW hanhanW requested a review from kparzysz June 4, 2025 15:13
@llvmbot llvmbot added mlir:core MLIR Core Infrastructure mlir:affine mlir labels Jun 4, 2025
@hanhanW hanhanW requested a review from jplehr June 4, 2025 15:14
@llvmbot
Copy link
Member

llvmbot commented Jun 4, 2025

@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-affine

Author: Han-Chung Wang (hanhanW)

Changes

Below is the original commit description. Furthermore, it applies a fix for CMakeList.txt

The issue occurs during a downstream pass which does dialect conversion, where both FuncOpConversion and SubviewFolder are run together. The original starting IR is:

module {
  func.func @<!-- -->foo(%arg0: memref&lt;100x100xf32&gt;, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -&gt; memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt; {
    %subview = memref.subview %arg0[%arg1, %arg2] [%arg3, %arg4] [1, 1] : memref&lt;100x100xf32&gt; to memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt;
    return %subview : memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt;
  }
}

After FuncOpConversion runs, the IR looks like:

"builtin.module"() ({
  "llvm.func"() &lt;{CConv = #llvm.cconv&lt;ccc&gt;, function_type = !llvm.func&lt;struct&lt;(ptr, ptr, i64, array&lt;2 x i64&gt;, array&lt;2 x i64&gt;)&gt; (ptr, ptr, i64, i64, i64, i64, i64, i64, i64, i64, i64)&gt;, linkage = #llvm.linkage&lt;external&gt;, sym_name = "foo", visibility_ = 0 : i64}&gt; ({
  ^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64, %arg3: i64, %arg4: i64, %arg5: i64, %arg6: i64, %arg7: i64, %arg8: i64, %arg9: i64, %arg10: i64):
    %0 = "memref.subview"(&lt;&lt;UNKNOWN SSA VALUE&gt;&gt;, &lt;&lt;UNKNOWN SSA VALUE&gt;&gt;, &lt;&lt;UNKNOWN SSA VALUE&gt;&gt;, &lt;&lt;UNKNOWN SSA VALUE&gt;&gt;, &lt;&lt;UNKNOWN SSA VALUE&gt;&gt;) &lt;{operandSegmentSizes = array&lt;i32: 1, 2, 2, 0&gt;, static_offsets = array&lt;i64: -9223372036854775808, -9223372036854775808&gt;, static_sizes = array&lt;i64: -9223372036854775808, -9223372036854775808&gt;, static_strides = array&lt;i64: 1, 1&gt;}&gt; : (memref&lt;100x100xf32&gt;, index, index, index, index) -&gt; memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt;
    "func.return"(%0) : (memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt;) -&gt; ()
  }) : () -&gt; ()
  "func.func"() &lt;{function_type = (memref&lt;100x100xf32&gt;, index, index, index, index) -&gt; memref&lt;?x?xf32, strided&lt;[100, 1], offset: ?&gt;&gt;, sym_name = "foo"}&gt; ({
  }) : () -&gt; ()
}) {llvm.data_layout = "", llvm.target_triple = ""} : () -&gt; ()

The &lt;&lt;UNKNOWN SSA VALUE&gt;&gt;'s here are block arguments of a separate unlinked block, which is disconnected from the rest of the IR (so not only is the IR verifier-invalid, it can't even be parsed). This IR is created by signature conversion in the dialect conversion infra.

Now SubviewFolder is applied, and the utility function here is called on one of these disconnected block arguments, causing a crash.

The TestMemRefToLLVMWithTransforms pass is introduced to exercise the bug, and it can be reused by other contributors in the future.

Co-authored-by: Rahul Kayaith <rkayaith@gmail.com>


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

7 Files Affected:

  • (modified) mlir/lib/Dialect/Affine/IR/AffineOps.cpp (+1-1)
  • (added) mlir/test/Conversion/MemRefToLLVM/memref-to-llvm-with-transforms.mlir (+10)
  • (modified) mlir/test/lib/Conversion/CMakeLists.txt (+1)
  • (added) mlir/test/lib/Conversion/MemRefToLLVM/CMakeLists.txt (+22)
  • (added) mlir/test/lib/Conversion/MemRefToLLVM/TestMemRefToLLVMWithTransforms.cpp (+62)
  • (modified) mlir/tools/mlir-opt/CMakeLists.txt (+1)
  • (modified) mlir/tools/mlir-opt/mlir-opt.cpp (+2)
diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 2364f8957992d..8a708eb29210c 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -2667,7 +2667,7 @@ AffineParallelOp mlir::affine::getAffineParallelInductionVarOwner(Value val) {
   if (!ivArg || !ivArg.getOwner())
     return nullptr;
   Operation *containingOp = ivArg.getOwner()->getParentOp();
-  auto parallelOp = dyn_cast<AffineParallelOp>(containingOp);
+  auto parallelOp = dyn_cast_if_present<AffineParallelOp>(containingOp);
   if (parallelOp && llvm::is_contained(parallelOp.getIVs(), val))
     return parallelOp;
   return nullptr;
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm-with-transforms.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm-with-transforms.mlir
new file mode 100644
index 0000000000000..f6d0524fce39d
--- /dev/null
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm-with-transforms.mlir
@@ -0,0 +1,10 @@
+// RUN: mlir-opt -test-memref-to-llvm-with-transforms %s | FileCheck %s
+
+// Checks that the program does not crash. The functionality of the pattern is
+// already checked in test/Dialect/MemRef/*.mlir
+
+func.func @subview_folder(%arg0: memref<100x100xf32>, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> memref<?x?xf32, strided<[100, 1], offset: ?>> {
+  %subview = memref.subview %arg0[%arg1, %arg2] [%arg3, %arg4] [1, 1] : memref<100x100xf32> to memref<?x?xf32, strided<[100, 1], offset: ?>>
+  return %subview : memref<?x?xf32, strided<[100, 1], offset: ?>>
+}
+// CHECK-LABEL: llvm.func @subview_folder
diff --git a/mlir/test/lib/Conversion/CMakeLists.txt b/mlir/test/lib/Conversion/CMakeLists.txt
index c09496be729be..167cce225595b 100644
--- a/mlir/test/lib/Conversion/CMakeLists.txt
+++ b/mlir/test/lib/Conversion/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory(ConvertToSPIRV)
 add_subdirectory(FuncToLLVM)
 add_subdirectory(MathToVCIX)
+add_subdirectory(MemRefToLLVM)
 add_subdirectory(VectorToSPIRV)
diff --git a/mlir/test/lib/Conversion/MemRefToLLVM/CMakeLists.txt b/mlir/test/lib/Conversion/MemRefToLLVM/CMakeLists.txt
new file mode 100644
index 0000000000000..580c9ca4a6049
--- /dev/null
+++ b/mlir/test/lib/Conversion/MemRefToLLVM/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Exclude tests from libMLIR.so
+add_mlir_library(MLIRTestMemRefToLLVMWithTransforms
+  TestMemRefToLLVMWithTransforms.cpp
+
+  EXCLUDE_FROM_LIBMLIR
+
+  LINK_LIBS PUBLIC
+  MLIRTestDialect
+  )
+mlir_target_link_libraries(MLIRTestMemRefToLLVMWithTransforms PUBLIC
+  MLIRFuncToLLVM
+  MLIRLLVMCommonConversion
+  MLIRLLVMDialect
+  MLIRMemRefTransforms
+  MLIRPass
+  )
+
+target_include_directories(MLIRTestMemRefToLLVMWithTransforms
+  PRIVATE
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../Dialect/Test
+  ${CMAKE_CURRENT_BINARY_DIR}/../../Dialect/Test
+  )
diff --git a/mlir/test/lib/Conversion/MemRefToLLVM/TestMemRefToLLVMWithTransforms.cpp b/mlir/test/lib/Conversion/MemRefToLLVM/TestMemRefToLLVMWithTransforms.cpp
new file mode 100644
index 0000000000000..af3b6608aea16
--- /dev/null
+++ b/mlir/test/lib/Conversion/MemRefToLLVM/TestMemRefToLLVMWithTransforms.cpp
@@ -0,0 +1,62 @@
+//===- TestMemRefToLLVMWithTransforms.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
+#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
+#include "mlir/Conversion/LLVMCommon/LoweringOptions.h"
+#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
+#include "mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/MemRef/Transforms/Transforms.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Pass/Pass.h"
+
+using namespace mlir;
+
+namespace {
+
+struct TestMemRefToLLVMWithTransforms
+    : public PassWrapper<TestMemRefToLLVMWithTransforms,
+                         OperationPass<ModuleOp>> {
+  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestMemRefToLLVMWithTransforms)
+
+  void getDependentDialects(DialectRegistry &registry) const final {
+    registry.insert<LLVM::LLVMDialect>();
+  }
+
+  StringRef getArgument() const final {
+    return "test-memref-to-llvm-with-transforms";
+  }
+
+  StringRef getDescription() const final {
+    return "Tests conversion of MemRef dialects + `func.func` to LLVM dialect "
+           "with MemRef transforms.";
+  }
+
+  void runOnOperation() override {
+    MLIRContext *ctx = &getContext();
+    LowerToLLVMOptions options(ctx);
+    LLVMTypeConverter typeConverter(ctx, options);
+    RewritePatternSet patterns(ctx);
+    memref::populateExpandStridedMetadataPatterns(patterns);
+    populateFuncToLLVMConversionPatterns(typeConverter, patterns);
+    LLVMConversionTarget target(getContext());
+    if (failed(applyPartialConversion(getOperation(), target,
+                                      std::move(patterns))))
+      signalPassFailure();
+  }
+};
+
+} // namespace
+
+namespace mlir::test {
+void registerTestMemRefToLLVMWithTransforms() {
+  PassRegistration<TestMemRefToLLVMWithTransforms>();
+}
+} // namespace mlir::test
diff --git a/mlir/tools/mlir-opt/CMakeLists.txt b/mlir/tools/mlir-opt/CMakeLists.txt
index 34db3051d36a0..26d7597347a8a 100644
--- a/mlir/tools/mlir-opt/CMakeLists.txt
+++ b/mlir/tools/mlir-opt/CMakeLists.txt
@@ -28,6 +28,7 @@ if(MLIR_INCLUDE_TESTS)
     MLIRMathTestPasses
     MLIRTestMathToVCIX
     MLIRMemRefTestPasses
+    MLIRTestMemRefToLLVMWithTransforms
     MLIRMeshTest
     MLIRNVGPUTestPasses
     MLIRSCFTestPasses
diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp
index 2e08ae6f37980..6ef9ff8e84545 100644
--- a/mlir/tools/mlir-opt/mlir-opt.cpp
+++ b/mlir/tools/mlir-opt/mlir-opt.cpp
@@ -130,6 +130,7 @@ void registerTestMathToVCIXPass();
 void registerTestIrdlTestDialectConversionPass();
 void registerTestMemRefDependenceCheck();
 void registerTestMemRefStrideCalculation();
+void registerTestMemRefToLLVMWithTransforms();
 void registerTestMeshReshardingSpmdizationPass();
 void registerTestMeshSimplificationsPass();
 void registerTestMultiBuffering();
@@ -275,6 +276,7 @@ void registerTestPasses() {
   mlir::test::registerTestMathToVCIXPass();
   mlir::test::registerTestMemRefDependenceCheck();
   mlir::test::registerTestMemRefStrideCalculation();
+  mlir::test::registerTestMemRefToLLVMWithTransforms();
   mlir::test::registerTestMeshReshardingSpmdizationPass();
   mlir::test::registerTestMeshSimplificationsPass();
   mlir::test::registerTestMultiBuffering();

@hanhanW hanhanW merged commit 07a5341 into llvm:main Jun 4, 2025
11 of 13 checks passed
@hanhanW hanhanW deleted the iree-issue-20928-2 branch June 4, 2025 15:32
hanhanW added a commit that referenced this pull request Jun 4, 2025
hanhanW added a commit that referenced this pull request Jun 4, 2025
…allelInductionVarOwner" (#142785)"

This reverts commit 178b64e.

The author misread the report of the failure, and thought that it broke
the CI again. Reland the fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:affine mlir:core MLIR Core Infrastructure mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants