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