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 | |
11 | namespace sh |
12 | { |
13 | |
14 | namespace |
15 | { |
16 | |
17 | const int kMaxAllowedTraversalDepth = 256; |
18 | |
19 | class 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 | |
39 | void 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 | |
67 | void 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 | |
90 | bool 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 | |
103 | bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node) |
104 | { |
105 | if (node->isAssignment()) |
106 | { |
107 | mIsValid = false; |
108 | } |
109 | return true; |
110 | } |
111 | |
112 | bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node) |
113 | { |
114 | if (node->isAssignment()) |
115 | { |
116 | mIsValid = false; |
117 | } |
118 | return true; |
119 | } |
120 | |
121 | ValidateGlobalInitializerTraverser::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 | |
132 | bool 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 | |