1 | // |
2 | // Copyright (c) 2002-2014 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 | #include "compiler/translator/ParseContext.h" |
8 | |
9 | #include <stdarg.h> |
10 | #include <stdio.h> |
11 | |
12 | #include "common/mathutil.h" |
13 | #include "compiler/preprocessor/SourceLocation.h" |
14 | #include "compiler/translator/Declarator.h" |
15 | #include "compiler/translator/ParseContext_autogen.h" |
16 | #include "compiler/translator/StaticType.h" |
17 | #include "compiler/translator/ValidateGlobalInitializer.h" |
18 | #include "compiler/translator/ValidateSwitch.h" |
19 | #include "compiler/translator/glslang.h" |
20 | #include "compiler/translator/tree_util/IntermNode_util.h" |
21 | #include "compiler/translator/util.h" |
22 | |
23 | namespace sh |
24 | { |
25 | |
26 | /////////////////////////////////////////////////////////////////////// |
27 | // |
28 | // Sub- vector and matrix fields |
29 | // |
30 | //////////////////////////////////////////////////////////////////////// |
31 | |
32 | namespace |
33 | { |
34 | |
35 | const int kWebGLMaxStructNesting = 4; |
36 | |
37 | bool ContainsSampler(const TStructure *structType); |
38 | |
39 | bool ContainsSampler(const TType &type) |
40 | { |
41 | if (IsSampler(type.getBasicType())) |
42 | { |
43 | return true; |
44 | } |
45 | if (type.getBasicType() == EbtStruct) |
46 | { |
47 | return ContainsSampler(type.getStruct()); |
48 | } |
49 | |
50 | return false; |
51 | } |
52 | |
53 | bool ContainsSampler(const TStructure *structType) |
54 | { |
55 | for (const auto &field : structType->fields()) |
56 | { |
57 | if (ContainsSampler(*field->type())) |
58 | return true; |
59 | } |
60 | return false; |
61 | } |
62 | |
63 | // Get a token from an image argument to use as an error message token. |
64 | const char *GetImageArgumentToken(TIntermTyped *imageNode) |
65 | { |
66 | ASSERT(IsImage(imageNode->getBasicType())); |
67 | while (imageNode->getAsBinaryNode() && |
68 | (imageNode->getAsBinaryNode()->getOp() == EOpIndexIndirect || |
69 | imageNode->getAsBinaryNode()->getOp() == EOpIndexDirect)) |
70 | { |
71 | imageNode = imageNode->getAsBinaryNode()->getLeft(); |
72 | } |
73 | TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode(); |
74 | if (imageSymbol) |
75 | { |
76 | return imageSymbol->getName().data(); |
77 | } |
78 | return "image" ; |
79 | } |
80 | |
81 | bool CanSetDefaultPrecisionOnType(const TPublicType &type) |
82 | { |
83 | if (!SupportsPrecision(type.getBasicType())) |
84 | { |
85 | return false; |
86 | } |
87 | if (type.getBasicType() == EbtUInt) |
88 | { |
89 | // ESSL 3.00.4 section 4.5.4 |
90 | return false; |
91 | } |
92 | if (type.isAggregate()) |
93 | { |
94 | // Not allowed to set for aggregate types |
95 | return false; |
96 | } |
97 | return true; |
98 | } |
99 | |
100 | // Map input primitive types to input array sizes in a geometry shader. |
101 | GLuint GetGeometryShaderInputArraySize(TLayoutPrimitiveType primitiveType) |
102 | { |
103 | switch (primitiveType) |
104 | { |
105 | case EptPoints: |
106 | return 1u; |
107 | case EptLines: |
108 | return 2u; |
109 | case EptTriangles: |
110 | return 3u; |
111 | case EptLinesAdjacency: |
112 | return 4u; |
113 | case EptTrianglesAdjacency: |
114 | return 6u; |
115 | default: |
116 | UNREACHABLE(); |
117 | return 0u; |
118 | } |
119 | } |
120 | |
121 | bool IsBufferOrSharedVariable(TIntermTyped *var) |
122 | { |
123 | if (var->isInterfaceBlock() || var->getQualifier() == EvqBuffer || |
124 | var->getQualifier() == EvqShared) |
125 | { |
126 | return true; |
127 | } |
128 | return false; |
129 | } |
130 | |
131 | } // namespace |
132 | |
133 | // This tracks each binding point's current default offset for inheritance of subsequent |
134 | // variables using the same binding, and keeps offsets unique and non overlapping. |
135 | // See GLSL ES 3.1, section 4.4.6. |
136 | class TParseContext::AtomicCounterBindingState |
137 | { |
138 | public: |
139 | AtomicCounterBindingState() : mDefaultOffset(0) {} |
140 | // Inserts a new span and returns -1 if overlapping, else returns the starting offset of |
141 | // newly inserted span. |
142 | int insertSpan(int start, size_t length) |
143 | { |
144 | gl::RangeI newSpan(start, start + static_cast<int>(length)); |
145 | for (const auto &span : mSpans) |
146 | { |
147 | if (newSpan.intersects(span)) |
148 | { |
149 | return -1; |
150 | } |
151 | } |
152 | mSpans.push_back(newSpan); |
153 | mDefaultOffset = newSpan.high(); |
154 | return start; |
155 | } |
156 | // Inserts a new span starting from the default offset. |
157 | int appendSpan(size_t length) { return insertSpan(mDefaultOffset, length); } |
158 | void setDefaultOffset(int offset) { mDefaultOffset = offset; } |
159 | |
160 | private: |
161 | int mDefaultOffset; |
162 | std::vector<gl::RangeI> mSpans; |
163 | }; |
164 | |
165 | TParseContext::TParseContext(TSymbolTable &symt, |
166 | TExtensionBehavior &ext, |
167 | sh::GLenum type, |
168 | ShShaderSpec spec, |
169 | ShCompileOptions options, |
170 | bool checksPrecErrors, |
171 | TDiagnostics *diagnostics, |
172 | const ShBuiltInResources &resources) |
173 | : symbolTable(symt), |
174 | mDeferredNonEmptyDeclarationErrorCheck(false), |
175 | mShaderType(type), |
176 | mShaderSpec(spec), |
177 | mCompileOptions(options), |
178 | mShaderVersion(100), |
179 | mTreeRoot(nullptr), |
180 | mLoopNestingLevel(0), |
181 | mStructNestingLevel(0), |
182 | mSwitchNestingLevel(0), |
183 | mCurrentFunctionType(nullptr), |
184 | mFunctionReturnsValue(false), |
185 | mChecksPrecisionErrors(checksPrecErrors), |
186 | mFragmentPrecisionHighOnESSL1(false), |
187 | mDefaultUniformMatrixPacking(EmpColumnMajor), |
188 | mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), |
189 | mDefaultBufferMatrixPacking(EmpColumnMajor), |
190 | mDefaultBufferBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), |
191 | mDiagnostics(diagnostics), |
192 | mDirectiveHandler(ext, |
193 | *mDiagnostics, |
194 | mShaderVersion, |
195 | mShaderType, |
196 | resources.WEBGL_debug_shader_precision == 1), |
197 | mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings(spec)), |
198 | mScanner(nullptr), |
199 | mMinProgramTexelOffset(resources.MinProgramTexelOffset), |
200 | mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), |
201 | mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset), |
202 | mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset), |
203 | mComputeShaderLocalSizeDeclared(false), |
204 | mComputeShaderLocalSize(-1), |
205 | mNumViews(-1), |
206 | mMaxNumViews(resources.MaxViewsOVR), |
207 | mMaxImageUnits(resources.MaxImageUnits), |
208 | mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits), |
209 | mMaxUniformLocations(resources.MaxUniformLocations), |
210 | mMaxUniformBufferBindings(resources.MaxUniformBufferBindings), |
211 | mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings), |
212 | mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings), |
213 | mDeclaringFunction(false), |
214 | mGeometryShaderInputPrimitiveType(EptUndefined), |
215 | mGeometryShaderOutputPrimitiveType(EptUndefined), |
216 | mGeometryShaderInvocations(0), |
217 | mGeometryShaderMaxVertices(-1), |
218 | mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations), |
219 | mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices) |
220 | {} |
221 | |
222 | TParseContext::~TParseContext() {} |
223 | |
224 | bool TParseContext::parseVectorFields(const TSourceLoc &line, |
225 | const ImmutableString &compString, |
226 | int vecSize, |
227 | TVector<int> *fieldOffsets) |
228 | { |
229 | ASSERT(fieldOffsets); |
230 | size_t fieldCount = compString.length(); |
231 | if (fieldCount > 4u) |
232 | { |
233 | error(line, "illegal vector field selection" , compString); |
234 | return false; |
235 | } |
236 | fieldOffsets->resize(fieldCount); |
237 | |
238 | enum |
239 | { |
240 | exyzw, |
241 | ergba, |
242 | estpq |
243 | } fieldSet[4]; |
244 | |
245 | for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) |
246 | { |
247 | switch (compString[i]) |
248 | { |
249 | case 'x': |
250 | (*fieldOffsets)[i] = 0; |
251 | fieldSet[i] = exyzw; |
252 | break; |
253 | case 'r': |
254 | (*fieldOffsets)[i] = 0; |
255 | fieldSet[i] = ergba; |
256 | break; |
257 | case 's': |
258 | (*fieldOffsets)[i] = 0; |
259 | fieldSet[i] = estpq; |
260 | break; |
261 | case 'y': |
262 | (*fieldOffsets)[i] = 1; |
263 | fieldSet[i] = exyzw; |
264 | break; |
265 | case 'g': |
266 | (*fieldOffsets)[i] = 1; |
267 | fieldSet[i] = ergba; |
268 | break; |
269 | case 't': |
270 | (*fieldOffsets)[i] = 1; |
271 | fieldSet[i] = estpq; |
272 | break; |
273 | case 'z': |
274 | (*fieldOffsets)[i] = 2; |
275 | fieldSet[i] = exyzw; |
276 | break; |
277 | case 'b': |
278 | (*fieldOffsets)[i] = 2; |
279 | fieldSet[i] = ergba; |
280 | break; |
281 | case 'p': |
282 | (*fieldOffsets)[i] = 2; |
283 | fieldSet[i] = estpq; |
284 | break; |
285 | |
286 | case 'w': |
287 | (*fieldOffsets)[i] = 3; |
288 | fieldSet[i] = exyzw; |
289 | break; |
290 | case 'a': |
291 | (*fieldOffsets)[i] = 3; |
292 | fieldSet[i] = ergba; |
293 | break; |
294 | case 'q': |
295 | (*fieldOffsets)[i] = 3; |
296 | fieldSet[i] = estpq; |
297 | break; |
298 | default: |
299 | error(line, "illegal vector field selection" , compString); |
300 | return false; |
301 | } |
302 | } |
303 | |
304 | for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) |
305 | { |
306 | if ((*fieldOffsets)[i] >= vecSize) |
307 | { |
308 | error(line, "vector field selection out of range" , compString); |
309 | return false; |
310 | } |
311 | |
312 | if (i > 0) |
313 | { |
314 | if (fieldSet[i] != fieldSet[i - 1]) |
315 | { |
316 | error(line, "illegal - vector component fields not from the same set" , compString); |
317 | return false; |
318 | } |
319 | } |
320 | } |
321 | |
322 | return true; |
323 | } |
324 | |
325 | /////////////////////////////////////////////////////////////////////// |
326 | // |
327 | // Errors |
328 | // |
329 | //////////////////////////////////////////////////////////////////////// |
330 | |
331 | // |
332 | // Used by flex/bison to output all syntax and parsing errors. |
333 | // |
334 | void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token) |
335 | { |
336 | mDiagnostics->error(loc, reason, token); |
337 | } |
338 | |
339 | void TParseContext::error(const TSourceLoc &loc, const char *reason, const ImmutableString &token) |
340 | { |
341 | mDiagnostics->error(loc, reason, token.data()); |
342 | } |
343 | |
344 | void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token) |
345 | { |
346 | mDiagnostics->warning(loc, reason, token); |
347 | } |
348 | |
349 | void TParseContext::outOfRangeError(bool isError, |
350 | const TSourceLoc &loc, |
351 | const char *reason, |
352 | const char *token) |
353 | { |
354 | if (isError) |
355 | { |
356 | error(loc, reason, token); |
357 | } |
358 | else |
359 | { |
360 | warning(loc, reason, token); |
361 | } |
362 | } |
363 | |
364 | // |
365 | // Same error message for all places assignments don't work. |
366 | // |
367 | void TParseContext::assignError(const TSourceLoc &line, |
368 | const char *op, |
369 | const TType &left, |
370 | const TType &right) |
371 | { |
372 | TInfoSinkBase reasonStream; |
373 | reasonStream << "cannot convert from '" << right << "' to '" << left << "'" ; |
374 | error(line, reasonStream.c_str(), op); |
375 | } |
376 | |
377 | // |
378 | // Same error message for all places unary operations don't work. |
379 | // |
380 | void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, const TType &operand) |
381 | { |
382 | TInfoSinkBase reasonStream; |
383 | reasonStream << "wrong operand type - no operation '" << op |
384 | << "' exists that takes an operand of type " << operand |
385 | << " (or there is no acceptable conversion)" ; |
386 | error(line, reasonStream.c_str(), op); |
387 | } |
388 | |
389 | // |
390 | // Same error message for all binary operations don't work. |
391 | // |
392 | void TParseContext::binaryOpError(const TSourceLoc &line, |
393 | const char *op, |
394 | const TType &left, |
395 | const TType &right) |
396 | { |
397 | TInfoSinkBase reasonStream; |
398 | reasonStream << "wrong operand types - no operation '" << op |
399 | << "' exists that takes a left-hand operand of type '" << left |
400 | << "' and a right operand of type '" << right |
401 | << "' (or there is no acceptable conversion)" ; |
402 | error(line, reasonStream.c_str(), op); |
403 | } |
404 | |
405 | void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, |
406 | TPrecision precision, |
407 | TBasicType type) |
408 | { |
409 | if (!mChecksPrecisionErrors) |
410 | return; |
411 | |
412 | if (precision != EbpUndefined && !SupportsPrecision(type)) |
413 | { |
414 | error(line, "illegal type for precision qualifier" , getBasicString(type)); |
415 | } |
416 | |
417 | if (precision == EbpUndefined) |
418 | { |
419 | switch (type) |
420 | { |
421 | case EbtFloat: |
422 | error(line, "No precision specified for (float)" , "" ); |
423 | return; |
424 | case EbtInt: |
425 | case EbtUInt: |
426 | UNREACHABLE(); // there's always a predeclared qualifier |
427 | error(line, "No precision specified (int)" , "" ); |
428 | return; |
429 | default: |
430 | if (IsOpaqueType(type)) |
431 | { |
432 | error(line, "No precision specified" , getBasicString(type)); |
433 | return; |
434 | } |
435 | } |
436 | } |
437 | } |
438 | |
439 | void TParseContext::markStaticReadIfSymbol(TIntermNode *node) |
440 | { |
441 | TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); |
442 | if (swizzleNode) |
443 | { |
444 | markStaticReadIfSymbol(swizzleNode->getOperand()); |
445 | return; |
446 | } |
447 | TIntermBinary *binaryNode = node->getAsBinaryNode(); |
448 | if (binaryNode) |
449 | { |
450 | switch (binaryNode->getOp()) |
451 | { |
452 | case EOpIndexDirect: |
453 | case EOpIndexIndirect: |
454 | case EOpIndexDirectStruct: |
455 | case EOpIndexDirectInterfaceBlock: |
456 | markStaticReadIfSymbol(binaryNode->getLeft()); |
457 | return; |
458 | default: |
459 | return; |
460 | } |
461 | } |
462 | TIntermSymbol *symbolNode = node->getAsSymbolNode(); |
463 | if (symbolNode) |
464 | { |
465 | symbolTable.markStaticRead(symbolNode->variable()); |
466 | } |
467 | } |
468 | |
469 | // Both test and if necessary, spit out an error, to see if the node is really |
470 | // an l-value that can be operated on this way. |
471 | bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node) |
472 | { |
473 | TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); |
474 | if (swizzleNode) |
475 | { |
476 | bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand()); |
477 | if (ok && swizzleNode->hasDuplicateOffsets()) |
478 | { |
479 | error(line, " l-value of swizzle cannot have duplicate components" , op); |
480 | return false; |
481 | } |
482 | return ok; |
483 | } |
484 | |
485 | TIntermBinary *binaryNode = node->getAsBinaryNode(); |
486 | if (binaryNode) |
487 | { |
488 | switch (binaryNode->getOp()) |
489 | { |
490 | case EOpIndexDirect: |
491 | case EOpIndexIndirect: |
492 | case EOpIndexDirectStruct: |
493 | case EOpIndexDirectInterfaceBlock: |
494 | if (node->getMemoryQualifier().readonly) |
495 | { |
496 | error(line, "can't modify a readonly variable" , op); |
497 | return false; |
498 | } |
499 | return checkCanBeLValue(line, op, binaryNode->getLeft()); |
500 | default: |
501 | break; |
502 | } |
503 | error(line, " l-value required" , op); |
504 | return false; |
505 | } |
506 | |
507 | std::string message; |
508 | switch (node->getQualifier()) |
509 | { |
510 | case EvqConst: |
511 | message = "can't modify a const" ; |
512 | break; |
513 | case EvqConstReadOnly: |
514 | message = "can't modify a const" ; |
515 | break; |
516 | case EvqAttribute: |
517 | message = "can't modify an attribute" ; |
518 | break; |
519 | case EvqFragmentIn: |
520 | case EvqVertexIn: |
521 | case EvqGeometryIn: |
522 | case EvqFlatIn: |
523 | case EvqSmoothIn: |
524 | case EvqCentroidIn: |
525 | message = "can't modify an input" ; |
526 | break; |
527 | case EvqUniform: |
528 | message = "can't modify a uniform" ; |
529 | break; |
530 | case EvqVaryingIn: |
531 | message = "can't modify a varying" ; |
532 | break; |
533 | case EvqFragCoord: |
534 | message = "can't modify gl_FragCoord" ; |
535 | break; |
536 | case EvqFrontFacing: |
537 | message = "can't modify gl_FrontFacing" ; |
538 | break; |
539 | case EvqPointCoord: |
540 | message = "can't modify gl_PointCoord" ; |
541 | break; |
542 | case EvqNumWorkGroups: |
543 | message = "can't modify gl_NumWorkGroups" ; |
544 | break; |
545 | case EvqWorkGroupSize: |
546 | message = "can't modify gl_WorkGroupSize" ; |
547 | break; |
548 | case EvqWorkGroupID: |
549 | message = "can't modify gl_WorkGroupID" ; |
550 | break; |
551 | case EvqLocalInvocationID: |
552 | message = "can't modify gl_LocalInvocationID" ; |
553 | break; |
554 | case EvqGlobalInvocationID: |
555 | message = "can't modify gl_GlobalInvocationID" ; |
556 | break; |
557 | case EvqLocalInvocationIndex: |
558 | message = "can't modify gl_LocalInvocationIndex" ; |
559 | break; |
560 | case EvqViewIDOVR: |
561 | message = "can't modify gl_ViewID_OVR" ; |
562 | break; |
563 | case EvqComputeIn: |
564 | message = "can't modify work group size variable" ; |
565 | break; |
566 | case EvqPerVertexIn: |
567 | message = "can't modify any member in gl_in" ; |
568 | break; |
569 | case EvqPrimitiveIDIn: |
570 | message = "can't modify gl_PrimitiveIDIn" ; |
571 | break; |
572 | case EvqInvocationID: |
573 | message = "can't modify gl_InvocationID" ; |
574 | break; |
575 | case EvqPrimitiveID: |
576 | if (mShaderType == GL_FRAGMENT_SHADER) |
577 | { |
578 | message = "can't modify gl_PrimitiveID in a fragment shader" ; |
579 | } |
580 | break; |
581 | case EvqLayer: |
582 | if (mShaderType == GL_FRAGMENT_SHADER) |
583 | { |
584 | message = "can't modify gl_Layer in a fragment shader" ; |
585 | } |
586 | break; |
587 | default: |
588 | // |
589 | // Type that can't be written to? |
590 | // |
591 | if (node->getBasicType() == EbtVoid) |
592 | { |
593 | message = "can't modify void" ; |
594 | } |
595 | if (IsOpaqueType(node->getBasicType())) |
596 | { |
597 | message = "can't modify a variable with type " ; |
598 | message += getBasicString(node->getBasicType()); |
599 | } |
600 | else if (node->getMemoryQualifier().readonly) |
601 | { |
602 | message = "can't modify a readonly variable" ; |
603 | } |
604 | } |
605 | |
606 | ASSERT(binaryNode == nullptr && swizzleNode == nullptr); |
607 | TIntermSymbol *symNode = node->getAsSymbolNode(); |
608 | if (message.empty() && symNode != nullptr) |
609 | { |
610 | symbolTable.markStaticWrite(symNode->variable()); |
611 | return true; |
612 | } |
613 | |
614 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
615 | reasonStream << "l-value required" ; |
616 | if (!message.empty()) |
617 | { |
618 | if (symNode) |
619 | { |
620 | // Symbol inside an expression can't be nameless. |
621 | ASSERT(symNode->variable().symbolType() != SymbolType::Empty); |
622 | const ImmutableString &symbol = symNode->getName(); |
623 | reasonStream << " (" << message << " \"" << symbol << "\")" ; |
624 | } |
625 | else |
626 | { |
627 | reasonStream << " (" << message << ")" ; |
628 | } |
629 | } |
630 | std::string reason = reasonStream.str(); |
631 | error(line, reason.c_str(), op); |
632 | |
633 | return false; |
634 | } |
635 | |
636 | // Both test, and if necessary spit out an error, to see if the node is really |
637 | // a constant. |
638 | void TParseContext::checkIsConst(TIntermTyped *node) |
639 | { |
640 | if (node->getQualifier() != EvqConst) |
641 | { |
642 | error(node->getLine(), "constant expression required" , "" ); |
643 | } |
644 | } |
645 | |
646 | // Both test, and if necessary spit out an error, to see if the node is really |
647 | // an integer. |
648 | void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token) |
649 | { |
650 | if (!node->isScalarInt()) |
651 | { |
652 | error(node->getLine(), "integer expression required" , token); |
653 | } |
654 | } |
655 | |
656 | // Both test, and if necessary spit out an error, to see if we are currently |
657 | // globally scoped. |
658 | bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token) |
659 | { |
660 | if (!symbolTable.atGlobalLevel()) |
661 | { |
662 | error(line, "only allowed at global scope" , token); |
663 | return false; |
664 | } |
665 | return true; |
666 | } |
667 | |
668 | // ESSL 3.00.5 sections 3.8 and 3.9. |
669 | // If it starts "gl_" or contains two consecutive underscores, it's reserved. |
670 | // Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a webgl shader. |
671 | bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier) |
672 | { |
673 | static const char *reservedErrMsg = "reserved built-in name" ; |
674 | if (identifier.beginsWith("gl_" )) |
675 | { |
676 | error(line, reservedErrMsg, "gl_" ); |
677 | return false; |
678 | } |
679 | if (sh::IsWebGLBasedSpec(mShaderSpec)) |
680 | { |
681 | if (identifier.beginsWith("webgl_" )) |
682 | { |
683 | error(line, reservedErrMsg, "webgl_" ); |
684 | return false; |
685 | } |
686 | if (identifier.beginsWith("_webgl_" )) |
687 | { |
688 | error(line, reservedErrMsg, "_webgl_" ); |
689 | return false; |
690 | } |
691 | } |
692 | if (identifier.contains("__" )) |
693 | { |
694 | error(line, |
695 | "identifiers containing two consecutive underscores (__) are reserved as " |
696 | "possible future keywords" , |
697 | identifier); |
698 | return false; |
699 | } |
700 | return true; |
701 | } |
702 | |
703 | // Make sure the argument types are correct for constructing a specific type. |
704 | bool TParseContext::checkConstructorArguments(const TSourceLoc &line, |
705 | const TIntermSequence &arguments, |
706 | const TType &type) |
707 | { |
708 | if (arguments.empty()) |
709 | { |
710 | error(line, "constructor does not have any arguments" , "constructor" ); |
711 | return false; |
712 | } |
713 | |
714 | for (TIntermNode *arg : arguments) |
715 | { |
716 | markStaticReadIfSymbol(arg); |
717 | const TIntermTyped *argTyped = arg->getAsTyped(); |
718 | ASSERT(argTyped != nullptr); |
719 | if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType())) |
720 | { |
721 | std::string reason("cannot convert a variable with type " ); |
722 | reason += getBasicString(argTyped->getBasicType()); |
723 | error(line, reason.c_str(), "constructor" ); |
724 | return false; |
725 | } |
726 | else if (argTyped->getMemoryQualifier().writeonly) |
727 | { |
728 | error(line, "cannot convert a variable with writeonly" , "constructor" ); |
729 | return false; |
730 | } |
731 | if (argTyped->getBasicType() == EbtVoid) |
732 | { |
733 | error(line, "cannot convert a void" , "constructor" ); |
734 | return false; |
735 | } |
736 | } |
737 | |
738 | if (type.isArray()) |
739 | { |
740 | // The size of an unsized constructor should already have been determined. |
741 | ASSERT(!type.isUnsizedArray()); |
742 | if (static_cast<size_t>(type.getOutermostArraySize()) != arguments.size()) |
743 | { |
744 | error(line, "array constructor needs one argument per array element" , "constructor" ); |
745 | return false; |
746 | } |
747 | // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of |
748 | // the array. |
749 | for (TIntermNode *const &argNode : arguments) |
750 | { |
751 | const TType &argType = argNode->getAsTyped()->getType(); |
752 | if (mShaderVersion < 310 && argType.isArray()) |
753 | { |
754 | error(line, "constructing from a non-dereferenced array" , "constructor" ); |
755 | return false; |
756 | } |
757 | if (!argType.isElementTypeOf(type)) |
758 | { |
759 | error(line, "Array constructor argument has an incorrect type" , "constructor" ); |
760 | return false; |
761 | } |
762 | } |
763 | } |
764 | else if (type.getBasicType() == EbtStruct) |
765 | { |
766 | const TFieldList &fields = type.getStruct()->fields(); |
767 | if (fields.size() != arguments.size()) |
768 | { |
769 | error(line, |
770 | "Number of constructor parameters does not match the number of structure fields" , |
771 | "constructor" ); |
772 | return false; |
773 | } |
774 | |
775 | for (size_t i = 0; i < fields.size(); i++) |
776 | { |
777 | if (i >= arguments.size() || |
778 | arguments[i]->getAsTyped()->getType() != *fields[i]->type()) |
779 | { |
780 | error(line, "Structure constructor arguments do not match structure fields" , |
781 | "constructor" ); |
782 | return false; |
783 | } |
784 | } |
785 | } |
786 | else |
787 | { |
788 | // We're constructing a scalar, vector, or matrix. |
789 | |
790 | // Note: It's okay to have too many components available, but not okay to have unused |
791 | // arguments. 'full' will go to true when enough args have been seen. If we loop again, |
792 | // there is an extra argument, so 'overFull' will become true. |
793 | |
794 | size_t size = 0; |
795 | bool full = false; |
796 | bool overFull = false; |
797 | bool matrixArg = false; |
798 | for (TIntermNode *arg : arguments) |
799 | { |
800 | const TIntermTyped *argTyped = arg->getAsTyped(); |
801 | ASSERT(argTyped != nullptr); |
802 | |
803 | if (argTyped->getBasicType() == EbtStruct) |
804 | { |
805 | error(line, "a struct cannot be used as a constructor argument for this type" , |
806 | "constructor" ); |
807 | return false; |
808 | } |
809 | if (argTyped->getType().isArray()) |
810 | { |
811 | error(line, "constructing from a non-dereferenced array" , "constructor" ); |
812 | return false; |
813 | } |
814 | if (argTyped->getType().isMatrix()) |
815 | { |
816 | matrixArg = true; |
817 | } |
818 | |
819 | size += argTyped->getType().getObjectSize(); |
820 | if (full) |
821 | { |
822 | overFull = true; |
823 | } |
824 | if (size >= type.getObjectSize()) |
825 | { |
826 | full = true; |
827 | } |
828 | } |
829 | |
830 | if (type.isMatrix() && matrixArg) |
831 | { |
832 | if (arguments.size() != 1) |
833 | { |
834 | error(line, "constructing matrix from matrix can only take one argument" , |
835 | "constructor" ); |
836 | return false; |
837 | } |
838 | } |
839 | else |
840 | { |
841 | if (size != 1 && size < type.getObjectSize()) |
842 | { |
843 | error(line, "not enough data provided for construction" , "constructor" ); |
844 | return false; |
845 | } |
846 | if (overFull) |
847 | { |
848 | error(line, "too many arguments" , "constructor" ); |
849 | return false; |
850 | } |
851 | } |
852 | } |
853 | |
854 | return true; |
855 | } |
856 | |
857 | // This function checks to see if a void variable has been declared and raise an error message for |
858 | // such a case |
859 | // |
860 | // returns true in case of an error |
861 | // |
862 | bool TParseContext::checkIsNonVoid(const TSourceLoc &line, |
863 | const ImmutableString &identifier, |
864 | const TBasicType &type) |
865 | { |
866 | if (type == EbtVoid) |
867 | { |
868 | error(line, "illegal use of type 'void'" , identifier); |
869 | return false; |
870 | } |
871 | |
872 | return true; |
873 | } |
874 | |
875 | // This function checks to see if the node (for the expression) contains a scalar boolean expression |
876 | // or not. |
877 | bool TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type) |
878 | { |
879 | if (type->getBasicType() != EbtBool || !type->isScalar()) |
880 | { |
881 | error(line, "boolean expression expected" , "" ); |
882 | return false; |
883 | } |
884 | return true; |
885 | } |
886 | |
887 | // This function checks to see if the node (for the expression) contains a scalar boolean expression |
888 | // or not. |
889 | void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType) |
890 | { |
891 | if (pType.getBasicType() != EbtBool || pType.isAggregate()) |
892 | { |
893 | error(line, "boolean expression expected" , "" ); |
894 | } |
895 | } |
896 | |
897 | bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line, |
898 | const TTypeSpecifierNonArray &pType, |
899 | const char *reason) |
900 | { |
901 | if (pType.type == EbtStruct) |
902 | { |
903 | if (ContainsSampler(pType.userDef)) |
904 | { |
905 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
906 | reasonStream << reason << " (structure contains a sampler)" ; |
907 | std::string reasonStr = reasonStream.str(); |
908 | error(line, reasonStr.c_str(), getBasicString(pType.type)); |
909 | return false; |
910 | } |
911 | // only samplers need to be checked from structs, since other opaque types can't be struct |
912 | // members. |
913 | return true; |
914 | } |
915 | else if (IsOpaqueType(pType.type)) |
916 | { |
917 | error(line, reason, getBasicString(pType.type)); |
918 | return false; |
919 | } |
920 | |
921 | return true; |
922 | } |
923 | |
924 | void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, |
925 | const TPublicType &pType) |
926 | { |
927 | if (pType.layoutQualifier.location != -1) |
928 | { |
929 | error(line, "location must only be specified for a single input or output variable" , |
930 | "location" ); |
931 | } |
932 | } |
933 | |
934 | void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location, |
935 | const TLayoutQualifier &layoutQualifier) |
936 | { |
937 | if (layoutQualifier.location != -1) |
938 | { |
939 | const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs" ; |
940 | if (mShaderVersion >= 310) |
941 | { |
942 | errorMsg = |
943 | "invalid layout qualifier: only valid on shader inputs, outputs, and uniforms" ; |
944 | } |
945 | error(location, errorMsg, "location" ); |
946 | } |
947 | } |
948 | |
949 | void TParseContext::checkStd430IsForShaderStorageBlock(const TSourceLoc &location, |
950 | const TLayoutBlockStorage &blockStorage, |
951 | const TQualifier &qualifier) |
952 | { |
953 | if (blockStorage == EbsStd430 && qualifier != EvqBuffer) |
954 | { |
955 | error(location, "The std430 layout is supported only for shader storage blocks." , "std430" ); |
956 | } |
957 | } |
958 | |
959 | void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line, |
960 | TQualifier qualifier, |
961 | const TType &type) |
962 | { |
963 | ASSERT(qualifier == EvqOut || qualifier == EvqInOut); |
964 | if (IsOpaqueType(type.getBasicType())) |
965 | { |
966 | error(line, "opaque types cannot be output parameters" , type.getBasicString()); |
967 | } |
968 | } |
969 | |
970 | // Do size checking for an array type's size. |
971 | unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr) |
972 | { |
973 | TIntermConstantUnion *constant = expr->getAsConstantUnion(); |
974 | |
975 | // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be |
976 | // safe against corner cases we still check for constant folding. Some interpretations of the |
977 | // spec have allowed constant expressions with side effects - like array length() method on a |
978 | // non-constant array. |
979 | if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt()) |
980 | { |
981 | error(line, "array size must be a constant integer expression" , "" ); |
982 | return 1u; |
983 | } |
984 | |
985 | unsigned int size = 0u; |
986 | |
987 | if (constant->getBasicType() == EbtUInt) |
988 | { |
989 | size = constant->getUConst(0); |
990 | } |
991 | else |
992 | { |
993 | int signedSize = constant->getIConst(0); |
994 | |
995 | if (signedSize < 0) |
996 | { |
997 | error(line, "array size must be non-negative" , "" ); |
998 | return 1u; |
999 | } |
1000 | |
1001 | size = static_cast<unsigned int>(signedSize); |
1002 | } |
1003 | |
1004 | if (size == 0u) |
1005 | { |
1006 | error(line, "array size must be greater than zero" , "" ); |
1007 | return 1u; |
1008 | } |
1009 | |
1010 | // The size of arrays is restricted here to prevent issues further down the |
1011 | // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to |
1012 | // 4096 registers so this should be reasonable even for aggressively optimizable code. |
1013 | const unsigned int sizeLimit = 65536; |
1014 | |
1015 | if (size > sizeLimit) |
1016 | { |
1017 | error(line, "array size too large" , "" ); |
1018 | return 1u; |
1019 | } |
1020 | |
1021 | return size; |
1022 | } |
1023 | |
1024 | // See if this qualifier can be an array. |
1025 | bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line, |
1026 | const TPublicType &elementQualifier) |
1027 | { |
1028 | if ((elementQualifier.qualifier == EvqAttribute) || |
1029 | (elementQualifier.qualifier == EvqVertexIn) || |
1030 | (elementQualifier.qualifier == EvqConst && mShaderVersion < 300)) |
1031 | { |
1032 | error(line, "cannot declare arrays of this qualifier" , |
1033 | TType(elementQualifier).getQualifierString()); |
1034 | return false; |
1035 | } |
1036 | |
1037 | return true; |
1038 | } |
1039 | |
1040 | // See if this element type can be formed into an array. |
1041 | bool TParseContext::checkArrayElementIsNotArray(const TSourceLoc &line, |
1042 | const TPublicType &elementType) |
1043 | { |
1044 | if (mShaderVersion < 310 && elementType.isArray()) |
1045 | { |
1046 | TInfoSinkBase typeString; |
1047 | typeString << TType(elementType); |
1048 | error(line, "cannot declare arrays of arrays" , typeString.c_str()); |
1049 | return false; |
1050 | } |
1051 | return true; |
1052 | } |
1053 | |
1054 | // Check if this qualified element type can be formed into an array. This is only called when array |
1055 | // brackets are associated with an identifier in a declaration, like this: |
1056 | // float a[2]; |
1057 | // Similar checks are done in addFullySpecifiedType for array declarations where the array brackets |
1058 | // are associated with the type, like this: |
1059 | // float[2] a; |
1060 | bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, |
1061 | const TPublicType &elementType) |
1062 | { |
1063 | if (!checkArrayElementIsNotArray(indexLocation, elementType)) |
1064 | { |
1065 | return false; |
1066 | } |
1067 | // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. |
1068 | // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section |
1069 | // 4.3.4). |
1070 | // Geometry shader requires each user-defined input be declared as arrays or inside input |
1071 | // blocks declared as arrays (GL_EXT_geometry_shader section 11.1gs.4.3). For the purposes of |
1072 | // interface matching, such variables and blocks are treated as though they were not declared |
1073 | // as arrays (GL_EXT_geometry_shader section 7.4.1). |
1074 | if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && |
1075 | sh::IsVarying(elementType.qualifier) && |
1076 | !IsGeometryShaderInput(mShaderType, elementType.qualifier)) |
1077 | { |
1078 | TInfoSinkBase typeString; |
1079 | typeString << TType(elementType); |
1080 | error(indexLocation, "cannot declare arrays of structs of this qualifier" , |
1081 | typeString.c_str()); |
1082 | return false; |
1083 | } |
1084 | return checkIsValidQualifierForArray(indexLocation, elementType); |
1085 | } |
1086 | |
1087 | // Enforce non-initializer type/qualifier rules. |
1088 | void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, |
1089 | const ImmutableString &identifier, |
1090 | TType *type) |
1091 | { |
1092 | ASSERT(type != nullptr); |
1093 | if (type->getQualifier() == EvqConst) |
1094 | { |
1095 | // Make the qualifier make sense. |
1096 | type->setQualifier(EvqTemporary); |
1097 | |
1098 | // Generate informative error messages for ESSL1. |
1099 | // In ESSL3 arrays and structures containing arrays can be constant. |
1100 | if (mShaderVersion < 300 && type->isStructureContainingArrays()) |
1101 | { |
1102 | error(line, |
1103 | "structures containing arrays may not be declared constant since they cannot be " |
1104 | "initialized" , |
1105 | identifier); |
1106 | } |
1107 | else |
1108 | { |
1109 | error(line, "variables with qualifier 'const' must be initialized" , identifier); |
1110 | } |
1111 | } |
1112 | // This will make the type sized if it isn't sized yet. |
1113 | checkIsNotUnsizedArray(line, "implicitly sized arrays need to be initialized" , identifier, |
1114 | type); |
1115 | } |
1116 | |
1117 | // Do some simple checks that are shared between all variable declarations, |
1118 | // and update the symbol table. |
1119 | // |
1120 | // Returns true if declaring the variable succeeded. |
1121 | // |
1122 | bool TParseContext::declareVariable(const TSourceLoc &line, |
1123 | const ImmutableString &identifier, |
1124 | const TType *type, |
1125 | TVariable **variable) |
1126 | { |
1127 | ASSERT((*variable) == nullptr); |
1128 | |
1129 | (*variable) = new TVariable(&symbolTable, identifier, type, SymbolType::UserDefined); |
1130 | |
1131 | ASSERT(type->getLayoutQualifier().index == -1 || |
1132 | (isExtensionEnabled(TExtension::EXT_blend_func_extended) && |
1133 | mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300)); |
1134 | if (type->getQualifier() == EvqFragmentOut) |
1135 | { |
1136 | if (type->getLayoutQualifier().index != -1 && type->getLayoutQualifier().location == -1) |
1137 | { |
1138 | error(line, |
1139 | "If index layout qualifier is specified for a fragment output, location must " |
1140 | "also be specified." , |
1141 | "index" ); |
1142 | return false; |
1143 | } |
1144 | } |
1145 | else |
1146 | { |
1147 | checkIndexIsNotSpecified(line, type->getLayoutQualifier().index); |
1148 | } |
1149 | |
1150 | checkBindingIsValid(line, *type); |
1151 | |
1152 | bool needsReservedCheck = true; |
1153 | |
1154 | // gl_LastFragData may be redeclared with a new precision qualifier |
1155 | if (type->isArray() && identifier.beginsWith("gl_LastFragData" )) |
1156 | { |
1157 | const TVariable *maxDrawBuffers = static_cast<const TVariable *>( |
1158 | symbolTable.findBuiltIn(ImmutableString("gl_MaxDrawBuffers" ), mShaderVersion)); |
1159 | if (type->isArrayOfArrays()) |
1160 | { |
1161 | error(line, "redeclaration of gl_LastFragData as an array of arrays" , identifier); |
1162 | return false; |
1163 | } |
1164 | else if (static_cast<int>(type->getOutermostArraySize()) == |
1165 | maxDrawBuffers->getConstPointer()->getIConst()) |
1166 | { |
1167 | if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) |
1168 | { |
1169 | needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->extension()); |
1170 | } |
1171 | } |
1172 | else |
1173 | { |
1174 | error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers" , |
1175 | identifier); |
1176 | return false; |
1177 | } |
1178 | } |
1179 | |
1180 | if (needsReservedCheck && !checkIsNotReserved(line, identifier)) |
1181 | return false; |
1182 | |
1183 | if (!symbolTable.declare(*variable)) |
1184 | { |
1185 | error(line, "redefinition" , identifier); |
1186 | return false; |
1187 | } |
1188 | |
1189 | if (!checkIsNonVoid(line, identifier, type->getBasicType())) |
1190 | return false; |
1191 | |
1192 | return true; |
1193 | } |
1194 | |
1195 | void TParseContext::checkIsParameterQualifierValid( |
1196 | const TSourceLoc &line, |
1197 | const TTypeQualifierBuilder &typeQualifierBuilder, |
1198 | TType *type) |
1199 | { |
1200 | // The only parameter qualifiers a parameter can have are in, out, inout or const. |
1201 | TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(mDiagnostics); |
1202 | |
1203 | if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut) |
1204 | { |
1205 | checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type); |
1206 | } |
1207 | |
1208 | if (!IsImage(type->getBasicType())) |
1209 | { |
1210 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line); |
1211 | } |
1212 | else |
1213 | { |
1214 | type->setMemoryQualifier(typeQualifier.memoryQualifier); |
1215 | } |
1216 | |
1217 | type->setQualifier(typeQualifier.qualifier); |
1218 | |
1219 | if (typeQualifier.precision != EbpUndefined) |
1220 | { |
1221 | type->setPrecision(typeQualifier.precision); |
1222 | } |
1223 | } |
1224 | |
1225 | template <size_t size> |
1226 | bool TParseContext::checkCanUseOneOfExtensions(const TSourceLoc &line, |
1227 | const std::array<TExtension, size> &extensions) |
1228 | { |
1229 | ASSERT(!extensions.empty()); |
1230 | const TExtensionBehavior &extBehavior = extensionBehavior(); |
1231 | |
1232 | bool canUseWithWarning = false; |
1233 | bool canUseWithoutWarning = false; |
1234 | |
1235 | const char *errorMsgString = "" ; |
1236 | TExtension errorMsgExtension = TExtension::UNDEFINED; |
1237 | |
1238 | for (TExtension extension : extensions) |
1239 | { |
1240 | auto extIter = extBehavior.find(extension); |
1241 | if (canUseWithWarning) |
1242 | { |
1243 | // We already have an extension that we can use, but with a warning. |
1244 | // See if we can use the alternative extension without a warning. |
1245 | if (extIter == extBehavior.end()) |
1246 | { |
1247 | continue; |
1248 | } |
1249 | if (extIter->second == EBhEnable || extIter->second == EBhRequire) |
1250 | { |
1251 | canUseWithoutWarning = true; |
1252 | break; |
1253 | } |
1254 | continue; |
1255 | } |
1256 | if (extIter == extBehavior.end()) |
1257 | { |
1258 | errorMsgString = "extension is not supported" ; |
1259 | errorMsgExtension = extension; |
1260 | } |
1261 | else if (extIter->second == EBhUndefined || extIter->second == EBhDisable) |
1262 | { |
1263 | errorMsgString = "extension is disabled" ; |
1264 | errorMsgExtension = extension; |
1265 | } |
1266 | else if (extIter->second == EBhWarn) |
1267 | { |
1268 | errorMsgExtension = extension; |
1269 | canUseWithWarning = true; |
1270 | } |
1271 | else |
1272 | { |
1273 | ASSERT(extIter->second == EBhEnable || extIter->second == EBhRequire); |
1274 | canUseWithoutWarning = true; |
1275 | break; |
1276 | } |
1277 | } |
1278 | |
1279 | if (canUseWithoutWarning) |
1280 | { |
1281 | return true; |
1282 | } |
1283 | if (canUseWithWarning) |
1284 | { |
1285 | warning(line, "extension is being used" , GetExtensionNameString(errorMsgExtension)); |
1286 | return true; |
1287 | } |
1288 | error(line, errorMsgString, GetExtensionNameString(errorMsgExtension)); |
1289 | return false; |
1290 | } |
1291 | |
1292 | template bool TParseContext::checkCanUseOneOfExtensions( |
1293 | const TSourceLoc &line, |
1294 | const std::array<TExtension, 1> &extensions); |
1295 | template bool TParseContext::checkCanUseOneOfExtensions( |
1296 | const TSourceLoc &line, |
1297 | const std::array<TExtension, 2> &extensions); |
1298 | template bool TParseContext::checkCanUseOneOfExtensions( |
1299 | const TSourceLoc &line, |
1300 | const std::array<TExtension, 3> &extensions); |
1301 | |
1302 | bool TParseContext::checkCanUseExtension(const TSourceLoc &line, TExtension extension) |
1303 | { |
1304 | ASSERT(extension != TExtension::UNDEFINED); |
1305 | return checkCanUseOneOfExtensions(line, std::array<TExtension, 1u>{{extension}}); |
1306 | } |
1307 | |
1308 | // ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause |
1309 | // compile-time or link-time errors are the same whether or not the declaration is empty". |
1310 | // This function implements all the checks that are done on qualifiers regardless of if the |
1311 | // declaration is empty. |
1312 | void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier, |
1313 | const sh::TLayoutQualifier &layoutQualifier, |
1314 | const TSourceLoc &location) |
1315 | { |
1316 | if (qualifier == EvqShared && !layoutQualifier.isEmpty()) |
1317 | { |
1318 | error(location, "Shared memory declarations cannot have layout specified" , "layout" ); |
1319 | } |
1320 | |
1321 | if (layoutQualifier.matrixPacking != EmpUnspecified) |
1322 | { |
1323 | error(location, "layout qualifier only valid for interface blocks" , |
1324 | getMatrixPackingString(layoutQualifier.matrixPacking)); |
1325 | return; |
1326 | } |
1327 | |
1328 | if (layoutQualifier.blockStorage != EbsUnspecified) |
1329 | { |
1330 | error(location, "layout qualifier only valid for interface blocks" , |
1331 | getBlockStorageString(layoutQualifier.blockStorage)); |
1332 | return; |
1333 | } |
1334 | |
1335 | if (qualifier == EvqFragmentOut) |
1336 | { |
1337 | if (layoutQualifier.location != -1 && layoutQualifier.yuv == true) |
1338 | { |
1339 | error(location, "invalid layout qualifier combination" , "yuv" ); |
1340 | return; |
1341 | } |
1342 | } |
1343 | else |
1344 | { |
1345 | checkYuvIsNotSpecified(location, layoutQualifier.yuv); |
1346 | } |
1347 | |
1348 | // If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous |
1349 | // parsing steps. So it needs to be checked here. |
1350 | if (isExtensionEnabled(TExtension::OVR_multiview2) && mShaderVersion < 300 && |
1351 | qualifier == EvqVertexIn) |
1352 | { |
1353 | error(location, "storage qualifier supported in GLSL ES 3.00 and above only" , "in" ); |
1354 | } |
1355 | |
1356 | bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut; |
1357 | if (mShaderVersion >= 310) |
1358 | { |
1359 | canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier); |
1360 | // We're not checking whether the uniform location is in range here since that depends on |
1361 | // the type of the variable. |
1362 | // The type can only be fully determined for non-empty declarations. |
1363 | } |
1364 | if (!canHaveLocation) |
1365 | { |
1366 | checkLocationIsNotSpecified(location, layoutQualifier); |
1367 | } |
1368 | } |
1369 | |
1370 | void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicType, |
1371 | const TSourceLoc &location) |
1372 | { |
1373 | if (publicType.precision != EbpHigh) |
1374 | { |
1375 | error(location, "Can only be highp" , "atomic counter" ); |
1376 | } |
1377 | // dEQP enforces compile error if location is specified. See uniform_location.test. |
1378 | if (publicType.layoutQualifier.location != -1) |
1379 | { |
1380 | error(location, "location must not be set for atomic_uint" , "layout" ); |
1381 | } |
1382 | if (publicType.layoutQualifier.binding == -1) |
1383 | { |
1384 | error(location, "no binding specified" , "atomic counter" ); |
1385 | } |
1386 | } |
1387 | |
1388 | void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location) |
1389 | { |
1390 | if (type.isUnsizedArray()) |
1391 | { |
1392 | // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an |
1393 | // error. It is assumed that this applies to empty declarations as well. |
1394 | error(location, "empty array declaration needs to specify a size" , "" ); |
1395 | } |
1396 | |
1397 | if (type.getQualifier() != EvqFragmentOut) |
1398 | { |
1399 | checkIndexIsNotSpecified(location, type.getLayoutQualifier().index); |
1400 | } |
1401 | } |
1402 | |
1403 | // These checks are done for all declarations that are non-empty. They're done for non-empty |
1404 | // declarations starting a declarator list, and declarators that follow an empty declaration. |
1405 | void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, |
1406 | const TSourceLoc &identifierLocation) |
1407 | { |
1408 | switch (publicType.qualifier) |
1409 | { |
1410 | case EvqVaryingIn: |
1411 | case EvqVaryingOut: |
1412 | case EvqAttribute: |
1413 | case EvqVertexIn: |
1414 | case EvqFragmentOut: |
1415 | case EvqComputeIn: |
1416 | if (publicType.getBasicType() == EbtStruct) |
1417 | { |
1418 | error(identifierLocation, "cannot be used with a structure" , |
1419 | getQualifierString(publicType.qualifier)); |
1420 | return; |
1421 | } |
1422 | break; |
1423 | case EvqBuffer: |
1424 | if (publicType.getBasicType() != EbtInterfaceBlock) |
1425 | { |
1426 | error(identifierLocation, |
1427 | "cannot declare buffer variables at global scope(outside a block)" , |
1428 | getQualifierString(publicType.qualifier)); |
1429 | return; |
1430 | } |
1431 | break; |
1432 | default: |
1433 | break; |
1434 | } |
1435 | std::string reason(getBasicString(publicType.getBasicType())); |
1436 | reason += "s must be uniform" ; |
1437 | if (publicType.qualifier != EvqUniform && |
1438 | !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str())) |
1439 | { |
1440 | return; |
1441 | } |
1442 | |
1443 | if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal && |
1444 | publicType.qualifier != EvqConst) && |
1445 | publicType.getBasicType() == EbtYuvCscStandardEXT) |
1446 | { |
1447 | error(identifierLocation, "cannot be used with a yuvCscStandardEXT" , |
1448 | getQualifierString(publicType.qualifier)); |
1449 | return; |
1450 | } |
1451 | |
1452 | if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform) |
1453 | { |
1454 | // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized. |
1455 | // But invalid shaders may still reach here with an unsized array declaration. |
1456 | TType type(publicType); |
1457 | if (!type.isUnsizedArray()) |
1458 | { |
1459 | checkUniformLocationInRange(identifierLocation, type.getLocationCount(), |
1460 | publicType.layoutQualifier); |
1461 | } |
1462 | } |
1463 | |
1464 | // check for layout qualifier issues |
1465 | const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; |
1466 | |
1467 | if (IsImage(publicType.getBasicType())) |
1468 | { |
1469 | |
1470 | switch (layoutQualifier.imageInternalFormat) |
1471 | { |
1472 | case EiifRGBA32F: |
1473 | case EiifRGBA16F: |
1474 | case EiifR32F: |
1475 | case EiifRGBA8: |
1476 | case EiifRGBA8_SNORM: |
1477 | if (!IsFloatImage(publicType.getBasicType())) |
1478 | { |
1479 | error(identifierLocation, |
1480 | "internal image format requires a floating image type" , |
1481 | getBasicString(publicType.getBasicType())); |
1482 | return; |
1483 | } |
1484 | break; |
1485 | case EiifRGBA32I: |
1486 | case EiifRGBA16I: |
1487 | case EiifRGBA8I: |
1488 | case EiifR32I: |
1489 | if (!IsIntegerImage(publicType.getBasicType())) |
1490 | { |
1491 | error(identifierLocation, |
1492 | "internal image format requires an integer image type" , |
1493 | getBasicString(publicType.getBasicType())); |
1494 | return; |
1495 | } |
1496 | break; |
1497 | case EiifRGBA32UI: |
1498 | case EiifRGBA16UI: |
1499 | case EiifRGBA8UI: |
1500 | case EiifR32UI: |
1501 | if (!IsUnsignedImage(publicType.getBasicType())) |
1502 | { |
1503 | error(identifierLocation, |
1504 | "internal image format requires an unsigned image type" , |
1505 | getBasicString(publicType.getBasicType())); |
1506 | return; |
1507 | } |
1508 | break; |
1509 | case EiifUnspecified: |
1510 | error(identifierLocation, "layout qualifier" , "No image internal format specified" ); |
1511 | return; |
1512 | default: |
1513 | error(identifierLocation, "layout qualifier" , "unrecognized token" ); |
1514 | return; |
1515 | } |
1516 | |
1517 | // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers |
1518 | switch (layoutQualifier.imageInternalFormat) |
1519 | { |
1520 | case EiifR32F: |
1521 | case EiifR32I: |
1522 | case EiifR32UI: |
1523 | break; |
1524 | default: |
1525 | if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly) |
1526 | { |
1527 | error(identifierLocation, "layout qualifier" , |
1528 | "Except for images with the r32f, r32i and r32ui format qualifiers, " |
1529 | "image variables must be qualified readonly and/or writeonly" ); |
1530 | return; |
1531 | } |
1532 | break; |
1533 | } |
1534 | } |
1535 | else |
1536 | { |
1537 | checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat); |
1538 | checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation); |
1539 | } |
1540 | |
1541 | if (IsAtomicCounter(publicType.getBasicType())) |
1542 | { |
1543 | atomicCounterQualifierErrorCheck(publicType, identifierLocation); |
1544 | } |
1545 | else |
1546 | { |
1547 | checkOffsetIsNotSpecified(identifierLocation, layoutQualifier.offset); |
1548 | } |
1549 | } |
1550 | |
1551 | void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type) |
1552 | { |
1553 | TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); |
1554 | // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier |
1555 | // on arrays of arrays should be handled. We interpret the spec so that the binding value is |
1556 | // incremented for each element of the innermost nested arrays. This is in line with how arrays |
1557 | // of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation |
1558 | // when it comes to which shaders are accepted by the compiler. |
1559 | int arrayTotalElementCount = type.getArraySizeProduct(); |
1560 | if (IsImage(type.getBasicType())) |
1561 | { |
1562 | checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, |
1563 | arrayTotalElementCount); |
1564 | } |
1565 | else if (IsSampler(type.getBasicType())) |
1566 | { |
1567 | checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, |
1568 | arrayTotalElementCount); |
1569 | } |
1570 | else if (IsAtomicCounter(type.getBasicType())) |
1571 | { |
1572 | checkAtomicCounterBindingIsValid(identifierLocation, layoutQualifier.binding); |
1573 | } |
1574 | else |
1575 | { |
1576 | ASSERT(!IsOpaqueType(type.getBasicType())); |
1577 | checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding); |
1578 | } |
1579 | } |
1580 | |
1581 | void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, |
1582 | const ImmutableString &layoutQualifierName, |
1583 | int versionRequired) |
1584 | { |
1585 | |
1586 | if (mShaderVersion < versionRequired) |
1587 | { |
1588 | error(location, "invalid layout qualifier: not supported" , layoutQualifierName); |
1589 | } |
1590 | } |
1591 | |
1592 | bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, |
1593 | const TLayoutQualifier &layoutQualifier) |
1594 | { |
1595 | const sh::WorkGroupSize &localSize = layoutQualifier.localSize; |
1596 | for (size_t i = 0u; i < localSize.size(); ++i) |
1597 | { |
1598 | if (localSize[i] != -1) |
1599 | { |
1600 | error(location, |
1601 | "invalid layout qualifier: only valid when used with 'in' in a compute shader " |
1602 | "global layout declaration" , |
1603 | getWorkGroupSizeString(i)); |
1604 | return false; |
1605 | } |
1606 | } |
1607 | |
1608 | return true; |
1609 | } |
1610 | |
1611 | void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location, |
1612 | TLayoutImageInternalFormat internalFormat) |
1613 | { |
1614 | if (internalFormat != EiifUnspecified) |
1615 | { |
1616 | error(location, "invalid layout qualifier: only valid when used with images" , |
1617 | getImageInternalFormatString(internalFormat)); |
1618 | } |
1619 | } |
1620 | |
1621 | void TParseContext::checkIndexIsNotSpecified(const TSourceLoc &location, int index) |
1622 | { |
1623 | if (index != -1) |
1624 | { |
1625 | error(location, |
1626 | "invalid layout qualifier: only valid when used with a fragment shader output in " |
1627 | "ESSL version >= 3.00 and EXT_blend_func_extended is enabled" , |
1628 | "index" ); |
1629 | } |
1630 | } |
1631 | |
1632 | void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding) |
1633 | { |
1634 | if (binding != -1) |
1635 | { |
1636 | error(location, |
1637 | "invalid layout qualifier: only valid when used with opaque types or blocks" , |
1638 | "binding" ); |
1639 | } |
1640 | } |
1641 | |
1642 | void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int offset) |
1643 | { |
1644 | if (offset != -1) |
1645 | { |
1646 | error(location, "invalid layout qualifier: only valid when used with atomic counters" , |
1647 | "offset" ); |
1648 | } |
1649 | } |
1650 | |
1651 | void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, |
1652 | int binding, |
1653 | int arrayTotalElementCount) |
1654 | { |
1655 | // Expects arraySize to be 1 when setting binding for only a single variable. |
1656 | if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits) |
1657 | { |
1658 | error(location, "image binding greater than gl_MaxImageUnits" , "binding" ); |
1659 | } |
1660 | } |
1661 | |
1662 | void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location, |
1663 | int binding, |
1664 | int arrayTotalElementCount) |
1665 | { |
1666 | // Expects arraySize to be 1 when setting binding for only a single variable. |
1667 | if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits) |
1668 | { |
1669 | error(location, "sampler binding greater than maximum texture units" , "binding" ); |
1670 | } |
1671 | } |
1672 | |
1673 | void TParseContext::checkBlockBindingIsValid(const TSourceLoc &location, |
1674 | const TQualifier &qualifier, |
1675 | int binding, |
1676 | int arraySize) |
1677 | { |
1678 | int size = (arraySize == 0 ? 1 : arraySize); |
1679 | if (qualifier == EvqUniform) |
1680 | { |
1681 | if (binding + size > mMaxUniformBufferBindings) |
1682 | { |
1683 | error(location, "uniform block binding greater than MAX_UNIFORM_BUFFER_BINDINGS" , |
1684 | "binding" ); |
1685 | } |
1686 | } |
1687 | else if (qualifier == EvqBuffer) |
1688 | { |
1689 | if (binding + size > mMaxShaderStorageBufferBindings) |
1690 | { |
1691 | error(location, |
1692 | "shader storage block binding greater than MAX_SHADER_STORAGE_BUFFER_BINDINGS" , |
1693 | "binding" ); |
1694 | } |
1695 | } |
1696 | } |
1697 | void TParseContext::checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding) |
1698 | { |
1699 | if (binding >= mMaxAtomicCounterBindings) |
1700 | { |
1701 | error(location, "atomic counter binding greater than gl_MaxAtomicCounterBindings" , |
1702 | "binding" ); |
1703 | } |
1704 | } |
1705 | |
1706 | void TParseContext::checkUniformLocationInRange(const TSourceLoc &location, |
1707 | int objectLocationCount, |
1708 | const TLayoutQualifier &layoutQualifier) |
1709 | { |
1710 | int loc = layoutQualifier.location; |
1711 | if (loc >= 0 && loc + objectLocationCount > mMaxUniformLocations) |
1712 | { |
1713 | error(location, "Uniform location out of range" , "location" ); |
1714 | } |
1715 | } |
1716 | |
1717 | void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv) |
1718 | { |
1719 | if (yuv != false) |
1720 | { |
1721 | error(location, "invalid layout qualifier: only valid on program outputs" , "yuv" ); |
1722 | } |
1723 | } |
1724 | |
1725 | void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, |
1726 | TIntermAggregate *fnCall) |
1727 | { |
1728 | for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) |
1729 | { |
1730 | TQualifier qual = fnCandidate->getParam(i)->getType().getQualifier(); |
1731 | TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped(); |
1732 | bool argumentIsRead = (IsQualifierUnspecified(qual) || qual == EvqIn || qual == EvqInOut || |
1733 | qual == EvqConstReadOnly); |
1734 | if (argumentIsRead) |
1735 | { |
1736 | markStaticReadIfSymbol(argument); |
1737 | if (!IsImage(argument->getBasicType())) |
1738 | { |
1739 | if (argument->getMemoryQualifier().writeonly) |
1740 | { |
1741 | error(argument->getLine(), |
1742 | "Writeonly value cannot be passed for 'in' or 'inout' parameters." , |
1743 | fnCall->functionName()); |
1744 | return; |
1745 | } |
1746 | } |
1747 | } |
1748 | if (qual == EvqOut || qual == EvqInOut) |
1749 | { |
1750 | if (!checkCanBeLValue(argument->getLine(), "assign" , argument)) |
1751 | { |
1752 | error(argument->getLine(), |
1753 | "Constant value cannot be passed for 'out' or 'inout' parameters." , |
1754 | fnCall->functionName()); |
1755 | return; |
1756 | } |
1757 | } |
1758 | } |
1759 | } |
1760 | |
1761 | void TParseContext::checkInvariantVariableQualifier(bool invariant, |
1762 | const TQualifier qualifier, |
1763 | const TSourceLoc &invariantLocation) |
1764 | { |
1765 | if (!invariant) |
1766 | return; |
1767 | |
1768 | if (mShaderVersion < 300) |
1769 | { |
1770 | // input variables in the fragment shader can be also qualified as invariant |
1771 | if (!sh::CanBeInvariantESSL1(qualifier)) |
1772 | { |
1773 | error(invariantLocation, "Cannot be qualified as invariant." , "invariant" ); |
1774 | } |
1775 | } |
1776 | else |
1777 | { |
1778 | if (!sh::CanBeInvariantESSL3OrGreater(qualifier)) |
1779 | { |
1780 | error(invariantLocation, "Cannot be qualified as invariant." , "invariant" ); |
1781 | } |
1782 | } |
1783 | } |
1784 | |
1785 | bool TParseContext::isExtensionEnabled(TExtension extension) const |
1786 | { |
1787 | return IsExtensionEnabled(extensionBehavior(), extension); |
1788 | } |
1789 | |
1790 | void TParseContext::handleExtensionDirective(const TSourceLoc &loc, |
1791 | const char *extName, |
1792 | const char *behavior) |
1793 | { |
1794 | angle::pp::SourceLocation srcLoc; |
1795 | srcLoc.file = loc.first_file; |
1796 | srcLoc.line = loc.first_line; |
1797 | mDirectiveHandler.handleExtension(srcLoc, extName, behavior); |
1798 | } |
1799 | |
1800 | void TParseContext::handlePragmaDirective(const TSourceLoc &loc, |
1801 | const char *name, |
1802 | const char *value, |
1803 | bool stdgl) |
1804 | { |
1805 | angle::pp::SourceLocation srcLoc; |
1806 | srcLoc.file = loc.first_file; |
1807 | srcLoc.line = loc.first_line; |
1808 | mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl); |
1809 | } |
1810 | |
1811 | sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const |
1812 | { |
1813 | sh::WorkGroupSize result(-1); |
1814 | for (size_t i = 0u; i < result.size(); ++i) |
1815 | { |
1816 | if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1) |
1817 | { |
1818 | result[i] = 1; |
1819 | } |
1820 | else |
1821 | { |
1822 | result[i] = mComputeShaderLocalSize[i]; |
1823 | } |
1824 | } |
1825 | return result; |
1826 | } |
1827 | |
1828 | TIntermConstantUnion *TParseContext::addScalarLiteral(const TConstantUnion *constantUnion, |
1829 | const TSourceLoc &line) |
1830 | { |
1831 | TIntermConstantUnion *node = new TIntermConstantUnion( |
1832 | constantUnion, TType(constantUnion->getType(), EbpUndefined, EvqConst)); |
1833 | node->setLine(line); |
1834 | return node; |
1835 | } |
1836 | |
1837 | ///////////////////////////////////////////////////////////////////////////////// |
1838 | // |
1839 | // Non-Errors. |
1840 | // |
1841 | ///////////////////////////////////////////////////////////////////////////////// |
1842 | |
1843 | const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, |
1844 | const ImmutableString &name, |
1845 | const TSymbol *symbol) |
1846 | { |
1847 | if (!symbol) |
1848 | { |
1849 | error(location, "undeclared identifier" , name); |
1850 | return nullptr; |
1851 | } |
1852 | |
1853 | if (!symbol->isVariable()) |
1854 | { |
1855 | error(location, "variable expected" , name); |
1856 | return nullptr; |
1857 | } |
1858 | |
1859 | const TVariable *variable = static_cast<const TVariable *>(symbol); |
1860 | |
1861 | if (variable->extension() != TExtension::UNDEFINED) |
1862 | { |
1863 | checkCanUseExtension(location, variable->extension()); |
1864 | } |
1865 | |
1866 | // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables |
1867 | if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared && |
1868 | variable->getType().getQualifier() == EvqWorkGroupSize) |
1869 | { |
1870 | error(location, |
1871 | "It is an error to use gl_WorkGroupSize before declaring the local group size" , |
1872 | "gl_WorkGroupSize" ); |
1873 | } |
1874 | return variable; |
1875 | } |
1876 | |
1877 | TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, |
1878 | const ImmutableString &name, |
1879 | const TSymbol *symbol) |
1880 | { |
1881 | const TVariable *variable = getNamedVariable(location, name, symbol); |
1882 | |
1883 | if (!variable) |
1884 | { |
1885 | TIntermTyped *node = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); |
1886 | node->setLine(location); |
1887 | return node; |
1888 | } |
1889 | |
1890 | const TType &variableType = variable->getType(); |
1891 | TIntermTyped *node = nullptr; |
1892 | |
1893 | if (variable->getConstPointer() && variableType.canReplaceWithConstantUnion()) |
1894 | { |
1895 | const TConstantUnion *constArray = variable->getConstPointer(); |
1896 | node = new TIntermConstantUnion(constArray, variableType); |
1897 | } |
1898 | else if (variableType.getQualifier() == EvqWorkGroupSize && mComputeShaderLocalSizeDeclared) |
1899 | { |
1900 | // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it |
1901 | // needs to be added to the AST as a constant and not as a symbol. |
1902 | sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize(); |
1903 | TConstantUnion *constArray = new TConstantUnion[3]; |
1904 | for (size_t i = 0; i < 3; ++i) |
1905 | { |
1906 | constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i])); |
1907 | } |
1908 | |
1909 | ASSERT(variableType.getBasicType() == EbtUInt); |
1910 | ASSERT(variableType.getObjectSize() == 3); |
1911 | |
1912 | TType type(variableType); |
1913 | type.setQualifier(EvqConst); |
1914 | node = new TIntermConstantUnion(constArray, type); |
1915 | } |
1916 | else if ((mGeometryShaderInputPrimitiveType != EptUndefined) && |
1917 | (variableType.getQualifier() == EvqPerVertexIn)) |
1918 | { |
1919 | ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr); |
1920 | node = new TIntermSymbol(symbolTable.getGlInVariableWithArraySize()); |
1921 | } |
1922 | else |
1923 | { |
1924 | node = new TIntermSymbol(variable); |
1925 | } |
1926 | ASSERT(node != nullptr); |
1927 | node->setLine(location); |
1928 | return node; |
1929 | } |
1930 | |
1931 | // Initializers show up in several places in the grammar. Have one set of |
1932 | // code to handle them here. |
1933 | // |
1934 | // Returns true on success. |
1935 | bool TParseContext::executeInitializer(const TSourceLoc &line, |
1936 | const ImmutableString &identifier, |
1937 | TType *type, |
1938 | TIntermTyped *initializer, |
1939 | TIntermBinary **initNode) |
1940 | { |
1941 | ASSERT(initNode != nullptr); |
1942 | ASSERT(*initNode == nullptr); |
1943 | |
1944 | if (type->isUnsizedArray()) |
1945 | { |
1946 | // In case initializer is not an array or type has more dimensions than initializer, this |
1947 | // will default to setting array sizes to 1. We have not checked yet whether the initializer |
1948 | // actually is an array or not. Having a non-array initializer for an unsized array will |
1949 | // result in an error later, so we don't generate an error message here. |
1950 | auto *arraySizes = initializer->getType().getArraySizes(); |
1951 | type->sizeUnsizedArrays(arraySizes); |
1952 | } |
1953 | |
1954 | const TQualifier qualifier = type->getQualifier(); |
1955 | |
1956 | bool constError = false; |
1957 | if (qualifier == EvqConst) |
1958 | { |
1959 | if (EvqConst != initializer->getType().getQualifier()) |
1960 | { |
1961 | TInfoSinkBase reasonStream; |
1962 | reasonStream << "assigning non-constant to '" << *type << "'" ; |
1963 | error(line, reasonStream.c_str(), "=" ); |
1964 | |
1965 | // We're still going to declare the variable to avoid extra error messages. |
1966 | type->setQualifier(EvqTemporary); |
1967 | constError = true; |
1968 | } |
1969 | } |
1970 | |
1971 | TVariable *variable = nullptr; |
1972 | if (!declareVariable(line, identifier, type, &variable)) |
1973 | { |
1974 | return false; |
1975 | } |
1976 | |
1977 | if (constError) |
1978 | { |
1979 | return false; |
1980 | } |
1981 | |
1982 | bool globalInitWarning = false; |
1983 | if (symbolTable.atGlobalLevel() && |
1984 | !ValidateGlobalInitializer(initializer, mShaderVersion, &globalInitWarning)) |
1985 | { |
1986 | // Error message does not completely match behavior with ESSL 1.00, but |
1987 | // we want to steer developers towards only using constant expressions. |
1988 | error(line, "global variable initializers must be constant expressions" , "=" ); |
1989 | return false; |
1990 | } |
1991 | if (globalInitWarning) |
1992 | { |
1993 | warning( |
1994 | line, |
1995 | "global variable initializers should be constant expressions " |
1996 | "(uniforms and globals are allowed in global initializers for legacy compatibility)" , |
1997 | "=" ); |
1998 | } |
1999 | |
2000 | // identifier must be of type constant, a global, or a temporary |
2001 | if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) |
2002 | { |
2003 | error(line, " cannot initialize this type of qualifier " , |
2004 | variable->getType().getQualifierString()); |
2005 | return false; |
2006 | } |
2007 | |
2008 | TIntermSymbol *intermSymbol = new TIntermSymbol(variable); |
2009 | intermSymbol->setLine(line); |
2010 | |
2011 | if (!binaryOpCommonCheck(EOpInitialize, intermSymbol, initializer, line)) |
2012 | { |
2013 | assignError(line, "=" , variable->getType(), initializer->getType()); |
2014 | return false; |
2015 | } |
2016 | |
2017 | if (qualifier == EvqConst) |
2018 | { |
2019 | // Save the constant folded value to the variable if possible. |
2020 | const TConstantUnion *constArray = initializer->getConstantValue(); |
2021 | if (constArray) |
2022 | { |
2023 | variable->shareConstPointer(constArray); |
2024 | if (initializer->getType().canReplaceWithConstantUnion()) |
2025 | { |
2026 | ASSERT(*initNode == nullptr); |
2027 | return true; |
2028 | } |
2029 | } |
2030 | } |
2031 | |
2032 | *initNode = new TIntermBinary(EOpInitialize, intermSymbol, initializer); |
2033 | markStaticReadIfSymbol(initializer); |
2034 | (*initNode)->setLine(line); |
2035 | return true; |
2036 | } |
2037 | |
2038 | TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType, |
2039 | const ImmutableString &identifier, |
2040 | TIntermTyped *initializer, |
2041 | const TSourceLoc &loc) |
2042 | { |
2043 | checkIsScalarBool(loc, pType); |
2044 | TIntermBinary *initNode = nullptr; |
2045 | TType *type = new TType(pType); |
2046 | if (executeInitializer(loc, identifier, type, initializer, &initNode)) |
2047 | { |
2048 | // The initializer is valid. The init condition needs to have a node - either the |
2049 | // initializer node, or a constant node in case the initialized variable is const and won't |
2050 | // be recorded in the AST. |
2051 | if (initNode == nullptr) |
2052 | { |
2053 | return initializer; |
2054 | } |
2055 | else |
2056 | { |
2057 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
2058 | declaration->appendDeclarator(initNode); |
2059 | return declaration; |
2060 | } |
2061 | } |
2062 | return nullptr; |
2063 | } |
2064 | |
2065 | TIntermNode *TParseContext::addLoop(TLoopType type, |
2066 | TIntermNode *init, |
2067 | TIntermNode *cond, |
2068 | TIntermTyped *expr, |
2069 | TIntermNode *body, |
2070 | const TSourceLoc &line) |
2071 | { |
2072 | TIntermNode *node = nullptr; |
2073 | TIntermTyped *typedCond = nullptr; |
2074 | if (cond) |
2075 | { |
2076 | markStaticReadIfSymbol(cond); |
2077 | typedCond = cond->getAsTyped(); |
2078 | } |
2079 | if (expr) |
2080 | { |
2081 | markStaticReadIfSymbol(expr); |
2082 | } |
2083 | // In case the loop body was not parsed as a block and contains a statement that simply refers |
2084 | // to a variable, we need to mark it as statically used. |
2085 | if (body) |
2086 | { |
2087 | markStaticReadIfSymbol(body); |
2088 | } |
2089 | if (cond == nullptr || typedCond) |
2090 | { |
2091 | if (type == ELoopDoWhile) |
2092 | { |
2093 | checkIsScalarBool(line, typedCond); |
2094 | } |
2095 | // In the case of other loops, it was checked before that the condition is a scalar boolean. |
2096 | ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr || |
2097 | (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && |
2098 | !typedCond->isVector())); |
2099 | |
2100 | node = new TIntermLoop(type, init, typedCond, expr, EnsureBlock(body)); |
2101 | node->setLine(line); |
2102 | return node; |
2103 | } |
2104 | |
2105 | ASSERT(type != ELoopDoWhile); |
2106 | |
2107 | TIntermDeclaration *declaration = cond->getAsDeclarationNode(); |
2108 | ASSERT(declaration); |
2109 | TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode(); |
2110 | ASSERT(declarator->getLeft()->getAsSymbolNode()); |
2111 | |
2112 | // The condition is a declaration. In the AST representation we don't support declarations as |
2113 | // loop conditions. Wrap the loop to a block that declares the condition variable and contains |
2114 | // the loop. |
2115 | TIntermBlock *block = new TIntermBlock(); |
2116 | |
2117 | TIntermDeclaration *declareCondition = new TIntermDeclaration(); |
2118 | declareCondition->appendDeclarator(declarator->getLeft()->deepCopy()); |
2119 | block->appendStatement(declareCondition); |
2120 | |
2121 | TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(), |
2122 | declarator->getRight()->deepCopy()); |
2123 | TIntermLoop *loop = new TIntermLoop(type, init, conditionInit, expr, EnsureBlock(body)); |
2124 | block->appendStatement(loop); |
2125 | loop->setLine(line); |
2126 | block->setLine(line); |
2127 | return block; |
2128 | } |
2129 | |
2130 | TIntermNode *TParseContext::addIfElse(TIntermTyped *cond, |
2131 | TIntermNodePair code, |
2132 | const TSourceLoc &loc) |
2133 | { |
2134 | bool isScalarBool = checkIsScalarBool(loc, cond); |
2135 | // In case the conditional statements were not parsed as blocks and contain a statement that |
2136 | // simply refers to a variable, we need to mark them as statically used. |
2137 | if (code.node1) |
2138 | { |
2139 | markStaticReadIfSymbol(code.node1); |
2140 | } |
2141 | if (code.node2) |
2142 | { |
2143 | markStaticReadIfSymbol(code.node2); |
2144 | } |
2145 | |
2146 | // For compile time constant conditions, prune the code now. |
2147 | if (isScalarBool && cond->getAsConstantUnion()) |
2148 | { |
2149 | if (cond->getAsConstantUnion()->getBConst(0) == true) |
2150 | { |
2151 | return EnsureBlock(code.node1); |
2152 | } |
2153 | else |
2154 | { |
2155 | return EnsureBlock(code.node2); |
2156 | } |
2157 | } |
2158 | |
2159 | TIntermIfElse *node = new TIntermIfElse(cond, EnsureBlock(code.node1), EnsureBlock(code.node2)); |
2160 | markStaticReadIfSymbol(cond); |
2161 | node->setLine(loc); |
2162 | |
2163 | return node; |
2164 | } |
2165 | |
2166 | void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier) |
2167 | { |
2168 | checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision, |
2169 | typeSpecifier->getBasicType()); |
2170 | |
2171 | if (mShaderVersion < 300 && typeSpecifier->isArray()) |
2172 | { |
2173 | error(typeSpecifier->getLine(), "not supported" , "first-class array" ); |
2174 | typeSpecifier->clearArrayness(); |
2175 | } |
2176 | } |
2177 | |
2178 | TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, |
2179 | const TPublicType &typeSpecifier) |
2180 | { |
2181 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); |
2182 | |
2183 | TPublicType returnType = typeSpecifier; |
2184 | returnType.qualifier = typeQualifier.qualifier; |
2185 | returnType.invariant = typeQualifier.invariant; |
2186 | returnType.layoutQualifier = typeQualifier.layoutQualifier; |
2187 | returnType.memoryQualifier = typeQualifier.memoryQualifier; |
2188 | returnType.precision = typeSpecifier.precision; |
2189 | |
2190 | if (typeQualifier.precision != EbpUndefined) |
2191 | { |
2192 | returnType.precision = typeQualifier.precision; |
2193 | } |
2194 | |
2195 | checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision, |
2196 | typeSpecifier.getBasicType()); |
2197 | |
2198 | checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier, |
2199 | typeSpecifier.getLine()); |
2200 | |
2201 | checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier); |
2202 | |
2203 | if (mShaderVersion < 300) |
2204 | { |
2205 | if (typeSpecifier.isArray()) |
2206 | { |
2207 | error(typeSpecifier.getLine(), "not supported" , "first-class array" ); |
2208 | returnType.clearArrayness(); |
2209 | } |
2210 | |
2211 | if (returnType.qualifier == EvqAttribute && |
2212 | (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) |
2213 | { |
2214 | error(typeSpecifier.getLine(), "cannot be bool or int" , |
2215 | getQualifierString(returnType.qualifier)); |
2216 | } |
2217 | |
2218 | if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) && |
2219 | (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) |
2220 | { |
2221 | error(typeSpecifier.getLine(), "cannot be bool or int" , |
2222 | getQualifierString(returnType.qualifier)); |
2223 | } |
2224 | } |
2225 | else |
2226 | { |
2227 | if (!returnType.layoutQualifier.isEmpty()) |
2228 | { |
2229 | checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout" ); |
2230 | } |
2231 | if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || |
2232 | returnType.qualifier == EvqFragmentOut) |
2233 | { |
2234 | checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, |
2235 | typeSpecifier.getLine()); |
2236 | } |
2237 | if (returnType.qualifier == EvqComputeIn) |
2238 | { |
2239 | error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size" , |
2240 | "in" ); |
2241 | } |
2242 | } |
2243 | |
2244 | return returnType; |
2245 | } |
2246 | |
2247 | void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, |
2248 | const TPublicType &type, |
2249 | const TSourceLoc &qualifierLocation) |
2250 | { |
2251 | // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. |
2252 | if (type.getBasicType() == EbtBool) |
2253 | { |
2254 | error(qualifierLocation, "cannot be bool" , getQualifierString(qualifier)); |
2255 | } |
2256 | |
2257 | // Specific restrictions apply for vertex shader inputs and fragment shader outputs. |
2258 | switch (qualifier) |
2259 | { |
2260 | case EvqVertexIn: |
2261 | // ESSL 3.00 section 4.3.4 |
2262 | if (type.isArray()) |
2263 | { |
2264 | error(qualifierLocation, "cannot be array" , getQualifierString(qualifier)); |
2265 | } |
2266 | // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck |
2267 | return; |
2268 | case EvqFragmentOut: |
2269 | // ESSL 3.00 section 4.3.6 |
2270 | if (type.typeSpecifierNonArray.isMatrix()) |
2271 | { |
2272 | error(qualifierLocation, "cannot be matrix" , getQualifierString(qualifier)); |
2273 | } |
2274 | // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck |
2275 | return; |
2276 | default: |
2277 | break; |
2278 | } |
2279 | |
2280 | // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of |
2281 | // restrictions. |
2282 | bool typeContainsIntegers = |
2283 | (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || |
2284 | type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); |
2285 | if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) |
2286 | { |
2287 | error(qualifierLocation, "must use 'flat' interpolation here" , |
2288 | getQualifierString(qualifier)); |
2289 | } |
2290 | |
2291 | if (type.getBasicType() == EbtStruct) |
2292 | { |
2293 | // ESSL 3.00 sections 4.3.4 and 4.3.6. |
2294 | // These restrictions are only implied by the ESSL 3.00 spec, but |
2295 | // the ESSL 3.10 spec lists these restrictions explicitly. |
2296 | if (type.isArray()) |
2297 | { |
2298 | error(qualifierLocation, "cannot be an array of structures" , |
2299 | getQualifierString(qualifier)); |
2300 | } |
2301 | if (type.isStructureContainingArrays()) |
2302 | { |
2303 | error(qualifierLocation, "cannot be a structure containing an array" , |
2304 | getQualifierString(qualifier)); |
2305 | } |
2306 | if (type.isStructureContainingType(EbtStruct)) |
2307 | { |
2308 | error(qualifierLocation, "cannot be a structure containing a structure" , |
2309 | getQualifierString(qualifier)); |
2310 | } |
2311 | if (type.isStructureContainingType(EbtBool)) |
2312 | { |
2313 | error(qualifierLocation, "cannot be a structure containing a bool" , |
2314 | getQualifierString(qualifier)); |
2315 | } |
2316 | } |
2317 | } |
2318 | |
2319 | void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier) |
2320 | { |
2321 | if (qualifier.getType() == QtStorage) |
2322 | { |
2323 | const TStorageQualifierWrapper &storageQualifier = |
2324 | static_cast<const TStorageQualifierWrapper &>(qualifier); |
2325 | if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst && |
2326 | !symbolTable.atGlobalLevel()) |
2327 | { |
2328 | error(storageQualifier.getLine(), |
2329 | "Local variables can only use the const storage qualifier." , |
2330 | storageQualifier.getQualifierString()); |
2331 | } |
2332 | } |
2333 | } |
2334 | |
2335 | void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, |
2336 | const TSourceLoc &location) |
2337 | { |
2338 | const std::string reason( |
2339 | "Only allowed with shader storage blocks, variables declared within shader storage blocks " |
2340 | "and variables declared as image types." ); |
2341 | if (memoryQualifier.readonly) |
2342 | { |
2343 | error(location, reason.c_str(), "readonly" ); |
2344 | } |
2345 | if (memoryQualifier.writeonly) |
2346 | { |
2347 | error(location, reason.c_str(), "writeonly" ); |
2348 | } |
2349 | if (memoryQualifier.coherent) |
2350 | { |
2351 | error(location, reason.c_str(), "coherent" ); |
2352 | } |
2353 | if (memoryQualifier.restrictQualifier) |
2354 | { |
2355 | error(location, reason.c_str(), "restrict" ); |
2356 | } |
2357 | if (memoryQualifier.volatileQualifier) |
2358 | { |
2359 | error(location, reason.c_str(), "volatile" ); |
2360 | } |
2361 | } |
2362 | |
2363 | // Make sure there is no offset overlapping, and store the newly assigned offset to "type" in |
2364 | // intermediate tree. |
2365 | void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, |
2366 | const TSourceLoc &loc, |
2367 | TType *type) |
2368 | { |
2369 | const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct() |
2370 | : kAtomicCounterSize; |
2371 | TLayoutQualifier layoutQualifier = type->getLayoutQualifier(); |
2372 | auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding]; |
2373 | int offset; |
2374 | if (layoutQualifier.offset == -1 || forceAppend) |
2375 | { |
2376 | offset = bindingState.appendSpan(size); |
2377 | } |
2378 | else |
2379 | { |
2380 | offset = bindingState.insertSpan(layoutQualifier.offset, size); |
2381 | } |
2382 | if (offset == -1) |
2383 | { |
2384 | error(loc, "Offset overlapping" , "atomic counter" ); |
2385 | return; |
2386 | } |
2387 | layoutQualifier.offset = offset; |
2388 | type->setLayoutQualifier(layoutQualifier); |
2389 | } |
2390 | |
2391 | void TParseContext::checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type) |
2392 | { |
2393 | TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); |
2394 | |
2395 | // OpenGL ES 3.1 Table 6.5, Atomic counter offset must be a multiple of 4 |
2396 | if (layoutQualifier.offset % 4 != 0) |
2397 | { |
2398 | error(location, "Offset must be multiple of 4" , "atomic counter" ); |
2399 | } |
2400 | } |
2401 | |
2402 | void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, |
2403 | const ImmutableString &token, |
2404 | TType *type) |
2405 | { |
2406 | if (IsGeometryShaderInput(mShaderType, type->getQualifier())) |
2407 | { |
2408 | if (type->isArray() && type->getOutermostArraySize() == 0u) |
2409 | { |
2410 | // Set size for the unsized geometry shader inputs if they are declared after a valid |
2411 | // input primitive declaration. |
2412 | if (mGeometryShaderInputPrimitiveType != EptUndefined) |
2413 | { |
2414 | ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr); |
2415 | type->sizeOutermostUnsizedArray( |
2416 | symbolTable.getGlInVariableWithArraySize()->getType().getOutermostArraySize()); |
2417 | } |
2418 | else |
2419 | { |
2420 | // [GLSL ES 3.2 SPEC Chapter 4.4.1.2] |
2421 | // An input can be declared without an array size if there is a previous layout |
2422 | // which specifies the size. |
2423 | error(location, |
2424 | "Missing a valid input primitive declaration before declaring an unsized " |
2425 | "array input" , |
2426 | token); |
2427 | } |
2428 | } |
2429 | else if (type->isArray()) |
2430 | { |
2431 | setGeometryShaderInputArraySize(type->getOutermostArraySize(), location); |
2432 | } |
2433 | else |
2434 | { |
2435 | error(location, "Geometry shader input variable must be declared as an array" , token); |
2436 | } |
2437 | } |
2438 | } |
2439 | |
2440 | TIntermDeclaration *TParseContext::parseSingleDeclaration( |
2441 | TPublicType &publicType, |
2442 | const TSourceLoc &identifierOrTypeLocation, |
2443 | const ImmutableString &identifier) |
2444 | { |
2445 | TType *type = new TType(publicType); |
2446 | if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && |
2447 | mDirectiveHandler.pragma().stdgl.invariantAll) |
2448 | { |
2449 | TQualifier qualifier = type->getQualifier(); |
2450 | |
2451 | // The directive handler has already taken care of rejecting invalid uses of this pragma |
2452 | // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all |
2453 | // affected variable declarations: |
2454 | // |
2455 | // 1. Built-in special variables which are inputs to the fragment shader. (These are handled |
2456 | // elsewhere, in TranslatorGLSL.) |
2457 | // |
2458 | // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It |
2459 | // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but |
2460 | // the way this is currently implemented we have to enable this compiler option before |
2461 | // parsing the shader and determining the shading language version it uses. If this were |
2462 | // implemented as a post-pass, the workaround could be more targeted. |
2463 | // |
2464 | // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of |
2465 | // the specification, but there are desktop OpenGL drivers that expect that this is the |
2466 | // behavior of the #pragma when specified in ESSL 1.00 fragment shaders. |
2467 | if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn) |
2468 | { |
2469 | type->setInvariant(true); |
2470 | } |
2471 | } |
2472 | |
2473 | checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type); |
2474 | |
2475 | declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, |
2476 | identifierOrTypeLocation); |
2477 | |
2478 | bool emptyDeclaration = (identifier == "" ); |
2479 | mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration; |
2480 | |
2481 | TIntermSymbol *symbol = nullptr; |
2482 | if (emptyDeclaration) |
2483 | { |
2484 | emptyDeclarationErrorCheck(*type, identifierOrTypeLocation); |
2485 | // In most cases we don't need to create a symbol node for an empty declaration. |
2486 | // But if the empty declaration is declaring a struct type, the symbol node will store that. |
2487 | if (type->getBasicType() == EbtStruct) |
2488 | { |
2489 | TVariable *emptyVariable = |
2490 | new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty); |
2491 | symbol = new TIntermSymbol(emptyVariable); |
2492 | } |
2493 | else if (IsAtomicCounter(publicType.getBasicType())) |
2494 | { |
2495 | setAtomicCounterBindingDefaultOffset(publicType, identifierOrTypeLocation); |
2496 | } |
2497 | } |
2498 | else |
2499 | { |
2500 | nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation); |
2501 | |
2502 | checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, type); |
2503 | |
2504 | if (IsAtomicCounter(type->getBasicType())) |
2505 | { |
2506 | checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, type); |
2507 | |
2508 | checkAtomicCounterOffsetAlignment(identifierOrTypeLocation, *type); |
2509 | } |
2510 | |
2511 | TVariable *variable = nullptr; |
2512 | if (declareVariable(identifierOrTypeLocation, identifier, type, &variable)) |
2513 | { |
2514 | symbol = new TIntermSymbol(variable); |
2515 | } |
2516 | } |
2517 | |
2518 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
2519 | declaration->setLine(identifierOrTypeLocation); |
2520 | if (symbol) |
2521 | { |
2522 | symbol->setLine(identifierOrTypeLocation); |
2523 | declaration->appendDeclarator(symbol); |
2524 | } |
2525 | return declaration; |
2526 | } |
2527 | |
2528 | TIntermDeclaration *TParseContext::parseSingleArrayDeclaration( |
2529 | TPublicType &elementType, |
2530 | const TSourceLoc &identifierLocation, |
2531 | const ImmutableString &identifier, |
2532 | const TSourceLoc &indexLocation, |
2533 | const TVector<unsigned int> &arraySizes) |
2534 | { |
2535 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2536 | |
2537 | declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, |
2538 | identifierLocation); |
2539 | |
2540 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); |
2541 | |
2542 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); |
2543 | |
2544 | TType *arrayType = new TType(elementType); |
2545 | arrayType->makeArrays(arraySizes); |
2546 | |
2547 | checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType); |
2548 | |
2549 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); |
2550 | |
2551 | if (IsAtomicCounter(arrayType->getBasicType())) |
2552 | { |
2553 | checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, arrayType); |
2554 | |
2555 | checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); |
2556 | } |
2557 | |
2558 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
2559 | declaration->setLine(identifierLocation); |
2560 | |
2561 | TVariable *variable = nullptr; |
2562 | if (declareVariable(identifierLocation, identifier, arrayType, &variable)) |
2563 | { |
2564 | TIntermSymbol *symbol = new TIntermSymbol(variable); |
2565 | symbol->setLine(identifierLocation); |
2566 | declaration->appendDeclarator(symbol); |
2567 | } |
2568 | |
2569 | return declaration; |
2570 | } |
2571 | |
2572 | TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, |
2573 | const TSourceLoc &identifierLocation, |
2574 | const ImmutableString &identifier, |
2575 | const TSourceLoc &initLocation, |
2576 | TIntermTyped *initializer) |
2577 | { |
2578 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2579 | |
2580 | declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, |
2581 | identifierLocation); |
2582 | |
2583 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); |
2584 | |
2585 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
2586 | declaration->setLine(identifierLocation); |
2587 | |
2588 | TIntermBinary *initNode = nullptr; |
2589 | TType *type = new TType(publicType); |
2590 | if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) |
2591 | { |
2592 | if (initNode) |
2593 | { |
2594 | declaration->appendDeclarator(initNode); |
2595 | } |
2596 | } |
2597 | return declaration; |
2598 | } |
2599 | |
2600 | TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration( |
2601 | TPublicType &elementType, |
2602 | const TSourceLoc &identifierLocation, |
2603 | const ImmutableString &identifier, |
2604 | const TSourceLoc &indexLocation, |
2605 | const TVector<unsigned int> &arraySizes, |
2606 | const TSourceLoc &initLocation, |
2607 | TIntermTyped *initializer) |
2608 | { |
2609 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2610 | |
2611 | declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, |
2612 | identifierLocation); |
2613 | |
2614 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); |
2615 | |
2616 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); |
2617 | |
2618 | TType *arrayType = new TType(elementType); |
2619 | arrayType->makeArrays(arraySizes); |
2620 | |
2621 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
2622 | declaration->setLine(identifierLocation); |
2623 | |
2624 | // initNode will correspond to the whole of "type b[n] = initializer". |
2625 | TIntermBinary *initNode = nullptr; |
2626 | if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) |
2627 | { |
2628 | if (initNode) |
2629 | { |
2630 | declaration->appendDeclarator(initNode); |
2631 | } |
2632 | } |
2633 | |
2634 | return declaration; |
2635 | } |
2636 | |
2637 | TIntermInvariantDeclaration *TParseContext::parseInvariantDeclaration( |
2638 | const TTypeQualifierBuilder &typeQualifierBuilder, |
2639 | const TSourceLoc &identifierLoc, |
2640 | const ImmutableString &identifier, |
2641 | const TSymbol *symbol) |
2642 | { |
2643 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); |
2644 | |
2645 | if (!typeQualifier.invariant) |
2646 | { |
2647 | error(identifierLoc, "Expected invariant" , identifier); |
2648 | return nullptr; |
2649 | } |
2650 | if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying" )) |
2651 | { |
2652 | return nullptr; |
2653 | } |
2654 | if (!symbol) |
2655 | { |
2656 | error(identifierLoc, "undeclared identifier declared as invariant" , identifier); |
2657 | return nullptr; |
2658 | } |
2659 | if (!IsQualifierUnspecified(typeQualifier.qualifier)) |
2660 | { |
2661 | error(identifierLoc, "invariant declaration specifies qualifier" , |
2662 | getQualifierString(typeQualifier.qualifier)); |
2663 | } |
2664 | if (typeQualifier.precision != EbpUndefined) |
2665 | { |
2666 | error(identifierLoc, "invariant declaration specifies precision" , |
2667 | getPrecisionString(typeQualifier.precision)); |
2668 | } |
2669 | if (!typeQualifier.layoutQualifier.isEmpty()) |
2670 | { |
2671 | error(identifierLoc, "invariant declaration specifies layout" , "'layout'" ); |
2672 | } |
2673 | |
2674 | const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); |
2675 | if (!variable) |
2676 | { |
2677 | return nullptr; |
2678 | } |
2679 | const TType &type = variable->getType(); |
2680 | |
2681 | checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(), |
2682 | typeQualifier.line); |
2683 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); |
2684 | |
2685 | symbolTable.addInvariantVarying(*variable); |
2686 | |
2687 | TIntermSymbol *intermSymbol = new TIntermSymbol(variable); |
2688 | intermSymbol->setLine(identifierLoc); |
2689 | |
2690 | return new TIntermInvariantDeclaration(intermSymbol, identifierLoc); |
2691 | } |
2692 | |
2693 | void TParseContext::parseDeclarator(TPublicType &publicType, |
2694 | const TSourceLoc &identifierLocation, |
2695 | const ImmutableString &identifier, |
2696 | TIntermDeclaration *declarationOut) |
2697 | { |
2698 | // If the declaration starting this declarator list was empty (example: int,), some checks were |
2699 | // not performed. |
2700 | if (mDeferredNonEmptyDeclarationErrorCheck) |
2701 | { |
2702 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); |
2703 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2704 | } |
2705 | |
2706 | checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); |
2707 | |
2708 | TType *type = new TType(publicType); |
2709 | |
2710 | checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type); |
2711 | |
2712 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type); |
2713 | |
2714 | if (IsAtomicCounter(type->getBasicType())) |
2715 | { |
2716 | checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, type); |
2717 | |
2718 | checkAtomicCounterOffsetAlignment(identifierLocation, *type); |
2719 | } |
2720 | |
2721 | TVariable *variable = nullptr; |
2722 | if (declareVariable(identifierLocation, identifier, type, &variable)) |
2723 | { |
2724 | TIntermSymbol *symbol = new TIntermSymbol(variable); |
2725 | symbol->setLine(identifierLocation); |
2726 | declarationOut->appendDeclarator(symbol); |
2727 | } |
2728 | } |
2729 | |
2730 | void TParseContext::parseArrayDeclarator(TPublicType &elementType, |
2731 | const TSourceLoc &identifierLocation, |
2732 | const ImmutableString &identifier, |
2733 | const TSourceLoc &arrayLocation, |
2734 | const TVector<unsigned int> &arraySizes, |
2735 | TIntermDeclaration *declarationOut) |
2736 | { |
2737 | // If the declaration starting this declarator list was empty (example: int,), some checks were |
2738 | // not performed. |
2739 | if (mDeferredNonEmptyDeclarationErrorCheck) |
2740 | { |
2741 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); |
2742 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2743 | } |
2744 | |
2745 | checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); |
2746 | |
2747 | if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType)) |
2748 | { |
2749 | TType *arrayType = new TType(elementType); |
2750 | arrayType->makeArrays(arraySizes); |
2751 | |
2752 | checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType); |
2753 | |
2754 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); |
2755 | |
2756 | if (IsAtomicCounter(arrayType->getBasicType())) |
2757 | { |
2758 | checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, arrayType); |
2759 | |
2760 | checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); |
2761 | } |
2762 | |
2763 | TVariable *variable = nullptr; |
2764 | if (declareVariable(identifierLocation, identifier, arrayType, &variable)) |
2765 | { |
2766 | TIntermSymbol *symbol = new TIntermSymbol(variable); |
2767 | symbol->setLine(identifierLocation); |
2768 | declarationOut->appendDeclarator(symbol); |
2769 | } |
2770 | } |
2771 | } |
2772 | |
2773 | void TParseContext::parseInitDeclarator(const TPublicType &publicType, |
2774 | const TSourceLoc &identifierLocation, |
2775 | const ImmutableString &identifier, |
2776 | const TSourceLoc &initLocation, |
2777 | TIntermTyped *initializer, |
2778 | TIntermDeclaration *declarationOut) |
2779 | { |
2780 | // If the declaration starting this declarator list was empty (example: int,), some checks were |
2781 | // not performed. |
2782 | if (mDeferredNonEmptyDeclarationErrorCheck) |
2783 | { |
2784 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); |
2785 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2786 | } |
2787 | |
2788 | checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); |
2789 | |
2790 | TIntermBinary *initNode = nullptr; |
2791 | TType *type = new TType(publicType); |
2792 | if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) |
2793 | { |
2794 | // |
2795 | // build the intermediate representation |
2796 | // |
2797 | if (initNode) |
2798 | { |
2799 | declarationOut->appendDeclarator(initNode); |
2800 | } |
2801 | } |
2802 | } |
2803 | |
2804 | void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType, |
2805 | const TSourceLoc &identifierLocation, |
2806 | const ImmutableString &identifier, |
2807 | const TSourceLoc &indexLocation, |
2808 | const TVector<unsigned int> &arraySizes, |
2809 | const TSourceLoc &initLocation, |
2810 | TIntermTyped *initializer, |
2811 | TIntermDeclaration *declarationOut) |
2812 | { |
2813 | // If the declaration starting this declarator list was empty (example: int,), some checks were |
2814 | // not performed. |
2815 | if (mDeferredNonEmptyDeclarationErrorCheck) |
2816 | { |
2817 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); |
2818 | mDeferredNonEmptyDeclarationErrorCheck = false; |
2819 | } |
2820 | |
2821 | checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); |
2822 | |
2823 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); |
2824 | |
2825 | TType *arrayType = new TType(elementType); |
2826 | arrayType->makeArrays(arraySizes); |
2827 | |
2828 | // initNode will correspond to the whole of "b[n] = initializer". |
2829 | TIntermBinary *initNode = nullptr; |
2830 | if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) |
2831 | { |
2832 | if (initNode) |
2833 | { |
2834 | declarationOut->appendDeclarator(initNode); |
2835 | } |
2836 | } |
2837 | } |
2838 | |
2839 | TIntermNode *TParseContext::addEmptyStatement(const TSourceLoc &location) |
2840 | { |
2841 | // It's simpler to parse an empty statement as a constant expression rather than having a |
2842 | // different type of node just for empty statements, that will be pruned from the AST anyway. |
2843 | TIntermNode *node = CreateZeroNode(TType(EbtInt, EbpMedium)); |
2844 | node->setLine(location); |
2845 | return node; |
2846 | } |
2847 | |
2848 | void TParseContext::setAtomicCounterBindingDefaultOffset(const TPublicType &publicType, |
2849 | const TSourceLoc &location) |
2850 | { |
2851 | const TLayoutQualifier &layoutQualifier = publicType.layoutQualifier; |
2852 | checkAtomicCounterBindingIsValid(location, layoutQualifier.binding); |
2853 | if (layoutQualifier.binding == -1 || layoutQualifier.offset == -1) |
2854 | { |
2855 | error(location, "Requires both binding and offset" , "layout" ); |
2856 | return; |
2857 | } |
2858 | mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset); |
2859 | } |
2860 | |
2861 | void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision, |
2862 | const TPublicType &type, |
2863 | const TSourceLoc &loc) |
2864 | { |
2865 | if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER) && |
2866 | !getFragmentPrecisionHigh()) |
2867 | { |
2868 | error(loc, "precision is not supported in fragment shader" , "highp" ); |
2869 | } |
2870 | |
2871 | if (!CanSetDefaultPrecisionOnType(type)) |
2872 | { |
2873 | error(loc, "illegal type argument for default precision qualifier" , |
2874 | getBasicString(type.getBasicType())); |
2875 | return; |
2876 | } |
2877 | symbolTable.setDefaultPrecision(type.getBasicType(), precision); |
2878 | } |
2879 | |
2880 | bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier) |
2881 | { |
2882 | switch (typeQualifier.layoutQualifier.primitiveType) |
2883 | { |
2884 | case EptLines: |
2885 | case EptLinesAdjacency: |
2886 | case EptTriangles: |
2887 | case EptTrianglesAdjacency: |
2888 | return typeQualifier.qualifier == EvqGeometryIn; |
2889 | |
2890 | case EptLineStrip: |
2891 | case EptTriangleStrip: |
2892 | return typeQualifier.qualifier == EvqGeometryOut; |
2893 | |
2894 | case EptPoints: |
2895 | return true; |
2896 | |
2897 | default: |
2898 | UNREACHABLE(); |
2899 | return false; |
2900 | } |
2901 | } |
2902 | |
2903 | void TParseContext::setGeometryShaderInputArraySize(unsigned int inputArraySize, |
2904 | const TSourceLoc &line) |
2905 | { |
2906 | if (!symbolTable.setGlInArraySize(inputArraySize)) |
2907 | { |
2908 | error(line, |
2909 | "Array size or input primitive declaration doesn't match the size of earlier sized " |
2910 | "array inputs." , |
2911 | "layout" ); |
2912 | } |
2913 | } |
2914 | |
2915 | bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier) |
2916 | { |
2917 | ASSERT(typeQualifier.qualifier == EvqGeometryIn); |
2918 | |
2919 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; |
2920 | |
2921 | if (layoutQualifier.maxVertices != -1) |
2922 | { |
2923 | error(typeQualifier.line, |
2924 | "max_vertices can only be declared in 'out' layout in a geometry shader" , "layout" ); |
2925 | return false; |
2926 | } |
2927 | |
2928 | // Set mGeometryInputPrimitiveType if exists |
2929 | if (layoutQualifier.primitiveType != EptUndefined) |
2930 | { |
2931 | if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) |
2932 | { |
2933 | error(typeQualifier.line, "invalid primitive type for 'in' layout" , "layout" ); |
2934 | return false; |
2935 | } |
2936 | |
2937 | if (mGeometryShaderInputPrimitiveType == EptUndefined) |
2938 | { |
2939 | mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType; |
2940 | setGeometryShaderInputArraySize( |
2941 | GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType), |
2942 | typeQualifier.line); |
2943 | } |
2944 | else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType) |
2945 | { |
2946 | error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration" , |
2947 | "layout" ); |
2948 | return false; |
2949 | } |
2950 | } |
2951 | |
2952 | // Set mGeometryInvocations if exists |
2953 | if (layoutQualifier.invocations > 0) |
2954 | { |
2955 | if (mGeometryShaderInvocations == 0) |
2956 | { |
2957 | mGeometryShaderInvocations = layoutQualifier.invocations; |
2958 | } |
2959 | else if (mGeometryShaderInvocations != layoutQualifier.invocations) |
2960 | { |
2961 | error(typeQualifier.line, "invocations contradicts to the earlier declaration" , |
2962 | "layout" ); |
2963 | return false; |
2964 | } |
2965 | } |
2966 | |
2967 | return true; |
2968 | } |
2969 | |
2970 | bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier) |
2971 | { |
2972 | ASSERT(typeQualifier.qualifier == EvqGeometryOut); |
2973 | |
2974 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; |
2975 | |
2976 | if (layoutQualifier.invocations > 0) |
2977 | { |
2978 | error(typeQualifier.line, |
2979 | "invocations can only be declared in 'in' layout in a geometry shader" , "layout" ); |
2980 | return false; |
2981 | } |
2982 | |
2983 | // Set mGeometryOutputPrimitiveType if exists |
2984 | if (layoutQualifier.primitiveType != EptUndefined) |
2985 | { |
2986 | if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) |
2987 | { |
2988 | error(typeQualifier.line, "invalid primitive type for 'out' layout" , "layout" ); |
2989 | return false; |
2990 | } |
2991 | |
2992 | if (mGeometryShaderOutputPrimitiveType == EptUndefined) |
2993 | { |
2994 | mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType; |
2995 | } |
2996 | else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType) |
2997 | { |
2998 | error(typeQualifier.line, |
2999 | "primitive doesn't match earlier output primitive declaration" , "layout" ); |
3000 | return false; |
3001 | } |
3002 | } |
3003 | |
3004 | // Set mGeometryMaxVertices if exists |
3005 | if (layoutQualifier.maxVertices > -1) |
3006 | { |
3007 | if (mGeometryShaderMaxVertices == -1) |
3008 | { |
3009 | mGeometryShaderMaxVertices = layoutQualifier.maxVertices; |
3010 | } |
3011 | else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices) |
3012 | { |
3013 | error(typeQualifier.line, "max_vertices contradicts to the earlier declaration" , |
3014 | "layout" ); |
3015 | return false; |
3016 | } |
3017 | } |
3018 | |
3019 | return true; |
3020 | } |
3021 | |
3022 | void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) |
3023 | { |
3024 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); |
3025 | const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; |
3026 | |
3027 | checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier, |
3028 | typeQualifier.line); |
3029 | |
3030 | // It should never be the case, but some strange parser errors can send us here. |
3031 | if (layoutQualifier.isEmpty()) |
3032 | { |
3033 | error(typeQualifier.line, "Error during layout qualifier parsing." , "?" ); |
3034 | return; |
3035 | } |
3036 | |
3037 | if (!layoutQualifier.isCombinationValid()) |
3038 | { |
3039 | error(typeQualifier.line, "invalid layout qualifier combination" , "layout" ); |
3040 | return; |
3041 | } |
3042 | |
3043 | checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index); |
3044 | |
3045 | checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding); |
3046 | |
3047 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); |
3048 | |
3049 | checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat); |
3050 | |
3051 | checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv); |
3052 | |
3053 | checkOffsetIsNotSpecified(typeQualifier.line, layoutQualifier.offset); |
3054 | |
3055 | checkStd430IsForShaderStorageBlock(typeQualifier.line, layoutQualifier.blockStorage, |
3056 | typeQualifier.qualifier); |
3057 | |
3058 | if (typeQualifier.qualifier == EvqComputeIn) |
3059 | { |
3060 | if (mComputeShaderLocalSizeDeclared && |
3061 | !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize)) |
3062 | { |
3063 | error(typeQualifier.line, "Work group size does not match the previous declaration" , |
3064 | "layout" ); |
3065 | return; |
3066 | } |
3067 | |
3068 | if (mShaderVersion < 310) |
3069 | { |
3070 | error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only" , "layout" ); |
3071 | return; |
3072 | } |
3073 | |
3074 | if (!layoutQualifier.localSize.isAnyValueSet()) |
3075 | { |
3076 | error(typeQualifier.line, "No local work group size specified" , "layout" ); |
3077 | return; |
3078 | } |
3079 | |
3080 | const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>( |
3081 | symbolTable.findBuiltIn(ImmutableString("gl_MaxComputeWorkGroupSize" ), mShaderVersion)); |
3082 | |
3083 | const TConstantUnion *maxComputeWorkGroupSizeData = |
3084 | maxComputeWorkGroupSize->getConstPointer(); |
3085 | |
3086 | for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i) |
3087 | { |
3088 | if (layoutQualifier.localSize[i] != -1) |
3089 | { |
3090 | mComputeShaderLocalSize[i] = layoutQualifier.localSize[i]; |
3091 | const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst(); |
3092 | if (mComputeShaderLocalSize[i] < 1 || |
3093 | mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue) |
3094 | { |
3095 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
3096 | reasonStream << "invalid value: Value must be at least 1 and no greater than " |
3097 | << maxComputeWorkGroupSizeValue; |
3098 | const std::string &reason = reasonStream.str(); |
3099 | |
3100 | error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i)); |
3101 | return; |
3102 | } |
3103 | } |
3104 | } |
3105 | |
3106 | mComputeShaderLocalSizeDeclared = true; |
3107 | } |
3108 | else if (typeQualifier.qualifier == EvqGeometryIn) |
3109 | { |
3110 | if (mShaderVersion < 310) |
3111 | { |
3112 | error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only" , "layout" ); |
3113 | return; |
3114 | } |
3115 | |
3116 | if (!parseGeometryShaderInputLayoutQualifier(typeQualifier)) |
3117 | { |
3118 | return; |
3119 | } |
3120 | } |
3121 | else if (typeQualifier.qualifier == EvqGeometryOut) |
3122 | { |
3123 | if (mShaderVersion < 310) |
3124 | { |
3125 | error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only" , |
3126 | "layout" ); |
3127 | return; |
3128 | } |
3129 | |
3130 | if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier)) |
3131 | { |
3132 | return; |
3133 | } |
3134 | } |
3135 | else if (isExtensionEnabled(TExtension::OVR_multiview2) && |
3136 | typeQualifier.qualifier == EvqVertexIn) |
3137 | { |
3138 | // This error is only specified in WebGL, but tightens unspecified behavior in the native |
3139 | // specification. |
3140 | if (mNumViews != -1 && layoutQualifier.numViews != mNumViews) |
3141 | { |
3142 | error(typeQualifier.line, "Number of views does not match the previous declaration" , |
3143 | "layout" ); |
3144 | return; |
3145 | } |
3146 | |
3147 | if (layoutQualifier.numViews == -1) |
3148 | { |
3149 | error(typeQualifier.line, "No num_views specified" , "layout" ); |
3150 | return; |
3151 | } |
3152 | |
3153 | if (layoutQualifier.numViews > mMaxNumViews) |
3154 | { |
3155 | error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR" , |
3156 | "layout" ); |
3157 | return; |
3158 | } |
3159 | |
3160 | mNumViews = layoutQualifier.numViews; |
3161 | } |
3162 | else |
3163 | { |
3164 | if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier)) |
3165 | { |
3166 | return; |
3167 | } |
3168 | |
3169 | if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) |
3170 | { |
3171 | error(typeQualifier.line, "invalid qualifier: global layout can only be set for blocks" , |
3172 | getQualifierString(typeQualifier.qualifier)); |
3173 | return; |
3174 | } |
3175 | |
3176 | if (mShaderVersion < 300) |
3177 | { |
3178 | error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above" , |
3179 | "layout" ); |
3180 | return; |
3181 | } |
3182 | |
3183 | checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier); |
3184 | |
3185 | if (layoutQualifier.matrixPacking != EmpUnspecified) |
3186 | { |
3187 | if (typeQualifier.qualifier == EvqUniform) |
3188 | { |
3189 | mDefaultUniformMatrixPacking = layoutQualifier.matrixPacking; |
3190 | } |
3191 | else if (typeQualifier.qualifier == EvqBuffer) |
3192 | { |
3193 | mDefaultBufferMatrixPacking = layoutQualifier.matrixPacking; |
3194 | } |
3195 | } |
3196 | |
3197 | if (layoutQualifier.blockStorage != EbsUnspecified) |
3198 | { |
3199 | if (typeQualifier.qualifier == EvqUniform) |
3200 | { |
3201 | mDefaultUniformBlockStorage = layoutQualifier.blockStorage; |
3202 | } |
3203 | else if (typeQualifier.qualifier == EvqBuffer) |
3204 | { |
3205 | mDefaultBufferBlockStorage = layoutQualifier.blockStorage; |
3206 | } |
3207 | } |
3208 | } |
3209 | } |
3210 | |
3211 | TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction( |
3212 | const TFunction &function, |
3213 | const TSourceLoc &location, |
3214 | bool insertParametersToSymbolTable) |
3215 | { |
3216 | checkIsNotReserved(location, function.name()); |
3217 | |
3218 | TIntermFunctionPrototype *prototype = new TIntermFunctionPrototype(&function); |
3219 | prototype->setLine(location); |
3220 | |
3221 | for (size_t i = 0; i < function.getParamCount(); i++) |
3222 | { |
3223 | const TVariable *param = function.getParam(i); |
3224 | |
3225 | // If the parameter has no name, it's not an error, just don't add it to symbol table (could |
3226 | // be used for unused args). |
3227 | if (param->symbolType() != SymbolType::Empty) |
3228 | { |
3229 | if (insertParametersToSymbolTable) |
3230 | { |
3231 | if (!symbolTable.declare(const_cast<TVariable *>(param))) |
3232 | { |
3233 | error(location, "redefinition" , param->name()); |
3234 | } |
3235 | } |
3236 | // Unsized type of a named parameter should have already been checked and sanitized. |
3237 | ASSERT(!param->getType().isUnsizedArray()); |
3238 | } |
3239 | else |
3240 | { |
3241 | if (param->getType().isUnsizedArray()) |
3242 | { |
3243 | error(location, "function parameter array must be sized at compile time" , "[]" ); |
3244 | // We don't need to size the arrays since the parameter is unnamed and hence |
3245 | // inaccessible. |
3246 | } |
3247 | } |
3248 | } |
3249 | return prototype; |
3250 | } |
3251 | |
3252 | TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration( |
3253 | const TFunction &parsedFunction, |
3254 | const TSourceLoc &location) |
3255 | { |
3256 | // Note: function found from the symbol table could be the same as parsedFunction if this is the |
3257 | // first declaration. Either way the instance in the symbol table is used to track whether the |
3258 | // function is declared multiple times. |
3259 | bool hadPrototypeDeclaration = false; |
3260 | const TFunction *function = symbolTable.markFunctionHasPrototypeDeclaration( |
3261 | parsedFunction.getMangledName(), &hadPrototypeDeclaration); |
3262 | |
3263 | if (hadPrototypeDeclaration && mShaderVersion == 100) |
3264 | { |
3265 | // ESSL 1.00.17 section 4.2.7. |
3266 | // Doesn't apply to ESSL 3.00.4: see section 4.2.3. |
3267 | error(location, "duplicate function prototype declarations are not allowed" , "function" ); |
3268 | } |
3269 | |
3270 | TIntermFunctionPrototype *prototype = |
3271 | createPrototypeNodeFromFunction(*function, location, false); |
3272 | |
3273 | symbolTable.pop(); |
3274 | |
3275 | if (!symbolTable.atGlobalLevel()) |
3276 | { |
3277 | // ESSL 3.00.4 section 4.2.4. |
3278 | error(location, "local function prototype declarations are not allowed" , "function" ); |
3279 | } |
3280 | |
3281 | return prototype; |
3282 | } |
3283 | |
3284 | TIntermFunctionDefinition *TParseContext::addFunctionDefinition( |
3285 | TIntermFunctionPrototype *functionPrototype, |
3286 | TIntermBlock *functionBody, |
3287 | const TSourceLoc &location) |
3288 | { |
3289 | // Check that non-void functions have at least one return statement. |
3290 | if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) |
3291 | { |
3292 | error(location, |
3293 | "function does not return a value:" , functionPrototype->getFunction()->name()); |
3294 | } |
3295 | |
3296 | if (functionBody == nullptr) |
3297 | { |
3298 | functionBody = new TIntermBlock(); |
3299 | functionBody->setLine(location); |
3300 | } |
3301 | TIntermFunctionDefinition *functionNode = |
3302 | new TIntermFunctionDefinition(functionPrototype, functionBody); |
3303 | functionNode->setLine(location); |
3304 | |
3305 | symbolTable.pop(); |
3306 | return functionNode; |
3307 | } |
3308 | |
3309 | void TParseContext::(const TSourceLoc &location, |
3310 | const TFunction *function, |
3311 | TIntermFunctionPrototype **prototypeOut) |
3312 | { |
3313 | ASSERT(function); |
3314 | |
3315 | bool wasDefined = false; |
3316 | function = symbolTable.setFunctionParameterNamesFromDefinition(function, &wasDefined); |
3317 | if (wasDefined) |
3318 | { |
3319 | error(location, "function already has a body" , function->name()); |
3320 | } |
3321 | |
3322 | // Remember the return type for later checking for return statements. |
3323 | mCurrentFunctionType = &(function->getReturnType()); |
3324 | mFunctionReturnsValue = false; |
3325 | |
3326 | *prototypeOut = createPrototypeNodeFromFunction(*function, location, true); |
3327 | setLoopNestingLevel(0); |
3328 | } |
3329 | |
3330 | TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function) |
3331 | { |
3332 | // |
3333 | // We don't know at this point whether this is a function definition or a prototype. |
3334 | // The definition production code will check for redefinitions. |
3335 | // In the case of ESSL 1.00 the prototype production code will also check for redeclarations. |
3336 | // |
3337 | |
3338 | for (size_t i = 0u; i < function->getParamCount(); ++i) |
3339 | { |
3340 | const TVariable *param = function->getParam(i); |
3341 | if (param->getType().isStructSpecifier()) |
3342 | { |
3343 | // ESSL 3.00.6 section 12.10. |
3344 | error(location, "Function parameter type cannot be a structure definition" , |
3345 | function->name()); |
3346 | } |
3347 | } |
3348 | |
3349 | if (getShaderVersion() >= 300) |
3350 | { |
3351 | const UnmangledBuiltIn *builtIn = |
3352 | symbolTable.getUnmangledBuiltInForShaderVersion(function->name(), getShaderVersion()); |
3353 | if (builtIn && |
3354 | (builtIn->extension == TExtension::UNDEFINED || isExtensionEnabled(builtIn->extension))) |
3355 | { |
3356 | // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as |
3357 | // functions. Therefore overloading or redefining builtin functions is an error. |
3358 | error(location, "Name of a built-in function cannot be redeclared as function" , |
3359 | function->name()); |
3360 | } |
3361 | } |
3362 | else |
3363 | { |
3364 | // ESSL 1.00.17 section 4.2.6: built-ins can be overloaded but not redefined. We assume that |
3365 | // this applies to redeclarations as well. |
3366 | const TSymbol *builtIn = |
3367 | symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion()); |
3368 | if (builtIn) |
3369 | { |
3370 | error(location, "built-in functions cannot be redefined" , function->name()); |
3371 | } |
3372 | } |
3373 | |
3374 | // Return types and parameter qualifiers must match in all redeclarations, so those are checked |
3375 | // here. |
3376 | const TFunction *prevDec = |
3377 | static_cast<const TFunction *>(symbolTable.findGlobal(function->getMangledName())); |
3378 | if (prevDec) |
3379 | { |
3380 | if (prevDec->getReturnType() != function->getReturnType()) |
3381 | { |
3382 | error(location, "function must have the same return type in all of its declarations" , |
3383 | function->getReturnType().getBasicString()); |
3384 | } |
3385 | for (size_t i = 0; i < prevDec->getParamCount(); ++i) |
3386 | { |
3387 | if (prevDec->getParam(i)->getType().getQualifier() != |
3388 | function->getParam(i)->getType().getQualifier()) |
3389 | { |
3390 | error(location, |
3391 | "function must have the same parameter qualifiers in all of its declarations" , |
3392 | function->getParam(i)->getType().getQualifierString()); |
3393 | } |
3394 | } |
3395 | } |
3396 | |
3397 | // Check for previously declared variables using the same name. |
3398 | const TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion()); |
3399 | bool insertUnmangledName = true; |
3400 | if (prevSym) |
3401 | { |
3402 | if (!prevSym->isFunction()) |
3403 | { |
3404 | error(location, "redefinition of a function" , function->name()); |
3405 | } |
3406 | insertUnmangledName = false; |
3407 | } |
3408 | // Parsing is at the inner scope level of the function's arguments and body statement at this |
3409 | // point, but declareUserDefinedFunction takes care of declaring the function at the global |
3410 | // scope. |
3411 | symbolTable.declareUserDefinedFunction(function, insertUnmangledName); |
3412 | |
3413 | // Raise error message if main function takes any parameters or return anything other than void |
3414 | if (function->isMain()) |
3415 | { |
3416 | if (function->getParamCount() > 0) |
3417 | { |
3418 | error(location, "function cannot take any parameter(s)" , "main" ); |
3419 | } |
3420 | if (function->getReturnType().getBasicType() != EbtVoid) |
3421 | { |
3422 | error(location, "main function cannot return a value" , |
3423 | function->getReturnType().getBasicString()); |
3424 | } |
3425 | } |
3426 | |
3427 | // |
3428 | // If this is a redeclaration, it could also be a definition, in which case, we want to use the |
3429 | // variable names from this one, and not the one that's |
3430 | // being redeclared. So, pass back up this declaration, not the one in the symbol table. |
3431 | // |
3432 | return function; |
3433 | } |
3434 | |
3435 | TFunction *TParseContext::(const TPublicType &type, |
3436 | const ImmutableString &name, |
3437 | const TSourceLoc &location) |
3438 | { |
3439 | if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary) |
3440 | { |
3441 | error(location, "no qualifiers allowed for function return" , |
3442 | getQualifierString(type.qualifier)); |
3443 | } |
3444 | if (!type.layoutQualifier.isEmpty()) |
3445 | { |
3446 | error(location, "no qualifiers allowed for function return" , "layout" ); |
3447 | } |
3448 | // make sure an opaque type is not involved as well... |
3449 | std::string reason(getBasicString(type.getBasicType())); |
3450 | reason += "s can't be function return values" ; |
3451 | checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str()); |
3452 | if (mShaderVersion < 300) |
3453 | { |
3454 | // Array return values are forbidden, but there's also no valid syntax for declaring array |
3455 | // return values in ESSL 1.00. |
3456 | ASSERT(!type.isArray() || mDiagnostics->numErrors() > 0); |
3457 | |
3458 | if (type.isStructureContainingArrays()) |
3459 | { |
3460 | // ESSL 1.00.17 section 6.1 Function Definitions |
3461 | TInfoSinkBase typeString; |
3462 | typeString << TType(type); |
3463 | error(location, "structures containing arrays can't be function return values" , |
3464 | typeString.c_str()); |
3465 | } |
3466 | } |
3467 | |
3468 | // Add the function as a prototype after parsing it (we do not support recursion) |
3469 | return new TFunction(&symbolTable, name, SymbolType::UserDefined, new TType(type), false); |
3470 | } |
3471 | |
3472 | TFunctionLookup *TParseContext::addNonConstructorFunc(const ImmutableString &name, |
3473 | const TSymbol *symbol) |
3474 | { |
3475 | return TFunctionLookup::CreateFunctionCall(name, symbol); |
3476 | } |
3477 | |
3478 | TFunctionLookup *TParseContext::addConstructorFunc(const TPublicType &publicType) |
3479 | { |
3480 | if (mShaderVersion < 300 && publicType.isArray()) |
3481 | { |
3482 | error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only" , |
3483 | "[]" ); |
3484 | } |
3485 | if (publicType.isStructSpecifier()) |
3486 | { |
3487 | error(publicType.getLine(), "constructor can't be a structure definition" , |
3488 | getBasicString(publicType.getBasicType())); |
3489 | } |
3490 | |
3491 | TType *type = new TType(publicType); |
3492 | if (!type->canBeConstructed()) |
3493 | { |
3494 | error(publicType.getLine(), "cannot construct this type" , |
3495 | getBasicString(publicType.getBasicType())); |
3496 | type->setBasicType(EbtFloat); |
3497 | } |
3498 | return TFunctionLookup::CreateConstructor(type); |
3499 | } |
3500 | |
3501 | void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line, |
3502 | const char *errorMessage, |
3503 | const ImmutableString &token, |
3504 | TType *arrayType) |
3505 | { |
3506 | if (arrayType->isUnsizedArray()) |
3507 | { |
3508 | error(line, errorMessage, token); |
3509 | arrayType->sizeUnsizedArrays(nullptr); |
3510 | } |
3511 | } |
3512 | |
3513 | TParameter TParseContext::parseParameterDeclarator(TType *type, |
3514 | const ImmutableString &name, |
3515 | const TSourceLoc &nameLoc) |
3516 | { |
3517 | ASSERT(type); |
3518 | checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size" , name, type); |
3519 | if (type->getBasicType() == EbtVoid) |
3520 | { |
3521 | error(nameLoc, "illegal use of type 'void'" , name); |
3522 | } |
3523 | checkIsNotReserved(nameLoc, name); |
3524 | TParameter param = {name.data(), type}; |
3525 | return param; |
3526 | } |
3527 | |
3528 | TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType, |
3529 | const ImmutableString &name, |
3530 | const TSourceLoc &nameLoc) |
3531 | { |
3532 | TType *type = new TType(publicType); |
3533 | return parseParameterDeclarator(type, name, nameLoc); |
3534 | } |
3535 | |
3536 | TParameter TParseContext::parseParameterArrayDeclarator(const ImmutableString &name, |
3537 | const TSourceLoc &nameLoc, |
3538 | const TVector<unsigned int> &arraySizes, |
3539 | const TSourceLoc &arrayLoc, |
3540 | TPublicType *elementType) |
3541 | { |
3542 | checkArrayElementIsNotArray(arrayLoc, *elementType); |
3543 | TType *arrayType = new TType(*elementType); |
3544 | arrayType->makeArrays(arraySizes); |
3545 | return parseParameterDeclarator(arrayType, name, nameLoc); |
3546 | } |
3547 | |
3548 | bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality( |
3549 | const TIntermSequence &arguments, |
3550 | TType type, |
3551 | const TSourceLoc &line) |
3552 | { |
3553 | if (arguments.empty()) |
3554 | { |
3555 | error(line, "implicitly sized array constructor must have at least one argument" , "[]" ); |
3556 | return false; |
3557 | } |
3558 | for (TIntermNode *arg : arguments) |
3559 | { |
3560 | const TIntermTyped *element = arg->getAsTyped(); |
3561 | ASSERT(element); |
3562 | size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u; |
3563 | if (dimensionalityFromElement > type.getNumArraySizes()) |
3564 | { |
3565 | error(line, "constructing from a non-dereferenced array" , "constructor" ); |
3566 | return false; |
3567 | } |
3568 | else if (dimensionalityFromElement < type.getNumArraySizes()) |
3569 | { |
3570 | if (dimensionalityFromElement == 1u) |
3571 | { |
3572 | error(line, "implicitly sized array of arrays constructor argument is not an array" , |
3573 | "constructor" ); |
3574 | } |
3575 | else |
3576 | { |
3577 | error(line, |
3578 | "implicitly sized array of arrays constructor argument dimensionality is too " |
3579 | "low" , |
3580 | "constructor" ); |
3581 | } |
3582 | return false; |
3583 | } |
3584 | } |
3585 | return true; |
3586 | } |
3587 | |
3588 | // This function is used to test for the correctness of the parameters passed to various constructor |
3589 | // functions and also convert them to the right datatype if it is allowed and required. |
3590 | // |
3591 | // Returns a node to add to the tree regardless of if an error was generated or not. |
3592 | // |
3593 | TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line) |
3594 | { |
3595 | TType type = fnCall->constructorType(); |
3596 | TIntermSequence &arguments = fnCall->arguments(); |
3597 | if (type.isUnsizedArray()) |
3598 | { |
3599 | if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line)) |
3600 | { |
3601 | type.sizeUnsizedArrays(nullptr); |
3602 | return CreateZeroNode(type); |
3603 | } |
3604 | TIntermTyped *firstElement = arguments.at(0)->getAsTyped(); |
3605 | ASSERT(firstElement); |
3606 | if (type.getOutermostArraySize() == 0u) |
3607 | { |
3608 | type.sizeOutermostUnsizedArray(static_cast<unsigned int>(arguments.size())); |
3609 | } |
3610 | for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i) |
3611 | { |
3612 | if ((*type.getArraySizes())[i] == 0u) |
3613 | { |
3614 | type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]); |
3615 | } |
3616 | } |
3617 | ASSERT(!type.isUnsizedArray()); |
3618 | } |
3619 | |
3620 | if (!checkConstructorArguments(line, arguments, type)) |
3621 | { |
3622 | return CreateZeroNode(type); |
3623 | } |
3624 | |
3625 | TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, &arguments); |
3626 | constructorNode->setLine(line); |
3627 | |
3628 | return constructorNode->fold(mDiagnostics); |
3629 | } |
3630 | |
3631 | // |
3632 | // Interface/uniform blocks |
3633 | // TODO([email protected]): implement GL_EXT_shader_io_blocks. |
3634 | // |
3635 | TIntermDeclaration *TParseContext::addInterfaceBlock( |
3636 | const TTypeQualifierBuilder &typeQualifierBuilder, |
3637 | const TSourceLoc &nameLine, |
3638 | const ImmutableString &blockName, |
3639 | TFieldList *fieldList, |
3640 | const ImmutableString &instanceName, |
3641 | const TSourceLoc &instanceLine, |
3642 | TIntermTyped *arrayIndex, |
3643 | const TSourceLoc &arrayIndexLine) |
3644 | { |
3645 | checkIsNotReserved(nameLine, blockName); |
3646 | |
3647 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); |
3648 | |
3649 | if (mShaderVersion < 310 && typeQualifier.qualifier != EvqUniform) |
3650 | { |
3651 | error(typeQualifier.line, |
3652 | "invalid qualifier: interface blocks must be uniform in version lower than GLSL ES " |
3653 | "3.10" , |
3654 | getQualifierString(typeQualifier.qualifier)); |
3655 | } |
3656 | else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) |
3657 | { |
3658 | error(typeQualifier.line, "invalid qualifier: interface blocks must be uniform or buffer" , |
3659 | getQualifierString(typeQualifier.qualifier)); |
3660 | } |
3661 | |
3662 | if (typeQualifier.invariant) |
3663 | { |
3664 | error(typeQualifier.line, "invalid qualifier on interface block member" , "invariant" ); |
3665 | } |
3666 | |
3667 | if (typeQualifier.qualifier != EvqBuffer) |
3668 | { |
3669 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); |
3670 | } |
3671 | |
3672 | // add array index |
3673 | unsigned int arraySize = 0; |
3674 | if (arrayIndex != nullptr) |
3675 | { |
3676 | arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex); |
3677 | } |
3678 | |
3679 | checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index); |
3680 | |
3681 | if (mShaderVersion < 310) |
3682 | { |
3683 | checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding); |
3684 | } |
3685 | else |
3686 | { |
3687 | checkBlockBindingIsValid(typeQualifier.line, typeQualifier.qualifier, |
3688 | typeQualifier.layoutQualifier.binding, arraySize); |
3689 | } |
3690 | |
3691 | checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv); |
3692 | |
3693 | TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; |
3694 | checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); |
3695 | checkStd430IsForShaderStorageBlock(typeQualifier.line, blockLayoutQualifier.blockStorage, |
3696 | typeQualifier.qualifier); |
3697 | |
3698 | if (blockLayoutQualifier.matrixPacking == EmpUnspecified) |
3699 | { |
3700 | if (typeQualifier.qualifier == EvqUniform) |
3701 | { |
3702 | blockLayoutQualifier.matrixPacking = mDefaultUniformMatrixPacking; |
3703 | } |
3704 | else if (typeQualifier.qualifier == EvqBuffer) |
3705 | { |
3706 | blockLayoutQualifier.matrixPacking = mDefaultBufferMatrixPacking; |
3707 | } |
3708 | } |
3709 | |
3710 | if (blockLayoutQualifier.blockStorage == EbsUnspecified) |
3711 | { |
3712 | if (typeQualifier.qualifier == EvqUniform) |
3713 | { |
3714 | blockLayoutQualifier.blockStorage = mDefaultUniformBlockStorage; |
3715 | } |
3716 | else if (typeQualifier.qualifier == EvqBuffer) |
3717 | { |
3718 | blockLayoutQualifier.blockStorage = mDefaultBufferBlockStorage; |
3719 | } |
3720 | } |
3721 | |
3722 | checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier); |
3723 | |
3724 | checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat); |
3725 | |
3726 | // check for sampler types and apply layout qualifiers |
3727 | for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) |
3728 | { |
3729 | TField *field = (*fieldList)[memberIndex]; |
3730 | TType *fieldType = field->type(); |
3731 | if (IsOpaqueType(fieldType->getBasicType())) |
3732 | { |
3733 | std::string reason("unsupported type - " ); |
3734 | reason += fieldType->getBasicString(); |
3735 | reason += " types are not allowed in interface blocks" ; |
3736 | error(field->line(), reason.c_str(), fieldType->getBasicString()); |
3737 | } |
3738 | |
3739 | const TQualifier qualifier = fieldType->getQualifier(); |
3740 | switch (qualifier) |
3741 | { |
3742 | case EvqGlobal: |
3743 | break; |
3744 | case EvqUniform: |
3745 | if (typeQualifier.qualifier == EvqBuffer) |
3746 | { |
3747 | error(field->line(), "invalid qualifier on shader storage block member" , |
3748 | getQualifierString(qualifier)); |
3749 | } |
3750 | break; |
3751 | case EvqBuffer: |
3752 | if (typeQualifier.qualifier == EvqUniform) |
3753 | { |
3754 | error(field->line(), "invalid qualifier on uniform block member" , |
3755 | getQualifierString(qualifier)); |
3756 | } |
3757 | break; |
3758 | default: |
3759 | error(field->line(), "invalid qualifier on interface block member" , |
3760 | getQualifierString(qualifier)); |
3761 | break; |
3762 | } |
3763 | |
3764 | if (fieldType->isInvariant()) |
3765 | { |
3766 | error(field->line(), "invalid qualifier on interface block member" , "invariant" ); |
3767 | } |
3768 | |
3769 | // check layout qualifiers |
3770 | TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); |
3771 | checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier); |
3772 | checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index); |
3773 | checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding); |
3774 | |
3775 | if (fieldLayoutQualifier.blockStorage != EbsUnspecified) |
3776 | { |
3777 | error(field->line(), "invalid layout qualifier: cannot be used here" , |
3778 | getBlockStorageString(fieldLayoutQualifier.blockStorage)); |
3779 | } |
3780 | |
3781 | if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) |
3782 | { |
3783 | fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; |
3784 | } |
3785 | else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct) |
3786 | { |
3787 | warning(field->line(), |
3788 | "extraneous layout qualifier: only has an effect on matrix types" , |
3789 | getMatrixPackingString(fieldLayoutQualifier.matrixPacking)); |
3790 | } |
3791 | |
3792 | fieldType->setLayoutQualifier(fieldLayoutQualifier); |
3793 | |
3794 | if (mShaderVersion < 310 || memberIndex != fieldList->size() - 1u || |
3795 | typeQualifier.qualifier != EvqBuffer) |
3796 | { |
3797 | // ESSL 3.10 spec section 4.1.9 allows for runtime-sized arrays. |
3798 | checkIsNotUnsizedArray(field->line(), |
3799 | "array members of interface blocks must specify a size" , |
3800 | field->name(), field->type()); |
3801 | } |
3802 | |
3803 | if (typeQualifier.qualifier == EvqBuffer) |
3804 | { |
3805 | // set memory qualifiers |
3806 | // GLSL ES 3.10 session 4.9 [Memory Access Qualifiers]. When a block declaration is |
3807 | // qualified with a memory qualifier, it is as if all of its members were declared with |
3808 | // the same memory qualifier. |
3809 | const TMemoryQualifier &blockMemoryQualifier = typeQualifier.memoryQualifier; |
3810 | TMemoryQualifier fieldMemoryQualifier = fieldType->getMemoryQualifier(); |
3811 | fieldMemoryQualifier.readonly |= blockMemoryQualifier.readonly; |
3812 | fieldMemoryQualifier.writeonly |= blockMemoryQualifier.writeonly; |
3813 | fieldMemoryQualifier.coherent |= blockMemoryQualifier.coherent; |
3814 | fieldMemoryQualifier.restrictQualifier |= blockMemoryQualifier.restrictQualifier; |
3815 | fieldMemoryQualifier.volatileQualifier |= blockMemoryQualifier.volatileQualifier; |
3816 | // TODO([email protected]): Decide whether if readonly and writeonly buffer variable |
3817 | // is legal. See bug https://github.com/KhronosGroup/OpenGL-API/issues/7 |
3818 | fieldType->setMemoryQualifier(fieldMemoryQualifier); |
3819 | } |
3820 | } |
3821 | |
3822 | TInterfaceBlock *interfaceBlock = new TInterfaceBlock( |
3823 | &symbolTable, blockName, fieldList, blockLayoutQualifier, SymbolType::UserDefined); |
3824 | if (!symbolTable.declare(interfaceBlock)) |
3825 | { |
3826 | error(nameLine, "redefinition of an interface block name" , blockName); |
3827 | } |
3828 | |
3829 | TType *interfaceBlockType = |
3830 | new TType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier); |
3831 | if (arrayIndex != nullptr) |
3832 | { |
3833 | interfaceBlockType->makeArray(arraySize); |
3834 | } |
3835 | |
3836 | // The instance variable gets created to refer to the interface block type from the AST |
3837 | // regardless of if there's an instance name. It's created as an empty symbol if there is no |
3838 | // instance name. |
3839 | TVariable *instanceVariable = |
3840 | new TVariable(&symbolTable, instanceName, interfaceBlockType, |
3841 | instanceName.empty() ? SymbolType::Empty : SymbolType::UserDefined); |
3842 | |
3843 | if (instanceVariable->symbolType() == SymbolType::Empty) |
3844 | { |
3845 | // define symbols for the members of the interface block |
3846 | for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) |
3847 | { |
3848 | TField *field = (*fieldList)[memberIndex]; |
3849 | TType *fieldType = new TType(*field->type()); |
3850 | |
3851 | // set parent pointer of the field variable |
3852 | fieldType->setInterfaceBlock(interfaceBlock); |
3853 | |
3854 | fieldType->setQualifier(typeQualifier.qualifier); |
3855 | |
3856 | TVariable *fieldVariable = |
3857 | new TVariable(&symbolTable, field->name(), fieldType, SymbolType::UserDefined); |
3858 | if (!symbolTable.declare(fieldVariable)) |
3859 | { |
3860 | error(field->line(), "redefinition of an interface block member name" , |
3861 | field->name()); |
3862 | } |
3863 | } |
3864 | } |
3865 | else |
3866 | { |
3867 | checkIsNotReserved(instanceLine, instanceName); |
3868 | |
3869 | // add a symbol for this interface block |
3870 | if (!symbolTable.declare(instanceVariable)) |
3871 | { |
3872 | error(instanceLine, "redefinition of an interface block instance name" , instanceName); |
3873 | } |
3874 | } |
3875 | |
3876 | TIntermSymbol *blockSymbol = new TIntermSymbol(instanceVariable); |
3877 | blockSymbol->setLine(typeQualifier.line); |
3878 | TIntermDeclaration *declaration = new TIntermDeclaration(); |
3879 | declaration->appendDeclarator(blockSymbol); |
3880 | declaration->setLine(nameLine); |
3881 | |
3882 | exitStructDeclaration(); |
3883 | return declaration; |
3884 | } |
3885 | |
3886 | void TParseContext::enterStructDeclaration(const TSourceLoc &line, |
3887 | const ImmutableString &identifier) |
3888 | { |
3889 | ++mStructNestingLevel; |
3890 | |
3891 | // Embedded structure definitions are not supported per GLSL ES spec. |
3892 | // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11. |
3893 | if (mStructNestingLevel > 1) |
3894 | { |
3895 | error(line, "Embedded struct definitions are not allowed" , "struct" ); |
3896 | } |
3897 | } |
3898 | |
3899 | void TParseContext::exitStructDeclaration() |
3900 | { |
3901 | --mStructNestingLevel; |
3902 | } |
3903 | |
3904 | void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field) |
3905 | { |
3906 | if (!sh::IsWebGLBasedSpec(mShaderSpec)) |
3907 | { |
3908 | return; |
3909 | } |
3910 | |
3911 | if (field.type()->getBasicType() != EbtStruct) |
3912 | { |
3913 | return; |
3914 | } |
3915 | |
3916 | // We're already inside a structure definition at this point, so add |
3917 | // one to the field's struct nesting. |
3918 | if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) |
3919 | { |
3920 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
3921 | if (field.type()->getStruct()->symbolType() == SymbolType::Empty) |
3922 | { |
3923 | // This may happen in case there are nested struct definitions. While they are also |
3924 | // invalid GLSL, they don't cause a syntax error. |
3925 | reasonStream << "Struct nesting" ; |
3926 | } |
3927 | else |
3928 | { |
3929 | reasonStream << "Reference of struct type " << field.type()->getStruct()->name(); |
3930 | } |
3931 | reasonStream << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting; |
3932 | std::string reason = reasonStream.str(); |
3933 | error(line, reason.c_str(), field.name()); |
3934 | return; |
3935 | } |
3936 | } |
3937 | |
3938 | // |
3939 | // Parse an array index expression |
3940 | // |
3941 | TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, |
3942 | const TSourceLoc &location, |
3943 | TIntermTyped *indexExpression) |
3944 | { |
3945 | if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) |
3946 | { |
3947 | if (baseExpression->getAsSymbolNode()) |
3948 | { |
3949 | error(location, " left of '[' is not of type array, matrix, or vector " , |
3950 | baseExpression->getAsSymbolNode()->getName()); |
3951 | } |
3952 | else |
3953 | { |
3954 | error(location, " left of '[' is not of type array, matrix, or vector " , "expression" ); |
3955 | } |
3956 | |
3957 | return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); |
3958 | } |
3959 | |
3960 | if (baseExpression->getQualifier() == EvqPerVertexIn) |
3961 | { |
3962 | ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT); |
3963 | if (mGeometryShaderInputPrimitiveType == EptUndefined) |
3964 | { |
3965 | error(location, "missing input primitive declaration before indexing gl_in." , "[" ); |
3966 | return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); |
3967 | } |
3968 | } |
3969 | |
3970 | TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); |
3971 | |
3972 | // ANGLE should be able to fold any constant expressions resulting in an integer - but to be |
3973 | // safe we don't treat "EvqConst" that's evaluated according to the spec as being sufficient |
3974 | // for constness. Some interpretations of the spec have allowed constant expressions with side |
3975 | // effects - like array length() method on a non-constant array. |
3976 | if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr) |
3977 | { |
3978 | if (baseExpression->isInterfaceBlock()) |
3979 | { |
3980 | // TODO([email protected]): implement GL_EXT_shader_io_blocks. |
3981 | switch (baseExpression->getQualifier()) |
3982 | { |
3983 | case EvqPerVertexIn: |
3984 | break; |
3985 | case EvqUniform: |
3986 | case EvqBuffer: |
3987 | error(location, |
3988 | "array indexes for uniform block arrays and shader storage block arrays " |
3989 | "must be constant integral expressions" , |
3990 | "[" ); |
3991 | break; |
3992 | default: |
3993 | // We can reach here only in error cases. |
3994 | ASSERT(mDiagnostics->numErrors() > 0); |
3995 | break; |
3996 | } |
3997 | } |
3998 | else if (baseExpression->getQualifier() == EvqFragmentOut) |
3999 | { |
4000 | error(location, |
4001 | "array indexes for fragment outputs must be constant integral expressions" , "[" ); |
4002 | } |
4003 | else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData) |
4004 | { |
4005 | error(location, "array index for gl_FragData must be constant zero" , "[" ); |
4006 | } |
4007 | } |
4008 | |
4009 | if (indexConstantUnion) |
4010 | { |
4011 | // If an out-of-range index is not qualified as constant, the behavior in the spec is |
4012 | // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may |
4013 | // constant fold expressions that are not constant expressions). The most compatible way to |
4014 | // handle this case is to report a warning instead of an error and force the index to be in |
4015 | // the correct range. |
4016 | bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst; |
4017 | int index = 0; |
4018 | if (indexConstantUnion->getBasicType() == EbtInt) |
4019 | { |
4020 | index = indexConstantUnion->getIConst(0); |
4021 | } |
4022 | else if (indexConstantUnion->getBasicType() == EbtUInt) |
4023 | { |
4024 | index = static_cast<int>(indexConstantUnion->getUConst(0)); |
4025 | } |
4026 | |
4027 | int safeIndex = -1; |
4028 | |
4029 | if (index < 0) |
4030 | { |
4031 | outOfRangeError(outOfRangeIndexIsError, location, "index expression is negative" , "[]" ); |
4032 | safeIndex = 0; |
4033 | } |
4034 | |
4035 | if (!baseExpression->getType().isUnsizedArray()) |
4036 | { |
4037 | if (baseExpression->isArray()) |
4038 | { |
4039 | if (baseExpression->getQualifier() == EvqFragData && index > 0) |
4040 | { |
4041 | if (!isExtensionEnabled(TExtension::EXT_draw_buffers)) |
4042 | { |
4043 | outOfRangeError(outOfRangeIndexIsError, location, |
4044 | "array index for gl_FragData must be zero when " |
4045 | "GL_EXT_draw_buffers is disabled" , |
4046 | "[]" ); |
4047 | safeIndex = 0; |
4048 | } |
4049 | } |
4050 | } |
4051 | // Only do generic out-of-range check if similar error hasn't already been reported. |
4052 | if (safeIndex < 0) |
4053 | { |
4054 | if (baseExpression->isArray()) |
4055 | { |
4056 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, |
4057 | baseExpression->getOutermostArraySize(), |
4058 | "array index out of range" ); |
4059 | } |
4060 | else if (baseExpression->isMatrix()) |
4061 | { |
4062 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, |
4063 | baseExpression->getType().getCols(), |
4064 | "matrix field selection out of range" ); |
4065 | } |
4066 | else |
4067 | { |
4068 | ASSERT(baseExpression->isVector()); |
4069 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, |
4070 | baseExpression->getType().getNominalSize(), |
4071 | "vector field selection out of range" ); |
4072 | } |
4073 | } |
4074 | |
4075 | ASSERT(safeIndex >= 0); |
4076 | // Data of constant unions can't be changed, because it may be shared with other |
4077 | // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new |
4078 | // sanitized object. |
4079 | if (safeIndex != index || indexConstantUnion->getBasicType() != EbtInt) |
4080 | { |
4081 | TConstantUnion *safeConstantUnion = new TConstantUnion(); |
4082 | safeConstantUnion->setIConst(safeIndex); |
4083 | indexExpression = new TIntermConstantUnion( |
4084 | safeConstantUnion, TType(EbtInt, indexExpression->getPrecision(), |
4085 | indexExpression->getQualifier())); |
4086 | } |
4087 | |
4088 | TIntermBinary *node = |
4089 | new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression); |
4090 | node->setLine(location); |
4091 | return expressionOrFoldedResult(node); |
4092 | } |
4093 | } |
4094 | |
4095 | markStaticReadIfSymbol(indexExpression); |
4096 | TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression); |
4097 | node->setLine(location); |
4098 | // Indirect indexing can never be constant folded. |
4099 | return node; |
4100 | } |
4101 | |
4102 | int TParseContext::checkIndexLessThan(bool outOfRangeIndexIsError, |
4103 | const TSourceLoc &location, |
4104 | int index, |
4105 | int arraySize, |
4106 | const char *reason) |
4107 | { |
4108 | // Should not reach here with an unsized / runtime-sized array. |
4109 | ASSERT(arraySize > 0); |
4110 | // A negative index should already have been checked. |
4111 | ASSERT(index >= 0); |
4112 | if (index >= arraySize) |
4113 | { |
4114 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
4115 | reasonStream << reason << " '" << index << "'" ; |
4116 | std::string token = reasonStream.str(); |
4117 | outOfRangeError(outOfRangeIndexIsError, location, reason, "[]" ); |
4118 | return arraySize - 1; |
4119 | } |
4120 | return index; |
4121 | } |
4122 | |
4123 | TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, |
4124 | const TSourceLoc &dotLocation, |
4125 | const ImmutableString &fieldString, |
4126 | const TSourceLoc &fieldLocation) |
4127 | { |
4128 | if (baseExpression->isArray()) |
4129 | { |
4130 | error(fieldLocation, "cannot apply dot operator to an array" , "." ); |
4131 | return baseExpression; |
4132 | } |
4133 | |
4134 | if (baseExpression->isVector()) |
4135 | { |
4136 | TVector<int> fieldOffsets; |
4137 | if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(), |
4138 | &fieldOffsets)) |
4139 | { |
4140 | fieldOffsets.resize(1); |
4141 | fieldOffsets[0] = 0; |
4142 | } |
4143 | TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets); |
4144 | node->setLine(dotLocation); |
4145 | |
4146 | return node->fold(mDiagnostics); |
4147 | } |
4148 | else if (baseExpression->getBasicType() == EbtStruct) |
4149 | { |
4150 | const TFieldList &fields = baseExpression->getType().getStruct()->fields(); |
4151 | if (fields.empty()) |
4152 | { |
4153 | error(dotLocation, "structure has no fields" , "Internal Error" ); |
4154 | return baseExpression; |
4155 | } |
4156 | else |
4157 | { |
4158 | bool fieldFound = false; |
4159 | unsigned int i; |
4160 | for (i = 0; i < fields.size(); ++i) |
4161 | { |
4162 | if (fields[i]->name() == fieldString) |
4163 | { |
4164 | fieldFound = true; |
4165 | break; |
4166 | } |
4167 | } |
4168 | if (fieldFound) |
4169 | { |
4170 | TIntermTyped *index = CreateIndexNode(i); |
4171 | index->setLine(fieldLocation); |
4172 | TIntermBinary *node = |
4173 | new TIntermBinary(EOpIndexDirectStruct, baseExpression, index); |
4174 | node->setLine(dotLocation); |
4175 | return expressionOrFoldedResult(node); |
4176 | } |
4177 | else |
4178 | { |
4179 | error(dotLocation, " no such field in structure" , fieldString); |
4180 | return baseExpression; |
4181 | } |
4182 | } |
4183 | } |
4184 | else if (baseExpression->isInterfaceBlock()) |
4185 | { |
4186 | const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); |
4187 | if (fields.empty()) |
4188 | { |
4189 | error(dotLocation, "interface block has no fields" , "Internal Error" ); |
4190 | return baseExpression; |
4191 | } |
4192 | else |
4193 | { |
4194 | bool fieldFound = false; |
4195 | unsigned int i; |
4196 | for (i = 0; i < fields.size(); ++i) |
4197 | { |
4198 | if (fields[i]->name() == fieldString) |
4199 | { |
4200 | fieldFound = true; |
4201 | break; |
4202 | } |
4203 | } |
4204 | if (fieldFound) |
4205 | { |
4206 | TIntermTyped *index = CreateIndexNode(i); |
4207 | index->setLine(fieldLocation); |
4208 | TIntermBinary *node = |
4209 | new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index); |
4210 | node->setLine(dotLocation); |
4211 | // Indexing interface blocks can never be constant folded. |
4212 | return node; |
4213 | } |
4214 | else |
4215 | { |
4216 | error(dotLocation, " no such field in interface block" , fieldString); |
4217 | return baseExpression; |
4218 | } |
4219 | } |
4220 | } |
4221 | else |
4222 | { |
4223 | if (mShaderVersion < 300) |
4224 | { |
4225 | error(dotLocation, " field selection requires structure or vector on left hand side" , |
4226 | fieldString); |
4227 | } |
4228 | else |
4229 | { |
4230 | error(dotLocation, |
4231 | " field selection requires structure, vector, or interface block on left hand " |
4232 | "side" , |
4233 | fieldString); |
4234 | } |
4235 | return baseExpression; |
4236 | } |
4237 | } |
4238 | |
4239 | TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, |
4240 | const TSourceLoc &qualifierTypeLine) |
4241 | { |
4242 | TLayoutQualifier qualifier = TLayoutQualifier::Create(); |
4243 | |
4244 | if (qualifierType == "shared" ) |
4245 | { |
4246 | if (sh::IsWebGLBasedSpec(mShaderSpec)) |
4247 | { |
4248 | error(qualifierTypeLine, "Only std140 layout is allowed in WebGL" , "shared" ); |
4249 | } |
4250 | qualifier.blockStorage = EbsShared; |
4251 | } |
4252 | else if (qualifierType == "packed" ) |
4253 | { |
4254 | if (sh::IsWebGLBasedSpec(mShaderSpec)) |
4255 | { |
4256 | error(qualifierTypeLine, "Only std140 layout is allowed in WebGL" , "packed" ); |
4257 | } |
4258 | qualifier.blockStorage = EbsPacked; |
4259 | } |
4260 | else if (qualifierType == "std430" ) |
4261 | { |
4262 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4263 | qualifier.blockStorage = EbsStd430; |
4264 | } |
4265 | else if (qualifierType == "std140" ) |
4266 | { |
4267 | qualifier.blockStorage = EbsStd140; |
4268 | } |
4269 | else if (qualifierType == "row_major" ) |
4270 | { |
4271 | qualifier.matrixPacking = EmpRowMajor; |
4272 | } |
4273 | else if (qualifierType == "column_major" ) |
4274 | { |
4275 | qualifier.matrixPacking = EmpColumnMajor; |
4276 | } |
4277 | else if (qualifierType == "location" ) |
4278 | { |
4279 | error(qualifierTypeLine, "invalid layout qualifier: location requires an argument" , |
4280 | qualifierType); |
4281 | } |
4282 | else if (qualifierType == "yuv" && mShaderType == GL_FRAGMENT_SHADER) |
4283 | { |
4284 | if (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_YUV_target)) |
4285 | { |
4286 | qualifier.yuv = true; |
4287 | } |
4288 | } |
4289 | else if (qualifierType == "rgba32f" ) |
4290 | { |
4291 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4292 | qualifier.imageInternalFormat = EiifRGBA32F; |
4293 | } |
4294 | else if (qualifierType == "rgba16f" ) |
4295 | { |
4296 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4297 | qualifier.imageInternalFormat = EiifRGBA16F; |
4298 | } |
4299 | else if (qualifierType == "r32f" ) |
4300 | { |
4301 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4302 | qualifier.imageInternalFormat = EiifR32F; |
4303 | } |
4304 | else if (qualifierType == "rgba8" ) |
4305 | { |
4306 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4307 | qualifier.imageInternalFormat = EiifRGBA8; |
4308 | } |
4309 | else if (qualifierType == "rgba8_snorm" ) |
4310 | { |
4311 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4312 | qualifier.imageInternalFormat = EiifRGBA8_SNORM; |
4313 | } |
4314 | else if (qualifierType == "rgba32i" ) |
4315 | { |
4316 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4317 | qualifier.imageInternalFormat = EiifRGBA32I; |
4318 | } |
4319 | else if (qualifierType == "rgba16i" ) |
4320 | { |
4321 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4322 | qualifier.imageInternalFormat = EiifRGBA16I; |
4323 | } |
4324 | else if (qualifierType == "rgba8i" ) |
4325 | { |
4326 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4327 | qualifier.imageInternalFormat = EiifRGBA8I; |
4328 | } |
4329 | else if (qualifierType == "r32i" ) |
4330 | { |
4331 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4332 | qualifier.imageInternalFormat = EiifR32I; |
4333 | } |
4334 | else if (qualifierType == "rgba32ui" ) |
4335 | { |
4336 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4337 | qualifier.imageInternalFormat = EiifRGBA32UI; |
4338 | } |
4339 | else if (qualifierType == "rgba16ui" ) |
4340 | { |
4341 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4342 | qualifier.imageInternalFormat = EiifRGBA16UI; |
4343 | } |
4344 | else if (qualifierType == "rgba8ui" ) |
4345 | { |
4346 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4347 | qualifier.imageInternalFormat = EiifRGBA8UI; |
4348 | } |
4349 | else if (qualifierType == "r32ui" ) |
4350 | { |
4351 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4352 | qualifier.imageInternalFormat = EiifR32UI; |
4353 | } |
4354 | else if (qualifierType == "points" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4355 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4356 | { |
4357 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4358 | qualifier.primitiveType = EptPoints; |
4359 | } |
4360 | else if (qualifierType == "lines" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4361 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4362 | { |
4363 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4364 | qualifier.primitiveType = EptLines; |
4365 | } |
4366 | else if (qualifierType == "lines_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4367 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4368 | { |
4369 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4370 | qualifier.primitiveType = EptLinesAdjacency; |
4371 | } |
4372 | else if (qualifierType == "triangles" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4373 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4374 | { |
4375 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4376 | qualifier.primitiveType = EptTriangles; |
4377 | } |
4378 | else if (qualifierType == "triangles_adjacency" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4379 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4380 | { |
4381 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4382 | qualifier.primitiveType = EptTrianglesAdjacency; |
4383 | } |
4384 | else if (qualifierType == "line_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4385 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4386 | { |
4387 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4388 | qualifier.primitiveType = EptLineStrip; |
4389 | } |
4390 | else if (qualifierType == "triangle_strip" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4391 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4392 | { |
4393 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4394 | qualifier.primitiveType = EptTriangleStrip; |
4395 | } |
4396 | |
4397 | else |
4398 | { |
4399 | error(qualifierTypeLine, "invalid layout qualifier" , qualifierType); |
4400 | } |
4401 | |
4402 | return qualifier; |
4403 | } |
4404 | |
4405 | void TParseContext::parseLocalSize(const ImmutableString &qualifierType, |
4406 | const TSourceLoc &qualifierTypeLine, |
4407 | int intValue, |
4408 | const TSourceLoc &intValueLine, |
4409 | const std::string &intValueString, |
4410 | size_t index, |
4411 | sh::WorkGroupSize *localSize) |
4412 | { |
4413 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4414 | if (intValue < 1) |
4415 | { |
4416 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); |
4417 | reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive" ; |
4418 | std::string reason = reasonStream.str(); |
4419 | error(intValueLine, reason.c_str(), intValueString.c_str()); |
4420 | } |
4421 | (*localSize)[index] = intValue; |
4422 | } |
4423 | |
4424 | void TParseContext::parseNumViews(int intValue, |
4425 | const TSourceLoc &intValueLine, |
4426 | const std::string &intValueString, |
4427 | int *numViews) |
4428 | { |
4429 | // This error is only specified in WebGL, but tightens unspecified behavior in the native |
4430 | // specification. |
4431 | if (intValue < 1) |
4432 | { |
4433 | error(intValueLine, "out of range: num_views must be positive" , intValueString.c_str()); |
4434 | } |
4435 | *numViews = intValue; |
4436 | } |
4437 | |
4438 | void TParseContext::parseInvocations(int intValue, |
4439 | const TSourceLoc &intValueLine, |
4440 | const std::string &intValueString, |
4441 | int *numInvocations) |
4442 | { |
4443 | // Although SPEC isn't clear whether invocations can be less than 1, we add this limit because |
4444 | // it doesn't make sense to accept invocations <= 0. |
4445 | if (intValue < 1 || intValue > mMaxGeometryShaderInvocations) |
4446 | { |
4447 | error(intValueLine, |
4448 | "out of range: invocations must be in the range of [1, " |
4449 | "MAX_GEOMETRY_SHADER_INVOCATIONS_OES]" , |
4450 | intValueString.c_str()); |
4451 | } |
4452 | else |
4453 | { |
4454 | *numInvocations = intValue; |
4455 | } |
4456 | } |
4457 | |
4458 | void TParseContext::parseMaxVertices(int intValue, |
4459 | const TSourceLoc &intValueLine, |
4460 | const std::string &intValueString, |
4461 | int *maxVertices) |
4462 | { |
4463 | // Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because |
4464 | // it doesn't make sense to accept max_vertices < 0. |
4465 | if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices) |
4466 | { |
4467 | error( |
4468 | intValueLine, |
4469 | "out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]" , |
4470 | intValueString.c_str()); |
4471 | } |
4472 | else |
4473 | { |
4474 | *maxVertices = intValue; |
4475 | } |
4476 | } |
4477 | |
4478 | void TParseContext::parseIndexLayoutQualifier(int intValue, |
4479 | const TSourceLoc &intValueLine, |
4480 | const std::string &intValueString, |
4481 | int *index) |
4482 | { |
4483 | // EXT_blend_func_extended specifies that most validation should happen at link time, but since |
4484 | // we're validating output variable locations at compile time, it makes sense to validate that |
4485 | // index is 0 or 1 also at compile time. Also since we use "-1" as a placeholder for unspecified |
4486 | // index, we can't accept it here. |
4487 | if (intValue < 0 || intValue > 1) |
4488 | { |
4489 | error(intValueLine, "out of range: index layout qualifier can only be 0 or 1" , |
4490 | intValueString.c_str()); |
4491 | } |
4492 | else |
4493 | { |
4494 | *index = intValue; |
4495 | } |
4496 | } |
4497 | |
4498 | TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, |
4499 | const TSourceLoc &qualifierTypeLine, |
4500 | int intValue, |
4501 | const TSourceLoc &intValueLine) |
4502 | { |
4503 | TLayoutQualifier qualifier = TLayoutQualifier::Create(); |
4504 | |
4505 | std::string intValueString = Str(intValue); |
4506 | |
4507 | if (qualifierType == "location" ) |
4508 | { |
4509 | // must check that location is non-negative |
4510 | if (intValue < 0) |
4511 | { |
4512 | error(intValueLine, "out of range: location must be non-negative" , |
4513 | intValueString.c_str()); |
4514 | } |
4515 | else |
4516 | { |
4517 | qualifier.location = intValue; |
4518 | qualifier.locationsSpecified = 1; |
4519 | } |
4520 | } |
4521 | else if (qualifierType == "binding" ) |
4522 | { |
4523 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4524 | if (intValue < 0) |
4525 | { |
4526 | error(intValueLine, "out of range: binding must be non-negative" , |
4527 | intValueString.c_str()); |
4528 | } |
4529 | else |
4530 | { |
4531 | qualifier.binding = intValue; |
4532 | } |
4533 | } |
4534 | else if (qualifierType == "offset" ) |
4535 | { |
4536 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); |
4537 | if (intValue < 0) |
4538 | { |
4539 | error(intValueLine, "out of range: offset must be non-negative" , |
4540 | intValueString.c_str()); |
4541 | } |
4542 | else |
4543 | { |
4544 | qualifier.offset = intValue; |
4545 | } |
4546 | } |
4547 | else if (qualifierType == "local_size_x" ) |
4548 | { |
4549 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u, |
4550 | &qualifier.localSize); |
4551 | } |
4552 | else if (qualifierType == "local_size_y" ) |
4553 | { |
4554 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u, |
4555 | &qualifier.localSize); |
4556 | } |
4557 | else if (qualifierType == "local_size_z" ) |
4558 | { |
4559 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, |
4560 | &qualifier.localSize); |
4561 | } |
4562 | else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER) |
4563 | { |
4564 | if (checkCanUseExtension(qualifierTypeLine, TExtension::OVR_multiview2)) |
4565 | { |
4566 | parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews); |
4567 | } |
4568 | } |
4569 | else if (qualifierType == "invocations" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4570 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4571 | { |
4572 | parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations); |
4573 | } |
4574 | else if (qualifierType == "max_vertices" && mShaderType == GL_GEOMETRY_SHADER_EXT && |
4575 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_geometry_shader)) |
4576 | { |
4577 | parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices); |
4578 | } |
4579 | else if (qualifierType == "index" && mShaderType == GL_FRAGMENT_SHADER && |
4580 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_blend_func_extended)) |
4581 | { |
4582 | parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index); |
4583 | } |
4584 | else |
4585 | { |
4586 | error(qualifierTypeLine, "invalid layout qualifier" , qualifierType); |
4587 | } |
4588 | |
4589 | return qualifier; |
4590 | } |
4591 | |
4592 | TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc) |
4593 | { |
4594 | return new TTypeQualifierBuilder( |
4595 | new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc), |
4596 | mShaderVersion); |
4597 | } |
4598 | |
4599 | TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier, |
4600 | const TSourceLoc &loc) |
4601 | { |
4602 | checkIsAtGlobalLevel(loc, getQualifierString(qualifier)); |
4603 | return new TStorageQualifierWrapper(qualifier, loc); |
4604 | } |
4605 | |
4606 | TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc) |
4607 | { |
4608 | if (getShaderType() == GL_VERTEX_SHADER) |
4609 | { |
4610 | return parseGlobalStorageQualifier(EvqVaryingOut, loc); |
4611 | } |
4612 | return parseGlobalStorageQualifier(EvqVaryingIn, loc); |
4613 | } |
4614 | |
4615 | TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) |
4616 | { |
4617 | if (declaringFunction()) |
4618 | { |
4619 | return new TStorageQualifierWrapper(EvqIn, loc); |
4620 | } |
4621 | |
4622 | switch (getShaderType()) |
4623 | { |
4624 | case GL_VERTEX_SHADER: |
4625 | { |
4626 | if (mShaderVersion < 300 && !isExtensionEnabled(TExtension::OVR_multiview2)) |
4627 | { |
4628 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only" , "in" ); |
4629 | } |
4630 | return new TStorageQualifierWrapper(EvqVertexIn, loc); |
4631 | } |
4632 | case GL_FRAGMENT_SHADER: |
4633 | { |
4634 | if (mShaderVersion < 300) |
4635 | { |
4636 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only" , "in" ); |
4637 | } |
4638 | return new TStorageQualifierWrapper(EvqFragmentIn, loc); |
4639 | } |
4640 | case GL_COMPUTE_SHADER: |
4641 | { |
4642 | return new TStorageQualifierWrapper(EvqComputeIn, loc); |
4643 | } |
4644 | case GL_GEOMETRY_SHADER_EXT: |
4645 | { |
4646 | return new TStorageQualifierWrapper(EvqGeometryIn, loc); |
4647 | } |
4648 | default: |
4649 | { |
4650 | UNREACHABLE(); |
4651 | return new TStorageQualifierWrapper(EvqLast, loc); |
4652 | } |
4653 | } |
4654 | } |
4655 | |
4656 | TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc) |
4657 | { |
4658 | if (declaringFunction()) |
4659 | { |
4660 | return new TStorageQualifierWrapper(EvqOut, loc); |
4661 | } |
4662 | switch (getShaderType()) |
4663 | { |
4664 | case GL_VERTEX_SHADER: |
4665 | { |
4666 | if (mShaderVersion < 300) |
4667 | { |
4668 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only" , "out" ); |
4669 | } |
4670 | return new TStorageQualifierWrapper(EvqVertexOut, loc); |
4671 | } |
4672 | case GL_FRAGMENT_SHADER: |
4673 | { |
4674 | if (mShaderVersion < 300) |
4675 | { |
4676 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only" , "out" ); |
4677 | } |
4678 | return new TStorageQualifierWrapper(EvqFragmentOut, loc); |
4679 | } |
4680 | case GL_COMPUTE_SHADER: |
4681 | { |
4682 | error(loc, "storage qualifier isn't supported in compute shaders" , "out" ); |
4683 | return new TStorageQualifierWrapper(EvqLast, loc); |
4684 | } |
4685 | case GL_GEOMETRY_SHADER_EXT: |
4686 | { |
4687 | return new TStorageQualifierWrapper(EvqGeometryOut, loc); |
4688 | } |
4689 | default: |
4690 | { |
4691 | UNREACHABLE(); |
4692 | return new TStorageQualifierWrapper(EvqLast, loc); |
4693 | } |
4694 | } |
4695 | } |
4696 | |
4697 | TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc) |
4698 | { |
4699 | if (!declaringFunction()) |
4700 | { |
4701 | error(loc, "invalid qualifier: can be only used with function parameters" , "inout" ); |
4702 | } |
4703 | return new TStorageQualifierWrapper(EvqInOut, loc); |
4704 | } |
4705 | |
4706 | TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, |
4707 | TLayoutQualifier rightQualifier, |
4708 | const TSourceLoc &rightQualifierLocation) |
4709 | { |
4710 | return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation, |
4711 | mDiagnostics); |
4712 | } |
4713 | |
4714 | TDeclarator *TParseContext::parseStructDeclarator(const ImmutableString &identifier, |
4715 | const TSourceLoc &loc) |
4716 | { |
4717 | checkIsNotReserved(loc, identifier); |
4718 | return new TDeclarator(identifier, loc); |
4719 | } |
4720 | |
4721 | TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &identifier, |
4722 | const TSourceLoc &loc, |
4723 | const TVector<unsigned int> *arraySizes) |
4724 | { |
4725 | checkIsNotReserved(loc, identifier); |
4726 | return new TDeclarator(identifier, arraySizes, loc); |
4727 | } |
4728 | |
4729 | void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, |
4730 | const TFieldList::const_iterator end, |
4731 | const ImmutableString &name, |
4732 | const TSourceLoc &location) |
4733 | { |
4734 | for (auto fieldIter = begin; fieldIter != end; ++fieldIter) |
4735 | { |
4736 | if ((*fieldIter)->name() == name) |
4737 | { |
4738 | error(location, "duplicate field name in structure" , name); |
4739 | } |
4740 | } |
4741 | } |
4742 | |
4743 | TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location) |
4744 | { |
4745 | for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end(); |
4746 | ++fieldIter) |
4747 | { |
4748 | checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(), |
4749 | location); |
4750 | } |
4751 | return fields; |
4752 | } |
4753 | |
4754 | TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields, |
4755 | const TFieldList *newlyAddedFields, |
4756 | const TSourceLoc &location) |
4757 | { |
4758 | for (TField *field : *newlyAddedFields) |
4759 | { |
4760 | checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(), |
4761 | field->name(), location); |
4762 | processedFields->push_back(field); |
4763 | } |
4764 | return processedFields; |
4765 | } |
4766 | |
4767 | TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( |
4768 | const TTypeQualifierBuilder &typeQualifierBuilder, |
4769 | TPublicType *typeSpecifier, |
4770 | const TDeclaratorList *declaratorList) |
4771 | { |
4772 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); |
4773 | |
4774 | typeSpecifier->qualifier = typeQualifier.qualifier; |
4775 | typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier; |
4776 | typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier; |
4777 | typeSpecifier->invariant = typeQualifier.invariant; |
4778 | if (typeQualifier.precision != EbpUndefined) |
4779 | { |
4780 | typeSpecifier->precision = typeQualifier.precision; |
4781 | } |
4782 | return addStructDeclaratorList(*typeSpecifier, declaratorList); |
4783 | } |
4784 | |
4785 | TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, |
4786 | const TDeclaratorList *declaratorList) |
4787 | { |
4788 | checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, |
4789 | typeSpecifier.getBasicType()); |
4790 | |
4791 | checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(), |
4792 | typeSpecifier.getBasicType()); |
4793 | |
4794 | checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); |
4795 | |
4796 | TFieldList *fieldList = new TFieldList(); |
4797 | |
4798 | for (const TDeclarator *declarator : *declaratorList) |
4799 | { |
4800 | TType *type = new TType(typeSpecifier); |
4801 | if (declarator->isArray()) |
4802 | { |
4803 | // Don't allow arrays of arrays in ESSL < 3.10. |
4804 | checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier); |
4805 | type->makeArrays(*declarator->arraySizes()); |
4806 | } |
4807 | |
4808 | TField *field = |
4809 | new TField(type, declarator->name(), declarator->line(), SymbolType::UserDefined); |
4810 | checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *field); |
4811 | fieldList->push_back(field); |
4812 | } |
4813 | |
4814 | return fieldList; |
4815 | } |
4816 | |
4817 | TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, |
4818 | const TSourceLoc &nameLine, |
4819 | const ImmutableString &structName, |
4820 | TFieldList *fieldList) |
4821 | { |
4822 | SymbolType structSymbolType = SymbolType::UserDefined; |
4823 | if (structName.empty()) |
4824 | { |
4825 | structSymbolType = SymbolType::Empty; |
4826 | } |
4827 | TStructure *structure = new TStructure(&symbolTable, structName, fieldList, structSymbolType); |
4828 | |
4829 | // Store a bool in the struct if we're at global scope, to allow us to |
4830 | // skip the local struct scoping workaround in HLSL. |
4831 | structure->setAtGlobalScope(symbolTable.atGlobalLevel()); |
4832 | |
4833 | if (structSymbolType != SymbolType::Empty) |
4834 | { |
4835 | checkIsNotReserved(nameLine, structName); |
4836 | if (!symbolTable.declare(structure)) |
4837 | { |
4838 | error(nameLine, "redefinition of a struct" , structName); |
4839 | } |
4840 | } |
4841 | |
4842 | // ensure we do not specify any storage qualifiers on the struct members |
4843 | for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++) |
4844 | { |
4845 | TField &field = *(*fieldList)[typeListIndex]; |
4846 | const TQualifier qualifier = field.type()->getQualifier(); |
4847 | switch (qualifier) |
4848 | { |
4849 | case EvqGlobal: |
4850 | case EvqTemporary: |
4851 | break; |
4852 | default: |
4853 | error(field.line(), "invalid qualifier on struct member" , |
4854 | getQualifierString(qualifier)); |
4855 | break; |
4856 | } |
4857 | if (field.type()->isInvariant()) |
4858 | { |
4859 | error(field.line(), "invalid qualifier on struct member" , "invariant" ); |
4860 | } |
4861 | // ESSL 3.10 section 4.1.8 -- atomic_uint or images are not allowed as structure member. |
4862 | if (IsImage(field.type()->getBasicType()) || IsAtomicCounter(field.type()->getBasicType())) |
4863 | { |
4864 | error(field.line(), "disallowed type in struct" , field.type()->getBasicString()); |
4865 | } |
4866 | |
4867 | checkIsNotUnsizedArray(field.line(), "array members of structs must specify a size" , |
4868 | field.name(), field.type()); |
4869 | |
4870 | checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line()); |
4871 | |
4872 | checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index); |
4873 | |
4874 | checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding); |
4875 | |
4876 | checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); |
4877 | } |
4878 | |
4879 | TTypeSpecifierNonArray typeSpecifierNonArray; |
4880 | typeSpecifierNonArray.initializeStruct(structure, true, structLine); |
4881 | exitStructDeclaration(); |
4882 | |
4883 | return typeSpecifierNonArray; |
4884 | } |
4885 | |
4886 | TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, |
4887 | TIntermBlock *statementList, |
4888 | const TSourceLoc &loc) |
4889 | { |
4890 | TBasicType switchType = init->getBasicType(); |
4891 | if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() || |
4892 | init->isVector()) |
4893 | { |
4894 | error(init->getLine(), "init-expression in a switch statement must be a scalar integer" , |
4895 | "switch" ); |
4896 | return nullptr; |
4897 | } |
4898 | |
4899 | ASSERT(statementList); |
4900 | if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc)) |
4901 | { |
4902 | ASSERT(mDiagnostics->numErrors() > 0); |
4903 | return nullptr; |
4904 | } |
4905 | |
4906 | markStaticReadIfSymbol(init); |
4907 | TIntermSwitch *node = new TIntermSwitch(init, statementList); |
4908 | node->setLine(loc); |
4909 | return node; |
4910 | } |
4911 | |
4912 | TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) |
4913 | { |
4914 | if (mSwitchNestingLevel == 0) |
4915 | { |
4916 | error(loc, "case labels need to be inside switch statements" , "case" ); |
4917 | return nullptr; |
4918 | } |
4919 | if (condition == nullptr) |
4920 | { |
4921 | error(loc, "case label must have a condition" , "case" ); |
4922 | return nullptr; |
4923 | } |
4924 | if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || |
4925 | condition->isMatrix() || condition->isArray() || condition->isVector()) |
4926 | { |
4927 | error(condition->getLine(), "case label must be a scalar integer" , "case" ); |
4928 | } |
4929 | TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); |
4930 | // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be |
4931 | // safe against corner cases we still check for conditionConst. Some interpretations of the |
4932 | // spec have allowed constant expressions with side effects - like array length() method on a |
4933 | // non-constant array. |
4934 | if (condition->getQualifier() != EvqConst || conditionConst == nullptr) |
4935 | { |
4936 | error(condition->getLine(), "case label must be constant" , "case" ); |
4937 | } |
4938 | TIntermCase *node = new TIntermCase(condition); |
4939 | node->setLine(loc); |
4940 | return node; |
4941 | } |
4942 | |
4943 | TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) |
4944 | { |
4945 | if (mSwitchNestingLevel == 0) |
4946 | { |
4947 | error(loc, "default labels need to be inside switch statements" , "default" ); |
4948 | return nullptr; |
4949 | } |
4950 | TIntermCase *node = new TIntermCase(nullptr); |
4951 | node->setLine(loc); |
4952 | return node; |
4953 | } |
4954 | |
4955 | TIntermTyped *TParseContext::createUnaryMath(TOperator op, |
4956 | TIntermTyped *child, |
4957 | const TSourceLoc &loc, |
4958 | const TFunction *func) |
4959 | { |
4960 | ASSERT(child != nullptr); |
4961 | |
4962 | switch (op) |
4963 | { |
4964 | case EOpLogicalNot: |
4965 | if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() || |
4966 | child->isVector()) |
4967 | { |
4968 | unaryOpError(loc, GetOperatorString(op), child->getType()); |
4969 | return nullptr; |
4970 | } |
4971 | break; |
4972 | case EOpBitwiseNot: |
4973 | if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || |
4974 | child->isMatrix() || child->isArray()) |
4975 | { |
4976 | unaryOpError(loc, GetOperatorString(op), child->getType()); |
4977 | return nullptr; |
4978 | } |
4979 | break; |
4980 | case EOpPostIncrement: |
4981 | case EOpPreIncrement: |
4982 | case EOpPostDecrement: |
4983 | case EOpPreDecrement: |
4984 | case EOpNegative: |
4985 | case EOpPositive: |
4986 | if (child->getBasicType() == EbtStruct || child->isInterfaceBlock() || |
4987 | child->getBasicType() == EbtBool || child->isArray() || |
4988 | child->getBasicType() == EbtVoid || IsOpaqueType(child->getBasicType())) |
4989 | { |
4990 | unaryOpError(loc, GetOperatorString(op), child->getType()); |
4991 | return nullptr; |
4992 | } |
4993 | break; |
4994 | // Operators for built-ins are already type checked against their prototype. |
4995 | default: |
4996 | break; |
4997 | } |
4998 | |
4999 | if (child->getMemoryQualifier().writeonly) |
5000 | { |
5001 | unaryOpError(loc, GetOperatorString(op), child->getType()); |
5002 | return nullptr; |
5003 | } |
5004 | |
5005 | markStaticReadIfSymbol(child); |
5006 | TIntermUnary *node = new TIntermUnary(op, child, func); |
5007 | node->setLine(loc); |
5008 | |
5009 | return node->fold(mDiagnostics); |
5010 | } |
5011 | |
5012 | TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) |
5013 | { |
5014 | ASSERT(op != EOpNull); |
5015 | TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); |
5016 | if (node == nullptr) |
5017 | { |
5018 | return child; |
5019 | } |
5020 | return node; |
5021 | } |
5022 | |
5023 | TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, |
5024 | TIntermTyped *child, |
5025 | const TSourceLoc &loc) |
5026 | { |
5027 | checkCanBeLValue(loc, GetOperatorString(op), child); |
5028 | return addUnaryMath(op, child, loc); |
5029 | } |
5030 | |
5031 | TIntermTyped *TParseContext::expressionOrFoldedResult(TIntermTyped *expression) |
5032 | { |
5033 | // If we can, we should return the folded version of the expression for subsequent parsing. This |
5034 | // enables folding the containing expression during parsing as well, instead of the separate |
5035 | // FoldExpressions() step where folding nested expressions requires multiple full AST |
5036 | // traversals. |
5037 | |
5038 | // Even if folding fails the fold() functions return some node representing the expression, |
5039 | // typically the original node. So "folded" can be assumed to be non-null. |
5040 | TIntermTyped *folded = expression->fold(mDiagnostics); |
5041 | ASSERT(folded != nullptr); |
5042 | if (folded->getQualifier() == expression->getQualifier()) |
5043 | { |
5044 | // We need this expression to have the correct qualifier when validating the consuming |
5045 | // expression. So we can only return the folded node from here in case it has the same |
5046 | // qualifier as the original expression. In this kind of a cases the qualifier of the folded |
5047 | // node is EvqConst, whereas the qualifier of the expression is EvqTemporary: |
5048 | // 1. (true ? 1.0 : non_constant) |
5049 | // 2. (non_constant, 1.0) |
5050 | return folded; |
5051 | } |
5052 | return expression; |
5053 | } |
5054 | |
5055 | bool TParseContext::binaryOpCommonCheck(TOperator op, |
5056 | TIntermTyped *left, |
5057 | TIntermTyped *right, |
5058 | const TSourceLoc &loc) |
5059 | { |
5060 | // Check opaque types are not allowed to be operands in expressions other than array indexing |
5061 | // and structure member selection. |
5062 | if (IsOpaqueType(left->getBasicType()) || IsOpaqueType(right->getBasicType())) |
5063 | { |
5064 | switch (op) |
5065 | { |
5066 | case EOpIndexDirect: |
5067 | case EOpIndexIndirect: |
5068 | break; |
5069 | |
5070 | default: |
5071 | ASSERT(op != EOpIndexDirectStruct); |
5072 | error(loc, "Invalid operation for variables with an opaque type" , |
5073 | GetOperatorString(op)); |
5074 | return false; |
5075 | } |
5076 | } |
5077 | |
5078 | if (right->getMemoryQualifier().writeonly) |
5079 | { |
5080 | error(loc, "Invalid operation for variables with writeonly" , GetOperatorString(op)); |
5081 | return false; |
5082 | } |
5083 | |
5084 | if (left->getMemoryQualifier().writeonly) |
5085 | { |
5086 | switch (op) |
5087 | { |
5088 | case EOpAssign: |
5089 | case EOpInitialize: |
5090 | case EOpIndexDirect: |
5091 | case EOpIndexIndirect: |
5092 | case EOpIndexDirectStruct: |
5093 | case EOpIndexDirectInterfaceBlock: |
5094 | break; |
5095 | default: |
5096 | error(loc, "Invalid operation for variables with writeonly" , GetOperatorString(op)); |
5097 | return false; |
5098 | } |
5099 | } |
5100 | |
5101 | if (left->getType().getStruct() || right->getType().getStruct()) |
5102 | { |
5103 | switch (op) |
5104 | { |
5105 | case EOpIndexDirectStruct: |
5106 | ASSERT(left->getType().getStruct()); |
5107 | break; |
5108 | case EOpEqual: |
5109 | case EOpNotEqual: |
5110 | case EOpAssign: |
5111 | case EOpInitialize: |
5112 | if (left->getType() != right->getType()) |
5113 | { |
5114 | return false; |
5115 | } |
5116 | break; |
5117 | default: |
5118 | error(loc, "Invalid operation for structs" , GetOperatorString(op)); |
5119 | return false; |
5120 | } |
5121 | } |
5122 | |
5123 | if (left->isInterfaceBlock() || right->isInterfaceBlock()) |
5124 | { |
5125 | switch (op) |
5126 | { |
5127 | case EOpIndexDirectInterfaceBlock: |
5128 | ASSERT(left->getType().getInterfaceBlock()); |
5129 | break; |
5130 | default: |
5131 | error(loc, "Invalid operation for interface blocks" , GetOperatorString(op)); |
5132 | return false; |
5133 | } |
5134 | } |
5135 | |
5136 | if (left->isArray() != right->isArray()) |
5137 | { |
5138 | error(loc, "array / non-array mismatch" , GetOperatorString(op)); |
5139 | return false; |
5140 | } |
5141 | |
5142 | if (left->isArray()) |
5143 | { |
5144 | ASSERT(right->isArray()); |
5145 | if (mShaderVersion < 300) |
5146 | { |
5147 | error(loc, "Invalid operation for arrays" , GetOperatorString(op)); |
5148 | return false; |
5149 | } |
5150 | |
5151 | switch (op) |
5152 | { |
5153 | case EOpEqual: |
5154 | case EOpNotEqual: |
5155 | case EOpAssign: |
5156 | case EOpInitialize: |
5157 | break; |
5158 | default: |
5159 | error(loc, "Invalid operation for arrays" , GetOperatorString(op)); |
5160 | return false; |
5161 | } |
5162 | // At this point, size of implicitly sized arrays should be resolved. |
5163 | if (*left->getType().getArraySizes() != *right->getType().getArraySizes()) |
5164 | { |
5165 | error(loc, "array size mismatch" , GetOperatorString(op)); |
5166 | return false; |
5167 | } |
5168 | } |
5169 | |
5170 | // Check ops which require integer / ivec parameters |
5171 | bool isBitShift = false; |
5172 | switch (op) |
5173 | { |
5174 | case EOpBitShiftLeft: |
5175 | case EOpBitShiftRight: |
5176 | case EOpBitShiftLeftAssign: |
5177 | case EOpBitShiftRightAssign: |
5178 | // Unsigned can be bit-shifted by signed and vice versa, but we need to |
5179 | // check that the basic type is an integer type. |
5180 | isBitShift = true; |
5181 | if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) |
5182 | { |
5183 | return false; |
5184 | } |
5185 | break; |
5186 | case EOpBitwiseAnd: |
5187 | case EOpBitwiseXor: |
5188 | case EOpBitwiseOr: |
5189 | case EOpBitwiseAndAssign: |
5190 | case EOpBitwiseXorAssign: |
5191 | case EOpBitwiseOrAssign: |
5192 | // It is enough to check the type of only one operand, since later it |
5193 | // is checked that the operand types match. |
5194 | if (!IsInteger(left->getBasicType())) |
5195 | { |
5196 | return false; |
5197 | } |
5198 | break; |
5199 | default: |
5200 | break; |
5201 | } |
5202 | |
5203 | // GLSL ES 1.00 and 3.00 do not support implicit type casting. |
5204 | // So the basic type should usually match. |
5205 | if (!isBitShift && left->getBasicType() != right->getBasicType()) |
5206 | { |
5207 | return false; |
5208 | } |
5209 | |
5210 | // Check that: |
5211 | // 1. Type sizes match exactly on ops that require that. |
5212 | // 2. Restrictions for structs that contain arrays or samplers are respected. |
5213 | // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected. |
5214 | switch (op) |
5215 | { |
5216 | case EOpAssign: |
5217 | case EOpInitialize: |
5218 | case EOpEqual: |
5219 | case EOpNotEqual: |
5220 | // ESSL 1.00 sections 5.7, 5.8, 5.9 |
5221 | if (mShaderVersion < 300 && left->getType().isStructureContainingArrays()) |
5222 | { |
5223 | error(loc, "undefined operation for structs containing arrays" , |
5224 | GetOperatorString(op)); |
5225 | return false; |
5226 | } |
5227 | // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, |
5228 | // we interpret the spec so that this extends to structs containing samplers, |
5229 | // similarly to ESSL 1.00 spec. |
5230 | if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && |
5231 | left->getType().isStructureContainingSamplers()) |
5232 | { |
5233 | error(loc, "undefined operation for structs containing samplers" , |
5234 | GetOperatorString(op)); |
5235 | return false; |
5236 | } |
5237 | |
5238 | if ((left->getNominalSize() != right->getNominalSize()) || |
5239 | (left->getSecondarySize() != right->getSecondarySize())) |
5240 | { |
5241 | error(loc, "dimension mismatch" , GetOperatorString(op)); |
5242 | return false; |
5243 | } |
5244 | break; |
5245 | case EOpLessThan: |
5246 | case EOpGreaterThan: |
5247 | case EOpLessThanEqual: |
5248 | case EOpGreaterThanEqual: |
5249 | if (!left->isScalar() || !right->isScalar()) |
5250 | { |
5251 | error(loc, "comparison operator only defined for scalars" , GetOperatorString(op)); |
5252 | return false; |
5253 | } |
5254 | break; |
5255 | case EOpAdd: |
5256 | case EOpSub: |
5257 | case EOpDiv: |
5258 | case EOpIMod: |
5259 | case EOpBitShiftLeft: |
5260 | case EOpBitShiftRight: |
5261 | case EOpBitwiseAnd: |
5262 | case EOpBitwiseXor: |
5263 | case EOpBitwiseOr: |
5264 | case EOpAddAssign: |
5265 | case EOpSubAssign: |
5266 | case EOpDivAssign: |
5267 | case EOpIModAssign: |
5268 | case EOpBitShiftLeftAssign: |
5269 | case EOpBitShiftRightAssign: |
5270 | case EOpBitwiseAndAssign: |
5271 | case EOpBitwiseXorAssign: |
5272 | case EOpBitwiseOrAssign: |
5273 | if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) |
5274 | { |
5275 | return false; |
5276 | } |
5277 | |
5278 | // Are the sizes compatible? |
5279 | if (left->getNominalSize() != right->getNominalSize() || |
5280 | left->getSecondarySize() != right->getSecondarySize()) |
5281 | { |
5282 | // If the nominal sizes of operands do not match: |
5283 | // One of them must be a scalar. |
5284 | if (!left->isScalar() && !right->isScalar()) |
5285 | return false; |
5286 | |
5287 | // In the case of compound assignment other than multiply-assign, |
5288 | // the right side needs to be a scalar. Otherwise a vector/matrix |
5289 | // would be assigned to a scalar. A scalar can't be shifted by a |
5290 | // vector either. |
5291 | if (!right->isScalar() && |
5292 | (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) |
5293 | return false; |
5294 | } |
5295 | break; |
5296 | default: |
5297 | break; |
5298 | } |
5299 | |
5300 | return true; |
5301 | } |
5302 | |
5303 | bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op, |
5304 | const TType &left, |
5305 | const TType &right) |
5306 | { |
5307 | switch (op) |
5308 | { |
5309 | case EOpMul: |
5310 | case EOpMulAssign: |
5311 | return left.getNominalSize() == right.getNominalSize() && |
5312 | left.getSecondarySize() == right.getSecondarySize(); |
5313 | case EOpVectorTimesScalar: |
5314 | return true; |
5315 | case EOpVectorTimesScalarAssign: |
5316 | ASSERT(!left.isMatrix() && !right.isMatrix()); |
5317 | return left.isVector() && !right.isVector(); |
5318 | case EOpVectorTimesMatrix: |
5319 | return left.getNominalSize() == right.getRows(); |
5320 | case EOpVectorTimesMatrixAssign: |
5321 | ASSERT(!left.isMatrix() && right.isMatrix()); |
5322 | return left.isVector() && left.getNominalSize() == right.getRows() && |
5323 | left.getNominalSize() == right.getCols(); |
5324 | case EOpMatrixTimesVector: |
5325 | return left.getCols() == right.getNominalSize(); |
5326 | case EOpMatrixTimesScalar: |
5327 | return true; |
5328 | case EOpMatrixTimesScalarAssign: |
5329 | ASSERT(left.isMatrix() && !right.isMatrix()); |
5330 | return !right.isVector(); |
5331 | case EOpMatrixTimesMatrix: |
5332 | return left.getCols() == right.getRows(); |
5333 | case EOpMatrixTimesMatrixAssign: |
5334 | ASSERT(left.isMatrix() && right.isMatrix()); |
5335 | // We need to check two things: |
5336 | // 1. The matrix multiplication step is valid. |
5337 | // 2. The result will have the same number of columns as the lvalue. |
5338 | return left.getCols() == right.getRows() && left.getCols() == right.getCols(); |
5339 | |
5340 | default: |
5341 | UNREACHABLE(); |
5342 | return false; |
5343 | } |
5344 | } |
5345 | |
5346 | TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, |
5347 | TIntermTyped *left, |
5348 | TIntermTyped *right, |
5349 | const TSourceLoc &loc) |
5350 | { |
5351 | if (!binaryOpCommonCheck(op, left, right, loc)) |
5352 | return nullptr; |
5353 | |
5354 | switch (op) |
5355 | { |
5356 | case EOpEqual: |
5357 | case EOpNotEqual: |
5358 | case EOpLessThan: |
5359 | case EOpGreaterThan: |
5360 | case EOpLessThanEqual: |
5361 | case EOpGreaterThanEqual: |
5362 | break; |
5363 | case EOpLogicalOr: |
5364 | case EOpLogicalXor: |
5365 | case EOpLogicalAnd: |
5366 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && |
5367 | !right->getType().getStruct()); |
5368 | if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar()) |
5369 | { |
5370 | return nullptr; |
5371 | } |
5372 | // Basic types matching should have been already checked. |
5373 | ASSERT(right->getBasicType() == EbtBool); |
5374 | break; |
5375 | case EOpAdd: |
5376 | case EOpSub: |
5377 | case EOpDiv: |
5378 | case EOpMul: |
5379 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && |
5380 | !right->getType().getStruct()); |
5381 | if (left->getBasicType() == EbtBool) |
5382 | { |
5383 | return nullptr; |
5384 | } |
5385 | break; |
5386 | case EOpIMod: |
5387 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && |
5388 | !right->getType().getStruct()); |
5389 | // Note that this is only for the % operator, not for mod() |
5390 | if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) |
5391 | { |
5392 | return nullptr; |
5393 | } |
5394 | break; |
5395 | default: |
5396 | break; |
5397 | } |
5398 | |
5399 | if (op == EOpMul) |
5400 | { |
5401 | op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType()); |
5402 | if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) |
5403 | { |
5404 | return nullptr; |
5405 | } |
5406 | } |
5407 | |
5408 | TIntermBinary *node = new TIntermBinary(op, left, right); |
5409 | ASSERT(op != EOpAssign); |
5410 | markStaticReadIfSymbol(left); |
5411 | markStaticReadIfSymbol(right); |
5412 | node->setLine(loc); |
5413 | return expressionOrFoldedResult(node); |
5414 | } |
5415 | |
5416 | TIntermTyped *TParseContext::addBinaryMath(TOperator op, |
5417 | TIntermTyped *left, |
5418 | TIntermTyped *right, |
5419 | const TSourceLoc &loc) |
5420 | { |
5421 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); |
5422 | if (node == 0) |
5423 | { |
5424 | binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); |
5425 | return left; |
5426 | } |
5427 | return node; |
5428 | } |
5429 | |
5430 | TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, |
5431 | TIntermTyped *left, |
5432 | TIntermTyped *right, |
5433 | const TSourceLoc &loc) |
5434 | { |
5435 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); |
5436 | if (node == nullptr) |
5437 | { |
5438 | binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); |
5439 | node = CreateBoolNode(false); |
5440 | node->setLine(loc); |
5441 | } |
5442 | return node; |
5443 | } |
5444 | |
5445 | TIntermTyped *TParseContext::addAssign(TOperator op, |
5446 | TIntermTyped *left, |
5447 | TIntermTyped *right, |
5448 | const TSourceLoc &loc) |
5449 | { |
5450 | checkCanBeLValue(loc, "assign" , left); |
5451 | TIntermBinary *node = nullptr; |
5452 | if (binaryOpCommonCheck(op, left, right, loc)) |
5453 | { |
5454 | if (op == EOpMulAssign) |
5455 | { |
5456 | op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType()); |
5457 | if (isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) |
5458 | { |
5459 | node = new TIntermBinary(op, left, right); |
5460 | } |
5461 | } |
5462 | else |
5463 | { |
5464 | node = new TIntermBinary(op, left, right); |
5465 | } |
5466 | } |
5467 | if (node == nullptr) |
5468 | { |
5469 | assignError(loc, "assign" , left->getType(), right->getType()); |
5470 | return left; |
5471 | } |
5472 | if (op != EOpAssign) |
5473 | { |
5474 | markStaticReadIfSymbol(left); |
5475 | } |
5476 | markStaticReadIfSymbol(right); |
5477 | node->setLine(loc); |
5478 | return node; |
5479 | } |
5480 | |
5481 | TIntermTyped *TParseContext::addComma(TIntermTyped *left, |
5482 | TIntermTyped *right, |
5483 | const TSourceLoc &loc) |
5484 | { |
5485 | // WebGL2 section 5.26, the following results in an error: |
5486 | // "Sequence operator applied to void, arrays, or structs containing arrays" |
5487 | if (mShaderSpec == SH_WEBGL2_SPEC && |
5488 | (left->isArray() || left->getBasicType() == EbtVoid || |
5489 | left->getType().isStructureContainingArrays() || right->isArray() || |
5490 | right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays())) |
5491 | { |
5492 | error(loc, |
5493 | "sequence operator is not allowed for void, arrays, or structs containing arrays" , |
5494 | "," ); |
5495 | } |
5496 | |
5497 | TIntermBinary *commaNode = TIntermBinary::CreateComma(left, right, mShaderVersion); |
5498 | markStaticReadIfSymbol(left); |
5499 | markStaticReadIfSymbol(right); |
5500 | commaNode->setLine(loc); |
5501 | |
5502 | return expressionOrFoldedResult(commaNode); |
5503 | } |
5504 | |
5505 | TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) |
5506 | { |
5507 | switch (op) |
5508 | { |
5509 | case EOpContinue: |
5510 | if (mLoopNestingLevel <= 0) |
5511 | { |
5512 | error(loc, "continue statement only allowed in loops" , "" ); |
5513 | } |
5514 | break; |
5515 | case EOpBreak: |
5516 | if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) |
5517 | { |
5518 | error(loc, "break statement only allowed in loops and switch statements" , "" ); |
5519 | } |
5520 | break; |
5521 | case EOpReturn: |
5522 | if (mCurrentFunctionType->getBasicType() != EbtVoid) |
5523 | { |
5524 | error(loc, "non-void function must return a value" , "return" ); |
5525 | } |
5526 | break; |
5527 | case EOpKill: |
5528 | if (mShaderType != GL_FRAGMENT_SHADER) |
5529 | { |
5530 | error(loc, "discard supported in fragment shaders only" , "discard" ); |
5531 | } |
5532 | break; |
5533 | default: |
5534 | UNREACHABLE(); |
5535 | break; |
5536 | } |
5537 | return addBranch(op, nullptr, loc); |
5538 | } |
5539 | |
5540 | TIntermBranch *TParseContext::addBranch(TOperator op, |
5541 | TIntermTyped *expression, |
5542 | const TSourceLoc &loc) |
5543 | { |
5544 | if (expression != nullptr) |
5545 | { |
5546 | markStaticReadIfSymbol(expression); |
5547 | ASSERT(op == EOpReturn); |
5548 | mFunctionReturnsValue = true; |
5549 | if (mCurrentFunctionType->getBasicType() == EbtVoid) |
5550 | { |
5551 | error(loc, "void function cannot return a value" , "return" ); |
5552 | } |
5553 | else if (*mCurrentFunctionType != expression->getType()) |
5554 | { |
5555 | error(loc, "function return is not matching type:" , "return" ); |
5556 | } |
5557 | } |
5558 | TIntermBranch *node = new TIntermBranch(op, expression); |
5559 | node->setLine(loc); |
5560 | return node; |
5561 | } |
5562 | |
5563 | void TParseContext::appendStatement(TIntermBlock *block, TIntermNode *statement) |
5564 | { |
5565 | if (statement != nullptr) |
5566 | { |
5567 | markStaticReadIfSymbol(statement); |
5568 | block->appendStatement(statement); |
5569 | } |
5570 | } |
5571 | |
5572 | void TParseContext::checkTextureGather(TIntermAggregate *functionCall) |
5573 | { |
5574 | ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); |
5575 | const TFunction *func = functionCall->getFunction(); |
5576 | if (BuiltInGroup::isTextureGather(func)) |
5577 | { |
5578 | bool isTextureGatherOffset = BuiltInGroup::isTextureGatherOffset(func); |
5579 | TIntermNode *componentNode = nullptr; |
5580 | TIntermSequence *arguments = functionCall->getSequence(); |
5581 | ASSERT(arguments->size() >= 2u && arguments->size() <= 4u); |
5582 | const TIntermTyped *sampler = arguments->front()->getAsTyped(); |
5583 | ASSERT(sampler != nullptr); |
5584 | switch (sampler->getBasicType()) |
5585 | { |
5586 | case EbtSampler2D: |
5587 | case EbtISampler2D: |
5588 | case EbtUSampler2D: |
5589 | case EbtSampler2DArray: |
5590 | case EbtISampler2DArray: |
5591 | case EbtUSampler2DArray: |
5592 | if ((!isTextureGatherOffset && arguments->size() == 3u) || |
5593 | (isTextureGatherOffset && arguments->size() == 4u)) |
5594 | { |
5595 | componentNode = arguments->back(); |
5596 | } |
5597 | break; |
5598 | case EbtSamplerCube: |
5599 | case EbtISamplerCube: |
5600 | case EbtUSamplerCube: |
5601 | ASSERT(!isTextureGatherOffset); |
5602 | if (arguments->size() == 3u) |
5603 | { |
5604 | componentNode = arguments->back(); |
5605 | } |
5606 | break; |
5607 | case EbtSampler2DShadow: |
5608 | case EbtSampler2DArrayShadow: |
5609 | case EbtSamplerCubeShadow: |
5610 | break; |
5611 | default: |
5612 | UNREACHABLE(); |
5613 | break; |
5614 | } |
5615 | if (componentNode) |
5616 | { |
5617 | const TIntermConstantUnion *componentConstantUnion = |
5618 | componentNode->getAsConstantUnion(); |
5619 | if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion) |
5620 | { |
5621 | error(functionCall->getLine(), "Texture component must be a constant expression" , |
5622 | func->name()); |
5623 | } |
5624 | else |
5625 | { |
5626 | int component = componentConstantUnion->getIConst(0); |
5627 | if (component < 0 || component > 3) |
5628 | { |
5629 | error(functionCall->getLine(), "Component must be in the range [0;3]" , |
5630 | func->name()); |
5631 | } |
5632 | } |
5633 | } |
5634 | } |
5635 | } |
5636 | |
5637 | void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) |
5638 | { |
5639 | ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); |
5640 | const TFunction *func = functionCall->getFunction(); |
5641 | TIntermNode *offset = nullptr; |
5642 | TIntermSequence *arguments = functionCall->getSequence(); |
5643 | bool useTextureGatherOffsetConstraints = false; |
5644 | if (BuiltInGroup::isTextureOffsetNoBias(func)) |
5645 | { |
5646 | offset = arguments->back(); |
5647 | } |
5648 | else if (BuiltInGroup::isTextureOffsetBias(func)) |
5649 | { |
5650 | // A bias parameter follows the offset parameter. |
5651 | ASSERT(arguments->size() >= 3); |
5652 | offset = (*arguments)[2]; |
5653 | } |
5654 | else if (BuiltInGroup::isTextureGatherOffset(func)) |
5655 | { |
5656 | ASSERT(arguments->size() >= 3u); |
5657 | const TIntermTyped *sampler = arguments->front()->getAsTyped(); |
5658 | ASSERT(sampler != nullptr); |
5659 | switch (sampler->getBasicType()) |
5660 | { |
5661 | case EbtSampler2D: |
5662 | case EbtISampler2D: |
5663 | case EbtUSampler2D: |
5664 | case EbtSampler2DArray: |
5665 | case EbtISampler2DArray: |
5666 | case EbtUSampler2DArray: |
5667 | offset = (*arguments)[2]; |
5668 | break; |
5669 | case EbtSampler2DShadow: |
5670 | case EbtSampler2DArrayShadow: |
5671 | offset = (*arguments)[3]; |
5672 | break; |
5673 | default: |
5674 | UNREACHABLE(); |
5675 | break; |
5676 | } |
5677 | useTextureGatherOffsetConstraints = true; |
5678 | } |
5679 | if (offset != nullptr) |
5680 | { |
5681 | TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion(); |
5682 | if (offset->getAsTyped()->getQualifier() != EvqConst || !offsetConstantUnion) |
5683 | { |
5684 | error(functionCall->getLine(), "Texture offset must be a constant expression" , |
5685 | func->name()); |
5686 | } |
5687 | else |
5688 | { |
5689 | ASSERT(offsetConstantUnion->getBasicType() == EbtInt); |
5690 | size_t size = offsetConstantUnion->getType().getObjectSize(); |
5691 | const TConstantUnion *values = offsetConstantUnion->getConstantValue(); |
5692 | int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset |
5693 | : mMinProgramTexelOffset; |
5694 | int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset |
5695 | : mMaxProgramTexelOffset; |
5696 | for (size_t i = 0u; i < size; ++i) |
5697 | { |
5698 | int offsetValue = values[i].getIConst(); |
5699 | if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue) |
5700 | { |
5701 | std::stringstream tokenStream = sh::InitializeStream<std::stringstream>(); |
5702 | tokenStream << offsetValue; |
5703 | std::string token = tokenStream.str(); |
5704 | error(offset->getLine(), "Texture offset value out of valid range" , |
5705 | token.c_str()); |
5706 | } |
5707 | } |
5708 | } |
5709 | } |
5710 | } |
5711 | |
5712 | void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall) |
5713 | { |
5714 | const TFunction *func = functionCall->getFunction(); |
5715 | if (BuiltInGroup::isAtomicMemory(func)) |
5716 | { |
5717 | ASSERT(IsAtomicFunction(functionCall->getOp())); |
5718 | TIntermSequence *arguments = functionCall->getSequence(); |
5719 | TIntermTyped *memNode = (*arguments)[0]->getAsTyped(); |
5720 | |
5721 | if (IsBufferOrSharedVariable(memNode)) |
5722 | { |
5723 | return; |
5724 | } |
5725 | |
5726 | while (memNode->getAsBinaryNode()) |
5727 | { |
5728 | memNode = memNode->getAsBinaryNode()->getLeft(); |
5729 | if (IsBufferOrSharedVariable(memNode)) |
5730 | { |
5731 | return; |
5732 | } |
5733 | } |
5734 | |
5735 | error(memNode->getLine(), |
5736 | "The value passed to the mem argument of an atomic memory function does not " |
5737 | "correspond to a buffer or shared variable." , |
5738 | func->name()); |
5739 | } |
5740 | } |
5741 | |
5742 | // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers |
5743 | void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall) |
5744 | { |
5745 | ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); |
5746 | |
5747 | const TFunction *func = functionCall->getFunction(); |
5748 | |
5749 | if (BuiltInGroup::isImage(func)) |
5750 | { |
5751 | TIntermSequence *arguments = functionCall->getSequence(); |
5752 | TIntermTyped *imageNode = (*arguments)[0]->getAsTyped(); |
5753 | |
5754 | const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier(); |
5755 | |
5756 | if (BuiltInGroup::isImageStore(func)) |
5757 | { |
5758 | if (memoryQualifier.readonly) |
5759 | { |
5760 | error(imageNode->getLine(), |
5761 | "'imageStore' cannot be used with images qualified as 'readonly'" , |
5762 | GetImageArgumentToken(imageNode)); |
5763 | } |
5764 | } |
5765 | else if (BuiltInGroup::isImageLoad(func)) |
5766 | { |
5767 | if (memoryQualifier.writeonly) |
5768 | { |
5769 | error(imageNode->getLine(), |
5770 | "'imageLoad' cannot be used with images qualified as 'writeonly'" , |
5771 | GetImageArgumentToken(imageNode)); |
5772 | } |
5773 | } |
5774 | } |
5775 | } |
5776 | |
5777 | // GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters |
5778 | void TParseContext::checkImageMemoryAccessForUserDefinedFunctions( |
5779 | const TFunction *functionDefinition, |
5780 | const TIntermAggregate *functionCall) |
5781 | { |
5782 | ASSERT(functionCall->getOp() == EOpCallFunctionInAST); |
5783 | |
5784 | const TIntermSequence &arguments = *functionCall->getSequence(); |
5785 | |
5786 | ASSERT(functionDefinition->getParamCount() == arguments.size()); |
5787 | |
5788 | for (size_t i = 0; i < arguments.size(); ++i) |
5789 | { |
5790 | TIntermTyped *typedArgument = arguments[i]->getAsTyped(); |
5791 | const TType &functionArgumentType = typedArgument->getType(); |
5792 | const TType &functionParameterType = functionDefinition->getParam(i)->getType(); |
5793 | ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType()); |
5794 | |
5795 | if (IsImage(functionArgumentType.getBasicType())) |
5796 | { |
5797 | const TMemoryQualifier &functionArgumentMemoryQualifier = |
5798 | functionArgumentType.getMemoryQualifier(); |
5799 | const TMemoryQualifier &functionParameterMemoryQualifier = |
5800 | functionParameterType.getMemoryQualifier(); |
5801 | if (functionArgumentMemoryQualifier.readonly && |
5802 | !functionParameterMemoryQualifier.readonly) |
5803 | { |
5804 | error(functionCall->getLine(), |
5805 | "Function call discards the 'readonly' qualifier from image" , |
5806 | GetImageArgumentToken(typedArgument)); |
5807 | } |
5808 | |
5809 | if (functionArgumentMemoryQualifier.writeonly && |
5810 | !functionParameterMemoryQualifier.writeonly) |
5811 | { |
5812 | error(functionCall->getLine(), |
5813 | "Function call discards the 'writeonly' qualifier from image" , |
5814 | GetImageArgumentToken(typedArgument)); |
5815 | } |
5816 | |
5817 | if (functionArgumentMemoryQualifier.coherent && |
5818 | !functionParameterMemoryQualifier.coherent) |
5819 | { |
5820 | error(functionCall->getLine(), |
5821 | "Function call discards the 'coherent' qualifier from image" , |
5822 | GetImageArgumentToken(typedArgument)); |
5823 | } |
5824 | |
5825 | if (functionArgumentMemoryQualifier.volatileQualifier && |
5826 | !functionParameterMemoryQualifier.volatileQualifier) |
5827 | { |
5828 | error(functionCall->getLine(), |
5829 | "Function call discards the 'volatile' qualifier from image" , |
5830 | GetImageArgumentToken(typedArgument)); |
5831 | } |
5832 | } |
5833 | } |
5834 | } |
5835 | |
5836 | TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) |
5837 | { |
5838 | if (fnCall->thisNode() != nullptr) |
5839 | { |
5840 | return addMethod(fnCall, loc); |
5841 | } |
5842 | if (fnCall->isConstructor()) |
5843 | { |
5844 | return addConstructor(fnCall, loc); |
5845 | } |
5846 | return addNonConstructorFunctionCall(fnCall, loc); |
5847 | } |
5848 | |
5849 | TIntermTyped *TParseContext::addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) |
5850 | { |
5851 | TIntermTyped *thisNode = fnCall->thisNode(); |
5852 | // It's possible for the name pointer in the TFunction to be null in case it gets parsed as |
5853 | // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS |
5854 | // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead. |
5855 | // So accessing fnCall->name() below is safe. |
5856 | if (fnCall->name() != "length" ) |
5857 | { |
5858 | error(loc, "invalid method" , fnCall->name()); |
5859 | } |
5860 | else if (!fnCall->arguments().empty()) |
5861 | { |
5862 | error(loc, "method takes no parameters" , "length" ); |
5863 | } |
5864 | else if (!thisNode->isArray()) |
5865 | { |
5866 | error(loc, "length can only be called on arrays" , "length" ); |
5867 | } |
5868 | else if (thisNode->getQualifier() == EvqPerVertexIn && |
5869 | mGeometryShaderInputPrimitiveType == EptUndefined) |
5870 | { |
5871 | ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT); |
5872 | error(loc, "missing input primitive declaration before calling length on gl_in" , "length" ); |
5873 | } |
5874 | else |
5875 | { |
5876 | TIntermUnary *node = new TIntermUnary(EOpArrayLength, thisNode, nullptr); |
5877 | markStaticReadIfSymbol(thisNode); |
5878 | node->setLine(loc); |
5879 | return node->fold(mDiagnostics); |
5880 | } |
5881 | return CreateZeroNode(TType(EbtInt, EbpUndefined, EvqConst)); |
5882 | } |
5883 | |
5884 | TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCall, |
5885 | const TSourceLoc &loc) |
5886 | { |
5887 | // First check whether the function has been hidden by a variable name or struct typename by |
5888 | // using the symbol looked up in the lexical phase. If the function is not hidden, look for one |
5889 | // with a matching argument list. |
5890 | if (fnCall->symbol() != nullptr && !fnCall->symbol()->isFunction()) |
5891 | { |
5892 | error(loc, "function name expected" , fnCall->name()); |
5893 | } |
5894 | else |
5895 | { |
5896 | // There are no inner functions, so it's enough to look for user-defined functions in the |
5897 | // global scope. |
5898 | const TSymbol *symbol = symbolTable.findGlobal(fnCall->getMangledName()); |
5899 | if (symbol != nullptr) |
5900 | { |
5901 | // A user-defined function - could be an overloaded built-in as well. |
5902 | ASSERT(symbol->symbolType() == SymbolType::UserDefined); |
5903 | const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); |
5904 | TIntermAggregate *callNode = |
5905 | TIntermAggregate::CreateFunctionCall(*fnCandidate, &fnCall->arguments()); |
5906 | callNode->setLine(loc); |
5907 | checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); |
5908 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); |
5909 | return callNode; |
5910 | } |
5911 | |
5912 | symbol = symbolTable.findBuiltIn(fnCall->getMangledName(), mShaderVersion); |
5913 | if (symbol == nullptr) |
5914 | { |
5915 | error(loc, "no matching overloaded function found" , fnCall->name()); |
5916 | } |
5917 | else |
5918 | { |
5919 | // A built-in function. |
5920 | ASSERT(symbol->symbolType() == SymbolType::BuiltIn); |
5921 | const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); |
5922 | |
5923 | if (fnCandidate->extension() != TExtension::UNDEFINED) |
5924 | { |
5925 | checkCanUseExtension(loc, fnCandidate->extension()); |
5926 | } |
5927 | TOperator op = fnCandidate->getBuiltInOp(); |
5928 | if (op != EOpCallBuiltInFunction) |
5929 | { |
5930 | // A function call mapped to a built-in operation. |
5931 | if (fnCandidate->getParamCount() == 1) |
5932 | { |
5933 | // Treat it like a built-in unary operator. |
5934 | TIntermNode *unaryParamNode = fnCall->arguments().front(); |
5935 | TIntermTyped *callNode = |
5936 | createUnaryMath(op, unaryParamNode->getAsTyped(), loc, fnCandidate); |
5937 | ASSERT(callNode != nullptr); |
5938 | return callNode; |
5939 | } |
5940 | |
5941 | TIntermAggregate *callNode = |
5942 | TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); |
5943 | callNode->setLine(loc); |
5944 | |
5945 | checkAtomicMemoryBuiltinFunctions(callNode); |
5946 | |
5947 | // Some built-in functions have out parameters too. |
5948 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); |
5949 | |
5950 | // See if we can constant fold a built-in. Note that this may be possible |
5951 | // even if it is not const-qualified. |
5952 | return callNode->fold(mDiagnostics); |
5953 | } |
5954 | |
5955 | // This is a built-in function with no op associated with it. |
5956 | TIntermAggregate *callNode = |
5957 | TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); |
5958 | callNode->setLine(loc); |
5959 | checkTextureOffsetConst(callNode); |
5960 | checkTextureGather(callNode); |
5961 | checkImageMemoryAccessForBuiltinFunctions(callNode); |
5962 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); |
5963 | return callNode; |
5964 | } |
5965 | } |
5966 | |
5967 | // Error message was already written. Put on a dummy node for error recovery. |
5968 | return CreateZeroNode(TType(EbtFloat, EbpMedium, EvqConst)); |
5969 | } |
5970 | |
5971 | TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, |
5972 | TIntermTyped *trueExpression, |
5973 | TIntermTyped *falseExpression, |
5974 | const TSourceLoc &loc) |
5975 | { |
5976 | if (!checkIsScalarBool(loc, cond)) |
5977 | { |
5978 | return falseExpression; |
5979 | } |
5980 | |
5981 | if (trueExpression->getType() != falseExpression->getType()) |
5982 | { |
5983 | TInfoSinkBase reasonStream; |
5984 | reasonStream << "mismatching ternary operator operand types '" << trueExpression->getType() |
5985 | << " and '" << falseExpression->getType() << "'" ; |
5986 | error(loc, reasonStream.c_str(), "?:" ); |
5987 | return falseExpression; |
5988 | } |
5989 | if (IsOpaqueType(trueExpression->getBasicType())) |
5990 | { |
5991 | // ESSL 1.00 section 4.1.7 |
5992 | // ESSL 3.00.6 section 4.1.7 |
5993 | // Opaque/sampler types are not allowed in most types of expressions, including ternary. |
5994 | // Note that structs containing opaque types don't need to be checked as structs are |
5995 | // forbidden below. |
5996 | error(loc, "ternary operator is not allowed for opaque types" , "?:" ); |
5997 | return falseExpression; |
5998 | } |
5999 | |
6000 | if (cond->getMemoryQualifier().writeonly || trueExpression->getMemoryQualifier().writeonly || |
6001 | falseExpression->getMemoryQualifier().writeonly) |
6002 | { |
6003 | error(loc, "ternary operator is not allowed for variables with writeonly" , "?:" ); |
6004 | return falseExpression; |
6005 | } |
6006 | |
6007 | // ESSL 1.00.17 sections 5.2 and 5.7: |
6008 | // Ternary operator is not among the operators allowed for structures/arrays. |
6009 | // ESSL 3.00.6 section 5.7: |
6010 | // Ternary operator support is optional for arrays. No certainty that it works across all |
6011 | // devices with struct either, so we err on the side of caution here. TODO ([email protected]): |
6012 | // Would be nice to make the spec and implementation agree completely here. |
6013 | if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct) |
6014 | { |
6015 | error(loc, "ternary operator is not allowed for structures or arrays" , "?:" ); |
6016 | return falseExpression; |
6017 | } |
6018 | if (trueExpression->getBasicType() == EbtInterfaceBlock) |
6019 | { |
6020 | error(loc, "ternary operator is not allowed for interface blocks" , "?:" ); |
6021 | return falseExpression; |
6022 | } |
6023 | |
6024 | // WebGL2 section 5.26, the following results in an error: |
6025 | // "Ternary operator applied to void, arrays, or structs containing arrays" |
6026 | if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid) |
6027 | { |
6028 | error(loc, "ternary operator is not allowed for void" , "?:" ); |
6029 | return falseExpression; |
6030 | } |
6031 | |
6032 | TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression); |
6033 | markStaticReadIfSymbol(cond); |
6034 | markStaticReadIfSymbol(trueExpression); |
6035 | markStaticReadIfSymbol(falseExpression); |
6036 | node->setLine(loc); |
6037 | return expressionOrFoldedResult(node); |
6038 | } |
6039 | |
6040 | // |
6041 | // Parse an array of strings using yyparse. |
6042 | // |
6043 | // Returns 0 for success. |
6044 | // |
6045 | int PaParseStrings(size_t count, |
6046 | const char *const string[], |
6047 | const int length[], |
6048 | TParseContext *context) |
6049 | { |
6050 | if ((count == 0) || (string == nullptr)) |
6051 | return 1; |
6052 | |
6053 | if (glslang_initialize(context)) |
6054 | return 1; |
6055 | |
6056 | int error = glslang_scan(count, string, length, context); |
6057 | if (!error) |
6058 | error = glslang_parse(context); |
6059 | |
6060 | glslang_finalize(context); |
6061 | |
6062 | return (error == 0) && (context->numErrors() == 0) ? 0 : 1; |
6063 | } |
6064 | |
6065 | } // namespace sh |
6066 | |