spirv-fuzz: Fix GetIdEquivalenceClasses (#3767)

Pointer (if VariablePointers is enabled) to find sets of potential
synonyms.

However, some instructions with these types cannot be used in an OpPhi:

- OpFunction cannot be used as a value
- OpUndef should not be used, because it yields an undefined value for
  each use
Fixes #3761.
diff --git a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
index 97adfb2..88cc830 100644
--- a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
@@ -167,6 +167,15 @@
       continue;
     }
 
+    // Exclude OpFunction and OpUndef instructions, because:
+    // - OpFunction does not yield a value;
+    // - OpUndef yields an undefined value at each use, so it should never be a
+    //   synonym of another id.
+    if (pair.second->opcode() == SpvOpFunction ||
+        pair.second->opcode() == SpvOpUndef) {
+      continue;
+    }
+
     // We need a new equivalence class for this id.
     std::set<uint32_t> new_equivalence_class;
 
diff --git a/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp b/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp
index 9341b56..39da98f 100644
--- a/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp
+++ b/test/fuzz/fuzzer_pass_add_opphi_synonyms_test.cpp
@@ -76,6 +76,7 @@
           %5 = OpTypeBool
           %6 = OpConstantTrue %5
           %7 = OpTypeInt 32 1
+         %31 = OpTypeFunction %7
           %8 = OpTypeInt 32 0
           %9 = OpConstant %7 1
          %10 = OpConstant %7 2
@@ -109,6 +110,10 @@
          %28 = OpLabel
                OpReturn
                OpFunctionEnd
+         %32 = OpFunction %7 None %31
+         %33 = OpLabel
+               OpReturnValue %9
+               OpFunctionEnd
 )";
 
 TEST(FuzzerPassAddOpPhiSynonymsTest, HelperFunctions) {