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
19namespace
20{
21
22class ValidateGlobalInitializerTraverser : public TIntermTraverser
23{
24public:
25	ValidateGlobalInitializerTraverser(const TParseContext *context);
26
27	void visitSymbol(TIntermSymbol *node) override;
28
29	bool isValid() const { return mIsValid; }
30	bool issueWarning() const { return mIssueWarning; }
31
32private:
33	const TParseContext *mContext;
34	bool mIsValid;
35	bool mIssueWarning;
36};
37
38void 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
70ValidateGlobalInitializerTraverser::ValidateGlobalInitializerTraverser(const TParseContext *context)
71	: TIntermTraverser(true, false, false),
72	  mContext(context),
73	  mIsValid(true),
74	  mIssueWarning(false)
75{
76}
77
78} // namespace
79
80bool 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