[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"
+    }
+  }
+#-}