OSDN Git Service

Elide single basic block variable materialization
[android-x86/external-swiftshader.git] / src / Reactor / ReactorUnitTests.cpp
index 7cbde5d..a5de4f9 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "gtest/gtest.h"
 
+#include <tuple>
+
 using namespace rr;
 
 int reference(int *p, int y)
@@ -110,6 +112,65 @@ TEST(ReactorUnitTests, Uninitialized)
        delete routine;
 }
 
+TEST(ReactorUnitTests, Unreachable)
+{
+       Routine *routine = nullptr;
+
+       {
+               Function<Int(Int)> function;
+               {
+                       Int a = function.Arg<0>();
+                       Int z = 4;
+
+                       Return(a + z);
+
+                       // Code beyond this point is unreachable but should not cause any
+                       // compilation issues.
+
+                       z += a;
+               }
+
+               routine = function("one");
+
+               if(routine)
+               {
+                       int (*callable)(int) = (int(*)(int))routine->getEntry();
+                       int result = callable(16);
+                       EXPECT_EQ(result, 20);
+               }
+       }
+
+       delete routine;
+}
+
+TEST(ReactorUnitTests, VariableAddress)
+{
+       Routine *routine = nullptr;
+
+       {
+               Function<Int(Int)> function;
+               {
+                       Int a = function.Arg<0>();
+                       Int z = 0;
+                       Pointer<Int> p = &z;
+                       *p = 4;
+
+                       Return(a + z);
+               }
+
+               routine = function("one");
+
+               if(routine)
+               {
+                       int (*callable)(int) = (int(*)(int))routine->getEntry();
+                       int result = callable(16);
+                       EXPECT_EQ(result, 20);
+               }
+       }
+
+       delete routine;
+}
+
 TEST(ReactorUnitTests, SubVectorLoadStore)
 {
        Routine *routine = nullptr;
@@ -923,14 +984,29 @@ TEST(ReactorUnitTests, MulHigh)
                {
                        Pointer<Byte> out = function.Arg<0>();
 
-                       *Pointer<Short4>(out + 8 * 0) =
-                               MulHigh(Short4(0x1aa, 0x2dd, 0x3ee, 0xF422),
-                                       Short4(0x1bb, 0x2cc, 0x3ff, 0xF411));
-                       *Pointer<UShort4>(out + 8 * 1) =
-                               MulHigh(UShort4(0x1aa, 0x2dd, 0x3ee, 0xF422),
-                                       UShort4(0x1bb, 0x2cc, 0x3ff, 0xF411));
+                       *Pointer<Short4>(out + 16 * 0) =
+                               MulHigh(Short4(0x01AA, 0x02DD, 0x03EE, 0xF422),
+                                       Short4(0x01BB, 0x02CC, 0x03FF, 0xF411));
+                       *Pointer<UShort4>(out + 16 * 1) =
+                               MulHigh(UShort4(0x01AA, 0x02DD, 0x03EE, 0xF422),
+                                       UShort4(0x01BB, 0x02CC, 0x03FF, 0xF411));
+
+                       *Pointer<Int4>(out + 16 * 2) =
+                               MulHigh(Int4(0x000001AA, 0x000002DD, 0xC8000000, 0xF8000000),
+                                       Int4(0x000001BB, 0x84000000, 0x000003EE, 0xD7000000));
+                       *Pointer<UInt4>(out + 16 * 3) =
+                               MulHigh(UInt4(0x000001AAu, 0x000002DDu, 0xC8000000u, 0xD8000000u),
+                                       UInt4(0x000001BBu, 0x84000000u, 0x000003EEu, 0xD7000000u));
+
+                       *Pointer<Int4>(out + 16 * 4) =
+                               MulHigh(Int4(0x7FFFFFFF, 0x7FFFFFFF, 0x80008000, 0xFFFFFFFF),
+                                       Int4(0x7FFFFFFF, 0x80000000, 0x80008000, 0xFFFFFFFF));
+                       *Pointer<UInt4>(out + 16 * 5) =
+                               MulHigh(UInt4(0x7FFFFFFFu, 0x7FFFFFFFu, 0x80008000u, 0xFFFFFFFFu),
+                                       UInt4(0x7FFFFFFFu, 0x80000000u, 0x80008000u, 0xFFFFFFFFu));
+
+                       // (U)Short8 variants currently unimplemented.
 
-                       // (U)Short8 variants are mentioned but unimplemented
                        Return(0);
                }
 
@@ -938,7 +1014,7 @@ TEST(ReactorUnitTests, MulHigh)
 
                if(routine)
                {
-                       unsigned int out[2][2];
+                       unsigned int out[6][4];
 
                        memset(&out, 0, sizeof(out));
 
@@ -946,10 +1022,30 @@ TEST(ReactorUnitTests, MulHigh)
                        callable(&out);
 
                        EXPECT_EQ(out[0][0], 0x00080002u);
-                       EXPECT_EQ(out[0][1], 0x008D000fu);
+                       EXPECT_EQ(out[0][1], 0x008D000Fu);
 
                        EXPECT_EQ(out[1][0], 0x00080002u);
-                       EXPECT_EQ(out[1][1], 0xe8C0000Fu);
+                       EXPECT_EQ(out[1][1], 0xE8C0000Fu);
+
+                       EXPECT_EQ(out[2][0], 0x00000000u);
+                       EXPECT_EQ(out[2][1], 0xFFFFFE9Cu);
+                       EXPECT_EQ(out[2][2], 0xFFFFFF23u);
+                       EXPECT_EQ(out[2][3], 0x01480000u);
+
+                       EXPECT_EQ(out[3][0], 0x00000000u);
+                       EXPECT_EQ(out[3][1], 0x00000179u);
+                       EXPECT_EQ(out[3][2], 0x00000311u);
+                       EXPECT_EQ(out[3][3], 0xB5680000u);
+
+                       EXPECT_EQ(out[4][0], 0x3FFFFFFFu);
+                       EXPECT_EQ(out[4][1], 0xC0000000u);
+                       EXPECT_EQ(out[4][2], 0x3FFF8000u);
+                       EXPECT_EQ(out[4][3], 0x00000000u);
+
+                       EXPECT_EQ(out[5][0], 0x3FFFFFFFu);
+                       EXPECT_EQ(out[5][1], 0x3FFFFFFFu);
+                       EXPECT_EQ(out[5][2], 0x40008000u);
+                       EXPECT_EQ(out[5][3], 0xFFFFFFFEu);
                }
        }
 
