/src/shaderc/third_party/glslang/glslang/MachineIndependent/ParseContextBase.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. |
3 | | // Copyright (C) 2016 Google, Inc. |
4 | | // |
5 | | // All rights reserved. |
6 | | // |
7 | | // Redistribution and use in source and binary forms, with or without |
8 | | // modification, are permitted provided that the following conditions |
9 | | // are met: |
10 | | // |
11 | | // Redistributions of source code must retain the above copyright |
12 | | // notice, this list of conditions and the following disclaimer. |
13 | | // |
14 | | // Redistributions in binary form must reproduce the above |
15 | | // copyright notice, this list of conditions and the following |
16 | | // disclaimer in the documentation and/or other materials provided |
17 | | // with the distribution. |
18 | | // |
19 | | // Neither the name of 3Dlabs Inc. Ltd. nor the names of its |
20 | | // contributors may be used to endorse or promote products derived |
21 | | // from this software without specific prior written permission. |
22 | | // |
23 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
24 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
25 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
26 | | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
27 | | // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
28 | | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
29 | | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
30 | | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
31 | | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
33 | | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
34 | | // POSSIBILITY OF SUCH DAMAGE. |
35 | | // |
36 | | |
37 | | // Implement the TParseContextBase class. |
38 | | |
39 | | #include <cstdarg> |
40 | | |
41 | | #include "ParseHelper.h" |
42 | | |
43 | | extern int yyparse(glslang::TParseContext*); |
44 | | |
45 | | namespace glslang { |
46 | | |
47 | | // |
48 | | // Used to output syntax, parsing, and semantic errors. |
49 | | // |
50 | | |
51 | | void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReason, |
52 | | const char* szToken, |
53 | | const char* szExtraInfoFormat, |
54 | | TPrefixType prefix, va_list args) |
55 | 11.6M | { |
56 | 11.6M | const int maxSize = MaxTokenLength + 200; |
57 | 11.6M | char szExtraInfo[maxSize]; |
58 | | |
59 | 11.6M | safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); |
60 | | |
61 | 11.6M | infoSink.info.prefix(prefix); |
62 | 11.6M | infoSink.info.location(loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); |
63 | 11.6M | infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; |
64 | | |
65 | 11.6M | if (prefix == EPrefixError) { |
66 | 11.6M | ++numErrors; |
67 | 11.6M | } |
68 | 11.6M | } |
69 | | |
70 | | void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken, |
71 | | const char* szExtraInfoFormat, ...) |
72 | 11.1M | { |
73 | 11.1M | if (messages & EShMsgOnlyPreprocessor) |
74 | 3.74M | return; |
75 | | // If enhanced msg readability, only print one error |
76 | 7.36M | if (messages & EShMsgEnhanced && numErrors > 0) |
77 | 0 | return; |
78 | 7.36M | va_list args; |
79 | 7.36M | va_start(args, szExtraInfoFormat); |
80 | 7.36M | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
81 | 7.36M | va_end(args); |
82 | | |
83 | 7.36M | if ((messages & EShMsgCascadingErrors) == 0) |
84 | 3.91k | currentScanner->setEndOfInput(); |
85 | 7.36M | } |
86 | | |
87 | | void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
88 | | const char* szExtraInfoFormat, ...) |
89 | 7.07k | { |
90 | 7.07k | if (suppressWarnings()) |
91 | 0 | return; |
92 | 7.07k | va_list args; |
93 | 7.07k | va_start(args, szExtraInfoFormat); |
94 | 7.07k | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
95 | 7.07k | va_end(args); |
96 | 7.07k | } |
97 | | |
98 | | void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, |
99 | | const char* szExtraInfoFormat, ...) |
100 | 4.31M | { |
101 | 4.31M | va_list args; |
102 | 4.31M | va_start(args, szExtraInfoFormat); |
103 | 4.31M | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
104 | 4.31M | va_end(args); |
105 | | |
106 | 4.31M | if ((messages & EShMsgCascadingErrors) == 0) |
107 | 0 | currentScanner->setEndOfInput(); |
108 | 4.31M | } |
109 | | |
110 | | void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
111 | | const char* szExtraInfoFormat, ...) |
112 | 2.50k | { |
113 | 2.50k | va_list args; |
114 | 2.50k | va_start(args, szExtraInfoFormat); |
115 | 2.50k | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
116 | 2.50k | va_end(args); |
117 | 2.50k | } |
118 | | |
119 | | // |
120 | | // Both test and if necessary, spit out an error, to see if the node is really |
121 | | // an l-value that can be operated on this way. |
122 | | // |
123 | | // Returns true if there was an error. |
124 | | // |
125 | | bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) |
126 | 680k | { |
127 | 680k | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
128 | | |
129 | 680k | const char* symbol = nullptr; |
130 | 680k | TIntermSymbol* symNode = node->getAsSymbolNode(); |
131 | 680k | if (symNode != nullptr) |
132 | 584k | symbol = symNode->getName().c_str(); |
133 | | |
134 | 680k | const char* message = nullptr; |
135 | 680k | switch (node->getQualifier().storage) { |
136 | 1.25k | case EvqConst: message = "can't modify a const"; break; |
137 | 16 | case EvqConstReadOnly: message = "can't modify a const"; break; |
138 | 3.37k | case EvqUniform: message = "can't modify a uniform"; break; |
139 | 88.5k | case EvqBuffer: |
140 | 88.5k | if (node->getQualifier().isReadOnly()) |
141 | 0 | message = "can't modify a readonly buffer"; |
142 | 88.5k | if (node->getQualifier().isShaderRecord()) |
143 | 0 | message = "can't modify a shaderrecordnv qualified buffer"; |
144 | 88.5k | break; |
145 | 0 | case EvqHitAttr: |
146 | 0 | if (language != EShLangIntersect) |
147 | 0 | message = "cannot modify hitAttributeNV in this stage"; |
148 | 0 | break; |
149 | | |
150 | 587k | default: |
151 | | // |
152 | | // Type that can't be written to? |
153 | | // |
154 | 587k | switch (node->getBasicType()) { |
155 | 0 | case EbtSampler: |
156 | 0 | if (extensionTurnedOn(E_GL_ARB_bindless_texture) == false) |
157 | 0 | message = "can't modify a sampler"; |
158 | 0 | break; |
159 | 6 | case EbtVoid: |
160 | 6 | message = "can't modify void"; |
161 | 6 | break; |
162 | 0 | case EbtAtomicUint: |
163 | 0 | message = "can't modify an atomic_uint"; |
164 | 0 | break; |
165 | 0 | case EbtAccStruct: |
166 | 0 | message = "can't modify accelerationStructureNV"; |
167 | 0 | break; |
168 | 3 | case EbtRayQuery: |
169 | 3 | message = "can't modify rayQueryEXT"; |
170 | 3 | break; |
171 | 0 | case EbtHitObjectNV: |
172 | 0 | message = "can't modify hitObjectNV"; |
173 | 0 | break; |
174 | 587k | default: |
175 | 587k | break; |
176 | 587k | } |
177 | 680k | } |
178 | | |
179 | 680k | if (message == nullptr && binaryNode == nullptr && symNode == nullptr) { |
180 | 1.02k | error(loc, " l-value required", op, "", ""); |
181 | | |
182 | 1.02k | return true; |
183 | 1.02k | } |
184 | | |
185 | | // |
186 | | // Everything else is okay, no error. |
187 | | // |
188 | 679k | if (message == nullptr) |
189 | 674k | { |
190 | 674k | if (binaryNode) { |
191 | 93.7k | switch (binaryNode->getOp()) { |
192 | 45.7k | case EOpIndexDirect: |
193 | 46.7k | case EOpIndexIndirect: // fall through |
194 | 93.6k | case EOpIndexDirectStruct: // fall through |
195 | 93.7k | case EOpVectorSwizzle: |
196 | 93.7k | case EOpMatrixSwizzle: |
197 | 93.7k | return lValueErrorCheck(loc, op, binaryNode->getLeft()); |
198 | 47 | default: |
199 | 47 | break; |
200 | 93.7k | } |
201 | 47 | error(loc, " l-value required", op, "", ""); |
202 | | |
203 | 47 | return true; |
204 | 93.7k | } |
205 | 581k | return false; |
206 | 674k | } |
207 | | |
208 | | // |
209 | | // If we get here, we have an error and a message. |
210 | | // |
211 | 4.65k | const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); |
212 | | |
213 | 4.65k | if (symNode) |
214 | 3.28k | error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); |
215 | 1.36k | else |
216 | 1.36k | if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct) |
217 | 108 | if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) |
218 | 107 | error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message); |
219 | 1 | else |
220 | 1 | error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message); |
221 | 1.25k | else |
222 | 1.25k | error(loc, " l-value required", op, "(%s)", message); |
223 | | |
224 | 4.65k | return true; |
225 | 679k | } |
226 | | |
227 | | // Test for and give an error if the node can't be read from. |
228 | | void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) |
229 | 7.70M | { |
230 | 7.70M | if (! node) |
231 | 0 | return; |
232 | | |
233 | 7.70M | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
234 | 7.70M | const TIntermSymbol* symNode = node->getAsSymbolNode(); |
235 | | |
236 | 7.70M | if (node->getQualifier().isWriteOnly()) { |
237 | 9 | const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); |
238 | | |
239 | 9 | if (symNode != nullptr) |
240 | 9 | error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); |
241 | 0 | else if (binaryNode && |
242 | 0 | (binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct || |
243 | 0 | binaryNode->getAsOperator()->getOp() == EOpIndexDirect)) |
244 | 0 | if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) |
245 | 0 | error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str()); |
246 | 0 | else |
247 | 0 | error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str()); |
248 | 0 | else |
249 | 0 | error(loc, "can't read from writeonly object: ", op, ""); |
250 | | |
251 | 7.70M | } else { |
252 | 7.70M | if (binaryNode) { |
253 | 328k | switch (binaryNode->getOp()) { |
254 | 34.9k | case EOpIndexDirect: |
255 | 42.9k | case EOpIndexIndirect: |
256 | 66.1k | case EOpIndexDirectStruct: |
257 | 73.0k | case EOpVectorSwizzle: |
258 | 73.0k | case EOpMatrixSwizzle: |
259 | 73.0k | rValueErrorCheck(loc, op, binaryNode->getLeft()); |
260 | 73.0k | break; |
261 | 255k | default: |
262 | 255k | break; |
263 | 328k | } |
264 | 328k | } |
265 | 7.70M | } |
266 | 7.70M | } |
267 | | |
268 | | // Add 'symbol' to the list of deferred linkage symbols, which |
269 | | // are later processed in finish(), at which point the symbol |
270 | | // must still be valid. |
271 | | // It is okay if the symbol's type will be subsequently edited; |
272 | | // the modifications will be tracked. |
273 | | // Order is preserved, to avoid creating novel forward references. |
274 | | void TParseContextBase::trackLinkage(TSymbol& symbol) |
275 | 11.5M | { |
276 | 11.5M | if (!parsingBuiltins) |
277 | 303k | linkageSymbols.push_back(&symbol); |
278 | 11.5M | } |
279 | | |
280 | | // Ensure index is in bounds, correct if necessary. |
281 | | // Give an error if not. |
282 | | void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int& index) |
283 | 68.2k | { |
284 | 68.2k | const auto sizeIsSpecializationExpression = [&type]() { |
285 | 54.2k | return type.containsSpecializationSize() && |
286 | 54.2k | type.getArraySizes()->getOuterNode() != nullptr && |
287 | 54.2k | type.getArraySizes()->getOuterNode()->getAsSymbolNode() == nullptr; }; |
288 | | |
289 | 68.2k | if (index < 0) { |
290 | 323 | error(loc, "", "[", "index out of range '%d'", index); |
291 | 323 | index = 0; |
292 | 67.9k | } else if (type.isArray()) { |
293 | 55.8k | if (type.isSizedArray() && !sizeIsSpecializationExpression() && |
294 | 55.8k | index >= type.getOuterArraySize()) { |
295 | 767 | error(loc, "", "[", "array index out of range '%d'", index); |
296 | 767 | index = type.getOuterArraySize() - 1; |
297 | 767 | } |
298 | 55.8k | } else if (type.isVector()) { |
299 | 6.47k | if (index >= type.getVectorSize()) { |
300 | 197 | error(loc, "", "[", "vector index out of range '%d'", index); |
301 | 197 | index = type.getVectorSize() - 1; |
302 | 197 | } |
303 | 6.47k | } else if (type.isMatrix()) { |
304 | 5.64k | if (index >= type.getMatrixCols()) { |
305 | 89 | error(loc, "", "[", "matrix index out of range '%d'", index); |
306 | 89 | index = type.getMatrixCols() - 1; |
307 | 89 | } |
308 | 5.64k | } else if (type.isCoopVecNV()) { |
309 | 0 | if (index >= type.computeNumComponents()) { |
310 | 0 | error(loc, "", "[", "cooperative vector index out of range '%d'", index); |
311 | 0 | index = type.computeNumComponents() - 1; |
312 | 0 | } |
313 | 0 | } |
314 | 68.2k | } |
315 | | |
316 | | // Make a shared symbol have a non-shared version that can be edited by the current |
317 | | // compile, such that editing its type will not change the shared version and will |
318 | | // effect all nodes already sharing it (non-shallow type), |
319 | | // or adopting its full type after being edited (shallow type). |
320 | | void TParseContextBase::makeEditable(TSymbol*& symbol) |
321 | 858 | { |
322 | | // copyUp() does a deep copy of the type. |
323 | 858 | symbol = symbolTable.copyUp(symbol); |
324 | | |
325 | | // Save it (deferred, so it can be edited first) in the AST for linker use. |
326 | 858 | if (symbol) |
327 | 858 | trackLinkage(*symbol); |
328 | 858 | } |
329 | | |
330 | | // Return a writable version of the variable 'name'. |
331 | | // |
332 | | // Return nullptr if 'name' is not found. This should mean |
333 | | // something is seriously wrong (e.g., compiler asking self for |
334 | | // built-in that doesn't exist). |
335 | | TVariable* TParseContextBase::getEditableVariable(const char* name) |
336 | 0 | { |
337 | 0 | bool builtIn; |
338 | 0 | TSymbol* symbol = symbolTable.find(name, &builtIn); |
339 | |
|
340 | 0 | assert(symbol != nullptr); |
341 | 0 | if (symbol == nullptr) |
342 | 0 | return nullptr; |
343 | | |
344 | 0 | if (builtIn) |
345 | 0 | makeEditable(symbol); |
346 | |
|
347 | 0 | return symbol->getAsVariable(); |
348 | 0 | } |
349 | | |
350 | | // Select the best matching function for 'call' from 'candidateList'. |
351 | | // |
352 | | // Assumptions |
353 | | // |
354 | | // There is no exact match, so a selection algorithm needs to run. That is, the |
355 | | // language-specific handler should check for exact match first, to |
356 | | // decide what to do, before calling this selector. |
357 | | // |
358 | | // Input |
359 | | // |
360 | | // * list of candidate signatures to select from |
361 | | // * the call |
362 | | // * a predicate function convertible(from, to) that says whether or not type |
363 | | // 'from' can implicitly convert to type 'to' (it includes the case of what |
364 | | // the calling language would consider a matching type with no conversion |
365 | | // needed) |
366 | | // * a predicate function better(from1, from2, to1, to2) that says whether or |
367 | | // not a conversion from <-> to2 is considered better than a conversion |
368 | | // from <-> to1 (both in and out directions need testing, as declared by the |
369 | | // formal parameter) |
370 | | // |
371 | | // Output |
372 | | // |
373 | | // * best matching candidate (or none, if no viable candidates found) |
374 | | // * whether there was a tie for the best match (ambiguous overload selection, |
375 | | // caller's choice for how to report) |
376 | | // |
377 | | const TFunction* TParseContextBase::selectFunction( |
378 | | const TVector<const TFunction*> candidateList, |
379 | | const TFunction& call, |
380 | | std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible, |
381 | | std::function<bool(const TType& from, const TType& to1, const TType& to2)> better, |
382 | | /* output */ bool& tie) |
383 | 91.9k | { |
384 | | // |
385 | | // Operation |
386 | | // |
387 | | // 1. Prune the input list of candidates down to a list of viable candidates, |
388 | | // where each viable candidate has |
389 | | // |
390 | | // * at least as many parameters as there are calling arguments, with any |
391 | | // remaining parameters being optional or having default values |
392 | | // * each parameter is true under convertible(A, B), where A is the calling |
393 | | // type for in and B is the formal type, and in addition, for out B is the |
394 | | // calling type and A is the formal type |
395 | | // |
396 | | // 2. If there are no viable candidates, return with no match. |
397 | | // |
398 | | // 3. If there is only one viable candidate, it is the best match. |
399 | | // |
400 | | // 4. If there are multiple viable candidates, select the first viable candidate |
401 | | // as the incumbent. Compare the incumbent to the next viable candidate, and if |
402 | | // that candidate is better (bullets below), make it the incumbent. Repeat, with |
403 | | // a linear walk through the viable candidate list. The final incumbent will be |
404 | | // returned as the best match. A viable candidate is better than the incumbent if |
405 | | // |
406 | | // * it has a function argument with a better(...) conversion than the incumbent, |
407 | | // for all directions needed by in and out |
408 | | // * the incumbent has no argument with a better(...) conversion then the |
409 | | // candidate, for either in or out (as needed) |
410 | | // |
411 | | // 5. Check for ambiguity by comparing the best match against all other viable |
412 | | // candidates. If any other viable candidate has a function argument with a |
413 | | // better(...) conversion than the best candidate (for either in or out |
414 | | // directions), return that there was a tie for best. |
415 | | // |
416 | | |
417 | 91.9k | tie = false; |
418 | | |
419 | | // 1. prune to viable... |
420 | 91.9k | TVector<const TFunction*> viableCandidates; |
421 | 2.18M | for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { |
422 | 2.09M | const TFunction& candidate = *(*it); |
423 | | |
424 | | // to even be a potential match, number of arguments must be >= the number of |
425 | | // fixed (non-default) parameters, and <= the total (including parameter with defaults). |
426 | 2.09M | if (call.getParamCount() < candidate.getFixedParamCount() || |
427 | 2.09M | call.getParamCount() > candidate.getParamCount()) |
428 | 890k | continue; |
429 | | |
430 | | // see if arguments are convertible |
431 | 1.20M | bool viable = true; |
432 | | |
433 | | // The call can have fewer parameters than the candidate, if some have defaults. |
434 | 1.20M | const int paramCount = std::min(call.getParamCount(), candidate.getParamCount()); |
435 | 1.53M | for (int param = 0; param < paramCount; ++param) { |
436 | 1.35M | if (candidate[param].type->getQualifier().isParamInput()) { |
437 | 1.34M | if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) { |
438 | 1.02M | viable = false; |
439 | 1.02M | break; |
440 | 1.02M | } |
441 | 1.34M | } |
442 | 326k | if (candidate[param].type->getQualifier().isParamOutput()) { |
443 | 4.33k | if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) { |
444 | 704 | viable = false; |
445 | 704 | break; |
446 | 704 | } |
447 | 4.33k | } |
448 | 326k | } |
449 | | |
450 | 1.20M | if (viable) |
451 | 178k | viableCandidates.push_back(&candidate); |
452 | 1.20M | } |
453 | | |
454 | | // 2. none viable... |
455 | 91.9k | if (viableCandidates.size() == 0) |
456 | 70.8k | return nullptr; |
457 | | |
458 | | // 3. only one viable... |
459 | 21.0k | if (viableCandidates.size() == 1) |
460 | 5.14k | return viableCandidates.front(); |
461 | | |
462 | | // 4. find best... |
463 | 330k | const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
464 | | // is call -> can2 better than call -> can1 for any parameter |
465 | 330k | bool hasBetterParam = false; |
466 | 796k | for (int param = 0; param < call.getParamCount(); ++param) { |
467 | 484k | if (better(*call[param].type, *can1[param].type, *can2[param].type)) { |
468 | 17.8k | hasBetterParam = true; |
469 | 17.8k | break; |
470 | 17.8k | } |
471 | 484k | } |
472 | 330k | return hasBetterParam; |
473 | 330k | }; |
474 | | |
475 | 156k | const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
476 | | // is call -> can2 equivalent to call -> can1 for all the call parameters? |
477 | 186k | for (int param = 0; param < call.getParamCount(); ++param) { |
478 | 164k | if (better(*call[param].type, *can1[param].type, *can2[param].type) || |
479 | 164k | better(*call[param].type, *can2[param].type, *can1[param].type)) |
480 | 134k | return false; |
481 | 164k | } |
482 | 21.9k | return true; |
483 | 156k | }; |
484 | | |
485 | 15.9k | const TFunction* incumbent = viableCandidates.front(); |
486 | 173k | for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) { |
487 | 157k | const TFunction& candidate = *(*it); |
488 | 157k | if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent)) |
489 | 13.3k | incumbent = &candidate; |
490 | 157k | } |
491 | | |
492 | | // 5. ambiguity... |
493 | 189k | for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) { |
494 | 173k | if (incumbent == *it) |
495 | 15.9k | continue; |
496 | 157k | const TFunction& candidate = *(*it); |
497 | | |
498 | | // In the case of default parameters, it may have an identical initial set, which is |
499 | | // also ambiguous |
500 | 157k | if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate)) |
501 | 23.2k | tie = true; |
502 | 157k | } |
503 | | |
504 | 15.9k | return incumbent; |
505 | 21.0k | } |
506 | | |
507 | | // |
508 | | // Look at a '.' field selector string and change it into numerical selectors |
509 | | // for a vector or scalar. |
510 | | // |
511 | | // Always return some form of swizzle, so the result is always usable. |
512 | | // |
513 | | void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize, |
514 | | TSwizzleSelectors<TVectorSelector>& selector) |
515 | 115k | { |
516 | | // Too long? |
517 | 115k | if (compString.size() > MaxSwizzleSelectors) |
518 | 1.34k | error(loc, "vector swizzle too long", compString.c_str(), ""); |
519 | | |
520 | | // Use this to test that all swizzle characters are from the same swizzle-namespace-set |
521 | 115k | enum { |
522 | 115k | exyzw, |
523 | 115k | ergba, |
524 | 115k | estpq, |
525 | 115k | } fieldSet[MaxSwizzleSelectors]; |
526 | | |
527 | | // Decode the swizzle string. |
528 | 115k | int size = std::min(MaxSwizzleSelectors, (int)compString.size()); |
529 | 281k | for (int i = 0; i < size; ++i) { |
530 | 166k | switch (compString[i]) { |
531 | 82.5k | case 'x': |
532 | 82.5k | selector.push_back(0); |
533 | 82.5k | fieldSet[i] = exyzw; |
534 | 82.5k | break; |
535 | 5.07k | case 'r': |
536 | 5.07k | selector.push_back(0); |
537 | 5.07k | fieldSet[i] = ergba; |
538 | 5.07k | break; |
539 | 1.88k | case 's': |
540 | 1.88k | selector.push_back(0); |
541 | 1.88k | fieldSet[i] = estpq; |
542 | 1.88k | break; |
543 | | |
544 | 38.6k | case 'y': |
545 | 38.6k | selector.push_back(1); |
546 | 38.6k | fieldSet[i] = exyzw; |
547 | 38.6k | break; |
548 | 3.84k | case 'g': |
549 | 3.84k | selector.push_back(1); |
550 | 3.84k | fieldSet[i] = ergba; |
551 | 3.84k | break; |
552 | 1.47k | case 't': |
553 | 1.47k | selector.push_back(1); |
554 | 1.47k | fieldSet[i] = estpq; |
555 | 1.47k | break; |
556 | | |
557 | 17.6k | case 'z': |
558 | 17.6k | selector.push_back(2); |
559 | 17.6k | fieldSet[i] = exyzw; |
560 | 17.6k | break; |
561 | 3.88k | case 'b': |
562 | 3.88k | selector.push_back(2); |
563 | 3.88k | fieldSet[i] = ergba; |
564 | 3.88k | break; |
565 | 395 | case 'p': |
566 | 395 | selector.push_back(2); |
567 | 395 | fieldSet[i] = estpq; |
568 | 395 | break; |
569 | | |
570 | 3.94k | case 'w': |
571 | 3.94k | selector.push_back(3); |
572 | 3.94k | fieldSet[i] = exyzw; |
573 | 3.94k | break; |
574 | 2.61k | case 'a': |
575 | 2.61k | selector.push_back(3); |
576 | 2.61k | fieldSet[i] = ergba; |
577 | 2.61k | break; |
578 | 57 | case 'q': |
579 | 57 | selector.push_back(3); |
580 | 57 | fieldSet[i] = estpq; |
581 | 57 | break; |
582 | | |
583 | 3.97k | default: |
584 | 3.97k | error(loc, "unknown swizzle selection", compString.c_str(), ""); |
585 | 3.97k | break; |
586 | 166k | } |
587 | 166k | } |
588 | | |
589 | | // Additional error checking. |
590 | 271k | for (int i = 0; i < selector.size(); ++i) { |
591 | 160k | if (selector[i] >= vecSize) { |
592 | 4.06k | error(loc, "vector swizzle selection out of range", compString.c_str(), ""); |
593 | 4.06k | selector.resize(i); |
594 | 4.06k | break; |
595 | 4.06k | } |
596 | | |
597 | 156k | if (i > 0 && fieldSet[i] != fieldSet[i-1]) { |
598 | 735 | error(loc, "vector swizzle selectors not from the same set", compString.c_str(), ""); |
599 | 735 | selector.resize(i); |
600 | 735 | break; |
601 | 735 | } |
602 | 156k | } |
603 | | |
604 | | // Ensure it is valid. |
605 | 115k | if (selector.size() == 0) |
606 | 3.10k | selector.push_back(0); |
607 | 115k | } |
608 | | |
609 | | // |
610 | | // Make the passed-in variable information become a member of the |
611 | | // global uniform block. If this doesn't exist yet, make it. |
612 | | // |
613 | | void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) |
614 | 4.52k | { |
615 | | // Make the global block, if not yet made. |
616 | 4.52k | if (globalUniformBlock == nullptr) { |
617 | 1.11k | TQualifier blockQualifier; |
618 | 1.11k | blockQualifier.clear(); |
619 | 1.11k | blockQualifier.storage = EvqUniform; |
620 | 1.11k | TType blockType(new TTypeList, *NewPoolTString(getGlobalUniformBlockName()), blockQualifier); |
621 | 1.11k | setUniformBlockDefaults(blockType); |
622 | 1.11k | globalUniformBlock = new TVariable(NewPoolTString(""), blockType, true); |
623 | 1.11k | firstNewMember = 0; |
624 | 1.11k | } |
625 | | |
626 | | // Update with binding and set |
627 | 4.52k | globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding; |
628 | 4.52k | globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet; |
629 | | |
630 | | // Check for declarations of this default uniform that already exist due to other compilation units. |
631 | 4.52k | TSymbol* symbol = symbolTable.find(memberName); |
632 | 4.52k | if (symbol) { |
633 | 238 | if (memberType != symbol->getType()) { |
634 | 46 | TString err; |
635 | 46 | err += "Redeclaration: already declared as \"" + symbol->getType().getCompleteString() + "\""; |
636 | 46 | error(loc, "", memberName.c_str(), err.c_str()); |
637 | 46 | } |
638 | 238 | return; |
639 | 238 | } |
640 | | |
641 | | // Add the requested member as a member to the global block. |
642 | 4.28k | TType* type = new TType; |
643 | 4.28k | type->shallowCopy(memberType); |
644 | 4.28k | type->setFieldName(memberName); |
645 | 4.28k | if (typeList) |
646 | 6 | type->setStruct(typeList); |
647 | 4.28k | TTypeLoc typeLoc = {type, loc}; |
648 | 4.28k | globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc); |
649 | | |
650 | | // Insert into the symbol table. |
651 | 4.28k | if (firstNewMember == 0) { |
652 | | // This is the first request; we need a normal symbol table insert |
653 | 1.10k | if (symbolTable.insert(*globalUniformBlock)) |
654 | 1.10k | trackLinkage(*globalUniformBlock); |
655 | 0 | else |
656 | 0 | error(loc, "failed to insert the global constant buffer", "uniform", ""); |
657 | 3.18k | } else { |
658 | | // This is a follow-on request; we need to amend the first insert |
659 | 3.18k | symbolTable.amend(*globalUniformBlock, firstNewMember); |
660 | 3.18k | } |
661 | | |
662 | 4.28k | ++firstNewMember; |
663 | 4.28k | } |
664 | | |
665 | 0 | void TParseContextBase::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) { |
666 | | // Make the atomic counter block, if not yet made. |
667 | 0 | const auto &at = atomicCounterBuffers.find(binding); |
668 | 0 | if (at == atomicCounterBuffers.end()) { |
669 | 0 | atomicCounterBuffers.insert({binding, (TVariable*)nullptr }); |
670 | 0 | atomicCounterBlockFirstNewMember.insert({binding, 0}); |
671 | 0 | } |
672 | |
|
673 | 0 | TVariable*& atomicCounterBuffer = atomicCounterBuffers[binding]; |
674 | 0 | int& bufferNewMember = atomicCounterBlockFirstNewMember[binding]; |
675 | |
|
676 | 0 | if (atomicCounterBuffer == nullptr) { |
677 | 0 | TQualifier blockQualifier; |
678 | 0 | blockQualifier.clear(); |
679 | 0 | blockQualifier.storage = EvqBuffer; |
680 | | |
681 | 0 | char charBuffer[512]; |
682 | 0 | if (binding != TQualifier::layoutBindingEnd) { |
683 | 0 | snprintf(charBuffer, 512, "%s_%d", getAtomicCounterBlockName(), binding); |
684 | 0 | } else { |
685 | 0 | snprintf(charBuffer, 512, "%s_0", getAtomicCounterBlockName()); |
686 | 0 | } |
687 | | |
688 | 0 | TType blockType(new TTypeList, *NewPoolTString(charBuffer), blockQualifier); |
689 | 0 | setUniformBlockDefaults(blockType); |
690 | 0 | blockType.getQualifier().layoutPacking = ElpStd430; |
691 | 0 | atomicCounterBuffer = new TVariable(NewPoolTString(""), blockType, true); |
692 | | // If we arn't auto mapping bindings then set the block to use the same |
693 | | // binding as what the atomic was set to use |
694 | 0 | if (!intermediate.getAutoMapBindings()) { |
695 | 0 | atomicCounterBuffer->getWritableType().getQualifier().layoutBinding = binding; |
696 | 0 | } |
697 | 0 | bufferNewMember = 0; |
698 | |
|
699 | 0 | atomicCounterBuffer->getWritableType().getQualifier().layoutSet = atomicCounterBlockSet; |
700 | 0 | } |
701 | | |
702 | | // Add the requested member as a member to the global block. |
703 | 0 | TType* type = new TType; |
704 | 0 | type->shallowCopy(memberType); |
705 | 0 | type->setFieldName(memberName); |
706 | 0 | if (typeList) |
707 | 0 | type->setStruct(typeList); |
708 | 0 | TTypeLoc typeLoc = {type, loc}; |
709 | 0 | atomicCounterBuffer->getType().getWritableStruct()->push_back(typeLoc); |
710 | | |
711 | | // Insert into the symbol table. |
712 | 0 | if (bufferNewMember == 0) { |
713 | | // This is the first request; we need a normal symbol table insert |
714 | 0 | if (symbolTable.insert(*atomicCounterBuffer)) |
715 | 0 | trackLinkage(*atomicCounterBuffer); |
716 | 0 | else |
717 | 0 | error(loc, "failed to insert the global constant buffer", "buffer", ""); |
718 | 0 | } else { |
719 | | // This is a follow-on request; we need to amend the first insert |
720 | 0 | symbolTable.amend(*atomicCounterBuffer, bufferNewMember); |
721 | 0 | } |
722 | |
|
723 | 0 | ++bufferNewMember; |
724 | 0 | } |
725 | | |
726 | | void TParseContextBase::finish() |
727 | 333k | { |
728 | 333k | if (parsingBuiltins) |
729 | 294k | return; |
730 | | |
731 | 38.4k | for (const TString& relaxedSymbol : relaxedSymbols) |
732 | 0 | { |
733 | 0 | TSymbol* symbol = symbolTable.find(relaxedSymbol); |
734 | 0 | TType& type = symbol->getWritableType(); |
735 | 0 | for (const TTypeLoc& typeLoc : *type.getStruct()) |
736 | 0 | { |
737 | 0 | if (typeLoc.type->isOpaque()) |
738 | 0 | { |
739 | 0 | typeLoc.type->getSampler() = TSampler{}; |
740 | 0 | typeLoc.type->setBasicType(EbtInt); |
741 | 0 | TString fieldName("/*"); |
742 | 0 | fieldName.append(typeLoc.type->getFieldName()); |
743 | 0 | fieldName.append("*/"); |
744 | 0 | typeLoc.type->setFieldName(fieldName); |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } |
748 | | |
749 | | // Transfer the linkage symbols to AST nodes, preserving order. |
750 | 38.4k | TIntermAggregate* linkage = new TIntermAggregate; |
751 | 332k | for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i) |
752 | 294k | intermediate.addSymbolLinkageNode(linkage, **i); |
753 | 38.4k | intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable); |
754 | 38.4k | } |
755 | | |
756 | | } // end namespace glslang |