SpirvShader: Document activeLaneMask() and storesAndAtomicsMask()

These had no documentation and it took me a while to figure out what the distinction was between them.

I've also added the currently unused activeStoresAndAtomicsMask() method.
While I'm not keen on adding dead code, the other two methods make reference to the fact this is the method you probably want to use if you are doing something that has side effects.
Given that it's inline, it should have no bloat to the final binary while it is currently unused.

Bug: b/140294254
Change-Id: I0f1517aef86679f277d998f2a3fb301cf657f03a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44369
Kokoro-Result: 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.hpp b/src/Pipeline/SpirvShader.hpp
index dd05d8e..4524783 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -919,18 +919,38 @@
 			ASSERT(executionModelToStage(executionModel) != VkShaderStageFlagBits(0));  // Must parse OpEntryPoint before emitting.
 		}
 
+		// Returns the mask describing the active lanes as updated by dynamic
+		// control flow. Active lanes include helper invocations, used for
+		// calculating fragment derivitives, which must not perform memory
+		// stores or atomic writes.
+		//
+		// Use activeStoresAndAtomicsMask() to consider both control flow and
+		// lanes which are permitted to perform memory stores and atomic
+		// operations
 		RValue<SIMD::Int> activeLaneMask() const
 		{
 			ASSERT(activeLaneMaskValue != nullptr);
 			return RValue<SIMD::Int>(activeLaneMaskValue);
 		}
 
+		// Returns the immutable lane mask that describes which lanes are
+		// permitted to perform memory stores and atomic operations.
+		// Note that unlike activeStoresAndAtomicsMask() this mask *does not*
+		// consider lanes that have been made inactive due to control flow.
 		RValue<SIMD::Int> storesAndAtomicsMask() const
 		{
 			ASSERT(storesAndAtomicsMaskValue != nullptr);
 			return RValue<SIMD::Int>(storesAndAtomicsMaskValue);
 		}
 
+		// Returns a lane mask that describes which lanes are permitted to
+		// perform memory stores and atomic operations, considering lanes that
+		// may have been made inactive due to control flow.
+		RValue<SIMD::Int> activeStoresAndAtomicsMask() const
+		{
+			return activeLaneMask() & storesAndAtomicsMask();
+		}
+
 		// Add a new active lane mask edge from the current block to out.
 		// The edge mask value will be (mask AND activeLaneMaskValue).
 		// If multiple active lane masks are added for the same edge, then