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