[Stream] Fix crash in ConvertSplatConstantsIntoSplats for dense_resource (#24683)
## Description
https://github.com/iree-org/iree/issues/24448 crashes because:
1. the frontend generates `DenseResourceElementsAttr` instead of
`SplatElementsAttr` for models, it satisfies `isSplat()` because the
`isSplat` has a default implementation and the tensor's elements share
the same value(for batchnorm, the weight is 1.0, the mean is 0.0 by
default)
2. the subsequent code attempts to `dyn_cast` the attribute to
`SplatElementsAttr` , which returns `nullptr` and causes a segfault upon
dereference.
## Solution
1. restrict the initial cast to `DenseElementsAttr`. since
`DenseResourceElementsAttr` does not inherit from `DenseElementsAttr`,
the cast will safely fail and we could return `failure()` as expected.
2. retrieve the splat value directly via
`DenseElementsAttr::getSplatValue()` , which is natively supported for
all splat-valued dense attributes
## E2E test
run
https://gist.github.com/hsqStephenZhang/31c9516a5b8788e7036061aae0ff46ba
before the fix, it leads to segfault. after the fix, it exit
successfully.
---------
Signed-off-by: hsqStephenZhang <stephenzhang666666@gmail.com>
Co-authored-by: Artem Gindinson <gindinson@roofline.ai>
diff --git a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamOpFolders.cpp b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamOpFolders.cpp
index 0305edf..665531a 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/IR/StreamOpFolders.cpp
+++ b/compiler/src/iree/compiler/Dialect/Stream/IR/StreamOpFolders.cpp
@@ -1515,12 +1515,11 @@
using Base::Base;
LogicalResult matchAndRewrite(AsyncConstantOp constantOp,
PatternRewriter &rewriter) const override {
- auto value = dyn_cast<ElementsAttr>(constantOp.getValue());
+ auto value = dyn_cast<DenseElementsAttr>(constantOp.getValue());
if (!value || !value.isSplat()) {
return failure();
}
- auto splatElementAttr =
- dyn_cast<SplatElementsAttr>(value).getSplatValue<TypedAttr>();
+ auto splatElementAttr = value.getSplatValue<TypedAttr>();
auto splatValue =
arith::ConstantOp::create(rewriter, constantOp.getLoc(),
splatElementAttr.getType(), splatElementAttr);
diff --git a/compiler/src/iree/compiler/Dialect/Stream/IR/test/async_folding.mlir b/compiler/src/iree/compiler/Dialect/Stream/IR/test/async_folding.mlir
index ee6c739..b8977e4 100644
--- a/compiler/src/iree/compiler/Dialect/Stream/IR/test/async_folding.mlir
+++ b/compiler/src/iree/compiler/Dialect/Stream/IR/test/async_folding.mlir
@@ -723,3 +723,21 @@
// CHECK: util.return %[[RESULT]]
util.return %1 : !stream.resource<*>
}
+
+// -----
+
+// Since dense_resource is not a true DenseElementsAttr splat, the pattern under test must leave it unchanged.
+
+// CHECK-LABEL: @NoConvertSplatConstantsIntoSplats_dense_resource
+util.func private @NoConvertSplatConstantsIntoSplats_dense_resource(%arg0: index) -> !stream.resource<transient> {
+ // CHECK: = stream.async.constant : !stream.resource<transient>{%arg0} = dense_resource<resource_i64> : tensor<1xi64>
+ %0 = stream.async.constant : !stream.resource<transient>{%arg0} = dense_resource<resource_i64> : tensor<1xi64>
+ util.return %0 : !stream.resource<transient>
+}
+{-#
+ dialect_resources: {
+ builtin: {
+ resource_i64: "0x080000000100000000000000"
+ }
+ }
+#-}