Reuse Store logic for Modf and Frexp output parameters

The Modf and Frexp instructions from the GLSL.std.450 extended SPIR-V
instruction set take a pointer argument to write one of their results
to. This makes them the only arithmetic instructions which need to know
how to explicitly access memory.

This change replaces the partial duplication of store logic with a call
to the underlying implementation of OpStore. To support storing
intermediate values not associated with SPIR-V objects, the Operand
class can now also wrap an independent Intermediate instance.

Bug: b/153641251
Change-Id: Iebab43640b45ed6c27a77576168481d1a27158b6
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43728
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index b098cb1..9a9ccd3 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -2431,6 +2431,13 @@
 	ASSERT(intermediate || (object.kind == SpirvShader::Object::Kind::Constant));
 }
 
+SpirvShader::Operand::Operand(const Intermediate &value)
+    : constant(nullptr)
+    , intermediate(&value)
+    , componentCount(value.componentCount)
+{
+}
+
 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
     : pipelineLayout(pipelineLayout)
 {