[Flow][NFC] Optimize dispatch annotation type string generation (#24675)

Use `getElementTypeOrSelf()` helper instead of manual ShapedType
checking
and cache operand type strings to avoid repeated computation.

This simplifies the code and improves maintainability.

Signed-off-by: cubehan3 <cubehan3@gmail.com>
diff --git a/compiler/src/iree/compiler/Dialect/Flow/Transforms/AnnotateDispatches.cpp b/compiler/src/iree/compiler/Dialect/Flow/Transforms/AnnotateDispatches.cpp
index f83e4a1..c377b47 100644
--- a/compiler/src/iree/compiler/Dialect/Flow/Transforms/AnnotateDispatches.cpp
+++ b/compiler/src/iree/compiler/Dialect/Flow/Transforms/AnnotateDispatches.cpp
@@ -133,14 +133,9 @@
 }
 
 static std::string operandTypeToString(Value operandValue) {
-  auto operandType = operandValue.getType();
   std::string outputString;
   llvm::raw_string_ostream sstream(outputString);
-  if (auto shapedType = dyn_cast<ShapedType>(operandType)) {
-    shapedType.getElementType().print(sstream);
-  } else {
-    operandType.print(sstream);
-  }
+  getElementTypeOrSelf(operandValue).print(sstream);
   return outputString;
 }
 
@@ -152,11 +147,12 @@
   SmallVector<std::string> datatypeTokens;
 
   for (Value operandValue : op->getOperands()) {
-    datatypeTokens.push_back(operandTypeToString(operandValue));
+    std::string typeStr = operandTypeToString(operandValue);
+    datatypeTokens.push_back(typeStr);
     if (firstToken.empty()) {
-      firstToken = operandTypeToString(operandValue);
+      firstToken = typeStr;
     } else if (allTokensSame) {
-      allTokensSame = firstToken == operandTypeToString(operandValue);
+      allTokensSame = firstToken == typeStr;
     }
   }