| // |
| // 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 <vector> |
| |
| #include "angle_gl.h" |
| #include "gtest/gtest.h" |
| #include "GLSLANG/ShaderLang.h" |
| #include "compiler/translator/PoolAlloc.h" |
| #include "compiler/translator/TranslatorESSL.h" |
| |
| template <typename T> |
| class ConstantFinder : public TIntermTraverser |
| { |
| public: |
| ConstantFinder(const std::vector<T> &constantVector) |
| : mConstantVector(constantVector), |
| mFound(false) |
| {} |
| |
| ConstantFinder(const T &value) |
| : mFound(false) |
| { |
| mConstantVector.push_back(value); |
| } |
| |
| void visitConstantUnion(TIntermConstantUnion *node) |
| { |
| if (node->getType().getObjectSize() == mConstantVector.size()) |
| { |
| bool found = true; |
| for (size_t i = 0; i < mConstantVector.size(); i++) |
| { |
| if (node->getUnionArrayPointer()[i] != mConstantVector[i]) |
| { |
| found = false; |
| break; |
| } |
| } |
| if (found) |
| { |
| mFound = found; |
| } |
| } |
| } |
| |
| bool found() const { return mFound; } |
| |
| private: |
| std::vector<T> mConstantVector; |
| bool mFound; |
| }; |
| |
| class ConstantFoldingTest : public testing::Test |
| { |
| public: |
| ConstantFoldingTest() {} |
| |
| protected: |
| virtual void SetUp() |
| { |
| allocator.push(); |
| SetGlobalPoolAllocator(&allocator); |
| ShBuiltInResources resources; |
| ShInitBuiltInResources(&resources); |
| |
| mTranslatorESSL = new TranslatorESSL(GL_FRAGMENT_SHADER, SH_GLES3_SPEC); |
| ASSERT_TRUE(mTranslatorESSL->Init(resources)); |
| } |
| |
| virtual void TearDown() |
| { |
| delete mTranslatorESSL; |
| SetGlobalPoolAllocator(NULL); |
| allocator.pop(); |
| } |
| |
| void compile(const std::string& shaderString) |
| { |
| const char *shaderStrings[] = { shaderString.c_str() }; |
| |
| mASTRoot = mTranslatorESSL->compileTreeForTesting(shaderStrings, 1, SH_OBJECT_CODE); |
| if (!mASTRoot) |
| { |
| TInfoSink &infoSink = mTranslatorESSL->getInfoSink(); |
| FAIL() << "Shader compilation into ESSL failed " << infoSink.info.c_str(); |
| } |
| } |
| |
| template <typename T> |
| bool constantFoundInAST(T constant) |
| { |
| ConstantFinder<T> finder(constant); |
| mASTRoot->traverse(&finder); |
| return finder.found(); |
| } |
| |
| template <typename T> |
| bool constantVectorFoundInAST(const std::vector<T> &constantVector) |
| { |
| ConstantFinder<T> finder(constantVector); |
| mASTRoot->traverse(&finder); |
| return finder.found(); |
| } |
| |
| private: |
| TranslatorESSL *mTranslatorESSL; |
| TIntermNode *mASTRoot; |
| |
| TPoolAllocator allocator; |
| }; |
| |
| 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"; |
| compile(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"; |
| compile(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"; |
| compile(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"; |
| compile(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"; |
| compile(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"; |
| compile(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)); |
| } |