Edit

kc3-lang/angle/src/tests/compiler_tests/RemoveUnreferencedVariables_test.cpp

Branch :

  • Show log

    Commit

  • Author : Stuart Morgan
    Date : 2019-08-14 12:25:12
    Hash : 9d737966
    Message : Standardize copyright notices to project style For all "ANGLE Project" copyrights, standardize to the format specified by the style guide. Changes: - "Copyright (c)" and "Copyright(c)" changed to just "Copyright". - Removed the second half of date ranges ("Y1Y1-Y2Y2"->"Y1Y1"). - Fixed a small number of files that had no copyright date using the initial commit year from the version control history. - Fixed one instance of copyright being "The ANGLE Project" rather than "The ANGLE Project Authors" These changes are applied both to the copyright of source file, and where applicable to copyright statements that are generated by templates. BUG=angleproject:3811 Change-Id: I973dd65e4ef9deeba232d5be74c768256a0eb2e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1754397 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/compiler_tests/RemoveUnreferencedVariables_test.cpp
  • //
    // Copyright 2017 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.
    //
    // RemoveUnreferencedVariables_test.cpp:
    //   Tests for removing unreferenced variables from the AST.
    //
    
    #include "GLSLANG/ShaderLang.h"
    #include "angle_gl.h"
    #include "gtest/gtest.h"
    #include "tests/test_utils/compiler_test.h"
    
    using namespace sh;
    
    class RemoveUnreferencedVariablesTest : public MatchOutputCodeTest
    {
      public:
        RemoveUnreferencedVariablesTest() : MatchOutputCodeTest(GL_FRAGMENT_SHADER, 0, SH_ESSL_OUTPUT)
        {}
    };
    
    // Test that a simple unreferenced declaration is pruned.
    TEST_F(RemoveUnreferencedVariablesTest, SimpleDeclaration)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            void main()
            {
                vec4 myUnreferencedVec;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec"));
    }
    
    // Test that a simple unreferenced global declaration is pruned.
    TEST_F(RemoveUnreferencedVariablesTest, SimpleGlobalDeclaration)
    {
        const std::string &shaderString =
            R"(precision mediump float;
    
            vec4 myUnreferencedVec;
    
            void main()
            {
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec"));
    }
    
    // Test that a simple unreferenced variable with an initializer is pruned.
    TEST_F(RemoveUnreferencedVariablesTest, SimpleInitializer)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myUnreferencedVec = uVec;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec"));
    }
    
    // Test that a user-defined function call inside an unreferenced variable initializer is retained.
    TEST_F(RemoveUnreferencedVariablesTest, SideEffectInInitializer)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            vec4 sideEffect(int i)
            {
                gl_FragColor = vec4(0, i, 0, 1);
                return vec4(0);
            }
            void main()
            {
                vec4 myUnreferencedVec = sideEffect(1);
            })";
        compile(shaderString);
    
        // We're happy as long as the function with side effects is called.
        ASSERT_TRUE(foundInCode("sideEffect(1)"));
    }
    
    // Test that a modf call inside an unreferenced variable initializer is retained.
    TEST_F(RemoveUnreferencedVariablesTest, BuiltInSideEffectInInitializer)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision mediump float;
            uniform float uF;
            out vec4 my_FragColor;
    
            void main()
            {
                float iPart = 0.0;
                float myUnreferencedFloat = modf(uF, iPart);
                my_FragColor = vec4(0.0, iPart, 0.0, 1.0);
            })";
        compile(shaderString);
    
        // We're happy as long as the function with side effects is called.
        ASSERT_TRUE(foundInCode("modf("));
    }
    
    // Test that an imageStore call inside an unreferenced variable initializer is retained.
    TEST_F(RemoveUnreferencedVariablesTest, ImageStoreSideEffectInInitializer)
    {
        const std::string &shaderString =
            R"(#version 310 es
            precision highp float;
            layout(rgba32i) uniform highp writeonly iimage2D img;
    
            void main()
            {
                float myUnreferencedFloat = (imageStore(img, ivec2(0), ivec4(1)), 1.0);
            })";
        compile(shaderString);
    
        // We're happy as long as the function with side effects is called.
        ASSERT_TRUE(foundInCode("imageStore("));
    }
    
    // Test that multiple variables that are chained but otherwise are unreferenced are removed.
    TEST_F(RemoveUnreferencedVariablesTest, MultipleVariablesChained)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myUnreferencedVec1 = uVec;
                vec4 myUnreferencedVec2 = myUnreferencedVec1 * 2.0;
                vec4 myUnreferencedVec3 = myUnreferencedVec2 + 1.0;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec3"));
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec2"));
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec1"));
    }
    
    // Test that multiple variables that are chained with the last one being referenced are kept.
    TEST_F(RemoveUnreferencedVariablesTest, MultipleVariablesChainedReferenced)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myReferencedVec1 = uVec;
                vec4 myReferencedVec2 = myReferencedVec1 * 2.0;
                vec4 myReferencedVec3 = myReferencedVec2 + 1.0;
                gl_FragColor = myReferencedVec3;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("myReferencedVec3"));
        ASSERT_TRUE(foundInCode("myReferencedVec2"));
        ASSERT_TRUE(foundInCode("myReferencedVec1"));
    }
    
    // Test that multiple variables that are chained within two scopes but otherwise are unreferenced
    // are removed.
    TEST_F(RemoveUnreferencedVariablesTest, MultipleVariablesChainedTwoScopes)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myUnreferencedVec1 = uVec;
                vec4 myUnreferencedVec2 = myUnreferencedVec1 * 2.0;
                if (uVec.x > 0.0)
                {
                    vec4 myUnreferencedVec3 = myUnreferencedVec2 + 1.0;
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec3"));
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec2"));
        ASSERT_TRUE(notFoundInCode("myUnreferencedVec1"));
    }
    
    // Test that multiple variables that are chained with the last one being referenced in an inner
    // scope are kept.
    TEST_F(RemoveUnreferencedVariablesTest, VariableReferencedInAnotherScope)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myReferencedVec1 = uVec;
                vec4 myReferencedVec2 = myReferencedVec1 * 2.0;
                if (uVec.x > 0.0)
                {
                    vec4 myReferencedVec3 = myReferencedVec2 + 1.0;
                    gl_FragColor = myReferencedVec3;
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("myReferencedVec3"));
        ASSERT_TRUE(foundInCode("myReferencedVec2"));
        ASSERT_TRUE(foundInCode("myReferencedVec1"));
    }
    
    // Test that if there are two variables with the same name, one of them can be removed and another
    // one kept.
    TEST_F(RemoveUnreferencedVariablesTest, TwoVariablesWithSameNameInDifferentScopes)
    {
        const std::string &shaderString =
            R"(precision mediump float;
            uniform vec4 uVec;
            void main()
            {
                vec4 myVec = uVec;  // This one is unreferenced.
                if (uVec.x > 0.0)
                {
                    vec4 myVec = uVec * 2.0;  // This one is referenced.
                    gl_FragColor = myVec;
                }
                vec4 myUnreferencedVec = myVec;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("myVec", 2));
    }
    
    // Test that an unreferenced variable declared in a for loop header is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UnreferencedVariableDeclaredInForLoopHeader)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
            uniform int ui;
    
            out vec4 my_FragColor;
    
            void main()
            {
                my_FragColor = vec4(0.0);
                int index = 0;
                for (int unreferencedInt = ui; index < 10; ++index)
                {
                    my_FragColor += vec4(0.0, float(index) * 0.01, 0.0, 0.0);
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("index"));
        ASSERT_TRUE(notFoundInCode("unreferencedInt"));
    }
    
    // Test that a loop condition is kept even if it declares an unreferenced variable.
    TEST_F(RemoveUnreferencedVariablesTest, UnreferencedVariableDeclaredInWhileLoopCondition)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
            uniform int ui;
    
            out vec4 my_FragColor;
    
            void main()
            {
                my_FragColor = vec4(0.0);
                int index = 0;
                while (bool b = (index < 10))
                {
                    my_FragColor += vec4(0.0, float(index) * 0.01, 0.0, 0.0);
                    ++index;
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("index < 10"));
    }
    
    // Test that a variable declared in a for loop header that is only referenced in an unreferenced
    // variable initializer is removed.
    TEST_F(RemoveUnreferencedVariablesTest,
           VariableDeclaredInForLoopHeaderAccessedInUnreferencedVariableInitializer)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
            uniform int ui;
    
            out vec4 my_FragColor;
    
            void main()
            {
                my_FragColor = vec4(0.0);
                int index = 0;
                for (int unreferencedInt1 = ui; index < 10; ++index)
                {
                    int unreferencedInt2 = unreferencedInt1;
                    my_FragColor += vec4(0.0, float(index) * 0.01, 0.0, 0.0);
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("index"));
        ASSERT_TRUE(notFoundInCode("unreferencedInt2"));
        ASSERT_TRUE(notFoundInCode("unreferencedInt1"));
    }
    
    // Test that a user-defined type (struct) declaration that's used is not removed, but that the
    // variable that's declared in the same declaration is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedAndVariableNotReferenced)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
            uniform float uF;
    
            out vec4 my_FragColor;
    
            void main()
            {
                struct myStruct { float member; } unreferencedStruct;
                myStruct usedStruct = myStruct(uF);
                my_FragColor = vec4(usedStruct.member);
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("myStruct"));
        ASSERT_TRUE(foundInCode("usedStruct"));
        ASSERT_TRUE(notFoundInCode("unreferencedStruct"));
    }
    
    // Test that a nameless user-defined type (struct) declaration is removed entirely.
    TEST_F(RemoveUnreferencedVariablesTest, NamelessUserDefinedTypeUnreferenced)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
            void main()
            {
                struct { float member; } unreferencedStruct;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("unreferencedStruct"));
        ASSERT_TRUE(notFoundInCode("member"));
    }
    
    // Test that a variable that's only referenced in a unused function is removed.
    TEST_F(RemoveUnreferencedVariablesTest, VariableOnlyReferencedInUnusedFunction)
    {
        const std::string &shaderString =
            R"(
            int onlyReferencedInUnusedFunction = 0;
            void unusedFunc() {
                onlyReferencedInUnusedFunction++;
            }
    
            void main()
            {
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("onlyReferencedInUnusedFunction"));
    }
    
    // Test that a variable that's only referenced in an array length() method call is removed.
    TEST_F(RemoveUnreferencedVariablesTest, VariableOnlyReferencedInLengthMethod)
    {
        const std::string &shaderString =
            R"(#version 300 es
            precision highp float;
    
            out vec4 my_FragColor;
    
            void main()
            {
                float onlyReferencedInLengthMethodCall[1];
                int len = onlyReferencedInLengthMethodCall.length();
                my_FragColor = vec4(0, len, 0, 1);
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("onlyReferencedInLengthMethodCall"));
    }
    
    // Test that an unreferenced user-defined type is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeUnreferenced)
    {
        const std::string &shaderString =
            R"(
            struct myStructType
            {
                int i;
            } myStructVariable;
    
            void main()
            {
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myStructType"));
    }
    
    // Test that a user-defined type that's only referenced in an unreferenced variable is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedInUnreferencedVariable)
    {
        const std::string &shaderString =
            R"(
            struct myStructType
            {
                int i;
            };
    
            void main()
            {
                myStructType myStructVariable;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myStructType"));
    }
    
    // Test that a user-defined type that's declared in an empty declaration and that is only referenced
    // in an unreferenced variable is removed also when the shader contains another independent
    // user-defined type that's declared in an empty declaration. This tests special case handling of
    // reference counting of empty symbols.
    TEST_F(RemoveUnreferencedVariablesTest,
           TwoUserDefinedTypesDeclaredInEmptyDeclarationsWithOneOfThemUnreferenced)
    {
        const std::string &shaderString =
            R"(
            struct myStructTypeA
            {
                int i;
            };
    
            struct myStructTypeB
            {
                int j;
            };
    
            uniform myStructTypeB myStructVariableB;
    
            void main()
            {
                myStructTypeA myStructVariableA;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myStructTypeA"));
        ASSERT_TRUE(foundInCode("myStructTypeB"));
    }
    
    // Test that a user-defined type that is only referenced in another unreferenced type is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeChain)
    {
        const std::string &shaderString =
            R"(
            struct myInnerStructType
            {
                int i;
            };
    
            struct myOuterStructType
            {
                myInnerStructType inner;
            } myStructVariable;
    
            void main()
            {
                myOuterStructType myStructVariable2;
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myInnerStructType"));
    }
    
    // Test that a user-defined type that is referenced in another user-defined type that is used is
    // kept.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeChainReferenced)
    {
        const std::string &shaderString =
            R"(
            precision mediump float;
    
            struct myInnerStructType
            {
                int i;
            };
    
            uniform struct
            {
                myInnerStructType inner;
            } myStructVariable;
    
            void main()
            {
                if (myStructVariable.inner.i > 0)
                {
                    gl_FragColor = vec4(0, 1, 0, 1);
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("struct _umyInnerStructType"));
    }
    
    // Test that a struct type that is only referenced in a constructor and function call is kept.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedInConstructorAndCall)
    {
        const std::string &shaderString =
            R"(
            precision mediump float;
    
            uniform int ui;
    
            struct myStructType
            {
                int iMember;
            };
    
            void func(myStructType myStructParam)
            {
                if (myStructParam.iMember > 0)
                {
                    gl_FragColor = vec4(0, 1, 0, 1);
                }
            }
    
            void main()
            {
                func(myStructType(ui));
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("struct _umyStructType"));
    }
    
    // Test that a struct type that is only referenced in a constructor is kept. This assumes that there
    // isn't more sophisticated folding of struct field access going on.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedInConstructor)
    {
        const std::string &shaderString =
            R"(
            precision mediump float;
    
            uniform int ui;
    
            struct myStructType
            {
                int iMember;
            };
    
            void main()
            {
                if (myStructType(ui).iMember > 0)
                {
                    gl_FragColor = vec4(0, 1, 0, 1);
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("struct _umyStructType"));
    }
    
    // Test that a struct type that is only referenced in an unused function is removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedInUnusedFunction)
    {
        const std::string &shaderString =
            R"(
            precision mediump float;
    
            struct myStructType
            {
                int iMember;
            };
    
            void func(myStructType myStructParam)
            {
                if (myStructParam.iMember > 0)
                {
                    gl_FragColor = vec4(0, 1, 0, 1);
                }
            }
    
            void main()
            {
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myStructType"));
    }
    
    // Test that a struct type that is only referenced in an unused function is kept in case
    // SH_DONT_PRUNE_UNUSED_FUNCTIONS is specified.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReferencedInUnusedFunctionThatIsNotPruned)
    {
        const std::string &shaderString =
            R"(
            struct myStructType
            {
                int iMember;
            };
    
            myStructType func()
            {
                return myStructType(0);
            }
    
            void main()
            {
            })";
        compile(shaderString, SH_DONT_PRUNE_UNUSED_FUNCTIONS);
    
        ASSERT_TRUE(foundInCode("struct _umyStructType"));
    
        // Ensure that the struct isn't declared as a part of the function header.
        ASSERT_TRUE(foundInCode("};"));
    }
    
    // Test that a struct type that is only referenced as a function return value is kept.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeReturnedFromFunction)
    {
        const std::string &shaderString =
            R"(
            precision mediump float;
    
            struct myStructType
            {
                int iMember;
            };
    
            myStructType func()
            {
                gl_FragColor = vec4(0, 1, 0, 1);
                return myStructType(0);
            }
    
            void main()
            {
                func();
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("struct _umyStructType"));
    
        // Ensure that the struct isn't declared as a part of the function header.
        ASSERT_TRUE(foundInCode("};"));
    }
    
    // Test that a struct type that is only referenced in a uniform block is kept.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeInUniformBlock)
    {
        const std::string &shaderString =
            R"(#version 300 es
    
            precision highp float;
            out vec4 my_FragColor;
    
            struct myStructType
            {
                int iMember;
            };
    
            layout(std140) uniform myBlock {
                myStructType uStruct;
                int ui;
            };
    
            void main()
            {
                if (ui > 0)
                {
                    my_FragColor = vec4(0, 1, 0, 1);
                }
            })";
        compile(shaderString);
    
        ASSERT_TRUE(foundInCode("struct _umyStructType"));
    }
    
    // Test that a struct type that is referenced from an initializer with a constructor can be removed.
    TEST_F(RemoveUnreferencedVariablesTest, UserDefinedTypeConstructorInitializer)
    {
        const std::string &shaderString =
            R"(#version 300 es
    
            precision highp float;
            out vec4 my_FragColor;
    
            struct myStructType
            {
                int iMember;
            };
    
            uniform int ui;
    
            void main()
            {
                myStructType S = myStructType(ui);
                my_FragColor = vec4(0, 1, 0, 1);
            })";
        compile(shaderString);
    
        ASSERT_TRUE(notFoundInCode("myStructType"));
    }