Add a unit test for bug fixed by swiftshader-cl/50008
This ReactorUnitTest fails if the fix made in swiftshader-cl/50008 is
reverted. Git hash of fix: 3476ca348bd0cd1223d815173ec528abbabd32f5
Bug: angleproject:4482
Change-Id: I0d1977923f7d8ea1c02e905b0c0c5273a19864c0
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/50075
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 77cf3af..4b07ce9 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -120,6 +120,10 @@
virtual Type *getType() const = 0;
+ // This function is only public for testing purposes, as it affects performance.
+ // It is not considered part of Reactor's public API.
+ static void materializeAll();
+
protected:
Variable();
Variable(const Variable &) = default;
@@ -127,7 +131,6 @@
virtual ~Variable();
private:
- static void materializeAll();
static void killUnmaterialized();
virtual Value *allocate() const;
diff --git a/src/Reactor/ReactorUnitTests.cpp b/src/Reactor/ReactorUnitTests.cpp
index cc6f0c9..f1deb2f 100644
--- a/src/Reactor/ReactorUnitTests.cpp
+++ b/src/Reactor/ReactorUnitTests.cpp
@@ -3147,6 +3147,75 @@
Arithmetic_ConstArgs(6.f, 3.f, 2.f, [](auto c1, auto c2) { return c1 / c2; });
}
+// Test for Subzero bad code-gen that was fixed in swiftshader-cl/50008
+// This tests the case of copying enough arguments to local variables so that the locals
+// get spilled to the stack when no more registers remain, and making sure these copies
+// are generated correctly. Without the aforementioned fix, this fails 100% on Windows x86.
+TEST(ReactorUnitTests, SpillLocalCopiesOfArgs)
+{
+ struct Helpers
+ {
+ static bool True() { return true; }
+ };
+
+ const int numLoops = 5; // 2 should be enough, but loop more to make sure
+
+ FunctionT<int(int, int, int, int, int, int, int, int, int, int, int, int)> function;
+ {
+ Int result = 0;
+ Int a1 = function.Arg<0>();
+ Int a2 = function.Arg<1>();
+ Int a3 = function.Arg<2>();
+ Int a4 = function.Arg<3>();
+ Int a5 = function.Arg<4>();
+ Int a6 = function.Arg<5>();
+ Int a7 = function.Arg<6>();
+ Int a8 = function.Arg<7>();
+ Int a9 = function.Arg<8>();
+ Int a10 = function.Arg<9>();
+ Int a11 = function.Arg<10>();
+ Int a12 = function.Arg<11>();
+
+ for(int i = 0; i < numLoops; ++i)
+ {
+ // Copy all arguments to locals so that Ice::LocalVariableSplitter::handleSimpleVarAssign
+ // creates Variable copies of arguments. We loop so that we create enough of these so
+ // that some spill over to the stack.
+ Int i1 = a1;
+ Int i2 = a2;
+ Int i3 = a3;
+ Int i4 = a4;
+ Int i5 = a5;
+ Int i6 = a6;
+ Int i7 = a7;
+ Int i8 = a8;
+ Int i9 = a9;
+ Int i10 = a10;
+ Int i11 = a11;
+ Int i12 = a12;
+
+ // Forcibly materialize all variables so that Ice::Variable instances are created for each
+ // local; otherwise, Reactor r-value optimizations kick in, and the locals are elided.
+ Variable::materializeAll();
+
+ // We also need to create a separate block that uses the variables declared above
+ // so that rr::optimize() doesn't optimize them out when attempting to eliminate stores
+ // followed by a load in the same block.
+ If(Call(Helpers::True))
+ {
+ result += (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12);
+ }
+ }
+
+ Return(result);
+ }
+
+ auto routine = function("one");
+ int result = routine(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+ int expected = numLoops * (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12);
+ EXPECT_EQ(result, expected);
+}
+
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);