| // |
| // Copyright (c) 2015 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. |
| // |
| // ConstantFolding_test.cpp: |
| // Tests for constant folding |
| // |
| |
| #include "tests/test_utils/ConstantFoldingTest.h" |
| |
| using namespace sh; |
| |
| // Test that zero, true or false are not found in AST when they are not expected. This is to make |
| // sure that the subsequent tests run correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldFloatTestSanityCheck) |
| { |
| const std::string &floatString = "1.0"; |
| evaluateFloat(floatString); |
| ASSERT_FALSE(constantFoundInAST(0.0f)); |
| ASSERT_FALSE(constantFoundInAST(true)); |
| ASSERT_FALSE(constantFoundInAST(false)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldIntegerAdd) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out int my_Int;\n" |
| "void main() {\n" |
| " const int i = 1124 + 5;\n" |
| " my_Int = i;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_FALSE(constantFoundInAST(1124)); |
| ASSERT_FALSE(constantFoundInAST(5)); |
| ASSERT_TRUE(constantFoundInAST(1129)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldIntegerSub) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out int my_Int;\n" |
| "void main() {\n" |
| " const int i = 1124 - 5;\n" |
| " my_Int = i;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_FALSE(constantFoundInAST(1124)); |
| ASSERT_FALSE(constantFoundInAST(5)); |
| ASSERT_TRUE(constantFoundInAST(1119)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldIntegerMul) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out int my_Int;\n" |
| "void main() {\n" |
| " const int i = 1124 * 5;\n" |
| " my_Int = i;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_FALSE(constantFoundInAST(1124)); |
| ASSERT_FALSE(constantFoundInAST(5)); |
| ASSERT_TRUE(constantFoundInAST(5620)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldIntegerDiv) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out int my_Int;\n" |
| "void main() {\n" |
| " const int i = 1124 / 5;\n" |
| " my_Int = i;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_FALSE(constantFoundInAST(1124)); |
| ASSERT_FALSE(constantFoundInAST(5)); |
| // Rounding mode of division is undefined in the spec but ANGLE can be expected to round down. |
| ASSERT_TRUE(constantFoundInAST(224)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldIntegerModulus) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out int my_Int;\n" |
| "void main() {\n" |
| " const int i = 1124 % 5;\n" |
| " my_Int = i;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_FALSE(constantFoundInAST(1124)); |
| ASSERT_FALSE(constantFoundInAST(5)); |
| ASSERT_TRUE(constantFoundInAST(4)); |
| } |
| |
| TEST_F(ConstantFoldingTest, FoldVectorCrossProduct) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec3 my_Vec3;" |
| "void main() {\n" |
| " const vec3 v3 = cross(vec3(1.0f, 1.0f, 1.0f), vec3(1.0f, -1.0f, 1.0f));\n" |
| " my_Vec3 = v3;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| std::vector<float> input1(3, 1.0f); |
| ASSERT_FALSE(constantVectorFoundInAST(input1)); |
| std::vector<float> input2; |
| input2.push_back(1.0f); |
| input2.push_back(-1.0f); |
| input2.push_back(1.0f); |
| ASSERT_FALSE(constantVectorFoundInAST(input2)); |
| std::vector<float> result; |
| result.push_back(2.0f); |
| result.push_back(0.0f); |
| result.push_back(-2.0f); |
| ASSERT_TRUE(constantVectorFoundInAST(result)); |
| } |
| |
| // FoldMxNMatrixInverse tests check if the matrix 'inverse' operation |
| // on MxN matrix is constant folded when argument is constant expression and also |
| // checks the correctness of the result returned by the constant folding operation. |
| // All the matrices including matrices in the shader code are in column-major order. |
| TEST_F(ConstantFoldingTest, Fold2x2MatrixInverse) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "in float i;\n" |
| "out vec2 my_Vec;\n" |
| "void main() {\n" |
| " const mat2 m2 = inverse(mat2(2.0f, 3.0f,\n" |
| " 5.0f, 7.0f));\n" |
| " mat2 m = m2 * mat2(i);\n" |
| " my_Vec = m[0];\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 2.0f, 3.0f, |
| 5.0f, 7.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 4); |
| ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input)); |
| float outputElements[] = |
| { |
| -7.0f, 3.0f, |
| 5.0f, -2.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Check if the matrix 'inverse' operation on 3x3 matrix is constant folded. |
| TEST_F(ConstantFoldingTest, Fold3x3MatrixInverse) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "in float i;\n" |
| "out vec3 my_Vec;\n" |
| "void main() {\n" |
| " const mat3 m3 = inverse(mat3(11.0f, 13.0f, 19.0f,\n" |
| " 23.0f, 29.0f, 31.0f,\n" |
| " 37.0f, 41.0f, 43.0f));\n" |
| " mat3 m = m3 * mat3(i);\n" |
| " my_Vec = m3[0];\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 11.0f, 13.0f, 19.0f, |
| 23.0f, 29.0f, 31.0f, |
| 37.0f, 41.0f, 43.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 9); |
| ASSERT_FALSE(constantVectorFoundInAST(input)); |
| float outputElements[] = |
| { |
| 3.0f / 85.0f, -11.0f / 34.0f, 37.0f / 170.0f, |
| -79.0f / 340.0f, 23.0f / 68.0f, -12.0f / 85.0f, |
| 13.0f / 68.0f, -3.0f / 68.0f, -1.0f / 34.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 9); |
| const float floatFaultTolerance = 0.000001f; |
| ASSERT_TRUE(constantVectorNearFoundInAST(result, floatFaultTolerance)); |
| } |
| |
| // Check if the matrix 'inverse' operation on 4x4 matrix is constant folded. |
| TEST_F(ConstantFoldingTest, Fold4x4MatrixInverse) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "in float i;\n" |
| "out vec4 my_Vec;\n" |
| "void main() {\n" |
| " const mat4 m4 = inverse(mat4(29.0f, 31.0f, 37.0f, 41.0f,\n" |
| " 43.0f, 47.0f, 53.0f, 59.0f,\n" |
| " 61.0f, 67.0f, 71.0f, 73.0f,\n" |
| " 79.0f, 83.0f, 89.0f, 97.0f));\n" |
| " mat4 m = m4 * mat4(i);\n" |
| " my_Vec = m[0];\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 29.0f, 31.0f, 37.0f, 41.0f, |
| 43.0f, 47.0f, 53.0f, 59.0f, |
| 61.0f, 67.0f, 71.0f, 73.0f, |
| 79.0f, 83.0f, 89.0f, 97.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 16); |
| ASSERT_FALSE(constantVectorFoundInAST(input)); |
| float outputElements[] = |
| { |
| 43.0f / 126.0f, -11.0f / 21.0f, -2.0f / 21.0f, 31.0f / 126.0f, |
| -5.0f / 7.0f, 9.0f / 14.0f, 1.0f / 14.0f, -1.0f / 7.0f, |
| 85.0f / 126.0f, -11.0f / 21.0f, 43.0f / 210.0f, -38.0f / 315.0f, |
| -2.0f / 7.0f, 5.0f / 14.0f, -6.0f / 35.0f, 3.0f / 70.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 16); |
| const float floatFaultTolerance = 0.00001f; |
| ASSERT_TRUE(constantVectorNearFoundInAST(result, floatFaultTolerance)); |
| } |
| |
| // FoldMxNMatrixDeterminant tests check if the matrix 'determinant' operation |
| // on MxN matrix is constant folded when argument is constant expression and also |
| // checks the correctness of the result returned by the constant folding operation. |
| // All the matrices including matrices in the shader code are in column-major order. |
| TEST_F(ConstantFoldingTest, Fold2x2MatrixDeterminant) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out float my_Float;" |
| "void main() {\n" |
| " const float f = determinant(mat2(2.0f, 3.0f,\n" |
| " 5.0f, 7.0f));\n" |
| " my_Float = f;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 2.0f, 3.0f, |
| 5.0f, 7.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 4); |
| ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input)); |
| ASSERT_TRUE(constantFoundInAST(-1.0f)); |
| } |
| |
| // Check if the matrix 'determinant' operation on 3x3 matrix is constant folded. |
| TEST_F(ConstantFoldingTest, Fold3x3MatrixDeterminant) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out float my_Float;" |
| "void main() {\n" |
| " const float f = determinant(mat3(11.0f, 13.0f, 19.0f,\n" |
| " 23.0f, 29.0f, 31.0f,\n" |
| " 37.0f, 41.0f, 43.0f));\n" |
| " my_Float = f;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 11.0f, 13.0f, 19.0f, |
| 23.0f, 29.0f, 31.0f, |
| 37.0f, 41.0f, 43.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 9); |
| ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input)); |
| ASSERT_TRUE(constantFoundInAST(-680.0f)); |
| } |
| |
| // Check if the matrix 'determinant' operation on 4x4 matrix is constant folded. |
| TEST_F(ConstantFoldingTest, Fold4x4MatrixDeterminant) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out float my_Float;" |
| "void main() {\n" |
| " const float f = determinant(mat4(29.0f, 31.0f, 37.0f, 41.0f,\n" |
| " 43.0f, 47.0f, 53.0f, 59.0f,\n" |
| " 61.0f, 67.0f, 71.0f, 73.0f,\n" |
| " 79.0f, 83.0f, 89.0f, 97.0f));\n" |
| " my_Float = f;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 29.0f, 31.0f, 37.0f, 41.0f, |
| 43.0f, 47.0f, 53.0f, 59.0f, |
| 61.0f, 67.0f, 71.0f, 73.0f, |
| 79.0f, 83.0f, 89.0f, 97.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 16); |
| ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input)); |
| ASSERT_TRUE(constantFoundInAST(-2520.0f)); |
| } |
| |
| // Check if the matrix 'transpose' operation on 3x3 matrix is constant folded. |
| // All the matrices including matrices in the shader code are in column-major order. |
| TEST_F(ConstantFoldingTest, Fold3x3MatrixTranspose) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "in float i;\n" |
| "out vec3 my_Vec;\n" |
| "void main() {\n" |
| " const mat3 m3 = transpose(mat3(11.0f, 13.0f, 19.0f,\n" |
| " 23.0f, 29.0f, 31.0f,\n" |
| " 37.0f, 41.0f, 43.0f));\n" |
| " mat3 m = m3 * mat3(i);\n" |
| " my_Vec = m[0];\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float inputElements[] = |
| { |
| 11.0f, 13.0f, 19.0f, |
| 23.0f, 29.0f, 31.0f, |
| 37.0f, 41.0f, 43.0f |
| }; |
| std::vector<float> input(inputElements, inputElements + 9); |
| ASSERT_FALSE(constantColumnMajorMatrixFoundInAST(input)); |
| float outputElements[] = |
| { |
| 11.0f, 23.0f, 37.0f, |
| 13.0f, 29.0f, 41.0f, |
| 19.0f, 31.0f, 43.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 9); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that 0xFFFFFFFF wraps to -1 when parsed as integer. |
| // 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_F(ConstantFoldingTest, ParseWrappedHexIntLiteral) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "precision highp int;\n" |
| "uniform int inInt;\n" |
| "out vec4 my_Vec;\n" |
| "void main() {\n" |
| " const int i = 0xFFFFFFFF;\n" |
| " my_Vec = vec4(i * inInt);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(-1)); |
| } |
| |
| // Test that 3000000000 wraps to -1294967296 when parsed as integer. |
| // This is featured in the examples of GLSL 4.5, and ESSL behavior should match |
| // desktop GLSL when it comes to integer parsing. |
| TEST_F(ConstantFoldingTest, ParseWrappedDecimalIntLiteral) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "precision highp int;\n" |
| "uniform int inInt;\n" |
| "out vec4 my_Vec;\n" |
| "void main() {\n" |
| " const int i = 3000000000;\n" |
| " my_Vec = vec4(i * inInt);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(-1294967296)); |
| } |
| |
| // Test that 0xFFFFFFFFu is parsed correctly as an unsigned integer literal. |
| // 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_F(ConstantFoldingTest, ParseMaxUintLiteral) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "precision highp int;\n" |
| "uniform uint inInt;\n" |
| "out vec4 my_Vec;\n" |
| "void main() {\n" |
| " const uint i = 0xFFFFFFFFu;\n" |
| " my_Vec = vec4(i * inInt);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu)); |
| } |
| |
| // Test that unary minus applied to unsigned int is constant folded correctly. |
| // 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_F(ConstantFoldingTest, FoldUnaryMinusOnUintLiteral) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "precision highp int;\n" |
| "uniform uint inInt;\n" |
| "out vec4 my_Vec;\n" |
| "void main() {\n" |
| " const uint i = -1u;\n" |
| " my_Vec = vec4(i * inInt);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0xFFFFFFFFu)); |
| } |
| |
| // Test that constant mat2 initialization with a mat2 parameter works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMat2) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "void main() {\n" |
| " const mat2 cm = mat2(mat2(0.0, 1.0, 2.0, 3.0));\n" |
| " mat2 m = cm * mult;\n" |
| " gl_FragColor = vec4(m[0], m[1]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| 0.0f, 1.0f, |
| 2.0f, 3.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that constant mat2 initialization with an int parameter works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingScalar) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "void main() {\n" |
| " const mat2 cm = mat2(3);\n" |
| " mat2 m = cm * mult;\n" |
| " gl_FragColor = vec4(m[0], m[1]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| 3.0f, 0.0f, |
| 0.0f, 3.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that constant mat2 initialization with a mix of parameters works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMix) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "void main() {\n" |
| " const mat2 cm = mat2(-1, vec2(0.0, 1.0), vec4(2.0));\n" |
| " mat2 m = cm * mult;\n" |
| " gl_FragColor = vec4(m[0], m[1]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| -1.0, 0.0f, |
| 1.0f, 2.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that constant mat2 initialization with a mat3 parameter works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingMat3) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "void main() {\n" |
| " const mat2 cm = mat2(mat3(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0));\n" |
| " mat2 m = cm * mult;\n" |
| " gl_FragColor = vec4(m[0], m[1]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| 0.0f, 1.0f, |
| 3.0f, 4.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that constant mat4x3 initialization with a mat3x2 parameter works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat4x3ConstructorTakingMat3x2) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "out vec4 my_FragColor;\n" |
| "void main() {\n" |
| " const mat4x3 cm = mat4x3(mat3x2(1.0, 2.0,\n" |
| " 3.0, 4.0,\n" |
| " 5.0, 6.0));\n" |
| " mat4x3 m = cm * mult;\n" |
| " my_FragColor = vec4(m[0], m[1][0]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| 1.0f, 2.0f, 0.0f, |
| 3.0f, 4.0f, 0.0f, |
| 5.0f, 6.0f, 1.0f, |
| 0.0f, 0.0f, 0.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 12); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| |
| // Test that constant mat2 initialization with a vec4 parameter works correctly. |
| TEST_F(ConstantFoldingTest, FoldMat2ConstructorTakingVec4) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "uniform float mult;\n" |
| "void main() {\n" |
| " const mat2 cm = mat2(vec4(0.0, 1.0, 2.0, 3.0));\n" |
| " mat2 m = cm * mult;\n" |
| " gl_FragColor = vec4(m[0], m[1]);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = |
| { |
| 0.0f, 1.0f, |
| 2.0f, 3.0f |
| }; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that equality comparison of two different structs with a nested struct inside returns false. |
| TEST_F(ConstantFoldingTest, FoldNestedDifferentStructEqualityComparison) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "struct nested {\n" |
| " float f\n;" |
| "};\n" |
| "struct S {\n" |
| " nested a;\n" |
| " float f;\n" |
| "};\n" |
| "uniform vec4 mult;\n" |
| "void main()\n" |
| "{\n" |
| " const S s1 = S(nested(0.0), 2.0);\n" |
| " const S s2 = S(nested(0.0), 3.0);\n" |
| " gl_FragColor = (s1 == s2 ? 1.0 : 0.5) * mult;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0.5f)); |
| } |
| |
| // Test that equality comparison of two identical structs with a nested struct inside returns true. |
| TEST_F(ConstantFoldingTest, FoldNestedIdenticalStructEqualityComparison) |
| { |
| const std::string &shaderString = |
| "precision mediump float;\n" |
| "struct nested {\n" |
| " float f\n;" |
| "};\n" |
| "struct S {\n" |
| " nested a;\n" |
| " float f;\n" |
| " int i;\n" |
| "};\n" |
| "uniform vec4 mult;\n" |
| "void main()\n" |
| "{\n" |
| " const S s1 = S(nested(0.0), 2.0, 3);\n" |
| " const S s2 = S(nested(0.0), 2.0, 3);\n" |
| " gl_FragColor = (s1 == s2 ? 1.0 : 0.5) * mult;\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(1.0f)); |
| } |
| |
| // Test that right elements are chosen from non-square matrix |
| TEST_F(ConstantFoldingTest, FoldNonSquareMatrixIndexing) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " my_FragColor = mat3x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)[1];\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| float outputElements[] = {4.0f, 5.0f, 6.0f, 7.0f}; |
| std::vector<float> result(outputElements, outputElements + 4); |
| ASSERT_TRUE(constantVectorFoundInAST(result)); |
| } |
| |
| // Test that folding outer product of vectors with non-matching lengths works. |
| TEST_F(ConstantFoldingTest, FoldNonSquareOuterProduct) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " mat3x2 prod = outerProduct(vec2(2.0, 3.0), vec3(5.0, 7.0, 11.0));\n" |
| " my_FragColor = vec4(prod[0].x);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| // clang-format off |
| float outputElements[] = |
| { |
| 10.0f, 15.0f, |
| 14.0f, 21.0f, |
| 22.0f, 33.0f |
| }; |
| // clang-format on |
| std::vector<float> result(outputElements, outputElements + 6); |
| ASSERT_TRUE(constantColumnMajorMatrixFoundInAST(result)); |
| } |
| |
| // Test that folding bit shift left with non-matching signedness works. |
| TEST_F(ConstantFoldingTest, FoldBitShiftLeftDifferentSignedness) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " uint u = 0xffffffffu << 31;\n" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0x80000000u)); |
| } |
| |
| // Test that folding bit shift right with non-matching signedness works. |
| TEST_F(ConstantFoldingTest, FoldBitShiftRightDifferentSignedness) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " uint u = 0xffffffffu >> 30;\n" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0x3u)); |
| } |
| |
| // Test that folding signed bit shift right extends the sign bit. |
| // ESSL 3.00.6 section 5.9 Expressions. |
| TEST_F(ConstantFoldingTest, FoldBitShiftRightExtendSignBit) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " const int i = 0x8fffe000 >> 6;\n" |
| " uint u = uint(i);" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| // The bits of the operand are 0x8fffe000 = 1000 1111 1111 1111 1110 0000 0000 0000 |
| // After shifting, they become 1111 1110 0011 1111 1111 1111 1000 0000 = 0xfe3fff80 |
| ASSERT_TRUE(constantFoundInAST(0xfe3fff80u)); |
| } |
| |
| // Signed bit shift left should interpret its operand as a bit pattern. As a consequence a number |
| // may turn from positive to negative when shifted left. |
| // ESSL 3.00.6 section 5.9 Expressions. |
| TEST_F(ConstantFoldingTest, FoldBitShiftLeftInterpretedAsBitPattern) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " const int i = 0x1fffffff << 3;\n" |
| " uint u = uint(i);" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0xfffffff8u)); |
| } |
| |
| // Test that dividing the minimum signed integer by -1 works. |
| // 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." |
| TEST_F(ConstantFoldingTest, FoldDivideMinimumIntegerByMinusOne) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = 0x80000000 / (-1);\n" |
| " my_FragColor = vec4(i);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0x7fffffff) || constantFoundInAST(-0x7fffffff - 1)); |
| } |
| |
| // Test that folding an unsigned integer addition that overflows works. |
| // 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, FoldUnsignedIntegerAddOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " uint u = 0xffffffffu + 43u;\n" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(42u)); |
| } |
| |
| // Test that folding a signed integer addition that overflows works. |
| // 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, FoldSignedIntegerAddOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = 0x7fffffff + 4;\n" |
| " my_FragColor = vec4(i);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(-0x7ffffffd)); |
| } |
| |
| // Test that folding an unsigned integer subtraction that overflows works. |
| // 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, FoldUnsignedIntegerDiffOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " uint u = 0u - 5u;\n" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0xfffffffbu)); |
| } |
| |
| // Test that folding a signed integer subtraction that overflows works. |
| // 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, FoldSignedIntegerDiffOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = -0x7fffffff - 7;\n" |
| " my_FragColor = vec4(i);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0x7ffffffa)); |
| } |
| |
| // Test that folding an unsigned integer multiplication that overflows works. |
| // 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, FoldUnsignedIntegerMultiplyOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " uint u = 0xffffffffu * 10u;\n" |
| " my_FragColor = vec4(u);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(0xfffffff6u)); |
| } |
| |
| // Test that folding a signed integer multiplication that overflows works. |
| // 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, FoldSignedIntegerMultiplyOverflow) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = 0x7fffffff * 42;\n" |
| " my_FragColor = vec4(i);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| 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"; |
| compileAssumeSuccess(shaderString); |
| // Negating the minimum signed integer overflows the positive range, so it wraps back to itself. |
| ASSERT_TRUE(constantFoundInAST(-0x7fffffff - 1)); |
| } |
| |
| // Test that folding of shifting the minimum representable integer works. |
| TEST_F(ConstantFoldingTest, FoldMinimumSignedIntegerRightShift) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = (0x80000000 >> 1);\n" |
| " int j = (0x80000000 >> 7);\n" |
| " my_FragColor = vec4(i, j, i, j);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(-0x40000000)); |
| ASSERT_TRUE(constantFoundInAST(-0x01000000)); |
| } |
| |
| // Test that folding of shifting by 0 works. |
| TEST_F(ConstantFoldingTest, FoldShiftByZero) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " int i = (3 >> 0);\n" |
| " int j = (73 << 0);\n" |
| " my_FragColor = vec4(i, j, i, j);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(3)); |
| ASSERT_TRUE(constantFoundInAST(73)); |
| } |
| |
| // Test that folding IsInf results in true when the parameter is an out-of-range float literal. |
| // 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_F(ConstantFoldingTest, FoldIsInfOutOfRangeFloatLiteral) |
| { |
| const std::string &shaderString = |
| "#version 300 es\n" |
| "precision mediump float;\n" |
| "out vec4 my_FragColor;\n" |
| "void main()\n" |
| "{\n" |
| " bool b = isinf(1.0e2048);\n" |
| " my_FragColor = vec4(b);\n" |
| "}\n"; |
| compileAssumeSuccess(shaderString); |
| ASSERT_TRUE(constantFoundInAST(true)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldTooSmallFloat) |
| { |
| const std::string &floatString = "1.0e-2048"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldRadiansInfinity) |
| { |
| const std::string &floatString = "radians(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldDegreesInfinity) |
| { |
| const std::string &floatString = "degrees(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldSinhInfinity) |
| { |
| const std::string &floatString = "sinh(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldSinhNegativeInfinity) |
| { |
| const std::string &floatString = "sinh(-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldCoshInfinity) |
| { |
| const std::string &floatString = "cosh(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldCoshNegativeInfinity) |
| { |
| const std::string &floatString = "cosh(-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldAsinhInfinity) |
| { |
| const std::string &floatString = "asinh(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldAsinhNegativeInfinity) |
| { |
| const std::string &floatString = "asinh(-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldAcoshInfinity) |
| { |
| const std::string &floatString = "acosh(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldPowInfinity) |
| { |
| const std::string &floatString = "pow(0.0, 1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldExpInfinity) |
| { |
| const std::string &floatString = "exp(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldExpNegativeInfinity) |
| { |
| const std::string &floatString = "exp(-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldLogInfinity) |
| { |
| const std::string &floatString = "log(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldExp2Infinity) |
| { |
| const std::string &floatString = "exp2(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldExp2NegativeInfinity) |
| { |
| const std::string &floatString = "exp2(-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldLog2Infinity) |
| { |
| const std::string &floatString = "log2(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldSqrtInfinity) |
| { |
| const std::string &floatString = "sqrt(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInversesqrtInfinity) |
| { |
| const std::string &floatString = "inversesqrt(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldLengthInfinity) |
| { |
| const std::string &floatString = "length(1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldDotInfinity) |
| { |
| const std::string &floatString = "dot(1.0e2048, 1.0)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldDotInfinity2) |
| { |
| const std::string &floatString = "dot(vec2(1.0e2048, -1.0), vec2(1.0))"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldFaceForwardInfinity) |
| { |
| const std::string &floatString = "faceforward(4.0, 1.0e2048, 1.0)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-4.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldFaceForwardInfinity2) |
| { |
| const std::string &floatString = "faceforward(vec2(4.0), vec2(1.0e2048, -1.0), vec2(1.0)).x"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-4.0f)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInfinityMinusFinite) |
| { |
| const std::string &floatString = "1.0e2048 - 1.0e20"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldMinusInfinityPlusFinite) |
| { |
| const std::string &floatString = "(-1.0e2048) + 1.0e20"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByFinite) |
| { |
| const std::string &floatString = "1.0e2048 * 1.0e-20"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByInfinity) |
| { |
| const std::string &floatString = "1.0e2048 * 1.0e2048"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInfinityMultipliedByNegativeInfinity) |
| { |
| const std::string &floatString = "1.0e2048 * (-1.0e2048)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldDivideByNegativeZero) |
| { |
| const std::string &floatString = "1.0 / (-0.0)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| ASSERT_TRUE(hasWarning()); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldInfinityDividedByZero) |
| { |
| const std::string &floatString = "1.0e2048 / 0.0"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(std::numeric_limits<float>::infinity())); |
| ASSERT_TRUE(hasWarning()); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldMinusInfinityDividedByZero) |
| { |
| const std::string &floatString = "(-1.0e2048) / 0.0"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-std::numeric_limits<float>::infinity())); |
| ASSERT_TRUE(hasWarning()); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldDivideByInfinity) |
| { |
| const std::string &floatString = "1.0e30 / 1.0e2048"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(0.0f)); |
| } |
| |
| // Test that unsigned bitfieldExtract is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldUnsignedBitfieldExtract) |
| { |
| const std::string &uintString = "bitfieldExtract(0x00110000u, 16, 5)"; |
| evaluateUint(uintString); |
| ASSERT_TRUE(constantFoundInAST(0x11u)); |
| } |
| |
| // Test that unsigned bitfieldExtract to extract 32 bits is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldUnsignedBitfieldExtract32Bits) |
| { |
| const std::string &uintString = "bitfieldExtract(0xff0000ffu, 0, 32)"; |
| evaluateUint(uintString); |
| ASSERT_TRUE(constantFoundInAST(0xff0000ffu)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldSignedBitfieldExtract) |
| { |
| const std::string &intString = "bitfieldExtract(0x00110000, 16, 5)"; |
| evaluateInt(intString); |
| // 0xfffffff1 == -15 |
| ASSERT_TRUE(constantFoundInAST(-15)); |
| } |
| |
| // Test that bitfieldInsert is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldBitfieldInsert) |
| { |
| const std::string &uintString = "bitfieldInsert(0x04501701u, 0x11u, 8, 5)"; |
| evaluateUint(uintString); |
| ASSERT_TRUE(constantFoundInAST(0x04501101u)); |
| } |
| |
| // Test that bitfieldInsert to insert 32 bits is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldBitfieldInsert32Bits) |
| { |
| const std::string &uintString = "bitfieldInsert(0xff0000ffu, 0x11u, 0, 32)"; |
| evaluateUint(uintString); |
| ASSERT_TRUE(constantFoundInAST(0x11u)); |
| } |
| |
| // Test that bitfieldReverse is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldBitfieldReverse) |
| { |
| const std::string &uintString = "bitfieldReverse((1u << 4u) | (1u << 7u))"; |
| evaluateUint(uintString); |
| uint32_t flag1 = 1u << (31u - 4u); |
| uint32_t flag2 = 1u << (31u - 7u); |
| ASSERT_TRUE(constantFoundInAST(flag1 | flag2)); |
| } |
| |
| // Test that bitCount is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldBitCount) |
| { |
| const std::string &intString = "bitCount(0x17103121u)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(10)); |
| } |
| |
| // Test that findLSB is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldFindLSB) |
| { |
| const std::string &intString = "findLSB(0x80010000u)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(16)); |
| } |
| |
| // Test that findLSB is folded correctly when the operand is zero. |
| TEST_F(ConstantFoldingExpressionTest, FoldFindLSBZero) |
| { |
| const std::string &intString = "findLSB(0u)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(-1)); |
| } |
| |
| // Test that findMSB is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldFindMSB) |
| { |
| const std::string &intString = "findMSB(0x01000008u)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(24)); |
| } |
| |
| // Test that findMSB is folded correctly when the operand is zero. |
| TEST_F(ConstantFoldingExpressionTest, FoldFindMSBZero) |
| { |
| const std::string &intString = "findMSB(0u)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(-1)); |
| } |
| |
| // 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_F(ConstantFoldingExpressionTest, FoldFindMSBNegativeInt) |
| { |
| const std::string &intString = "findMSB(-8)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(2)); |
| } |
| |
| // Test that findMSB is folded correctly for -1. |
| TEST_F(ConstantFoldingExpressionTest, FoldFindMSBMinusOne) |
| { |
| const std::string &intString = "findMSB(-1)"; |
| evaluateInt(intString); |
| ASSERT_TRUE(constantFoundInAST(-1)); |
| } |
| |
| // Test that packUnorm4x8 is folded correctly for a vector of zeroes. |
| TEST_F(ConstantFoldingExpressionTest, FoldPackUnorm4x8Zero) |
| { |
| const std::string &intString = "packUnorm4x8(vec4(0.0))"; |
| evaluateUint(intString); |
| ASSERT_TRUE(constantFoundInAST(0u)); |
| } |
| |
| // Test that packUnorm4x8 is folded correctly for a vector of ones. |
| TEST_F(ConstantFoldingExpressionTest, FoldPackUnorm4x8One) |
| { |
| const std::string &intString = "packUnorm4x8(vec4(1.0))"; |
| evaluateUint(intString); |
| ASSERT_TRUE(constantFoundInAST(0xffffffffu)); |
| } |
| |
| // Test that packSnorm4x8 is folded correctly for a vector of zeroes. |
| TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8Zero) |
| { |
| const std::string &intString = "packSnorm4x8(vec4(0.0))"; |
| evaluateUint(intString); |
| ASSERT_TRUE(constantFoundInAST(0u)); |
| } |
| |
| // Test that packSnorm4x8 is folded correctly for a vector of ones. |
| TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8One) |
| { |
| const std::string &intString = "packSnorm4x8(vec4(1.0))"; |
| evaluateUint(intString); |
| ASSERT_TRUE(constantFoundInAST(0x7f7f7f7fu)); |
| } |
| |
| // Test that packSnorm4x8 is folded correctly for a vector of minus ones. |
| TEST_F(ConstantFoldingExpressionTest, FoldPackSnorm4x8MinusOne) |
| { |
| const std::string &intString = "packSnorm4x8(vec4(-1.0))"; |
| evaluateUint(intString); |
| ASSERT_TRUE(constantFoundInAST(0x81818181u)); |
| } |
| |
| // Test that unpackSnorm4x8 is folded correctly when it needs to clamp the result. |
| TEST_F(ConstantFoldingExpressionTest, FoldUnpackSnorm4x8Clamp) |
| { |
| const std::string &floatString = "unpackSnorm4x8(0x00000080u).x"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(-1.0f)); |
| } |
| |
| // Test that unpackUnorm4x8 is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldUnpackUnorm4x8) |
| { |
| const std::string &floatString = "unpackUnorm4x8(0x007bbeefu).z"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(123.0f / 255.0f)); |
| } |
| |
| // Test that ldexp is folded correctly. |
| TEST_F(ConstantFoldingExpressionTest, FoldLdexp) |
| { |
| const std::string &floatString = "ldexp(0.625, 1)"; |
| evaluateFloat(floatString); |
| ASSERT_TRUE(constantFoundInAST(1.25f)); |
| } |