[Mlir-commits] [mlir] [mlir][sparse] Reject dense level after non-unique level in encoding verifier (PR #184157)
Mehdi Amini
llvmlistbot at llvm.org
Mon Mar 2 07:42:54 PST 2026
https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/184157
The sparse tensor iteration model for dense levels requires exactly one parent position to linearize into a contiguous range. However, when a non-unique level (e.g. compressed(nonunique)) precedes a dense level, the DedupIterator provides a two-element cursor {posLo, segHi}, causing DenseLevel::peekRangeAt to assert and crash with:
Assertion `parentPos.size() == 1 && "Dense level can not be non-unique."'
Fix this by adding a check in SparseTensorEncodingAttr::verify that rejects any encoding where a dense level directly follows a non-unique level, emitting a proper diagnostic instead of crashing during lowering.
Fixes #130008
>From edd7e0c82c2a7fa587c5d3f27528271ff8ac5274 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Mon, 2 Mar 2026 07:29:05 -0800
Subject: [PATCH] [mlir][sparse] Reject dense level after non-unique level in
encoding verifier
The sparse tensor iteration model for dense levels requires exactly one
parent position to linearize into a contiguous range. However, when a
non-unique level (e.g. compressed(nonunique)) precedes a dense level, the
DedupIterator provides a two-element cursor {posLo, segHi}, causing
DenseLevel::peekRangeAt to assert and crash with:
Assertion `parentPos.size() == 1 && "Dense level can not be non-unique."'
Fix this by adding a check in SparseTensorEncodingAttr::verify that
rejects any encoding where a dense level directly follows a non-unique
level, emitting a proper diagnostic instead of crashing during lowering.
Fixes #130008
---
.../Dialect/SparseTensor/IR/SparseTensorDialect.cpp | 9 +++++++++
mlir/test/Dialect/SparseTensor/invalid_encoding.mlir | 11 +++++++++++
2 files changed, 20 insertions(+)
diff --git a/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp b/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
index 3a34ad90941b0..05b2e07b88ba5 100644
--- a/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
+++ b/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
@@ -826,6 +826,15 @@ LogicalResult SparseTensorEncodingAttr::verify(
return emitError() << "SoA is only applicable to singleton lvlTypes.";
}
+ // Dense levels cannot follow a non-unique level. The iteration model for
+ // dense levels requires exactly one parent position to linearize into a
+ // contiguous range, but a non-unique parent provides two cursor values
+ // (segment start and end), which the dense level cannot handle.
+ for (auto [i, lt] : llvm::drop_begin(llvm::enumerate(lvlTypes))) {
+ if (isDenseLT(lt) && !isUniqueLT(lvlTypes[i - 1]))
+ return emitError() << "dense level cannot follow a non-unique level";
+ }
+
// TODO: audit formats that actually are supported by backend.
if (auto it = llvm::find_if(lvlTypes, isNOutOfMLT);
it != std::end(lvlTypes)) {
diff --git a/mlir/test/Dialect/SparseTensor/invalid_encoding.mlir b/mlir/test/Dialect/SparseTensor/invalid_encoding.mlir
index a3f72bd3ae971..0d0234149fb3e 100644
--- a/mlir/test/Dialect/SparseTensor/invalid_encoding.mlir
+++ b/mlir/test/Dialect/SparseTensor/invalid_encoding.mlir
@@ -256,6 +256,17 @@ func.func private @sparse_coo(tensor<?x?xf32, #COO_SoA>)
// -----
+// expected-error at +1{{dense level cannot follow a non-unique level}}
+#COO_Dense = #sparse_tensor.encoding<{
+ map = (i, j) -> (
+ i : compressed(nonunique),
+ j : dense
+ )
+}>
+func.func private @dense_after_nonunique(tensor<?x?xf32, #COO_Dense>)
+
+// -----
+
// expected-error at +2 {{use of undeclared identifier 'l1'}}
#TooFewLvlDecl = #sparse_tensor.encoding<{
map = {l0} (d0, d1) -> (l0 = d0 : dense, l1 = d1 : compressed)
More information about the Mlir-commits
mailing list