reader/spirv: Optimize FindUnusedDerivedName()

Store the last search id suffix so that we don't research the same suffixes over and over again.

Bug: oss-fuzz:38098
Bug: oss-fuzz:38606
Bug: oss-fuzz:39300
Bug: oss-fuzz:40339
Change-Id: I295147d91bb9f805170c49114267033bbb781e4d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/75427
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/spirv/namer.cc b/src/reader/spirv/namer.cc
index 4d819b4..c2b2e98 100644
--- a/src/reader/spirv/namer.cc
+++ b/src/reader/spirv/namer.cc
@@ -104,20 +104,24 @@
   return result;
 }
 
-std::string Namer::FindUnusedDerivedName(const std::string& base_name) const {
+std::string Namer::FindUnusedDerivedName(const std::string& base_name) {
   // Ensure uniqueness among names.
   std::string derived_name;
-  int i = 0;
-  do {
+  uint32_t& i = next_unusued_derived_name_id_[base_name];
+  while (i != 0xffffffff) {
     std::stringstream new_name_stream;
     new_name_stream << base_name;
     if (i > 0) {
       new_name_stream << "_" << i;
     }
-    i++;
     derived_name = new_name_stream.str();
-  } while (IsRegistered(derived_name));
-  return derived_name;
+    if (!IsRegistered(derived_name)) {
+      return derived_name;
+    }
+    i++;
+  }
+  TINT_ASSERT(Reader, false /* FindUnusedDerivedName() overflowed u32 */);
+  return "<u32 overflow>";
 }
 
 std::string Namer::MakeDerivedName(const std::string& base_name) {
diff --git a/src/reader/spirv/namer.h b/src/reader/spirv/namer.h
index 1d231f4..c17d9f0 100644
--- a/src/reader/spirv/namer.h
+++ b/src/reader/spirv/namer.h
@@ -92,7 +92,7 @@
   /// Returns an unregistered name based on a given base name.
   /// @param base_name the base name
   /// @returns a new name
-  std::string FindUnusedDerivedName(const std::string& base_name) const;
+  std::string FindUnusedDerivedName(const std::string& base_name);
 
   /// Returns a newly registered name based on a given base name.
   /// In the internal table `name_to_id_`, it is mapped to the invalid
@@ -152,6 +152,10 @@
   // If entry k in the vector is an empty string, then a suggestion
   // was recorded for a higher-numbered index, but not for index k.
   std::unordered_map<uint32_t, std::vector<std::string>> struct_member_names_;
+
+  // Saved search id suffix for a given base name. Used by
+  // FindUnusedDerivedName().
+  std::unordered_map<std::string, uint32_t> next_unusued_derived_name_id_;
 };
 
 }  // namespace spirv