Subzero: temp fix Float4 % Float4 (FRem)
Subzero emits incorrect code for FRem operations on vectors. Replace
with an emulated version that calls fmodf on each component for now.
Bug: b/148139679
Change-Id: Ib541370b71b99649f8c73f982fd12cb3cde25e7f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/40450
Presubmit-Ready: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Antonio Maiorano <amaiorano@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Reactor/EmulatedReactor.cpp b/src/Reactor/EmulatedReactor.cpp
index 8e93909..dc3d558 100644
--- a/src/Reactor/EmulatedReactor.cpp
+++ b/src/Reactor/EmulatedReactor.cpp
@@ -224,5 +224,10 @@
return call4(log2f, x);
}
+RValue<Float4> FRem(RValue<Float4> lhs, RValue<Float4> rhs)
+{
+ return call4(fmodf, lhs, rhs);
+}
+
} // namespace emulated
} // namespace rr
diff --git a/src/Reactor/EmulatedReactor.hpp b/src/Reactor/EmulatedReactor.hpp
index 10b9b2a..ccc6245 100644
--- a/src/Reactor/EmulatedReactor.hpp
+++ b/src/Reactor/EmulatedReactor.hpp
@@ -48,6 +48,7 @@
RValue<Float4> Log(RValue<Float4> x);
RValue<Float4> Exp2(RValue<Float4> x);
RValue<Float4> Log2(RValue<Float4> x);
+RValue<Float4> FRem(RValue<Float4> lhs, RValue<Float4> rhs);
} // namespace emulated
} // namespace rr
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 99c43de..7cdf460 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -1632,6 +1632,11 @@
return V(jit->builder->CreateFRem(V(lhs), V(rhs)));
}
+RValue<Float4> operator%(RValue<Float4> lhs, RValue<Float4> rhs)
+{
+ return RValue<Float4>(Nucleus::createFRem(lhs.value, rhs.value));
+}
+
Value *Nucleus::createShl(Value *lhs, Value *rhs)
{
RR_DEBUG_INFO_UPDATE_LOC();
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index 5cf3bce..33e1972 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -4240,11 +4240,6 @@
return RValue<Float4>(Nucleus::createFDiv(lhs.value, rhs.value));
}
-RValue<Float4> operator%(RValue<Float4> lhs, RValue<Float4> rhs)
-{
- return RValue<Float4>(Nucleus::createFRem(lhs.value, rhs.value));
-}
-
RValue<Float4> operator+=(Float4 &lhs, RValue<Float4> rhs)
{
return lhs = lhs + rhs;
diff --git a/src/Reactor/ReactorUnitTests.cpp b/src/Reactor/ReactorUnitTests.cpp
index a72cb1e..ffe71c4 100644
--- a/src/Reactor/ReactorUnitTests.cpp
+++ b/src/Reactor/ReactorUnitTests.cpp
@@ -25,32 +25,63 @@
constexpr float PI = 3.141592653589793f;
using float4 = float[4];
+using int4 = int[4];
-// Value type wrapper around a float4
-struct float4_value
+// TODO: Move to Reactor.hpp
+template<>
+struct rr::CToReactor<int[4]>
{
- float4_value() = default;
- explicit float4_value(float rep)
+ using type = Int4;
+ static Int4 cast(float[4]);
+};
+
+// Value type wrapper around a <type>[4] (i.e. float4, int4)
+template<typename T>
+struct type4_value
+{
+ using E = typename std::remove_pointer_t<std::decay_t<T>>;
+
+ type4_value() = default;
+ explicit type4_value(E rep)
: v{ rep, rep, rep, rep }
{}
- float4_value(float x, float y, float z, float w)
+ type4_value(E x, E y, E z, E w)
: v{ x, y, z, w }
{}
- bool operator==(const float4_value &rhs) const
+ bool operator==(const type4_value &rhs) const
{
return std::equal(std::begin(v), std::end(v), rhs.v);
}
// For gtest printing
- friend std::ostream &operator<<(std::ostream &os, const float4_value &value)
+ friend std::ostream &operator<<(std::ostream &os, const type4_value &value)
{
return os << "[" << value.v[0] << ", " << value.v[1] << ", " << value.v[2] << ", " << value.v[3] << "]";
}
- float4 v;
+ T v;
};
+using float4_value = type4_value<float4>;
+using int4_value = type4_value<int4>;
+
+// Invoke a void(type4_value<T>*) routine on &v.v, returning wrapped result in v
+template<typename RoutineType, typename T>
+type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v)
+{
+ routine(&v.v);
+ return v;
+}
+
+// Invoke a void(type4_value<T>*, type4_value<T>*) routine on &v1.v, &v2.v returning wrapped result in v1
+template<typename RoutineType, typename T>
+type4_value<T> invokeRoutine(RoutineType &routine, type4_value<T> v1, type4_value<T> v2)
+{
+ routine(&v1.v, &v2.v);
+ return v1;
+}
+
// For gtest printing of pairs
namespace std {
template<typename T, typename U>
@@ -60,22 +91,6 @@
}
} // namespace std
-// Invoke a void(float4*) routine on &v.v, returning wrapped result in v
-template<typename RoutineType>
-float4_value invokeRoutine(RoutineType &routine, float4_value v)
-{
- routine(&v.v);
- return v;
-}
-
-// Invoke a void(float4*, float4*) routine on &v1.v, &v2.v returning wrapped result in v1
-template<typename RoutineType>
-float4_value invokeRoutine(RoutineType &routine, float4_value v1, float4_value v2)
-{
- routine(&v1.v, &v2.v);
- return v1;
-}
-
int reference(int *p, int y)
{
int x = p[-1];
@@ -2237,6 +2252,44 @@
EXPECT_EQ(result[3], 678);
}
+TEST(ReactorUnitTests, SRem)
+{
+ FunctionT<void(int4 *, int4 *)> function;
+ {
+ Pointer<Int4> a = function.Arg<0>();
+ Pointer<Int4> b = function.Arg<1>();
+ *a = *a % *b;
+ }
+
+ auto routine = function("one");
+
+ int4_value result = invokeRoutine(routine, int4_value{ 10, 11, 12, 13 }, int4_value{ 3, 3, 3, 3 });
+ int4_value expected = int4_value{ 10 % 3, 11 % 3, 12 % 3, 13 % 3 };
+ EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
+ EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
+ EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
+ EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
+}
+
+TEST(ReactorUnitTests, FRem)
+{
+ FunctionT<void(float4 *, float4 *)> function;
+ {
+ Pointer<Float4> a = function.Arg<0>();
+ Pointer<Float4> b = function.Arg<1>();
+ *a = *a % *b;
+ }
+
+ auto routine = function("one");
+
+ float4_value result = invokeRoutine(routine, float4_value{ 10.1f, 11.2f, 12.3f, 13.4f }, float4_value{ 3.f, 3.f, 3.f, 3.f });
+ float4_value expected = float4_value{ fmodf(10.1f, 3.f), fmodf(11.2f, 3.f), fmodf(12.3f, 3.f), fmodf(13.4f, 3.f) };
+ EXPECT_FLOAT_EQ(result.v[0], expected.v[0]);
+ EXPECT_FLOAT_EQ(result.v[1], expected.v[1]);
+ EXPECT_FLOAT_EQ(result.v[2], expected.v[2]);
+ EXPECT_FLOAT_EQ(result.v[3], expected.v[3]);
+}
+
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 54dcf93..91de455 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -898,7 +898,15 @@
Value *Nucleus::createFRem(Value *lhs, Value *rhs)
{
- return createArithmetic(Ice::InstArithmetic::Frem, lhs, rhs);
+ // TODO(b/148139679) Fix Subzero generating invalid code for FRem on vector types
+ // createArithmetic(Ice::InstArithmetic::Frem, lhs, rhs);
+ UNIMPLEMENTED("Nucleus::createFRem");
+ return nullptr;
+}
+
+RValue<Float4> operator%(RValue<Float4> lhs, RValue<Float4> rhs)
+{
+ return emulated::FRem(lhs, rhs);
}
Value *Nucleus::createShl(Value *lhs, Value *rhs)