1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "ValidateGlobalInitializer.h"
16
17 #include "ParseHelper.h"
18
19 namespace
20 {
21
22 class ValidateGlobalInitializerTraverser : public TIntermTraverser
23 {
24 public:
25 ValidateGlobalInitializerTraverser(const TParseContext *context);
26
27 void visitSymbol(TIntermSymbol *node) override;
28
isValid() const29 bool isValid() const { return mIsValid; }
issueWarning() const30 bool issueWarning() const { return mIssueWarning; }
31
32 private:
33 const TParseContext *mContext;
34 bool mIsValid;
35 bool mIssueWarning;
36 };
37
visitSymbol(TIntermSymbol * node)38 void ValidateGlobalInitializerTraverser::visitSymbol(TIntermSymbol *node)
39 {
40 const TSymbol *sym = 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 EvqConstExpr:
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 with.
55 if (mContext->getShaderVersion() >= 300)
56 {
57 mIsValid = false;
58 }
59 else
60 {
61 mIssueWarning = true;
62 }
63 break;
64 default:
65 mIsValid = false;
66 }
67 }
68 }
69
ValidateGlobalInitializerTraverser(const TParseContext * context)70 ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
71 : TIntermTraverser(true, false, false),
72 mContext(context),
73 mIsValid(true),
74 mIssueWarning(false)
75 {
76 }
77
78 } // namespace
79
ValidateGlobalInitializer(TIntermTyped * initializer,const TParseContext * context,bool * warning)80 bool ValidateGlobalInitializer(TIntermTyped *initializer, const TParseContext *context, bool *warning)
81 {
82 ValidateGlobalInitializerTraverser validate(context);
83 initializer->traverse(&validate);
84 ASSERT(warning != nullptr);
85 *warning = validate.issueWarning();
86 return validate.isValid();
87 }
88
89