[GlobalOpt] Fix crash in RaiseSpecialOps on buffer-semantics named ops (#24626)

## Problem

Passing a `linalg.matmul` (or any named contraction/convolution op) with
**memref / buffer operands** to `iree-compile` crashes with a hard
assert instead of a clean diagnostic:

```
Assertion failed: (index < size() && "invalid index into type range"),
function operator[], file TypeRange.h, line 156.
...
NamedImplicitCastOpConversion<linalg::ContractionOpInterface>::matchAndRewrite(...)
```

`NamedImplicitCastOpConversion::matchAndRewrite` in
`GlobalOptimization/RaiseSpecialOps.cpp` reasons about the op's results
(`getResultTypes()[0]`) and rewrites its body region, both of which
assume tensor semantics. A buffer-semantics linalg op writes to an
output buffer and has **zero results**, so `getResultTypes()[0]` indexes
an empty `TypeRange` and aborts.

## Fix

Bail out via `hasPureTensorSemantics()` before touching results,
matching the guards already used elsewhere in this file (e.g. lines 48,
231). The op is left untouched and compilation proceeds normally.

## Verification (local, llvm-cpu)

A/B on identical current `main` sources, exact reproducer from the
issue:

| Build | `iree-compile ... memref matmul` |
|---|---|
| unfixed (`main`) | exit **134**, assert in
`NamedImplicitCastOpConversion` |
| fixed (this PR) | exit **0**, compiles cleanly to a valid `.vmfb` |

- Added lit test `@matmul_memref_no_crash` in `raise_special_ops.mlir`.
- Full `raise_special_ops.mlir` lit suite passes.

Fixes #24624

Signed-off-by: Alex-Wengg <hanweng9@gmail.com>
diff --git a/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp b/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
index 4077d76..3ca4d33 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
+++ b/compiler/src/iree/compiler/GlobalOptimization/RaiseSpecialOps.cpp
@@ -284,6 +284,12 @@
       return failure();
     }
 
+    auto linalgOp = dyn_cast<linalg::LinalgOp>(namedOp.getOperation());
+    if (!linalgOp || !linalgOp.hasPureTensorSemantics()) {
+      return rewriter.notifyMatchFailure(
+          namedOp, "expected an op with pure tensor semantics");
+    }
+
     // Look for a producer of the given operand that does an elementwise extend
     // and replace the operand with the source of the elementwise producer.
     // Returns true if the operand was updated to inform the pattern rewriter
diff --git a/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir b/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
index 877b169..6b3e22a 100644
--- a/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
+++ b/compiler/src/iree/compiler/GlobalOptimization/test/raise_special_ops.mlir
@@ -921,3 +921,15 @@
 //       CHECK:   %[[PAD:.+]] = tensor.pad %[[ARG0]] low[1, 2] high[%[[H0]], %[[H1]]]
 //       CHECK:     tensor.yield %[[C1]]
 //       CHECK:   util.return %[[PAD]]
+
+// -----
+
+util.func public @matmul_memref_no_crash(%arg0: memref<10x20xf32>,
+    %arg1: memref<20x40xf32>, %arg2: memref<10x40xf32>) {
+  linalg.matmul ins(%arg0, %arg1 : memref<10x20xf32>, memref<20x40xf32>)
+      outs(%arg2 : memref<10x40xf32>)
+  util.return
+}
+// CHECK-LABEL: util.func public @matmul_memref_no_crash
+//       CHECK:   linalg.matmul
+//       CHECK:   util.return