Commit 42fad76d by Olli Etuaho Committed by Commit Bot

Handle negation of minimum representable integer

Negating the minimum representable integer overflows, so it has undefined behavior in C++. Handle this as a special case in the code. BUG=chromium:637050 TEST=angle_unittests Change-Id: Ic6e6d638faddad9b70b5d1637bb4b42ef4f43784 Reviewed-on: https://chromium-review.googlesource.com/390551Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 1be4d493
...@@ -1599,11 +1599,30 @@ TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op, ...@@ -1599,11 +1599,30 @@ TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
resultArray[i].setFConst(-operandArray[i].getFConst()); resultArray[i].setFConst(-operandArray[i].getFConst());
break; break;
case EbtInt: case EbtInt:
resultArray[i].setIConst(-operandArray[i].getIConst()); if (operandArray[i] == std::numeric_limits<int>::min())
{
// The minimum representable integer doesn't have a positive
// counterpart, rather the negation overflows and in ESSL is supposed to
// wrap back to the minimum representable integer. Make sure that we
// don't actually let the negation overflow, which has undefined
// behavior in C++.
resultArray[i].setIConst(std::numeric_limits<int>::min());
}
else
{
resultArray[i].setIConst(-operandArray[i].getIConst());
}
break; break;
case EbtUInt: case EbtUInt:
resultArray[i].setUConst(static_cast<unsigned int>( if (operandArray[i] == 0x80000000u)
-static_cast<int>(operandArray[i].getUConst()))); {
resultArray[i].setUConst(0x80000000u);
}
else
{
resultArray[i].setUConst(static_cast<unsigned int>(
-static_cast<int>(operandArray[i].getUConst())));
}
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -963,3 +963,25 @@ TEST_F(ConstantFoldingTest, FoldSignedIntegerMultiplyOverflow) ...@@ -963,3 +963,25 @@ TEST_F(ConstantFoldingTest, FoldSignedIntegerMultiplyOverflow)
compile(shaderString); compile(shaderString);
ASSERT_TRUE(constantFoundInAST(-42)); ASSERT_TRUE(constantFoundInAST(-42));
} }
// Test that folding of negating the minimum representable integer works. Note that in the test
// "0x80000000" is a negative literal, and the minus sign before it is the negation operator.
// ESSL 3.00.6 section 4.1.3 Integers:
// "For all precisions, operations resulting in overflow or underflow will not cause any exception,
// nor will they saturate, rather they will 'wrap' to yield the low-order n bits of the result where
// n is the size in bits of the integer."
TEST_F(ConstantFoldingTest, FoldMinimumSignedIntegerNegation)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" int i = -0x80000000;\n"
" my_FragColor = vec4(i);\n"
"}\n";
compile(shaderString);
// Negating the minimum signed integer overflows the positive range, so it wraps back to itself.
ASSERT_TRUE(constantFoundInAST(-0x7fffffff - 1));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment