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
79 static_assert(offsetof(ShBuiltInResources, OES_standard_derivatives) != 0,
80 "Update SymbolTable extension logic");
81
82 #define EXT_INDEX(Ext) (offsetof(ShBuiltInResources, Ext) / sizeof(int))
83
84 class SymbolRule
85 {
86 public:
87 const TSymbol *get(ShShaderSpec shaderSpec,
88 int shaderVersion,
89 sh::GLenum shaderType,
90 const ShBuiltInResources &resources,
91 const TSymbolTableBase &symbolTable) const;
92
93 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
94 constexpr static SymbolRule Get(T value);
95
96 private:
97 constexpr SymbolRule(Spec spec,
98 int version,
99 Shader shaders,
100 size_t extensionIndex,
101 const TSymbol *symbol);
102
103 constexpr SymbolRule(Spec spec,
104 int version,
105 Shader shaders,
106 size_t extensionIndex,
107 VarPointer resourceVar);
108
109 union SymbolOrVar
110 {
SymbolOrVar(const TSymbol * symbolIn)111 constexpr SymbolOrVar(const TSymbol *symbolIn) : symbol(symbolIn) {}
SymbolOrVar(VarPointer varIn)112 constexpr SymbolOrVar(VarPointer varIn) : var(varIn) {}
113
114 const TSymbol *symbol;
115 VarPointer var;
116 };
117
118 uint16_t mIsDesktop : 1;
119 uint16_t mIsVar : 1;
120 uint16_t mVersion : 14;
121 uint8_t mShaders;
122 uint8_t mExtensionIndex;
123 SymbolOrVar mSymbolOrVar;
124 };
125
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,const TSymbol * symbol)126 constexpr SymbolRule::SymbolRule(Spec spec,
127 int version,
128 Shader shaders,
129 size_t extensionIndex,
130 const TSymbol *symbol)
131 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
132 mIsVar(0u),
133 mVersion(static_cast<uint16_t>(version)),
134 mShaders(static_cast<uint8_t>(shaders)),
135 mExtensionIndex(extensionIndex),
136 mSymbolOrVar(symbol)
137 {}
138
SymbolRule(Spec spec,int version,Shader shaders,size_t extensionIndex,VarPointer resourceVar)139 constexpr SymbolRule::SymbolRule(Spec spec,
140 int version,
141 Shader shaders,
142 size_t extensionIndex,
143 VarPointer resourceVar)
144 : mIsDesktop(spec == Spec::GLSL ? 1u : 0u),
145 mIsVar(1u),
146 mVersion(static_cast<uint16_t>(version)),
147 mShaders(static_cast<uint8_t>(shaders)),
148 mExtensionIndex(extensionIndex),
149 mSymbolOrVar(resourceVar)
150 {}
151
152 template <Spec spec, int version, Shader shaders, size_t extensionIndex, typename T>
153 // static
Get(T value)154 constexpr SymbolRule SymbolRule::Get(T value)
155 {
156 static_assert(version < 0x4000u, "version OOR");
157 static_assert(static_cast<uint8_t>(shaders) < 0xFFu, "shaders OOR");
158 static_assert(static_cast<uint8_t>(extensionIndex) < 0xFF, "extensionIndex OOR");
159 return SymbolRule(spec, version, shaders, extensionIndex, value);
160 }
161
162 const TSymbol *FindMangledBuiltIn(ShShaderSpec shaderSpec,
163 int shaderVersion,
164 sh::GLenum shaderType,
165 const ShBuiltInResources &resources,
166 const TSymbolTableBase &symbolTable,
167 const SymbolRule *rules,
168 uint16_t startIndex,
169 uint16_t endIndex);
170
171 class UnmangledEntry
172 {
173 public:
174 template <size_t ESSLExtCount>
175 constexpr UnmangledEntry(const char *name,
176 const std::array<TExtension, ESSLExtCount> &esslExtensions,
177 TExtension glslExtension,
178 int esslVersion,
179 int glslVersion,
180 Shader shaderType);
181
182 bool matches(const ImmutableString &name,
183 ShShaderSpec shaderSpec,
184 int shaderVersion,
185 sh::GLenum shaderType,
186 const TExtensionBehavior &extensions) const;
187
188 private:
189 const char *mName;
190 std::array<TExtension, 2u> mESSLExtensions;
191 TExtension mGLSLExtension;
192 uint8_t mShaderType;
193 uint16_t mESSLVersion;
194 uint16_t mGLSLVersion;
195 };
196
197 template <>
UnmangledEntry(const char * name,const std::array<TExtension,1> & esslExtensions,TExtension glslExtension,int esslVersion,int glslVersion,Shader shaderType)198 constexpr UnmangledEntry::UnmangledEntry(const char *name,
199 const std::array<TExtension, 1> &esslExtensions,
200 TExtension glslExtension,
201 int esslVersion,
202 int glslVersion,
203 Shader shaderType)
204 : mName(name),
205 mESSLExtensions{esslExtensions[0], TExtension::UNDEFINED},
206 mGLSLExtension(glslExtension),
207 mShaderType(static_cast<uint8_t>(shaderType)),
208 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
209 : static_cast<uint16_t>(esslVersion)),
210 mGLSLVersion(glslVersion < 0 ? std::numeric_limits<uint16_t>::max()
211 : static_cast<uint16_t>(glslVersion))
212 {}
213
214 // Note: Until C++17, std::array functions are not constexpr, so the constructor is necessarily
215 // duplicated.
216 template <>
UnmangledEntry(const char * name,const std::array<TExtension,2> & esslExtensions,TExtension glslExtension,int esslVersion,int glslVersion,Shader shaderType)217 constexpr UnmangledEntry::UnmangledEntry(const char *name,
218 const std::array<TExtension, 2> &esslExtensions,
219 TExtension glslExtension,
220 int esslVersion,
221 int glslVersion,
222 Shader shaderType)
223 : mName(name),
224 mESSLExtensions{esslExtensions[0], esslExtensions[1]},
225 mGLSLExtension(glslExtension),
226 mShaderType(static_cast<uint8_t>(shaderType)),
227 mESSLVersion(esslVersion < 0 ? std::numeric_limits<uint16_t>::max()
228 : static_cast<uint16_t>(esslVersion)),
229 mGLSLVersion(glslVersion < 0 ? std::numeric_limits<uint16_t>::max()
230 : static_cast<uint16_t>(glslVersion))
231 {}
232
233 class TSymbolTable : angle::NonCopyable, TSymbolTableBase
234 {
235 public:
236 TSymbolTable();
237 // To start using the symbol table after construction:
238 // * initializeBuiltIns() needs to be called.
239 // * push() needs to be called to push the global level.
240
241 ~TSymbolTable();
242
243 bool isEmpty() const;
244 bool atGlobalLevel() const;
245
246 void push();
247 void pop();
248
249 // Declare a non-function symbol at the current scope. Return true in case the declaration was
250 // successful, and false if the declaration failed due to redefinition.
251 bool declare(TSymbol *symbol);
252
253 // Only used to declare internal variables.
254 bool declareInternal(TSymbol *symbol);
255
256 // Functions are always declared at global scope.
257 void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
258
259 // These return the TFunction pointer to keep using to refer to this function.
260 const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
261 bool *hadPrototypeDeclarationOut) const;
262 const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
263 bool *wasDefinedOut) const;
264
265 // Return false if the gl_in array size has already been initialized with a mismatching value.
266 bool setGlInArraySize(unsigned int inputArraySize);
267 TVariable *getGlInVariableWithArraySize() const;
268
269 const TVariable *gl_FragData() const;
270 const TVariable *gl_SecondaryFragDataEXT() const;
271
272 void markStaticRead(const TVariable &variable);
273 void markStaticWrite(const TVariable &variable);
274
275 // Note: Should not call this for constant variables.
276 bool isStaticallyUsed(const TVariable &variable) const;
277
278 // find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
279 // with a reference to a short-lived char * is fine to pass here.
280 const TSymbol *find(const ImmutableString &name, int shaderVersion) const;
281
282 const TSymbol *findUserDefined(const ImmutableString &name) const;
283
284 TFunction *findUserDefinedFunction(const ImmutableString &name) const;
285
286 const TSymbol *findGlobal(const ImmutableString &name) const;
287 const TSymbol *findGlobalWithConversion(const std::vector<ImmutableString> &names) const;
288
289 const TSymbol *findBuiltIn(const ImmutableString &name, int shaderVersion) const;
290 const TSymbol *findBuiltInWithConversion(const std::vector<ImmutableString> &names,
291 int shaderVersion) const;
292
293 void setDefaultPrecision(TBasicType type, TPrecision prec);
294
295 // Searches down the precisionStack for a precision qualifier
296 // for the specified TBasicType
297 TPrecision getDefaultPrecision(TBasicType type) const;
298
299 // This records invariant varyings declared through "invariant varying_name;".
300 void addInvariantVarying(const TVariable &variable);
301
302 // If this returns false, the varying could still be invariant if it is set as invariant during
303 // the varying variable declaration - this piece of information is stored in the variable's
304 // type, not here.
305 bool isVaryingInvariant(const TVariable &variable) const;
306
307 void setGlobalInvariant(bool invariant);
308
nextUniqueId()309 const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
310
311 // Gets the built-in accessible by a shader with the specified version, if any.
312 bool isUnmangledBuiltInName(const ImmutableString &name,
313 int shaderVersion,
314 const TExtensionBehavior &extensions) const;
315
316 void initializeBuiltIns(sh::GLenum type,
317 ShShaderSpec spec,
318 const ShBuiltInResources &resources);
319 void clearCompilationResults();
320
getDefaultUniformsBindingIndex()321 int getDefaultUniformsBindingIndex() const { return mResources.DriverUniformsBindingIndex; }
getDriverUniformsBindingIndex()322 int getDriverUniformsBindingIndex() const { return mResources.DefaultUniformsBindingIndex; }
getUBOArgumentBufferBindingIndex()323 int getUBOArgumentBufferBindingIndex() const
324 {
325 return mResources.UBOArgumentBufferBindingIndex;
326 }
327
328 private:
329 friend class TSymbolUniqueId;
330
331 struct VariableMetadata
332 {
333 VariableMetadata();
334 bool staticRead;
335 bool staticWrite;
336 bool invariant;
337 };
338
339 int nextUniqueIdValue();
340
341 class TSymbolTableLevel;
342
343 void initSamplerDefaultPrecision(TBasicType samplerType);
344
345 void initializeBuiltInVariables(sh::GLenum shaderType,
346 ShShaderSpec spec,
347 const ShBuiltInResources &resources);
348
349 VariableMetadata *getOrCreateVariableMetadata(const TVariable &variable);
350
351 std::vector<std::unique_ptr<TSymbolTableLevel>> mTable;
352
353 // There's one precision stack level for predefined precisions and then one level for each scope
354 // in table.
355 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel;
356 std::vector<std::unique_ptr<PrecisionStackLevel>> mPrecisionStack;
357
358 bool mGlobalInvariant;
359
360 int mUniqueIdCounter;
361
362 static const int kLastBuiltInId;
363
364 sh::GLenum mShaderType;
365 ShShaderSpec mShaderSpec;
366 ShBuiltInResources mResources;
367
368 // Indexed by unique id. Map instead of vector since the variables are fairly sparse.
369 std::map<int, VariableMetadata> mVariableMetadata;
370
371 // Store gl_in variable with its array size once the array size can be determined. The array
372 // size can also be checked against latter input primitive type declaration.
373 TVariable *mGlInVariableWithArraySize;
374 };
375
376 } // namespace sh
377
378 #endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_
379