SpirvShader: Fix another edge case with phis and loops

If the merge block M contains phis, and M is a loop header of a second loop, we will get assertions that the back edges of the second loop have not yet been generated.

We're only trying to update the phis of M for the lane exits of the first loop, so filter the phi updates to edges from those blocks.

Bug: b/139424793
Change-Id: Idc197fb93c28cdc4b91174a687179f9fc498344a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35208
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index f9a1572..061d9cf 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -2276,18 +2276,19 @@
 			return; // Already emitted this loop.
 		}
 
-		std::unordered_set<Block::ID> incomingBlocks;
+		// Gather all the blocks that make up the loop.
 		std::unordered_set<Block::ID> loopBlocks;
+		loopBlocks.emplace(block.mergeBlock);
+		function.TraverseReachableBlocks(blockId, loopBlocks);
+
+		// incomingBlocks are block ins that are not back-edges.
+		std::unordered_set<Block::ID> incomingBlocks;
 		for (auto in : block.ins)
 		{
-			if (!function.ExistsPath(blockId, in, mergeBlockId)) // if not a loop back-edge
+			if (loopBlocks.count(in) == 0)
 			{
 				incomingBlocks.emplace(in);
 			}
-			else
-			{
-				loopBlocks.emplace(in);
-			}
 		}
 
 		// Emit the loop phi instructions, and initialize them with a value from
@@ -2408,7 +2409,7 @@
 		{
 			if (insn.opcode() == spv::OpPhi)
 			{
-				StorePhi(mergeBlockId, insn, state, mergeBlock.ins);
+				StorePhi(mergeBlockId, insn, state, loopBlocks);
 			}
 		}
 
@@ -6692,8 +6693,7 @@
 		}
 	}
 
-
-	void SpirvShader::Function::TraverseReachableBlocks(Block::ID id, SpirvShader::Block::Set& reachable)
+	void SpirvShader::Function::TraverseReachableBlocks(Block::ID id, SpirvShader::Block::Set& reachable) const
 	{
 		if (reachable.count(id) == 0)
 		{
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 412d7a2..6d77117 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -578,7 +578,7 @@
 
 			// Walks all reachable the blocks starting from id adding them to
 			// reachable.
-			void TraverseReachableBlocks(Block::ID id, Block::Set& reachable);
+			void TraverseReachableBlocks(Block::ID id, Block::Set& reachable) const;
 
 			// AssignBlockFields() performs the following for all reachable blocks:
 			// * Assigns Block::ins with the identifiers of all blocks that contain