@@ -992,6 +1088,236 @@ TEST(ReactorUnitTests, MulAdd)
        delete routine;
 }
 
+// Check that a complex generated function which utilizes all 8 or 16 XMM
+// registers computes the correct result.
+// (Note that due to MSC's lack of support for inline assembly in x64,
+// this test does not actually check that the register contents are
+// preserved, just that the generated function computes the correct value.
+// It's necessary to inspect the registers in a debugger to actually verify.)
+TEST(ReactorUnitTests, PreserveXMMRegisters)
+{
+    Routine *routine = nullptr;
+
+    {
+        Function<Void(Pointer<Byte>, Pointer<Byte>)> function;
+        {
+            Pointer<Byte> in = function.Arg<0>();
+            Pointer<Byte> out = function.Arg<1>();
+
+            Float4 a = *Pointer<Float4>(in + 16 * 0);
+            Float4 b = *Pointer<Float4>(in + 16 * 1);
+            Float4 c = *Pointer<Float4>(in + 16 * 2);
+            Float4 d = *Pointer<Float4>(in + 16 * 3);
+            Float4 e = *Pointer<Float4>(in + 16 * 4);
+            Float4 f = *Pointer<Float4>(in + 16 * 5);
+            Float4 g = *Pointer<Float4>(in + 16 * 6);
+            Float4 h = *Pointer<Float4>(in + 16 * 7);
+            Float4 i = *Pointer<Float4>(in + 16 * 8);
+            Float4 j = *Pointer<Float4>(in + 16 * 9);
+            Float4 k = *Pointer<Float4>(in + 16 * 10);
+            Float4 l = *Pointer<Float4>(in + 16 * 11);
+            Float4 m = *Pointer<Float4>(in + 16 * 12);
+            Float4 n = *Pointer<Float4>(in + 16 * 13);
+            Float4 o = *Pointer<Float4>(in + 16 * 14);
+            Float4 p = *Pointer<Float4>(in + 16 * 15);
+
+            Float4 ab = a + b;
+            Float4 cd = c + d;
+            Float4 ef = e + f;
+            Float4 gh = g + h;
+            Float4 ij = i + j;
+            Float4 kl = k + l;
+            Float4 mn = m + n;
+            Float4 op = o + p;
+
+            Float4 abcd = ab + cd;
+            Float4 efgh = ef + gh;
+            Float4 ijkl = ij + kl;
+            Float4 mnop = mn + op;
+
+            Float4 abcdefgh = abcd + efgh;
+            Float4 ijklmnop = ijkl + mnop;
+            Float4 sum = abcdefgh + ijklmnop;
+            *Pointer<Float4>(out) = sum;
+            Return();
+        }
+
+        routine = function("one");
+        assert(routine);
+
+        float input[64] = { 1.0f,  0.0f,   0.0f, 0.0f,
+                           -1.0f,  1.0f,  -1.0f, 0.0f,
+                            1.0f,  2.0f,  -2.0f, 0.0f,
+                           -1.0f,  3.0f,  -3.0f, 0.0f,
+                            1.0f,  4.0f,  -4.0f, 0.0f,
+                           -1.0f,  5.0f,  -5.0f, 0.0f,
+                            1.0f,  6.0f,  -6.0f, 0.0f,
+                           -1.0f,  7.0f,  -7.0f, 0.0f,
+                            1.0f,  8.0f,  -8.0f, 0.0f,
+                           -1.0f,  9.0f,  -9.0f, 0.0f,
+                            1.0f, 10.0f, -10.0f, 0.0f,
+                           -1.0f, 11.0f, -11.0f, 0.0f,
+                            1.0f, 12.0f, -12.0f, 0.0f,
+                           -1.0f, 13.0f, -13.0f, 0.0f,
+                            1.0f, 14.0f, -14.0f, 0.0f,
+                           -1.0f, 15.0f, -15.0f, 0.0f };
+
+        float result[4];
+        void (*callable)(float*, float*) = (void(*)(float*,float*))routine->getEntry();
+
+        callable(input, result);
+
+        EXPECT_EQ(result[0], 0.0f);
+        EXPECT_EQ(result[1], 120.0f);
+        EXPECT_EQ(result[2], -120.0f);
+        EXPECT_EQ(result[3], 0.0f);
+    }
+
+    delete routine;
+}
+
+template <typename T>
+class CToReactorCastTest : public ::testing::Test
+{
+public:
+       using CType = typename std::tuple_element<0, T>::type;
+       using ReactorType = typename std::tuple_element<1, T>::type;
+};
+
+using CToReactorCastTestTypes = ::testing::Types
+       < // Subset of types that can be used as arguments.
+       //      std::pair<bool,         Bool>,    FIXME(capn): Not supported as argument type by Subzero.
+       //      std::pair<uint8_t,      Byte>,    FIXME(capn): Not supported as argument type by Subzero.
+       //      std::pair<int8_t,       SByte>,   FIXME(capn): Not supported as argument type by Subzero.
+       //      std::pair<int16_t,      Short>,   FIXME(capn): Not supported as argument type by Subzero.
+       //      std::pair<uint16_t,     UShort>,  FIXME(capn): Not supported as argument type by Subzero.
+               std::pair<int,          Int>,
+               std::pair<unsigned int, UInt>,
+               std::pair<float,        Float>
+       >;
+
+TYPED_TEST_CASE(CToReactorCastTest, CToReactorCastTestTypes);
+
+TYPED_TEST(CToReactorCastTest, Casts)
+{
+       using CType = typename TestFixture::CType;
+       using ReactorType = typename TestFixture::ReactorType;
+
+       Routine *routine = nullptr;
+
+       {
+               Function< Int(ReactorType) > function;
+               {
+                       ReactorType a = function.template Arg<0>();
+                       ReactorType b = CType{};
+                       RValue<ReactorType> c = RValue<ReactorType>(CType{});
+                       Bool same = (a == b) && (a == c);
+                       Return(IfThenElse(same, Int(1), Int(0))); // TODO: Ability to use Bools as return values.
+               }
+
+               routine = function("one");
+
+               if(routine)
+               {
+                       auto callable = (int(*)(CType))routine->getEntry();
+                       CType in = {};
+                       EXPECT_EQ(callable(in), 1);
+               }
+       }
+
+       delete routine;
+}
+
+template <typename T>
+class GEPTest : public ::testing::Test
+{
+public:
+       using CType = typename std::tuple_element<0, T>::type;
+       using ReactorType = typename std::tuple_element<1, T>::type;
+};
+
+using GEPTestTypes = ::testing::Types
+       <
+               std::pair<bool,        Bool>,
+               std::pair<int8_t,      Byte>,
+               std::pair<int8_t,      SByte>,
+               std::pair<int8_t[4],   Byte4>,
+               std::pair<int8_t[4],   SByte4>,
+               std::pair<int8_t[8],   Byte8>,
+               std::pair<int8_t[8],   SByte8>,
+               std::pair<int8_t[16],  Byte16>,
+               std::pair<int8_t[16],  SByte16>,
+               std::pair<int16_t,     Short>,
+               std::pair<int16_t,     UShort>,
+               std::pair<int16_t[2],  Short2>,
+               std::pair<int16_t[2],  UShort2>,
+               std::pair<int16_t[4],  Short4>,
+               std::pair<int16_t[4],  UShort4>,
+               std::pair<int16_t[8],  Short8>,
+               std::pair<int16_t[8],  UShort8>,
+               std::pair<int,         Int>,
+               std::pair<int,         UInt>,
+               std::pair<int[2],      Int2>,
+               std::pair<int[2],      UInt2>,
+               std::pair<int[4],      Int4>,
+               std::pair<int[4],      UInt4>,
+               std::pair<int64_t,     Long>,
+               std::pair<int16_t,     Half>,
+               std::pair<float,       Float>,
+               std::pair<float[2],    Float2>,
+               std::pair<float[4],    Float4>
+       >;
+
+TYPED_TEST_CASE(GEPTest, GEPTestTypes);
+
+TYPED_TEST(GEPTest, PtrOffsets)
+{
+       using CType = typename TestFixture::CType;
+       using ReactorType = typename TestFixture::ReactorType;
+
+       Routine *routine = nullptr;
+
+       {
+               Function< Pointer<ReactorType>(Pointer<ReactorType>, Int) > function;
+               {
+                       Pointer<ReactorType> pointer = function.template Arg<0>();
+                       Int index = function.template Arg<1>();
+                       Return(&pointer[index]);
+               }
+
+               routine = function("one");
+
+               if(routine)
+               {
+                       auto callable = (CType*(*)(CType*, unsigned int))routine->getEntry();
+
+                       union PtrInt {
+                               CType* p;
+                               size_t i;
+                       };
+
+                       PtrInt base;
+                       base.i = 0x10000;
+
+                       for (int i = 0; i < 5; i++)
+                       {
+                               PtrInt reference;
+                               reference.p = &base.p[i];
+
+                               PtrInt result;
+                               result.p = callable(base.p, i);
+
+                               auto expect = reference.i - base.i;
+                               auto got = result.i - base.i;
+
+                               EXPECT_EQ(got, expect) << "i:" << i;
+                       }
+               }
+       }
+
+       delete routine;
+}
+
 int main(int argc, char **argv)
 {
        ::testing::InitGoogleTest(&argc, argv);