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