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