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/IntermTraverse.h"
10 #include "compiler/translator/ParseContext.h"
11
12 namespace sh
13 {
14
15 namespace
16 {
17
18 class ValidateGlobalInitializerTraverser : public TIntermTraverser
19 {
20 public:
21 ValidateGlobalInitializerTraverser(const TParseContext *context);
22
23 void visitSymbol(TIntermSymbol *node) override;
24 bool visitAggregate(Visit visit, TIntermAggregate *node) override;
25 bool visitBinary(Visit visit, TIntermBinary *node) override;
26 bool visitUnary(Visit visit, TIntermUnary *node) override;
27
isValid() const28 bool isValid() const { return mIsValid; }
issueWarning() const29 bool issueWarning() const { return mIssueWarning; }
30
31 private:
32 const TParseContext *mContext;
33 bool mIsValid;
34 bool mIssueWarning;
35 };
36
visitSymbol(TIntermSymbol * node)37 void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
38 {
39 const TSymbol *sym =
40 mContext->symbolTable.find(node->getSymbol(), mContext->getShaderVersion());
41 if (sym->isVariable())
42 {
43 // ESSL 1.00 section 4.3 (or ESSL 3.00 section 4.3):
44 // Global initializers must be constant expressions.
45 const TVariable *var = static_cast<const TVariable *>(sym);
46 switch (var->getType().getQualifier())
47 {
48 case EvqConst:
49 break;
50 case EvqGlobal:
51 case EvqTemporary:
52 case EvqUniform:
53 // We allow these cases to be compatible with legacy ESSL 1.00 content.
54 // Implement stricter rules for ESSL 3.00 since there's no legacy content to deal
55 // with.
56 if (mContext->getShaderVersion() >= 300)
57 {
58 mIsValid = false;
59 }
60 else
61 {
62 mIssueWarning = true;
63 }
64 break;
65 default:
66 mIsValid = false;
67 }
68 }
69 }
70
visitAggregate(Visit visit,TIntermAggregate * node)71 bool ValidateGlobalInitializerTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
72 {
73 // Disallow calls to user-defined functions and texture lookup functions in global variable
74 // initializers.
75 // This is done simply by disabling all function calls - built-in math functions don't use
76 // the function call ops.
77 if (node->isFunctionCall())
78 {
79 mIsValid = false;
80 }
81 return true;
82 }
83
visitBinary(Visit visit,TIntermBinary * node)84 bool ValidateGlobalInitializerTraverser::visitBinary(Visit visit, TIntermBinary *node)
85 {
86 if (node->isAssignment())
87 {
88 mIsValid = false;
89 }
90 return true;
91 }
92
visitUnary(Visit visit,TIntermUnary * node)93 bool ValidateGlobalInitializerTraverser::visitUnary(Visit visit, TIntermUnary *node)
94 {
95 if (node->isAssignment())
96 {
97 mIsValid = false;
98 }
99 return true;
100 }
101
ValidateGlobalInitializerTraverser(const TParseContext * context)102 ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
103 : TIntermTraverser(true, false, false), mContext(context), mIsValid(true), mIssueWarning(false)
104 {
105 }
106
107 } // namespace
108
ValidateGlobalInitializer(TIntermTyped * initializer,const TParseContext * context,bool * warning)109 bool ValidateGlobalInitializer(TIntermTyped *initializer,
110 const TParseContext *context,
111 bool *warning)
112 {
113 ValidateGlobalInitializerTraverser validate(context);
114 initializer->traverse(&validate);
115 ASSERT(warning != nullptr);
116 *warning = validate.issueWarning();
117 return validate.isValid();
118 }
119
120 } // namespace sh
121