spirv-fuzz: Avoid invalidating analyses when splitting blocks (#4218)

It is easy to avoid the need to invalidate the def-use analysis and
instruction to block mapping when splitting blocks, and profiling has
revealed that invalidation of def-use in particular is expensive when
splitting many blocks. This change avoids these invalidations.
diff --git a/source/fuzz/transformation_split_block.cpp b/source/fuzz/transformation_split_block.cpp
index 00ef081..e15dffa 100644
--- a/source/fuzz/transformation_split_block.cpp
+++ b/source/fuzz/transformation_split_block.cpp
@@ -109,24 +109,37 @@
                                                 split_before);
   // The split does not automatically add a branch between the two parts of
   // the original block, so we add one.
-  block_to_split->AddInstruction(MakeUnique<opt::Instruction>(
+  auto branch_instruction = MakeUnique<opt::Instruction>(
       ir_context, SpvOpBranch, 0, 0,
       std::initializer_list<opt::Operand>{opt::Operand(
-          spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})}));
+          spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})});
+  auto branch_instruction_ptr = branch_instruction.get();
+  block_to_split->AddInstruction(std::move(branch_instruction));
+
+  // Inform the def-use manager about the branch instruction, and record its
+  // block.
+  ir_context->get_def_use_mgr()->AnalyzeInstDefUse(branch_instruction_ptr);
+  ir_context->set_instr_block(branch_instruction_ptr, block_to_split);
+
   // If we split before OpPhi instructions, we need to update their
   // predecessor operand so that the block they used to be inside is now the
   // predecessor.
-  new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) {
+  new_bb->ForEachPhiInst([block_to_split,
+                          ir_context](opt::Instruction* phi_inst) {
     assert(
         phi_inst->NumInOperands() == 2 &&
         "Precondition: a block can only be split before an OpPhi if the block"
         "has exactly one predecessor.");
     phi_inst->SetInOperand(1, {block_to_split->id()});
+    ir_context->UpdateDefUse(phi_inst);
   });
 
-  // Invalidate all analyses
+  // We have updated the def-use manager and the instruction to block mapping,
+  // but other analyses (especially control flow-related ones) need to be
+  // recomputed.
   ir_context->InvalidateAnalysesExceptFor(
-      opt::IRContext::Analysis::kAnalysisNone);
+      opt::IRContext::Analysis::kAnalysisDefUse |
+      opt::IRContext::Analysis::kAnalysisInstrToBlockMapping);
 
   // If the block being split was dead, the new block arising from the split is
   // also dead.