Support constructing a SIMD constant from a lambda expression

This makes it easier to construct complex SIMD width dependent constant
vectors. The lambda expression takes the lane index as input and must
return the value for that lane.

Example usage:

SIMD::Int([](int i) { return 1 << i; })

Produces {1, 2, 4, 8, 16, 32, ...}.

Note we also still support construction from an std::vector<>. This is
more verbose as it requires creating a temporary and explicitly looping
for SIMD::Width iterations, but may be easier to read in some cases. It
also supports shorter input vectors, by implicitly applying a modulo
operation, which this new lambda approach does not. So they both have
their uses.

Bug: b/214583550
Change-Id: Ib0b2024cf57254bfa9cc7836ef656f2f507fe21a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/67429
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/SIMD.cpp b/src/Reactor/SIMD.cpp
index ddf2d56..ee02cdb 100644
--- a/src/Reactor/SIMD.cpp
+++ b/src/Reactor/SIMD.cpp
@@ -57,6 +57,14 @@
 	storeValue(Nucleus::createConstantVector(constantVector, type()));
 }
 
+SIMD::Int::Int(std::function<int(int)> LaneValueProducer)
+    : XYZW(this)
+{
+	std::vector<int64_t> constantVector;
+	for(int i = 0; i < SIMD::Width; i++) { constantVector.push_back(LaneValueProducer(i)); }
+	storeValue(Nucleus::createConstantVector(constantVector, type()));
+}
+
 SIMD::Int::Int(RValue<SIMD::Int> rhs)
     : XYZW(this)
 {
@@ -277,6 +285,14 @@
 	storeValue(Nucleus::createConstantVector(constantVector, type()));
 }
 
+SIMD::UInt::UInt(std::function<int(int)> LaneValueProducer)
+    : XYZW(this)
+{
+	std::vector<int64_t> constantVector;
+	for(int i = 0; i < SIMD::Width; i++) { constantVector.push_back(LaneValueProducer(i)); }
+	storeValue(Nucleus::createConstantVector(constantVector, type()));
+}
+
 SIMD::UInt::UInt(RValue<SIMD::UInt> rhs)
     : XYZW(this)
 {
@@ -512,6 +528,14 @@
 	storeValue(Nucleus::createConstantVector(constantVector, type()));
 }
 
+SIMD::Float::Float(std::function<float(int)> LaneValueProducer)
+    : XYZW(this)
+{
+	std::vector<double> constantVector;
+	for(int i = 0; i < SIMD::Width; i++) { constantVector.push_back(LaneValueProducer(i)); }
+	storeValue(Nucleus::createConstantVector(constantVector, type()));
+}
+
 SIMD::Float SIMD::Float::infinity()
 {
 	SIMD::Float result;
diff --git a/src/Reactor/SIMD.hpp b/src/Reactor/SIMD.hpp
index 6508704..cf54f29 100644
--- a/src/Reactor/SIMD.hpp
+++ b/src/Reactor/SIMD.hpp
@@ -17,6 +17,7 @@
 
 #include "Reactor.hpp"
 
+#include <functional>
 #include <vector>
 
 namespace rr {
@@ -54,6 +55,7 @@
 	Int(int broadcast);
 	Int(int x, int y, int z, int w);
 	Int(std::vector<int> v);
+	Int(std::function<int(int)> LaneValueProducer);
 	Int(RValue<SIMD::Int> rhs);
 	Int(const Int &rhs);
 	Int(const Reference<SIMD::Int> &rhs);
@@ -86,6 +88,7 @@
 	UInt(int broadcast);
 	UInt(int x, int y, int z, int w);
 	UInt(std::vector<int> v);
+	UInt(std::function<int(int)> LaneValueProducer);
 	UInt(RValue<SIMD::UInt> rhs);
 	UInt(const UInt &rhs);
 	UInt(const Reference<SIMD::UInt> &rhs);
@@ -115,6 +118,7 @@
 	Float(float broadcast);
 	Float(float x, float y, float z, float w);
 	Float(std::vector<float> v);
+	Float(std::function<float(int)> LaneValueProducer);
 	Float(RValue<SIMD::Float> rhs);
 	Float(const Float &rhs);
 	Float(const Reference<SIMD::Float> &rhs);