LLVMReactor: Clamp RHS of bit shifts.
This is a temporary fix for MSAN failures, preventing SwiftShader from rolling into Chromium.
Bug: swiftshader:185
Change-Id: Ib6ee7e02dd6e061095e4d9b67cb73769999a7f80
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/72008
Reviewed-by: David Neto <dneto@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index def17d3..31dbfe3 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -356,6 +356,21 @@
return jit->builder->CreateTrunc(mulh, ty);
}
+// TODO(crbug.com/swiftshader/185): A temporary workaround for failing chromium tests.
+llvm::Value *clampForShift(llvm::Value *rhs)
+{
+ llvm::Value *max;
+ if(auto *vec = llvm::dyn_cast<llvm::VectorType>(rhs->getType()))
+ {
+ max = llvm::ConstantVector::getSplat(vec->getNumElements(), llvm::ConstantInt::get(vec->getElementType(), 31));
+ }
+ else
+ {
+ max = llvm::ConstantInt::get(rhs->getType(), 31);
+ }
+ return jit->builder->CreateSelect(jit->builder->CreateICmpULE(rhs, max), rhs, max);
+}
+
} // namespace
namespace rr {
@@ -806,13 +821,15 @@
Value *Nucleus::createShl(Value *lhs, Value *rhs)
{
RR_DEBUG_INFO_UPDATE_LOC();
- return V(jit->builder->CreateFreeze(jit->builder->CreateShl(V(lhs), V(rhs))));
+ auto *clamped_rhs = clampForShift(V(rhs));
+ return V(jit->builder->CreateFreeze(jit->builder->CreateShl(V(lhs), clamped_rhs)));
}
Value *Nucleus::createLShr(Value *lhs, Value *rhs)
{
RR_DEBUG_INFO_UPDATE_LOC();
- return V(jit->builder->CreateFreeze(jit->builder->CreateLShr(V(lhs), V(rhs))));
+ auto *clamped_rhs = clampForShift(V(rhs));
+ return V(jit->builder->CreateFreeze(jit->builder->CreateLShr(V(lhs), clamped_rhs)));
}
Value *Nucleus::createAShr(Value *lhs, Value *rhs)
diff --git a/tests/ReactorUnitTests/ReactorUnitTests.cpp b/tests/ReactorUnitTests/ReactorUnitTests.cpp
index 6407e60..1c234f1 100644
--- a/tests/ReactorUnitTests/ReactorUnitTests.cpp
+++ b/tests/ReactorUnitTests/ReactorUnitTests.cpp
@@ -2061,6 +2061,169 @@
}
}
+TEST(ReactorUnitTests, ShlSmallRHSScalar)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<unsigned()> function;
+ {
+ auto lhs = UInt(4);
+ auto rhs = UInt(8);
+ auto res = lhs << rhs;
+ Return(res);
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned res = routine();
+ EXPECT_EQ(res, 1u << 10u);
+}
+
+TEST(ReactorUnitTests, ShlLargeRHSScalar)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<unsigned()> function;
+ {
+ auto lhs = UInt(1);
+ auto rhs = UInt(99);
+ auto res = lhs << rhs;
+ Return(res);
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned res = routine();
+ EXPECT_EQ(res, 1u << 31u);
+}
+
+TEST(ReactorUnitTests, ShrSmallRHSScalar)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<unsigned()> function;
+ {
+ auto lhs = UInt(64);
+ auto rhs = UInt(4);
+ auto res = lhs >> rhs;
+ Return(res);
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned res = routine();
+ EXPECT_EQ(res, 4);
+}
+
+TEST(ReactorUnitTests, ShrLargeRHSScalar)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<unsigned()> function;
+ {
+ auto lhs = UInt(4);
+ auto rhs = UInt(99);
+ auto res = lhs >> rhs;
+ Return(res);
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned res = routine();
+ EXPECT_EQ(res, 0);
+}
+
+TEST(ReactorUnitTests, ShlRHSVector)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<void(unsigned *a, unsigned *b, unsigned *c, unsigned *d)> function;
+ {
+ Pointer<UInt> a = function.Arg<0>();
+ Pointer<UInt> b = function.Arg<1>();
+ Pointer<UInt> c = function.Arg<2>();
+ Pointer<UInt> d = function.Arg<3>();
+
+ auto lhs = UInt4(4, 3, 6, 5);
+ auto rhs = UInt4(8, 99, 2, 50);
+ UInt4 res = lhs << rhs;
+ *a = res.x;
+ *b = res.y;
+ *c = res.z;
+ *d = res.w;
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned a = 0;
+ unsigned b = 0;
+ unsigned c = 0;
+ unsigned d = 0;
+ routine(&a, &b, &c, &d);
+ EXPECT_EQ(a, 1024);
+ EXPECT_EQ(b, 0x80000000);
+ EXPECT_EQ(c, 24);
+ EXPECT_EQ(d, 0x80000000);
+}
+
+TEST(ReactorUnitTests, ShrRHSVector)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<void(unsigned *a, unsigned *b, unsigned *c, unsigned *d)> function;
+ {
+ Pointer<UInt> a = function.Arg<0>();
+ Pointer<UInt> b = function.Arg<1>();
+ Pointer<UInt> c = function.Arg<2>();
+ Pointer<UInt> d = function.Arg<3>();
+
+ auto lhs = UInt4(745, 23, 234, 54);
+ auto rhs = UInt4(8, 99, 2, 50);
+ UInt4 res = lhs >> rhs;
+ *a = res.x;
+ *b = res.y;
+ *c = res.z;
+ *d = res.w;
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned a = 0;
+ unsigned b = 0;
+ unsigned c = 0;
+ unsigned d = 0;
+ routine(&a, &b, &c, &d);
+ EXPECT_EQ(a, 2);
+ EXPECT_EQ(b, 0);
+ EXPECT_EQ(c, 58);
+ EXPECT_EQ(d, 0);
+}
+
+TEST(ReactorUnitTests, ShrLargeRHSVector)
+{
+ // TODO(crbug.com/swiftshader/185): Testing a temporary LLVM workaround
+ if(Caps::backendName().find("LLVM") == std::string::npos) return;
+
+ FunctionT<unsigned()> function;
+ {
+ auto lhs = UInt(4);
+ auto rhs = UInt(99);
+ auto res = lhs >> rhs;
+ Return(res);
+ }
+
+ auto routine = function(testName().c_str());
+
+ unsigned res = routine();
+ EXPECT_EQ(res, 0);
+}
+
TEST(ReactorUnitTests, Call)
{
struct Class