Test variable materialization edge cases
These cases were discovered through various attempts to elide more loads
and stores after a branch has already occurred.
Also implement operator!= for Pointer<T>, and remove the redundant
Nucleus:createPtrEQ() which both LLVM and Subzero support through
integer value comparison.
Bug: b/180131694
Change-Id: I27c86b4fcbe6e1740801e40cb6877629f01d6540
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/52929
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 506e5dc..bc214f3 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -1437,12 +1437,6 @@
return V(jit->builder->CreateBitCast(V(v), T(destType)));
}
-Value *Nucleus::createPtrEQ(Value *lhs, Value *rhs)
-{
- RR_DEBUG_INFO_UPDATE_LOC();
- return V(jit->builder->CreateICmpEQ(V(lhs), V(rhs)));
-}
-
Value *Nucleus::createICmpEQ(Value *lhs, Value *rhs)
{
RR_DEBUG_INFO_UPDATE_LOC();
diff --git a/src/Reactor/Nucleus.hpp b/src/Reactor/Nucleus.hpp
index 4c08ddd..4d2b003 100644
--- a/src/Reactor/Nucleus.hpp
+++ b/src/Reactor/Nucleus.hpp
@@ -276,7 +276,6 @@
static Value *createBitCast(Value *V, Type *destType);
// Compare instructions
- static Value *createPtrEQ(Value *lhs, Value *rhs);
static Value *createICmpEQ(Value *lhs, Value *rhs);
static Value *createICmpNE(Value *lhs, Value *rhs);
static Value *createICmpUGT(Value *lhs, Value *rhs);
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 4871c6e..87bfffd 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2504,7 +2504,13 @@
template<typename T>
RValue<Bool> operator==(const Pointer<T> &lhs, const Pointer<T> &rhs)
{
- return RValue<Bool>(Nucleus::createPtrEQ(lhs.loadValue(), rhs.loadValue()));
+ return RValue<Bool>(Nucleus::createICmpEQ(lhs.loadValue(), rhs.loadValue()));
+}
+
+template<typename T>
+RValue<Bool> operator!=(const Pointer<T> &lhs, const Pointer<T> &rhs)
+{
+ return RValue<Bool>(Nucleus::createICmpNE(lhs.loadValue(), rhs.loadValue()));
}
template<typename T>
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 15d15e3..41c07c8 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -1740,12 +1740,6 @@
return V(result);
}
-Value *Nucleus::createPtrEQ(Value *lhs, Value *rhs)
-{
- RR_DEBUG_INFO_UPDATE_LOC();
- return createIntCompare(Ice::InstIcmp::Eq, lhs, rhs);
-}
-
Value *Nucleus::createICmpEQ(Value *lhs, Value *rhs)
{
RR_DEBUG_INFO_UPDATE_LOC();
diff --git a/tests/ReactorUnitTests/ReactorUnitTests.cpp b/tests/ReactorUnitTests/ReactorUnitTests.cpp
index 16c9fb4..b9eeb07 100644
--- a/tests/ReactorUnitTests/ReactorUnitTests.cpp
+++ b/tests/ReactorUnitTests/ReactorUnitTests.cpp
@@ -266,6 +266,8 @@
EXPECT_EQ(result, 9);
}
+// This test excercises modifying the value of a local variable through a
+// pointer to it.
TEST(ReactorUnitTests, VariableAddress)
{
FunctionT<int(int)> function;
@@ -284,6 +286,96 @@
EXPECT_EQ(result, 20);
}
+// This test exercises taking the address of a local varible at the end of a
+// loop and modifying its value through the pointer in the second iteration.
+TEST(ReactorUnitTests, LateVariableAddress)
+{
+ FunctionT<int(void)> function;
+ {
+ Pointer<Int> p = nullptr;
+ Int a = 0;
+
+ While(a == 0)
+ {
+ If(p != Pointer<Int>(nullptr))
+ {
+ *p = 1;
+ }
+
+ p = &a;
+ }
+
+ Return(a);
+ }
+
+ auto routine = function(testName().c_str());
+
+ int result = routine();
+ EXPECT_EQ(result, 1);
+}
+
+// This test checks that the value of a local variable which has been modified
+// though a pointer is correct at the point before its address is (statically)
+// obtained.
+TEST(ReactorUnitTests, LoadAfterIndirectStore)
+{
+ FunctionT<int(void)> function;
+ {
+ Pointer<Int> p = nullptr;
+ Int a = 0;
+ Int b = 0;
+
+ While(a == 0)
+ {
+ If(p != Pointer<Int>(nullptr))
+ {
+ *p = 1;
+ }
+
+ // `a` must be loaded from memory here, despite not statically knowing
+ // yet that its address will be taken below.
+ b = a + 5;
+
+ p = &a;
+ }
+
+ Return(b);
+ }
+
+ auto routine = function(testName().c_str());
+
+ int result = routine();
+ EXPECT_EQ(result, 6);
+}
+
+// This test checks that variables statically accessed after a Return statement
+// are still loaded, modified, and stored correctly.
+TEST(ReactorUnitTests, LoopAfterReturn)
+{
+ FunctionT<int(void)> function;
+ {
+ Int min = 100;
+ Int max = 200;
+
+ If(min > max)
+ {
+ Return(5);
+ }
+
+ While(min < max)
+ {
+ min++;
+ }
+
+ Return(7);
+ }
+
+ auto routine = function(testName().c_str());
+
+ int result = routine();
+ EXPECT_EQ(result, 7);
+}
+
TEST(ReactorUnitTests, SubVectorLoadStore)
{
FunctionT<int(void *, void *)> function;