1//
2// Copyright (c) 2002-2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/translator/ValidateGlobalInitializer.h"
8
9#include "compiler/translator/tree_util/IntermTraverse.h"
10
11namespace sh
12{
13
14namespace
15{
16
17const int kMaxAllowedTraversalDepth = 256;
18
19class ValidateGlobalInitializerTraverser : public TIntermTraverser
20{
21 public:
22 ValidateGlobalInitializerTraverser(int shaderVersion);
23
24 void visitSymbol(TIntermSymbol *node) override;
25 void visitConstantUnion(TIntermConstantUnion *node) override;
26 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
27 bool visitBinary(Visit visit, TIntermBinary *node) override;
28 bool visitUnary(Visit visit, TIntermUnary *node) override;
29
30 bool isValid() const { return mIsValid && mMaxDepth < mMaxAllowedDepth; }
31 bool issueWarning() const { return mIssueWarning; }
32
33 private:
34 int mShaderVersion;
35 bool mIsValid;
36 bool mIssueWarning;
37};
38
39void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
40{
41 // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
42 // Global initializers must be constant expressions.
43 switch (node->getType().getQualifier())
44 {
45 case EvqConst:
46 break;
47 case EvqGlobal:
48 case EvqTemporary:
49 case EvqUniform:
50 // We allow these cases to be compatible with legacy ESSL 1.00 content.
51 // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal
52 // with.
53 if (mShaderVersion >= 300)
54 {
55 mIsValid = false;
56 }
57 else
58 {
59 mIssueWarning = true;
60 }
61 break;
62 default:
63 mIsValid = false;
64 }
65}
66
67void ValidateGlobalInitializerTraverser::visitConstantUnion(TIntermConstantUnion *node)
68{
69 // Constant unions that are not constant expressions may result from folding a ternary
70 // expression.
71 switch (node->getType().getQualifier())
72 {
73 case EvqConst:
74 break;
75 case EvqTemporary:
76 if (mShaderVersion >= 300)
77 {
78 mIsValid = false;
79 }
80 else
81 {
82 mIssueWarning = true;
83 }
84 break;
85 default:
86 UNREACHABLE();
87 }
88}
89
90bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
91{
92 // Disallow calls to user-defined functions and texture lookup functions in global variable
93 // initializers.
94 // This is done simply by disabling all function calls - built-in math functions don't use
95 // the function call ops.
96 if (node->isFunctionCall())
97 {
98 mIsValid = false;
99 }
100 return true;
101}
102
103bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
104{
105 if (node->isAssignment())
106 {
107 mIsValid = false;
108 }
109 return true;
110}
111
112bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
113{
114 if (node->isAssignment())
115 {
116 mIsValid = false;
117 }
118 return true;
119}
120
121ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(int shaderVersion)
122 : TIntermTraverser(true, false, false, nullptr),
123 mShaderVersion(shaderVersion),
124 mIsValid(true),
125 mIssueWarning(false)
126{
127 setMaxAllowedDepth(kMaxAllowedTraversalDepth);
128}
129
130} // namespace
131
132bool ValidateGlobalInitializer(TIntermTyped *initializer, int shaderVersion, bool *warning)
133{
134 ValidateGlobalInitializerTraverser validate(shaderVersion);
135 initializer->traverse(&validate);
136 ASSERT(warning != nullptr);
137 *warning = validate.issueWarning();
138 return validate.isValid();
139}
140
141} // namespace sh
142