/src/shaderc/third_party/glslang/glslang/MachineIndependent/ParseContextBase.cpp
Line | Count | Source |
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 | 10.5M | { |
56 | 10.5M | const int maxSize = MaxTokenLength + 200; |
57 | 10.5M | char szExtraInfo[maxSize]; |
58 | | |
59 | 10.5M | safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); |
60 | | |
61 | 10.5M | infoSink.info.prefix(prefix); |
62 | 10.5M | infoSink.info.location(loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); |
63 | 10.5M | infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; |
64 | | |
65 | 10.5M | if (prefix == EPrefixError) { |
66 | 10.5M | ++numErrors; |
67 | 10.5M | } |
68 | 10.5M | } |
69 | | |
70 | | void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken, |
71 | | const char* szExtraInfoFormat, ...) |
72 | 7.32M | { |
73 | 7.32M | if (messages & EShMsgOnlyPreprocessor) |
74 | 1.61M | return; |
75 | | // If enhanced msg readability, only print one error |
76 | 5.71M | if (messages & EShMsgEnhanced && numErrors > 0) |
77 | 0 | return; |
78 | 5.71M | va_list args; |
79 | 5.71M | va_start(args, szExtraInfoFormat); |
80 | 5.71M | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
81 | 5.71M | va_end(args); |
82 | | |
83 | 5.71M | if ((messages & EShMsgCascadingErrors) == 0) |
84 | 39 | currentScanner->setEndOfInput(); |
85 | 5.71M | } |
86 | | |
87 | | void C_DECL TParseContextBase::warn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
88 | | const char* szExtraInfoFormat, ...) |
89 | 859 | { |
90 | 859 | if (suppressWarnings()) |
91 | 0 | return; |
92 | 859 | va_list args; |
93 | 859 | va_start(args, szExtraInfoFormat); |
94 | 859 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
95 | 859 | va_end(args); |
96 | 859 | } |
97 | | |
98 | | void C_DECL TParseContextBase::ppError(const TSourceLoc& loc, const char* szReason, const char* szToken, |
99 | | const char* szExtraInfoFormat, ...) |
100 | 4.86M | { |
101 | 4.86M | va_list args; |
102 | 4.86M | va_start(args, szExtraInfoFormat); |
103 | 4.86M | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); |
104 | 4.86M | va_end(args); |
105 | | |
106 | 4.86M | if ((messages & EShMsgCascadingErrors) == 0) |
107 | 0 | currentScanner->setEndOfInput(); |
108 | 4.86M | } |
109 | | |
110 | | void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReason, const char* szToken, |
111 | | const char* szExtraInfoFormat, ...) |
112 | 258 | { |
113 | 258 | va_list args; |
114 | 258 | va_start(args, szExtraInfoFormat); |
115 | 258 | outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixWarning, args); |
116 | 258 | va_end(args); |
117 | 258 | } |
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 | 380k | { |
127 | 380k | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
128 | | |
129 | 380k | const char* symbol = nullptr; |
130 | 380k | TIntermSymbol* symNode = node->getAsSymbolNode(); |
131 | 380k | if (symNode != nullptr) |
132 | 322k | symbol = symNode->getName().c_str(); |
133 | | |
134 | 380k | const char* message = nullptr; |
135 | 380k | switch (node->getQualifier().storage) { |
136 | 373 | case EvqConst: message = "can't modify a const"; break; |
137 | 0 | case EvqConstReadOnly: message = "can't modify a const"; break; |
138 | 3.17k | case EvqUniform: message = "can't modify a uniform"; break; |
139 | 48.4k | case EvqBuffer: |
140 | 48.4k | if (node->getQualifier().isReadOnly()) |
141 | 0 | message = "can't modify a readonly buffer"; |
142 | 48.4k | if (node->getQualifier().isShaderRecord()) |
143 | 0 | message = "can't modify a shaderrecordnv qualified buffer"; |
144 | 48.4k | break; |
145 | 0 | case EvqHitAttr: |
146 | 0 | if (language != EShLangIntersect) |
147 | 0 | message = "cannot modify hitAttributeNV in this stage"; |
148 | 0 | break; |
149 | | |
150 | 328k | default: |
151 | | // |
152 | | // Type that can't be written to? |
153 | | // |
154 | 328k | 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 | 0 | case EbtVoid: |
160 | 0 | message = "can't modify void"; |
161 | 0 | 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 | 0 | case EbtHitObjectEXT: |
175 | 0 | message = "can't modify hitObjectEXT"; |
176 | 0 | break; |
177 | 328k | default: |
178 | 328k | break; |
179 | 328k | } |
180 | 380k | } |
181 | | |
182 | 380k | if (message == nullptr && binaryNode == nullptr && symNode == nullptr) { |
183 | 149 | error(loc, " l-value required", op, "", ""); |
184 | | |
185 | 149 | return true; |
186 | 149 | } |
187 | | |
188 | | // |
189 | | // Everything else is okay, no error. |
190 | | // |
191 | 380k | if (message == nullptr) |
192 | 376k | { |
193 | 376k | if (binaryNode) { |
194 | 57.9k | switch (binaryNode->getOp()) { |
195 | 31.9k | case EOpIndexDirect: |
196 | 32.0k | case EOpIndexIndirect: // fall through |
197 | 57.9k | case EOpIndexDirectStruct: // fall through |
198 | 57.9k | case EOpVectorSwizzle: |
199 | 57.9k | case EOpMatrixSwizzle: |
200 | 57.9k | return lValueErrorCheck(loc, op, binaryNode->getLeft()); |
201 | 0 | default: |
202 | 0 | break; |
203 | 57.9k | } |
204 | 0 | error(loc, " l-value required", op, "", ""); |
205 | |
|
206 | 0 | return true; |
207 | 57.9k | } |
208 | 318k | return false; |
209 | 376k | } |
210 | | |
211 | | // |
212 | | // If we get here, we have an error and a message. |
213 | | // |
214 | 3.54k | const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); |
215 | | |
216 | 3.54k | if (symNode) |
217 | 3.17k | error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); |
218 | 378 | else |
219 | 378 | if (binaryNode && binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct) |
220 | 5 | if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) |
221 | 4 | error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str(), message); |
222 | 1 | else |
223 | 1 | error(loc, " l-value required", op, "\"%s\" (%s)", leftMostTypeNode->getAsSymbolNode()->getName().c_str(), message); |
224 | 373 | else |
225 | 373 | error(loc, " l-value required", op, "(%s)", message); |
226 | | |
227 | 3.54k | return true; |
228 | 380k | } |
229 | | |
230 | | // Test for and give an error if the node can't be read from. |
231 | | void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) |
232 | 1.81M | { |
233 | 1.81M | if (! node) |
234 | 0 | return; |
235 | | |
236 | 1.81M | TIntermBinary* binaryNode = node->getAsBinaryNode(); |
237 | 1.81M | const TIntermSymbol* symNode = node->getAsSymbolNode(); |
238 | | |
239 | 1.81M | if (node->getQualifier().isWriteOnly()) { |
240 | 9 | const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); |
241 | | |
242 | 9 | if (symNode != nullptr) |
243 | 9 | error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); |
244 | 0 | else if (binaryNode && |
245 | 0 | (binaryNode->getAsOperator()->getOp() == EOpIndexDirectStruct || |
246 | 0 | binaryNode->getAsOperator()->getOp() == EOpIndexDirect)) |
247 | 0 | if(IsAnonymous(leftMostTypeNode->getAsSymbolNode()->getName())) |
248 | 0 | error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getAccessName().c_str()); |
249 | 0 | else |
250 | 0 | error(loc, "can't read from writeonly object: ", op, leftMostTypeNode->getAsSymbolNode()->getName().c_str()); |
251 | 0 | else |
252 | 0 | error(loc, "can't read from writeonly object: ", op, ""); |
253 | | |
254 | 1.81M | } else { |
255 | 1.81M | if (binaryNode) { |
256 | 78.0k | switch (binaryNode->getOp()) { |
257 | 17.9k | case EOpIndexDirect: |
258 | 20.6k | case EOpIndexIndirect: |
259 | 29.0k | case EOpIndexDirectStruct: |
260 | 30.5k | case EOpVectorSwizzle: |
261 | 30.5k | case EOpMatrixSwizzle: |
262 | 30.5k | rValueErrorCheck(loc, op, binaryNode->getLeft()); |
263 | 30.5k | break; |
264 | 47.4k | default: |
265 | 47.4k | break; |
266 | 78.0k | } |
267 | 78.0k | } |
268 | 1.81M | } |
269 | 1.81M | } |
270 | | |
271 | | // Add 'symbol' to the list of deferred linkage symbols, which |
272 | | // are later processed in finish(), at which point the symbol |
273 | | // must still be valid. |
274 | | // It is okay if the symbol's type will be subsequently edited; |
275 | | // the modifications will be tracked. |
276 | | // Order is preserved, to avoid creating novel forward references. |
277 | | void TParseContextBase::trackLinkage(TSymbol& symbol) |
278 | 1.93M | { |
279 | 1.93M | if (!parsingBuiltins) |
280 | 115k | linkageSymbols.push_back(&symbol); |
281 | 1.93M | } |
282 | | |
283 | | // Ensure index is in bounds, correct if necessary. |
284 | | // Give an error if not. |
285 | | void TParseContextBase::checkIndex(const TSourceLoc& loc, const TType& type, int64_t& index) |
286 | 31.2k | { |
287 | 31.2k | const auto sizeIsSpecializationExpression = [&type]() { |
288 | 21.9k | return type.containsSpecializationSize() && |
289 | 0 | type.getArraySizes()->getOuterNode() != nullptr && |
290 | 0 | type.getArraySizes()->getOuterNode()->getAsSymbolNode() == nullptr; }; |
291 | | |
292 | 31.2k | if (index < 0) { |
293 | 131 | error(loc, "", "[", "index out of range '%d'", index); |
294 | 131 | index = 0; |
295 | 31.1k | } else if (type.isArray()) { |
296 | 22.5k | if (type.isSizedArray() && !sizeIsSpecializationExpression() && |
297 | 21.9k | index >= type.getOuterArraySize()) { |
298 | 324 | error(loc, "", "[", "array index out of range '%d'", index); |
299 | 324 | index = type.getOuterArraySize() - 1; |
300 | 324 | } |
301 | 22.5k | } else if (type.isVector()) { |
302 | 4.74k | if (index >= type.getVectorSize()) { |
303 | 88 | error(loc, "", "[", "vector index out of range '%d'", index); |
304 | 88 | index = type.getVectorSize() - 1; |
305 | 88 | } |
306 | 4.74k | } else if (type.isMatrix()) { |
307 | 3.84k | if (index >= type.getMatrixCols()) { |
308 | 47 | error(loc, "", "[", "matrix index out of range '%d'", index); |
309 | 47 | index = type.getMatrixCols() - 1; |
310 | 47 | } |
311 | 3.84k | } else if (type.isCoopVecNV()) { |
312 | 0 | if (index >= type.computeNumComponents()) { |
313 | 0 | error(loc, "", "[", "cooperative vector index out of range '%d'", index); |
314 | 0 | index = type.computeNumComponents() - 1; |
315 | 0 | } |
316 | 0 | } |
317 | 31.2k | } |
318 | | |
319 | | // Make a shared symbol have a non-shared version that can be edited by the current |
320 | | // compile, such that editing its type will not change the shared version and will |
321 | | // effect all nodes already sharing it (non-shallow type), |
322 | | // or adopting its full type after being edited (shallow type). |
323 | | void TParseContextBase::makeEditable(TSymbol*& symbol) |
324 | 356 | { |
325 | | // copyUp() does a deep copy of the type. |
326 | 356 | symbol = symbolTable.copyUp(symbol); |
327 | | |
328 | | // Save it (deferred, so it can be edited first) in the AST for linker use. |
329 | 356 | if (symbol) |
330 | 356 | trackLinkage(*symbol); |
331 | 356 | } |
332 | | |
333 | | // Return a writable version of the variable 'name'. |
334 | | // |
335 | | // Return nullptr if 'name' is not found. This should mean |
336 | | // something is seriously wrong (e.g., compiler asking self for |
337 | | // built-in that doesn't exist). |
338 | | TVariable* TParseContextBase::getEditableVariable(const char* name) |
339 | 0 | { |
340 | 0 | bool builtIn; |
341 | 0 | TSymbol* symbol = symbolTable.find(name, &builtIn); |
342 | |
|
343 | 0 | assert(symbol != nullptr); |
344 | 0 | if (symbol == nullptr) |
345 | 0 | return nullptr; |
346 | | |
347 | 0 | if (builtIn) |
348 | 0 | makeEditable(symbol); |
349 | |
|
350 | 0 | return symbol->getAsVariable(); |
351 | 0 | } |
352 | | |
353 | | // Select the best matching function for 'call' from 'candidateList'. |
354 | | // |
355 | | // Assumptions |
356 | | // |
357 | | // There is no exact match, so a selection algorithm needs to run. That is, the |
358 | | // language-specific handler should check for exact match first, to |
359 | | // decide what to do, before calling this selector. |
360 | | // |
361 | | // Input |
362 | | // |
363 | | // * list of candidate signatures to select from |
364 | | // * the call |
365 | | // * a predicate function convertible(from, to) that says whether or not type |
366 | | // 'from' can implicitly convert to type 'to' (it includes the case of what |
367 | | // the calling language would consider a matching type with no conversion |
368 | | // needed) |
369 | | // * a predicate function better(from1, from2, to1, to2) that says whether or |
370 | | // not a conversion from <-> to2 is considered better than a conversion |
371 | | // from <-> to1 (both in and out directions need testing, as declared by the |
372 | | // formal parameter) |
373 | | // |
374 | | // Output |
375 | | // |
376 | | // * best matching candidate (or none, if no viable candidates found) |
377 | | // * whether there was a tie for the best match (ambiguous overload selection, |
378 | | // caller's choice for how to report) |
379 | | // |
380 | | const TFunction* TParseContextBase::selectFunction( |
381 | | const TVector<const TFunction*> candidateList, |
382 | | const TFunction& call, |
383 | | std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible, |
384 | | std::function<bool(const TType& from, const TType& to1, const TType& to2)> better, |
385 | | /* output */ bool& tie) |
386 | 40.4k | { |
387 | | // |
388 | | // Operation |
389 | | // |
390 | | // 1. Prune the input list of candidates down to a list of viable candidates, |
391 | | // where each viable candidate has |
392 | | // |
393 | | // * at least as many parameters as there are calling arguments, with any |
394 | | // remaining parameters being optional or having default values |
395 | | // * each parameter is true under convertible(A, B), where A is the calling |
396 | | // type for in and B is the formal type, and in addition, for out B is the |
397 | | // calling type and A is the formal type |
398 | | // |
399 | | // 2. If there are no viable candidates, return with no match. |
400 | | // |
401 | | // 3. If there is only one viable candidate, it is the best match. |
402 | | // |
403 | | // 4. If there are multiple viable candidates, select the first viable candidate |
404 | | // as the incumbent. Compare the incumbent to the next viable candidate, and if |
405 | | // that candidate is better (bullets below), make it the incumbent. Repeat, with |
406 | | // a linear walk through the viable candidate list. The final incumbent will be |
407 | | // returned as the best match. A viable candidate is better than the incumbent if |
408 | | // |
409 | | // * it has a function argument with a better(...) conversion than the incumbent, |
410 | | // for all directions needed by in and out |
411 | | // * the incumbent has no argument with a better(...) conversion then the |
412 | | // candidate, for either in or out (as needed) |
413 | | // |
414 | | // 5. Check for ambiguity by comparing the best match against all other viable |
415 | | // candidates. If any other viable candidate has a function argument with a |
416 | | // better(...) conversion than the best candidate (for either in or out |
417 | | // directions), return that there was a tie for best. |
418 | | // |
419 | | |
420 | 40.4k | tie = false; |
421 | | |
422 | | // 1. prune to viable... |
423 | 40.4k | TVector<const TFunction*> viableCandidates; |
424 | 1.05M | for (auto it = candidateList.begin(); it != candidateList.end(); ++it) { |
425 | 1.01M | const TFunction& candidate = *(*it); |
426 | | |
427 | | // to even be a potential match, number of arguments must be >= the number of |
428 | | // fixed (non-default) parameters, and <= the total (including parameter with defaults). |
429 | 1.01M | if (call.getParamCount() < candidate.getFixedParamCount() || |
430 | 891k | (call.getParamCount() > candidate.getParamCount() && !candidate.isVariadic())) |
431 | 509k | continue; |
432 | | |
433 | | // see if arguments are convertible |
434 | 509k | bool viable = true; |
435 | | |
436 | | // The call can have fewer parameters than the candidate, if some have defaults. |
437 | 509k | const int paramCount = std::min(call.getParamCount(), candidate.getParamCount()); |
438 | 546k | for (int param = 0; param < paramCount; ++param) { |
439 | 532k | if (candidate[param].type->getQualifier().isParamInput()) { |
440 | 532k | if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) { |
441 | 495k | viable = false; |
442 | 495k | break; |
443 | 495k | } |
444 | 532k | } |
445 | 36.5k | if (candidate[param].type->getQualifier().isParamOutput()) { |
446 | 272 | if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) { |
447 | 56 | viable = false; |
448 | 56 | break; |
449 | 56 | } |
450 | 272 | } |
451 | 36.5k | } |
452 | | |
453 | 509k | if (viable) |
454 | 13.6k | viableCandidates.push_back(&candidate); |
455 | 509k | } |
456 | | |
457 | | // 2. none viable... |
458 | 40.4k | if (viableCandidates.size() == 0) |
459 | 33.9k | return nullptr; |
460 | | |
461 | | // 3. only one viable... |
462 | 6.46k | if (viableCandidates.size() == 1) |
463 | 1.68k | return viableCandidates.front(); |
464 | | |
465 | | // 4. find best... |
466 | 18.6k | const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
467 | | // is call -> can2 better than call -> can1 for any parameter |
468 | 18.6k | bool hasBetterParam = false; |
469 | 18.6k | const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()}); |
470 | 43.0k | for (int param = 0; param < paramCount; ++param) { |
471 | 28.7k | if (better(*call[param].type, *can1[param].type, *can2[param].type)) { |
472 | 4.28k | hasBetterParam = true; |
473 | 4.28k | break; |
474 | 4.28k | } |
475 | 28.7k | } |
476 | 18.6k | return hasBetterParam; |
477 | 18.6k | }; |
478 | | |
479 | 7.15k | const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool { |
480 | | // is call -> can2 equivalent to call -> can1 for all the call parameters? |
481 | 7.15k | const int paramCount = std::min({call.getParamCount(), can1.getParamCount(), can2.getParamCount()}); |
482 | 7.63k | for (int param = 0; param < paramCount; ++param) { |
483 | 7.41k | if (better(*call[param].type, *can1[param].type, *can2[param].type) || |
484 | 7.41k | better(*call[param].type, *can2[param].type, *can1[param].type)) |
485 | 6.94k | return false; |
486 | 7.41k | } |
487 | 215 | return true; |
488 | 7.15k | }; |
489 | | |
490 | 4.77k | const auto enabled = [this](const TFunction& candidate) -> bool { |
491 | 215 | bool enabled = candidate.getNumExtensions() == 0; |
492 | 215 | for (int i = 0; i < candidate.getNumExtensions(); ++i) { |
493 | 0 | TExtensionBehavior behavior = getExtensionBehavior(candidate.getExtensions()[i]); |
494 | 0 | if (behavior == EBhEnable || behavior == EBhRequire) |
495 | 0 | enabled = true; |
496 | 0 | } |
497 | 215 | return enabled; |
498 | 215 | }; |
499 | | |
500 | 4.77k | const TFunction* incumbent = viableCandidates.front(); |
501 | 11.9k | for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) { |
502 | 7.15k | const TFunction& candidate = *(*it); |
503 | 7.15k | if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent)) |
504 | 4.28k | incumbent = &candidate; |
505 | 7.15k | } |
506 | | |
507 | | // 5. ambiguity... |
508 | 16.7k | for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) { |
509 | 11.9k | if (incumbent == *it) |
510 | 4.77k | continue; |
511 | 7.15k | const TFunction& candidate = *(*it); |
512 | | |
513 | | // In the case of default parameters, it may have an identical initial set, which is |
514 | | // also ambiguous |
515 | 7.15k | if ((betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate)) && enabled(candidate)) |
516 | 215 | tie = true; |
517 | 7.15k | } |
518 | | |
519 | 4.77k | return incumbent; |
520 | 6.46k | } |
521 | | |
522 | | // |
523 | | // Look at a '.' field selector string and change it into numerical selectors |
524 | | // for a vector or scalar. |
525 | | // |
526 | | // Always return some form of swizzle, so the result is always usable. |
527 | | // |
528 | | void TParseContextBase::parseSwizzleSelector(const TSourceLoc& loc, const TString& compString, int vecSize, |
529 | | TSwizzleSelectors<TVectorSelector>& selector) |
530 | 59.7k | { |
531 | | // Too long? |
532 | 59.7k | if (compString.size() > MaxSwizzleSelectors) |
533 | 338 | error(loc, "vector swizzle too long", compString.c_str(), ""); |
534 | | |
535 | | // Use this to test that all swizzle characters are from the same swizzle-namespace-set |
536 | 59.7k | enum { |
537 | 59.7k | exyzw, |
538 | 59.7k | ergba, |
539 | 59.7k | estpq, |
540 | 59.7k | } fieldSet[MaxSwizzleSelectors]; |
541 | | |
542 | | // Decode the swizzle string. |
543 | 59.7k | int size = std::min(MaxSwizzleSelectors, (int)compString.size()); |
544 | 136k | for (int i = 0; i < size; ++i) { |
545 | 76.3k | switch (compString[i]) { |
546 | 47.5k | case 'x': |
547 | 47.5k | selector.push_back(0); |
548 | 47.5k | fieldSet[i] = exyzw; |
549 | 47.5k | break; |
550 | 1.04k | case 'r': |
551 | 1.04k | selector.push_back(0); |
552 | 1.04k | fieldSet[i] = ergba; |
553 | 1.04k | break; |
554 | 558 | case 's': |
555 | 558 | selector.push_back(0); |
556 | 558 | fieldSet[i] = estpq; |
557 | 558 | break; |
558 | | |
559 | 16.4k | case 'y': |
560 | 16.4k | selector.push_back(1); |
561 | 16.4k | fieldSet[i] = exyzw; |
562 | 16.4k | break; |
563 | 661 | case 'g': |
564 | 661 | selector.push_back(1); |
565 | 661 | fieldSet[i] = ergba; |
566 | 661 | break; |
567 | 350 | case 't': |
568 | 350 | selector.push_back(1); |
569 | 350 | fieldSet[i] = estpq; |
570 | 350 | break; |
571 | | |
572 | 6.39k | case 'z': |
573 | 6.39k | selector.push_back(2); |
574 | 6.39k | fieldSet[i] = exyzw; |
575 | 6.39k | break; |
576 | 657 | case 'b': |
577 | 657 | selector.push_back(2); |
578 | 657 | fieldSet[i] = ergba; |
579 | 657 | break; |
580 | 125 | case 'p': |
581 | 125 | selector.push_back(2); |
582 | 125 | fieldSet[i] = estpq; |
583 | 125 | break; |
584 | | |
585 | 1.18k | case 'w': |
586 | 1.18k | selector.push_back(3); |
587 | 1.18k | fieldSet[i] = exyzw; |
588 | 1.18k | break; |
589 | 563 | case 'a': |
590 | 563 | selector.push_back(3); |
591 | 563 | fieldSet[i] = ergba; |
592 | 563 | break; |
593 | 9 | case 'q': |
594 | 9 | selector.push_back(3); |
595 | 9 | fieldSet[i] = estpq; |
596 | 9 | break; |
597 | | |
598 | 833 | default: |
599 | 833 | error(loc, "unknown swizzle selection", compString.c_str(), ""); |
600 | 833 | break; |
601 | 76.3k | } |
602 | 76.3k | } |
603 | | |
604 | | // Additional error checking. |
605 | 134k | for (int i = 0; i < selector.size(); ++i) { |
606 | 75.3k | if (selector[i] >= vecSize) { |
607 | 668 | error(loc, "vector swizzle selection out of range", compString.c_str(), ""); |
608 | 668 | selector.resize(i); |
609 | 668 | break; |
610 | 668 | } |
611 | | |
612 | 74.6k | if (i > 0 && fieldSet[i] != fieldSet[i-1]) { |
613 | 256 | error(loc, "vector swizzle selectors not from the same set", compString.c_str(), ""); |
614 | 256 | selector.resize(i); |
615 | 256 | break; |
616 | 256 | } |
617 | 74.6k | } |
618 | | |
619 | | // Ensure it is valid. |
620 | 59.7k | if (selector.size() == 0) |
621 | 445 | selector.push_back(0); |
622 | 59.7k | } |
623 | | |
624 | | // |
625 | | // Make the passed-in variable information become a member of the |
626 | | // global uniform block. If this doesn't exist yet, make it. |
627 | | // |
628 | | void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) |
629 | 0 | { |
630 | | // Make the global block, if not yet made. |
631 | 0 | if (globalUniformBlock == nullptr) { |
632 | 0 | TQualifier blockQualifier; |
633 | 0 | blockQualifier.clear(); |
634 | 0 | blockQualifier.storage = EvqUniform; |
635 | 0 | TType blockType(new TTypeList, *NewPoolTString(getGlobalUniformBlockName()), blockQualifier); |
636 | 0 | setUniformBlockDefaults(blockType); |
637 | 0 | globalUniformBlock = new TVariable(NewPoolTString(""), blockType, true); |
638 | 0 | firstNewMember = 0; |
639 | 0 | } |
640 | | |
641 | | // Update with binding and set |
642 | 0 | globalUniformBlock->getWritableType().getQualifier().layoutBinding = globalUniformBinding; |
643 | 0 | globalUniformBlock->getWritableType().getQualifier().layoutSet = globalUniformSet; |
644 | | |
645 | | // Check for declarations of this default uniform that already exist due to other compilation units. |
646 | 0 | TSymbol* symbol = symbolTable.find(memberName); |
647 | 0 | if (symbol) { |
648 | 0 | if (memberType != symbol->getType()) { |
649 | 0 | TString err; |
650 | 0 | err += "Redeclaration: already declared as \"" + symbol->getType().getCompleteString() + "\""; |
651 | 0 | error(loc, "", memberName.c_str(), err.c_str()); |
652 | 0 | } |
653 | 0 | return; |
654 | 0 | } |
655 | | |
656 | | // Add the requested member as a member to the global block. |
657 | 0 | TType* type = new TType; |
658 | 0 | type->shallowCopy(memberType); |
659 | 0 | type->setFieldName(memberName); |
660 | 0 | if (typeList) |
661 | 0 | type->setStruct(typeList); |
662 | 0 | TTypeLoc typeLoc = {type, loc}; |
663 | 0 | globalUniformBlock->getType().getWritableStruct()->push_back(typeLoc); |
664 | | |
665 | | // Insert into the symbol table. |
666 | 0 | if (firstNewMember == 0) { |
667 | | // This is the first request; we need a normal symbol table insert |
668 | 0 | if (symbolTable.insert(*globalUniformBlock)) |
669 | 0 | trackLinkage(*globalUniformBlock); |
670 | 0 | else |
671 | 0 | error(loc, "failed to insert the global constant buffer", "uniform", ""); |
672 | 0 | } else { |
673 | | // This is a follow-on request; we need to amend the first insert |
674 | 0 | symbolTable.amend(*globalUniformBlock, firstNewMember); |
675 | 0 | } |
676 | |
|
677 | 0 | ++firstNewMember; |
678 | 0 | } |
679 | | |
680 | 0 | void TParseContextBase::growAtomicCounterBlock(int binding, const TSourceLoc& loc, TType& memberType, const TString& memberName, TTypeList* typeList) { |
681 | | // Make the atomic counter block, if not yet made. |
682 | 0 | const auto &at = atomicCounterBuffers.find(binding); |
683 | 0 | if (at == atomicCounterBuffers.end()) { |
684 | 0 | atomicCounterBuffers.insert({binding, (TVariable*)nullptr }); |
685 | 0 | atomicCounterBlockFirstNewMember.insert({binding, 0}); |
686 | 0 | } |
687 | |
|
688 | 0 | TVariable*& atomicCounterBuffer = atomicCounterBuffers[binding]; |
689 | 0 | int& bufferNewMember = atomicCounterBlockFirstNewMember[binding]; |
690 | |
|
691 | 0 | if (atomicCounterBuffer == nullptr) { |
692 | 0 | TQualifier blockQualifier; |
693 | 0 | blockQualifier.clear(); |
694 | 0 | blockQualifier.storage = EvqBuffer; |
695 | | |
696 | 0 | char charBuffer[512]; |
697 | 0 | if (binding != TQualifier::layoutBindingEnd) { |
698 | 0 | snprintf(charBuffer, 512, "%s_%d", getAtomicCounterBlockName(), binding); |
699 | 0 | } else { |
700 | 0 | snprintf(charBuffer, 512, "%s_0", getAtomicCounterBlockName()); |
701 | 0 | } |
702 | | |
703 | 0 | TType blockType(new TTypeList, *NewPoolTString(charBuffer), blockQualifier); |
704 | 0 | setUniformBlockDefaults(blockType); |
705 | 0 | blockType.getQualifier().layoutPacking = ElpStd430; |
706 | 0 | atomicCounterBuffer = new TVariable(NewPoolTString(""), blockType, true); |
707 | | // If we arn't auto mapping bindings then set the block to use the same |
708 | | // binding as what the atomic was set to use |
709 | 0 | if (!intermediate.getAutoMapBindings()) { |
710 | 0 | atomicCounterBuffer->getWritableType().getQualifier().layoutBinding = binding; |
711 | 0 | } |
712 | 0 | bufferNewMember = 0; |
713 | |
|
714 | 0 | atomicCounterBuffer->getWritableType().getQualifier().layoutSet = atomicCounterBlockSet; |
715 | 0 | } |
716 | | |
717 | | // Add the requested member as a member to the global block. |
718 | 0 | TType* type = new TType; |
719 | 0 | type->shallowCopy(memberType); |
720 | 0 | type->setFieldName(memberName); |
721 | 0 | if (typeList) |
722 | 0 | type->setStruct(typeList); |
723 | 0 | TTypeLoc typeLoc = {type, loc}; |
724 | 0 | atomicCounterBuffer->getType().getWritableStruct()->push_back(typeLoc); |
725 | | |
726 | | // Insert into the symbol table. |
727 | 0 | if (bufferNewMember == 0) { |
728 | | // This is the first request; we need a normal symbol table insert |
729 | 0 | if (symbolTable.insert(*atomicCounterBuffer)) |
730 | 0 | trackLinkage(*atomicCounterBuffer); |
731 | 0 | else |
732 | 0 | error(loc, "failed to insert the global constant buffer", "buffer", ""); |
733 | 0 | } else { |
734 | | // This is a follow-on request; we need to amend the first insert |
735 | 0 | symbolTable.amend(*atomicCounterBuffer, bufferNewMember); |
736 | 0 | } |
737 | |
|
738 | 0 | ++bufferNewMember; |
739 | 0 | } |
740 | | |
741 | | void TParseContextBase::finish() |
742 | 56.0k | { |
743 | 56.0k | if (parsingBuiltins) |
744 | 49.3k | return; |
745 | | |
746 | 6.70k | for (const TString& relaxedSymbol : relaxedSymbols) |
747 | 0 | { |
748 | 0 | TSymbol* symbol = symbolTable.find(relaxedSymbol); |
749 | 0 | TType& type = symbol->getWritableType(); |
750 | 0 | for (const TTypeLoc& typeLoc : *type.getStruct()) |
751 | 0 | { |
752 | 0 | if (typeLoc.type->isOpaque()) |
753 | 0 | { |
754 | 0 | typeLoc.type->getSampler() = TSampler{}; |
755 | 0 | typeLoc.type->setBasicType(EbtInt); |
756 | 0 | TString fieldName("/*"); |
757 | 0 | fieldName.append(typeLoc.type->getFieldName()); |
758 | 0 | fieldName.append("*/"); |
759 | 0 | typeLoc.type->setFieldName(fieldName); |
760 | 0 | } |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | | // Transfer the linkage symbols to AST nodes, preserving order. |
765 | 6.70k | TIntermAggregate* linkage = new TIntermAggregate; |
766 | 122k | for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i) |
767 | 115k | intermediate.addSymbolLinkageNode(linkage, **i); |
768 | 6.70k | intermediate.addSymbolLinkageNodes(linkage, getLanguage(), symbolTable); |
769 | 6.70k | } |
770 | | |
771 | | } // end namespace glslang |