Fix constant folding right shift corner cases
Right-shifting the minimum signed integer needs to be handled as a
special case, since it can't go through the usual path that clears the
sign bit.
Code for right-shifting by zero also had a typo that resulted in
setting the wrong value to the result.
BUG=chromium:662706
TEST=angle_unittests
Change-Id: Ief24d738064906a72212242e0917ce30e45d6b25
Reviewed-on: https://chromium-review.googlesource.com/408158
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ConstantUnion.cpp b/src/compiler/translator/ConstantUnion.cpp
index 1ee3f64..66f444b 100644
--- a/src/compiler/translator/ConstantUnion.cpp
+++ b/src/compiler/translator/ConstantUnion.cpp
@@ -423,27 +423,42 @@
// ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
// the sign bit." In C++ shifting negative integers is undefined, so we implement
// extending the sign bit manually.
- bool extendSignBit = false;
int lhsSafe = lhs.iConst;
- if (lhsSafe < 0)
+ if (lhsSafe == std::numeric_limits<int>::min())
{
- extendSignBit = true;
- // Clear the sign bit so that bitshift right is defined in C++.
- lhsSafe &= 0x7fffffff;
- ASSERT(lhsSafe > 0);
+ // The min integer needs special treatment because only bit it has set is the
+ // sign bit, which we clear later to implement safe right shift of negative
+ // numbers.
+ lhsSafe = -0x40000000;
+ --shiftOffset;
}
- returnValue.setIConst(lhsSafe >> shiftOffset);
-
- // Manually fill in the extended sign bit if necessary.
- if (extendSignBit)
+ if (shiftOffset > 0)
{
- int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
- returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
+ bool extendSignBit = false;
+ if (lhsSafe < 0)
+ {
+ extendSignBit = true;
+ // Clear the sign bit so that bitshift right is defined in C++.
+ lhsSafe &= 0x7fffffff;
+ ASSERT(lhsSafe > 0);
+ }
+ returnValue.setIConst(lhsSafe >> shiftOffset);
+
+ // Manually fill in the extended sign bit if necessary.
+ if (extendSignBit)
+ {
+ int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
+ returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
+ }
+ }
+ else
+ {
+ returnValue.setIConst(lhsSafe);
}
}
else
{
- returnValue.setIConst(rhs.iConst);
+ returnValue.setIConst(lhs.iConst);
}
break;
}