| // | |
| // Copyright 2016 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. | |
| // | |
| // ConstantFoldingTest.h: | |
| // Utilities for constant folding tests. | |
| // | |
| #ifndef TESTS_TEST_UTILS_CONSTANTFOLDINGTEST_H_ | |
| #define TESTS_TEST_UTILS_CONSTANTFOLDINGTEST_H_ | |
| #include <vector> | |
| #include "common/mathutil.h" | |
| #include "compiler/translator/tree_util/FindMain.h" | |
| #include "compiler/translator/tree_util/FindSymbolNode.h" | |
| #include "compiler/translator/tree_util/IntermTraverse.h" | |
| #include "tests/test_utils/ShaderCompileTreeTest.h" | |
| namespace sh | |
| { | |
| class TranslatorESSL; | |
| template <typename T> | |
| class ConstantFinder : public TIntermTraverser | |
| { | |
| public: | |
| ConstantFinder(const std::vector<T> &constantVector) | |
| : TIntermTraverser(true, false, false), | |
| mConstantVector(constantVector), | |
| mFaultTolerance(T()), | |
| mFound(false) | |
| {} | |
| ConstantFinder(const std::vector<T> &constantVector, const T &faultTolerance) | |
| : TIntermTraverser(true, false, false), | |
| mConstantVector(constantVector), | |
| mFaultTolerance(faultTolerance), | |
| mFound(false) | |
| {} | |
| ConstantFinder(const T &value) | |
| : TIntermTraverser(true, false, false), mFaultTolerance(T()), 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 (!isEqual(node->getConstantValue()[i], mConstantVector[i])) | |
| { | |
| found = false; | |
| break; | |
| } | |
| } | |
| if (found) | |
| { | |
| mFound = found; | |
| } | |
| } | |
| } | |
| bool found() const { return mFound; } | |
| private: | |
| bool isEqual(const TConstantUnion &node, const float &value) const | |
| { | |
| if (node.getType() != EbtFloat) | |
| { | |
| return false; | |
| } | |
| if (value == std::numeric_limits<float>::infinity()) | |
| { | |
| return gl::isInf(node.getFConst()) && node.getFConst() > 0; | |
| } | |
| else if (value == -std::numeric_limits<float>::infinity()) | |
| { | |
| return gl::isInf(node.getFConst()) && node.getFConst() < 0; | |
| } | |
| else if (gl::isNaN(value)) | |
| { | |
| // All NaNs are treated as equal. | |
| return gl::isNaN(node.getFConst()); | |
| } | |
| return mFaultTolerance >= fabsf(node.getFConst() - value); | |
| } | |
| bool isEqual(const TConstantUnion &node, const int &value) const | |
| { | |
| if (node.getType() != EbtInt) | |
| { | |
| return false; | |
| } | |
| ASSERT(mFaultTolerance < std::numeric_limits<int>::max()); | |
| // abs() returns 0 at least on some platforms when the minimum int value is passed in (it | |
| // doesn't have a positive counterpart). | |
| return mFaultTolerance >= abs(node.getIConst() - value) && | |
| (node.getIConst() - value) != std::numeric_limits<int>::min(); | |
| } | |
| bool isEqual(const TConstantUnion &node, const unsigned int &value) const | |
| { | |
| if (node.getType() != EbtUInt) | |
| { | |
| return false; | |
| } | |
| ASSERT(mFaultTolerance < static_cast<unsigned int>(std::numeric_limits<int>::max())); | |
| return static_cast<int>(mFaultTolerance) >= | |
| abs(static_cast<int>(node.getUConst() - value)) && | |
| static_cast<int>(node.getUConst() - value) != std::numeric_limits<int>::min(); | |
| } | |
| bool isEqual(const TConstantUnion &node, const bool &value) const | |
| { | |
| if (node.getType() != EbtBool) | |
| { | |
| return false; | |
| } | |
| return node.getBConst() == value; | |
| } | |
| std::vector<T> mConstantVector; | |
| T mFaultTolerance; | |
| bool mFound; | |
| }; | |
| class ConstantFoldingTest : public ShaderCompileTreeTest | |
| { | |
| public: | |
| ConstantFoldingTest() {} | |
| protected: | |
| ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; } | |
| ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; } | |
| 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(); | |
| } | |
| template <typename T> | |
| bool constantColumnMajorMatrixFoundInAST(const std::vector<T> &constantMatrix) | |
| { | |
| return constantVectorFoundInAST(constantMatrix); | |
| } | |
| template <typename T> | |
| bool constantVectorNearFoundInAST(const std::vector<T> &constantVector, const T &faultTolerance) | |
| { | |
| ConstantFinder<T> finder(constantVector, faultTolerance); | |
| mASTRoot->traverse(&finder); | |
| return finder.found(); | |
| } | |
| bool symbolFoundInAST(const char *symbolName) | |
| { | |
| return FindSymbolNode(mASTRoot, ImmutableString(symbolName)) != nullptr; | |
| } | |
| bool symbolFoundInMain(const char *symbolName) | |
| { | |
| return FindSymbolNode(FindMain(mASTRoot), ImmutableString(symbolName)) != nullptr; | |
| } | |
| }; | |
| class ConstantFoldingExpressionTest : public ConstantFoldingTest | |
| { | |
| public: | |
| ConstantFoldingExpressionTest() {} | |
| void evaluateFloat(const std::string &floatExpression); | |
| void evaluateInt(const std::string &intExpression); | |
| void evaluateUint(const std::string &uintExpression); | |
| }; | |
| } // namespace sh | |
| #endif // TESTS_TEST_UTILS_CONSTANTFOLDINGTEST_H_ |