Implement SIMD helper functions using 128-bit operations

Functions such as SignMask() are not straightforward to implement for
SIMD vectors larger than 128-bit (i.e. more than 4 lanes wide), but to
facilitate the transition to using rr::SIMD types we can simply
implement them using the legacy 128-bit functions operating only on the
lower 128-bit half of the SIMD vector.

This approach ensures we don't lose performance when replacing types
such as rr::Float4 with rr::SIMD::Float while keeping the width at 4.
ASSERT() expressions have been added to pinpoint which functions need
work when locally testing with wider SIMD width.

Bug: b/214583550
Change-Id: Ia644e38c9bb2a0c8175da0ddc5a861d5e62e7bd4
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/66811
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Reactor/SIMD.cpp b/src/Reactor/SIMD.cpp
index ecaca87..bfeed07 100644
--- a/src/Reactor/SIMD.cpp
+++ b/src/Reactor/SIMD.cpp
@@ -678,6 +678,100 @@
 	return ScalarizeCall(log2f, x);
 }
 
+RValue<Int> SignMask(RValue<SIMD::Int> x)
+{
+	ASSERT(SIMD::Width == 4);
+	return SignMask(Extract128(x, 0));
+}
+
+RValue<SIMD::UInt> Ctlz(RValue<SIMD::UInt> x, bool isZeroUndef)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::UInt result;
+	return Insert128(result, Ctlz(Extract128(x, 0), isZeroUndef), 0);
+}
+
+RValue<SIMD::UInt> Cttz(RValue<SIMD::UInt> x, bool isZeroUndef)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::UInt result;
+	return Insert128(result, Cttz(Extract128(x, 0), isZeroUndef), 0);
+}
+
+RValue<SIMD::Int> MulHigh(RValue<SIMD::Int> x, RValue<SIMD::Int> y)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::Int result;
+	return Insert128(result, MulHigh(Extract128(x, 0), Extract128(y, 0)), 0);
+}
+
+RValue<SIMD::UInt> MulHigh(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::UInt result;
+	return Insert128(result, MulHigh(Extract128(x, 0), Extract128(y, 0)), 0);
+}
+
+RValue<Bool> AnyTrue(const RValue<SIMD::Int> &bools)
+{
+	ASSERT(SIMD::Width == 4);
+	return AnyTrue(Extract128(bools, 0));
+}
+
+RValue<Bool> AnyFalse(const RValue<SIMD::Int> &bools)
+{
+	ASSERT(SIMD::Width == 4);
+	return AnyFalse(Extract128(bools, 0));
+}
+
+RValue<Bool> Divergent(const RValue<SIMD::Int> &ints)
+{
+	ASSERT(SIMD::Width == 4);
+	return Divergent(Extract128(ints, 0));
+}
+
+RValue<SIMD::Int> Swizzle(RValue<SIMD::Int> x, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::Int result;
+	return Insert128(result, Swizzle(Extract128(x, 0), select), 0);
+}
+
+RValue<SIMD::UInt> Swizzle(RValue<SIMD::UInt> x, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::UInt result;
+	return Insert128(result, Swizzle(Extract128(x, 0), select), 0);
+}
+
+RValue<SIMD::Float> Swizzle(RValue<SIMD::Float> x, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::Float result;
+	return Insert128(result, Swizzle(Extract128(x, 0), select), 0);
+}
+
+RValue<SIMD::Int> Shuffle(RValue<SIMD::Int> x, RValue<SIMD::Int> y, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::Int result;
+	return Insert128(result, Shuffle(Extract128(x, 0), Extract128(y, 0), select), 0);
+}
+
+RValue<SIMD::UInt> Shuffle(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::UInt result;
+	return Insert128(result, Shuffle(Extract128(x, 0), Extract128(y, 0), select), 0);
+}
+
+RValue<SIMD::Float> Shuffle(RValue<SIMD::Float> x, RValue<SIMD::Float> y, uint16_t select)
+{
+	ASSERT(SIMD::Width == 4);
+	SIMD::Float result;
+	return Insert128(result, Shuffle(Extract128(x, 0), Extract128(y, 0), select), 0);
+}
+
 Pointer4::Pointer4(Pointer<Byte> base, rr::Int limit)
     : base(base)
     , dynamicLimit(limit)
diff --git a/src/Reactor/SIMD.hpp b/src/Reactor/SIMD.hpp
index de7c2c5..8c5ddf6 100644
--- a/src/Reactor/SIMD.hpp
+++ b/src/Reactor/SIMD.hpp
@@ -411,6 +411,21 @@
 RValue<SIMD::Float> Exp2(RValue<SIMD::Float> x);
 RValue<SIMD::Float> Log2(RValue<SIMD::Float> x);
 
+RValue<Int> SignMask(RValue<SIMD::Int> x);
+RValue<SIMD::UInt> Ctlz(RValue<SIMD::UInt> x, bool isZeroUndef);
+RValue<SIMD::UInt> Cttz(RValue<SIMD::UInt> x, bool isZeroUndef);
+RValue<SIMD::Int> MulHigh(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
+RValue<SIMD::UInt> MulHigh(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
+RValue<Bool> AnyTrue(const RValue<SIMD::Int> &bools);
+RValue<Bool> AnyFalse(const RValue<SIMD::Int> &bools);
+RValue<Bool> Divergent(const RValue<SIMD::Int> &ints);
+RValue<SIMD::Int> Swizzle(RValue<SIMD::Int> x, uint16_t select);
+RValue<SIMD::UInt> Swizzle(RValue<SIMD::UInt> x, uint16_t select);
+RValue<SIMD::Float> Swizzle(RValue<SIMD::Float> x, uint16_t select);
+RValue<SIMD::Int> Shuffle(RValue<SIMD::Int> x, RValue<SIMD::Int> y, uint16_t select);
+RValue<SIMD::UInt> Shuffle(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y, uint16_t select);
+RValue<SIMD::Float> Shuffle(RValue<SIMD::Float> x, RValue<SIMD::Float> y, uint16_t select);
+
 RValue<Float4> Gather(RValue<Pointer<Float>> base, RValue<Int4> offsets, RValue<Int4> mask, unsigned int alignment, bool zeroMaskedLanes = false);
 RValue<Int4> Gather(RValue<Pointer<Int>> base, RValue<Int4> offsets, RValue<Int4> mask, unsigned int alignment, bool zeroMaskedLanes = false);
 void Scatter(RValue<Pointer<Float>> base, RValue<Float4> val, RValue<Int4> offsets, RValue<Int4> mask, unsigned int alignment);