1 //
2 // Copyright 2002 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 #ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_
8 #define COMPILER_TRANSLATOR_SYMBOLTABLE_H_
9
10 //
11 // Symbol table for parsing. Has these design characteristics:
12 //
13 // * Same symbol table can be used to compile many shaders, to preserve
14 // effort of creating and loading with the large numbers of built-in
15 // symbols.
16 //
17 // * Name mangling will be used to give each function a unique name
18 // so that symbol table lookups are never ambiguous. This allows
19 // a simpler symbol table structure.
20 //
21 // * Pushing and popping of scope, so symbol table will really be a stack
22 // of symbol tables. Searched from the top, with new inserts going into
23 // the top.
24 //
25 // * Constants: Compile time constant symbols will keep their values
26 // in the symbol table. The parser can substitute constants at parse
27 // time, including doing constant folding and constant propagation.
28 //
29 // * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
30 // are tracked in the intermediate representation, not the symbol table.
31 //
32
33 #include <limits>
34 #include <memory>
35 #include <set>
36
37 #include "common/angleutils.h"
38 #include "compiler/translator/ExtensionBehavior.h"
39 #include "compiler/translator/ImmutableString.h"
40 #include "compiler/translator/InfoSink.h"
41 #include "compiler/translator/IntermNode.h"
42 #include "compiler/translator/Symbol.h"
43 #include "compiler/translator/SymbolTable_autogen.h"
44
45 enum class Shader : uint8_t
46 {
47 ALL,
48 FRAGMENT, // GL_FRAGMENT_SHADER
49 VERTEX, // GL_VERTEX_SHADER
50 COMPUTE, // GL_COMPUTE_SHADER
51 GEOMETRY, // GL_GEOMETRY_SHADER
52 GEOMETRY_EXT, // GL_GEOMETRY_SHADER_EXT
53 TESS_CONTROL_EXT, // GL_TESS_CONTROL_SHADER_EXT
54 TESS_EVALUATION_EXT, // GL_TESS_EVALUATION_SHADER_EXT
55 NOT_COMPUTE
56 };
57
58 namespace sh
59 {
60
61 struct UnmangledBuiltIn
62 {
UnmangledBuiltInUnmangledBuiltIn63 constexpr UnmangledBuiltIn(TExtension extension) : extension(extension) {}
64
65 TExtension extension;
66 };
67
68 using VarPointer = TSymbol *(TSymbolTableBase::*);
69 using ValidateExtension = int ShBuiltInResources::*;
70
71 enum class Spec : uint8_t
72 {
73 GLSL,
74 ESSL
75 };
76
77 constexpr uint16_t kESSL1Only = 100;
78 // Some built-ins from backend shader languages are made available internally to ESSL for use in
79 // tree transformations. This (invalid) shader version is used to select those built-ins. This
80 // value needs to be larger than all other shader versions.
81 constexpr uint16_t kESSLInternalBackendBuiltIns = 0x3FFF;
82
83 // The version assigned to |kESSLInternalBackendBuiltIns| should be good until OpenGL 20.0!
84 static_assert(kESSLInternalBackendBuiltIns > 2000,
85 "Accidentally exposing internal backend built-ins in OpenGL");
86
87 static_assert(offsetof(ShBuiltInResources, OES_standard_derivatives) != 0,
88 "Update SymbolTable extension logic");
89
90 #define EXT_INDEX(Ext) (offsetof(ShBuiltInResources, Ext) / sizeof(int))
91
92 class SymbolRule
93 {
94 public:
95 const TSymbol *get(ShShaderSpec shaderSpec,
96 int shaderVersion,
97 sh::GLenum shaderType,
98 const ShBuiltInResources &resources,
99 const TSymbolTableBase &symbolTable) const;
100
101 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
102 constexpr static SymbolRule Get(T value);
103
104 private:
105 constexpr SymbolRule(Spec spec,
106 int version,
107 Shader shaders,
108 size_t extensionIndex,
109 const TSymbol *symbol);
110
111 constexpr SymbolRule(Spec spec,
112 int version,
113 Shader shaders,
114 size_t extensionIndex,
115 VarPointer resourceVar);
116
117 union SymbolOrVar
118 {
SymbolOrVar(const TSymbol * symbolIn)119 constexpr SymbolOrVar(const TSymbol *symbolIn) : symbol(symbolIn) {}
SymbolOrVar(VarPointer varIn)120 constexpr SymbolOrVar(VarPointer varIn) : var(varIn) {}
121
122 const TSymbol *symbol;
123 VarPointer var;
124 };
125
126 uint16_t mIsDesktop : 1;
127 uint16_t mIsVar : 1;
128 uint16_t mVersion : 14;
129 uint8_t mShaders;
130 uint8_t mExtensionIndex;
131 SymbolOrVar mSymbolOrVar;
132 };
133
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,const TSymbol * symbol)134 constexpr SymbolRule::SymbolRule(Spec spec,
135 int version,
136 Shader shaders,
137 size_t extensionIndex,
138 const TSymbol *symbol)
139 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
140 mIsVar(0u),
141 mVersion(static_cast<uint16_t>(version)),
142 mShaders(static_cast<uint8_t>(shaders)),
143 mExtensionIndex(extensionIndex),
144 mSymbolOrVar(symbol)
145 {}
146
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,VarPointer resourceVar)147 constexpr SymbolRule::SymbolRule(Spec spec,
148 int version,
149 Shader shaders,
150 size_t extensionIndex,
151 VarPointer resourceVar)
152 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
153 mIsVar(1u),
154 mVersion(static_cast<uint16_t>(version)),
155 mShaders(static_cast<uint8_t>(shaders)),
156 mExtensionIndex(extensionIndex),
157 mSymbolOrVar(resourceVar)
158 {}
159
160 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
161 // static
Get(T value)162 constexpr SymbolRule SymbolRule::Get(T value)
163 {
164 static_assert(version < 0x4000u, "version OOR");
165 static_assert(static_cast<uint8_t>(shaders) < 0xFFu, "shaders OOR");
166 static_assert(static_cast<uint8_t>(extensionIndex) < 0xFF, "extensionIndex OOR");
167 return SymbolRule(spec, version, shaders, extensionIndex, value);
168 }
169
170 const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
171 int shaderVersion,
172 sh::GLenum shaderType,
173 const ShBuiltInResources &resources,
174 const TSymbolTableBase &symbolTable,
175 const SymbolRule *rules,
176 uint16_t startIndex,
177 uint16_t endIndex);
178
179 class UnmangledEntry
180 {
181 public:
182 template <size_t ESSLExtCount>
183 constexpr UnmangledEntry(const char *name,
184 const std::array<TExtension, ESSLExtCount> &esslExtensions,
185 TExtension glslExtension,
186 int esslVersion,
187 int glslVersion,
188 Shader shaderType);
189
190 bool matches(const ImmutableString &name,
191 ShShaderSpec shaderSpec,
192 int shaderVersion,
193 sh::GLenum shaderType,
194 const TExtensionBehavior &extensions) const;
195
196 private:
197 const char *mName;
198 std::array<TExtension, 2u> mESSLExtensions;
199 TExtension mGLSLExtension;
200 uint8_t mShaderType;
201 uint16_t mESSLVersion;
202 uint16_t mGLSLVersion;
203 };
204
205 template <size_t ESSLExtCount>
UnmangledEntry(const char * name,const std::array<TExtension,ESSLExtCount> & esslExtensions,TExtension glslExtension,int esslVersion,int glslVersion,Shader shaderType)206 constexpr UnmangledEntry::UnmangledEntry(const char *name,
207 const std::array<TExtension, ESSLExtCount> &esslExtensions,
208 TExtension glslExtension,
209 int esslVersion,
210 int glslVersion,
211 Shader shaderType)
212 : mName(name),
213 mESSLExtensions{(ESSLExtCount >= 1) ? esslExtensions[0] : TExtension::UNDEFINED,
214 (ESSLExtCount >= 2) ? esslExtensions[1] : TExtension::UNDEFINED},
215 mGLSLExtension(glslExtension),
216 mShaderType(static_cast<uint8_t>(shaderType)),
217 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
218 : static_cast<uint16_t>(esslVersion)),
219 mGLSLVersion(glslVersion < 0 ? std::numeric_limits<uint16_t>::max()
220 : static_cast<uint16_t>(glslVersion))
221 {}
222
223 class TSymbolTable : angle::NonCopyable, TSymbolTableBase
224 {
225 public:
226 TSymbolTable();
227 // To start using the symbol table after construction:
228 // * initializeBuiltIns() needs to be called.
229 // * push() needs to be called to push the global level.
230
231 ~TSymbolTable();
232
233 bool isEmpty() const;
234 bool atGlobalLevel() const;
235
236 void push();
237 void pop();
238
239 // Declare a non-function symbol at the current scope. Return true in case the declaration was
240 // successful, and false if the declaration failed due to redefinition.
241 bool declare(TSymbol *symbol);
242
243 // Only used to declare internal variables.
244 bool declareInternal(TSymbol *symbol);
245
246 // Functions are always declared at global scope.
247 void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
248
249 // These return the TFunction pointer to keep using to refer to this function.
250 const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
251 bool *hadPrototypeDeclarationOut) const;
252 const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
253 bool *wasDefinedOut) const;
254
255 // Return false if the gl_in array size has already been initialized with a mismatching value.
256 bool setGlInArraySize(unsigned int inputArraySize);
257 TVariable *getGlInVariableWithArraySize() const;
258
259 const TVariable *gl_FragData() const;
260 const TVariable *gl_SecondaryFragDataEXT() const;
261
262 void markStaticRead(const TVariable &variable);
263 void markStaticWrite(const TVariable &variable);
264
265 // Note: Should not call this for constant variables.
266 bool isStaticallyUsed(const TVariable &variable) const;
267
268 // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
269 // with a reference to a short-lived char * is fine to pass here.
270 const TSymbol *find(const ImmutableString &name, int shaderVersion) const;
271
272 const TSymbol *findUserDefined(const ImmutableString &name) const;
273
274 TFunction *findUserDefinedFunction(const ImmutableString &name) const;
275
276 const TSymbol *findGlobal(const ImmutableString &name) const;
277 const TSymbol *findGlobalWithConversion(const std::vector<ImmutableString> &names) const;
278
279 const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const;
280 const TSymbol *findBuiltInWithConversion(const std::vector<ImmutableString> &names,
281 int shaderVersion) const;
282
283 void setDefaultPrecision(TBasicType type, TPrecision prec);
284
285 // Searches down the precisionStack for a precision qualifier
286 // for the specified TBasicType
287 TPrecision getDefaultPrecision(TBasicType type) const;
288
289 // This records invariant varyings declared through "invariant varying_name;".
290 void addInvariantVarying(const TVariable &variable);
291
292 // If this returns false, the varying could still be invariant if it is set as invariant during
293 // the varying variable declaration - this piece of information is stored in the variable's
294 // type, not here.
295 bool isVaryingInvariant(const TVariable &variable) const;
296
297 void setGlobalInvariant(bool invariant);
298
nextUniqueId()299 const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
300
301 // Gets the built-in accessible by a shader with the specified version, if any.
302 bool isUnmangledBuiltInName(const ImmutableString &name,
303 int shaderVersion,
304 const TExtensionBehavior &extensions) const;
305
306 void initializeBuiltIns(sh::GLenum type,
307 ShShaderSpec spec,
308 const ShBuiltInResources &resources);
309 void clearCompilationResults();
310
getShaderSpec()311 ShShaderSpec getShaderSpec() const { return mShaderSpec; }
312
313 private:
314 friend class TSymbolUniqueId;
315
316 struct VariableMetadata
317 {
318 VariableMetadata();
319 bool staticRead;
320 bool staticWrite;
321 bool invariant;
322 };
323
324 int nextUniqueIdValue();
325
326 class TSymbolTableLevel;
327
328 void initSamplerDefaultPrecision(TBasicType samplerType);
329
330 void initializeBuiltInVariables(sh::GLenum shaderType,
331 ShShaderSpec spec,
332 const ShBuiltInResources &resources);
333
334 VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable);
335
336 std::vector<std::unique_ptr<TSymbolTableLevel>> mTable;
337
338 // There's one precision stack level for predefined precisions and then one level for each scope
339 // in table.
340 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
341 std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack;
342
343 bool mGlobalInvariant;
344
345 int mUniqueIdCounter;
346
347 static const int kLastBuiltInId;
348
349 sh::GLenum mShaderType;
350 ShShaderSpec mShaderSpec;
351 ShBuiltInResources mResources;
352
353 // Indexed by unique id. Map instead of vector since the variables are fairly sparse.
354 std::map<int, VariableMetadata> mVariableMetadata;
355
356 // Store gl_in variable with its array size once the array size can be determined. The array
357 // size can also be checked against latter input primitive type declaration.
358 TVariable *mGlInVariableWithArraySize;
359 };
360
361 } // namespace sh
362
363 #endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
364