blob: c78a0d3cd453edd20ff568c9a3efdf5224fa4f59 [file] [log] [blame] [edit]
//
// Copyright 2025 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifdef UNSAFE_BUFFERS_BUILD
# pragma allow_unsafe_buffers
#endif
#include "test_utils/CompilerTest.h"
#include "test_utils/angle_test_configs.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
class GLSLConstantFoldingTest : public CompilerTest
{
protected:
GLSLConstantFoldingTest() {}
virtual const char *version() { return "300"; }
// Helper to verify constant folding result. It's given:
//
// * The type of the constant: a varying `v` will be created of this type.
// * The expression to define and set `c` of that type: The varying is assigned the value of `c`
// in the vertex shader.
// * An expression involving `v` that compares it with the expectation in the fragment shader,
// resulting in a bool.
void test(const char *type, const char *defineC, const char *compareWithV)
{
std::stringstream vsSrc;
vsSrc << "#version " << version() << R"( es
precision highp float;
precision highp int;
flat out )" << type
<< R"( v;
void main()
{
)" << defineC
<< R"(;
v = c;
vec2 pos = vec2(0.);
switch (gl_VertexID) {
// The tests often include 1 and 3, reduce the chance of checking for those values hitting
// the values for position by using 1.1 and 3.1 instead of 1.0 and 3.0.
case 0: pos = vec2(-1.5, -1.5); break;
case 1: pos = vec2(3.5, -1.5); break;
case 2: pos = vec2(-1.5, 3.5); break;
};
gl_Position = vec4(pos, 0.1, 1.1);
})";
std::stringstream fsSrc;
fsSrc << "#version " << version() << R"( es
precision highp float;
precision highp int;
flat in )" << type
<< R"( v;
out vec4 color;
void main()
{
if ()" << compareWithV
<< R"()
{
color = vec4(0, 1, 0, 1);
}
else
{
color = vec4(1, 0, 0, 1);
}
})";
const CompiledShader &vs = compile(GL_VERTEX_SHADER, vsSrc.str().c_str());
const CompiledShader &fs = compile(GL_FRAGMENT_SHADER, fsSrc.str().c_str());
ASSERT_TRUE(vs.success());
ASSERT_TRUE(fs.success());
const GLuint program = link();
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Check that the expected constant (the result of folding) is present in the translated source
// for the vertex shader (where constant folding is expected to have happened).
//
// Given the various backends and formatting details of the generators, we can't realistically
// completely verify the translated output. Often, it's enough to verify that a substring only
// found if the constant folding is performed is present; the correctness check in test() makes
// sure constant folding is functionally correct.
//
// Additionally, due to the numerous shader massaging in non-GLSL backends, it's easy for
// expectations to mismatch. Therefore, these expectations are only checked with the GLSL
// backend.
void verifyIsInTranslation(const char *expect)
{
if (IsOpenGL())
{
EXPECT_TRUE(getCompiledShader(GL_VERTEX_SHADER).verifyInTranslatedSource(expect))
<< '"' << expect << "\" should have been in:\n"
<< getCompiledShader(GL_VERTEX_SHADER).getTranslatedSource();
}
}
void verifyIsNotInTranslation(const char *expect)
{
if (IsOpenGL())
{
EXPECT_TRUE(getCompiledShader(GL_VERTEX_SHADER).verifyNotInTranslatedSource(expect))
<< '"' << expect << "\" should not have been in:\n"
<< getCompiledShader(GL_VERTEX_SHADER).getTranslatedSource();
}
}
};
class GLSLConstantFoldingTest_ES31 : public GLSLConstantFoldingTest
{
public:
const char *version() override { return "310"; }
};
// Constant fold integer addition
TEST_P(GLSLConstantFoldingTest, IntegerAdd)
{
test("int", "const int c = 1124 + 5", "v == 1129");
verifyIsInTranslation(" 1129");
verifyIsNotInTranslation("1124");
}
// Constant fold integer subtraction
TEST_P(GLSLConstantFoldingTest, IntegerSub)
{
test("int", "const int c = 1124 - 5", "v == 1119");
verifyIsInTranslation(" 1119");
verifyIsNotInTranslation("1124");
}
// Constant fold integer multiplication
TEST_P(GLSLConstantFoldingTest, IntegerMul)
{
test("int", "const int c = 1124 * 5", "v == 5620");
verifyIsInTranslation(" 5620");
verifyIsNotInTranslation("1124");
}
// Constant fold integer division
TEST_P(GLSLConstantFoldingTest, IntegerDiv)
{
// Rounding mode of division is undefined in the spec but ANGLE can be expected to round down.
test("int", "const int c = 1124 / 5", "v == 224");
verifyIsInTranslation(" 224");
verifyIsNotInTranslation("1124");
}
// Constant fold integer modulus
TEST_P(GLSLConstantFoldingTest, IntegerMod)
{
test("int", "const int c = 1124 % 5", "v == 4");
verifyIsInTranslation(" 4");
verifyIsNotInTranslation("1124");
}
// Constant fold cross()
TEST_P(GLSLConstantFoldingTest, Cross)
{
test("vec3", "const vec3 c = cross(vec3(1., 1., 1.), vec3(1., -1., 1.))",
"all(equal(v, vec3(2., 0., -2.)))");
verifyIsInTranslation("-2.0");
verifyIsNotInTranslation("cross");
verifyIsNotInTranslation("-1.0");
}
// Constant fold inverse()
TEST_P(GLSLConstantFoldingTest, Inverse2x2)
{
test("mat2", "const mat2 c = inverse(mat2(2., 3., 5., 7.))",
"all(equal(v[0], vec2(-7., 3.))) && all(equal(v[1], vec2(5., -2.)))");
verifyIsInTranslation("-7.0");
verifyIsNotInTranslation("5.0, 7.0");
verifyIsNotInTranslation("inverse");
}
// Constant fold inverse()
TEST_P(GLSLConstantFoldingTest, Inverse3x3)
{
test("mat3", "const mat3 c = inverse(mat3(11., 13., 19., 23., 29., 31., 37., 41., 43.))",
"all(lessThan(abs(v[0] - vec3(31.*41.-29.*43., 13.*43.-19.*41., 19.*29.-13.*31.)/680.), "
"vec3(0.000001))) && "
"all(lessThan(abs(v[1] - vec3(23.*43.-31.*37., 19.*37.-11.*43., 11.*31.-19.*23.)/680.), "
"vec3(0.000001))) && "
"all(lessThan(abs(v[2] - vec3(29.*37.-23.*41., 11.*41.-13.*37., 13.*23.-11.*29.)/680.), "
"vec3(0.000001)))");
verifyIsInTranslation("0.0352");
verifyIsNotInTranslation("29.0");
verifyIsNotInTranslation("inverse");
}
// Constant fold inverse()
TEST_P(GLSLConstantFoldingTest, Inverse4x4)
{
test("mat4",
"const mat4 c = inverse(mat4(29., 31., 37., 41., "
"43., 47., 53., 59., "
"61., 67., 71., 73., "
"79., 83., 89., 97.))",
"all(lessThan(abs(v[0] - vec4(215., -330., -60., 155.)/630.), vec4(0.000001))) && "
"all(lessThan(abs(v[1] - vec4(-450., 405., 45., -90.)/630.), vec4(0.000001))) && "
"all(lessThan(abs(v[2] - vec4(425., -330., 129., -76.)/630.), vec4(0.000001))) && "
"all(lessThan(abs(v[3] - vec4(-180., 225., -108., 27.)/630.), vec4(0.000001)))");
verifyIsInTranslation("0.3412");
verifyIsNotInTranslation("53.0");
verifyIsNotInTranslation("inverse");
}
// Constant fold determinant()
TEST_P(GLSLConstantFoldingTest, Determinant2x2)
{
test("float", "const float c = determinant(mat2(2., 3., 5., 7.))", "v == -1.");
verifyIsInTranslation("-1.0");
verifyIsNotInTranslation("7.0");
verifyIsNotInTranslation("determinant");
}
// Constant fold determinant()
TEST_P(GLSLConstantFoldingTest, Determinant3x3)
{
test("float", "const float c = determinant(mat3(11., 13., 19., 23., 29., 31., 37., 41., 43.))",
"v == -680.");
verifyIsInTranslation("-680.");
verifyIsNotInTranslation("31.0");
verifyIsNotInTranslation("determinant");
}
// Constant fold determinant()
TEST_P(GLSLConstantFoldingTest, Determinant4x4)
{
test("float",
"const float c = determinant(mat4(29., 31., 37., 41., "
"43., 47., 53., 59., "
"61., 67., 71., 73., "
"79., 83., 89., 97.))",
"v == -2520.");
verifyIsInTranslation("-2520.0");
verifyIsNotInTranslation("71.0");
verifyIsNotInTranslation("determinant");
}
// Constant fold transpose()
TEST_P(GLSLConstantFoldingTest, Transpose3x3)
{
test("mat3", "const mat3 c = transpose(mat3(11., 13., 19., 23., 29., 31., 37., 41., 43.))",
"all(lessThan(abs(v[0] - vec3(11., 23., 37.)), vec3(0.000001))) && "
"all(lessThan(abs(v[1] - vec3(13., 29., 41.)), vec3(0.000001))) && "
"all(lessThan(abs(v[2] - vec3(19., 31., 43.)), vec3(0.000001)))");
verifyIsInTranslation("11.0, 23.0");
verifyIsNotInTranslation("11.0, 13.0");
verifyIsNotInTranslation("transpose");
}
// 0xFFFFFFFF as int should evaluate to -1.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_P(GLSLConstantFoldingTest, ParseWrappedHexIntLiteral)
{
test("int", "const int c = 0xFFFFFFFF", "v == -1");
verifyIsInTranslation("-1");
}
// 3000000000 as int should wrap to -1294967296.
// This is featured in the examples of GLSL 4.5, and ESSL behavior should match
// desktop GLSL when it comes to integer parsing.
TEST_P(GLSLConstantFoldingTest, ParseWrappedDecimalIntLiteral)
{
test("int", "const int c = 3000000000", "v == -1294967296");
verifyIsInTranslation("-1294967296");
}
// 0xFFFFFFFF as uint should be unchanged.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_P(GLSLConstantFoldingTest, ParseMaxUintLiteral)
{
test("uint", "const uint c = 0xFFFFFFFFu", "v == 0xFFFFFFFFu");
verifyIsInTranslation("4294967295");
}
// -1 as uint should wrap to 0xFFFFFFFF.
// This is featured in the examples of ESSL3 section 4.1.3. ESSL3 section 12.42
// means that any 32-bit unsigned integer value is a valid literal.
TEST_P(GLSLConstantFoldingTest, ParseUnaryMinusOneUintLiteral)
{
test("uint", "const uint c = -1u", "v == 0xFFFFFFFFu");
verifyIsInTranslation("4294967295");
}
// Constant fold matrix constructor from matrix with identical size
TEST_P(GLSLConstantFoldingTest, ConstructMat2FromMat2)
{
test("mat2", "const mat2 c = mat2(mat2(0., 1., 2., 3.))",
"all(equal(v[0], vec2(0., 1.))) && "
"all(equal(v[1], vec2(2., 3.)))");
}
// Constant fold matrix constructor from scalar
TEST_P(GLSLConstantFoldingTest, ConstructMat2FromScalar)
{
test("mat2", "const mat2 c = mat2(3)",
"all(equal(v[0], vec2(3., 0.))) && "
"all(equal(v[1], vec2(0., 3.)))");
verifyIsInTranslation("0.0");
}
// Constant fold matrix constructor from vector
TEST_P(GLSLConstantFoldingTest, ConstructMat2FromVector)
{
test("mat2", "const mat2 c = mat2(vec4(0., 1., 2., 3.))",
"all(equal(v[0], vec2(0., 1.))) && "
"all(equal(v[1], vec2(2., 3.)))");
}
// Constant fold matrix constructor from multiple args
TEST_P(GLSLConstantFoldingTest, ConstructMat2FromMultiple)
{
test("mat2", "const mat2 c = mat2(-1, vec2(0., 1.), vec4(2.))",
"all(equal(v[0], vec2(-1., 0.))) && "
"all(equal(v[1], vec2(1., 2.)))");
verifyIsInTranslation("1.0, 2.0");
}
// Constant fold matrix constructor from larger matrix
TEST_P(GLSLConstantFoldingTest, ConstructMat2FromMat3)
{
test("mat2", "const mat2 c = mat2(mat3(0., 1., 2., 3., 4., 5., 6., 7., 8.))",
"all(equal(v[0], vec2(0., 1.))) && "
"all(equal(v[1], vec2(3., 4.)))");
}
// Constant fold matrix constructor from smaller matrix
TEST_P(GLSLConstantFoldingTest, ConstructMat4x3FromMat3x2)
{
test("mat4x3", "const mat4x3 c = mat4x3(mat3x2(1., 2., 3., 4., 5., 6.))",
"all(equal(v[0], vec3(1., 2., 0.))) && "
"all(equal(v[1], vec3(3., 4., 0.))) && "
"all(equal(v[2], vec3(5., 6., 1.))) && "
"all(equal(v[3], vec3(0., 0., 0.)))");
verifyIsInTranslation("2.0, 0.0");
}
// Constant fold struct comparison when structs are different
TEST_P(GLSLConstantFoldingTest, StructEqualityFalse)
{
test("int", R"(
struct nested {
float f;
};
struct S {
nested a;
float f;
};
const S s1 = S(nested(0.), 2.);
const S s2 = S(nested(0.), 3.);
const int c = s1 == s2 ? 1 : 0;)",
"!bool(v)");
verifyIsNotInTranslation("2.0");
verifyIsNotInTranslation("3.0");
verifyIsNotInTranslation("==");
}
// Constant fold struct comparison when structs are identical
TEST_P(GLSLConstantFoldingTest, StructEqualityTrue)
{
test("int", R"(
struct nested {
float f;
};
struct S {
nested a;
float f;
int i;
};
const S s1 = S(nested(0.), 2., 3);
const S s2 = S(nested(0.), 2., 3);
const int c = s1 == s2 ? 1 : 0;)",
"bool(v)");
verifyIsNotInTranslation("2.0");
verifyIsNotInTranslation("3.0");
verifyIsNotInTranslation("==");
}
// Constant fold indexing of a non-square matrix
TEST_P(GLSLConstantFoldingTest, NonSquareMatrixIndex)
{
test("vec4", "const vec4 c = mat3x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)[1]",
"all(equal(v, vec4(4, 5, 6, 7)))");
verifyIsInTranslation("4.0");
verifyIsNotInTranslation("[1]");
}
// Constant fold outerProduct with vectors of non-matching length
TEST_P(GLSLConstantFoldingTest, NonSquareOuterProduct)
{
test("mat3x2", "const mat3x2 c = outerProduct(vec2(2., 3.), vec3(5., 7., 11.))",
"all(equal(v[0], vec2(10., 15.))) &&"
"all(equal(v[1], vec2(14., 21.))) &&"
"all(equal(v[2], vec2(22., 33.)))");
verifyIsInTranslation("15.0");
verifyIsNotInTranslation("7.0");
verifyIsNotInTranslation("outerProduct");
}
// Constant fold shift left with different non-matching signedness
TEST_P(GLSLConstantFoldingTest, ShiftLeftMismatchingSignedness)
{
test("uint", "const uint c = 0xFFFFFFFFu << 31", "v == 0x80000000u");
verifyIsInTranslation("2147483648");
if (!IsOpenGLES())
{
// Do not check with GLES, because `#version 310 es` would match this.
verifyIsNotInTranslation("31");
}
verifyIsNotInTranslation("<<");
}
// Constant fold shift right with different non-matching signedness
TEST_P(GLSLConstantFoldingTest, ShiftRightMismatchingSignedness)
{
test("uint", "const uint c = 0xFFFFFFFFu >> 29", "v == 0x7u");
verifyIsInTranslation("7");
verifyIsNotInTranslation("29");
verifyIsNotInTranslation(">>");
}
// Constant fold shift right, expecting sign extension
TEST_P(GLSLConstantFoldingTest, ShiftRightSignExtension)
{
test("int", "const int c = 0x8FFFE000 >> 6", "v == 0xFE3FFF80");
verifyIsInTranslation("29360256");
verifyIsNotInTranslation(" 6");
verifyIsNotInTranslation(">>");
}
// Constant fold shift left, such that the number turns from positive to negative
TEST_P(GLSLConstantFoldingTest, ShiftLeftChangeSign)
{
test("int", "const int c = 0x1FFFFFFF << 7", "v == 0xFFFFFF80");
verifyIsInTranslation("-128");
verifyIsNotInTranslation(" 7");
verifyIsNotInTranslation("<<");
}
// Constant fold divide minimum integer by -1.
// ESSL 3.00.6 section 4.1.3 Integers:
// > However, for the case where the minimum representable value is divided by -1, it is allowed to
// > return either the minimum representable value or the maximum representable value.
//
// ANGLE always returns the maximum value.
TEST_P(GLSLConstantFoldingTest, DivideMinimumIntegerByMinusOne)
{
test("int", "const int c = 0x80000000 / -1", "v == 0x7FFFFFFF");
verifyIsInTranslation("2147483647");
}
// Constant fold unsigned addition with overflow
// 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_P(GLSLConstantFoldingTest, UnsignedIntegerAddOverflow)
{
test("uint", "const uint c = 0xFFFFFFFFu + 43u", "v == 42u");
verifyIsInTranslation("42");
verifyIsNotInTranslation("43");
}
// Constant fold signed addition with overflow
// 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_P(GLSLConstantFoldingTest, SignedIntegerAddOverflow)
{
test("int", "const int c = 0x7FFFFFFF + 4", "v == -0x7FFFFFFD");
verifyIsInTranslation("-2147483645");
}
// Constant fold unsigned subtraction with underflow
// 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_P(GLSLConstantFoldingTest, UnsignedIntegerSubUnderflow)
{
test("uint", "const uint c = 0u - 5u", "v == 0xFFFFFFFBu");
verifyIsInTranslation("4294967291");
}
// Constant fold signed subtraction with underflow
// 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_P(GLSLConstantFoldingTest, SignedIntegerSubUnderflow)
{
test("int", "const int c = -0x7FFFFFFF - 7", "v == 0x7FFFFFFA");
verifyIsInTranslation("2147483642");
}
// Constant fold unsigned multiplication with overflow
// 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_P(GLSLConstantFoldingTest, UnsignedIntegerMulOverflow)
{
test("uint", "const uint c = 0xFFFFFFFFu * 10u", "v == 0xFFFFFFF6u");
verifyIsInTranslation("4294967286");
}
// Constant fold signed multiplication with overflow
// 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_P(GLSLConstantFoldingTest, SignedIntegerMulOverflow)
{
test("int", "const int c = 0x7FFFFFFF * 42", "v == -42");
verifyIsInTranslation("-42");
}
// Constant fold negation of minimum integer value, which is 0x80000000.
// 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_P(GLSLConstantFoldingTest, SignedIntegerNegateOverflow)
{
test("int", "const int c = -0x80000000", "v == 0x80000000");
verifyIsInTranslation("-2147483648");
}
// Constant fold shift right of minimum integer value, which is 0x80000000.
TEST_P(GLSLConstantFoldingTest, SignedIntegerShiftRightMinimumValue)
{
test("int", "const int c = (0x80000000 >> 1) + (0x80000000 >> 7)", "v == -0x41000000");
verifyIsInTranslation("-1090519040");
}
// Constant fold shift left by zero.
TEST_P(GLSLConstantFoldingTest, SignedIntegerShiftLeftZero)
{
test("int", "const int c = 73 << 0", "v == 73");
}
// Constant fold shift right by zero.
TEST_P(GLSLConstantFoldingTest, SignedIntegerShiftRightZero)
{
test("int", "const int c = 3 >> 0", "v == 3");
}
// Constant fold isinf with an out-of-range value
// ESSL 3.00.6 section 4.1.4 Floats:
// > If the value of the floating point number is too large (small) to be stored as a single
// > precision value, it is converted to positive (negative) infinity.
// ESSL 3.00.6 section 12.4:
// > Mandate support for signed infinities.
TEST_P(GLSLConstantFoldingTest, IsInfTrue)
{
test("int", "const int c = isinf(1.0e2048) ? 1 : 0", "bool(v)");
verifyIsNotInTranslation("isinf");
}
// Test that floats that are too small to be represented get flushed to zero.
// ESSL 3.00.6 section 4.1.4 Floats:
// > A value with a magnitude too small to be represented as a mantissa and exponent is converted to
// > zero.
TEST_P(GLSLConstantFoldingTest, TooSmallFloat)
{
test("float", "const float c = 1.0e-2048", "v == 0.");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim radians(x) x -> inf = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, RadiansInfinity)
{
test("float", "const float c = radians(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("radians");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim degrees(x) x -> inf = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, DegreesInfinity)
{
test("float", "const float c = degrees(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("degress");
}
// IEEE 754 dictates that sinh(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, SinhInfinity)
{
test("float", "const float c = sinh(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("sinh");
}
// IEEE 754 dictates that sinh(-inf) = -inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, SinhNegativeInfinity)
{
test("float", "const float c = sinh(-1.0e2048)", "isinf(v) && v < 0.");
verifyIsNotInTranslation("sinh");
}
// IEEE 754 dictates that cosh(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, CoshInfinity)
{
test("float", "const float c = cosh(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("cosh");
}
// IEEE 754 dictates that cosh(-inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, CoshNegativeInfinity)
{
test("float", "const float c = cosh(-1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("cosh");
}
// IEEE 754 dictates that asinh(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, AsinhInfinity)
{
test("float", "const float c = asinh(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("asinh");
}
// IEEE 754 dictates that asinh(-inf) = -inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, AsinhNegativeInfinity)
{
test("float", "const float c = asinh(-1.0e2048)", "isinf(v) && v < 0.");
verifyIsNotInTranslation("asinh");
}
// IEEE 754 dictates that acosh(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, AcoshInfinity)
{
test("float", "const float c = acosh(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("acosh");
}
// IEEE 754 dictates that pow or powr(0, inf) = 0.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, PowInfinity)
{
test("float", "const float c = pow(0.0, 1.0e2048)", "v == 0.");
verifyIsNotInTranslation("pow");
}
// IEEE 754 dictates that exp(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, ExpInfinity)
{
test("float", "const float c = exp(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("exp");
}
// IEEE 754 dictates that exp(-inf) = 0.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, ExpNegativeInfinity)
{
test("float", "const float c = exp(-1.0e2048)", "v == 0.");
verifyIsNotInTranslation("exp");
}
// IEEE 754 dictates that log(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, LogInfinity)
{
test("float", "const float c = log(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("log");
}
// IEEE 754 dictates that exp2(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, Exp2Infinity)
{
test("float", "const float c = exp2(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("exp2");
}
// IEEE 754 dictates that exp2(-inf) = 0.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, Exp2NegativeInfinity)
{
test("float", "const float c = exp2(-1.0e2048)", "v == 0.");
verifyIsNotInTranslation("exp2");
}
// IEEE 754 dictates that log2(inf) = inf.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, Log2Infinity)
{
test("float", "const float c = log2(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("log2");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim sqrt(x) x -> inf = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, SqrtInfinity)
{
test("float", "const float c = sqrt(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("sqrt");
}
// IEEE 754 dictates that rSqrt(inf) = 0
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InversesqrtInfinity)
{
test("float", "const float c = inversesqrt(1.0e2048)", "v == 0.");
verifyIsNotInTranslation("inversesqrt");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim length(x) x -> inf = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, LengthInfinity)
{
test("float", "const float c = length(1.0e2048)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("length");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim dot(x, y) x -> inf, y > 0 = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, DotInfinity)
{
test("float", "const float c = dot(1.0e2048, 1.)", "isinf(v) && v > 0.");
verifyIsNotInTranslation("dot");
}
// IEEE 754 dictates that behavior of infinity is derived from limiting cases of real arithmetic.
// lim dot(vec2(x, y), vec2(z)) x -> inf, finite y, z > 0 = inf
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, DotInfinity2)
{
test("float", "const float c = dot(vec2(1.0e2048, -1.), vec2(1.))", "isinf(v) && v > 0.");
verifyIsNotInTranslation("dot");
}
// Faceforward behavior with infinity as a parameter can be derived from dot().
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, FaceForwardInfinity)
{
test("float", "const float c = faceforward(4., 1.0e2048, 1.)", "v == -4.");
verifyIsNotInTranslation("faceforward");
}
// Faceforward behavior with infinity as a parameter can be derived from dot().
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, FaceForwardInfinity2)
{
test("float", "const float c = faceforward(vec2(4.), vec2(1.0e2048, -1.), vec2(1.)).x",
"v == -4.");
verifyIsNotInTranslation("faceforward");
}
// Test that infinity - finite value evaluates to infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InfinityMinusFinite)
{
test("float", "const float c = 1.0e2048 - 1.0e20", "isinf(v) && v > 0.");
}
// Test that -infinity + finite value evaluates to -infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, MinusInfinityPlusFinite)
{
test("float", "const float c = (-1.0e2048) + 1.0e20", "isinf(v) && v < 0.");
}
// Test that infinity * finite value evaluates to infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InfinityMultipliedByFinite)
{
test("float", "const float c = 1.0e2048 * 1.0e-20", "isinf(v) && v > 0.");
}
// Test that infinity * infinity evaluates to infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InfinityMultipliedByInfinity)
{
test("float", "const float c = 1.0e2048 * 1.0e2048", "isinf(v) && v > 0.");
}
// Test that infinity * negative infinity evaluates to negative infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InfinityMultipliedByNegativeInfinity)
{
test("float", "const float c = 1.0e2048 * (-1.0e2048)", "isinf(v) && v < 0.");
}
// Test that dividing by minus zero results in the appropriately signed infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
// > If both positive and negative zeros are implemented, the correctly signed Inf will be
// > generated.
TEST_P(GLSLConstantFoldingTest, DivideByNegativeZero)
{
test("float", "const float c = 1. / (-0.)", "isinf(v) && v < 0.");
verifyIsNotInTranslation("-0.0");
}
// Test that infinity divided by zero evaluates to infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, InfinityDividedByZero)
{
test("float", "const float c = 1.0e2048 / 0.", "isinf(v) && v > 0.");
}
// Test that negative infinity divided by zero evaluates to negative infinity.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, MinusInfinityDividedByZero)
{
test("float", "const float c = (-1.0e2048) / 0.", "isinf(v) && v < 0.");
}
// Test that dividing a finite number by infinity results in zero.
// ESSL 3.00.6 section 4.5.1:
// > Infinities and zeroes are generated as dictated by IEEE.
TEST_P(GLSLConstantFoldingTest, DivideByInfinity)
{
test("float", "const float c = 1.0e30 / 1.0e2048", "v == 0.");
}
// Test that unsigned bitfieldExtract is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, UnsignedBitfieldExtract)
{
test("uint", "const uint c = bitfieldExtract(0x00110000u, 16, 5)", "v == 0x11u");
verifyIsInTranslation("17");
verifyIsNotInTranslation("16");
verifyIsNotInTranslation("bitfieldExtract");
}
// Test that unsigned bitfieldExtract to extract 32 bits is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, UnsignedBitfieldExtract32Bits)
{
test("uint", "const uint c = bitfieldExtract(0xFF0000FFu, 0, 32)", "v == 0xFF0000FFu");
verifyIsNotInTranslation("32");
verifyIsNotInTranslation("bitfieldExtract");
}
// Test that signed bitfieldExtract is folded correctly. The higher bits should be set to 1 if the
// most significant bit of the extracted value is 1.
TEST_P(GLSLConstantFoldingTest_ES31, SignedBitfieldExtract)
{
test("int", "const int c = bitfieldExtract(0x00110000, 16, 5)", "v == -15");
verifyIsInTranslation("-15");
verifyIsNotInTranslation("16");
verifyIsNotInTranslation("bitfieldExtract");
}
// Test that bitfieldInsert is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, BitfieldInsert)
{
test("uint", "const uint c = bitfieldInsert(0x04501701u, 0x11u, 8, 5)", "v == 0x04501101u");
verifyIsInTranslation("72356097");
verifyIsNotInTranslation(" 8");
verifyIsNotInTranslation("bitfieldInsert");
}
// Test that bitfieldInsert to insert 32 bits is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, BitfieldInsert32Bits)
{
test("uint", "const uint c = bitfieldInsert(0xFF0000FFu, 0x11u, 0, 32)", "v == 0x11u");
verifyIsInTranslation("17");
verifyIsNotInTranslation("32");
verifyIsNotInTranslation("bitfieldInsert");
}
// Test that bitfieldReverse is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, BitfieldReverse)
{
test("uint", "const uint c = bitfieldReverse((1u << 4u) | (1u << 7u))", "v == 0x9000000u");
verifyIsInTranslation("150994944");
verifyIsNotInTranslation(" 7");
verifyIsNotInTranslation("bitfieldReverse");
}
// Test that bitCount is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, BitCount)
{
test("int", "const int c = bitCount(0x17103121u)", "v == 10");
verifyIsInTranslation("10");
verifyIsNotInTranslation("386937121");
verifyIsNotInTranslation("bitCount");
}
// Test that findLSB is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, FindLSB)
{
test("int", "const int c = findLSB(0x80010000u)", "v == 16");
verifyIsInTranslation("16");
verifyIsNotInTranslation("2147549184");
verifyIsNotInTranslation("findLSB");
}
// Test that findLSB is folded correctly when the operand is zero.
TEST_P(GLSLConstantFoldingTest_ES31, FindLSBZero)
{
test("int", "const int c = findLSB(0u)", "v == -1");
verifyIsInTranslation("-1");
verifyIsNotInTranslation("findLSB");
}
// Test that findMSB is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, FindMSB)
{
test("int", "const int c = findMSB(0x01000008u)", "v == 24");
verifyIsInTranslation("24");
verifyIsNotInTranslation("16777224");
verifyIsNotInTranslation("findMSB");
}
// Test that findMSB is folded correctly when the operand is zero.
TEST_P(GLSLConstantFoldingTest_ES31, FindMSBZero)
{
test("int", "const int c = findMSB(0u)", "v == -1");
verifyIsInTranslation("-1");
verifyIsNotInTranslation("findMSB");
}
// Test that findMSB is folded correctly for a negative integer.
// It is supposed to return the index of the most significant bit set to 0.
TEST_P(GLSLConstantFoldingTest_ES31, FindMSBNegativeInt)
{
test("int", "const int c = findMSB(-8)", "v == 2");
verifyIsInTranslation("2");
verifyIsNotInTranslation("-8");
verifyIsNotInTranslation("findMSB");
}
// Test that findMSB is folded correctly for -1.
TEST_P(GLSLConstantFoldingTest_ES31, FindMSBMinusOne)
{
test("int", "const int c = findMSB(-1)", "v == -1");
verifyIsNotInTranslation("findMSB");
}
// Test that packUnorm4x8 is folded correctly for a vector of zeroes.
TEST_P(GLSLConstantFoldingTest_ES31, PackUnorm4x8Zero)
{
test("uint", "const uint c = packUnorm4x8(vec4(0.))", "v == 0u");
verifyIsNotInTranslation("packUnorm4x8");
}
// Test that packUnorm4x8 is folded correctly for a vector of ones.
TEST_P(GLSLConstantFoldingTest_ES31, PackUnorm4x8One)
{
test("uint", "const uint c = packUnorm4x8(vec4(1.))", "v == 0xFFFFFFFFu");
verifyIsInTranslation("4294967295");
verifyIsNotInTranslation("packUnorm4x8");
}
// Test that packSnorm4x8 is folded correctly for a vector of zeroes.
TEST_P(GLSLConstantFoldingTest_ES31, PackSnorm4x8Zero)
{
test("uint", "const uint c = packSnorm4x8(vec4(0.))", "v == 0u");
verifyIsNotInTranslation("packSnorm4x8");
}
// Test that packSnorm4x8 is folded correctly for a vector of ones.
TEST_P(GLSLConstantFoldingTest_ES31, PackSnorm4x8One)
{
test("uint", "const uint c = packSnorm4x8(vec4(1.))", "v == 0x7F7F7F7Fu");
verifyIsInTranslation("2139062143");
verifyIsNotInTranslation("packSnorm4x8");
}
// Test that packSnorm4x8 is folded correctly for a vector of minus ones.
TEST_P(GLSLConstantFoldingTest_ES31, PackSnorm4x8MinusOne)
{
test("uint", "const uint c = packSnorm4x8(vec4(-1.))", "v == 0x81818181u");
verifyIsInTranslation("2172748161");
verifyIsNotInTranslation("packSnorm4x8");
}
// Test that unpackSnorm4x8 is folded correctly when it needs to clamp the result.
TEST_P(GLSLConstantFoldingTest_ES31, UnpackSnorm4x8Clamp)
{
test("float", "const float c = unpackSnorm4x8(0x00000080u).x", "v == -1.");
verifyIsInTranslation("-1.0");
verifyIsNotInTranslation("packSnorm4x8");
}
// Test that unpackUnorm4x8 is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, UnpackUnorm4x8)
{
test("float", "const float c = unpackUnorm4x8(0x007bbeefu).z", "abs(v - 123./255.) < 0.000001");
verifyIsInTranslation("0.48235");
verifyIsNotInTranslation("8109807");
verifyIsNotInTranslation("packUnorm4x8");
}
// Test that ldexp is folded correctly.
TEST_P(GLSLConstantFoldingTest_ES31, Ldexp)
{
test("float", "const float c = ldexp(0.625, 1)", "v == 1.25");
verifyIsNotInTranslation("0.625");
verifyIsNotInTranslation("ldexp");
}
// Constant fold ternary
TEST_P(GLSLConstantFoldingTest, Ternary)
{
test("int", "int c = true ? 1 : v", "v == 1");
verifyIsNotInTranslation("?");
verifyIsNotInTranslation("if");
verifyIsNotInTranslation("else");
}
// Constant fold ternary
TEST_P(GLSLConstantFoldingTest, TernaryInsideExpression)
{
test("int", "int c = ivec2((true ? 1 : v) + 2, 4).x", "v == 3");
verifyIsNotInTranslation("?");
verifyIsNotInTranslation("if");
verifyIsNotInTranslation("else");
}
// Constant fold indexing of an array
TEST_P(GLSLConstantFoldingTest, ArrayIndex)
{
test("float", "const float c = float[3](-1., 1., 2.)[2]", "v == 2.");
verifyIsNotInTranslation("[2]");
}
// Constant fold indexing of an array of array
TEST_P(GLSLConstantFoldingTest_ES31, ArrayOfArrayIndex)
{
test("float", "const float c = float[2][2](float[2](-1., 1.), float[2](2., 3.))[1][0]",
"v == 2.");
verifyIsNotInTranslation("[1]");
verifyIsNotInTranslation("[0]");
}
// Constant fold indexing of an array stashed in another variable
TEST_P(GLSLConstantFoldingTest, NamedArrayIndex)
{
test("float", R"(const float[3] arr = float[3](-1., 1., 2.);
const float c = arr[1])",
"v == 1.");
verifyIsNotInTranslation("[1]");
}
// Constant fold indexing of an array of array stashed in another variable
TEST_P(GLSLConstantFoldingTest_ES31, NamedArrayOfArrayIndex)
{
test("float[2]", R"(const float[2][2] arr = float[2][2](float[2](-1., 1.), float[2](2., 3.));
const float[2] c = arr[1])",
"v[0] == 2. && v[1] == 3.");
// The AST path does not remove the definition of `arr`.
if (getEGLWindow()->isFeatureEnabled(Feature::UseIr))
{
verifyIsNotInTranslation("1.0");
}
}
// Constant fold indexing of an array of mixed constant and non-constant values (without side
// effect).
TEST_P(GLSLConstantFoldingTest, ArrayMixedArgumentsIndex)
{
test("float", R"(float c = float[2](v, 1.)[1])", "v == 1.");
verifyIsNotInTranslation("[1]");
}
// Constant fold indexing of an array of mixed constant and non-constant values with side
// effect should not discard the side effect.
TEST_P(GLSLConstantFoldingTest, ArrayMixedArgumentsWithSideEffectIndex)
{
test("float", R"(float sideEffectTarget = 0.;
float indexedElement = float[3](sideEffectTarget = 5., 11., 102.)[1];
float c = indexedElement + sideEffectTarget)",
"v == 16.");
}
// Constant fold equality of constructed arrays.
TEST_P(GLSLConstantFoldingTest, ArrayEqualityFalse)
{
test("float", "const float c = float[3](2., 1., 1.) == float[3](2., 1., -1.) ? 1. : 2.",
"v == 2.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold equality of constructed arrays.
TEST_P(GLSLConstantFoldingTest, ArrayEqualityTrue)
{
test("float", "const float c = float[3](2., 1., -1.) == float[3](2., 1., -1.) ? 1. : 2.",
"v == 1.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold equality of constructed arrays stashed in variables.
TEST_P(GLSLConstantFoldingTest, NamedArrayEqualityFalse)
{
test("float", R"(const float[3] arrA = float[3](-1., 1., 2.);
const float[3] arrB = float[3](1., 1., 2.);
float c = arrA == arrB ? 1. : 2.)",
"v == 2.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold equality of constructed arrays stashed in variables.
TEST_P(GLSLConstantFoldingTest, NamedArrayEqualityTrue)
{
test("float", R"(const float[3] arrA = float[3](-1., 1., 2.);
const float[3] arrB = float[3](-1., 1., 2.);
float c = arrA == arrB ? 1. : 2.)",
"v == 1.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold equality of constructed arrays of arrays.
TEST_P(GLSLConstantFoldingTest_ES31, ArrayOfArrayEqualityFalse)
{
test("float", R"(const float c = float[2][2](float[2](-1., 1.), float[2](2., 3.))
== float[2][2](float[2](-1., 1.), float[2](2., 1000.)) ? 1. : 2.)",
"v == 2.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold equality of constructed arrays.
TEST_P(GLSLConstantFoldingTest_ES31, ArrayOfArrayEqualityTrue)
{
test("float", R"(const float c = float[2][2](float[2](-1., 1.), float[2](2., 3.))
== float[2][2](float[2](-1., 1.), float[2](2., 3.)) ? 1. : 2.)",
"v == 1.");
verifyIsNotInTranslation("-1.0");
verifyIsNotInTranslation("==");
}
// Constant fold casting a negative float to uint.
// ESSL 3.00.6 section 5.4.1 specifies this as an undefined conversion.
TEST_P(GLSLConstantFoldingTest, NegativeFloatToUint)
{
test("uint", "const uint c = uint(-1.)", "v == 0xFFFFFFFFu");
verifyIsInTranslation("4294967295");
}
// Constant fold casting a negative float to uint inside a uvec constructor.
// ESSL 3.00.6 section 5.4.1 specifies this as an undefined conversion.
TEST_P(GLSLConstantFoldingTest, NegativeFloatToUvec)
{
test("uint", "const uint c = uvec4(2., 1., vec2(0., -1.)).w", "v == 0xFFFFFFFFu");
verifyIsInTranslation("4294967295");
verifyIsNotInTranslation("2.0");
}
// Constant fold casting a negative float to uint inside a uvec constructor, but that which is not
// used by the constructor.
TEST_P(GLSLConstantFoldingTest, NegativeFloatInsideUvecConstructorButOutOfRange)
{
test("uint", "const uint c = uvec2(1., vec2(0., -1.)).x", "v == 1u");
verifyIsNotInTranslation("-1.0");
}
// Constant fold a large float (above max signed int) to uint.
TEST_P(GLSLConstantFoldingTest, LargeFloatToUint)
{
test("uint", "const uint c = uint(3221225472.)", "v == 3221225472u");
}
// Constant fold modulus with a negative dividend.
TEST_P(GLSLConstantFoldingTest, IntegerModulusNegativeDividend)
{
test("int", "const int c = (-5) % 3", "v == 0");
verifyIsNotInTranslation("%");
}
// Constant fold modulus with a negative divisor.
TEST_P(GLSLConstantFoldingTest, IntegerModulusNegativeDivisor)
{
test("int", "const int c = 5 % (-3)", "v == 0");
verifyIsNotInTranslation("%");
}
// Constant fold isnan with multiple components
TEST_P(GLSLConstantFoldingTest_ES31, IsnanMultipleComponents)
{
test("ivec4", "const ivec4 c = ivec4(mix(ivec2(2), ivec2(3), isnan(vec2(1., 0. / 0.))), 4, 5)",
"all(equal(v, ivec4(2, 3, 4, 5)))");
verifyIsNotInTranslation("1.0");
verifyIsNotInTranslation("isnan");
verifyIsNotInTranslation("mix");
}
// Constant fold isinf with multiple components
TEST_P(GLSLConstantFoldingTest_ES31, IsinfMultipleComponents)
{
test("ivec4",
"const ivec4 c = ivec4(mix(ivec2(2), ivec2(3), isinf(vec2(0.0, 1.0e2048))), 4, 5)",
"all(equal(v, ivec4(2, 3, 4, 5)))");
verifyIsNotInTranslation("isnan");
verifyIsNotInTranslation("mix");
}
// Constant fold floatBitsToInt with multiple components
TEST_P(GLSLConstantFoldingTest, FloatBitsToIntMultipleComponents)
{
test("ivec4", "const ivec4 c = ivec4(floatBitsToInt(vec2(0.0, 1.0)), 4, 5)",
"all(equal(v, ivec4(0, 0x3f800000, 4, 5)))");
verifyIsNotInTranslation("1.0");
verifyIsNotInTranslation("floatBitsToInt");
}
// Constant fold floatBitsToUint with multiple components
TEST_P(GLSLConstantFoldingTest, FloatBitsToUintMultipleComponents)
{
test("ivec4", "const ivec4 c = ivec4(floatBitsToUint(vec2(0.0, 1.0)), 4, 5)",
"all(equal(v, ivec4(0, 0x3f800000, 4, 5)))");
verifyIsNotInTranslation("1.0");
verifyIsNotInTranslation("floatBitsToInt");
}
// Constant fold intBitsToFloat with multiple components
TEST_P(GLSLConstantFoldingTest, IntBitsToFloatMultipleComponents)
{
test("vec4", "const vec4 c = vec4(intBitsToFloat(ivec2(0, 0x3f800000)), 0.25, 0.5)",
"all(equal(v, vec4(0., 1., 0.25, 0.5)))");
verifyIsNotInTranslation("1065353216");
verifyIsNotInTranslation("intBitsToFloat");
}
// Constant fold uintBitsToFloat with multiple components
TEST_P(GLSLConstantFoldingTest, UintBitsToFloatMultipleComponents)
{
test("vec4", "const vec4 c = vec4(uintBitsToFloat(uvec2(0U, 0x3f800000U)), 0.25, 0.5)",
"all(equal(v, vec4(0., 1., 0.25, 0.5)))");
verifyIsNotInTranslation("1065353216");
verifyIsNotInTranslation("uintBitsToFloat");
}
// Test that infinity - infinity evaluates to NaN.
TEST_P(GLSLConstantFoldingTest, InfinityMinusInfinity)
{
test("float", "const float c = 1.0e2048 - 1.0e2048", "isnan(v)");
}
// Test that infinity + negative infinity evaluates to NaN.
TEST_P(GLSLConstantFoldingTest, InfinityPlusNegativeInfinity)
{
test("float", "const float c = 1.0e2048 + (-1.0e2048)", "isnan(v)");
}
// Test that infinity multiplied by zero evaluates to NaN.
TEST_P(GLSLConstantFoldingTest, InfinityMultipliedByZero)
{
test("float", "const float c = 1.0e2048 * 0.", "isnan(v)");
}
// Test that infinity divided by infinity evaluates to NaN.
TEST_P(GLSLConstantFoldingTest, InfinityDividedByInfinity)
{
test("float", "const float c = 1.0e2048 / 1.0e2048", "isnan(v)");
}
// Test that zero divided by zero evaluates to NaN.
TEST_P(GLSLConstantFoldingTest, ZeroDividedByZero)
{
test("float", "const float c = 0. / 0.", "isnan(v)");
}
// Test that addition that overflows is evaluated correctly.
TEST_P(GLSLConstantFoldingTest, FloatOverflowAdd)
{
test("float", "const float c = 2.0e38 + 2.0e38", "isinf(v) && v > 0.");
}
// Test that subtraction that overflows is evaluated correctly.
TEST_P(GLSLConstantFoldingTest, FloatOverflowSubtract)
{
test("float", "const float c = 2.0e38 - (-2.0e38)", "isinf(v) && v > 0.");
}
// Test that multiplication that overflows is evaluated correctly.
TEST_P(GLSLConstantFoldingTest, FloatOverflowMultiply)
{
test("float", "const float c = 1.0e30 * 1.0e10", "isinf(v) && v > 0.");
}
// Test that division that overflows is evaluated correctly.
TEST_P(GLSLConstantFoldingTest, FloatOverflowDivide)
{
test("float", "const float c = 1.0e30 / 1.0e-10", "isinf(v) && v > 0.");
}
} // namespace
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLConstantFoldingTest);
ANGLE_INSTANTIATE_TEST_ES3(GLSLConstantFoldingTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLConstantFoldingTest_ES31);
ANGLE_INSTANTIATE_TEST_ES31(GLSLConstantFoldingTest_ES31);