File: | root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp |
Warning: | line 6339, column 43 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // | |||
2 | // Copyright 2002 The ANGLE Project Authors. All rights reserved. | |||
3 | // Use of this source code is governed by a BSD-style license that can be | |||
4 | // found in the LICENSE file. | |||
5 | // | |||
6 | ||||
7 | #include "compiler/translator/ParseContext.h" | |||
8 | ||||
9 | #include <stdarg.h> | |||
10 | #include <stdio.h> | |||
11 | ||||
12 | #include "common/mathutil.h" | |||
13 | #include "common/utilities.h" | |||
14 | #include "compiler/preprocessor/SourceLocation.h" | |||
15 | #include "compiler/translator/Declarator.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()))(IsImage(imageNode->getBasicType()) ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 66, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 66 << "): " << "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()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 116, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 116 << ")"; } while (0); | |||
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 | TIntermTyped *FindLValueBase(TIntermTyped *node) | |||
132 | { | |||
133 | do | |||
134 | { | |||
135 | const TIntermBinary *binary = node->getAsBinaryNode(); | |||
136 | if (binary == nullptr) | |||
137 | { | |||
138 | return node; | |||
139 | } | |||
140 | ||||
141 | TOperator op = binary->getOp(); | |||
142 | if (op != EOpIndexDirect && op != EOpIndexIndirect) | |||
143 | { | |||
144 | return static_cast<TIntermTyped *>(nullptr); | |||
145 | } | |||
146 | ||||
147 | node = binary->getLeft(); | |||
148 | } while (true); | |||
149 | } | |||
150 | ||||
151 | void AddAdvancedBlendEquation(gl::BlendEquationType eq, TLayoutQualifier *qualifier) | |||
152 | { | |||
153 | qualifier->advancedBlendEquations.set(static_cast<uint32_t>(eq)); | |||
154 | } | |||
155 | ||||
156 | constexpr bool IsValidWithPixelLocalStorage(TLayoutImageInternalFormat internalFormat) | |||
157 | { | |||
158 | switch (internalFormat) | |||
159 | { | |||
160 | case EiifRGBA8: | |||
161 | case EiifRGBA8I: | |||
162 | case EiifRGBA8UI: | |||
163 | case EiifR32F: | |||
164 | case EiifR32UI: | |||
165 | return true; | |||
166 | default: | |||
167 | return false; | |||
168 | } | |||
169 | } | |||
170 | } // namespace | |||
171 | ||||
172 | // This tracks each binding point's current default offset for inheritance of subsequent | |||
173 | // variables using the same binding, and keeps offsets unique and non overlapping. | |||
174 | // See GLSL ES 3.1, section 4.4.6. | |||
175 | class TParseContext::AtomicCounterBindingState | |||
176 | { | |||
177 | public: | |||
178 | AtomicCounterBindingState() : mDefaultOffset(0) {} | |||
179 | // Inserts a new span and returns -1 if overlapping, else returns the starting offset of | |||
180 | // newly inserted span. | |||
181 | int insertSpan(int start, size_t length) | |||
182 | { | |||
183 | gl::RangeI newSpan(start, start + static_cast<int>(length)); | |||
184 | for (const auto &span : mSpans) | |||
185 | { | |||
186 | if (newSpan.intersects(span)) | |||
187 | { | |||
188 | return -1; | |||
189 | } | |||
190 | } | |||
191 | mSpans.push_back(newSpan); | |||
192 | mDefaultOffset = newSpan.high(); | |||
193 | return start; | |||
194 | } | |||
195 | // Inserts a new span starting from the default offset. | |||
196 | int appendSpan(size_t length) { return insertSpan(mDefaultOffset, length); } | |||
197 | void setDefaultOffset(int offset) { mDefaultOffset = offset; } | |||
198 | ||||
199 | private: | |||
200 | int mDefaultOffset; | |||
201 | std::vector<gl::RangeI> mSpans; | |||
202 | }; | |||
203 | ||||
204 | TParseContext::TParseContext(TSymbolTable &symt, | |||
205 | TExtensionBehavior &ext, | |||
206 | sh::GLenum type, | |||
207 | ShShaderSpec spec, | |||
208 | const ShCompileOptions &options, | |||
209 | bool checksPrecErrors, | |||
210 | TDiagnostics *diagnostics, | |||
211 | const ShBuiltInResources &resources, | |||
212 | ShShaderOutput outputType) | |||
213 | : symbolTable(symt), | |||
214 | mDeferredNonEmptyDeclarationErrorCheck(false), | |||
215 | mShaderType(type), | |||
216 | mShaderSpec(spec), | |||
217 | mCompileOptions(options), | |||
218 | mShaderVersion(100), | |||
219 | mTreeRoot(nullptr), | |||
220 | mLoopNestingLevel(0), | |||
221 | mStructNestingLevel(0), | |||
222 | mSwitchNestingLevel(0), | |||
223 | mCurrentFunctionType(nullptr), | |||
224 | mFunctionReturnsValue(false), | |||
225 | mChecksPrecisionErrors(checksPrecErrors), | |||
226 | mFragmentPrecisionHighOnESSL1(false), | |||
227 | mEarlyFragmentTestsSpecified(false), | |||
228 | mHasDiscard(false), | |||
229 | mSampleQualifierSpecified(false), | |||
230 | mDefaultUniformMatrixPacking(EmpColumnMajor), | |||
231 | mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), | |||
232 | mDefaultBufferMatrixPacking(EmpColumnMajor), | |||
233 | mDefaultBufferBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), | |||
234 | mDiagnostics(diagnostics), | |||
235 | mDirectiveHandler(ext, *mDiagnostics, mShaderVersion, mShaderType), | |||
236 | mPreprocessor(mDiagnostics, &mDirectiveHandler, angle::pp::PreprocessorSettings(spec)), | |||
237 | mScanner(nullptr), | |||
238 | mMinProgramTexelOffset(resources.MinProgramTexelOffset), | |||
239 | mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), | |||
240 | mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset), | |||
241 | mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset), | |||
242 | mComputeShaderLocalSizeDeclared(false), | |||
243 | mComputeShaderLocalSize(-1), | |||
244 | mNumViews(-1), | |||
245 | mMaxNumViews(resources.MaxViewsOVR), | |||
246 | mMaxImageUnits(resources.MaxImageUnits), | |||
247 | mMaxCombinedTextureImageUnits(resources.MaxCombinedTextureImageUnits), | |||
248 | mMaxUniformLocations(resources.MaxUniformLocations), | |||
249 | mMaxUniformBufferBindings(resources.MaxUniformBufferBindings), | |||
250 | mMaxVertexAttribs(resources.MaxVertexAttribs), | |||
251 | mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings), | |||
252 | mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings), | |||
253 | mDeclaringFunction(false), | |||
254 | mGeometryShaderInputPrimitiveType(EptUndefined), | |||
255 | mGeometryShaderOutputPrimitiveType(EptUndefined), | |||
256 | mGeometryShaderInvocations(0), | |||
257 | mGeometryShaderMaxVertices(-1), | |||
258 | mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations), | |||
259 | mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices), | |||
260 | mGeometryInputArraySize(0), | |||
261 | mMaxPatchVertices(resources.MaxPatchVertices), | |||
262 | mTessControlShaderOutputVertices(0), | |||
263 | mTessEvaluationShaderInputPrimitiveType(EtetUndefined), | |||
264 | mTessEvaluationShaderInputVertexSpacingType(EtetUndefined), | |||
265 | mTessEvaluationShaderInputOrderingType(EtetUndefined), | |||
266 | mTessEvaluationShaderInputPointType(EtetUndefined), | |||
267 | mHasAnyPreciseType(false), | |||
268 | mAdvancedBlendEquations(0), | |||
269 | mFunctionBodyNewScope(false), | |||
270 | mOutputType(outputType) | |||
271 | {} | |||
272 | ||||
273 | TParseContext::~TParseContext() {} | |||
274 | ||||
275 | bool TParseContext::anyMultiviewExtensionAvailable() | |||
276 | { | |||
277 | return isExtensionEnabled(TExtension::OVR_multiview) || | |||
278 | isExtensionEnabled(TExtension::OVR_multiview2); | |||
279 | } | |||
280 | ||||
281 | bool TParseContext::parseVectorFields(const TSourceLoc &line, | |||
282 | const ImmutableString &compString, | |||
283 | int vecSize, | |||
284 | TVector<int> *fieldOffsets) | |||
285 | { | |||
286 | ASSERT(fieldOffsets)(fieldOffsets ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 286, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 286 << "): " << "fieldOffsets" )); | |||
287 | size_t fieldCount = compString.length(); | |||
288 | if (fieldCount > 4u) | |||
289 | { | |||
290 | error(line, "illegal vector field selection", compString); | |||
291 | return false; | |||
292 | } | |||
293 | fieldOffsets->resize(fieldCount); | |||
294 | ||||
295 | enum | |||
296 | { | |||
297 | exyzw, | |||
298 | ergba, | |||
299 | estpq | |||
300 | } fieldSet[4]; | |||
301 | ||||
302 | for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) | |||
303 | { | |||
304 | switch (compString[i]) | |||
305 | { | |||
306 | case 'x': | |||
307 | (*fieldOffsets)[i] = 0; | |||
308 | fieldSet[i] = exyzw; | |||
309 | break; | |||
310 | case 'r': | |||
311 | (*fieldOffsets)[i] = 0; | |||
312 | fieldSet[i] = ergba; | |||
313 | break; | |||
314 | case 's': | |||
315 | (*fieldOffsets)[i] = 0; | |||
316 | fieldSet[i] = estpq; | |||
317 | break; | |||
318 | case 'y': | |||
319 | (*fieldOffsets)[i] = 1; | |||
320 | fieldSet[i] = exyzw; | |||
321 | break; | |||
322 | case 'g': | |||
323 | (*fieldOffsets)[i] = 1; | |||
324 | fieldSet[i] = ergba; | |||
325 | break; | |||
326 | case 't': | |||
327 | (*fieldOffsets)[i] = 1; | |||
328 | fieldSet[i] = estpq; | |||
329 | break; | |||
330 | case 'z': | |||
331 | (*fieldOffsets)[i] = 2; | |||
332 | fieldSet[i] = exyzw; | |||
333 | break; | |||
334 | case 'b': | |||
335 | (*fieldOffsets)[i] = 2; | |||
336 | fieldSet[i] = ergba; | |||
337 | break; | |||
338 | case 'p': | |||
339 | (*fieldOffsets)[i] = 2; | |||
340 | fieldSet[i] = estpq; | |||
341 | break; | |||
342 | ||||
343 | case 'w': | |||
344 | (*fieldOffsets)[i] = 3; | |||
345 | fieldSet[i] = exyzw; | |||
346 | break; | |||
347 | case 'a': | |||
348 | (*fieldOffsets)[i] = 3; | |||
349 | fieldSet[i] = ergba; | |||
350 | break; | |||
351 | case 'q': | |||
352 | (*fieldOffsets)[i] = 3; | |||
353 | fieldSet[i] = estpq; | |||
354 | break; | |||
355 | default: | |||
356 | error(line, "illegal vector field selection", compString); | |||
357 | return false; | |||
358 | } | |||
359 | } | |||
360 | ||||
361 | for (unsigned int i = 0u; i < fieldOffsets->size(); ++i) | |||
362 | { | |||
363 | if ((*fieldOffsets)[i] >= vecSize) | |||
364 | { | |||
365 | error(line, "vector field selection out of range", compString); | |||
366 | return false; | |||
367 | } | |||
368 | ||||
369 | if (i > 0) | |||
370 | { | |||
371 | if (fieldSet[i] != fieldSet[i - 1]) | |||
372 | { | |||
373 | error(line, "illegal - vector component fields not from the same set", compString); | |||
374 | return false; | |||
375 | } | |||
376 | } | |||
377 | } | |||
378 | ||||
379 | return true; | |||
380 | } | |||
381 | ||||
382 | /////////////////////////////////////////////////////////////////////// | |||
383 | // | |||
384 | // Errors | |||
385 | // | |||
386 | //////////////////////////////////////////////////////////////////////// | |||
387 | ||||
388 | // | |||
389 | // Used by flex/bison to output all syntax and parsing errors. | |||
390 | // | |||
391 | void TParseContext::error(const TSourceLoc &loc, const char *reason, const char *token) | |||
392 | { | |||
393 | mDiagnostics->error(loc, reason, token); | |||
394 | } | |||
395 | ||||
396 | void TParseContext::error(const TSourceLoc &loc, const char *reason, const ImmutableString &token) | |||
397 | { | |||
398 | mDiagnostics->error(loc, reason, token.data()); | |||
399 | } | |||
400 | ||||
401 | void TParseContext::warning(const TSourceLoc &loc, const char *reason, const char *token) | |||
402 | { | |||
403 | mDiagnostics->warning(loc, reason, token); | |||
404 | } | |||
405 | ||||
406 | void TParseContext::errorIfPLSDeclared(const TSourceLoc &loc, PLSIllegalOperations op) | |||
407 | { | |||
408 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
409 | { | |||
410 | return; | |||
411 | } | |||
412 | if (mPLSBindings.empty()) | |||
413 | { | |||
414 | // No pixel local storage uniforms have been declared yet. Remember this potential error in | |||
415 | // case PLS gets declared later. | |||
416 | mPLSPotentialErrors.emplace_back(loc, op); | |||
417 | return; | |||
418 | } | |||
419 | switch (op) | |||
420 | { | |||
421 | case PLSIllegalOperations::Discard: | |||
422 | error(loc, "illegal discard when pixel local storage is declared", "discard"); | |||
423 | break; | |||
424 | case PLSIllegalOperations::ReturnFromMain: | |||
425 | error(loc, "illegal return from main when pixel local storage is declared", "return"); | |||
426 | break; | |||
427 | case PLSIllegalOperations::AssignFragDepth: | |||
428 | error(loc, "value not assignable when pixel local storage is declared", "gl_FragDepth"); | |||
429 | break; | |||
430 | case PLSIllegalOperations::AssignSampleMask: | |||
431 | error(loc, "value not assignable when pixel local storage is declared", | |||
432 | "gl_SampleMask"); | |||
433 | break; | |||
434 | } | |||
435 | } | |||
436 | ||||
437 | void TParseContext::outOfRangeError(bool isError, | |||
438 | const TSourceLoc &loc, | |||
439 | const char *reason, | |||
440 | const char *token) | |||
441 | { | |||
442 | if (isError) | |||
443 | { | |||
444 | error(loc, reason, token); | |||
445 | } | |||
446 | else | |||
447 | { | |||
448 | warning(loc, reason, token); | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | void TParseContext::setTreeRoot(TIntermBlock *treeRoot) | |||
453 | { | |||
454 | mTreeRoot = treeRoot; | |||
455 | mTreeRoot->setIsTreeRoot(); | |||
456 | } | |||
457 | ||||
458 | // | |||
459 | // Same error message for all places assignments don't work. | |||
460 | // | |||
461 | void TParseContext::assignError(const TSourceLoc &line, | |||
462 | const char *op, | |||
463 | const TType &left, | |||
464 | const TType &right) | |||
465 | { | |||
466 | TInfoSinkBase reasonStream; | |||
467 | reasonStream << "cannot convert from '" << right << "' to '" << left << "'"; | |||
468 | error(line, reasonStream.c_str(), op); | |||
469 | } | |||
470 | ||||
471 | // | |||
472 | // Same error message for all places unary operations don't work. | |||
473 | // | |||
474 | void TParseContext::unaryOpError(const TSourceLoc &line, const char *op, const TType &operand) | |||
475 | { | |||
476 | TInfoSinkBase reasonStream; | |||
477 | reasonStream << "wrong operand type - no operation '" << op | |||
478 | << "' exists that takes an operand of type " << operand | |||
479 | << " (or there is no acceptable conversion)"; | |||
480 | error(line, reasonStream.c_str(), op); | |||
481 | } | |||
482 | ||||
483 | // | |||
484 | // Same error message for all binary operations don't work. | |||
485 | // | |||
486 | void TParseContext::binaryOpError(const TSourceLoc &line, | |||
487 | const char *op, | |||
488 | const TType &left, | |||
489 | const TType &right) | |||
490 | { | |||
491 | TInfoSinkBase reasonStream; | |||
492 | reasonStream << "wrong operand types - no operation '" << op | |||
493 | << "' exists that takes a left-hand operand of type '" << left | |||
494 | << "' and a right operand of type '" << right | |||
495 | << "' (or there is no acceptable conversion)"; | |||
496 | error(line, reasonStream.c_str(), op); | |||
497 | } | |||
498 | ||||
499 | void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, | |||
500 | TPrecision precision, | |||
501 | TBasicType type) | |||
502 | { | |||
503 | if (!mChecksPrecisionErrors) | |||
504 | return; | |||
505 | ||||
506 | if (precision != EbpUndefined && !SupportsPrecision(type)) | |||
507 | { | |||
508 | error(line, "illegal type for precision qualifier", getBasicString(type)); | |||
509 | } | |||
510 | ||||
511 | if (precision == EbpUndefined) | |||
512 | { | |||
513 | switch (type) | |||
514 | { | |||
515 | case EbtFloat: | |||
516 | error(line, "No precision specified for (float)", ""); | |||
517 | return; | |||
518 | case EbtInt: | |||
519 | case EbtUInt: | |||
520 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 520, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 520 << ")"; } while (0); // there's always a predeclared qualifier | |||
521 | error(line, "No precision specified (int)", ""); | |||
522 | return; | |||
523 | default: | |||
524 | if (IsOpaqueType(type)) | |||
525 | { | |||
526 | error(line, "No precision specified", getBasicString(type)); | |||
527 | return; | |||
528 | } | |||
529 | } | |||
530 | } | |||
531 | } | |||
532 | ||||
533 | void TParseContext::markStaticReadIfSymbol(TIntermNode *node) | |||
534 | { | |||
535 | TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); | |||
536 | if (swizzleNode) | |||
537 | { | |||
538 | markStaticReadIfSymbol(swizzleNode->getOperand()); | |||
539 | return; | |||
540 | } | |||
541 | TIntermBinary *binaryNode = node->getAsBinaryNode(); | |||
542 | if (binaryNode) | |||
543 | { | |||
544 | switch (binaryNode->getOp()) | |||
545 | { | |||
546 | case EOpIndexDirect: | |||
547 | case EOpIndexIndirect: | |||
548 | case EOpIndexDirectStruct: | |||
549 | case EOpIndexDirectInterfaceBlock: | |||
550 | markStaticReadIfSymbol(binaryNode->getLeft()); | |||
551 | return; | |||
552 | default: | |||
553 | return; | |||
554 | } | |||
555 | } | |||
556 | TIntermSymbol *symbolNode = node->getAsSymbolNode(); | |||
557 | if (symbolNode) | |||
558 | { | |||
559 | symbolTable.markStaticRead(symbolNode->variable()); | |||
560 | } | |||
561 | } | |||
562 | ||||
563 | // Both test and if necessary, spit out an error, to see if the node is really | |||
564 | // an l-value that can be operated on this way. | |||
565 | bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node) | |||
566 | { | |||
567 | TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); | |||
568 | if (swizzleNode) | |||
569 | { | |||
570 | bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand()); | |||
571 | if (ok && swizzleNode->hasDuplicateOffsets()) | |||
572 | { | |||
573 | error(line, " l-value of swizzle cannot have duplicate components", op); | |||
574 | return false; | |||
575 | } | |||
576 | return ok; | |||
577 | } | |||
578 | ||||
579 | TIntermBinary *binaryNode = node->getAsBinaryNode(); | |||
580 | if (binaryNode) | |||
581 | { | |||
582 | switch (binaryNode->getOp()) | |||
583 | { | |||
584 | case EOpIndexDirect: | |||
585 | case EOpIndexIndirect: | |||
586 | case EOpIndexDirectStruct: | |||
587 | case EOpIndexDirectInterfaceBlock: | |||
588 | if (node->getMemoryQualifier().readonly) | |||
589 | { | |||
590 | error(line, "can't modify a readonly variable", op); | |||
591 | return false; | |||
592 | } | |||
593 | return checkCanBeLValue(line, op, binaryNode->getLeft()); | |||
594 | default: | |||
595 | break; | |||
596 | } | |||
597 | error(line, " l-value required", op); | |||
598 | return false; | |||
599 | } | |||
600 | ||||
601 | std::string message; | |||
602 | switch (node->getQualifier()) | |||
603 | { | |||
604 | case EvqConst: | |||
605 | message = "can't modify a const"; | |||
606 | break; | |||
607 | case EvqParamConst: | |||
608 | message = "can't modify a const"; | |||
609 | break; | |||
610 | case EvqAttribute: | |||
611 | message = "can't modify an attribute"; | |||
612 | break; | |||
613 | case EvqFragmentIn: | |||
614 | case EvqVertexIn: | |||
615 | case EvqGeometryIn: | |||
616 | case EvqTessControlIn: | |||
617 | case EvqTessEvaluationIn: | |||
618 | case EvqFlatIn: | |||
619 | case EvqNoPerspectiveIn: | |||
620 | case EvqSmoothIn: | |||
621 | case EvqCentroidIn: | |||
622 | case EvqSampleIn: | |||
623 | message = "can't modify an input"; | |||
624 | break; | |||
625 | case EvqUniform: | |||
626 | message = "can't modify a uniform"; | |||
627 | break; | |||
628 | case EvqVaryingIn: | |||
629 | message = "can't modify a varying"; | |||
630 | break; | |||
631 | case EvqFragCoord: | |||
632 | message = "can't modify gl_FragCoord"; | |||
633 | break; | |||
634 | case EvqFrontFacing: | |||
635 | message = "can't modify gl_FrontFacing"; | |||
636 | break; | |||
637 | case EvqHelperInvocation: | |||
638 | message = "can't modify gl_HelperInvocation"; | |||
639 | break; | |||
640 | case EvqPointCoord: | |||
641 | message = "can't modify gl_PointCoord"; | |||
642 | break; | |||
643 | case EvqNumWorkGroups: | |||
644 | message = "can't modify gl_NumWorkGroups"; | |||
645 | break; | |||
646 | case EvqWorkGroupSize: | |||
647 | message = "can't modify gl_WorkGroupSize"; | |||
648 | break; | |||
649 | case EvqWorkGroupID: | |||
650 | message = "can't modify gl_WorkGroupID"; | |||
651 | break; | |||
652 | case EvqLocalInvocationID: | |||
653 | message = "can't modify gl_LocalInvocationID"; | |||
654 | break; | |||
655 | case EvqGlobalInvocationID: | |||
656 | message = "can't modify gl_GlobalInvocationID"; | |||
657 | break; | |||
658 | case EvqLocalInvocationIndex: | |||
659 | message = "can't modify gl_LocalInvocationIndex"; | |||
660 | break; | |||
661 | case EvqViewIDOVR: | |||
662 | message = "can't modify gl_ViewID_OVR"; | |||
663 | break; | |||
664 | case EvqComputeIn: | |||
665 | message = "can't modify work group size variable"; | |||
666 | break; | |||
667 | case EvqPerVertexIn: | |||
668 | message = "can't modify any member in gl_in"; | |||
669 | break; | |||
670 | case EvqPrimitiveIDIn: | |||
671 | message = "can't modify gl_PrimitiveIDIn"; | |||
672 | break; | |||
673 | case EvqInvocationID: | |||
674 | message = "can't modify gl_InvocationID"; | |||
675 | break; | |||
676 | case EvqPrimitiveID: | |||
677 | if (mShaderType == GL_FRAGMENT_SHADER0x8B30) | |||
678 | { | |||
679 | message = "can't modify gl_PrimitiveID in a fragment shader"; | |||
680 | } | |||
681 | break; | |||
682 | case EvqLayerIn: | |||
683 | message = "can't modify gl_Layer in a fragment shader"; | |||
684 | break; | |||
685 | case EvqSampleID: | |||
686 | message = "can't modify gl_SampleID"; | |||
687 | break; | |||
688 | case EvqSampleMaskIn: | |||
689 | message = "can't modify gl_SampleMaskIn"; | |||
690 | break; | |||
691 | case EvqSamplePosition: | |||
692 | message = "can't modify gl_SamplePosition"; | |||
693 | break; | |||
694 | case EvqClipDistance: | |||
695 | if (mShaderType == GL_FRAGMENT_SHADER0x8B30) | |||
696 | { | |||
697 | message = "can't modify gl_ClipDistance in a fragment shader"; | |||
698 | } | |||
699 | break; | |||
700 | case EvqCullDistance: | |||
701 | if (mShaderType == GL_FRAGMENT_SHADER0x8B30) | |||
702 | { | |||
703 | message = "can't modify gl_CullDistance in a fragment shader"; | |||
704 | } | |||
705 | break; | |||
706 | case EvqFragDepth: | |||
707 | errorIfPLSDeclared(line, PLSIllegalOperations::AssignFragDepth); | |||
708 | break; | |||
709 | case EvqSampleMask: | |||
710 | errorIfPLSDeclared(line, PLSIllegalOperations::AssignSampleMask); | |||
711 | break; | |||
712 | default: | |||
713 | // | |||
714 | // Type that can't be written to? | |||
715 | // | |||
716 | if (node->getBasicType() == EbtVoid) | |||
717 | { | |||
718 | message = "can't modify void"; | |||
719 | } | |||
720 | if (IsOpaqueType(node->getBasicType())) | |||
721 | { | |||
722 | message = "can't modify a variable with type "; | |||
723 | message += getBasicString(node->getBasicType()); | |||
724 | } | |||
725 | else if (node->getMemoryQualifier().readonly) | |||
726 | { | |||
727 | message = "can't modify a readonly variable"; | |||
728 | } | |||
729 | } | |||
730 | ||||
731 | ASSERT(binaryNode == nullptr && swizzleNode == nullptr)(binaryNode == nullptr && swizzleNode == nullptr ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 731, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 731 << "): " << "binaryNode == nullptr && swizzleNode == nullptr" )); | |||
732 | TIntermSymbol *symNode = node->getAsSymbolNode(); | |||
733 | if (message.empty() && symNode != nullptr) | |||
734 | { | |||
735 | symbolTable.markStaticWrite(symNode->variable()); | |||
736 | return true; | |||
737 | } | |||
738 | ||||
739 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
740 | reasonStream << "l-value required"; | |||
741 | if (!message.empty()) | |||
742 | { | |||
743 | if (symNode) | |||
744 | { | |||
745 | // Symbol inside an expression can't be nameless. | |||
746 | ASSERT(symNode->variable().symbolType() != SymbolType::Empty)(symNode->variable().symbolType() != SymbolType::Empty ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 746, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 746 << "): " << "symNode->variable().symbolType() != SymbolType::Empty" )); | |||
747 | const ImmutableString &symbol = symNode->getName(); | |||
748 | reasonStream << " (" << message << " \"" << symbol << "\")"; | |||
749 | } | |||
750 | else | |||
751 | { | |||
752 | reasonStream << " (" << message << ")"; | |||
753 | } | |||
754 | } | |||
755 | std::string reason = reasonStream.str(); | |||
756 | error(line, reason.c_str(), op); | |||
757 | ||||
758 | return false; | |||
759 | } | |||
760 | ||||
761 | // Both test, and if necessary spit out an error, to see if the node is really | |||
762 | // a constant. | |||
763 | void TParseContext::checkIsConst(TIntermTyped *node) | |||
764 | { | |||
765 | if (node->getQualifier() != EvqConst) | |||
766 | { | |||
767 | error(node->getLine(), "constant expression required", ""); | |||
768 | } | |||
769 | } | |||
770 | ||||
771 | // Both test, and if necessary spit out an error, to see if the node is really | |||
772 | // an integer. | |||
773 | void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token) | |||
774 | { | |||
775 | if (!node->isScalarInt()) | |||
776 | { | |||
777 | error(node->getLine(), "integer expression required", token); | |||
778 | } | |||
779 | } | |||
780 | ||||
781 | // Both test, and if necessary spit out an error, to see if we are currently | |||
782 | // globally scoped. | |||
783 | bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token) | |||
784 | { | |||
785 | if (!symbolTable.atGlobalLevel()) | |||
786 | { | |||
787 | error(line, "only allowed at global scope", token); | |||
788 | return false; | |||
789 | } | |||
790 | return true; | |||
791 | } | |||
792 | ||||
793 | // ESSL 3.00.5 sections 3.8 and 3.9. | |||
794 | // If it starts "gl_" or contains two consecutive underscores, it's reserved. | |||
795 | // Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a webgl shader. | |||
796 | bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const ImmutableString &identifier) | |||
797 | { | |||
798 | static const char *reservedErrMsg = "reserved built-in name"; | |||
799 | if (gl::IsBuiltInName(identifier.data())) | |||
800 | { | |||
801 | error(line, reservedErrMsg, "gl_"); | |||
802 | return false; | |||
803 | } | |||
804 | if (sh::IsWebGLBasedSpec(mShaderSpec)) | |||
805 | { | |||
806 | if (identifier.beginsWith("webgl_")) | |||
807 | { | |||
808 | error(line, reservedErrMsg, "webgl_"); | |||
809 | return false; | |||
810 | } | |||
811 | if (identifier.beginsWith("_webgl_")) | |||
812 | { | |||
813 | error(line, reservedErrMsg, "_webgl_"); | |||
814 | return false; | |||
815 | } | |||
816 | } | |||
817 | if (identifier.contains("__")) | |||
818 | { | |||
819 | if (sh::IsWebGLBasedSpec(mShaderSpec)) | |||
820 | { | |||
821 | error(line, | |||
822 | "identifiers containing two consecutive underscores (__) are reserved as " | |||
823 | "possible future keywords", | |||
824 | identifier); | |||
825 | return false; | |||
826 | } | |||
827 | else | |||
828 | { | |||
829 | // Using double underscores is allowed, but may result in unintended behaviors, so a | |||
830 | // warning is issued. | |||
831 | // OpenGL ES Shader Language 3.2 specification: | |||
832 | // > 3.7. Keywords | |||
833 | // > ... | |||
834 | // > In addition, all identifiers containing two consecutive underscores (__) are | |||
835 | // > reserved for use by underlying software layers. Defining such a name in a shader | |||
836 | // > does not itself result in an error, but may result in unintended behaviors that | |||
837 | // > stem from having multiple definitions of the same name. | |||
838 | warning(line, | |||
839 | "all identifiers containing two consecutive underscores (__) are reserved - " | |||
840 | "unintented behaviors are possible", | |||
841 | identifier.data()); | |||
842 | } | |||
843 | } | |||
844 | return true; | |||
845 | } | |||
846 | ||||
847 | // Make sure the argument types are correct for constructing a specific type. | |||
848 | bool TParseContext::checkConstructorArguments(const TSourceLoc &line, | |||
849 | const TIntermSequence &arguments, | |||
850 | const TType &type) | |||
851 | { | |||
852 | if (arguments.empty()) | |||
853 | { | |||
854 | error(line, "constructor does not have any arguments", "constructor"); | |||
855 | return false; | |||
856 | } | |||
857 | ||||
858 | for (TIntermNode *arg : arguments) | |||
859 | { | |||
860 | markStaticReadIfSymbol(arg); | |||
861 | const TIntermTyped *argTyped = arg->getAsTyped(); | |||
862 | ASSERT(argTyped != nullptr)(argTyped != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 862, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 862 << "): " << "argTyped != nullptr" )); | |||
863 | if (type.getBasicType() != EbtStruct && IsOpaqueType(argTyped->getBasicType())) | |||
864 | { | |||
865 | std::string reason("cannot convert a variable with type "); | |||
866 | reason += getBasicString(argTyped->getBasicType()); | |||
867 | error(line, reason.c_str(), "constructor"); | |||
868 | return false; | |||
869 | } | |||
870 | else if (argTyped->getMemoryQualifier().writeonly) | |||
871 | { | |||
872 | error(line, "cannot convert a variable with writeonly", "constructor"); | |||
873 | return false; | |||
874 | } | |||
875 | if (argTyped->getBasicType() == EbtVoid) | |||
876 | { | |||
877 | error(line, "cannot convert a void", "constructor"); | |||
878 | return false; | |||
879 | } | |||
880 | } | |||
881 | ||||
882 | if (type.isArray()) | |||
883 | { | |||
884 | // The size of an unsized constructor should already have been determined. | |||
885 | ASSERT(!type.isUnsizedArray())(!type.isUnsizedArray() ? static_cast<void>(0) : (!((:: gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 885, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 885 << "): " << "!type.isUnsizedArray()" )); | |||
886 | if (static_cast<size_t>(type.getOutermostArraySize()) != arguments.size()) | |||
887 | { | |||
888 | error(line, "array constructor needs one argument per array element", "constructor"); | |||
889 | return false; | |||
890 | } | |||
891 | // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of | |||
892 | // the array. | |||
893 | for (TIntermNode *const &argNode : arguments) | |||
894 | { | |||
895 | const TType &argType = argNode->getAsTyped()->getType(); | |||
896 | if (mShaderVersion < 310 && argType.isArray()) | |||
897 | { | |||
898 | error(line, "constructing from a non-dereferenced array", "constructor"); | |||
899 | return false; | |||
900 | } | |||
901 | if (!argType.isElementTypeOf(type)) | |||
902 | { | |||
903 | error(line, "Array constructor argument has an incorrect type", "constructor"); | |||
904 | return false; | |||
905 | } | |||
906 | } | |||
907 | } | |||
908 | else if (type.getBasicType() == EbtStruct) | |||
909 | { | |||
910 | const TFieldList &fields = type.getStruct()->fields(); | |||
911 | if (fields.size() != arguments.size()) | |||
912 | { | |||
913 | error(line, | |||
914 | "Number of constructor parameters does not match the number of structure fields", | |||
915 | "constructor"); | |||
916 | return false; | |||
917 | } | |||
918 | ||||
919 | for (size_t i = 0; i < fields.size(); i++) | |||
920 | { | |||
921 | if (i >= arguments.size() || | |||
922 | arguments[i]->getAsTyped()->getType() != *fields[i]->type()) | |||
923 | { | |||
924 | error(line, "Structure constructor arguments do not match structure fields", | |||
925 | "constructor"); | |||
926 | return false; | |||
927 | } | |||
928 | } | |||
929 | } | |||
930 | else | |||
931 | { | |||
932 | // We're constructing a scalar, vector, or matrix. | |||
933 | ||||
934 | // Note: It's okay to have too many components available, but not okay to have unused | |||
935 | // arguments. 'full' will go to true when enough args have been seen. If we loop again, | |||
936 | // there is an extra argument, so 'overFull' will become true. | |||
937 | ||||
938 | size_t size = 0; | |||
939 | bool full = false; | |||
940 | bool overFull = false; | |||
941 | bool matrixArg = false; | |||
942 | for (TIntermNode *arg : arguments) | |||
943 | { | |||
944 | const TIntermTyped *argTyped = arg->getAsTyped(); | |||
945 | ASSERT(argTyped != nullptr)(argTyped != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 945, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 945 << "): " << "argTyped != nullptr" )); | |||
946 | ||||
947 | if (argTyped->getBasicType() == EbtStruct) | |||
948 | { | |||
949 | error(line, "a struct cannot be used as a constructor argument for this type", | |||
950 | "constructor"); | |||
951 | return false; | |||
952 | } | |||
953 | if (argTyped->getType().isArray()) | |||
954 | { | |||
955 | error(line, "constructing from a non-dereferenced array", "constructor"); | |||
956 | return false; | |||
957 | } | |||
958 | if (argTyped->getType().isMatrix()) | |||
959 | { | |||
960 | matrixArg = true; | |||
961 | } | |||
962 | ||||
963 | size += argTyped->getType().getObjectSize(); | |||
964 | if (full) | |||
965 | { | |||
966 | overFull = true; | |||
967 | } | |||
968 | if (size >= type.getObjectSize()) | |||
969 | { | |||
970 | full = true; | |||
971 | } | |||
972 | } | |||
973 | ||||
974 | if (type.isMatrix() && matrixArg) | |||
975 | { | |||
976 | if (arguments.size() != 1) | |||
977 | { | |||
978 | error(line, "constructing matrix from matrix can only take one argument", | |||
979 | "constructor"); | |||
980 | return false; | |||
981 | } | |||
982 | } | |||
983 | else | |||
984 | { | |||
985 | if (size != 1 && size < type.getObjectSize()) | |||
986 | { | |||
987 | error(line, "not enough data provided for construction", "constructor"); | |||
988 | return false; | |||
989 | } | |||
990 | if (overFull) | |||
991 | { | |||
992 | error(line, "too many arguments", "constructor"); | |||
993 | return false; | |||
994 | } | |||
995 | } | |||
996 | } | |||
997 | ||||
998 | return true; | |||
999 | } | |||
1000 | ||||
1001 | // This function checks to see if a void variable has been declared and raise an error message for | |||
1002 | // such a case | |||
1003 | // | |||
1004 | // returns true in case of an error | |||
1005 | // | |||
1006 | bool TParseContext::checkIsNonVoid(const TSourceLoc &line, | |||
1007 | const ImmutableString &identifier, | |||
1008 | const TBasicType &type) | |||
1009 | { | |||
1010 | if (type == EbtVoid) | |||
1011 | { | |||
1012 | error(line, "illegal use of type 'void'", identifier); | |||
1013 | return false; | |||
1014 | } | |||
1015 | ||||
1016 | return true; | |||
1017 | } | |||
1018 | ||||
1019 | // This function checks to see if the node (for the expression) contains a scalar boolean expression | |||
1020 | // or not. | |||
1021 | bool TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type) | |||
1022 | { | |||
1023 | if (type->getBasicType() != EbtBool || !type->isScalar()) | |||
1024 | { | |||
1025 | error(line, "boolean expression expected", ""); | |||
1026 | return false; | |||
1027 | } | |||
1028 | return true; | |||
1029 | } | |||
1030 | ||||
1031 | // This function checks to see if the node (for the expression) contains a scalar boolean expression | |||
1032 | // or not. | |||
1033 | void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType) | |||
1034 | { | |||
1035 | if (pType.getBasicType() != EbtBool || pType.isAggregate()) | |||
1036 | { | |||
1037 | error(line, "boolean expression expected", ""); | |||
1038 | } | |||
1039 | } | |||
1040 | ||||
1041 | bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line, | |||
1042 | const TTypeSpecifierNonArray &pType, | |||
1043 | const char *reason) | |||
1044 | { | |||
1045 | if (pType.type == EbtStruct) | |||
1046 | { | |||
1047 | if (ContainsSampler(pType.userDef)) | |||
1048 | { | |||
1049 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
1050 | reasonStream << reason << " (structure contains a sampler)"; | |||
1051 | std::string reasonStr = reasonStream.str(); | |||
1052 | error(line, reasonStr.c_str(), getBasicString(pType.type)); | |||
1053 | return false; | |||
1054 | } | |||
1055 | // only samplers need to be checked from structs, since other opaque types can't be struct | |||
1056 | // members. | |||
1057 | return true; | |||
1058 | } | |||
1059 | else if (IsOpaqueType(pType.type)) | |||
1060 | { | |||
1061 | error(line, reason, getBasicString(pType.type)); | |||
1062 | return false; | |||
1063 | } | |||
1064 | ||||
1065 | return true; | |||
1066 | } | |||
1067 | ||||
1068 | void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, | |||
1069 | const TPublicType &pType) | |||
1070 | { | |||
1071 | if (pType.layoutQualifier.location != -1) | |||
1072 | { | |||
1073 | error(line, "location must only be specified for a single input or output variable", | |||
1074 | "location"); | |||
1075 | } | |||
1076 | } | |||
1077 | ||||
1078 | void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location, | |||
1079 | const TLayoutQualifier &layoutQualifier) | |||
1080 | { | |||
1081 | if (layoutQualifier.location != -1) | |||
1082 | { | |||
1083 | const char *errorMsg = "invalid layout qualifier: only valid on program inputs and outputs"; | |||
1084 | if (mShaderVersion >= 310) | |||
1085 | { | |||
1086 | errorMsg = | |||
1087 | "invalid layout qualifier: only valid on shader inputs, outputs, and uniforms"; | |||
1088 | } | |||
1089 | error(location, errorMsg, "location"); | |||
1090 | } | |||
1091 | } | |||
1092 | ||||
1093 | void TParseContext::checkStd430IsForShaderStorageBlock(const TSourceLoc &location, | |||
1094 | const TLayoutBlockStorage &blockStorage, | |||
1095 | const TQualifier &qualifier) | |||
1096 | { | |||
1097 | if (blockStorage == EbsStd430 && qualifier != EvqBuffer) | |||
1098 | { | |||
1099 | error(location, "The std430 layout is supported only for shader storage blocks.", "std430"); | |||
1100 | } | |||
1101 | } | |||
1102 | ||||
1103 | void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line, | |||
1104 | TQualifier qualifier, | |||
1105 | const TType &type) | |||
1106 | { | |||
1107 | ASSERT(qualifier == EvqParamOut || qualifier == EvqParamInOut)(qualifier == EvqParamOut || qualifier == EvqParamInOut ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1107, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1107 << "): " << "qualifier == EvqParamOut || qualifier == EvqParamInOut" )); | |||
1108 | if (IsOpaqueType(type.getBasicType())) | |||
1109 | { | |||
1110 | error(line, "opaque types cannot be output parameters", type.getBasicString()); | |||
1111 | } | |||
1112 | } | |||
1113 | ||||
1114 | // Do size checking for an array type's size. | |||
1115 | unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr) | |||
1116 | { | |||
1117 | TIntermConstantUnion *constant = expr->getAsConstantUnion(); | |||
1118 | ||||
1119 | // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be | |||
1120 | // safe against corner cases we still check for constant folding. Some interpretations of the | |||
1121 | // spec have allowed constant expressions with side effects - like array length() method on a | |||
1122 | // non-constant array. | |||
1123 | if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt()) | |||
1124 | { | |||
1125 | error(line, "array size must be a constant integer expression", ""); | |||
1126 | return 1u; | |||
1127 | } | |||
1128 | ||||
1129 | unsigned int size = 0u; | |||
1130 | ||||
1131 | if (constant->getBasicType() == EbtUInt) | |||
1132 | { | |||
1133 | size = constant->getUConst(0); | |||
1134 | } | |||
1135 | else | |||
1136 | { | |||
1137 | int signedSize = constant->getIConst(0); | |||
1138 | ||||
1139 | if (signedSize < 0) | |||
1140 | { | |||
1141 | error(line, "array size must be non-negative", ""); | |||
1142 | return 1u; | |||
1143 | } | |||
1144 | ||||
1145 | size = static_cast<unsigned int>(signedSize); | |||
1146 | } | |||
1147 | ||||
1148 | if (size == 0u) | |||
1149 | { | |||
1150 | error(line, "array size must be greater than zero", ""); | |||
1151 | return 1u; | |||
1152 | } | |||
1153 | ||||
1154 | if (IsOutputHLSL(getOutputType())) | |||
1155 | { | |||
1156 | // The size of arrays is restricted here to prevent issues further down the | |||
1157 | // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to | |||
1158 | // 4096 registers so this should be reasonable even for aggressively optimizable code. | |||
1159 | const unsigned int sizeLimit = 65536; | |||
1160 | ||||
1161 | if (size > sizeLimit) | |||
1162 | { | |||
1163 | error(line, "array size too large", ""); | |||
1164 | return 1u; | |||
1165 | } | |||
1166 | } | |||
1167 | ||||
1168 | return size; | |||
1169 | } | |||
1170 | ||||
1171 | // See if this qualifier can be an array. | |||
1172 | bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line, | |||
1173 | const TPublicType &elementQualifier) | |||
1174 | { | |||
1175 | if ((elementQualifier.qualifier == EvqAttribute) || | |||
1176 | (elementQualifier.qualifier == EvqVertexIn) || | |||
1177 | (elementQualifier.qualifier == EvqConst && mShaderVersion < 300)) | |||
1178 | { | |||
1179 | error(line, "cannot declare arrays of this qualifier", | |||
1180 | TType(elementQualifier).getQualifierString()); | |||
1181 | return false; | |||
1182 | } | |||
1183 | ||||
1184 | return true; | |||
1185 | } | |||
1186 | ||||
1187 | // See if this element type can be formed into an array. | |||
1188 | bool TParseContext::checkArrayElementIsNotArray(const TSourceLoc &line, | |||
1189 | const TPublicType &elementType) | |||
1190 | { | |||
1191 | if (mShaderVersion < 310 && elementType.isArray()) | |||
1192 | { | |||
1193 | TInfoSinkBase typeString; | |||
1194 | typeString << TType(elementType); | |||
1195 | error(line, "cannot declare arrays of arrays", typeString.c_str()); | |||
1196 | return false; | |||
1197 | } | |||
1198 | return true; | |||
1199 | } | |||
1200 | ||||
1201 | // Check for array-of-arrays being used as non-allowed shader inputs/outputs. | |||
1202 | bool TParseContext::checkArrayOfArraysInOut(const TSourceLoc &line, | |||
1203 | const TPublicType &elementType, | |||
1204 | const TType &arrayType) | |||
1205 | { | |||
1206 | if (arrayType.isArrayOfArrays()) | |||
1207 | { | |||
1208 | if (elementType.qualifier == EvqVertexOut) | |||
1209 | { | |||
1210 | error(line, "vertex shader output cannot be an array of arrays", | |||
1211 | TType(elementType).getQualifierString()); | |||
1212 | return false; | |||
1213 | } | |||
1214 | if (elementType.qualifier == EvqFragmentIn) | |||
1215 | { | |||
1216 | error(line, "fragment shader input cannot be an array of arrays", | |||
1217 | TType(elementType).getQualifierString()); | |||
1218 | return false; | |||
1219 | } | |||
1220 | if (elementType.qualifier == EvqFragmentOut || elementType.qualifier == EvqFragmentInOut) | |||
1221 | { | |||
1222 | error(line, "fragment shader output cannot be an array of arrays", | |||
1223 | TType(elementType).getQualifierString()); | |||
1224 | return false; | |||
1225 | } | |||
1226 | } | |||
1227 | return true; | |||
1228 | } | |||
1229 | ||||
1230 | // Check if this qualified element type can be formed into an array. This is only called when array | |||
1231 | // brackets are associated with an identifier in a declaration, like this: | |||
1232 | // float a[2]; | |||
1233 | // Similar checks are done in addFullySpecifiedType for array declarations where the array brackets | |||
1234 | // are associated with the type, like this: | |||
1235 | // float[2] a; | |||
1236 | bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, | |||
1237 | const TPublicType &elementType) | |||
1238 | { | |||
1239 | if (!checkArrayElementIsNotArray(indexLocation, elementType)) | |||
1240 | { | |||
1241 | return false; | |||
1242 | } | |||
1243 | // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. | |||
1244 | // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section | |||
1245 | // 4.3.4). | |||
1246 | // Geometry shader requires each user-defined input be declared as arrays or inside input | |||
1247 | // blocks declared as arrays (GL_EXT_geometry_shader section 11.1gs.4.3). For the purposes of | |||
1248 | // interface matching, such variables and blocks are treated as though they were not declared | |||
1249 | // as arrays (GL_EXT_geometry_shader section 7.4.1). | |||
1250 | if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && | |||
1251 | sh::IsVarying(elementType.qualifier) && | |||
1252 | !IsGeometryShaderInput(mShaderType, elementType.qualifier) && | |||
1253 | !IsTessellationControlShaderInput(mShaderType, elementType.qualifier) && | |||
1254 | !IsTessellationEvaluationShaderInput(mShaderType, elementType.qualifier) && | |||
1255 | !IsTessellationControlShaderOutput(mShaderType, elementType.qualifier)) | |||
1256 | { | |||
1257 | TInfoSinkBase typeString; | |||
1258 | typeString << TType(elementType); | |||
1259 | error(indexLocation, "cannot declare arrays of structs of this qualifier", | |||
1260 | typeString.c_str()); | |||
1261 | return false; | |||
1262 | } | |||
1263 | return checkIsValidQualifierForArray(indexLocation, elementType); | |||
1264 | } | |||
1265 | ||||
1266 | // Enforce non-initializer type/qualifier rules. | |||
1267 | void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, | |||
1268 | const ImmutableString &identifier, | |||
1269 | TType *type) | |||
1270 | { | |||
1271 | ASSERT(type != nullptr)(type != nullptr ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1271, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1271 << "): " << "type != nullptr" )); | |||
1272 | if (type->getQualifier() == EvqConst) | |||
1273 | { | |||
1274 | // Make the qualifier make sense. | |||
1275 | type->setQualifier(EvqTemporary); | |||
1276 | ||||
1277 | // Generate informative error messages for ESSL1. | |||
1278 | // In ESSL3 arrays and structures containing arrays can be constant. | |||
1279 | if (mShaderVersion < 300 && type->isStructureContainingArrays()) | |||
1280 | { | |||
1281 | error(line, | |||
1282 | "structures containing arrays may not be declared constant since they cannot be " | |||
1283 | "initialized", | |||
1284 | identifier); | |||
1285 | } | |||
1286 | else | |||
1287 | { | |||
1288 | error(line, "variables with qualifier 'const' must be initialized", identifier); | |||
1289 | } | |||
1290 | } | |||
1291 | ||||
1292 | // Implicitly declared arrays are only allowed with tessellation or geometry shader inputs | |||
1293 | if (type->isArray() && | |||
1294 | ((mShaderType != GL_TESS_CONTROL_SHADER0x8E88 && mShaderType != GL_TESS_EVALUATION_SHADER0x8E87 && | |||
1295 | mShaderType != GL_GEOMETRY_SHADER0x8DD9) || | |||
1296 | (mShaderType == GL_GEOMETRY_SHADER0x8DD9 && type->getQualifier() == EvqGeometryOut))) | |||
1297 | { | |||
1298 | const TSpan<const unsigned int> &arraySizes = type->getArraySizes(); | |||
1299 | for (unsigned int size : arraySizes) | |||
1300 | { | |||
1301 | if (size == 0) | |||
1302 | { | |||
1303 | error(line, | |||
1304 | "implicitly sized arrays only allowed for tessellation shaders " | |||
1305 | "or geometry shader inputs", | |||
1306 | identifier); | |||
1307 | } | |||
1308 | } | |||
1309 | } | |||
1310 | } | |||
1311 | ||||
1312 | // Do some simple checks that are shared between all variable declarations, | |||
1313 | // and update the symbol table. | |||
1314 | // | |||
1315 | // Returns true if declaring the variable succeeded. | |||
1316 | // | |||
1317 | bool TParseContext::declareVariable(const TSourceLoc &line, | |||
1318 | const ImmutableString &identifier, | |||
1319 | const TType *type, | |||
1320 | TVariable **variable) | |||
1321 | { | |||
1322 | ASSERT((*variable) == nullptr)((*variable) == nullptr ? static_cast<void>(0) : (!((:: gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1322, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1322 << "): " << "(*variable) == nullptr" )); | |||
1323 | ||||
1324 | SymbolType symbolType = SymbolType::UserDefined; | |||
1325 | switch (type->getQualifier()) | |||
1326 | { | |||
1327 | case EvqClipDistance: | |||
1328 | case EvqCullDistance: | |||
1329 | case EvqLastFragData: | |||
1330 | symbolType = SymbolType::BuiltIn; | |||
1331 | break; | |||
1332 | default: | |||
1333 | break; | |||
1334 | } | |||
1335 | ||||
1336 | (*variable) = new TVariable(&symbolTable, identifier, type, symbolType); | |||
1337 | ||||
1338 | ASSERT(type->getLayoutQualifier().index == -1 ||(type->getLayoutQualifier().index == -1 || (isExtensionEnabled (TExtension::EXT_blend_func_extended) && mShaderType == 0x8B30 && mShaderVersion >= 300) ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1340, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1340 << "): " << "type->getLayoutQualifier().index == -1 || (isExtensionEnabled(TExtension::EXT_blend_func_extended) && mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300)" )) | |||
1339 | (isExtensionEnabled(TExtension::EXT_blend_func_extended) &&(type->getLayoutQualifier().index == -1 || (isExtensionEnabled (TExtension::EXT_blend_func_extended) && mShaderType == 0x8B30 && mShaderVersion >= 300) ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1340, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1340 << "): " << "type->getLayoutQualifier().index == -1 || (isExtensionEnabled(TExtension::EXT_blend_func_extended) && mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300)" )) | |||
1340 | mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300))(type->getLayoutQualifier().index == -1 || (isExtensionEnabled (TExtension::EXT_blend_func_extended) && mShaderType == 0x8B30 && mShaderVersion >= 300) ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1340, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1340 << "): " << "type->getLayoutQualifier().index == -1 || (isExtensionEnabled(TExtension::EXT_blend_func_extended) && mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300)" )); | |||
1341 | if (type->getQualifier() == EvqFragmentOut) | |||
1342 | { | |||
1343 | if (type->getLayoutQualifier().index != -1 && type->getLayoutQualifier().location == -1) | |||
1344 | { | |||
1345 | error(line, | |||
1346 | "If index layout qualifier is specified for a fragment output, location must " | |||
1347 | "also be specified.", | |||
1348 | "index"); | |||
1349 | return false; | |||
1350 | } | |||
1351 | } | |||
1352 | else | |||
1353 | { | |||
1354 | checkIndexIsNotSpecified(line, type->getLayoutQualifier().index); | |||
1355 | } | |||
1356 | ||||
1357 | if (!((identifier.beginsWith("gl_LastFragData") || type->getQualifier() == EvqFragmentInOut) && | |||
1358 | (isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch) || | |||
1359 | isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch_non_coherent)))) | |||
1360 | { | |||
1361 | checkNoncoherentIsNotSpecified(line, type->getLayoutQualifier().noncoherent); | |||
1362 | } | |||
1363 | else if (isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch_non_coherent) && | |||
1364 | !isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch)) | |||
1365 | { | |||
1366 | checkNoncoherentIsSpecified(line, type->getLayoutQualifier().noncoherent); | |||
1367 | } | |||
1368 | ||||
1369 | checkBindingIsValid(line, *type); | |||
1370 | ||||
1371 | bool needsReservedCheck = true; | |||
1372 | ||||
1373 | // gl_LastFragData may be redeclared with a new precision qualifier | |||
1374 | if (type->isArray() && identifier.beginsWith("gl_LastFragData")) | |||
1375 | { | |||
1376 | const TVariable *maxDrawBuffers = static_cast<const TVariable *>( | |||
1377 | symbolTable.findBuiltIn(ImmutableString("gl_MaxDrawBuffers"), mShaderVersion)); | |||
1378 | if (type->isArrayOfArrays()) | |||
1379 | { | |||
1380 | error(line, "redeclaration of gl_LastFragData as an array of arrays", identifier); | |||
1381 | return false; | |||
1382 | } | |||
1383 | else if (static_cast<int>(type->getOutermostArraySize()) == | |||
1384 | maxDrawBuffers->getConstPointer()->getIConst()) | |||
1385 | { | |||
1386 | if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) | |||
1387 | { | |||
1388 | needsReservedCheck = !checkCanUseOneOfExtensions(line, builtInSymbol->extensions()); | |||
1389 | } | |||
1390 | } | |||
1391 | else | |||
1392 | { | |||
1393 | error(line, "redeclaration of gl_LastFragData with size != gl_MaxDrawBuffers", | |||
1394 | identifier); | |||
1395 | return false; | |||
1396 | } | |||
1397 | } | |||
1398 | else if (type->isArray() && identifier == "gl_ClipDistance") | |||
1399 | { | |||
1400 | // gl_ClipDistance can be redeclared with smaller size than gl_MaxClipDistances | |||
1401 | const TVariable *maxClipDistances = static_cast<const TVariable *>( | |||
1402 | symbolTable.findBuiltIn(ImmutableString("gl_MaxClipDistances"), mShaderVersion)); | |||
1403 | if (!maxClipDistances) | |||
1404 | { | |||
1405 | // Unsupported extension | |||
1406 | needsReservedCheck = true; | |||
1407 | } | |||
1408 | else if (type->isArrayOfArrays()) | |||
1409 | { | |||
1410 | error(line, "redeclaration of gl_ClipDistance as an array of arrays", identifier); | |||
1411 | return false; | |||
1412 | } | |||
1413 | else if (static_cast<int>(type->getOutermostArraySize()) <= | |||
1414 | maxClipDistances->getConstPointer()->getIConst()) | |||
1415 | { | |||
1416 | const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion); | |||
1417 | if (builtInSymbol) | |||
1418 | { | |||
1419 | needsReservedCheck = !checkCanUseOneOfExtensions(line, builtInSymbol->extensions()); | |||
1420 | } | |||
1421 | } | |||
1422 | else | |||
1423 | { | |||
1424 | error(line, "redeclaration of gl_ClipDistance with size > gl_MaxClipDistances", | |||
1425 | identifier); | |||
1426 | return false; | |||
1427 | } | |||
1428 | } | |||
1429 | else if (type->isArray() && identifier == "gl_CullDistance") | |||
1430 | { | |||
1431 | // gl_CullDistance can be redeclared with smaller size than gl_MaxCullDistances | |||
1432 | const TVariable *maxCullDistances = static_cast<const TVariable *>( | |||
1433 | symbolTable.findBuiltIn(ImmutableString("gl_MaxCullDistances"), mShaderVersion)); | |||
1434 | if (!maxCullDistances) | |||
1435 | { | |||
1436 | // Unsupported extension | |||
1437 | needsReservedCheck = true; | |||
1438 | } | |||
1439 | else if (type->isArrayOfArrays()) | |||
1440 | { | |||
1441 | error(line, "redeclaration of gl_CullDistance as an array of arrays", identifier); | |||
1442 | return false; | |||
1443 | } | |||
1444 | else if (static_cast<int>(type->getOutermostArraySize()) <= | |||
1445 | maxCullDistances->getConstPointer()->getIConst()) | |||
1446 | { | |||
1447 | if (const TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) | |||
1448 | { | |||
1449 | needsReservedCheck = !checkCanUseOneOfExtensions(line, builtInSymbol->extensions()); | |||
1450 | } | |||
1451 | } | |||
1452 | else | |||
1453 | { | |||
1454 | error(line, "redeclaration of gl_CullDistance with size > gl_MaxCullDistances", | |||
1455 | identifier); | |||
1456 | return false; | |||
1457 | } | |||
1458 | } | |||
1459 | ||||
1460 | if (needsReservedCheck && !checkIsNotReserved(line, identifier)) | |||
1461 | return false; | |||
1462 | ||||
1463 | if (!symbolTable.declare(*variable)) | |||
1464 | { | |||
1465 | error(line, "redefinition", identifier); | |||
1466 | return false; | |||
1467 | } | |||
1468 | ||||
1469 | if (!checkIsNonVoid(line, identifier, type->getBasicType())) | |||
1470 | return false; | |||
1471 | ||||
1472 | return true; | |||
1473 | } | |||
1474 | ||||
1475 | void TParseContext::checkIsParameterQualifierValid( | |||
1476 | const TSourceLoc &line, | |||
1477 | const TTypeQualifierBuilder &typeQualifierBuilder, | |||
1478 | TType *type) | |||
1479 | { | |||
1480 | // The only parameter qualifiers a parameter can have are in, out, inout or const. | |||
1481 | TTypeQualifier typeQualifier = | |||
1482 | typeQualifierBuilder.getParameterTypeQualifier(type->getBasicType(), mDiagnostics); | |||
1483 | ||||
1484 | if (typeQualifier.qualifier == EvqParamOut || typeQualifier.qualifier == EvqParamInOut) | |||
1485 | { | |||
1486 | checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type); | |||
1487 | } | |||
1488 | ||||
1489 | if (!IsImage(type->getBasicType())) | |||
1490 | { | |||
1491 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, line); | |||
1492 | } | |||
1493 | else | |||
1494 | { | |||
1495 | type->setMemoryQualifier(typeQualifier.memoryQualifier); | |||
1496 | } | |||
1497 | ||||
1498 | type->setQualifier(typeQualifier.qualifier); | |||
1499 | ||||
1500 | if (typeQualifier.precision != EbpUndefined) | |||
1501 | { | |||
1502 | type->setPrecision(typeQualifier.precision); | |||
1503 | } | |||
1504 | ||||
1505 | if (typeQualifier.precise) | |||
1506 | { | |||
1507 | type->setPrecise(true); | |||
1508 | } | |||
1509 | } | |||
1510 | ||||
1511 | template <size_t size> | |||
1512 | bool TParseContext::checkCanUseOneOfExtensions(const TSourceLoc &line, | |||
1513 | const std::array<TExtension, size> &extensions) | |||
1514 | { | |||
1515 | ASSERT(!extensions.empty())(!extensions.empty() ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1515, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1515 << "): " << "!extensions.empty()" )); | |||
1516 | const TExtensionBehavior &extBehavior = extensionBehavior(); | |||
1517 | ||||
1518 | bool canUseWithWarning = false; | |||
1519 | bool canUseWithoutWarning = false; | |||
1520 | ||||
1521 | const char *errorMsgString = ""; | |||
1522 | TExtension errorMsgExtension = TExtension::UNDEFINED; | |||
1523 | ||||
1524 | for (TExtension extension : extensions) | |||
1525 | { | |||
1526 | auto extIter = extBehavior.find(extension); | |||
1527 | if (canUseWithWarning) | |||
1528 | { | |||
1529 | // We already have an extension that we can use, but with a warning. | |||
1530 | // See if we can use the alternative extension without a warning. | |||
1531 | if (extIter == extBehavior.end()) | |||
1532 | { | |||
1533 | continue; | |||
1534 | } | |||
1535 | if (extIter->second == EBhEnable || extIter->second == EBhRequire) | |||
1536 | { | |||
1537 | canUseWithoutWarning = true; | |||
1538 | break; | |||
1539 | } | |||
1540 | continue; | |||
1541 | } | |||
1542 | if (extension == TExtension::UNDEFINED) | |||
1543 | { | |||
1544 | continue; | |||
1545 | } | |||
1546 | else if (extIter == extBehavior.end()) | |||
1547 | { | |||
1548 | errorMsgString = "extension is not supported"; | |||
1549 | errorMsgExtension = extension; | |||
1550 | } | |||
1551 | else if (extIter->second == EBhUndefined || extIter->second == EBhDisable) | |||
1552 | { | |||
1553 | errorMsgString = "extension is disabled"; | |||
1554 | errorMsgExtension = extension; | |||
1555 | } | |||
1556 | else if (extIter->second == EBhWarn) | |||
1557 | { | |||
1558 | errorMsgExtension = extension; | |||
1559 | canUseWithWarning = true; | |||
1560 | } | |||
1561 | else | |||
1562 | { | |||
1563 | ASSERT(extIter->second == EBhEnable || extIter->second == EBhRequire)(extIter->second == EBhEnable || extIter->second == EBhRequire ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1563, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1563 << "): " << "extIter->second == EBhEnable || extIter->second == EBhRequire" )); | |||
1564 | canUseWithoutWarning = true; | |||
1565 | break; | |||
1566 | } | |||
1567 | } | |||
1568 | ||||
1569 | if (canUseWithoutWarning) | |||
1570 | { | |||
1571 | return true; | |||
1572 | } | |||
1573 | if (canUseWithWarning) | |||
1574 | { | |||
1575 | warning(line, "extension is being used", GetExtensionNameString(errorMsgExtension)); | |||
1576 | return true; | |||
1577 | } | |||
1578 | error(line, errorMsgString, GetExtensionNameString(errorMsgExtension)); | |||
1579 | return false; | |||
1580 | } | |||
1581 | ||||
1582 | template bool TParseContext::checkCanUseOneOfExtensions( | |||
1583 | const TSourceLoc &line, | |||
1584 | const std::array<TExtension, 1> &extensions); | |||
1585 | template bool TParseContext::checkCanUseOneOfExtensions( | |||
1586 | const TSourceLoc &line, | |||
1587 | const std::array<TExtension, 2> &extensions); | |||
1588 | template bool TParseContext::checkCanUseOneOfExtensions( | |||
1589 | const TSourceLoc &line, | |||
1590 | const std::array<TExtension, 3> &extensions); | |||
1591 | ||||
1592 | bool TParseContext::checkCanUseExtension(const TSourceLoc &line, TExtension extension) | |||
1593 | { | |||
1594 | ASSERT(extension != TExtension::UNDEFINED)(extension != TExtension::UNDEFINED ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1594, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1594 << "): " << "extension != TExtension::UNDEFINED" )); | |||
1595 | return checkCanUseOneOfExtensions(line, std::array<TExtension, 1u>{{extension}}); | |||
1596 | } | |||
1597 | ||||
1598 | // ESSL 3.00.6 section 4.8 Empty Declarations: "The combinations of qualifiers that cause | |||
1599 | // compile-time or link-time errors are the same whether or not the declaration is empty". | |||
1600 | // This function implements all the checks that are done on qualifiers regardless of if the | |||
1601 | // declaration is empty. | |||
1602 | void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifier, | |||
1603 | const sh::TLayoutQualifier &layoutQualifier, | |||
1604 | const TSourceLoc &location) | |||
1605 | { | |||
1606 | if (qualifier == EvqShared && !layoutQualifier.isEmpty()) | |||
1607 | { | |||
1608 | error(location, "Shared memory declarations cannot have layout specified", "layout"); | |||
1609 | } | |||
1610 | ||||
1611 | if (layoutQualifier.matrixPacking != EmpUnspecified) | |||
1612 | { | |||
1613 | error(location, "layout qualifier only valid for interface blocks", | |||
1614 | getMatrixPackingString(layoutQualifier.matrixPacking)); | |||
1615 | return; | |||
1616 | } | |||
1617 | ||||
1618 | if (layoutQualifier.blockStorage != EbsUnspecified) | |||
1619 | { | |||
1620 | error(location, "layout qualifier only valid for interface blocks", | |||
1621 | getBlockStorageString(layoutQualifier.blockStorage)); | |||
1622 | return; | |||
1623 | } | |||
1624 | ||||
1625 | if (qualifier == EvqFragmentOut) | |||
1626 | { | |||
1627 | if (layoutQualifier.location != -1 && layoutQualifier.yuv == true) | |||
1628 | { | |||
1629 | error(location, "invalid layout qualifier combination", "yuv"); | |||
1630 | return; | |||
1631 | } | |||
1632 | } | |||
1633 | else | |||
1634 | { | |||
1635 | checkYuvIsNotSpecified(location, layoutQualifier.yuv); | |||
1636 | } | |||
1637 | ||||
1638 | if (qualifier != EvqFragmentIn) | |||
1639 | { | |||
1640 | checkEarlyFragmentTestsIsNotSpecified(location, layoutQualifier.earlyFragmentTests); | |||
1641 | } | |||
1642 | ||||
1643 | // If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous | |||
1644 | // parsing steps. So it needs to be checked here. | |||
1645 | if (anyMultiviewExtensionAvailable() && mShaderVersion < 300 && qualifier == EvqVertexIn) | |||
1646 | { | |||
1647 | error(location, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); | |||
1648 | } | |||
1649 | ||||
1650 | bool canHaveLocation = qualifier == EvqVertexIn || qualifier == EvqFragmentOut; | |||
1651 | if (mShaderVersion >= 300 && | |||
1652 | (isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch) || | |||
1653 | isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch_non_coherent))) | |||
1654 | { | |||
1655 | // In the case of EXT_shader_framebuffer_fetch or EXT_shader_framebuffer_fetch_non_coherent | |||
1656 | // extension, the location of inout qualifier is used to set the input attachment index | |||
1657 | canHaveLocation = canHaveLocation || qualifier == EvqFragmentInOut; | |||
1658 | } | |||
1659 | if (mShaderVersion >= 310) | |||
1660 | { | |||
1661 | canHaveLocation = canHaveLocation || qualifier == EvqUniform || IsVarying(qualifier); | |||
1662 | // We're not checking whether the uniform location is in range here since that depends on | |||
1663 | // the type of the variable. | |||
1664 | // The type can only be fully determined for non-empty declarations. | |||
1665 | } | |||
1666 | if (!canHaveLocation) | |||
1667 | { | |||
1668 | checkLocationIsNotSpecified(location, layoutQualifier); | |||
1669 | } | |||
1670 | } | |||
1671 | ||||
1672 | void TParseContext::atomicCounterQualifierErrorCheck(const TPublicType &publicType, | |||
1673 | const TSourceLoc &location) | |||
1674 | { | |||
1675 | if (publicType.precision != EbpHigh) | |||
1676 | { | |||
1677 | error(location, "Can only be highp", "atomic counter"); | |||
1678 | } | |||
1679 | // dEQP enforces compile error if location is specified. See uniform_location.test. | |||
1680 | if (publicType.layoutQualifier.location != -1) | |||
1681 | { | |||
1682 | error(location, "location must not be set for atomic_uint", "layout"); | |||
1683 | } | |||
1684 | if (publicType.layoutQualifier.binding == -1) | |||
1685 | { | |||
1686 | error(location, "no binding specified", "atomic counter"); | |||
1687 | } | |||
1688 | } | |||
1689 | ||||
1690 | void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceLoc &location) | |||
1691 | { | |||
1692 | if (type.isUnsizedArray()) | |||
1693 | { | |||
1694 | // ESSL3 spec section 4.1.9: Array declaration which leaves the size unspecified is an | |||
1695 | // error. It is assumed that this applies to empty declarations as well. | |||
1696 | error(location, "empty array declaration needs to specify a size", ""); | |||
1697 | } | |||
1698 | ||||
1699 | if (type.getQualifier() != EvqFragmentOut) | |||
1700 | { | |||
1701 | checkIndexIsNotSpecified(location, type.getLayoutQualifier().index); | |||
1702 | } | |||
1703 | } | |||
1704 | ||||
1705 | // These checks are done for all declarations that are non-empty. They're done for non-empty | |||
1706 | // declarations starting a declarator list, and declarators that follow an empty declaration. | |||
1707 | void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, | |||
1708 | const TSourceLoc &identifierLocation) | |||
1709 | { | |||
1710 | switch (publicType.qualifier) | |||
1711 | { | |||
1712 | case EvqVaryingIn: | |||
1713 | case EvqVaryingOut: | |||
1714 | case EvqAttribute: | |||
1715 | case EvqVertexIn: | |||
1716 | case EvqFragmentOut: | |||
1717 | case EvqFragmentInOut: | |||
1718 | case EvqComputeIn: | |||
1719 | if (publicType.getBasicType() == EbtStruct) | |||
1720 | { | |||
1721 | error(identifierLocation, "cannot be used with a structure", | |||
1722 | getQualifierString(publicType.qualifier)); | |||
1723 | return; | |||
1724 | } | |||
1725 | break; | |||
1726 | case EvqBuffer: | |||
1727 | if (publicType.getBasicType() != EbtInterfaceBlock) | |||
1728 | { | |||
1729 | error(identifierLocation, | |||
1730 | "cannot declare buffer variables at global scope(outside a block)", | |||
1731 | getQualifierString(publicType.qualifier)); | |||
1732 | return; | |||
1733 | } | |||
1734 | break; | |||
1735 | default: | |||
1736 | break; | |||
1737 | } | |||
1738 | std::string reason(getBasicString(publicType.getBasicType())); | |||
1739 | reason += "s must be uniform"; | |||
1740 | if (publicType.qualifier != EvqUniform && | |||
1741 | !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str())) | |||
1742 | { | |||
1743 | return; | |||
1744 | } | |||
1745 | ||||
1746 | if ((publicType.qualifier != EvqTemporary && publicType.qualifier != EvqGlobal && | |||
1747 | publicType.qualifier != EvqConst) && | |||
1748 | publicType.getBasicType() == EbtYuvCscStandardEXT) | |||
1749 | { | |||
1750 | error(identifierLocation, "cannot be used with a yuvCscStandardEXT", | |||
1751 | getQualifierString(publicType.qualifier)); | |||
1752 | return; | |||
1753 | } | |||
1754 | ||||
1755 | if (mShaderVersion >= 310 && publicType.qualifier == EvqUniform) | |||
1756 | { | |||
1757 | // Valid uniform declarations can't be unsized arrays since uniforms can't be initialized. | |||
1758 | // But invalid shaders may still reach here with an unsized array declaration. | |||
1759 | TType type(publicType); | |||
1760 | if (!type.isUnsizedArray()) | |||
1761 | { | |||
1762 | checkUniformLocationInRange(identifierLocation, type.getLocationCount(), | |||
1763 | publicType.layoutQualifier); | |||
1764 | } | |||
1765 | } | |||
1766 | ||||
1767 | if (mShaderVersion >= 300 && publicType.qualifier == EvqVertexIn) | |||
1768 | { | |||
1769 | // Valid vertex input declarations can't be unsized arrays since they can't be initialized. | |||
1770 | // But invalid shaders may still reach here with an unsized array declaration. | |||
1771 | TType type(publicType); | |||
1772 | if (!type.isUnsizedArray()) | |||
1773 | { | |||
1774 | checkAttributeLocationInRange(identifierLocation, type.getLocationCount(), | |||
1775 | publicType.layoutQualifier); | |||
1776 | } | |||
1777 | } | |||
1778 | ||||
1779 | // check for layout qualifier issues | |||
1780 | const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; | |||
1781 | ||||
1782 | if (IsImage(publicType.getBasicType())) | |||
1783 | { | |||
1784 | ||||
1785 | switch (layoutQualifier.imageInternalFormat) | |||
1786 | { | |||
1787 | case EiifRGBA32F: | |||
1788 | case EiifRGBA16F: | |||
1789 | case EiifR32F: | |||
1790 | case EiifRGBA8: | |||
1791 | case EiifRGBA8_SNORM: | |||
1792 | if (!IsFloatImage(publicType.getBasicType())) | |||
1793 | { | |||
1794 | error(identifierLocation, | |||
1795 | "internal image format requires a floating image type", | |||
1796 | getBasicString(publicType.getBasicType())); | |||
1797 | return; | |||
1798 | } | |||
1799 | break; | |||
1800 | case EiifRGBA32I: | |||
1801 | case EiifRGBA16I: | |||
1802 | case EiifRGBA8I: | |||
1803 | case EiifR32I: | |||
1804 | if (!IsIntegerImage(publicType.getBasicType())) | |||
1805 | { | |||
1806 | error(identifierLocation, | |||
1807 | "internal image format requires an integer image type", | |||
1808 | getBasicString(publicType.getBasicType())); | |||
1809 | return; | |||
1810 | } | |||
1811 | break; | |||
1812 | case EiifRGBA32UI: | |||
1813 | case EiifRGBA16UI: | |||
1814 | case EiifRGBA8UI: | |||
1815 | case EiifR32UI: | |||
1816 | if (!IsUnsignedImage(publicType.getBasicType())) | |||
1817 | { | |||
1818 | error(identifierLocation, | |||
1819 | "internal image format requires an unsigned image type", | |||
1820 | getBasicString(publicType.getBasicType())); | |||
1821 | return; | |||
1822 | } | |||
1823 | break; | |||
1824 | case EiifUnspecified: | |||
1825 | error(identifierLocation, "layout qualifier", "No image internal format specified"); | |||
1826 | return; | |||
1827 | default: | |||
1828 | error(identifierLocation, "layout qualifier", "unrecognized token"); | |||
1829 | return; | |||
1830 | } | |||
1831 | ||||
1832 | // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers | |||
1833 | switch (layoutQualifier.imageInternalFormat) | |||
1834 | { | |||
1835 | case EiifR32F: | |||
1836 | case EiifR32I: | |||
1837 | case EiifR32UI: | |||
1838 | break; | |||
1839 | default: | |||
1840 | if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly) | |||
1841 | { | |||
1842 | error(identifierLocation, "layout qualifier", | |||
1843 | "Except for images with the r32f, r32i and r32ui format qualifiers, " | |||
1844 | "image variables must be qualified readonly and/or writeonly"); | |||
1845 | return; | |||
1846 | } | |||
1847 | break; | |||
1848 | } | |||
1849 | } | |||
1850 | else if (IsPixelLocal(publicType.getBasicType())) | |||
1851 | { | |||
1852 | if (getShaderType() != GL_FRAGMENT_SHADER0x8B30) | |||
1853 | { | |||
1854 | error(identifierLocation, | |||
1855 | "undefined use of pixel local storage outside a fragment shader", | |||
1856 | getBasicString(publicType.getBasicType())); | |||
1857 | return; | |||
1858 | } | |||
1859 | switch (layoutQualifier.imageInternalFormat) | |||
1860 | { | |||
1861 | case EiifR32F: | |||
1862 | case EiifRGBA8: | |||
1863 | if (publicType.getBasicType() != EbtPixelLocalANGLE) | |||
1864 | { | |||
1865 | error(identifierLocation, "pixel local storage format requires pixelLocalANGLE", | |||
1866 | getImageInternalFormatString(layoutQualifier.imageInternalFormat)); | |||
1867 | } | |||
1868 | break; | |||
1869 | case EiifRGBA8I: | |||
1870 | if (publicType.getBasicType() != EbtIPixelLocalANGLE) | |||
1871 | { | |||
1872 | error(identifierLocation, | |||
1873 | "pixel local storage format requires ipixelLocalANGLE", | |||
1874 | getImageInternalFormatString(layoutQualifier.imageInternalFormat)); | |||
1875 | } | |||
1876 | break; | |||
1877 | case EiifR32UI: | |||
1878 | case EiifRGBA8UI: | |||
1879 | if (publicType.getBasicType() != EbtUPixelLocalANGLE) | |||
1880 | { | |||
1881 | error(identifierLocation, | |||
1882 | "pixel local storage format requires upixelLocalANGLE", | |||
1883 | getImageInternalFormatString(layoutQualifier.imageInternalFormat)); | |||
1884 | } | |||
1885 | break; | |||
1886 | case EiifR32I: | |||
1887 | case EiifRGBA8_SNORM: | |||
1888 | case EiifRGBA16F: | |||
1889 | case EiifRGBA32F: | |||
1890 | case EiifRGBA16I: | |||
1891 | case EiifRGBA32I: | |||
1892 | case EiifRGBA16UI: | |||
1893 | case EiifRGBA32UI: | |||
1894 | default: | |||
1895 | ASSERT(!IsValidWithPixelLocalStorage(layoutQualifier.imageInternalFormat))(!IsValidWithPixelLocalStorage(layoutQualifier.imageInternalFormat ) ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1895, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1895 << "): " << "!IsValidWithPixelLocalStorage(layoutQualifier.imageInternalFormat)" )); | |||
1896 | error(identifierLocation, "illegal pixel local storage format", | |||
1897 | getImageInternalFormatString(layoutQualifier.imageInternalFormat)); | |||
1898 | break; | |||
1899 | case EiifUnspecified: | |||
1900 | error(identifierLocation, "pixel local storage requires a format specifier", | |||
1901 | "layout qualifier"); | |||
1902 | break; | |||
1903 | } | |||
1904 | checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation); | |||
1905 | checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); | |||
1906 | } | |||
1907 | else | |||
1908 | { | |||
1909 | checkInternalFormatIsNotSpecified(identifierLocation, layoutQualifier.imageInternalFormat); | |||
1910 | checkMemoryQualifierIsNotSpecified(publicType.memoryQualifier, identifierLocation); | |||
1911 | } | |||
1912 | ||||
1913 | if (IsAtomicCounter(publicType.getBasicType())) | |||
1914 | { | |||
1915 | atomicCounterQualifierErrorCheck(publicType, identifierLocation); | |||
1916 | } | |||
1917 | else | |||
1918 | { | |||
1919 | checkOffsetIsNotSpecified(identifierLocation, layoutQualifier.offset); | |||
1920 | } | |||
1921 | } | |||
1922 | ||||
1923 | void TParseContext::checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type) | |||
1924 | { | |||
1925 | TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); | |||
1926 | // Note that the ESSL 3.10 section 4.4.5 is not particularly clear on how the binding qualifier | |||
1927 | // on arrays of arrays should be handled. We interpret the spec so that the binding value is | |||
1928 | // incremented for each element of the innermost nested arrays. This is in line with how arrays | |||
1929 | // of arrays of blocks are specified to behave in GLSL 4.50 and a conservative interpretation | |||
1930 | // when it comes to which shaders are accepted by the compiler. | |||
1931 | int arrayTotalElementCount = type.getArraySizeProduct(); | |||
1932 | if (IsPixelLocal(type.getBasicType())) | |||
1933 | { | |||
1934 | checkPixelLocalStorageBindingIsValid(identifierLocation, type); | |||
1935 | } | |||
1936 | else if (mShaderVersion < 310) | |||
1937 | { | |||
1938 | checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding); | |||
1939 | } | |||
1940 | else if (IsImage(type.getBasicType())) | |||
1941 | { | |||
1942 | checkImageBindingIsValid(identifierLocation, layoutQualifier.binding, | |||
1943 | arrayTotalElementCount); | |||
1944 | } | |||
1945 | else if (IsSampler(type.getBasicType())) | |||
1946 | { | |||
1947 | checkSamplerBindingIsValid(identifierLocation, layoutQualifier.binding, | |||
1948 | arrayTotalElementCount); | |||
1949 | } | |||
1950 | else if (IsAtomicCounter(type.getBasicType())) | |||
1951 | { | |||
1952 | checkAtomicCounterBindingIsValid(identifierLocation, layoutQualifier.binding); | |||
1953 | } | |||
1954 | else | |||
1955 | { | |||
1956 | ASSERT(!IsOpaqueType(type.getBasicType()))(!IsOpaqueType(type.getBasicType()) ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 1956, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 1956 << "): " << "!IsOpaqueType(type.getBasicType())" )); | |||
1957 | checkBindingIsNotSpecified(identifierLocation, layoutQualifier.binding); | |||
1958 | } | |||
1959 | } | |||
1960 | ||||
1961 | void TParseContext::checkCanUseLayoutQualifier(const TSourceLoc &location) | |||
1962 | { | |||
1963 | constexpr std::array<TExtension, 4u> extensions{ | |||
1964 | {TExtension::EXT_shader_framebuffer_fetch, | |||
1965 | TExtension::EXT_shader_framebuffer_fetch_non_coherent, | |||
1966 | TExtension::KHR_blend_equation_advanced, TExtension::ANGLE_shader_pixel_local_storage}}; | |||
1967 | if (getShaderVersion() < 300 && !checkCanUseOneOfExtensions(location, extensions)) | |||
1968 | { | |||
1969 | error(location, "qualifier supported in GLSL ES 3.00 and above only", "layout"); | |||
1970 | } | |||
1971 | } | |||
1972 | ||||
1973 | bool TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, | |||
1974 | const ImmutableString &layoutQualifierName, | |||
1975 | int versionRequired) | |||
1976 | { | |||
1977 | ||||
1978 | if (mShaderVersion < versionRequired) | |||
1979 | { | |||
1980 | error(location, "invalid layout qualifier: not supported", layoutQualifierName); | |||
1981 | return false; | |||
1982 | } | |||
1983 | return true; | |||
1984 | } | |||
1985 | ||||
1986 | bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, | |||
1987 | const TLayoutQualifier &layoutQualifier) | |||
1988 | { | |||
1989 | const sh::WorkGroupSize &localSize = layoutQualifier.localSize; | |||
1990 | for (size_t i = 0u; i < localSize.size(); ++i) | |||
1991 | { | |||
1992 | if (localSize[i] != -1) | |||
1993 | { | |||
1994 | error(location, | |||
1995 | "invalid layout qualifier: only valid when used with 'in' in a compute shader " | |||
1996 | "global layout declaration", | |||
1997 | getWorkGroupSizeString(i)); | |||
1998 | return false; | |||
1999 | } | |||
2000 | } | |||
2001 | ||||
2002 | return true; | |||
2003 | } | |||
2004 | ||||
2005 | void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location, | |||
2006 | TLayoutImageInternalFormat internalFormat) | |||
2007 | { | |||
2008 | if (internalFormat != EiifUnspecified) | |||
2009 | { | |||
2010 | if (mShaderVersion < 310) | |||
2011 | { | |||
2012 | if (IsValidWithPixelLocalStorage(internalFormat)) | |||
2013 | { | |||
2014 | error(location, | |||
2015 | "invalid layout qualifier: not supported before GLSL ES 3.10, except pixel " | |||
2016 | "local storage", | |||
2017 | getImageInternalFormatString(internalFormat)); | |||
2018 | } | |||
2019 | else | |||
2020 | { | |||
2021 | error(location, "invalid layout qualifier: not supported before GLSL ES 3.10", | |||
2022 | getImageInternalFormatString(internalFormat)); | |||
2023 | } | |||
2024 | } | |||
2025 | else | |||
2026 | { | |||
2027 | if (IsValidWithPixelLocalStorage(internalFormat)) | |||
2028 | { | |||
2029 | error(location, | |||
2030 | "invalid layout qualifier: only valid when used with images or pixel local " | |||
2031 | "storage ", | |||
2032 | getImageInternalFormatString(internalFormat)); | |||
2033 | } | |||
2034 | else | |||
2035 | { | |||
2036 | error(location, "invalid layout qualifier: only valid when used with images", | |||
2037 | getImageInternalFormatString(internalFormat)); | |||
2038 | } | |||
2039 | } | |||
2040 | } | |||
2041 | } | |||
2042 | ||||
2043 | void TParseContext::checkIndexIsNotSpecified(const TSourceLoc &location, int index) | |||
2044 | { | |||
2045 | if (index != -1) | |||
2046 | { | |||
2047 | error(location, | |||
2048 | "invalid layout qualifier: only valid when used with a fragment shader output in " | |||
2049 | "ESSL version >= 3.00 and EXT_blend_func_extended is enabled", | |||
2050 | "index"); | |||
2051 | } | |||
2052 | } | |||
2053 | ||||
2054 | void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding) | |||
2055 | { | |||
2056 | if (binding != -1) | |||
2057 | { | |||
2058 | if (mShaderVersion < 310) | |||
2059 | { | |||
2060 | error(location, | |||
2061 | "invalid layout qualifier: only valid when used with pixel local storage", | |||
2062 | "binding"); | |||
2063 | } | |||
2064 | else | |||
2065 | { | |||
2066 | error(location, | |||
2067 | "invalid layout qualifier: only valid when used with opaque types or blocks", | |||
2068 | "binding"); | |||
2069 | } | |||
2070 | } | |||
2071 | } | |||
2072 | ||||
2073 | void TParseContext::checkOffsetIsNotSpecified(const TSourceLoc &location, int offset) | |||
2074 | { | |||
2075 | if (offset != -1) | |||
2076 | { | |||
2077 | error(location, "invalid layout qualifier: only valid when used with atomic counters", | |||
2078 | "offset"); | |||
2079 | } | |||
2080 | } | |||
2081 | ||||
2082 | void TParseContext::checkImageBindingIsValid(const TSourceLoc &location, | |||
2083 | int binding, | |||
2084 | int arrayTotalElementCount) | |||
2085 | { | |||
2086 | // Expects arraySize to be 1 when setting binding for only a single variable. | |||
2087 | if (binding >= 0 && binding + arrayTotalElementCount > mMaxImageUnits) | |||
2088 | { | |||
2089 | error(location, "image binding greater than gl_MaxImageUnits", "binding"); | |||
2090 | } | |||
2091 | } | |||
2092 | ||||
2093 | void TParseContext::checkSamplerBindingIsValid(const TSourceLoc &location, | |||
2094 | int binding, | |||
2095 | int arrayTotalElementCount) | |||
2096 | { | |||
2097 | // Expects arraySize to be 1 when setting binding for only a single variable. | |||
2098 | if (binding >= 0 && binding + arrayTotalElementCount > mMaxCombinedTextureImageUnits) | |||
2099 | { | |||
2100 | error(location, "sampler binding greater than maximum texture units", "binding"); | |||
2101 | } | |||
2102 | } | |||
2103 | ||||
2104 | void TParseContext::checkBlockBindingIsValid(const TSourceLoc &location, | |||
2105 | const TQualifier &qualifier, | |||
2106 | int binding, | |||
2107 | int arraySize) | |||
2108 | { | |||
2109 | int size = (arraySize == 0 ? 1 : arraySize); | |||
2110 | if (qualifier == EvqUniform) | |||
2111 | { | |||
2112 | if (binding + size > mMaxUniformBufferBindings) | |||
2113 | { | |||
2114 | error(location, "uniform block binding greater than MAX_UNIFORM_BUFFER_BINDINGS", | |||
2115 | "binding"); | |||
2116 | } | |||
2117 | } | |||
2118 | else if (qualifier == EvqBuffer) | |||
2119 | { | |||
2120 | if (binding + size > mMaxShaderStorageBufferBindings) | |||
2121 | { | |||
2122 | error(location, | |||
2123 | "shader storage block binding greater than MAX_SHADER_STORAGE_BUFFER_BINDINGS", | |||
2124 | "binding"); | |||
2125 | } | |||
2126 | } | |||
2127 | } | |||
2128 | void TParseContext::checkAtomicCounterBindingIsValid(const TSourceLoc &location, int binding) | |||
2129 | { | |||
2130 | if (binding >= mMaxAtomicCounterBindings) | |||
2131 | { | |||
2132 | error(location, "atomic counter binding greater than gl_MaxAtomicCounterBindings", | |||
2133 | "binding"); | |||
2134 | } | |||
2135 | } | |||
2136 | ||||
2137 | void TParseContext::checkPixelLocalStorageBindingIsValid(const TSourceLoc &location, | |||
2138 | const TType &type) | |||
2139 | { | |||
2140 | TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); | |||
2141 | if (type.isArray()) | |||
2142 | { | |||
2143 | // PLS is not allowed in arrays. | |||
2144 | // TODO(anglebug.com/7279): Consider allowing this once more backends are implemented. | |||
2145 | error(location, "pixel local storage handles cannot be aggregated in arrays", "array"); | |||
2146 | } | |||
2147 | else if (layoutQualifier.binding < 0) | |||
2148 | { | |||
2149 | error(location, "pixel local storage requires a binding index", "layout qualifier"); | |||
2150 | } | |||
2151 | // TODO(anglebug.com/7279): | |||
2152 | // else if (binding >= GL_MAX_LOCAL_STORAGE_PLANES_ANGLE) | |||
2153 | // { | |||
2154 | // } | |||
2155 | else if (mPLSBindings.find(layoutQualifier.binding) != mPLSBindings.end()) | |||
2156 | { | |||
2157 | error(location, "duplicate pixel local storage binding index", | |||
2158 | std::to_string(layoutQualifier.binding).c_str()); | |||
2159 | } | |||
2160 | else | |||
2161 | { | |||
2162 | mPLSBindings[layoutQualifier.binding] = layoutQualifier.imageInternalFormat; | |||
2163 | // "mPLSBindings" is how we know whether pixel local storage uniforms have been declared, so | |||
2164 | // flush the queue of potential errors once mPLSBindings isn't empty. | |||
2165 | if (!mPLSPotentialErrors.empty()) | |||
2166 | { | |||
2167 | for (const auto &[loc, op] : mPLSPotentialErrors) | |||
2168 | { | |||
2169 | errorIfPLSDeclared(loc, op); | |||
2170 | } | |||
2171 | mPLSPotentialErrors.clear(); | |||
2172 | } | |||
2173 | } | |||
2174 | } | |||
2175 | ||||
2176 | void TParseContext::checkUniformLocationInRange(const TSourceLoc &location, | |||
2177 | int objectLocationCount, | |||
2178 | const TLayoutQualifier &layoutQualifier) | |||
2179 | { | |||
2180 | int loc = layoutQualifier.location; | |||
2181 | if (loc >= 0) // Shader-specified location | |||
2182 | { | |||
2183 | if (loc >= mMaxUniformLocations || objectLocationCount > mMaxUniformLocations || | |||
2184 | static_cast<unsigned int>(loc) + static_cast<unsigned int>(objectLocationCount) > | |||
2185 | static_cast<unsigned int>(mMaxUniformLocations)) | |||
2186 | { | |||
2187 | error(location, "Uniform location out of range", "location"); | |||
2188 | } | |||
2189 | } | |||
2190 | } | |||
2191 | ||||
2192 | void TParseContext::checkAttributeLocationInRange(const TSourceLoc &location, | |||
2193 | int objectLocationCount, | |||
2194 | const TLayoutQualifier &layoutQualifier) | |||
2195 | { | |||
2196 | int loc = layoutQualifier.location; | |||
2197 | if (loc >= 0) // Shader-specified location | |||
2198 | { | |||
2199 | if (loc >= mMaxVertexAttribs || objectLocationCount > mMaxVertexAttribs || | |||
2200 | static_cast<unsigned int>(loc) + static_cast<unsigned int>(objectLocationCount) > | |||
2201 | static_cast<unsigned int>(mMaxVertexAttribs)) | |||
2202 | { | |||
2203 | error(location, "Attribute location out of range", "location"); | |||
2204 | } | |||
2205 | } | |||
2206 | } | |||
2207 | ||||
2208 | void TParseContext::checkYuvIsNotSpecified(const TSourceLoc &location, bool yuv) | |||
2209 | { | |||
2210 | if (yuv != false) | |||
2211 | { | |||
2212 | error(location, "invalid layout qualifier: only valid on program outputs", "yuv"); | |||
2213 | } | |||
2214 | } | |||
2215 | ||||
2216 | void TParseContext::checkEarlyFragmentTestsIsNotSpecified(const TSourceLoc &location, | |||
2217 | bool earlyFragmentTests) | |||
2218 | { | |||
2219 | if (earlyFragmentTests != false) | |||
2220 | { | |||
2221 | error(location, | |||
2222 | "invalid layout qualifier: only valid when used with 'in' in a fragment shader", | |||
2223 | "early_fragment_tests"); | |||
2224 | } | |||
2225 | } | |||
2226 | ||||
2227 | void TParseContext::checkNoncoherentIsSpecified(const TSourceLoc &location, bool noncoherent) | |||
2228 | { | |||
2229 | if (noncoherent == false) | |||
2230 | { | |||
2231 | error(location, | |||
2232 | "'noncoherent' qualifier must be used when " | |||
2233 | "GL_EXT_shader_framebuffer_fetch_non_coherent extension is used", | |||
2234 | "noncoherent"); | |||
2235 | } | |||
2236 | } | |||
2237 | ||||
2238 | void TParseContext::checkNoncoherentIsNotSpecified(const TSourceLoc &location, bool noncoherent) | |||
2239 | { | |||
2240 | if (noncoherent != false) | |||
2241 | { | |||
2242 | error(location, | |||
2243 | "invalid layout qualifier: only valid when used with 'gl_LastFragData' or the " | |||
2244 | "variable decorated with 'inout' in a fragment shader", | |||
2245 | "noncoherent"); | |||
2246 | } | |||
2247 | } | |||
2248 | ||||
2249 | void TParseContext::checkTCSOutVarIndexIsValid(TIntermBinary *binaryExpression, | |||
2250 | const TSourceLoc &location) | |||
2251 | { | |||
2252 | ASSERT(binaryExpression->getOp() == EOpIndexIndirect ||(binaryExpression->getOp() == EOpIndexIndirect || binaryExpression ->getOp() == EOpIndexDirect ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2253, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2253 << "): " << "binaryExpression->getOp() == EOpIndexIndirect || binaryExpression->getOp() == EOpIndexDirect" )) | |||
2253 | binaryExpression->getOp() == EOpIndexDirect)(binaryExpression->getOp() == EOpIndexIndirect || binaryExpression ->getOp() == EOpIndexDirect ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2253, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2253 << "): " << "binaryExpression->getOp() == EOpIndexIndirect || binaryExpression->getOp() == EOpIndexDirect" )); | |||
2254 | const TIntermSymbol *intermSymbol = binaryExpression->getRight()->getAsSymbolNode(); | |||
2255 | if ((intermSymbol == nullptr) || (intermSymbol->getName() != "gl_InvocationID")) | |||
2256 | { | |||
2257 | error(location, | |||
2258 | "tessellation-control per-vertex output l-value must be indexed with " | |||
2259 | "gl_InvocationID", | |||
2260 | "["); | |||
2261 | } | |||
2262 | } | |||
2263 | ||||
2264 | void TParseContext::functionCallRValueLValueErrorCheck(const TFunction *fnCandidate, | |||
2265 | TIntermAggregate *fnCall) | |||
2266 | { | |||
2267 | for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) | |||
2268 | { | |||
2269 | TQualifier qual = fnCandidate->getParam(i)->getType().getQualifier(); | |||
2270 | TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped(); | |||
2271 | bool argumentIsRead = (IsQualifierUnspecified(qual) || qual == EvqParamIn || | |||
2272 | qual == EvqParamInOut || qual == EvqParamConst); | |||
2273 | if (argumentIsRead) | |||
2274 | { | |||
2275 | markStaticReadIfSymbol(argument); | |||
2276 | if (!IsImage(argument->getBasicType())) | |||
2277 | { | |||
2278 | if (argument->getMemoryQualifier().writeonly) | |||
2279 | { | |||
2280 | error(argument->getLine(), | |||
2281 | "Writeonly value cannot be passed for 'in' or 'inout' parameters.", | |||
2282 | fnCall->functionName()); | |||
2283 | return; | |||
2284 | } | |||
2285 | } | |||
2286 | } | |||
2287 | if (qual == EvqParamOut || qual == EvqParamInOut) | |||
2288 | { | |||
2289 | if (!checkCanBeLValue(argument->getLine(), "assign", argument)) | |||
2290 | { | |||
2291 | error(argument->getLine(), | |||
2292 | "Constant value cannot be passed for 'out' or 'inout' parameters.", | |||
2293 | fnCall->functionName()); | |||
2294 | return; | |||
2295 | } | |||
2296 | } | |||
2297 | } | |||
2298 | } | |||
2299 | ||||
2300 | void TParseContext::checkInvariantVariableQualifier(bool invariant, | |||
2301 | const TQualifier qualifier, | |||
2302 | const TSourceLoc &invariantLocation) | |||
2303 | { | |||
2304 | if (!invariant) | |||
2305 | return; | |||
2306 | ||||
2307 | if (mShaderVersion < 300) | |||
2308 | { | |||
2309 | // input variables in the fragment shader can be also qualified as invariant | |||
2310 | if (!sh::CanBeInvariantESSL1(qualifier)) | |||
2311 | { | |||
2312 | error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); | |||
2313 | } | |||
2314 | } | |||
2315 | else | |||
2316 | { | |||
2317 | if (!sh::CanBeInvariantESSL3OrGreater(qualifier)) | |||
2318 | { | |||
2319 | error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); | |||
2320 | } | |||
2321 | } | |||
2322 | } | |||
2323 | ||||
2324 | void TParseContext::checkAdvancedBlendEquationsNotSpecified( | |||
2325 | const TSourceLoc &location, | |||
2326 | const AdvancedBlendEquations &advancedBlendEquations, | |||
2327 | const TQualifier &qualifier) | |||
2328 | { | |||
2329 | if (advancedBlendEquations.any() && qualifier != EvqFragmentOut) | |||
2330 | { | |||
2331 | error(location, | |||
2332 | "invalid layout qualifier: blending equation qualifiers are only permitted on the " | |||
2333 | "fragment 'out' qualifier ", | |||
2334 | "blend_support_qualifier"); | |||
2335 | } | |||
2336 | } | |||
2337 | ||||
2338 | bool TParseContext::isExtensionEnabled(TExtension extension) const | |||
2339 | { | |||
2340 | return IsExtensionEnabled(extensionBehavior(), extension); | |||
2341 | } | |||
2342 | ||||
2343 | void TParseContext::handleExtensionDirective(const TSourceLoc &loc, | |||
2344 | const char *extName, | |||
2345 | const char *behavior) | |||
2346 | { | |||
2347 | angle::pp::SourceLocation srcLoc; | |||
2348 | srcLoc.file = loc.first_file; | |||
2349 | srcLoc.line = loc.first_line; | |||
2350 | mDirectiveHandler.handleExtension(srcLoc, extName, behavior); | |||
2351 | } | |||
2352 | ||||
2353 | void TParseContext::handlePragmaDirective(const TSourceLoc &loc, | |||
2354 | const char *name, | |||
2355 | const char *value, | |||
2356 | bool stdgl) | |||
2357 | { | |||
2358 | angle::pp::SourceLocation srcLoc; | |||
2359 | srcLoc.file = loc.first_file; | |||
2360 | srcLoc.line = loc.first_line; | |||
2361 | mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl); | |||
2362 | } | |||
2363 | ||||
2364 | sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const | |||
2365 | { | |||
2366 | sh::WorkGroupSize result(-1); | |||
2367 | for (size_t i = 0u; i < result.size(); ++i) | |||
2368 | { | |||
2369 | if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1) | |||
2370 | { | |||
2371 | result[i] = 1; | |||
2372 | } | |||
2373 | else | |||
2374 | { | |||
2375 | result[i] = mComputeShaderLocalSize[i]; | |||
2376 | } | |||
2377 | } | |||
2378 | return result; | |||
2379 | } | |||
2380 | ||||
2381 | TIntermConstantUnion *TParseContext::addScalarLiteral(const TConstantUnion *constantUnion, | |||
2382 | const TSourceLoc &line) | |||
2383 | { | |||
2384 | TIntermConstantUnion *node = new TIntermConstantUnion( | |||
2385 | constantUnion, TType(constantUnion->getType(), EbpUndefined, EvqConst)); | |||
2386 | node->setLine(line); | |||
2387 | return node; | |||
2388 | } | |||
2389 | ||||
2390 | ///////////////////////////////////////////////////////////////////////////////// | |||
2391 | // | |||
2392 | // Non-Errors. | |||
2393 | // | |||
2394 | ///////////////////////////////////////////////////////////////////////////////// | |||
2395 | ||||
2396 | const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, | |||
2397 | const ImmutableString &name, | |||
2398 | const TSymbol *symbol) | |||
2399 | { | |||
2400 | if (!symbol) | |||
2401 | { | |||
2402 | error(location, "undeclared identifier", name); | |||
2403 | return nullptr; | |||
2404 | } | |||
2405 | ||||
2406 | if (!symbol->isVariable()) | |||
2407 | { | |||
2408 | error(location, "variable expected", name); | |||
2409 | return nullptr; | |||
2410 | } | |||
2411 | ||||
2412 | const TVariable *variable = static_cast<const TVariable *>(symbol); | |||
2413 | ||||
2414 | if (!variable->extensions().empty() && variable->extensions()[0] != TExtension::UNDEFINED) | |||
2415 | { | |||
2416 | checkCanUseOneOfExtensions(location, variable->extensions()); | |||
2417 | } | |||
2418 | ||||
2419 | // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables | |||
2420 | if (getShaderType() == GL_COMPUTE_SHADER0x91B9 && !mComputeShaderLocalSizeDeclared && | |||
2421 | variable->getType().getQualifier() == EvqWorkGroupSize) | |||
2422 | { | |||
2423 | error(location, | |||
2424 | "It is an error to use gl_WorkGroupSize before declaring the local group size", | |||
2425 | "gl_WorkGroupSize"); | |||
2426 | } | |||
2427 | ||||
2428 | // If EXT_shader_framebuffer_fetch_non_coherent is used, gl_LastFragData should be decorated | |||
2429 | // with 'layout(noncoherent)' EXT_shader_framebuffer_fetch_non_coherent spec: "Unless the | |||
2430 | // GL_EXT_shader_framebuffer_fetch extension has been enabled in addition, it's an error to use | |||
2431 | // gl_LastFragData if it hasn't been explicitly redeclared with layout(noncoherent)." | |||
2432 | if (isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch_non_coherent) && | |||
2433 | !isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch) && | |||
2434 | variable->getType().getQualifier() == EvqLastFragData) | |||
2435 | { | |||
2436 | checkNoncoherentIsSpecified(location, variable->getType().getLayoutQualifier().noncoherent); | |||
2437 | } | |||
2438 | return variable; | |||
2439 | } | |||
2440 | ||||
2441 | TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, | |||
2442 | const ImmutableString &name, | |||
2443 | const TSymbol *symbol) | |||
2444 | { | |||
2445 | const TVariable *variable = getNamedVariable(location, name, symbol); | |||
2446 | ||||
2447 | if (!variable) | |||
2448 | { | |||
2449 | TIntermTyped *node = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); | |||
2450 | node->setLine(location); | |||
2451 | return node; | |||
2452 | } | |||
2453 | ||||
2454 | const TType &variableType = variable->getType(); | |||
2455 | TIntermTyped *node = nullptr; | |||
2456 | ||||
2457 | if (variable->getConstPointer() && variableType.canReplaceWithConstantUnion()) | |||
2458 | { | |||
2459 | const TConstantUnion *constArray = variable->getConstPointer(); | |||
2460 | node = new TIntermConstantUnion(constArray, variableType); | |||
2461 | } | |||
2462 | else if (variableType.getQualifier() == EvqWorkGroupSize && mComputeShaderLocalSizeDeclared) | |||
2463 | { | |||
2464 | // gl_WorkGroupSize can be used to size arrays according to the ESSL 3.10.4 spec, so it | |||
2465 | // needs to be added to the AST as a constant and not as a symbol. | |||
2466 | sh::WorkGroupSize workGroupSize = getComputeShaderLocalSize(); | |||
2467 | TConstantUnion *constArray = new TConstantUnion[3]; | |||
2468 | for (size_t i = 0; i < 3; ++i) | |||
2469 | { | |||
2470 | constArray[i].setUConst(static_cast<unsigned int>(workGroupSize[i])); | |||
2471 | } | |||
2472 | ||||
2473 | ASSERT(variableType.getBasicType() == EbtUInt)(variableType.getBasicType() == EbtUInt ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2473, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2473 << "): " << "variableType.getBasicType() == EbtUInt" )); | |||
2474 | ASSERT(variableType.getObjectSize() == 3)(variableType.getObjectSize() == 3 ? static_cast<void>( 0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2474, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2474 << "): " << "variableType.getObjectSize() == 3" )); | |||
2475 | ||||
2476 | TType type(variableType); | |||
2477 | type.setQualifier(EvqConst); | |||
2478 | node = new TIntermConstantUnion(constArray, type); | |||
2479 | } | |||
2480 | else if ((mGeometryShaderInputPrimitiveType != EptUndefined) && | |||
2481 | (variableType.getQualifier() == EvqPerVertexIn)) | |||
2482 | { | |||
2483 | ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr)(symbolTable.getGlInVariableWithArraySize() != nullptr ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2483, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2483 << "): " << "symbolTable.getGlInVariableWithArraySize() != nullptr" )); | |||
2484 | node = new TIntermSymbol(symbolTable.getGlInVariableWithArraySize()); | |||
2485 | } | |||
2486 | else | |||
2487 | { | |||
2488 | node = new TIntermSymbol(variable); | |||
2489 | } | |||
2490 | ASSERT(node != nullptr)(node != nullptr ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2490, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2490 << "): " << "node != nullptr" )); | |||
2491 | node->setLine(location); | |||
2492 | return node; | |||
2493 | } | |||
2494 | ||||
2495 | void TParseContext::adjustRedeclaredBuiltInType(const ImmutableString &identifier, TType *type) | |||
2496 | { | |||
2497 | if (identifier == "gl_ClipDistance") | |||
2498 | { | |||
2499 | type->setQualifier(EvqClipDistance); | |||
2500 | } | |||
2501 | else if (identifier == "gl_CullDistance") | |||
2502 | { | |||
2503 | type->setQualifier(EvqCullDistance); | |||
2504 | } | |||
2505 | else if (identifier == "gl_LastFragData") | |||
2506 | { | |||
2507 | type->setQualifier(EvqLastFragData); | |||
2508 | } | |||
2509 | } | |||
2510 | ||||
2511 | // Initializers show up in several places in the grammar. Have one set of | |||
2512 | // code to handle them here. | |||
2513 | // | |||
2514 | // Returns true on success. | |||
2515 | bool TParseContext::executeInitializer(const TSourceLoc &line, | |||
2516 | const ImmutableString &identifier, | |||
2517 | TType *type, | |||
2518 | TIntermTyped *initializer, | |||
2519 | TIntermBinary **initNode) | |||
2520 | { | |||
2521 | ASSERT(initNode != nullptr)(initNode != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2521, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2521 << "): " << "initNode != nullptr" )); | |||
2522 | ASSERT(*initNode == nullptr)(*initNode == nullptr ? static_cast<void>(0) : (!((::gl ::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2522, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2522 << "): " << "*initNode == nullptr" )); | |||
2523 | ||||
2524 | if (type->isUnsizedArray()) | |||
2525 | { | |||
2526 | // In case initializer is not an array or type has more dimensions than initializer, this | |||
2527 | // will default to setting array sizes to 1. We have not checked yet whether the initializer | |||
2528 | // actually is an array or not. Having a non-array initializer for an unsized array will | |||
2529 | // result in an error later, so we don't generate an error message here. | |||
2530 | type->sizeUnsizedArrays(initializer->getType().getArraySizes()); | |||
2531 | } | |||
2532 | ||||
2533 | const TQualifier qualifier = type->getQualifier(); | |||
2534 | ||||
2535 | bool constError = false; | |||
2536 | if (qualifier == EvqConst) | |||
2537 | { | |||
2538 | if (EvqConst != initializer->getType().getQualifier()) | |||
2539 | { | |||
2540 | TInfoSinkBase reasonStream; | |||
2541 | reasonStream << "assigning non-constant to '" << *type << "'"; | |||
2542 | error(line, reasonStream.c_str(), "="); | |||
2543 | ||||
2544 | // We're still going to declare the variable to avoid extra error messages. | |||
2545 | type->setQualifier(EvqTemporary); | |||
2546 | constError = true; | |||
2547 | } | |||
2548 | } | |||
2549 | ||||
2550 | TVariable *variable = nullptr; | |||
2551 | if (!declareVariable(line, identifier, type, &variable)) | |||
2552 | { | |||
2553 | return false; | |||
2554 | } | |||
2555 | ||||
2556 | if (constError) | |||
2557 | { | |||
2558 | return false; | |||
2559 | } | |||
2560 | ||||
2561 | bool nonConstGlobalInitializers = | |||
2562 | IsExtensionEnabled(mDirectiveHandler.extensionBehavior(), | |||
2563 | TExtension::EXT_shader_non_constant_global_initializers); | |||
2564 | bool globalInitWarning = false; | |||
2565 | if (symbolTable.atGlobalLevel() && | |||
2566 | !ValidateGlobalInitializer(initializer, mShaderVersion, sh::IsWebGLBasedSpec(mShaderSpec), | |||
2567 | nonConstGlobalInitializers, &globalInitWarning)) | |||
2568 | { | |||
2569 | // Error message does not completely match behavior with ESSL 1.00, but | |||
2570 | // we want to steer developers towards only using constant expressions. | |||
2571 | error(line, "global variable initializers must be constant expressions", "="); | |||
2572 | return false; | |||
2573 | } | |||
2574 | if (globalInitWarning) | |||
2575 | { | |||
2576 | warning( | |||
2577 | line, | |||
2578 | "global variable initializers should be constant expressions " | |||
2579 | "(uniforms and globals are allowed in global initializers for legacy compatibility)", | |||
2580 | "="); | |||
2581 | } | |||
2582 | ||||
2583 | // identifier must be of type constant, a global, or a temporary | |||
2584 | if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) | |||
2585 | { | |||
2586 | error(line, " cannot initialize this type of qualifier ", | |||
2587 | variable->getType().getQualifierString()); | |||
2588 | return false; | |||
2589 | } | |||
2590 | ||||
2591 | TIntermSymbol *intermSymbol = new TIntermSymbol(variable); | |||
2592 | intermSymbol->setLine(line); | |||
2593 | ||||
2594 | if (!binaryOpCommonCheck(EOpInitialize, intermSymbol, initializer, line)) | |||
2595 | { | |||
2596 | assignError(line, "=", variable->getType(), initializer->getType()); | |||
2597 | return false; | |||
2598 | } | |||
2599 | ||||
2600 | if (qualifier == EvqConst) | |||
2601 | { | |||
2602 | // Save the constant folded value to the variable if possible. | |||
2603 | const TConstantUnion *constArray = initializer->getConstantValue(); | |||
2604 | if (constArray) | |||
2605 | { | |||
2606 | variable->shareConstPointer(constArray); | |||
2607 | if (initializer->getType().canReplaceWithConstantUnion()) | |||
2608 | { | |||
2609 | ASSERT(*initNode == nullptr)(*initNode == nullptr ? static_cast<void>(0) : (!((::gl ::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2609, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2609 << "): " << "*initNode == nullptr" )); | |||
2610 | return true; | |||
2611 | } | |||
2612 | } | |||
2613 | } | |||
2614 | ||||
2615 | *initNode = new TIntermBinary(EOpInitialize, intermSymbol, initializer); | |||
2616 | markStaticReadIfSymbol(initializer); | |||
2617 | (*initNode)->setLine(line); | |||
2618 | return true; | |||
2619 | } | |||
2620 | ||||
2621 | TIntermNode *TParseContext::addConditionInitializer(const TPublicType &pType, | |||
2622 | const ImmutableString &identifier, | |||
2623 | TIntermTyped *initializer, | |||
2624 | const TSourceLoc &loc) | |||
2625 | { | |||
2626 | checkIsScalarBool(loc, pType); | |||
2627 | TIntermBinary *initNode = nullptr; | |||
2628 | TType *type = new TType(pType); | |||
2629 | if (executeInitializer(loc, identifier, type, initializer, &initNode)) | |||
2630 | { | |||
2631 | // The initializer is valid. The init condition needs to have a node - either the | |||
2632 | // initializer node, or a constant node in case the initialized variable is const and won't | |||
2633 | // be recorded in the AST. | |||
2634 | if (initNode == nullptr) | |||
2635 | { | |||
2636 | return initializer; | |||
2637 | } | |||
2638 | else | |||
2639 | { | |||
2640 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
2641 | declaration->appendDeclarator(initNode); | |||
2642 | return declaration; | |||
2643 | } | |||
2644 | } | |||
2645 | return nullptr; | |||
2646 | } | |||
2647 | ||||
2648 | TIntermNode *TParseContext::addLoop(TLoopType type, | |||
2649 | TIntermNode *init, | |||
2650 | TIntermNode *cond, | |||
2651 | TIntermTyped *expr, | |||
2652 | TIntermNode *body, | |||
2653 | const TSourceLoc &line) | |||
2654 | { | |||
2655 | TIntermNode *node = nullptr; | |||
2656 | TIntermTyped *typedCond = nullptr; | |||
2657 | if (cond) | |||
2658 | { | |||
2659 | markStaticReadIfSymbol(cond); | |||
2660 | typedCond = cond->getAsTyped(); | |||
2661 | } | |||
2662 | if (expr) | |||
2663 | { | |||
2664 | markStaticReadIfSymbol(expr); | |||
2665 | } | |||
2666 | // In case the loop body was not parsed as a block and contains a statement that simply refers | |||
2667 | // to a variable, we need to mark it as statically used. | |||
2668 | if (body) | |||
2669 | { | |||
2670 | markStaticReadIfSymbol(body); | |||
2671 | } | |||
2672 | if (cond == nullptr || typedCond) | |||
2673 | { | |||
2674 | if (type == ELoopDoWhile && typedCond) | |||
2675 | { | |||
2676 | checkIsScalarBool(line, typedCond); | |||
2677 | } | |||
2678 | // In the case of other loops, it was checked before that the condition is a scalar boolean. | |||
2679 | ASSERT(mDiagnostics->numErrors() > 0 || typedCond == nullptr ||(mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond ->isArray() && !typedCond->isVector()) ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2681, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2681 << "): " << "mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && !typedCond->isVector())" )) | |||
2680 | (typedCond->getBasicType() == EbtBool && !typedCond->isArray() &&(mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond ->isArray() && !typedCond->isVector()) ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2681, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2681 << "): " << "mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && !typedCond->isVector())" )) | |||
2681 | !typedCond->isVector()))(mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond ->isArray() && !typedCond->isVector()) ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2681, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2681 << "): " << "mDiagnostics->numErrors() > 0 || typedCond == nullptr || (typedCond->getBasicType() == EbtBool && !typedCond->isArray() && !typedCond->isVector())" )); | |||
2682 | ||||
2683 | node = new TIntermLoop(type, init, typedCond, expr, EnsureBlock(body)); | |||
2684 | node->setLine(line); | |||
2685 | return node; | |||
2686 | } | |||
2687 | ||||
2688 | ASSERT(type != ELoopDoWhile)(type != ELoopDoWhile ? static_cast<void>(0) : (!((::gl ::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2688, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2688 << "): " << "type != ELoopDoWhile" )); | |||
2689 | ||||
2690 | TIntermDeclaration *declaration = cond->getAsDeclarationNode(); | |||
2691 | ASSERT(declaration)(declaration ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2691, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2691 << "): " << "declaration" )); | |||
2692 | TIntermBinary *declarator = declaration->getSequence()->front()->getAsBinaryNode(); | |||
2693 | ASSERT(declarator->getLeft()->getAsSymbolNode())(declarator->getLeft()->getAsSymbolNode() ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 2693, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 2693 << "): " << "declarator->getLeft()->getAsSymbolNode()" )); | |||
2694 | ||||
2695 | // The condition is a declaration. In the AST representation we don't support declarations as | |||
2696 | // loop conditions. Wrap the loop to a block that declares the condition variable and contains | |||
2697 | // the loop. | |||
2698 | TIntermBlock *block = new TIntermBlock(); | |||
2699 | ||||
2700 | TIntermDeclaration *declareCondition = new TIntermDeclaration(); | |||
2701 | declareCondition->appendDeclarator(declarator->getLeft()->deepCopy()); | |||
2702 | block->appendStatement(declareCondition); | |||
2703 | ||||
2704 | TIntermBinary *conditionInit = new TIntermBinary(EOpAssign, declarator->getLeft()->deepCopy(), | |||
2705 | declarator->getRight()->deepCopy()); | |||
2706 | TIntermLoop *loop = new TIntermLoop(type, init, conditionInit, expr, EnsureBlock(body)); | |||
2707 | block->appendStatement(loop); | |||
2708 | loop->setLine(line); | |||
2709 | block->setLine(line); | |||
2710 | return block; | |||
2711 | } | |||
2712 | ||||
2713 | TIntermNode *TParseContext::addIfElse(TIntermTyped *cond, | |||
2714 | TIntermNodePair code, | |||
2715 | const TSourceLoc &loc) | |||
2716 | { | |||
2717 | bool isScalarBool = checkIsScalarBool(loc, cond); | |||
2718 | // In case the conditional statements were not parsed as blocks and contain a statement that | |||
2719 | // simply refers to a variable, we need to mark them as statically used. | |||
2720 | if (code.node1) | |||
2721 | { | |||
2722 | markStaticReadIfSymbol(code.node1); | |||
2723 | } | |||
2724 | if (code.node2) | |||
2725 | { | |||
2726 | markStaticReadIfSymbol(code.node2); | |||
2727 | } | |||
2728 | ||||
2729 | // For compile time constant conditions, prune the code now. | |||
2730 | if (isScalarBool && cond->getAsConstantUnion()) | |||
2731 | { | |||
2732 | if (cond->getAsConstantUnion()->getBConst(0) == true) | |||
2733 | { | |||
2734 | return EnsureBlock(code.node1); | |||
2735 | } | |||
2736 | else | |||
2737 | { | |||
2738 | return EnsureBlock(code.node2); | |||
2739 | } | |||
2740 | } | |||
2741 | ||||
2742 | TIntermIfElse *node = new TIntermIfElse(cond, EnsureBlock(code.node1), EnsureBlock(code.node2)); | |||
2743 | markStaticReadIfSymbol(cond); | |||
2744 | node->setLine(loc); | |||
2745 | ||||
2746 | return node; | |||
2747 | } | |||
2748 | ||||
2749 | void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier) | |||
2750 | { | |||
2751 | checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision, | |||
2752 | typeSpecifier->getBasicType()); | |||
2753 | ||||
2754 | if (mShaderVersion < 300 && typeSpecifier->isArray()) | |||
2755 | { | |||
2756 | error(typeSpecifier->getLine(), "not supported", "first-class array"); | |||
2757 | typeSpecifier->clearArrayness(); | |||
2758 | } | |||
2759 | } | |||
2760 | ||||
2761 | TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, | |||
2762 | const TPublicType &typeSpecifier) | |||
2763 | { | |||
2764 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); | |||
2765 | ||||
2766 | TPublicType returnType = typeSpecifier; | |||
2767 | returnType.qualifier = typeQualifier.qualifier; | |||
2768 | returnType.invariant = typeQualifier.invariant; | |||
2769 | returnType.precise = typeQualifier.precise; | |||
2770 | returnType.layoutQualifier = typeQualifier.layoutQualifier; | |||
2771 | returnType.memoryQualifier = typeQualifier.memoryQualifier; | |||
2772 | returnType.precision = typeSpecifier.precision; | |||
2773 | ||||
2774 | if (typeQualifier.precision != EbpUndefined) | |||
2775 | { | |||
2776 | returnType.precision = typeQualifier.precision; | |||
2777 | } | |||
2778 | ||||
2779 | checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision, | |||
2780 | typeSpecifier.getBasicType()); | |||
2781 | ||||
2782 | checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier, | |||
2783 | typeSpecifier.getLine()); | |||
2784 | ||||
2785 | checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier); | |||
2786 | ||||
2787 | checkEarlyFragmentTestsIsNotSpecified(typeSpecifier.getLine(), | |||
2788 | returnType.layoutQualifier.earlyFragmentTests); | |||
2789 | ||||
2790 | if (returnType.qualifier == EvqSampleIn || returnType.qualifier == EvqSampleOut) | |||
2791 | { | |||
2792 | mSampleQualifierSpecified = true; | |||
2793 | } | |||
2794 | ||||
2795 | if (mShaderVersion < 300) | |||
2796 | { | |||
2797 | if (typeSpecifier.isArray()) | |||
2798 | { | |||
2799 | error(typeSpecifier.getLine(), "not supported", "first-class array"); | |||
2800 | returnType.clearArrayness(); | |||
2801 | } | |||
2802 | ||||
2803 | if (returnType.qualifier == EvqAttribute && | |||
2804 | (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) | |||
2805 | { | |||
2806 | error(typeSpecifier.getLine(), "cannot be bool or int", | |||
2807 | getQualifierString(returnType.qualifier)); | |||
2808 | } | |||
2809 | ||||
2810 | if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) && | |||
2811 | (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) | |||
2812 | { | |||
2813 | error(typeSpecifier.getLine(), "cannot be bool or int", | |||
2814 | getQualifierString(returnType.qualifier)); | |||
2815 | } | |||
2816 | } | |||
2817 | else | |||
2818 | { | |||
2819 | if (!returnType.layoutQualifier.isEmpty()) | |||
2820 | { | |||
2821 | checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout"); | |||
2822 | } | |||
2823 | if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || | |||
2824 | returnType.qualifier == EvqFragmentOut || returnType.qualifier == EvqFragmentInOut) | |||
2825 | { | |||
2826 | checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, | |||
2827 | typeSpecifier.getLine()); | |||
2828 | } | |||
2829 | if (returnType.qualifier == EvqComputeIn) | |||
2830 | { | |||
2831 | error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size", | |||
2832 | "in"); | |||
2833 | } | |||
2834 | } | |||
2835 | ||||
2836 | return returnType; | |||
2837 | } | |||
2838 | ||||
2839 | void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, | |||
2840 | const TPublicType &type, | |||
2841 | const TSourceLoc &qualifierLocation) | |||
2842 | { | |||
2843 | // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. | |||
2844 | if (type.getBasicType() == EbtBool) | |||
2845 | { | |||
2846 | error(qualifierLocation, "cannot be bool", getQualifierString(qualifier)); | |||
2847 | } | |||
2848 | ||||
2849 | // Specific restrictions apply for vertex shader inputs and fragment shader outputs. | |||
2850 | switch (qualifier) | |||
2851 | { | |||
2852 | case EvqVertexIn: | |||
2853 | // ESSL 3.00 section 4.3.4 | |||
2854 | if (type.isArray()) | |||
2855 | { | |||
2856 | error(qualifierLocation, "cannot be array", getQualifierString(qualifier)); | |||
2857 | } | |||
2858 | // Vertex inputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck | |||
2859 | return; | |||
2860 | case EvqFragmentOut: | |||
2861 | case EvqFragmentInOut: | |||
2862 | // ESSL 3.00 section 4.3.6 | |||
2863 | if (type.typeSpecifierNonArray.isMatrix()) | |||
2864 | { | |||
2865 | error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier)); | |||
2866 | } | |||
2867 | // Fragment outputs with a struct type are disallowed in nonEmptyDeclarationErrorCheck | |||
2868 | return; | |||
2869 | default: | |||
2870 | break; | |||
2871 | } | |||
2872 | ||||
2873 | // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of | |||
2874 | // restrictions. | |||
2875 | bool typeContainsIntegers = | |||
2876 | (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || | |||
2877 | type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); | |||
2878 | bool extendedShaderTypes = mShaderVersion >= 320 || | |||
2879 | isExtensionEnabled(TExtension::EXT_geometry_shader) || | |||
2880 | isExtensionEnabled(TExtension::OES_geometry_shader) || | |||
2881 | isExtensionEnabled(TExtension::EXT_tessellation_shader); | |||
2882 | if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut && | |||
2883 | (!extendedShaderTypes || mShaderType == GL_FRAGMENT_SHADER0x8B30)) | |||
2884 | { | |||
2885 | error(qualifierLocation, "must use 'flat' interpolation here", | |||
2886 | getQualifierString(qualifier)); | |||
2887 | } | |||
2888 | ||||
2889 | if (type.getBasicType() == EbtStruct) | |||
2890 | { | |||
2891 | // ESSL 3.00 sections 4.3.4 and 4.3.6. | |||
2892 | // These restrictions are only implied by the ESSL 3.00 spec, but | |||
2893 | // the ESSL 3.10 spec lists these restrictions explicitly. | |||
2894 | if (type.isArray()) | |||
2895 | { | |||
2896 | error(qualifierLocation, "cannot be an array of structures", | |||
2897 | getQualifierString(qualifier)); | |||
2898 | } | |||
2899 | if (type.isStructureContainingArrays()) | |||
2900 | { | |||
2901 | error(qualifierLocation, "cannot be a structure containing an array", | |||
2902 | getQualifierString(qualifier)); | |||
2903 | } | |||
2904 | if (type.isStructureContainingType(EbtStruct)) | |||
2905 | { | |||
2906 | error(qualifierLocation, "cannot be a structure containing a structure", | |||
2907 | getQualifierString(qualifier)); | |||
2908 | } | |||
2909 | if (type.isStructureContainingType(EbtBool)) | |||
2910 | { | |||
2911 | error(qualifierLocation, "cannot be a structure containing a bool", | |||
2912 | getQualifierString(qualifier)); | |||
2913 | } | |||
2914 | } | |||
2915 | } | |||
2916 | ||||
2917 | void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier) | |||
2918 | { | |||
2919 | if (qualifier.getType() == QtStorage) | |||
2920 | { | |||
2921 | const TStorageQualifierWrapper &storageQualifier = | |||
2922 | static_cast<const TStorageQualifierWrapper &>(qualifier); | |||
2923 | if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst && | |||
2924 | !symbolTable.atGlobalLevel()) | |||
2925 | { | |||
2926 | error(storageQualifier.getLine(), | |||
2927 | "Local variables can only use the const storage qualifier.", | |||
2928 | storageQualifier.getQualifierString()); | |||
2929 | } | |||
2930 | } | |||
2931 | } | |||
2932 | ||||
2933 | void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, | |||
2934 | const TSourceLoc &location) | |||
2935 | { | |||
2936 | const std::string reason( | |||
2937 | "Only allowed with shader storage blocks, variables declared within shader storage blocks " | |||
2938 | "and variables declared as image types."); | |||
2939 | if (memoryQualifier.readonly) | |||
2940 | { | |||
2941 | error(location, reason.c_str(), "readonly"); | |||
2942 | } | |||
2943 | if (memoryQualifier.writeonly) | |||
2944 | { | |||
2945 | error(location, reason.c_str(), "writeonly"); | |||
2946 | } | |||
2947 | if (memoryQualifier.coherent) | |||
2948 | { | |||
2949 | error(location, reason.c_str(), "coherent"); | |||
2950 | } | |||
2951 | if (memoryQualifier.restrictQualifier) | |||
2952 | { | |||
2953 | error(location, reason.c_str(), "restrict"); | |||
2954 | } | |||
2955 | if (memoryQualifier.volatileQualifier) | |||
2956 | { | |||
2957 | error(location, reason.c_str(), "volatile"); | |||
2958 | } | |||
2959 | } | |||
2960 | ||||
2961 | // Make sure there is no offset overlapping, and store the newly assigned offset to "type" in | |||
2962 | // intermediate tree. | |||
2963 | void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, | |||
2964 | const TSourceLoc &loc, | |||
2965 | TType *type) | |||
2966 | { | |||
2967 | const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct() | |||
2968 | : kAtomicCounterSize; | |||
2969 | TLayoutQualifier layoutQualifier = type->getLayoutQualifier(); | |||
2970 | auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding]; | |||
2971 | int offset; | |||
2972 | if (layoutQualifier.offset == -1 || forceAppend) | |||
2973 | { | |||
2974 | offset = bindingState.appendSpan(size); | |||
2975 | } | |||
2976 | else | |||
2977 | { | |||
2978 | offset = bindingState.insertSpan(layoutQualifier.offset, size); | |||
2979 | } | |||
2980 | if (offset == -1) | |||
2981 | { | |||
2982 | error(loc, "Offset overlapping", "atomic counter"); | |||
2983 | return; | |||
2984 | } | |||
2985 | layoutQualifier.offset = offset; | |||
2986 | type->setLayoutQualifier(layoutQualifier); | |||
2987 | } | |||
2988 | ||||
2989 | void TParseContext::checkAtomicCounterOffsetAlignment(const TSourceLoc &location, const TType &type) | |||
2990 | { | |||
2991 | TLayoutQualifier layoutQualifier = type.getLayoutQualifier(); | |||
2992 | ||||
2993 | // OpenGL ES 3.1 Table 6.5, Atomic counter offset must be a multiple of 4 | |||
2994 | if (layoutQualifier.offset % 4 != 0) | |||
2995 | { | |||
2996 | error(location, "Offset must be multiple of 4", "atomic counter"); | |||
2997 | } | |||
2998 | } | |||
2999 | ||||
3000 | void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, | |||
3001 | const ImmutableString &token, | |||
3002 | TType *type) | |||
3003 | { | |||
3004 | if (IsGeometryShaderInput(mShaderType, type->getQualifier())) | |||
3005 | { | |||
3006 | if (type->isArray() && type->getOutermostArraySize() == 0u) | |||
3007 | { | |||
3008 | // Set size for the unsized geometry shader inputs if they are declared after a valid | |||
3009 | // input primitive declaration. | |||
3010 | if (mGeometryShaderInputPrimitiveType != EptUndefined) | |||
3011 | { | |||
3012 | ASSERT(symbolTable.getGlInVariableWithArraySize() != nullptr)(symbolTable.getGlInVariableWithArraySize() != nullptr ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3012, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3012 << "): " << "symbolTable.getGlInVariableWithArraySize() != nullptr" )); | |||
3013 | type->sizeOutermostUnsizedArray( | |||
3014 | symbolTable.getGlInVariableWithArraySize()->getType().getOutermostArraySize()); | |||
3015 | } | |||
3016 | else | |||
3017 | { | |||
3018 | // [GLSL ES 3.2 SPEC Chapter 4.4.1.2] | |||
3019 | // An input can be declared without an array size if there is a previous layout | |||
3020 | // which specifies the size. | |||
3021 | warning(location, | |||
3022 | "Missing a valid input primitive declaration before declaring an unsized " | |||
3023 | "array input", | |||
3024 | "Deferred"); | |||
3025 | mDeferredArrayTypesToSize.push_back(type); | |||
3026 | } | |||
3027 | } | |||
3028 | else if (type->isArray()) | |||
3029 | { | |||
3030 | setGeometryShaderInputArraySize(type->getOutermostArraySize(), location); | |||
3031 | } | |||
3032 | else | |||
3033 | { | |||
3034 | error(location, "Geometry shader input variable must be declared as an array", token); | |||
3035 | } | |||
3036 | } | |||
3037 | } | |||
3038 | ||||
3039 | void TParseContext::checkTessellationShaderUnsizedArraysAndSetSize(const TSourceLoc &location, | |||
3040 | const ImmutableString &token, | |||
3041 | TType *type) | |||
3042 | { | |||
3043 | TQualifier qualifier = type->getQualifier(); | |||
3044 | if (!IsTessellationControlShaderOutput(mShaderType, qualifier) && | |||
3045 | !IsTessellationControlShaderInput(mShaderType, qualifier) && | |||
3046 | !IsTessellationEvaluationShaderInput(mShaderType, qualifier)) | |||
3047 | { | |||
3048 | return; | |||
3049 | } | |||
3050 | ||||
3051 | // Such variables must be declared as arrays or inside output blocks declared as arrays. | |||
3052 | if (!type->isArray()) | |||
3053 | { | |||
3054 | error(location, "Tessellation interface variables must be declared as an array", token); | |||
3055 | return; | |||
3056 | } | |||
3057 | ||||
3058 | // If a size is specified, it must match the maximum patch size. | |||
3059 | unsigned int outermostSize = type->getOutermostArraySize(); | |||
3060 | if (outermostSize == 0u) | |||
3061 | { | |||
3062 | switch (qualifier) | |||
3063 | { | |||
3064 | case EvqTessControlIn: | |||
3065 | case EvqTessEvaluationIn: | |||
3066 | case EvqFlatIn: | |||
3067 | case EvqCentroidIn: | |||
3068 | case EvqSmoothIn: | |||
3069 | case EvqSampleIn: | |||
3070 | // Declaring an array size is optional. If no size is specified, it will be taken | |||
3071 | // from the implementation-dependent maximum patch size (gl_MaxPatchVertices). | |||
3072 | ASSERT(mMaxPatchVertices > 0)(mMaxPatchVertices > 0 ? static_cast<void>(0) : (!(( ::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3072, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3072 << "): " << "mMaxPatchVertices > 0" )); | |||
3073 | type->sizeOutermostUnsizedArray(mMaxPatchVertices); | |||
3074 | break; | |||
3075 | case EvqTessControlOut: | |||
3076 | case EvqFlatOut: | |||
3077 | case EvqCentroidOut: | |||
3078 | case EvqSmoothOut: | |||
3079 | case EvqSampleOut: | |||
3080 | // Declaring an array size is optional. If no size is specified, it will be taken | |||
3081 | // from output patch size declared in the shader. If the patch size is not yet | |||
3082 | // declared, this is deferred until such time as it does. | |||
3083 | if (mTessControlShaderOutputVertices == 0) | |||
3084 | { | |||
3085 | mDeferredArrayTypesToSize.push_back(type); | |||
3086 | } | |||
3087 | else | |||
3088 | { | |||
3089 | type->sizeOutermostUnsizedArray(mTessControlShaderOutputVertices); | |||
3090 | } | |||
3091 | break; | |||
3092 | default: | |||
3093 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3093, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3093 << ")"; } while (0); | |||
3094 | break; | |||
3095 | } | |||
3096 | return; | |||
3097 | } | |||
3098 | ||||
3099 | if (IsTessellationControlShaderInput(mShaderType, qualifier) || | |||
3100 | IsTessellationEvaluationShaderInput(mShaderType, qualifier)) | |||
3101 | { | |||
3102 | if (outermostSize != static_cast<unsigned int>(mMaxPatchVertices)) | |||
3103 | { | |||
3104 | error(location, | |||
3105 | "If a size is specified for a tessellation control or evaluation user-defined " | |||
3106 | "input variable, it must match the maximum patch size (gl_MaxPatchVertices).", | |||
3107 | token); | |||
3108 | } | |||
3109 | } | |||
3110 | else if (IsTessellationControlShaderOutput(mShaderType, qualifier)) | |||
3111 | { | |||
3112 | if (outermostSize != static_cast<unsigned int>(mTessControlShaderOutputVertices) && | |||
3113 | mTessControlShaderOutputVertices != 0) | |||
3114 | { | |||
3115 | error(location, | |||
3116 | "If a size is specified for a tessellation control user-defined per-vertex " | |||
3117 | "output variable, it must match the the number of vertices in the output " | |||
3118 | "patch.", | |||
3119 | token); | |||
3120 | } | |||
3121 | } | |||
3122 | } | |||
3123 | ||||
3124 | TIntermDeclaration *TParseContext::parseSingleDeclaration( | |||
3125 | TPublicType &publicType, | |||
3126 | const TSourceLoc &identifierOrTypeLocation, | |||
3127 | const ImmutableString &identifier) | |||
3128 | { | |||
3129 | TType *type = new TType(publicType); | |||
3130 | if (mCompileOptions.flattenPragmaSTDGLInvariantAll && | |||
3131 | mDirectiveHandler.pragma().stdgl.invariantAll) | |||
3132 | { | |||
3133 | TQualifier qualifier = type->getQualifier(); | |||
3134 | ||||
3135 | // The directive handler has already taken care of rejecting invalid uses of this pragma | |||
3136 | // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all | |||
3137 | // affected variable declarations: | |||
3138 | // | |||
3139 | // 1. Built-in special variables which are inputs to the fragment shader. (These are handled | |||
3140 | // elsewhere, in TranslatorGLSL.) | |||
3141 | // | |||
3142 | // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It | |||
3143 | // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but | |||
3144 | // the way this is currently implemented we have to enable this compiler option before | |||
3145 | // parsing the shader and determining the shading language version it uses. If this were | |||
3146 | // implemented as a post-pass, the workaround could be more targeted. | |||
3147 | if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut) | |||
3148 | { | |||
3149 | type->setInvariant(true); | |||
3150 | } | |||
3151 | } | |||
3152 | ||||
3153 | checkGeometryShaderInputAndSetArraySize(identifierOrTypeLocation, identifier, type); | |||
3154 | checkTessellationShaderUnsizedArraysAndSetSize(identifierOrTypeLocation, identifier, type); | |||
3155 | ||||
3156 | declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, | |||
3157 | identifierOrTypeLocation); | |||
3158 | ||||
3159 | bool emptyDeclaration = (identifier == ""); | |||
3160 | mDeferredNonEmptyDeclarationErrorCheck = emptyDeclaration; | |||
3161 | ||||
3162 | TIntermSymbol *symbol = nullptr; | |||
3163 | if (emptyDeclaration) | |||
3164 | { | |||
3165 | emptyDeclarationErrorCheck(*type, identifierOrTypeLocation); | |||
3166 | // In most cases we don't need to create a symbol node for an empty declaration. | |||
3167 | // But if the empty declaration is declaring a struct type, the symbol node will store that. | |||
3168 | if (type->getBasicType() == EbtStruct) | |||
3169 | { | |||
3170 | TVariable *emptyVariable = | |||
3171 | new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty); | |||
3172 | symbol = new TIntermSymbol(emptyVariable); | |||
3173 | } | |||
3174 | else if (IsAtomicCounter(publicType.getBasicType())) | |||
3175 | { | |||
3176 | setAtomicCounterBindingDefaultOffset(publicType, identifierOrTypeLocation); | |||
3177 | } | |||
3178 | } | |||
3179 | else | |||
3180 | { | |||
3181 | nonEmptyDeclarationErrorCheck(publicType, identifierOrTypeLocation); | |||
3182 | ||||
3183 | checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, type); | |||
3184 | ||||
3185 | if (IsAtomicCounter(type->getBasicType())) | |||
3186 | { | |||
3187 | checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, type); | |||
3188 | ||||
3189 | checkAtomicCounterOffsetAlignment(identifierOrTypeLocation, *type); | |||
3190 | } | |||
3191 | ||||
3192 | TVariable *variable = nullptr; | |||
3193 | if (declareVariable(identifierOrTypeLocation, identifier, type, &variable)) | |||
3194 | { | |||
3195 | symbol = new TIntermSymbol(variable); | |||
3196 | } | |||
3197 | } | |||
3198 | ||||
3199 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
3200 | declaration->setLine(identifierOrTypeLocation); | |||
3201 | if (symbol) | |||
3202 | { | |||
3203 | symbol->setLine(identifierOrTypeLocation); | |||
3204 | declaration->appendDeclarator(symbol); | |||
3205 | } | |||
3206 | return declaration; | |||
3207 | } | |||
3208 | ||||
3209 | TIntermDeclaration *TParseContext::parseSingleArrayDeclaration( | |||
3210 | TPublicType &elementType, | |||
3211 | const TSourceLoc &identifierLocation, | |||
3212 | const ImmutableString &identifier, | |||
3213 | const TSourceLoc &indexLocation, | |||
3214 | const TVector<unsigned int> &arraySizes) | |||
3215 | { | |||
3216 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3217 | ||||
3218 | declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, | |||
3219 | identifierLocation); | |||
3220 | ||||
3221 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); | |||
3222 | ||||
3223 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); | |||
3224 | ||||
3225 | TType *arrayType = new TType(elementType); | |||
3226 | arrayType->makeArrays(arraySizes); | |||
3227 | ||||
3228 | checkArrayOfArraysInOut(indexLocation, elementType, *arrayType); | |||
3229 | ||||
3230 | checkGeometryShaderInputAndSetArraySize(indexLocation, identifier, arrayType); | |||
3231 | checkTessellationShaderUnsizedArraysAndSetSize(indexLocation, identifier, arrayType); | |||
3232 | ||||
3233 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); | |||
3234 | ||||
3235 | if (IsAtomicCounter(arrayType->getBasicType())) | |||
3236 | { | |||
3237 | checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, arrayType); | |||
3238 | ||||
3239 | checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); | |||
3240 | } | |||
3241 | ||||
3242 | adjustRedeclaredBuiltInType(identifier, arrayType); | |||
3243 | ||||
3244 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
3245 | declaration->setLine(identifierLocation); | |||
3246 | ||||
3247 | TVariable *variable = nullptr; | |||
3248 | if (declareVariable(identifierLocation, identifier, arrayType, &variable)) | |||
3249 | { | |||
3250 | TIntermSymbol *symbol = new TIntermSymbol(variable); | |||
3251 | symbol->setLine(identifierLocation); | |||
3252 | declaration->appendDeclarator(symbol); | |||
3253 | } | |||
3254 | ||||
3255 | return declaration; | |||
3256 | } | |||
3257 | ||||
3258 | TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, | |||
3259 | const TSourceLoc &identifierLocation, | |||
3260 | const ImmutableString &identifier, | |||
3261 | const TSourceLoc &initLocation, | |||
3262 | TIntermTyped *initializer) | |||
3263 | { | |||
3264 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3265 | ||||
3266 | declarationQualifierErrorCheck(publicType.qualifier, publicType.layoutQualifier, | |||
3267 | identifierLocation); | |||
3268 | ||||
3269 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); | |||
3270 | ||||
3271 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
3272 | declaration->setLine(identifierLocation); | |||
3273 | ||||
3274 | TIntermBinary *initNode = nullptr; | |||
3275 | TType *type = new TType(publicType); | |||
3276 | if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) | |||
3277 | { | |||
3278 | if (initNode) | |||
3279 | { | |||
3280 | declaration->appendDeclarator(initNode); | |||
3281 | } | |||
3282 | else if (publicType.isStructSpecifier()) | |||
3283 | { | |||
3284 | // The initialization got constant folded. If it's a struct, declare the struct anyway. | |||
3285 | TVariable *emptyVariable = | |||
3286 | new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty); | |||
3287 | TIntermSymbol *symbol = new TIntermSymbol(emptyVariable); | |||
3288 | symbol->setLine(publicType.getLine()); | |||
3289 | declaration->appendDeclarator(symbol); | |||
3290 | } | |||
3291 | } | |||
3292 | return declaration; | |||
3293 | } | |||
3294 | ||||
3295 | TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration( | |||
3296 | TPublicType &elementType, | |||
3297 | const TSourceLoc &identifierLocation, | |||
3298 | const ImmutableString &identifier, | |||
3299 | const TSourceLoc &indexLocation, | |||
3300 | const TVector<unsigned int> &arraySizes, | |||
3301 | const TSourceLoc &initLocation, | |||
3302 | TIntermTyped *initializer) | |||
3303 | { | |||
3304 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3305 | ||||
3306 | declarationQualifierErrorCheck(elementType.qualifier, elementType.layoutQualifier, | |||
3307 | identifierLocation); | |||
3308 | ||||
3309 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); | |||
3310 | ||||
3311 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); | |||
3312 | ||||
3313 | TType *arrayType = new TType(elementType); | |||
3314 | arrayType->makeArrays(arraySizes); | |||
3315 | ||||
3316 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
3317 | declaration->setLine(identifierLocation); | |||
3318 | ||||
3319 | // initNode will correspond to the whole of "type b[n] = initializer". | |||
3320 | TIntermBinary *initNode = nullptr; | |||
3321 | if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) | |||
3322 | { | |||
3323 | if (initNode) | |||
3324 | { | |||
3325 | declaration->appendDeclarator(initNode); | |||
3326 | } | |||
3327 | } | |||
3328 | ||||
3329 | return declaration; | |||
3330 | } | |||
3331 | ||||
3332 | TIntermGlobalQualifierDeclaration *TParseContext::parseGlobalQualifierDeclaration( | |||
3333 | const TTypeQualifierBuilder &typeQualifierBuilder, | |||
3334 | const TSourceLoc &identifierLoc, | |||
3335 | const ImmutableString &identifier, | |||
3336 | const TSymbol *symbol) | |||
3337 | { | |||
3338 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); | |||
3339 | ||||
3340 | if (!typeQualifier.invariant && !typeQualifier.precise) | |||
3341 | { | |||
3342 | error(identifierLoc, "Expected invariant or precise", identifier); | |||
3343 | return nullptr; | |||
3344 | } | |||
3345 | if (typeQualifier.invariant && !checkIsAtGlobalLevel(identifierLoc, "invariant varying")) | |||
3346 | { | |||
3347 | return nullptr; | |||
3348 | } | |||
3349 | if (!symbol) | |||
3350 | { | |||
3351 | error(identifierLoc, "undeclared identifier declared as invariant or precise", identifier); | |||
3352 | return nullptr; | |||
3353 | } | |||
3354 | if (!IsQualifierUnspecified(typeQualifier.qualifier)) | |||
3355 | { | |||
3356 | error(identifierLoc, "invariant or precise declaration specifies qualifier", | |||
3357 | getQualifierString(typeQualifier.qualifier)); | |||
3358 | } | |||
3359 | if (typeQualifier.precision != EbpUndefined) | |||
3360 | { | |||
3361 | error(identifierLoc, "invariant or precise declaration specifies precision", | |||
3362 | getPrecisionString(typeQualifier.precision)); | |||
3363 | } | |||
3364 | if (!typeQualifier.layoutQualifier.isEmpty()) | |||
3365 | { | |||
3366 | error(identifierLoc, "invariant or precise declaration specifies layout", "'layout'"); | |||
3367 | } | |||
3368 | ||||
3369 | const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); | |||
3370 | if (!variable) | |||
3371 | { | |||
3372 | return nullptr; | |||
3373 | } | |||
3374 | const TType &type = variable->getType(); | |||
3375 | ||||
3376 | checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(), | |||
3377 | typeQualifier.line); | |||
3378 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); | |||
3379 | ||||
3380 | symbolTable.addInvariantVarying(*variable); | |||
3381 | ||||
3382 | TIntermSymbol *intermSymbol = new TIntermSymbol(variable); | |||
3383 | intermSymbol->setLine(identifierLoc); | |||
3384 | ||||
3385 | return new TIntermGlobalQualifierDeclaration(intermSymbol, typeQualifier.precise, | |||
3386 | identifierLoc); | |||
3387 | } | |||
3388 | ||||
3389 | void TParseContext::parseDeclarator(TPublicType &publicType, | |||
3390 | const TSourceLoc &identifierLocation, | |||
3391 | const ImmutableString &identifier, | |||
3392 | TIntermDeclaration *declarationOut) | |||
3393 | { | |||
3394 | // If the declaration starting this declarator list was empty (example: int,), some checks were | |||
3395 | // not performed. | |||
3396 | if (mDeferredNonEmptyDeclarationErrorCheck) | |||
3397 | { | |||
3398 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); | |||
3399 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3400 | } | |||
3401 | ||||
3402 | checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); | |||
3403 | ||||
3404 | TType *type = new TType(publicType); | |||
3405 | ||||
3406 | checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, type); | |||
3407 | checkTessellationShaderUnsizedArraysAndSetSize(identifierLocation, identifier, type); | |||
3408 | ||||
3409 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, type); | |||
3410 | ||||
3411 | if (IsAtomicCounter(type->getBasicType())) | |||
3412 | { | |||
3413 | checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, type); | |||
3414 | ||||
3415 | checkAtomicCounterOffsetAlignment(identifierLocation, *type); | |||
3416 | } | |||
3417 | ||||
3418 | adjustRedeclaredBuiltInType(identifier, type); | |||
3419 | ||||
3420 | TVariable *variable = nullptr; | |||
3421 | if (declareVariable(identifierLocation, identifier, type, &variable)) | |||
3422 | { | |||
3423 | TIntermSymbol *symbol = new TIntermSymbol(variable); | |||
3424 | symbol->setLine(identifierLocation); | |||
3425 | declarationOut->appendDeclarator(symbol); | |||
3426 | } | |||
3427 | } | |||
3428 | ||||
3429 | void TParseContext::parseArrayDeclarator(TPublicType &elementType, | |||
3430 | const TSourceLoc &identifierLocation, | |||
3431 | const ImmutableString &identifier, | |||
3432 | const TSourceLoc &arrayLocation, | |||
3433 | const TVector<unsigned int> &arraySizes, | |||
3434 | TIntermDeclaration *declarationOut) | |||
3435 | { | |||
3436 | // If the declaration starting this declarator list was empty (example: int,), some checks were | |||
3437 | // not performed. | |||
3438 | if (mDeferredNonEmptyDeclarationErrorCheck) | |||
3439 | { | |||
3440 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); | |||
3441 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3442 | } | |||
3443 | ||||
3444 | checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); | |||
3445 | ||||
3446 | if (checkIsValidTypeAndQualifierForArray(arrayLocation, elementType)) | |||
3447 | { | |||
3448 | TType *arrayType = new TType(elementType); | |||
3449 | arrayType->makeArrays(arraySizes); | |||
3450 | ||||
3451 | checkGeometryShaderInputAndSetArraySize(identifierLocation, identifier, arrayType); | |||
3452 | checkTessellationShaderUnsizedArraysAndSetSize(identifierLocation, identifier, arrayType); | |||
3453 | ||||
3454 | checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, arrayType); | |||
3455 | ||||
3456 | if (IsAtomicCounter(arrayType->getBasicType())) | |||
3457 | { | |||
3458 | checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, arrayType); | |||
3459 | ||||
3460 | checkAtomicCounterOffsetAlignment(identifierLocation, *arrayType); | |||
3461 | } | |||
3462 | ||||
3463 | adjustRedeclaredBuiltInType(identifier, arrayType); | |||
3464 | ||||
3465 | TVariable *variable = nullptr; | |||
3466 | if (declareVariable(identifierLocation, identifier, arrayType, &variable)) | |||
3467 | { | |||
3468 | TIntermSymbol *symbol = new TIntermSymbol(variable); | |||
3469 | symbol->setLine(identifierLocation); | |||
3470 | declarationOut->appendDeclarator(symbol); | |||
3471 | } | |||
3472 | } | |||
3473 | } | |||
3474 | ||||
3475 | void TParseContext::parseInitDeclarator(const TPublicType &publicType, | |||
3476 | const TSourceLoc &identifierLocation, | |||
3477 | const ImmutableString &identifier, | |||
3478 | const TSourceLoc &initLocation, | |||
3479 | TIntermTyped *initializer, | |||
3480 | TIntermDeclaration *declarationOut) | |||
3481 | { | |||
3482 | // If the declaration starting this declarator list was empty (example: int,), some checks were | |||
3483 | // not performed. | |||
3484 | if (mDeferredNonEmptyDeclarationErrorCheck) | |||
3485 | { | |||
3486 | nonEmptyDeclarationErrorCheck(publicType, identifierLocation); | |||
3487 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3488 | } | |||
3489 | ||||
3490 | checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); | |||
3491 | ||||
3492 | TIntermBinary *initNode = nullptr; | |||
3493 | TType *type = new TType(publicType); | |||
3494 | if (executeInitializer(identifierLocation, identifier, type, initializer, &initNode)) | |||
3495 | { | |||
3496 | // | |||
3497 | // build the intermediate representation | |||
3498 | // | |||
3499 | if (initNode) | |||
3500 | { | |||
3501 | declarationOut->appendDeclarator(initNode); | |||
3502 | } | |||
3503 | } | |||
3504 | } | |||
3505 | ||||
3506 | void TParseContext::parseArrayInitDeclarator(const TPublicType &elementType, | |||
3507 | const TSourceLoc &identifierLocation, | |||
3508 | const ImmutableString &identifier, | |||
3509 | const TSourceLoc &indexLocation, | |||
3510 | const TVector<unsigned int> &arraySizes, | |||
3511 | const TSourceLoc &initLocation, | |||
3512 | TIntermTyped *initializer, | |||
3513 | TIntermDeclaration *declarationOut) | |||
3514 | { | |||
3515 | // If the declaration starting this declarator list was empty (example: int,), some checks were | |||
3516 | // not performed. | |||
3517 | if (mDeferredNonEmptyDeclarationErrorCheck) | |||
3518 | { | |||
3519 | nonEmptyDeclarationErrorCheck(elementType, identifierLocation); | |||
3520 | mDeferredNonEmptyDeclarationErrorCheck = false; | |||
3521 | } | |||
3522 | ||||
3523 | checkDeclaratorLocationIsNotSpecified(identifierLocation, elementType); | |||
3524 | ||||
3525 | checkIsValidTypeAndQualifierForArray(indexLocation, elementType); | |||
3526 | ||||
3527 | TType *arrayType = new TType(elementType); | |||
3528 | arrayType->makeArrays(arraySizes); | |||
3529 | ||||
3530 | // initNode will correspond to the whole of "b[n] = initializer". | |||
3531 | TIntermBinary *initNode = nullptr; | |||
3532 | if (executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) | |||
3533 | { | |||
3534 | if (initNode) | |||
3535 | { | |||
3536 | declarationOut->appendDeclarator(initNode); | |||
3537 | } | |||
3538 | } | |||
3539 | } | |||
3540 | ||||
3541 | TIntermNode *TParseContext::addEmptyStatement(const TSourceLoc &location) | |||
3542 | { | |||
3543 | // It's simpler to parse an empty statement as a constant expression rather than having a | |||
3544 | // different type of node just for empty statements, that will be pruned from the AST anyway. | |||
3545 | TIntermNode *node = CreateZeroNode(TType(EbtInt, EbpMedium)); | |||
3546 | node->setLine(location); | |||
3547 | return node; | |||
3548 | } | |||
3549 | ||||
3550 | void TParseContext::setAtomicCounterBindingDefaultOffset(const TPublicType &publicType, | |||
3551 | const TSourceLoc &location) | |||
3552 | { | |||
3553 | const TLayoutQualifier &layoutQualifier = publicType.layoutQualifier; | |||
3554 | checkAtomicCounterBindingIsValid(location, layoutQualifier.binding); | |||
3555 | if (layoutQualifier.binding == -1 || layoutQualifier.offset == -1) | |||
3556 | { | |||
3557 | error(location, "Requires both binding and offset", "layout"); | |||
3558 | return; | |||
3559 | } | |||
3560 | mAtomicCounterBindingStates[layoutQualifier.binding].setDefaultOffset(layoutQualifier.offset); | |||
3561 | } | |||
3562 | ||||
3563 | void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision, | |||
3564 | const TPublicType &type, | |||
3565 | const TSourceLoc &loc) | |||
3566 | { | |||
3567 | if ((precision == EbpHigh) && (getShaderType() == GL_FRAGMENT_SHADER0x8B30) && | |||
3568 | !getFragmentPrecisionHigh()) | |||
3569 | { | |||
3570 | error(loc, "precision is not supported in fragment shader", "highp"); | |||
3571 | } | |||
3572 | ||||
3573 | if (!CanSetDefaultPrecisionOnType(type)) | |||
3574 | { | |||
3575 | error(loc, "illegal type argument for default precision qualifier", | |||
3576 | getBasicString(type.getBasicType())); | |||
3577 | return; | |||
3578 | } | |||
3579 | symbolTable.setDefaultPrecision(type.getBasicType(), precision); | |||
3580 | } | |||
3581 | ||||
3582 | bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier) | |||
3583 | { | |||
3584 | switch (typeQualifier.layoutQualifier.primitiveType) | |||
3585 | { | |||
3586 | case EptLines: | |||
3587 | case EptLinesAdjacency: | |||
3588 | case EptTriangles: | |||
3589 | case EptTrianglesAdjacency: | |||
3590 | return typeQualifier.qualifier == EvqGeometryIn; | |||
3591 | ||||
3592 | case EptLineStrip: | |||
3593 | case EptTriangleStrip: | |||
3594 | return typeQualifier.qualifier == EvqGeometryOut; | |||
3595 | ||||
3596 | case EptPoints: | |||
3597 | return true; | |||
3598 | ||||
3599 | default: | |||
3600 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3600, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3600 << ")"; } while (0); | |||
3601 | return false; | |||
3602 | } | |||
3603 | } | |||
3604 | ||||
3605 | void TParseContext::setGeometryShaderInputArraySize(unsigned int inputArraySize, | |||
3606 | const TSourceLoc &line) | |||
3607 | { | |||
3608 | if (!symbolTable.setGlInArraySize(inputArraySize)) | |||
3609 | { | |||
3610 | error(line, | |||
3611 | "Array size or input primitive declaration doesn't match the size of earlier sized " | |||
3612 | "array inputs.", | |||
3613 | "layout"); | |||
3614 | } | |||
3615 | mGeometryInputArraySize = inputArraySize; | |||
3616 | } | |||
3617 | ||||
3618 | bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier) | |||
3619 | { | |||
3620 | ASSERT(typeQualifier.qualifier == EvqGeometryIn)(typeQualifier.qualifier == EvqGeometryIn ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3620, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3620 << "): " << "typeQualifier.qualifier == EvqGeometryIn" )); | |||
3621 | ||||
3622 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; | |||
3623 | ||||
3624 | if (layoutQualifier.maxVertices != -1) | |||
3625 | { | |||
3626 | error(typeQualifier.line, | |||
3627 | "max_vertices can only be declared in 'out' layout in a geometry shader", "layout"); | |||
3628 | return false; | |||
3629 | } | |||
3630 | ||||
3631 | // Set mGeometryInputPrimitiveType if exists | |||
3632 | if (layoutQualifier.primitiveType != EptUndefined) | |||
3633 | { | |||
3634 | if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) | |||
3635 | { | |||
3636 | error(typeQualifier.line, "invalid primitive type for 'in' layout", "layout"); | |||
3637 | return false; | |||
3638 | } | |||
3639 | ||||
3640 | if (mGeometryShaderInputPrimitiveType == EptUndefined) | |||
3641 | { | |||
3642 | mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType; | |||
3643 | setGeometryShaderInputArraySize( | |||
3644 | GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType), | |||
3645 | typeQualifier.line); | |||
3646 | } | |||
3647 | else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType) | |||
3648 | { | |||
3649 | error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration", | |||
3650 | "layout"); | |||
3651 | return false; | |||
3652 | } | |||
3653 | ||||
3654 | // Size any implicitly sized arrays that have already been declared. | |||
3655 | for (TType *type : mDeferredArrayTypesToSize) | |||
3656 | { | |||
3657 | type->sizeOutermostUnsizedArray( | |||
3658 | symbolTable.getGlInVariableWithArraySize()->getType().getOutermostArraySize()); | |||
3659 | } | |||
3660 | mDeferredArrayTypesToSize.clear(); | |||
3661 | } | |||
3662 | ||||
3663 | // Set mGeometryInvocations if exists | |||
3664 | if (layoutQualifier.invocations > 0) | |||
3665 | { | |||
3666 | if (mGeometryShaderInvocations == 0) | |||
3667 | { | |||
3668 | mGeometryShaderInvocations = layoutQualifier.invocations; | |||
3669 | } | |||
3670 | else if (mGeometryShaderInvocations != layoutQualifier.invocations) | |||
3671 | { | |||
3672 | error(typeQualifier.line, "invocations contradicts to the earlier declaration", | |||
3673 | "layout"); | |||
3674 | return false; | |||
3675 | } | |||
3676 | } | |||
3677 | ||||
3678 | return true; | |||
3679 | } | |||
3680 | ||||
3681 | bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier) | |||
3682 | { | |||
3683 | ASSERT(typeQualifier.qualifier == EvqGeometryOut)(typeQualifier.qualifier == EvqGeometryOut ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3683, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3683 << "): " << "typeQualifier.qualifier == EvqGeometryOut" )); | |||
3684 | ||||
3685 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; | |||
3686 | ||||
3687 | if (layoutQualifier.invocations > 0) | |||
3688 | { | |||
3689 | error(typeQualifier.line, | |||
3690 | "invocations can only be declared in 'in' layout in a geometry shader", "layout"); | |||
3691 | return false; | |||
3692 | } | |||
3693 | ||||
3694 | // Set mGeometryOutputPrimitiveType if exists | |||
3695 | if (layoutQualifier.primitiveType != EptUndefined) | |||
3696 | { | |||
3697 | if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier)) | |||
3698 | { | |||
3699 | error(typeQualifier.line, "invalid primitive type for 'out' layout", "layout"); | |||
3700 | return false; | |||
3701 | } | |||
3702 | ||||
3703 | if (mGeometryShaderOutputPrimitiveType == EptUndefined) | |||
3704 | { | |||
3705 | mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType; | |||
3706 | } | |||
3707 | else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType) | |||
3708 | { | |||
3709 | error(typeQualifier.line, | |||
3710 | "primitive doesn't match earlier output primitive declaration", "layout"); | |||
3711 | return false; | |||
3712 | } | |||
3713 | } | |||
3714 | ||||
3715 | // Set mGeometryMaxVertices if exists | |||
3716 | if (layoutQualifier.maxVertices > -1) | |||
3717 | { | |||
3718 | if (mGeometryShaderMaxVertices == -1) | |||
3719 | { | |||
3720 | mGeometryShaderMaxVertices = layoutQualifier.maxVertices; | |||
3721 | } | |||
3722 | else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices) | |||
3723 | { | |||
3724 | error(typeQualifier.line, "max_vertices contradicts to the earlier declaration", | |||
3725 | "layout"); | |||
3726 | return false; | |||
3727 | } | |||
3728 | } | |||
3729 | ||||
3730 | return true; | |||
3731 | } | |||
3732 | ||||
3733 | bool TParseContext::parseTessControlShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier) | |||
3734 | { | |||
3735 | ASSERT(typeQualifier.qualifier == EvqTessControlOut)(typeQualifier.qualifier == EvqTessControlOut ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3735, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3735 << "): " << "typeQualifier.qualifier == EvqTessControlOut" )); | |||
3736 | ||||
3737 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; | |||
3738 | ||||
3739 | if (layoutQualifier.vertices == 0) | |||
3740 | { | |||
3741 | error(typeQualifier.line, "No vertices specified", "layout"); | |||
3742 | return false; | |||
3743 | } | |||
3744 | ||||
3745 | // Set mTessControlShaderOutputVertices if exists | |||
3746 | if (mTessControlShaderOutputVertices == 0) | |||
3747 | { | |||
3748 | mTessControlShaderOutputVertices = layoutQualifier.vertices; | |||
3749 | ||||
3750 | // Size any implicitly sized arrays that have already been declared. | |||
3751 | for (TType *type : mDeferredArrayTypesToSize) | |||
3752 | { | |||
3753 | type->sizeOutermostUnsizedArray(mTessControlShaderOutputVertices); | |||
3754 | } | |||
3755 | mDeferredArrayTypesToSize.clear(); | |||
3756 | } | |||
3757 | else | |||
3758 | { | |||
3759 | error(typeQualifier.line, "Duplicated vertices specified", "layout"); | |||
3760 | } | |||
3761 | return true; | |||
3762 | } | |||
3763 | ||||
3764 | bool TParseContext::parseTessEvaluationShaderInputLayoutQualifier( | |||
3765 | const TTypeQualifier &typeQualifier) | |||
3766 | { | |||
3767 | ASSERT(typeQualifier.qualifier == EvqTessEvaluationIn)(typeQualifier.qualifier == EvqTessEvaluationIn ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 3767, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 3767 << "): " << "typeQualifier.qualifier == EvqTessEvaluationIn" )); | |||
3768 | ||||
3769 | const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier; | |||
3770 | ||||
3771 | // Set mTessEvaluationShaderInputPrimitiveType if exists | |||
3772 | if (layoutQualifier.tesPrimitiveType != EtetUndefined) | |||
3773 | { | |||
3774 | if (mTessEvaluationShaderInputPrimitiveType == EtetUndefined) | |||
3775 | { | |||
3776 | mTessEvaluationShaderInputPrimitiveType = layoutQualifier.tesPrimitiveType; | |||
3777 | } | |||
3778 | else | |||
3779 | { | |||
3780 | error(typeQualifier.line, "Duplicated primitive type declaration", "layout"); | |||
3781 | } | |||
3782 | } | |||
3783 | // Set mTessEvaluationShaderVertexSpacingType if exists | |||
3784 | if (layoutQualifier.tesVertexSpacingType != EtetUndefined) | |||
3785 | { | |||
3786 | if (mTessEvaluationShaderInputVertexSpacingType == EtetUndefined) | |||
3787 | { | |||
3788 | mTessEvaluationShaderInputVertexSpacingType = layoutQualifier.tesVertexSpacingType; | |||
3789 | } | |||
3790 | else | |||
3791 | { | |||
3792 | error(typeQualifier.line, "Duplicated vertex spacing declaration", "layout"); | |||
3793 | } | |||
3794 | } | |||
3795 | // Set mTessEvaluationShaderInputOrderingType if exists | |||
3796 | if (layoutQualifier.tesOrderingType != EtetUndefined) | |||
3797 | { | |||
3798 | if (mTessEvaluationShaderInputOrderingType == EtetUndefined) | |||
3799 | { | |||
3800 | mTessEvaluationShaderInputOrderingType = layoutQualifier.tesOrderingType; | |||
3801 | } | |||
3802 | else | |||
3803 | { | |||
3804 | error(typeQualifier.line, "Duplicated ordering declaration", "layout"); | |||
3805 | } | |||
3806 | } | |||
3807 | // Set mTessEvaluationShaderInputPointType if exists | |||
3808 | if (layoutQualifier.tesPointType != EtetUndefined) | |||
3809 | { | |||
3810 | if (mTessEvaluationShaderInputPointType == EtetUndefined) | |||
3811 | { | |||
3812 | mTessEvaluationShaderInputPointType = layoutQualifier.tesPointType; | |||
3813 | } | |||
3814 | else | |||
3815 | { | |||
3816 | error(typeQualifier.line, "Duplicated point type declaration", "layout"); | |||
3817 | } | |||
3818 | } | |||
3819 | ||||
3820 | return true; | |||
3821 | } | |||
3822 | ||||
3823 | void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) | |||
3824 | { | |||
3825 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); | |||
3826 | const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; | |||
3827 | ||||
3828 | checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier, | |||
3829 | typeQualifier.line); | |||
3830 | ||||
3831 | // It should never be the case, but some strange parser errors can send us here. | |||
3832 | if (layoutQualifier.isEmpty()) | |||
3833 | { | |||
3834 | error(typeQualifier.line, "Error during layout qualifier parsing.", "?"); | |||
3835 | return; | |||
3836 | } | |||
3837 | ||||
3838 | if (!layoutQualifier.isCombinationValid()) | |||
3839 | { | |||
3840 | error(typeQualifier.line, "invalid layout qualifier combination", "layout"); | |||
3841 | return; | |||
3842 | } | |||
3843 | ||||
3844 | checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index); | |||
3845 | ||||
3846 | checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding); | |||
3847 | ||||
3848 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); | |||
3849 | ||||
3850 | checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat); | |||
3851 | ||||
3852 | checkYuvIsNotSpecified(typeQualifier.line, layoutQualifier.yuv); | |||
3853 | ||||
3854 | checkOffsetIsNotSpecified(typeQualifier.line, layoutQualifier.offset); | |||
3855 | ||||
3856 | checkStd430IsForShaderStorageBlock(typeQualifier.line, layoutQualifier.blockStorage, | |||
3857 | typeQualifier.qualifier); | |||
3858 | ||||
3859 | checkAdvancedBlendEquationsNotSpecified( | |||
3860 | typeQualifier.line, layoutQualifier.advancedBlendEquations, typeQualifier.qualifier); | |||
3861 | ||||
3862 | if (typeQualifier.qualifier != EvqFragmentIn) | |||
3863 | { | |||
3864 | checkEarlyFragmentTestsIsNotSpecified(typeQualifier.line, | |||
3865 | layoutQualifier.earlyFragmentTests); | |||
3866 | } | |||
3867 | ||||
3868 | if (typeQualifier.qualifier == EvqComputeIn) | |||
3869 | { | |||
3870 | if (mComputeShaderLocalSizeDeclared && | |||
3871 | !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize)) | |||
3872 | { | |||
3873 | error(typeQualifier.line, "Work group size does not match the previous declaration", | |||
3874 | "layout"); | |||
3875 | return; | |||
3876 | } | |||
3877 | ||||
3878 | if (mShaderVersion < 310) | |||
3879 | { | |||
3880 | error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); | |||
3881 | return; | |||
3882 | } | |||
3883 | ||||
3884 | if (!layoutQualifier.localSize.isAnyValueSet()) | |||
3885 | { | |||
3886 | error(typeQualifier.line, "No local work group size specified", "layout"); | |||
3887 | return; | |||
3888 | } | |||
3889 | ||||
3890 | const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>( | |||
3891 | symbolTable.findBuiltIn(ImmutableString("gl_MaxComputeWorkGroupSize"), mShaderVersion)); | |||
3892 | ||||
3893 | const TConstantUnion *maxComputeWorkGroupSizeData = | |||
3894 | maxComputeWorkGroupSize->getConstPointer(); | |||
3895 | ||||
3896 | for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i) | |||
3897 | { | |||
3898 | if (layoutQualifier.localSize[i] != -1) | |||
3899 | { | |||
3900 | mComputeShaderLocalSize[i] = layoutQualifier.localSize[i]; | |||
3901 | const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst(); | |||
3902 | if (mComputeShaderLocalSize[i] < 1 || | |||
3903 | mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue) | |||
3904 | { | |||
3905 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
3906 | reasonStream << "invalid value: Value must be at least 1 and no greater than " | |||
3907 | << maxComputeWorkGroupSizeValue; | |||
3908 | const std::string &reason = reasonStream.str(); | |||
3909 | ||||
3910 | error(typeQualifier.line, reason.c_str(), getWorkGroupSizeString(i)); | |||
3911 | return; | |||
3912 | } | |||
3913 | } | |||
3914 | } | |||
3915 | ||||
3916 | mComputeShaderLocalSizeDeclared = true; | |||
3917 | } | |||
3918 | else if (typeQualifier.qualifier == EvqGeometryIn) | |||
3919 | { | |||
3920 | if (mShaderVersion < 310) | |||
3921 | { | |||
3922 | error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); | |||
3923 | return; | |||
3924 | } | |||
3925 | ||||
3926 | if (!parseGeometryShaderInputLayoutQualifier(typeQualifier)) | |||
3927 | { | |||
3928 | return; | |||
3929 | } | |||
3930 | } | |||
3931 | else if (typeQualifier.qualifier == EvqGeometryOut) | |||
3932 | { | |||
3933 | if (mShaderVersion < 310) | |||
3934 | { | |||
3935 | error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only", | |||
3936 | "layout"); | |||
3937 | return; | |||
3938 | } | |||
3939 | ||||
3940 | if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier)) | |||
3941 | { | |||
3942 | return; | |||
3943 | } | |||
3944 | } | |||
3945 | else if (anyMultiviewExtensionAvailable() && typeQualifier.qualifier == EvqVertexIn) | |||
3946 | { | |||
3947 | // This error is only specified in WebGL, but tightens unspecified behavior in the native | |||
3948 | // specification. | |||
3949 | if (mNumViews != -1 && layoutQualifier.numViews != mNumViews) | |||
3950 | { | |||
3951 | error(typeQualifier.line, "Number of views does not match the previous declaration", | |||
3952 | "layout"); | |||
3953 | return; | |||
3954 | } | |||
3955 | ||||
3956 | if (layoutQualifier.numViews == -1) | |||
3957 | { | |||
3958 | error(typeQualifier.line, "No num_views specified", "layout"); | |||
3959 | return; | |||
3960 | } | |||
3961 | ||||
3962 | if (layoutQualifier.numViews > mMaxNumViews) | |||
3963 | { | |||
3964 | error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR", | |||
3965 | "layout"); | |||
3966 | return; | |||
3967 | } | |||
3968 | ||||
3969 | mNumViews = layoutQualifier.numViews; | |||
3970 | } | |||
3971 | else if (typeQualifier.qualifier == EvqFragmentIn) | |||
3972 | { | |||
3973 | if (mShaderVersion < 310) | |||
3974 | { | |||
3975 | error(typeQualifier.line, | |||
3976 | "in type qualifier without variable declaration supported in GLSL ES 3.10 and " | |||
3977 | "after", | |||
3978 | "layout"); | |||
3979 | return; | |||
3980 | } | |||
3981 | ||||
3982 | if (!layoutQualifier.earlyFragmentTests) | |||
3983 | { | |||
3984 | error(typeQualifier.line, | |||
3985 | "only early_fragment_tests is allowed as layout qualifier when not declaring a " | |||
3986 | "variable", | |||
3987 | "layout"); | |||
3988 | return; | |||
3989 | } | |||
3990 | ||||
3991 | mEarlyFragmentTestsSpecified = true; | |||
3992 | } | |||
3993 | else if (typeQualifier.qualifier == EvqFragmentOut) | |||
3994 | { | |||
3995 | if (mShaderVersion < 320 && !isExtensionEnabled(TExtension::KHR_blend_equation_advanced)) | |||
3996 | { | |||
3997 | error(typeQualifier.line, | |||
3998 | "out type qualifier without variable declaration is supported in GLSL ES 3.20," | |||
3999 | " or if GL_KHR_blend_equation_advanced is enabled", | |||
4000 | "layout"); | |||
4001 | return; | |||
4002 | } | |||
4003 | ||||
4004 | if (!layoutQualifier.advancedBlendEquations.any()) | |||
4005 | { | |||
4006 | error(typeQualifier.line, | |||
4007 | "only blend equations are allowed as layout qualifier when not declaring a " | |||
4008 | "variable", | |||
4009 | "layout"); | |||
4010 | return; | |||
4011 | } | |||
4012 | ||||
4013 | mAdvancedBlendEquations |= layoutQualifier.advancedBlendEquations; | |||
4014 | } | |||
4015 | else if (typeQualifier.qualifier == EvqTessControlOut) | |||
4016 | { | |||
4017 | if (mShaderVersion < 310) | |||
4018 | { | |||
4019 | error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 and after", | |||
4020 | "layout"); | |||
4021 | return; | |||
4022 | } | |||
4023 | ||||
4024 | if (!parseTessControlShaderOutputLayoutQualifier(typeQualifier)) | |||
4025 | { | |||
4026 | return; | |||
4027 | } | |||
4028 | } | |||
4029 | else if (typeQualifier.qualifier == EvqTessEvaluationIn) | |||
4030 | { | |||
4031 | if (mShaderVersion < 310) | |||
4032 | { | |||
4033 | error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 and after", | |||
4034 | "layout"); | |||
4035 | return; | |||
4036 | } | |||
4037 | ||||
4038 | if (!parseTessEvaluationShaderInputLayoutQualifier(typeQualifier)) | |||
4039 | { | |||
4040 | return; | |||
4041 | } | |||
4042 | } | |||
4043 | else | |||
4044 | { | |||
4045 | if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier)) | |||
4046 | { | |||
4047 | return; | |||
4048 | } | |||
4049 | ||||
4050 | if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) | |||
4051 | { | |||
4052 | error(typeQualifier.line, "invalid qualifier: global layout can only be set for blocks", | |||
4053 | getQualifierString(typeQualifier.qualifier)); | |||
4054 | return; | |||
4055 | } | |||
4056 | ||||
4057 | if (mShaderVersion < 300) | |||
4058 | { | |||
4059 | error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and after", | |||
4060 | "layout"); | |||
4061 | return; | |||
4062 | } | |||
4063 | ||||
4064 | checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier); | |||
4065 | ||||
4066 | if (layoutQualifier.matrixPacking != EmpUnspecified) | |||
4067 | { | |||
4068 | if (typeQualifier.qualifier == EvqUniform) | |||
4069 | { | |||
4070 | mDefaultUniformMatrixPacking = layoutQualifier.matrixPacking; | |||
4071 | } | |||
4072 | else if (typeQualifier.qualifier == EvqBuffer) | |||
4073 | { | |||
4074 | mDefaultBufferMatrixPacking = layoutQualifier.matrixPacking; | |||
4075 | } | |||
4076 | } | |||
4077 | ||||
4078 | if (layoutQualifier.blockStorage != EbsUnspecified) | |||
4079 | { | |||
4080 | if (typeQualifier.qualifier == EvqUniform) | |||
4081 | { | |||
4082 | mDefaultUniformBlockStorage = layoutQualifier.blockStorage; | |||
4083 | } | |||
4084 | else if (typeQualifier.qualifier == EvqBuffer) | |||
4085 | { | |||
4086 | mDefaultBufferBlockStorage = layoutQualifier.blockStorage; | |||
4087 | } | |||
4088 | } | |||
4089 | } | |||
4090 | } | |||
4091 | ||||
4092 | TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction( | |||
4093 | const TFunction &function, | |||
4094 | const TSourceLoc &location, | |||
4095 | bool insertParametersToSymbolTable) | |||
4096 | { | |||
4097 | checkIsNotReserved(location, function.name()); | |||
4098 | ||||
4099 | TIntermFunctionPrototype *prototype = new TIntermFunctionPrototype(&function); | |||
4100 | prototype->setLine(location); | |||
4101 | ||||
4102 | for (size_t i = 0; i < function.getParamCount(); i++) | |||
4103 | { | |||
4104 | const TVariable *param = function.getParam(i); | |||
4105 | ||||
4106 | // If the parameter has no name, it's not an error, just don't add it to symbol table (could | |||
4107 | // be used for unused args). | |||
4108 | if (param->symbolType() != SymbolType::Empty) | |||
4109 | { | |||
4110 | if (insertParametersToSymbolTable) | |||
4111 | { | |||
4112 | if (!symbolTable.declare(const_cast<TVariable *>(param))) | |||
4113 | { | |||
4114 | error(location, "redefinition", param->name()); | |||
4115 | } | |||
4116 | } | |||
4117 | // Unsized type of a named parameter should have already been checked and sanitized. | |||
4118 | ASSERT(!param->getType().isUnsizedArray())(!param->getType().isUnsizedArray() ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4118, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4118 << "): " << "!param->getType().isUnsizedArray()" )); | |||
4119 | } | |||
4120 | else | |||
4121 | { | |||
4122 | if (param->getType().isUnsizedArray()) | |||
4123 | { | |||
4124 | error(location, "function parameter array must be sized at compile time", "[]"); | |||
4125 | // We don't need to size the arrays since the parameter is unnamed and hence | |||
4126 | // inaccessible. | |||
4127 | } | |||
4128 | } | |||
4129 | } | |||
4130 | return prototype; | |||
4131 | } | |||
4132 | ||||
4133 | TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration( | |||
4134 | const TFunction &parsedFunction, | |||
4135 | const TSourceLoc &location) | |||
4136 | { | |||
4137 | // Note: function found from the symbol table could be the same as parsedFunction if this is the | |||
4138 | // first declaration. Either way the instance in the symbol table is used to track whether the | |||
4139 | // function is declared multiple times. | |||
4140 | bool hadPrototypeDeclaration = false; | |||
4141 | const TFunction *function = symbolTable.markFunctionHasPrototypeDeclaration( | |||
4142 | parsedFunction.getMangledName(), &hadPrototypeDeclaration); | |||
4143 | ||||
4144 | if (hadPrototypeDeclaration && mShaderVersion == 100) | |||
4145 | { | |||
4146 | // ESSL 1.00.17 section 4.2.7. | |||
4147 | // Doesn't apply to ESSL 3.00.4: see section 4.2.3. | |||
4148 | error(location, "duplicate function prototype declarations are not allowed", "function"); | |||
4149 | } | |||
4150 | ||||
4151 | TIntermFunctionPrototype *prototype = | |||
4152 | createPrototypeNodeFromFunction(*function, location, false); | |||
4153 | ||||
4154 | symbolTable.pop(); | |||
4155 | ||||
4156 | if (!symbolTable.atGlobalLevel()) | |||
4157 | { | |||
4158 | // ESSL 3.00.4 section 4.2.4. | |||
4159 | error(location, "local function prototype declarations are not allowed", "function"); | |||
4160 | } | |||
4161 | ||||
4162 | return prototype; | |||
4163 | } | |||
4164 | ||||
4165 | TIntermFunctionDefinition *TParseContext::addFunctionDefinition( | |||
4166 | TIntermFunctionPrototype *functionPrototype, | |||
4167 | TIntermBlock *functionBody, | |||
4168 | const TSourceLoc &location) | |||
4169 | { | |||
4170 | // Undo push at end of parseFunctionDefinitionHeader() below for ESSL1.00 case | |||
4171 | if (mFunctionBodyNewScope) | |||
4172 | { | |||
4173 | mFunctionBodyNewScope = false; | |||
4174 | symbolTable.pop(); | |||
4175 | } | |||
4176 | ||||
4177 | // Check that non-void functions have at least one return statement. | |||
4178 | if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) | |||
4179 | { | |||
4180 | error(location, | |||
4181 | "function does not return a value:", functionPrototype->getFunction()->name()); | |||
4182 | } | |||
4183 | ||||
4184 | if (functionBody == nullptr) | |||
4185 | { | |||
4186 | functionBody = new TIntermBlock(); | |||
4187 | functionBody->setLine(location); | |||
4188 | } | |||
4189 | TIntermFunctionDefinition *functionNode = | |||
4190 | new TIntermFunctionDefinition(functionPrototype, functionBody); | |||
4191 | functionNode->setLine(location); | |||
4192 | ||||
4193 | symbolTable.pop(); | |||
4194 | return functionNode; | |||
4195 | } | |||
4196 | ||||
4197 | void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location, | |||
4198 | const TFunction *function, | |||
4199 | TIntermFunctionPrototype **prototypeOut) | |||
4200 | { | |||
4201 | ASSERT(function)(function ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4201, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4201 << "): " << "function" )); | |||
4202 | ||||
4203 | bool wasDefined = false; | |||
4204 | function = symbolTable.setFunctionParameterNamesFromDefinition(function, &wasDefined); | |||
4205 | if (wasDefined) | |||
4206 | { | |||
4207 | error(location, "function already has a body", function->name()); | |||
4208 | } | |||
4209 | ||||
4210 | // Remember the return type for later checking for return statements. | |||
4211 | mCurrentFunctionType = &(function->getReturnType()); | |||
4212 | mFunctionReturnsValue = false; | |||
4213 | ||||
4214 | *prototypeOut = createPrototypeNodeFromFunction(*function, location, true); | |||
4215 | setLoopNestingLevel(0); | |||
4216 | ||||
4217 | // ESSL 1.00 spec allows for variable in function body to redefine parameter | |||
4218 | if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion)) | |||
4219 | { | |||
4220 | mFunctionBodyNewScope = true; | |||
4221 | symbolTable.push(); | |||
4222 | } | |||
4223 | } | |||
4224 | ||||
4225 | TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TFunction *function) | |||
4226 | { | |||
4227 | // | |||
4228 | // We don't know at this point whether this is a function definition or a prototype. | |||
4229 | // The definition production code will check for redefinitions. | |||
4230 | // In the case of ESSL 1.00 the prototype production code will also check for redeclarations. | |||
4231 | // | |||
4232 | ||||
4233 | for (size_t i = 0u; i < function->getParamCount(); ++i) | |||
4234 | { | |||
4235 | const TVariable *param = function->getParam(i); | |||
4236 | const TType ¶mType = param->getType(); | |||
4237 | ||||
4238 | if (paramType.isStructSpecifier()) | |||
4239 | { | |||
4240 | // ESSL 3.00.6 section 12.10. | |||
4241 | error(location, "Function parameter type cannot be a structure definition", | |||
4242 | function->name()); | |||
4243 | } | |||
4244 | ||||
4245 | checkPrecisionSpecified(location, paramType.getPrecision(), paramType.getBasicType()); | |||
4246 | } | |||
4247 | ||||
4248 | if (getShaderVersion() >= 300) | |||
4249 | { | |||
4250 | if (symbolTable.isUnmangledBuiltInName(function->name(), getShaderVersion(), | |||
4251 | extensionBehavior())) | |||
4252 | { | |||
4253 | // With ESSL 3.00 and above, names of built-in functions cannot be redeclared as | |||
4254 | // functions. Therefore overloading or redefining builtin functions is an error. | |||
4255 | error(location, "Name of a built-in function cannot be redeclared as function", | |||
4256 | function->name()); | |||
4257 | } | |||
4258 | } | |||
4259 | else | |||
4260 | { | |||
4261 | // ESSL 1.00.17 section 4.2.6: built-ins can be overloaded but not redefined. We assume that | |||
4262 | // this applies to redeclarations as well. | |||
4263 | const TSymbol *builtIn = | |||
4264 | symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion()); | |||
4265 | if (builtIn) | |||
4266 | { | |||
4267 | error(location, "built-in functions cannot be redefined", function->name()); | |||
4268 | } | |||
4269 | } | |||
4270 | ||||
4271 | // Return types and parameter qualifiers must match in all redeclarations, so those are checked | |||
4272 | // here. | |||
4273 | const TFunction *prevDec = | |||
4274 | static_cast<const TFunction *>(symbolTable.findGlobal(function->getMangledName())); | |||
4275 | if (prevDec) | |||
4276 | { | |||
4277 | if (prevDec->getReturnType() != function->getReturnType()) | |||
4278 | { | |||
4279 | error(location, "function must have the same return type in all of its declarations", | |||
4280 | function->getReturnType().getBasicString()); | |||
4281 | } | |||
4282 | for (size_t i = 0; i < prevDec->getParamCount(); ++i) | |||
4283 | { | |||
4284 | if (prevDec->getParam(i)->getType().getQualifier() != | |||
4285 | function->getParam(i)->getType().getQualifier()) | |||
4286 | { | |||
4287 | error(location, | |||
4288 | "function must have the same parameter qualifiers in all of its declarations", | |||
4289 | function->getParam(i)->getType().getQualifierString()); | |||
4290 | } | |||
4291 | } | |||
4292 | } | |||
4293 | ||||
4294 | // Check for previously declared variables using the same name. | |||
4295 | const TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion()); | |||
4296 | bool insertUnmangledName = true; | |||
4297 | if (prevSym) | |||
4298 | { | |||
4299 | if (!prevSym->isFunction()) | |||
4300 | { | |||
4301 | error(location, "redefinition of a function", function->name()); | |||
4302 | } | |||
4303 | insertUnmangledName = false; | |||
4304 | } | |||
4305 | // Parsing is at the inner scope level of the function's arguments and body statement at this | |||
4306 | // point, but declareUserDefinedFunction takes care of declaring the function at the global | |||
4307 | // scope. | |||
4308 | symbolTable.declareUserDefinedFunction(function, insertUnmangledName); | |||
4309 | ||||
4310 | // Raise error message if main function takes any parameters or return anything other than void | |||
4311 | if (function->isMain()) | |||
4312 | { | |||
4313 | if (function->getParamCount() > 0) | |||
4314 | { | |||
4315 | error(location, "function cannot take any parameter(s)", "main"); | |||
4316 | } | |||
4317 | if (function->getReturnType().getBasicType() != EbtVoid) | |||
4318 | { | |||
4319 | error(location, "main function cannot return a value", | |||
4320 | function->getReturnType().getBasicString()); | |||
4321 | } | |||
4322 | } | |||
4323 | ||||
4324 | mDeclaringMain = function->isMain(); | |||
4325 | ||||
4326 | // | |||
4327 | // If this is a redeclaration, it could also be a definition, in which case, we want to use the | |||
4328 | // variable names from this one, and not the one that's | |||
4329 | // being redeclared. So, pass back up this declaration, not the one in the symbol table. | |||
4330 | // | |||
4331 | return function; | |||
4332 | } | |||
4333 | ||||
4334 | TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, | |||
4335 | const ImmutableString &name, | |||
4336 | const TSourceLoc &location) | |||
4337 | { | |||
4338 | if (type.qualifier != EvqGlobal && type.qualifier != EvqTemporary) | |||
4339 | { | |||
4340 | error(location, "no qualifiers allowed for function return", | |||
4341 | getQualifierString(type.qualifier)); | |||
4342 | } | |||
4343 | if (!type.layoutQualifier.isEmpty()) | |||
4344 | { | |||
4345 | error(location, "no qualifiers allowed for function return", "layout"); | |||
4346 | } | |||
4347 | // make sure an opaque type is not involved as well... | |||
4348 | std::string reason(getBasicString(type.getBasicType())); | |||
4349 | reason += "s can't be function return values"; | |||
4350 | checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str()); | |||
4351 | if (mShaderVersion < 300) | |||
4352 | { | |||
4353 | // Array return values are forbidden, but there's also no valid syntax for declaring array | |||
4354 | // return values in ESSL 1.00. | |||
4355 | ASSERT(!type.isArray() || mDiagnostics->numErrors() > 0)(!type.isArray() || mDiagnostics->numErrors() > 0 ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4355, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4355 << "): " << "!type.isArray() || mDiagnostics->numErrors() > 0" )); | |||
4356 | ||||
4357 | if (type.isStructureContainingArrays()) | |||
4358 | { | |||
4359 | // ESSL 1.00.17 section 6.1 Function Definitions | |||
4360 | TInfoSinkBase typeString; | |||
4361 | typeString << TType(type); | |||
4362 | error(location, "structures containing arrays can't be function return values", | |||
4363 | typeString.c_str()); | |||
4364 | } | |||
4365 | } | |||
4366 | ||||
4367 | // Add the function as a prototype after parsing it (we do not support recursion) | |||
4368 | return new TFunction(&symbolTable, name, SymbolType::UserDefined, new TType(type), false); | |||
4369 | } | |||
4370 | ||||
4371 | TFunctionLookup *TParseContext::addNonConstructorFunc(const ImmutableString &name, | |||
4372 | const TSymbol *symbol) | |||
4373 | { | |||
4374 | return TFunctionLookup::CreateFunctionCall(name, symbol); | |||
4375 | } | |||
4376 | ||||
4377 | TFunctionLookup *TParseContext::addConstructorFunc(const TPublicType &publicType) | |||
4378 | { | |||
4379 | if (mShaderVersion < 300 && publicType.isArray()) | |||
4380 | { | |||
4381 | error(publicType.getLine(), "array constructor supported in GLSL ES 3.00 and above only", | |||
4382 | "[]"); | |||
4383 | } | |||
4384 | if (publicType.isStructSpecifier()) | |||
4385 | { | |||
4386 | error(publicType.getLine(), "constructor can't be a structure definition", | |||
4387 | getBasicString(publicType.getBasicType())); | |||
4388 | } | |||
4389 | ||||
4390 | TType *type = new TType(publicType); | |||
4391 | if (!type->canBeConstructed()) | |||
4392 | { | |||
4393 | error(publicType.getLine(), "cannot construct this type", | |||
4394 | getBasicString(publicType.getBasicType())); | |||
4395 | type->setBasicType(EbtFloat); | |||
4396 | } | |||
4397 | return TFunctionLookup::CreateConstructor(type); | |||
4398 | } | |||
4399 | ||||
4400 | void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line, | |||
4401 | const char *errorMessage, | |||
4402 | const ImmutableString &token, | |||
4403 | TType *arrayType) | |||
4404 | { | |||
4405 | if (arrayType->isUnsizedArray()) | |||
4406 | { | |||
4407 | error(line, errorMessage, token); | |||
4408 | arrayType->sizeUnsizedArrays(TSpan<const unsigned int>()); | |||
4409 | } | |||
4410 | } | |||
4411 | ||||
4412 | TParameter TParseContext::parseParameterDeclarator(TType *type, | |||
4413 | const ImmutableString &name, | |||
4414 | const TSourceLoc &nameLoc) | |||
4415 | { | |||
4416 | ASSERT(type)(type ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4416, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4416 << "): " << "type")); | |||
4417 | checkIsNotUnsizedArray(nameLoc, "function parameter array must specify a size", name, type); | |||
4418 | if (type->getBasicType() == EbtVoid) | |||
4419 | { | |||
4420 | error(nameLoc, "illegal use of type 'void'", name); | |||
4421 | } | |||
4422 | checkIsNotReserved(nameLoc, name); | |||
4423 | TParameter param = {name.data(), type}; | |||
4424 | return param; | |||
4425 | } | |||
4426 | ||||
4427 | TParameter TParseContext::parseParameterDeclarator(const TPublicType &publicType, | |||
4428 | const ImmutableString &name, | |||
4429 | const TSourceLoc &nameLoc) | |||
4430 | { | |||
4431 | TType *type = new TType(publicType); | |||
4432 | return parseParameterDeclarator(type, name, nameLoc); | |||
4433 | } | |||
4434 | ||||
4435 | TParameter TParseContext::parseParameterArrayDeclarator(const ImmutableString &name, | |||
4436 | const TSourceLoc &nameLoc, | |||
4437 | const TVector<unsigned int> &arraySizes, | |||
4438 | const TSourceLoc &arrayLoc, | |||
4439 | TPublicType *elementType) | |||
4440 | { | |||
4441 | checkArrayElementIsNotArray(arrayLoc, *elementType); | |||
4442 | TType *arrayType = new TType(*elementType); | |||
4443 | arrayType->makeArrays(arraySizes); | |||
4444 | return parseParameterDeclarator(arrayType, name, nameLoc); | |||
4445 | } | |||
4446 | ||||
4447 | bool TParseContext::checkUnsizedArrayConstructorArgumentDimensionality( | |||
4448 | const TIntermSequence &arguments, | |||
4449 | TType type, | |||
4450 | const TSourceLoc &line) | |||
4451 | { | |||
4452 | if (arguments.empty()) | |||
4453 | { | |||
4454 | error(line, "implicitly sized array constructor must have at least one argument", "[]"); | |||
4455 | return false; | |||
4456 | } | |||
4457 | for (TIntermNode *arg : arguments) | |||
4458 | { | |||
4459 | const TIntermTyped *element = arg->getAsTyped(); | |||
4460 | ASSERT(element)(element ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4460, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4460 << "): " << "element" )); | |||
4461 | size_t dimensionalityFromElement = element->getType().getNumArraySizes() + 1u; | |||
4462 | if (dimensionalityFromElement > type.getNumArraySizes()) | |||
4463 | { | |||
4464 | error(line, "constructing from a non-dereferenced array", "constructor"); | |||
4465 | return false; | |||
4466 | } | |||
4467 | else if (dimensionalityFromElement < type.getNumArraySizes()) | |||
4468 | { | |||
4469 | if (dimensionalityFromElement == 1u) | |||
4470 | { | |||
4471 | error(line, "implicitly sized array of arrays constructor argument is not an array", | |||
4472 | "constructor"); | |||
4473 | } | |||
4474 | else | |||
4475 | { | |||
4476 | error(line, | |||
4477 | "implicitly sized array of arrays constructor argument dimensionality is too " | |||
4478 | "low", | |||
4479 | "constructor"); | |||
4480 | } | |||
4481 | return false; | |||
4482 | } | |||
4483 | } | |||
4484 | return true; | |||
4485 | } | |||
4486 | ||||
4487 | // This function is used to test for the correctness of the parameters passed to various constructor | |||
4488 | // functions and also convert them to the right datatype if it is allowed and required. | |||
4489 | // | |||
4490 | // Returns a node to add to the tree regardless of if an error was generated or not. | |||
4491 | // | |||
4492 | TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSourceLoc &line) | |||
4493 | { | |||
4494 | TType type = fnCall->constructorType(); | |||
4495 | TIntermSequence &arguments = fnCall->arguments(); | |||
4496 | if (type.isUnsizedArray()) | |||
4497 | { | |||
4498 | if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line)) | |||
4499 | { | |||
4500 | type.sizeUnsizedArrays(TSpan<const unsigned int>()); | |||
4501 | return CreateZeroNode(type); | |||
4502 | } | |||
4503 | TIntermTyped *firstElement = arguments.at(0)->getAsTyped(); | |||
4504 | ASSERT(firstElement)(firstElement ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4504, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4504 << "): " << "firstElement" )); | |||
4505 | if (type.getOutermostArraySize() == 0u) | |||
4506 | { | |||
4507 | type.sizeOutermostUnsizedArray(static_cast<unsigned int>(arguments.size())); | |||
4508 | } | |||
4509 | for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i) | |||
4510 | { | |||
4511 | if (type.getArraySizes()[i] == 0u) | |||
4512 | { | |||
4513 | type.setArraySize(i, firstElement->getType().getArraySizes()[i]); | |||
4514 | } | |||
4515 | } | |||
4516 | ASSERT(!type.isUnsizedArray())(!type.isUnsizedArray() ? static_cast<void>(0) : (!((:: gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4516, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4516 << "): " << "!type.isUnsizedArray()" )); | |||
4517 | } | |||
4518 | ||||
4519 | if (!checkConstructorArguments(line, arguments, type)) | |||
4520 | { | |||
4521 | return CreateZeroNode(type); | |||
4522 | } | |||
4523 | ||||
4524 | TIntermAggregate *constructorNode = TIntermAggregate::CreateConstructor(type, &arguments); | |||
4525 | constructorNode->setLine(line); | |||
4526 | ||||
4527 | return constructorNode->fold(mDiagnostics); | |||
4528 | } | |||
4529 | ||||
4530 | // | |||
4531 | // Interface/uniform blocks | |||
4532 | TIntermDeclaration *TParseContext::addInterfaceBlock( | |||
4533 | const TTypeQualifierBuilder &typeQualifierBuilder, | |||
4534 | const TSourceLoc &nameLine, | |||
4535 | const ImmutableString &blockName, | |||
4536 | TFieldList *fieldList, | |||
4537 | const ImmutableString &instanceName, | |||
4538 | const TSourceLoc &instanceLine, | |||
4539 | const TVector<unsigned int> *arraySizes, | |||
4540 | const TSourceLoc &arraySizesLine) | |||
4541 | { | |||
4542 | const bool isGLPerVertex = blockName == "gl_PerVertex"; | |||
4543 | // gl_PerVertex is allowed to be redefined and therefore not reserved | |||
4544 | if (!isGLPerVertex) | |||
4545 | { | |||
4546 | checkIsNotReserved(nameLine, blockName); | |||
4547 | } | |||
4548 | ||||
4549 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); | |||
4550 | ||||
4551 | const bool isUniformOrBuffer = | |||
4552 | typeQualifier.qualifier == EvqUniform || typeQualifier.qualifier == EvqBuffer; | |||
4553 | const bool isShaderIoBlock = IsShaderIoBlock(typeQualifier.qualifier); | |||
4554 | ||||
4555 | if (mShaderVersion < 310 && typeQualifier.qualifier != EvqUniform) | |||
4556 | { | |||
4557 | error(typeQualifier.line, | |||
4558 | "invalid qualifier: interface blocks must be uniform in version lower than GLSL ES " | |||
4559 | "3.10", | |||
4560 | getQualifierString(typeQualifier.qualifier)); | |||
4561 | } | |||
4562 | else if (typeQualifier.qualifier == EvqPatchOut) | |||
4563 | { | |||
4564 | if ((!isExtensionEnabled(TExtension::EXT_tessellation_shader) && mShaderVersion < 320) || | |||
4565 | mShaderType != GL_TESS_CONTROL_SHADER0x8E88) | |||
4566 | { | |||
4567 | error(typeQualifier.line, | |||
4568 | "invalid qualifier: 'patch out' requires a tessellation control shader", | |||
4569 | getQualifierString(typeQualifier.qualifier)); | |||
4570 | } | |||
4571 | } | |||
4572 | else if (typeQualifier.qualifier == EvqPatchIn) | |||
4573 | { | |||
4574 | if ((!isExtensionEnabled(TExtension::EXT_tessellation_shader) && mShaderVersion < 320) || | |||
4575 | mShaderType != GL_TESS_EVALUATION_SHADER0x8E87) | |||
4576 | { | |||
4577 | error(typeQualifier.line, | |||
4578 | "invalid qualifier: 'patch in' requires a tessellation evaluation shader", | |||
4579 | getQualifierString(typeQualifier.qualifier)); | |||
4580 | } | |||
4581 | } | |||
4582 | else if (typeQualifier.qualifier != EvqUniform && typeQualifier.qualifier != EvqBuffer) | |||
4583 | { | |||
4584 | if (isShaderIoBlock) | |||
4585 | { | |||
4586 | if (!isExtensionEnabled(TExtension::OES_shader_io_blocks) && | |||
4587 | !isExtensionEnabled(TExtension::EXT_shader_io_blocks) && | |||
4588 | !isExtensionEnabled(TExtension::OES_geometry_shader) && | |||
4589 | !isExtensionEnabled(TExtension::EXT_geometry_shader) && mShaderVersion < 320) | |||
4590 | { | |||
4591 | error(typeQualifier.line, | |||
4592 | "invalid qualifier: shader IO blocks need shader io block extension", | |||
4593 | getQualifierString(typeQualifier.qualifier)); | |||
4594 | } | |||
4595 | ||||
4596 | // Both inputs and outputs of tessellation control shaders must be arrays. | |||
4597 | // For tessellation evaluation shaders, only inputs must necessarily be arrays. | |||
4598 | const bool isTCS = mShaderType == GL_TESS_CONTROL_SHADER0x8E88; | |||
4599 | const bool isTESIn = | |||
4600 | mShaderType == GL_TESS_EVALUATION_SHADER0x8E87 && IsShaderIn(typeQualifier.qualifier); | |||
4601 | if (arraySizes == nullptr && (isTCS || isTESIn)) | |||
4602 | { | |||
4603 | error(typeQualifier.line, "type must be an array", blockName); | |||
4604 | } | |||
4605 | } | |||
4606 | else | |||
4607 | { | |||
4608 | error(typeQualifier.line, | |||
4609 | "invalid qualifier: interface blocks must be uniform or buffer", | |||
4610 | getQualifierString(typeQualifier.qualifier)); | |||
4611 | } | |||
4612 | } | |||
4613 | ||||
4614 | if (typeQualifier.invariant) | |||
4615 | { | |||
4616 | error(typeQualifier.line, "invalid qualifier on interface block", "invariant"); | |||
4617 | } | |||
4618 | ||||
4619 | if (typeQualifier.qualifier != EvqBuffer) | |||
4620 | { | |||
4621 | checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); | |||
4622 | } | |||
4623 | ||||
4624 | // Verify array sizes | |||
4625 | if (arraySizes) | |||
4626 | { | |||
4627 | if (isUniformOrBuffer) | |||
4628 | { | |||
4629 | if (arraySizes->size() == 0) | |||
4630 | { | |||
4631 | error(arraySizesLine, "unsized arrays are not allowed with interface blocks", ""); | |||
4632 | } | |||
4633 | if (arraySizes->size() > 1) | |||
4634 | { | |||
4635 | error(arraySizesLine, "array of arrays are not allowed with interface blocks", ""); | |||
4636 | } | |||
4637 | } | |||
4638 | else if (isShaderIoBlock) | |||
4639 | { | |||
4640 | size_t arrayDimensions = arraySizes->size(); | |||
4641 | ||||
4642 | // Geometry shader inputs have a level arrayness that must be ignored. | |||
4643 | if (mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9 && IsVaryingIn(typeQualifier.qualifier)) | |||
4644 | { | |||
4645 | ASSERT(arrayDimensions > 0)(arrayDimensions > 0 ? static_cast<void>(0) : (!((:: gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 4645, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 4645 << "): " << "arrayDimensions > 0" )); | |||
4646 | --arrayDimensions; | |||
4647 | ||||
4648 | // Validate that the array size of input matches the geometry layout | |||
4649 | // declaration, if not automatic (specified as []). | |||
4650 | const unsigned int geometryDim = arraySizes->back(); | |||
4651 | if (geometryDim > 0 && geometryDim != mGeometryInputArraySize) | |||
4652 | { | |||
4653 | error(arraySizesLine, | |||
4654 | "geometry shader input block array size inconsistent " | |||
4655 | "with primitive", | |||
4656 | ""); | |||
4657 | } | |||
4658 | } | |||
4659 | ||||
4660 | if (arrayDimensions > 1) | |||
4661 | { | |||
4662 | error(arraySizesLine, "array of arrays are not allowed with I/O blocks", ""); | |||
4663 | } | |||
4664 | } | |||
4665 | } | |||
4666 | else if (isShaderIoBlock && mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9 && | |||
4667 | IsVaryingIn(typeQualifier.qualifier)) | |||
4668 | { | |||
4669 | error(arraySizesLine, "geometry shader input blocks must be an array", ""); | |||
4670 | } | |||
4671 | ||||
4672 | checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index); | |||
4673 | ||||
4674 | if (mShaderVersion < 310) | |||
4675 | { | |||
4676 | checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding); | |||
4677 | } | |||
4678 | else | |||
4679 | { | |||
4680 | unsigned int arraySize = | |||
4681 | arraySizes == nullptr || arraySizes->empty() ? 0 : (*arraySizes)[0]; | |||
4682 | checkBlockBindingIsValid(typeQualifier.line, typeQualifier.qualifier, | |||
4683 | typeQualifier.layoutQualifier.binding, arraySize); | |||
4684 | } | |||
4685 | ||||
4686 | checkYuvIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.yuv); | |||
4687 | checkEarlyFragmentTestsIsNotSpecified(typeQualifier.line, | |||
4688 | typeQualifier.layoutQualifier.earlyFragmentTests); | |||
4689 | checkNoncoherentIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.noncoherent); | |||
4690 | ||||
4691 | TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; | |||
4692 | if (!IsShaderIoBlock(typeQualifier.qualifier) && typeQualifier.qualifier != EvqPatchIn && | |||
4693 | typeQualifier.qualifier != EvqPatchOut) | |||
4694 | { | |||
4695 | checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); | |||
4696 | } | |||
4697 | checkStd430IsForShaderStorageBlock(typeQualifier.line, blockLayoutQualifier.blockStorage, | |||
4698 | typeQualifier.qualifier); | |||
4699 | ||||
4700 | if (blockLayoutQualifier.matrixPacking == EmpUnspecified) | |||
4701 | { | |||
4702 | if (typeQualifier.qualifier == EvqUniform) | |||
4703 | { | |||
4704 | blockLayoutQualifier.matrixPacking = mDefaultUniformMatrixPacking; | |||
4705 | } | |||
4706 | else if (typeQualifier.qualifier == EvqBuffer) | |||
4707 | { | |||
4708 | blockLayoutQualifier.matrixPacking = mDefaultBufferMatrixPacking; | |||
4709 | } | |||
4710 | } | |||
4711 | ||||
4712 | if (blockLayoutQualifier.blockStorage == EbsUnspecified) | |||
4713 | { | |||
4714 | if (typeQualifier.qualifier == EvqUniform) | |||
4715 | { | |||
4716 | blockLayoutQualifier.blockStorage = mDefaultUniformBlockStorage; | |||
4717 | } | |||
4718 | else if (typeQualifier.qualifier == EvqBuffer) | |||
4719 | { | |||
4720 | blockLayoutQualifier.blockStorage = mDefaultBufferBlockStorage; | |||
4721 | } | |||
4722 | } | |||
4723 | ||||
4724 | checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier); | |||
4725 | ||||
4726 | checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat); | |||
4727 | ||||
4728 | // check for sampler types and apply layout qualifiers | |||
4729 | for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) | |||
4730 | { | |||
4731 | TField *field = (*fieldList)[memberIndex]; | |||
4732 | TType *fieldType = field->type(); | |||
4733 | if (IsOpaqueType(fieldType->getBasicType())) | |||
4734 | { | |||
4735 | std::string reason("unsupported type - "); | |||
4736 | reason += fieldType->getBasicString(); | |||
4737 | reason += " types are not allowed in interface blocks"; | |||
4738 | error(field->line(), reason.c_str(), fieldType->getBasicString()); | |||
4739 | } | |||
4740 | ||||
4741 | const TQualifier qualifier = fieldType->getQualifier(); | |||
4742 | switch (qualifier) | |||
4743 | { | |||
4744 | case EvqGlobal: | |||
4745 | break; | |||
4746 | case EvqUniform: | |||
4747 | if (typeQualifier.qualifier == EvqBuffer) | |||
4748 | { | |||
4749 | error(field->line(), "invalid qualifier on shader storage block member", | |||
4750 | getQualifierString(qualifier)); | |||
4751 | } | |||
4752 | break; | |||
4753 | case EvqBuffer: | |||
4754 | if (typeQualifier.qualifier == EvqUniform) | |||
4755 | { | |||
4756 | error(field->line(), "invalid qualifier on uniform block member", | |||
4757 | getQualifierString(qualifier)); | |||
4758 | } | |||
4759 | break; | |||
4760 | // a member variable in io block may have different interpolation. | |||
4761 | case EvqFlatIn: | |||
4762 | case EvqFlatOut: | |||
4763 | case EvqNoPerspectiveIn: | |||
4764 | case EvqNoPerspectiveOut: | |||
4765 | case EvqSmoothIn: | |||
4766 | case EvqSmoothOut: | |||
4767 | case EvqCentroidIn: | |||
4768 | case EvqCentroidOut: | |||
4769 | break; | |||
4770 | // a member variable can have an incomplete qualifier because shader io block has either | |||
4771 | // in or out. | |||
4772 | case EvqSmooth: | |||
4773 | case EvqFlat: | |||
4774 | case EvqNoPerspective: | |||
4775 | case EvqCentroid: | |||
4776 | case EvqGeometryIn: | |||
4777 | case EvqGeometryOut: | |||
4778 | if (!IsShaderIoBlock(typeQualifier.qualifier) && | |||
4779 | typeQualifier.qualifier != EvqPatchIn && | |||
4780 | typeQualifier.qualifier != EvqPatchOut && | |||
4781 | typeQualifier.qualifier != EvqGeometryIn && | |||
4782 | typeQualifier.qualifier != EvqGeometryOut) | |||
4783 | { | |||
4784 | error(field->line(), "invalid qualifier on interface block member", | |||
4785 | getQualifierString(qualifier)); | |||
4786 | } | |||
4787 | break; | |||
4788 | default: | |||
4789 | error(field->line(), "invalid qualifier on interface block member", | |||
4790 | getQualifierString(qualifier)); | |||
4791 | break; | |||
4792 | } | |||
4793 | ||||
4794 | // On interface block members, invariant is only applicable to output I/O blocks. | |||
4795 | const bool isOutputShaderIoBlock = isShaderIoBlock && IsShaderOut(typeQualifier.qualifier); | |||
4796 | if (fieldType->isInvariant() && !isOutputShaderIoBlock) | |||
4797 | { | |||
4798 | error(field->line(), "invalid qualifier on interface block member", "invariant"); | |||
4799 | } | |||
4800 | ||||
4801 | // check layout qualifiers | |||
4802 | TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); | |||
4803 | checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index); | |||
4804 | checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding); | |||
4805 | ||||
4806 | if (fieldLayoutQualifier.blockStorage != EbsUnspecified) | |||
4807 | { | |||
4808 | error(field->line(), "invalid layout qualifier: cannot be used here", | |||
4809 | getBlockStorageString(fieldLayoutQualifier.blockStorage)); | |||
4810 | } | |||
4811 | ||||
4812 | if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) | |||
4813 | { | |||
4814 | fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; | |||
4815 | } | |||
4816 | else if (!fieldType->isMatrix() && fieldType->getBasicType() != EbtStruct) | |||
4817 | { | |||
4818 | warning(field->line(), | |||
4819 | "extraneous layout qualifier: only has an effect on matrix types", | |||
4820 | getMatrixPackingString(fieldLayoutQualifier.matrixPacking)); | |||
4821 | } | |||
4822 | ||||
4823 | fieldType->setLayoutQualifier(fieldLayoutQualifier); | |||
4824 | ||||
4825 | if (mShaderVersion < 310 || memberIndex != fieldList->size() - 1u || | |||
4826 | typeQualifier.qualifier != EvqBuffer) | |||
4827 | { | |||
4828 | // ESSL 3.10 spec section 4.1.9 allows for runtime-sized arrays. | |||
4829 | checkIsNotUnsizedArray(field->line(), | |||
4830 | "array members of interface blocks must specify a size", | |||
4831 | field->name(), field->type()); | |||
4832 | } | |||
4833 | ||||
4834 | if (typeQualifier.qualifier == EvqBuffer) | |||
4835 | { | |||
4836 | // set memory qualifiers | |||
4837 | // GLSL ES 3.10 session 4.9 [Memory Access Qualifiers]. When a block declaration is | |||
4838 | // qualified with a memory qualifier, it is as if all of its members were declared with | |||
4839 | // the same memory qualifier. | |||
4840 | const TMemoryQualifier &blockMemoryQualifier = typeQualifier.memoryQualifier; | |||
4841 | TMemoryQualifier fieldMemoryQualifier = fieldType->getMemoryQualifier(); | |||
4842 | fieldMemoryQualifier.readonly |= blockMemoryQualifier.readonly; | |||
4843 | fieldMemoryQualifier.writeonly |= blockMemoryQualifier.writeonly; | |||
4844 | fieldMemoryQualifier.coherent |= blockMemoryQualifier.coherent; | |||
4845 | fieldMemoryQualifier.restrictQualifier |= blockMemoryQualifier.restrictQualifier; | |||
4846 | fieldMemoryQualifier.volatileQualifier |= blockMemoryQualifier.volatileQualifier; | |||
4847 | // TODO(jiajia.qin@intel.com): Decide whether if readonly and writeonly buffer variable | |||
4848 | // is legal. See bug https://github.com/KhronosGroup/OpenGL-API/issues/7 | |||
4849 | fieldType->setMemoryQualifier(fieldMemoryQualifier); | |||
4850 | } | |||
4851 | } | |||
4852 | ||||
4853 | SymbolType instanceSymbolType = SymbolType::UserDefined; | |||
4854 | if (isGLPerVertex) | |||
4855 | { | |||
4856 | instanceSymbolType = SymbolType::BuiltIn; | |||
4857 | } | |||
4858 | TInterfaceBlock *interfaceBlock = new TInterfaceBlock(&symbolTable, blockName, fieldList, | |||
4859 | blockLayoutQualifier, instanceSymbolType); | |||
4860 | if (!symbolTable.declare(interfaceBlock) && isUniformOrBuffer) | |||
4861 | { | |||
4862 | error(nameLine, "redefinition of an interface block name", blockName); | |||
4863 | } | |||
4864 | ||||
4865 | TType *interfaceBlockType = | |||
4866 | new TType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier); | |||
4867 | if (arraySizes) | |||
4868 | { | |||
4869 | interfaceBlockType->makeArrays(*arraySizes); | |||
4870 | ||||
4871 | checkGeometryShaderInputAndSetArraySize(instanceLine, instanceName, interfaceBlockType); | |||
4872 | checkTessellationShaderUnsizedArraysAndSetSize(instanceLine, instanceName, | |||
4873 | interfaceBlockType); | |||
4874 | } | |||
4875 | ||||
4876 | // The instance variable gets created to refer to the interface block type from the AST | |||
4877 | // regardless of if there's an instance name. It's created as an empty symbol if there is no | |||
4878 | // instance name. | |||
4879 | TVariable *instanceVariable = | |||
4880 | new TVariable(&symbolTable, instanceName, interfaceBlockType, | |||
4881 | instanceName.empty() ? SymbolType::Empty : SymbolType::UserDefined); | |||
4882 | ||||
4883 | if (instanceVariable->symbolType() == SymbolType::Empty) | |||
4884 | { | |||
4885 | // define symbols for the members of the interface block | |||
4886 | for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) | |||
4887 | { | |||
4888 | TField *field = (*fieldList)[memberIndex]; | |||
4889 | TType *fieldType = new TType(*field->type()); | |||
4890 | ||||
4891 | // set parent pointer of the field variable | |||
4892 | fieldType->setInterfaceBlockField(interfaceBlock, memberIndex); | |||
4893 | ||||
4894 | fieldType->setQualifier(typeQualifier.qualifier); | |||
4895 | ||||
4896 | SymbolType symbolType = SymbolType::UserDefined; | |||
4897 | if (field->name() == "gl_Position" || field->name() == "gl_PointSize" || | |||
4898 | field->name() == "gl_ClipDistance" || field->name() == "gl_CullDistance") | |||
4899 | { | |||
4900 | // These builtins can be redifined only when used within a redefiend gl_PerVertex | |||
4901 | // block | |||
4902 | if (interfaceBlock->name() != "gl_PerVertex") | |||
4903 | { | |||
4904 | error(field->line(), "redefinition in an invalid interface block", | |||
4905 | field->name()); | |||
4906 | } | |||
4907 | symbolType = SymbolType::BuiltIn; | |||
4908 | } | |||
4909 | TVariable *fieldVariable = | |||
4910 | new TVariable(&symbolTable, field->name(), fieldType, symbolType); | |||
4911 | if (!symbolTable.declare(fieldVariable)) | |||
4912 | { | |||
4913 | error(field->line(), "redefinition of an interface block member name", | |||
4914 | field->name()); | |||
4915 | } | |||
4916 | } | |||
4917 | } | |||
4918 | else | |||
4919 | { | |||
4920 | checkIsNotReserved(instanceLine, instanceName); | |||
4921 | ||||
4922 | // add a symbol for this interface block | |||
4923 | if (!symbolTable.declare(instanceVariable)) | |||
4924 | { | |||
4925 | error(instanceLine, "redefinition of an interface block instance name", instanceName); | |||
4926 | } | |||
4927 | } | |||
4928 | ||||
4929 | TIntermSymbol *blockSymbol = new TIntermSymbol(instanceVariable); | |||
4930 | blockSymbol->setLine(typeQualifier.line); | |||
4931 | TIntermDeclaration *declaration = new TIntermDeclaration(); | |||
4932 | declaration->appendDeclarator(blockSymbol); | |||
4933 | declaration->setLine(nameLine); | |||
4934 | ||||
4935 | exitStructDeclaration(); | |||
4936 | return declaration; | |||
4937 | } | |||
4938 | ||||
4939 | void TParseContext::enterStructDeclaration(const TSourceLoc &line, | |||
4940 | const ImmutableString &identifier) | |||
4941 | { | |||
4942 | ++mStructNestingLevel; | |||
4943 | ||||
4944 | // Embedded structure definitions are not supported per GLSL ES spec. | |||
4945 | // ESSL 1.00.17 section 10.9. ESSL 3.00.6 section 12.11. | |||
4946 | if (mStructNestingLevel > 1) | |||
4947 | { | |||
4948 | error(line, "Embedded struct definitions are not allowed", "struct"); | |||
4949 | } | |||
4950 | } | |||
4951 | ||||
4952 | void TParseContext::exitStructDeclaration() | |||
4953 | { | |||
4954 | --mStructNestingLevel; | |||
4955 | } | |||
4956 | ||||
4957 | void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field) | |||
4958 | { | |||
4959 | if (!sh::IsWebGLBasedSpec(mShaderSpec)) | |||
4960 | { | |||
4961 | return; | |||
4962 | } | |||
4963 | ||||
4964 | if (field.type()->getBasicType() != EbtStruct) | |||
4965 | { | |||
4966 | return; | |||
4967 | } | |||
4968 | ||||
4969 | // We're already inside a structure definition at this point, so add | |||
4970 | // one to the field's struct nesting. | |||
4971 | if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) | |||
4972 | { | |||
4973 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
4974 | if (field.type()->getStruct()->symbolType() == SymbolType::Empty) | |||
4975 | { | |||
4976 | // This may happen in case there are nested struct definitions. While they are also | |||
4977 | // invalid GLSL, they don't cause a syntax error. | |||
4978 | reasonStream << "Struct nesting"; | |||
4979 | } | |||
4980 | else | |||
4981 | { | |||
4982 | reasonStream << "Reference of struct type " << field.type()->getStruct()->name(); | |||
4983 | } | |||
4984 | reasonStream << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting; | |||
4985 | std::string reason = reasonStream.str(); | |||
4986 | error(line, reason.c_str(), field.name()); | |||
4987 | return; | |||
4988 | } | |||
4989 | } | |||
4990 | ||||
4991 | // | |||
4992 | // Parse an array index expression | |||
4993 | // | |||
4994 | TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, | |||
4995 | const TSourceLoc &location, | |||
4996 | TIntermTyped *indexExpression) | |||
4997 | { | |||
4998 | if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) | |||
4999 | { | |||
5000 | if (baseExpression->getAsSymbolNode()) | |||
5001 | { | |||
5002 | error(location, " left of '[' is not of type array, matrix, or vector ", | |||
5003 | baseExpression->getAsSymbolNode()->getName()); | |||
5004 | } | |||
5005 | else | |||
5006 | { | |||
5007 | error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); | |||
5008 | } | |||
5009 | ||||
5010 | return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); | |||
5011 | } | |||
5012 | ||||
5013 | if (baseExpression->getQualifier() == EvqPerVertexIn) | |||
5014 | { | |||
5015 | if (mGeometryShaderInputPrimitiveType == EptUndefined && | |||
5016 | mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9) | |||
5017 | { | |||
5018 | error(location, "missing input primitive declaration before indexing gl_in.", "["); | |||
5019 | return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst)); | |||
5020 | } | |||
5021 | } | |||
5022 | ||||
5023 | TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); | |||
5024 | ||||
5025 | // ES3.2 or ES3.1's EXT_gpu_shader5 allow dynamically uniform expressions to be used as indices | |||
5026 | // of opaque types (samplers and atomic counters) as well as UBOs, but not SSBOs and images. | |||
5027 | bool allowUniformIndices = | |||
5028 | mShaderVersion >= 320 || isExtensionEnabled(TExtension::EXT_gpu_shader5); | |||
5029 | ||||
5030 | // ANGLE should be able to fold any constant expressions resulting in an integer - but to be | |||
5031 | // safe we don't treat "EvqConst" that's evaluated according to the spec as being sufficient | |||
5032 | // for constness. Some interpretations of the spec have allowed constant expressions with side | |||
5033 | // effects - like array length() method on a non-constant array. | |||
5034 | if (indexExpression->getQualifier() != EvqConst || indexConstantUnion == nullptr) | |||
5035 | { | |||
5036 | if (baseExpression->isInterfaceBlock()) | |||
5037 | { | |||
5038 | switch (baseExpression->getQualifier()) | |||
5039 | { | |||
5040 | case EvqPerVertexIn: | |||
5041 | break; | |||
5042 | case EvqUniform: | |||
5043 | if (!allowUniformIndices) | |||
5044 | { | |||
5045 | error(location, | |||
5046 | "array indexes for uniform block arrays must be constant integral " | |||
5047 | "expressions", | |||
5048 | "["); | |||
5049 | } | |||
5050 | break; | |||
5051 | case EvqBuffer: | |||
5052 | error(location, | |||
5053 | "array indexes for shader storage block arrays must be constant integral " | |||
5054 | "expressions", | |||
5055 | "["); | |||
5056 | break; | |||
5057 | default: | |||
5058 | // It's ok for shader I/O blocks to be dynamically indexed | |||
5059 | if (!IsShaderIoBlock(baseExpression->getQualifier()) && | |||
5060 | baseExpression->getQualifier() != EvqPatchIn && | |||
5061 | baseExpression->getQualifier() != EvqPatchOut) | |||
5062 | { | |||
5063 | // We can reach here only in error cases. | |||
5064 | ASSERT(mDiagnostics->numErrors() > 0)(mDiagnostics->numErrors() > 0 ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5064, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5064 << "): " << "mDiagnostics->numErrors() > 0" )); | |||
5065 | } | |||
5066 | break; | |||
5067 | } | |||
5068 | } | |||
5069 | else if (baseExpression->getQualifier() == EvqFragmentOut) | |||
5070 | { | |||
5071 | error(location, | |||
5072 | "array indexes for fragment outputs must be constant integral expressions", "["); | |||
5073 | } | |||
5074 | else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData) | |||
5075 | { | |||
5076 | error(location, "array index for gl_FragData must be constant zero", "["); | |||
5077 | } | |||
5078 | else if (baseExpression->isArray()) | |||
5079 | { | |||
5080 | TBasicType elementType = baseExpression->getType().getBasicType(); | |||
5081 | ||||
5082 | // Note: In Section 12.30 of the ESSL 3.00 spec on p143-144: | |||
5083 | // | |||
5084 | // Indexing of arrays of samplers by constant-index-expressions is | |||
5085 | // supported in GLSL ES 1.00. A constant-index-expression is an | |||
5086 | // expression formed from constant-expressions and certain loop indices, | |||
5087 | // defined for a subset of loop constructs. Should this functionality be | |||
5088 | // included in GLSL ES 3.00? | |||
5089 | // | |||
5090 | // RESOLUTION: No. Arrays of samplers may only be indexed by constant- | |||
5091 | // integral-expressions. | |||
5092 | if (IsSampler(elementType) && !allowUniformIndices && mShaderVersion > 100) | |||
5093 | { | |||
5094 | error(location, "array index for samplers must be constant integral expressions", | |||
5095 | "["); | |||
5096 | } | |||
5097 | else if (IsImage(elementType)) | |||
5098 | { | |||
5099 | error(location, | |||
5100 | "array indexes for image arrays must be constant integral expressions", "["); | |||
5101 | } | |||
5102 | } | |||
5103 | } | |||
5104 | ||||
5105 | if (indexConstantUnion) | |||
5106 | { | |||
5107 | // If an out-of-range index is not qualified as constant, the behavior in the spec is | |||
5108 | // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may | |||
5109 | // constant fold expressions that are not constant expressions). The most compatible way to | |||
5110 | // handle this case is to report a warning instead of an error and force the index to be in | |||
5111 | // the correct range. | |||
5112 | bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst; | |||
5113 | int index = 0; | |||
5114 | if (indexConstantUnion->getBasicType() == EbtInt) | |||
5115 | { | |||
5116 | index = indexConstantUnion->getIConst(0); | |||
5117 | } | |||
5118 | else if (indexConstantUnion->getBasicType() == EbtUInt) | |||
5119 | { | |||
5120 | index = static_cast<int>(indexConstantUnion->getUConst(0)); | |||
5121 | } | |||
5122 | ||||
5123 | int safeIndex = -1; | |||
5124 | ||||
5125 | if (index < 0) | |||
5126 | { | |||
5127 | outOfRangeError(outOfRangeIndexIsError, location, "index expression is negative", "[]"); | |||
5128 | safeIndex = 0; | |||
5129 | } | |||
5130 | ||||
5131 | if (!baseExpression->getType().isUnsizedArray()) | |||
5132 | { | |||
5133 | if (baseExpression->isArray()) | |||
5134 | { | |||
5135 | if (baseExpression->getQualifier() == EvqFragData && index > 0) | |||
5136 | { | |||
5137 | if (!isExtensionEnabled(TExtension::EXT_draw_buffers)) | |||
5138 | { | |||
5139 | outOfRangeError(outOfRangeIndexIsError, location, | |||
5140 | "array index for gl_FragData must be zero when " | |||
5141 | "GL_EXT_draw_buffers is disabled", | |||
5142 | "[]"); | |||
5143 | safeIndex = 0; | |||
5144 | } | |||
5145 | } | |||
5146 | } | |||
5147 | // Only do generic out-of-range check if similar error hasn't already been reported. | |||
5148 | if (safeIndex < 0) | |||
5149 | { | |||
5150 | if (baseExpression->isArray()) | |||
5151 | { | |||
5152 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, | |||
5153 | baseExpression->getOutermostArraySize(), | |||
5154 | "array index out of range"); | |||
5155 | } | |||
5156 | else if (baseExpression->isMatrix()) | |||
5157 | { | |||
5158 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, | |||
5159 | baseExpression->getType().getCols(), | |||
5160 | "matrix field selection out of range"); | |||
5161 | } | |||
5162 | else | |||
5163 | { | |||
5164 | ASSERT(baseExpression->isVector())(baseExpression->isVector() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5164, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5164 << "): " << "baseExpression->isVector()" )); | |||
5165 | safeIndex = checkIndexLessThan(outOfRangeIndexIsError, location, index, | |||
5166 | baseExpression->getType().getNominalSize(), | |||
5167 | "vector field selection out of range"); | |||
5168 | } | |||
5169 | } | |||
5170 | ||||
5171 | ASSERT(safeIndex >= 0)(safeIndex >= 0 ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5171, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5171 << "): " << "safeIndex >= 0" )); | |||
5172 | // Data of constant unions can't be changed, because it may be shared with other | |||
5173 | // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new | |||
5174 | // sanitized object. | |||
5175 | if (safeIndex != index || indexConstantUnion->getBasicType() != EbtInt) | |||
5176 | { | |||
5177 | TConstantUnion *safeConstantUnion = new TConstantUnion(); | |||
5178 | safeConstantUnion->setIConst(safeIndex); | |||
5179 | indexExpression = | |||
5180 | new TIntermConstantUnion(safeConstantUnion, TType(indexExpression->getType())); | |||
5181 | } | |||
5182 | ||||
5183 | TIntermBinary *node = | |||
5184 | new TIntermBinary(EOpIndexDirect, baseExpression, indexExpression); | |||
5185 | node->setLine(location); | |||
5186 | return expressionOrFoldedResult(node); | |||
5187 | } | |||
5188 | } | |||
5189 | ||||
5190 | markStaticReadIfSymbol(indexExpression); | |||
5191 | TIntermBinary *node = new TIntermBinary(EOpIndexIndirect, baseExpression, indexExpression); | |||
5192 | node->setLine(location); | |||
5193 | // Indirect indexing can never be constant folded. | |||
5194 | return node; | |||
5195 | } | |||
5196 | ||||
5197 | int TParseContext::checkIndexLessThan(bool outOfRangeIndexIsError, | |||
5198 | const TSourceLoc &location, | |||
5199 | int index, | |||
5200 | int arraySize, | |||
5201 | const char *reason) | |||
5202 | { | |||
5203 | // Should not reach here with an unsized / runtime-sized array. | |||
5204 | ASSERT(arraySize > 0)(arraySize > 0 ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5204, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5204 << "): " << "arraySize > 0" )); | |||
5205 | // A negative index should already have been checked. | |||
5206 | ASSERT(index >= 0)(index >= 0 ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5206, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5206 << "): " << "index >= 0" )); | |||
5207 | if (index >= arraySize) | |||
5208 | { | |||
5209 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
5210 | reasonStream << reason << " '" << index << "'"; | |||
5211 | std::string token = reasonStream.str(); | |||
5212 | outOfRangeError(outOfRangeIndexIsError, location, reason, "[]"); | |||
5213 | return arraySize - 1; | |||
5214 | } | |||
5215 | return index; | |||
5216 | } | |||
5217 | ||||
5218 | TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, | |||
5219 | const TSourceLoc &dotLocation, | |||
5220 | const ImmutableString &fieldString, | |||
5221 | const TSourceLoc &fieldLocation) | |||
5222 | { | |||
5223 | if (baseExpression->isArray()) | |||
5224 | { | |||
5225 | error(fieldLocation, "cannot apply dot operator to an array", "."); | |||
5226 | return baseExpression; | |||
5227 | } | |||
5228 | ||||
5229 | if (baseExpression->isVector()) | |||
5230 | { | |||
5231 | TVector<int> fieldOffsets; | |||
5232 | if (!parseVectorFields(fieldLocation, fieldString, baseExpression->getNominalSize(), | |||
5233 | &fieldOffsets)) | |||
5234 | { | |||
5235 | fieldOffsets.resize(1); | |||
5236 | fieldOffsets[0] = 0; | |||
5237 | } | |||
5238 | TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldOffsets); | |||
5239 | node->setLine(dotLocation); | |||
5240 | ||||
5241 | return node->fold(mDiagnostics); | |||
5242 | } | |||
5243 | else if (baseExpression->getBasicType() == EbtStruct) | |||
5244 | { | |||
5245 | const TFieldList &fields = baseExpression->getType().getStruct()->fields(); | |||
5246 | if (fields.empty()) | |||
5247 | { | |||
5248 | error(dotLocation, "structure has no fields", "Internal Error"); | |||
5249 | return baseExpression; | |||
5250 | } | |||
5251 | else | |||
5252 | { | |||
5253 | bool fieldFound = false; | |||
5254 | unsigned int i; | |||
5255 | for (i = 0; i < fields.size(); ++i) | |||
5256 | { | |||
5257 | if (fields[i]->name() == fieldString) | |||
5258 | { | |||
5259 | fieldFound = true; | |||
5260 | break; | |||
5261 | } | |||
5262 | } | |||
5263 | if (fieldFound) | |||
5264 | { | |||
5265 | TIntermTyped *index = CreateIndexNode(i); | |||
5266 | index->setLine(fieldLocation); | |||
5267 | TIntermBinary *node = | |||
5268 | new TIntermBinary(EOpIndexDirectStruct, baseExpression, index); | |||
5269 | node->setLine(dotLocation); | |||
5270 | return expressionOrFoldedResult(node); | |||
5271 | } | |||
5272 | else | |||
5273 | { | |||
5274 | error(dotLocation, " no such field in structure", fieldString); | |||
5275 | return baseExpression; | |||
5276 | } | |||
5277 | } | |||
5278 | } | |||
5279 | else if (baseExpression->isInterfaceBlock()) | |||
5280 | { | |||
5281 | const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); | |||
5282 | if (fields.empty()) | |||
5283 | { | |||
5284 | error(dotLocation, "interface block has no fields", "Internal Error"); | |||
5285 | return baseExpression; | |||
5286 | } | |||
5287 | else | |||
5288 | { | |||
5289 | bool fieldFound = false; | |||
5290 | unsigned int i; | |||
5291 | for (i = 0; i < fields.size(); ++i) | |||
5292 | { | |||
5293 | if (fields[i]->name() == fieldString) | |||
5294 | { | |||
5295 | fieldFound = true; | |||
5296 | break; | |||
5297 | } | |||
5298 | } | |||
5299 | if (fieldFound) | |||
5300 | { | |||
5301 | TIntermTyped *index = CreateIndexNode(i); | |||
5302 | index->setLine(fieldLocation); | |||
5303 | TIntermBinary *node = | |||
5304 | new TIntermBinary(EOpIndexDirectInterfaceBlock, baseExpression, index); | |||
5305 | node->setLine(dotLocation); | |||
5306 | // Indexing interface blocks can never be constant folded. | |||
5307 | return node; | |||
5308 | } | |||
5309 | else | |||
5310 | { | |||
5311 | error(dotLocation, " no such field in interface block", fieldString); | |||
5312 | return baseExpression; | |||
5313 | } | |||
5314 | } | |||
5315 | } | |||
5316 | else | |||
5317 | { | |||
5318 | if (mShaderVersion < 300) | |||
5319 | { | |||
5320 | error(dotLocation, " field selection requires structure or vector on left hand side", | |||
5321 | fieldString); | |||
5322 | } | |||
5323 | else | |||
5324 | { | |||
5325 | error(dotLocation, | |||
5326 | " field selection requires structure, vector, or interface block on left hand " | |||
5327 | "side", | |||
5328 | fieldString); | |||
5329 | } | |||
5330 | return baseExpression; | |||
5331 | } | |||
5332 | } | |||
5333 | ||||
5334 | TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, | |||
5335 | const TSourceLoc &qualifierTypeLine) | |||
5336 | { | |||
5337 | TLayoutQualifier qualifier = TLayoutQualifier::Create(); | |||
5338 | ||||
5339 | if (qualifierType == "shared") | |||
5340 | { | |||
5341 | if (sh::IsWebGLBasedSpec(mShaderSpec)) | |||
5342 | { | |||
5343 | error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared"); | |||
5344 | } | |||
5345 | qualifier.blockStorage = EbsShared; | |||
5346 | } | |||
5347 | else if (qualifierType == "packed") | |||
5348 | { | |||
5349 | if (sh::IsWebGLBasedSpec(mShaderSpec)) | |||
5350 | { | |||
5351 | error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed"); | |||
5352 | } | |||
5353 | qualifier.blockStorage = EbsPacked; | |||
5354 | } | |||
5355 | else if (qualifierType == "std430") | |||
5356 | { | |||
5357 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5358 | qualifier.blockStorage = EbsStd430; | |||
5359 | } | |||
5360 | else if (qualifierType == "std140") | |||
5361 | { | |||
5362 | qualifier.blockStorage = EbsStd140; | |||
5363 | } | |||
5364 | else if (qualifierType == "row_major") | |||
5365 | { | |||
5366 | qualifier.matrixPacking = EmpRowMajor; | |||
5367 | } | |||
5368 | else if (qualifierType == "column_major") | |||
5369 | { | |||
5370 | qualifier.matrixPacking = EmpColumnMajor; | |||
5371 | } | |||
5372 | else if (qualifierType == "location") | |||
5373 | { | |||
5374 | error(qualifierTypeLine, "invalid layout qualifier: location requires an argument", | |||
5375 | qualifierType); | |||
5376 | } | |||
5377 | else if (qualifierType == "yuv" && mShaderType == GL_FRAGMENT_SHADER0x8B30) | |||
5378 | { | |||
5379 | if (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_YUV_target)) | |||
5380 | { | |||
5381 | qualifier.yuv = true; | |||
5382 | } | |||
5383 | } | |||
5384 | else if (qualifierType == "early_fragment_tests") | |||
5385 | { | |||
5386 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5387 | qualifier.earlyFragmentTests = true; | |||
5388 | } | |||
5389 | else if (qualifierType == "rgba32f") | |||
5390 | { | |||
5391 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5392 | qualifier.imageInternalFormat = EiifRGBA32F; | |||
5393 | } | |||
5394 | else if (qualifierType == "rgba16f") | |||
5395 | { | |||
5396 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5397 | qualifier.imageInternalFormat = EiifRGBA16F; | |||
5398 | } | |||
5399 | else if (qualifierType == "r32f") | |||
5400 | { | |||
5401 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5402 | { | |||
5403 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5404 | } | |||
5405 | qualifier.imageInternalFormat = EiifR32F; | |||
5406 | } | |||
5407 | else if (qualifierType == "rgba8") | |||
5408 | { | |||
5409 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5410 | { | |||
5411 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5412 | } | |||
5413 | qualifier.imageInternalFormat = EiifRGBA8; | |||
5414 | } | |||
5415 | else if (qualifierType == "rgba8_snorm") | |||
5416 | { | |||
5417 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5418 | qualifier.imageInternalFormat = EiifRGBA8_SNORM; | |||
5419 | } | |||
5420 | else if (qualifierType == "rgba32i") | |||
5421 | { | |||
5422 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5423 | qualifier.imageInternalFormat = EiifRGBA32I; | |||
5424 | } | |||
5425 | else if (qualifierType == "rgba16i") | |||
5426 | { | |||
5427 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5428 | qualifier.imageInternalFormat = EiifRGBA16I; | |||
5429 | } | |||
5430 | else if (qualifierType == "rgba8i") | |||
5431 | { | |||
5432 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5433 | { | |||
5434 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5435 | } | |||
5436 | qualifier.imageInternalFormat = EiifRGBA8I; | |||
5437 | } | |||
5438 | else if (qualifierType == "r32i") | |||
5439 | { | |||
5440 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5441 | qualifier.imageInternalFormat = EiifR32I; | |||
5442 | } | |||
5443 | else if (qualifierType == "rgba32ui") | |||
5444 | { | |||
5445 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5446 | qualifier.imageInternalFormat = EiifRGBA32UI; | |||
5447 | } | |||
5448 | else if (qualifierType == "rgba16ui") | |||
5449 | { | |||
5450 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5451 | qualifier.imageInternalFormat = EiifRGBA16UI; | |||
5452 | } | |||
5453 | else if (qualifierType == "rgba8ui") | |||
5454 | { | |||
5455 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5456 | { | |||
5457 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5458 | } | |||
5459 | qualifier.imageInternalFormat = EiifRGBA8UI; | |||
5460 | } | |||
5461 | else if (qualifierType == "r32ui") | |||
5462 | { | |||
5463 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5464 | { | |||
5465 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5466 | } | |||
5467 | qualifier.imageInternalFormat = EiifR32UI; | |||
5468 | } | |||
5469 | else if (mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9 && | |||
5470 | (mShaderVersion >= 320 || | |||
5471 | (checkCanUseOneOfExtensions( | |||
5472 | qualifierTypeLine, | |||
5473 | std::array<TExtension, 2u>{ | |||
5474 | {TExtension::EXT_geometry_shader, TExtension::OES_geometry_shader}}) && | |||
5475 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310)))) | |||
5476 | { | |||
5477 | if (qualifierType == "points") | |||
5478 | { | |||
5479 | qualifier.primitiveType = EptPoints; | |||
5480 | } | |||
5481 | else if (qualifierType == "lines") | |||
5482 | { | |||
5483 | qualifier.primitiveType = EptLines; | |||
5484 | } | |||
5485 | else if (qualifierType == "lines_adjacency") | |||
5486 | { | |||
5487 | qualifier.primitiveType = EptLinesAdjacency; | |||
5488 | } | |||
5489 | else if (qualifierType == "triangles") | |||
5490 | { | |||
5491 | qualifier.primitiveType = EptTriangles; | |||
5492 | } | |||
5493 | else if (qualifierType == "triangles_adjacency") | |||
5494 | { | |||
5495 | qualifier.primitiveType = EptTrianglesAdjacency; | |||
5496 | } | |||
5497 | else if (qualifierType == "line_strip") | |||
5498 | { | |||
5499 | qualifier.primitiveType = EptLineStrip; | |||
5500 | } | |||
5501 | else if (qualifierType == "triangle_strip") | |||
5502 | { | |||
5503 | qualifier.primitiveType = EptTriangleStrip; | |||
5504 | } | |||
5505 | else | |||
5506 | { | |||
5507 | error(qualifierTypeLine, "invalid layout qualifier", qualifierType); | |||
5508 | } | |||
5509 | } | |||
5510 | else if (mShaderType == GL_TESS_EVALUATION_SHADER_EXT0x8E87 && | |||
5511 | (mShaderVersion >= 320 || | |||
5512 | (checkCanUseExtension(qualifierTypeLine, TExtension::EXT_tessellation_shader) && | |||
5513 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310)))) | |||
5514 | { | |||
5515 | if (qualifierType == "triangles") | |||
5516 | { | |||
5517 | qualifier.tesPrimitiveType = EtetTriangles; | |||
5518 | } | |||
5519 | else if (qualifierType == "quads") | |||
5520 | { | |||
5521 | qualifier.tesPrimitiveType = EtetQuads; | |||
5522 | } | |||
5523 | else if (qualifierType == "isolines") | |||
5524 | { | |||
5525 | qualifier.tesPrimitiveType = EtetIsolines; | |||
5526 | } | |||
5527 | else if (qualifierType == "equal_spacing") | |||
5528 | { | |||
5529 | qualifier.tesVertexSpacingType = EtetEqualSpacing; | |||
5530 | } | |||
5531 | else if (qualifierType == "fractional_even_spacing") | |||
5532 | { | |||
5533 | qualifier.tesVertexSpacingType = EtetFractionalEvenSpacing; | |||
5534 | } | |||
5535 | else if (qualifierType == "fractional_odd_spacing") | |||
5536 | { | |||
5537 | qualifier.tesVertexSpacingType = EtetFractionalOddSpacing; | |||
5538 | } | |||
5539 | else if (qualifierType == "cw") | |||
5540 | { | |||
5541 | qualifier.tesOrderingType = EtetCw; | |||
5542 | } | |||
5543 | else if (qualifierType == "ccw") | |||
5544 | { | |||
5545 | qualifier.tesOrderingType = EtetCcw; | |||
5546 | } | |||
5547 | else if (qualifierType == "point_mode") | |||
5548 | { | |||
5549 | qualifier.tesPointType = EtetPointMode; | |||
5550 | } | |||
5551 | else | |||
5552 | { | |||
5553 | error(qualifierTypeLine, "invalid layout qualifier", qualifierType); | |||
5554 | } | |||
5555 | } | |||
5556 | else if (mShaderType == GL_FRAGMENT_SHADER0x8B30) | |||
5557 | { | |||
5558 | if (qualifierType == "noncoherent") | |||
5559 | { | |||
5560 | if (checkCanUseOneOfExtensions( | |||
5561 | qualifierTypeLine, | |||
5562 | std::array<TExtension, 2u>{ | |||
5563 | {TExtension::EXT_shader_framebuffer_fetch, | |||
5564 | TExtension::EXT_shader_framebuffer_fetch_non_coherent}})) | |||
5565 | { | |||
5566 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 100); | |||
5567 | qualifier.noncoherent = true; | |||
5568 | } | |||
5569 | } | |||
5570 | else if (qualifierType == "blend_support_multiply") | |||
5571 | { | |||
5572 | AddAdvancedBlendEquation(gl::BlendEquationType::Multiply, &qualifier); | |||
5573 | } | |||
5574 | else if (qualifierType == "blend_support_screen") | |||
5575 | { | |||
5576 | AddAdvancedBlendEquation(gl::BlendEquationType::Screen, &qualifier); | |||
5577 | } | |||
5578 | else if (qualifierType == "blend_support_overlay") | |||
5579 | { | |||
5580 | AddAdvancedBlendEquation(gl::BlendEquationType::Overlay, &qualifier); | |||
5581 | } | |||
5582 | else if (qualifierType == "blend_support_darken") | |||
5583 | { | |||
5584 | AddAdvancedBlendEquation(gl::BlendEquationType::Darken, &qualifier); | |||
5585 | } | |||
5586 | else if (qualifierType == "blend_support_lighten") | |||
5587 | { | |||
5588 | AddAdvancedBlendEquation(gl::BlendEquationType::Lighten, &qualifier); | |||
5589 | } | |||
5590 | else if (qualifierType == "blend_support_colordodge") | |||
5591 | { | |||
5592 | AddAdvancedBlendEquation(gl::BlendEquationType::Colordodge, &qualifier); | |||
5593 | } | |||
5594 | else if (qualifierType == "blend_support_colorburn") | |||
5595 | { | |||
5596 | AddAdvancedBlendEquation(gl::BlendEquationType::Colorburn, &qualifier); | |||
5597 | } | |||
5598 | else if (qualifierType == "blend_support_hardlight") | |||
5599 | { | |||
5600 | AddAdvancedBlendEquation(gl::BlendEquationType::Hardlight, &qualifier); | |||
5601 | } | |||
5602 | else if (qualifierType == "blend_support_softlight") | |||
5603 | { | |||
5604 | AddAdvancedBlendEquation(gl::BlendEquationType::Softlight, &qualifier); | |||
5605 | } | |||
5606 | else if (qualifierType == "blend_support_difference") | |||
5607 | { | |||
5608 | AddAdvancedBlendEquation(gl::BlendEquationType::Difference, &qualifier); | |||
5609 | } | |||
5610 | else if (qualifierType == "blend_support_exclusion") | |||
5611 | { | |||
5612 | AddAdvancedBlendEquation(gl::BlendEquationType::Exclusion, &qualifier); | |||
5613 | } | |||
5614 | else if (qualifierType == "blend_support_hsl_hue") | |||
5615 | { | |||
5616 | AddAdvancedBlendEquation(gl::BlendEquationType::HslHue, &qualifier); | |||
5617 | } | |||
5618 | else if (qualifierType == "blend_support_hsl_saturation") | |||
5619 | { | |||
5620 | AddAdvancedBlendEquation(gl::BlendEquationType::HslSaturation, &qualifier); | |||
5621 | } | |||
5622 | else if (qualifierType == "blend_support_hsl_color") | |||
5623 | { | |||
5624 | AddAdvancedBlendEquation(gl::BlendEquationType::HslColor, &qualifier); | |||
5625 | } | |||
5626 | else if (qualifierType == "blend_support_hsl_luminosity") | |||
5627 | { | |||
5628 | AddAdvancedBlendEquation(gl::BlendEquationType::HslLuminosity, &qualifier); | |||
5629 | } | |||
5630 | else if (qualifierType == "blend_support_all_equations") | |||
5631 | { | |||
5632 | qualifier.advancedBlendEquations.setAll(); | |||
5633 | } | |||
5634 | else | |||
5635 | { | |||
5636 | error(qualifierTypeLine, "invalid layout qualifier", qualifierType); | |||
5637 | } | |||
5638 | ||||
5639 | if (qualifier.advancedBlendEquations.any() && mShaderVersion < 320) | |||
5640 | { | |||
5641 | if (!checkCanUseExtension(qualifierTypeLine, TExtension::KHR_blend_equation_advanced)) | |||
5642 | { | |||
5643 | qualifier.advancedBlendEquations.reset(); | |||
5644 | } | |||
5645 | } | |||
5646 | } | |||
5647 | else | |||
5648 | { | |||
5649 | error(qualifierTypeLine, "invalid layout qualifier", qualifierType); | |||
5650 | } | |||
5651 | ||||
5652 | return qualifier; | |||
5653 | } | |||
5654 | ||||
5655 | void TParseContext::parseLocalSize(const ImmutableString &qualifierType, | |||
5656 | const TSourceLoc &qualifierTypeLine, | |||
5657 | int intValue, | |||
5658 | const TSourceLoc &intValueLine, | |||
5659 | const std::string &intValueString, | |||
5660 | size_t index, | |||
5661 | sh::WorkGroupSize *localSize) | |||
5662 | { | |||
5663 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5664 | if (intValue < 1) | |||
5665 | { | |||
5666 | std::stringstream reasonStream = sh::InitializeStream<std::stringstream>(); | |||
5667 | reasonStream << "out of range: " << getWorkGroupSizeString(index) << " must be positive"; | |||
5668 | std::string reason = reasonStream.str(); | |||
5669 | error(intValueLine, reason.c_str(), intValueString.c_str()); | |||
5670 | } | |||
5671 | (*localSize)[index] = intValue; | |||
5672 | } | |||
5673 | ||||
5674 | void TParseContext::parseNumViews(int intValue, | |||
5675 | const TSourceLoc &intValueLine, | |||
5676 | const std::string &intValueString, | |||
5677 | int *numViews) | |||
5678 | { | |||
5679 | // This error is only specified in WebGL, but tightens unspecified behavior in the native | |||
5680 | // specification. | |||
5681 | if (intValue < 1) | |||
5682 | { | |||
5683 | error(intValueLine, "out of range: num_views must be positive", intValueString.c_str()); | |||
5684 | } | |||
5685 | *numViews = intValue; | |||
5686 | } | |||
5687 | ||||
5688 | void TParseContext::parseInvocations(int intValue, | |||
5689 | const TSourceLoc &intValueLine, | |||
5690 | const std::string &intValueString, | |||
5691 | int *numInvocations) | |||
5692 | { | |||
5693 | // Although SPEC isn't clear whether invocations can be less than 1, we add this limit because | |||
5694 | // it doesn't make sense to accept invocations <= 0. | |||
5695 | if (intValue < 1 || intValue > mMaxGeometryShaderInvocations) | |||
5696 | { | |||
5697 | error(intValueLine, | |||
5698 | "out of range: invocations must be in the range of [1, " | |||
5699 | "MAX_GEOMETRY_SHADER_INVOCATIONS_OES]", | |||
5700 | intValueString.c_str()); | |||
5701 | } | |||
5702 | else | |||
5703 | { | |||
5704 | *numInvocations = intValue; | |||
5705 | } | |||
5706 | } | |||
5707 | ||||
5708 | void TParseContext::parseMaxVertices(int intValue, | |||
5709 | const TSourceLoc &intValueLine, | |||
5710 | const std::string &intValueString, | |||
5711 | int *maxVertices) | |||
5712 | { | |||
5713 | // Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because | |||
5714 | // it doesn't make sense to accept max_vertices < 0. | |||
5715 | if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices) | |||
5716 | { | |||
5717 | error( | |||
5718 | intValueLine, | |||
5719 | "out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]", | |||
5720 | intValueString.c_str()); | |||
5721 | } | |||
5722 | else | |||
5723 | { | |||
5724 | *maxVertices = intValue; | |||
5725 | } | |||
5726 | } | |||
5727 | ||||
5728 | void TParseContext::parseVertices(int intValue, | |||
5729 | const TSourceLoc &intValueLine, | |||
5730 | const std::string &intValueString, | |||
5731 | int *vertices) | |||
5732 | { | |||
5733 | if (intValue < 1 || intValue > mMaxPatchVertices) | |||
5734 | { | |||
5735 | error(intValueLine, | |||
5736 | "out of range : vertices must be in the range of [1, gl_MaxPatchVertices]", | |||
5737 | intValueString.c_str()); | |||
5738 | } | |||
5739 | else | |||
5740 | { | |||
5741 | *vertices = intValue; | |||
5742 | } | |||
5743 | } | |||
5744 | ||||
5745 | void TParseContext::parseIndexLayoutQualifier(int intValue, | |||
5746 | const TSourceLoc &intValueLine, | |||
5747 | const std::string &intValueString, | |||
5748 | int *index) | |||
5749 | { | |||
5750 | // EXT_blend_func_extended specifies that most validation should happen at link time, but since | |||
5751 | // we're validating output variable locations at compile time, it makes sense to validate that | |||
5752 | // index is 0 or 1 also at compile time. Also since we use "-1" as a placeholder for unspecified | |||
5753 | // index, we can't accept it here. | |||
5754 | if (intValue < 0 || intValue > 1) | |||
5755 | { | |||
5756 | error(intValueLine, "out of range: index layout qualifier can only be 0 or 1", | |||
5757 | intValueString.c_str()); | |||
5758 | } | |||
5759 | else | |||
5760 | { | |||
5761 | *index = intValue; | |||
5762 | } | |||
5763 | } | |||
5764 | ||||
5765 | TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType, | |||
5766 | const TSourceLoc &qualifierTypeLine, | |||
5767 | int intValue, | |||
5768 | const TSourceLoc &intValueLine) | |||
5769 | { | |||
5770 | TLayoutQualifier qualifier = TLayoutQualifier::Create(); | |||
5771 | ||||
5772 | std::string intValueString = Str(intValue); | |||
5773 | ||||
5774 | if (qualifierType == "location") | |||
5775 | { | |||
5776 | // must check that location is non-negative | |||
5777 | if (intValue < 0) | |||
5778 | { | |||
5779 | error(intValueLine, "out of range: location must be non-negative", | |||
5780 | intValueString.c_str()); | |||
5781 | } | |||
5782 | else | |||
5783 | { | |||
5784 | qualifier.location = intValue; | |||
5785 | qualifier.locationsSpecified = 1; | |||
5786 | } | |||
5787 | } | |||
5788 | else if (qualifierType == "binding") | |||
5789 | { | |||
5790 | if (!isExtensionEnabled(TExtension::ANGLE_shader_pixel_local_storage)) | |||
5791 | { | |||
5792 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5793 | } | |||
5794 | if (intValue < 0) | |||
5795 | { | |||
5796 | error(intValueLine, "out of range: binding must be non-negative", | |||
5797 | intValueString.c_str()); | |||
5798 | } | |||
5799 | else | |||
5800 | { | |||
5801 | qualifier.binding = intValue; | |||
5802 | } | |||
5803 | } | |||
5804 | else if (qualifierType == "offset") | |||
5805 | { | |||
5806 | checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); | |||
5807 | if (intValue < 0) | |||
5808 | { | |||
5809 | error(intValueLine, "out of range: offset must be non-negative", | |||
5810 | intValueString.c_str()); | |||
5811 | } | |||
5812 | else | |||
5813 | { | |||
5814 | qualifier.offset = intValue; | |||
5815 | } | |||
5816 | } | |||
5817 | else if (qualifierType == "local_size_x") | |||
5818 | { | |||
5819 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u, | |||
5820 | &qualifier.localSize); | |||
5821 | } | |||
5822 | else if (qualifierType == "local_size_y") | |||
5823 | { | |||
5824 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u, | |||
5825 | &qualifier.localSize); | |||
5826 | } | |||
5827 | else if (qualifierType == "local_size_z") | |||
5828 | { | |||
5829 | parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, | |||
5830 | &qualifier.localSize); | |||
5831 | } | |||
5832 | else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER0x8B31) | |||
5833 | { | |||
5834 | if (checkCanUseOneOfExtensions( | |||
5835 | qualifierTypeLine, std::array<TExtension, 2u>{ | |||
5836 | {TExtension::OVR_multiview, TExtension::OVR_multiview2}})) | |||
5837 | { | |||
5838 | parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews); | |||
5839 | } | |||
5840 | } | |||
5841 | else if (qualifierType == "invocations" && mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9 && | |||
5842 | (mShaderVersion >= 320 || | |||
5843 | checkCanUseOneOfExtensions( | |||
5844 | qualifierTypeLine, | |||
5845 | std::array<TExtension, 2u>{ | |||
5846 | {TExtension::EXT_geometry_shader, TExtension::OES_geometry_shader}}))) | |||
5847 | { | |||
5848 | parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations); | |||
5849 | } | |||
5850 | else if (qualifierType == "max_vertices" && mShaderType == GL_GEOMETRY_SHADER_EXT0x8DD9 && | |||
5851 | (mShaderVersion >= 320 || | |||
5852 | checkCanUseOneOfExtensions( | |||
5853 | qualifierTypeLine, | |||
5854 | std::array<TExtension, 2u>{ | |||
5855 | {TExtension::EXT_geometry_shader, TExtension::OES_geometry_shader}}))) | |||
5856 | { | |||
5857 | parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices); | |||
5858 | } | |||
5859 | else if (qualifierType == "index" && mShaderType == GL_FRAGMENT_SHADER0x8B30 && | |||
5860 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_blend_func_extended)) | |||
5861 | { | |||
5862 | parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index); | |||
5863 | } | |||
5864 | else if (qualifierType == "vertices" && mShaderType == GL_TESS_CONTROL_SHADER_EXT0x8E88 && | |||
5865 | (mShaderVersion >= 320 || | |||
5866 | checkCanUseExtension(qualifierTypeLine, TExtension::EXT_tessellation_shader))) | |||
5867 | { | |||
5868 | parseVertices(intValue, intValueLine, intValueString, &qualifier.vertices); | |||
5869 | } | |||
5870 | else | |||
5871 | { | |||
5872 | error(qualifierTypeLine, "invalid layout qualifier", qualifierType); | |||
5873 | } | |||
5874 | ||||
5875 | return qualifier; | |||
5876 | } | |||
5877 | ||||
5878 | TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc) | |||
5879 | { | |||
5880 | return new TTypeQualifierBuilder( | |||
5881 | new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc), | |||
5882 | mShaderVersion); | |||
5883 | } | |||
5884 | ||||
5885 | TStorageQualifierWrapper *TParseContext::parseGlobalStorageQualifier(TQualifier qualifier, | |||
5886 | const TSourceLoc &loc) | |||
5887 | { | |||
5888 | checkIsAtGlobalLevel(loc, getQualifierString(qualifier)); | |||
5889 | return new TStorageQualifierWrapper(qualifier, loc); | |||
5890 | } | |||
5891 | ||||
5892 | TStorageQualifierWrapper *TParseContext::parseVaryingQualifier(const TSourceLoc &loc) | |||
5893 | { | |||
5894 | if (getShaderType() == GL_VERTEX_SHADER0x8B31) | |||
5895 | { | |||
5896 | return parseGlobalStorageQualifier(EvqVaryingOut, loc); | |||
5897 | } | |||
5898 | return parseGlobalStorageQualifier(EvqVaryingIn, loc); | |||
5899 | } | |||
5900 | ||||
5901 | TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) | |||
5902 | { | |||
5903 | if (declaringFunction()) | |||
5904 | { | |||
5905 | return new TStorageQualifierWrapper(EvqParamIn, loc); | |||
5906 | } | |||
5907 | ||||
5908 | switch (getShaderType()) | |||
5909 | { | |||
5910 | case GL_VERTEX_SHADER0x8B31: | |||
5911 | { | |||
5912 | if (mShaderVersion < 300 && !anyMultiviewExtensionAvailable() && | |||
5913 | !IsDesktopGLSpec(mShaderSpec)) | |||
5914 | { | |||
5915 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); | |||
5916 | } | |||
5917 | return new TStorageQualifierWrapper(EvqVertexIn, loc); | |||
5918 | } | |||
5919 | case GL_FRAGMENT_SHADER0x8B30: | |||
5920 | { | |||
5921 | if (mShaderVersion < 300 && !IsDesktopGLSpec(mShaderSpec)) | |||
5922 | { | |||
5923 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); | |||
5924 | } | |||
5925 | return new TStorageQualifierWrapper(EvqFragmentIn, loc); | |||
5926 | } | |||
5927 | case GL_COMPUTE_SHADER0x91B9: | |||
5928 | { | |||
5929 | return new TStorageQualifierWrapper(EvqComputeIn, loc); | |||
5930 | } | |||
5931 | case GL_GEOMETRY_SHADER0x8DD9: | |||
5932 | { | |||
5933 | return new TStorageQualifierWrapper(EvqGeometryIn, loc); | |||
5934 | } | |||
5935 | case GL_TESS_CONTROL_SHADER0x8E88: | |||
5936 | { | |||
5937 | return new TStorageQualifierWrapper(EvqTessControlIn, loc); | |||
5938 | } | |||
5939 | case GL_TESS_EVALUATION_SHADER0x8E87: | |||
5940 | { | |||
5941 | return new TStorageQualifierWrapper(EvqTessEvaluationIn, loc); | |||
5942 | } | |||
5943 | default: | |||
5944 | { | |||
5945 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5945, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5945 << ")"; } while (0); | |||
5946 | return new TStorageQualifierWrapper(EvqLast, loc); | |||
5947 | } | |||
5948 | } | |||
5949 | } | |||
5950 | ||||
5951 | TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc) | |||
5952 | { | |||
5953 | if (declaringFunction()) | |||
5954 | { | |||
5955 | return new TStorageQualifierWrapper(EvqParamOut, loc); | |||
5956 | } | |||
5957 | switch (getShaderType()) | |||
5958 | { | |||
5959 | case GL_VERTEX_SHADER0x8B31: | |||
5960 | { | |||
5961 | if (mShaderVersion < 300 && !IsDesktopGLSpec(mShaderSpec)) | |||
5962 | { | |||
5963 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); | |||
5964 | } | |||
5965 | return new TStorageQualifierWrapper(EvqVertexOut, loc); | |||
5966 | } | |||
5967 | case GL_FRAGMENT_SHADER0x8B30: | |||
5968 | { | |||
5969 | if (mShaderVersion < 300 && !IsDesktopGLSpec(mShaderSpec)) | |||
5970 | { | |||
5971 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out"); | |||
5972 | } | |||
5973 | return new TStorageQualifierWrapper(EvqFragmentOut, loc); | |||
5974 | } | |||
5975 | case GL_COMPUTE_SHADER0x91B9: | |||
5976 | { | |||
5977 | error(loc, "storage qualifier isn't supported in compute shaders", "out"); | |||
5978 | return new TStorageQualifierWrapper(EvqParamOut, loc); | |||
5979 | } | |||
5980 | case GL_GEOMETRY_SHADER_EXT0x8DD9: | |||
5981 | { | |||
5982 | return new TStorageQualifierWrapper(EvqGeometryOut, loc); | |||
5983 | } | |||
5984 | case GL_TESS_CONTROL_SHADER_EXT0x8E88: | |||
5985 | { | |||
5986 | return new TStorageQualifierWrapper(EvqTessControlOut, loc); | |||
5987 | } | |||
5988 | case GL_TESS_EVALUATION_SHADER_EXT0x8E87: | |||
5989 | { | |||
5990 | return new TStorageQualifierWrapper(EvqTessEvaluationOut, loc); | |||
5991 | } | |||
5992 | default: | |||
5993 | { | |||
5994 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 5994, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 5994 << ")"; } while (0); | |||
5995 | return new TStorageQualifierWrapper(EvqLast, loc); | |||
5996 | } | |||
5997 | } | |||
5998 | } | |||
5999 | ||||
6000 | TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc) | |||
6001 | { | |||
6002 | if (!declaringFunction()) | |||
6003 | { | |||
6004 | if (mShaderVersion < 300 && !IsDesktopGLSpec(mShaderSpec)) | |||
6005 | { | |||
6006 | error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "inout"); | |||
6007 | } | |||
6008 | ||||
6009 | if (getShaderType() != GL_FRAGMENT_SHADER0x8B30) | |||
6010 | { | |||
6011 | error(loc, "storage qualifier isn't supported in non-fragment shaders", "inout"); | |||
6012 | } | |||
6013 | ||||
6014 | if (isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch) || | |||
6015 | isExtensionEnabled(TExtension::EXT_shader_framebuffer_fetch_non_coherent)) | |||
6016 | { | |||
6017 | return new TStorageQualifierWrapper(EvqFragmentInOut, loc); | |||
6018 | } | |||
6019 | ||||
6020 | error(loc, | |||
6021 | "invalid qualifier: can be used with either function parameters or the variables for " | |||
6022 | "fetching input attachment data", | |||
6023 | "inout"); | |||
6024 | } | |||
6025 | return new TStorageQualifierWrapper(EvqParamInOut, loc); | |||
6026 | } | |||
6027 | ||||
6028 | TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, | |||
6029 | TLayoutQualifier rightQualifier, | |||
6030 | const TSourceLoc &rightQualifierLocation) | |||
6031 | { | |||
6032 | return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation, | |||
6033 | mDiagnostics); | |||
6034 | } | |||
6035 | ||||
6036 | TDeclarator *TParseContext::parseStructDeclarator(const ImmutableString &identifier, | |||
6037 | const TSourceLoc &loc) | |||
6038 | { | |||
6039 | return new TDeclarator(identifier, loc); | |||
6040 | } | |||
6041 | ||||
6042 | TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &identifier, | |||
6043 | const TSourceLoc &loc, | |||
6044 | const TVector<unsigned int> *arraySizes) | |||
6045 | { | |||
6046 | return new TDeclarator(identifier, arraySizes, loc); | |||
6047 | } | |||
6048 | ||||
6049 | void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin, | |||
6050 | const TFieldList::const_iterator end, | |||
6051 | const ImmutableString &name, | |||
6052 | const TSourceLoc &location) | |||
6053 | { | |||
6054 | for (auto fieldIter = begin; fieldIter != end; ++fieldIter) | |||
6055 | { | |||
6056 | if ((*fieldIter)->name() == name) | |||
6057 | { | |||
6058 | error(location, "duplicate field name in structure", name); | |||
6059 | } | |||
6060 | } | |||
6061 | } | |||
6062 | ||||
6063 | TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location) | |||
6064 | { | |||
6065 | for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end(); | |||
6066 | ++fieldIter) | |||
6067 | { | |||
6068 | checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(), | |||
6069 | location); | |||
6070 | } | |||
6071 | return fields; | |||
6072 | } | |||
6073 | ||||
6074 | TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields, | |||
6075 | const TFieldList *newlyAddedFields, | |||
6076 | const TSourceLoc &location) | |||
6077 | { | |||
6078 | for (TField *field : *newlyAddedFields) | |||
6079 | { | |||
6080 | checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(), | |||
6081 | field->name(), location); | |||
6082 | processedFields->push_back(field); | |||
6083 | } | |||
6084 | return processedFields; | |||
6085 | } | |||
6086 | ||||
6087 | TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( | |||
6088 | const TTypeQualifierBuilder &typeQualifierBuilder, | |||
6089 | TPublicType *typeSpecifier, | |||
6090 | const TDeclaratorList *declaratorList) | |||
6091 | { | |||
6092 | TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); | |||
6093 | ||||
6094 | typeSpecifier->qualifier = typeQualifier.qualifier; | |||
6095 | typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier; | |||
6096 | typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier; | |||
6097 | typeSpecifier->invariant = typeQualifier.invariant; | |||
6098 | typeSpecifier->precise = typeQualifier.precise; | |||
6099 | if (typeQualifier.precision != EbpUndefined) | |||
6100 | { | |||
6101 | typeSpecifier->precision = typeQualifier.precision; | |||
6102 | } | |||
6103 | return addStructDeclaratorList(*typeSpecifier, declaratorList); | |||
6104 | } | |||
6105 | ||||
6106 | TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, | |||
6107 | const TDeclaratorList *declaratorList) | |||
6108 | { | |||
6109 | checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, | |||
6110 | typeSpecifier.getBasicType()); | |||
6111 | ||||
6112 | checkIsNonVoid(typeSpecifier.getLine(), (*declaratorList)[0]->name(), | |||
6113 | typeSpecifier.getBasicType()); | |||
6114 | ||||
6115 | checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); | |||
6116 | checkEarlyFragmentTestsIsNotSpecified(typeSpecifier.getLine(), | |||
6117 | typeSpecifier.layoutQualifier.earlyFragmentTests); | |||
6118 | checkNoncoherentIsNotSpecified(typeSpecifier.getLine(), | |||
6119 | typeSpecifier.layoutQualifier.noncoherent); | |||
6120 | ||||
6121 | TFieldList *fieldList = new TFieldList(); | |||
6122 | ||||
6123 | for (const TDeclarator *declarator : *declaratorList) | |||
6124 | { | |||
6125 | TType *type = new TType(typeSpecifier); | |||
6126 | if (declarator->isArray()) | |||
6127 | { | |||
6128 | // Don't allow arrays of arrays in ESSL < 3.10. | |||
6129 | checkArrayElementIsNotArray(typeSpecifier.getLine(), typeSpecifier); | |||
6130 | type->makeArrays(*declarator->arraySizes()); | |||
6131 | } | |||
6132 | ||||
6133 | SymbolType symbolType = SymbolType::UserDefined; | |||
6134 | if (declarator->name() == "gl_Position" || declarator->name() == "gl_PointSize" || | |||
6135 | declarator->name() == "gl_ClipDistance" || declarator->name() == "gl_CullDistance") | |||
6136 | { | |||
6137 | symbolType = SymbolType::BuiltIn; | |||
6138 | } | |||
6139 | else | |||
6140 | { | |||
6141 | checkIsNotReserved(typeSpecifier.getLine(), declarator->name()); | |||
6142 | } | |||
6143 | TField *field = new TField(type, declarator->name(), declarator->line(), symbolType); | |||
6144 | checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *field); | |||
6145 | fieldList->push_back(field); | |||
6146 | } | |||
6147 | ||||
6148 | return fieldList; | |||
6149 | } | |||
6150 | ||||
6151 | TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, | |||
6152 | const TSourceLoc &nameLine, | |||
6153 | const ImmutableString &structName, | |||
6154 | TFieldList *fieldList) | |||
6155 | { | |||
6156 | SymbolType structSymbolType = SymbolType::UserDefined; | |||
6157 | if (structName.empty()) | |||
6158 | { | |||
6159 | structSymbolType = SymbolType::Empty; | |||
6160 | } | |||
6161 | TStructure *structure = new TStructure(&symbolTable, structName, fieldList, structSymbolType); | |||
6162 | ||||
6163 | // Store a bool in the struct if we're at global scope, to allow us to | |||
6164 | // skip the local struct scoping workaround in HLSL. | |||
6165 | structure->setAtGlobalScope(symbolTable.atGlobalLevel()); | |||
6166 | ||||
6167 | if (structSymbolType != SymbolType::Empty) | |||
6168 | { | |||
6169 | checkIsNotReserved(nameLine, structName); | |||
6170 | if (!symbolTable.declare(structure)) | |||
6171 | { | |||
6172 | error(nameLine, "redefinition of a struct", structName); | |||
6173 | } | |||
6174 | } | |||
6175 | ||||
6176 | // ensure we do not specify any storage qualifiers on the struct members | |||
6177 | for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++) | |||
6178 | { | |||
6179 | TField &field = *(*fieldList)[typeListIndex]; | |||
6180 | const TQualifier qualifier = field.type()->getQualifier(); | |||
6181 | switch (qualifier) | |||
6182 | { | |||
6183 | case EvqGlobal: | |||
6184 | case EvqTemporary: | |||
6185 | break; | |||
6186 | default: | |||
6187 | error(field.line(), "invalid qualifier on struct member", | |||
6188 | getQualifierString(qualifier)); | |||
6189 | break; | |||
6190 | } | |||
6191 | if (field.type()->isInvariant()) | |||
6192 | { | |||
6193 | error(field.line(), "invalid qualifier on struct member", "invariant"); | |||
6194 | } | |||
6195 | // ESSL 3.10 section 4.1.8 -- atomic_uint or images are not allowed as structure member. | |||
6196 | // ANGLE_shader_pixel_local_storage also disallows PLS as struct members. | |||
6197 | if (IsImage(field.type()->getBasicType()) || | |||
6198 | IsAtomicCounter(field.type()->getBasicType()) || | |||
6199 | IsPixelLocal(field.type()->getBasicType())) | |||
6200 | { | |||
6201 | error(field.line(), "disallowed type in struct", field.type()->getBasicString()); | |||
6202 | } | |||
6203 | ||||
6204 | checkIsNotUnsizedArray(field.line(), "array members of structs must specify a size", | |||
6205 | field.name(), field.type()); | |||
6206 | ||||
6207 | checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line()); | |||
6208 | ||||
6209 | checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index); | |||
6210 | ||||
6211 | checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding); | |||
6212 | ||||
6213 | checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); | |||
6214 | } | |||
6215 | ||||
6216 | TTypeSpecifierNonArray typeSpecifierNonArray; | |||
6217 | typeSpecifierNonArray.initializeStruct(structure, true, structLine); | |||
6218 | exitStructDeclaration(); | |||
6219 | ||||
6220 | return typeSpecifierNonArray; | |||
6221 | } | |||
6222 | ||||
6223 | TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, | |||
6224 | TIntermBlock *statementList, | |||
6225 | const TSourceLoc &loc) | |||
6226 | { | |||
6227 | TBasicType switchType = init->getBasicType(); | |||
6228 | if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() || | |||
6229 | init->isVector()) | |||
6230 | { | |||
6231 | error(init->getLine(), "init-expression in a switch statement must be a scalar integer", | |||
6232 | "switch"); | |||
6233 | return nullptr; | |||
6234 | } | |||
6235 | ||||
6236 | ASSERT(statementList)(statementList ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6236, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6236 << "): " << "statementList" )); | |||
6237 | if (!ValidateSwitchStatementList(switchType, mDiagnostics, statementList, loc)) | |||
6238 | { | |||
6239 | ASSERT(mDiagnostics->numErrors() > 0)(mDiagnostics->numErrors() > 0 ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6239, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6239 << "): " << "mDiagnostics->numErrors() > 0" )); | |||
6240 | return nullptr; | |||
6241 | } | |||
6242 | ||||
6243 | markStaticReadIfSymbol(init); | |||
6244 | TIntermSwitch *node = new TIntermSwitch(init, statementList); | |||
6245 | node->setLine(loc); | |||
6246 | return node; | |||
6247 | } | |||
6248 | ||||
6249 | TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) | |||
6250 | { | |||
6251 | if (mSwitchNestingLevel == 0) | |||
6252 | { | |||
6253 | error(loc, "case labels need to be inside switch statements", "case"); | |||
6254 | return nullptr; | |||
6255 | } | |||
6256 | if (condition == nullptr) | |||
6257 | { | |||
6258 | error(loc, "case label must have a condition", "case"); | |||
6259 | return nullptr; | |||
6260 | } | |||
6261 | if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || | |||
6262 | condition->isMatrix() || condition->isArray() || condition->isVector()) | |||
6263 | { | |||
6264 | error(condition->getLine(), "case label must be a scalar integer", "case"); | |||
6265 | } | |||
6266 | TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); | |||
6267 | // ANGLE should be able to fold any EvqConst expressions resulting in an integer - but to be | |||
6268 | // safe against corner cases we still check for conditionConst. Some interpretations of the | |||
6269 | // spec have allowed constant expressions with side effects - like array length() method on a | |||
6270 | // non-constant array. | |||
6271 | if (condition->getQualifier() != EvqConst || conditionConst == nullptr) | |||
6272 | { | |||
6273 | error(condition->getLine(), "case label must be constant", "case"); | |||
6274 | } | |||
6275 | TIntermCase *node = new TIntermCase(condition); | |||
6276 | node->setLine(loc); | |||
6277 | return node; | |||
6278 | } | |||
6279 | ||||
6280 | TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) | |||
6281 | { | |||
6282 | if (mSwitchNestingLevel == 0) | |||
6283 | { | |||
6284 | error(loc, "default labels need to be inside switch statements", "default"); | |||
6285 | return nullptr; | |||
6286 | } | |||
6287 | TIntermCase *node = new TIntermCase(nullptr); | |||
6288 | node->setLine(loc); | |||
6289 | return node; | |||
6290 | } | |||
6291 | ||||
6292 | TIntermTyped *TParseContext::createUnaryMath(TOperator op, | |||
6293 | TIntermTyped *child, | |||
6294 | const TSourceLoc &loc, | |||
6295 | const TFunction *func) | |||
6296 | { | |||
6297 | ASSERT(child != nullptr)(child != nullptr ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6297, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6297 << "): " << "child != nullptr" )); | |||
6298 | ||||
6299 | switch (op) | |||
6300 | { | |||
6301 | case EOpLogicalNot: | |||
6302 | if (child->getBasicType() != EbtBool || child->isMatrix() || child->isArray() || | |||
6303 | child->isVector()) | |||
6304 | { | |||
6305 | unaryOpError(loc, GetOperatorString(op), child->getType()); | |||
6306 | return nullptr; | |||
6307 | } | |||
6308 | break; | |||
6309 | case EOpBitwiseNot: | |||
6310 | if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || | |||
6311 | child->isMatrix() || child->isArray()) | |||
6312 | { | |||
6313 | unaryOpError(loc, GetOperatorString(op), child->getType()); | |||
6314 | return nullptr; | |||
6315 | } | |||
6316 | break; | |||
6317 | case EOpPostIncrement: | |||
6318 | case EOpPreIncrement: | |||
6319 | case EOpPostDecrement: | |||
6320 | case EOpPreDecrement: | |||
6321 | case EOpNegative: | |||
6322 | case EOpPositive: | |||
6323 | if (child->getBasicType() == EbtStruct || child->isInterfaceBlock() || | |||
6324 | child->getBasicType() == EbtBool || child->isArray() || | |||
6325 | child->getBasicType() == EbtVoid || IsOpaqueType(child->getBasicType())) | |||
6326 | { | |||
6327 | unaryOpError(loc, GetOperatorString(op), child->getType()); | |||
6328 | return nullptr; | |||
6329 | } | |||
6330 | break; | |||
6331 | // Operators for math built-ins are already type checked against their prototype. | |||
6332 | default: | |||
6333 | break; | |||
6334 | } | |||
6335 | ||||
6336 | if (child->getMemoryQualifier().writeonly) | |||
6337 | { | |||
6338 | const char *opStr = | |||
6339 | BuiltInGroup::IsBuiltIn(op) ? func->name().data() : GetOperatorString(op); | |||
| ||||
6340 | unaryOpError(loc, opStr, child->getType()); | |||
6341 | return nullptr; | |||
6342 | } | |||
6343 | ||||
6344 | markStaticReadIfSymbol(child); | |||
6345 | TIntermUnary *node = new TIntermUnary(op, child, func); | |||
6346 | node->setLine(loc); | |||
6347 | ||||
6348 | return node->fold(mDiagnostics); | |||
6349 | } | |||
6350 | ||||
6351 | TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) | |||
6352 | { | |||
6353 | ASSERT(op != EOpNull)(op != EOpNull ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6353, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6353 << "): " << "op != EOpNull" )); | |||
6354 | TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); | |||
6355 | if (node == nullptr) | |||
6356 | { | |||
6357 | return child; | |||
6358 | } | |||
6359 | return node; | |||
6360 | } | |||
6361 | ||||
6362 | TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, | |||
6363 | TIntermTyped *child, | |||
6364 | const TSourceLoc &loc) | |||
6365 | { | |||
6366 | checkCanBeLValue(loc, GetOperatorString(op), child); | |||
6367 | return addUnaryMath(op, child, loc); | |||
| ||||
6368 | } | |||
6369 | ||||
6370 | TIntermTyped *TParseContext::expressionOrFoldedResult(TIntermTyped *expression) | |||
6371 | { | |||
6372 | // If we can, we should return the folded version of the expression for subsequent parsing. This | |||
6373 | // enables folding the containing expression during parsing as well, instead of the separate | |||
6374 | // FoldExpressions() step where folding nested expressions requires multiple full AST | |||
6375 | // traversals. | |||
6376 | ||||
6377 | // Even if folding fails the fold() functions return some node representing the expression, | |||
6378 | // typically the original node. So "folded" can be assumed to be non-null. | |||
6379 | TIntermTyped *folded = expression->fold(mDiagnostics); | |||
6380 | ASSERT(folded != nullptr)(folded != nullptr ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6380, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6380 << "): " << "folded != nullptr" )); | |||
6381 | if (folded->getQualifier() == expression->getQualifier()) | |||
6382 | { | |||
6383 | // We need this expression to have the correct qualifier when validating the consuming | |||
6384 | // expression. So we can only return the folded node from here in case it has the same | |||
6385 | // qualifier as the original expression. In this kind of a cases the qualifier of the folded | |||
6386 | // node is EvqConst, whereas the qualifier of the expression is EvqTemporary: | |||
6387 | // 1. (true ? 1.0 : non_constant) | |||
6388 | // 2. (non_constant, 1.0) | |||
6389 | return folded; | |||
6390 | } | |||
6391 | return expression; | |||
6392 | } | |||
6393 | ||||
6394 | bool TParseContext::binaryOpCommonCheck(TOperator op, | |||
6395 | TIntermTyped *left, | |||
6396 | TIntermTyped *right, | |||
6397 | const TSourceLoc &loc) | |||
6398 | { | |||
6399 | // Check opaque types are not allowed to be operands in expressions other than array indexing | |||
6400 | // and structure member selection. | |||
6401 | if (IsOpaqueType(left->getBasicType()) || IsOpaqueType(right->getBasicType())) | |||
6402 | { | |||
6403 | switch (op) | |||
6404 | { | |||
6405 | case EOpIndexDirect: | |||
6406 | case EOpIndexIndirect: | |||
6407 | break; | |||
6408 | ||||
6409 | default: | |||
6410 | ASSERT(op != EOpIndexDirectStruct)(op != EOpIndexDirectStruct ? static_cast<void>(0) : (! ((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL) )) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6410, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6410 << "): " << "op != EOpIndexDirectStruct" )); | |||
6411 | error(loc, "Invalid operation for variables with an opaque type", | |||
6412 | GetOperatorString(op)); | |||
6413 | return false; | |||
6414 | } | |||
6415 | } | |||
6416 | ||||
6417 | if (right->getMemoryQualifier().writeonly) | |||
6418 | { | |||
6419 | error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); | |||
6420 | return false; | |||
6421 | } | |||
6422 | ||||
6423 | if (left->getMemoryQualifier().writeonly) | |||
6424 | { | |||
6425 | switch (op) | |||
6426 | { | |||
6427 | case EOpAssign: | |||
6428 | case EOpInitialize: | |||
6429 | case EOpIndexDirect: | |||
6430 | case EOpIndexIndirect: | |||
6431 | case EOpIndexDirectStruct: | |||
6432 | case EOpIndexDirectInterfaceBlock: | |||
6433 | break; | |||
6434 | default: | |||
6435 | error(loc, "Invalid operation for variables with writeonly", GetOperatorString(op)); | |||
6436 | return false; | |||
6437 | } | |||
6438 | } | |||
6439 | ||||
6440 | if (left->getType().getStruct() || right->getType().getStruct()) | |||
6441 | { | |||
6442 | switch (op) | |||
6443 | { | |||
6444 | case EOpIndexDirectStruct: | |||
6445 | ASSERT(left->getType().getStruct())(left->getType().getStruct() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6445, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6445 << "): " << "left->getType().getStruct()" )); | |||
6446 | break; | |||
6447 | case EOpEqual: | |||
6448 | case EOpNotEqual: | |||
6449 | case EOpAssign: | |||
6450 | case EOpInitialize: | |||
6451 | if (left->getType() != right->getType()) | |||
6452 | { | |||
6453 | return false; | |||
6454 | } | |||
6455 | break; | |||
6456 | default: | |||
6457 | error(loc, "Invalid operation for structs", GetOperatorString(op)); | |||
6458 | return false; | |||
6459 | } | |||
6460 | } | |||
6461 | ||||
6462 | if (left->isInterfaceBlock() || right->isInterfaceBlock()) | |||
6463 | { | |||
6464 | switch (op) | |||
6465 | { | |||
6466 | case EOpIndexDirectInterfaceBlock: | |||
6467 | ASSERT(left->getType().getInterfaceBlock())(left->getType().getInterfaceBlock() ? static_cast<void >(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl ::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6467, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6467 << "): " << "left->getType().getInterfaceBlock()" )); | |||
6468 | break; | |||
6469 | default: | |||
6470 | error(loc, "Invalid operation for interface blocks", GetOperatorString(op)); | |||
6471 | return false; | |||
6472 | } | |||
6473 | } | |||
6474 | ||||
6475 | if (left->isArray() != right->isArray()) | |||
6476 | { | |||
6477 | error(loc, "array / non-array mismatch", GetOperatorString(op)); | |||
6478 | return false; | |||
6479 | } | |||
6480 | ||||
6481 | if (left->isArray()) | |||
6482 | { | |||
6483 | ASSERT(right->isArray())(right->isArray() ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6483, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6483 << "): " << "right->isArray()" )); | |||
6484 | if (mShaderVersion < 300) | |||
6485 | { | |||
6486 | error(loc, "Invalid operation for arrays", GetOperatorString(op)); | |||
6487 | return false; | |||
6488 | } | |||
6489 | ||||
6490 | switch (op) | |||
6491 | { | |||
6492 | case EOpEqual: | |||
6493 | case EOpNotEqual: | |||
6494 | case EOpAssign: | |||
6495 | case EOpInitialize: | |||
6496 | break; | |||
6497 | default: | |||
6498 | error(loc, "Invalid operation for arrays", GetOperatorString(op)); | |||
6499 | return false; | |||
6500 | } | |||
6501 | // At this point, size of implicitly sized arrays should be resolved. | |||
6502 | if (left->getType().getArraySizes() != right->getType().getArraySizes()) | |||
6503 | { | |||
6504 | error(loc, "array size mismatch", GetOperatorString(op)); | |||
6505 | return false; | |||
6506 | } | |||
6507 | } | |||
6508 | ||||
6509 | // Check ops which require integer / ivec parameters | |||
6510 | bool isBitShift = false; | |||
6511 | switch (op) | |||
6512 | { | |||
6513 | case EOpBitShiftLeft: | |||
6514 | case EOpBitShiftRight: | |||
6515 | case EOpBitShiftLeftAssign: | |||
6516 | case EOpBitShiftRightAssign: | |||
6517 | // Unsigned can be bit-shifted by signed and vice versa, but we need to | |||
6518 | // check that the basic type is an integer type. | |||
6519 | isBitShift = true; | |||
6520 | if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) | |||
6521 | { | |||
6522 | return false; | |||
6523 | } | |||
6524 | break; | |||
6525 | case EOpBitwiseAnd: | |||
6526 | case EOpBitwiseXor: | |||
6527 | case EOpBitwiseOr: | |||
6528 | case EOpBitwiseAndAssign: | |||
6529 | case EOpBitwiseXorAssign: | |||
6530 | case EOpBitwiseOrAssign: | |||
6531 | // It is enough to check the type of only one operand, since later it | |||
6532 | // is checked that the operand types match. | |||
6533 | if (!IsInteger(left->getBasicType())) | |||
6534 | { | |||
6535 | return false; | |||
6536 | } | |||
6537 | break; | |||
6538 | default: | |||
6539 | break; | |||
6540 | } | |||
6541 | ||||
6542 | ImplicitTypeConversion conversion = GetConversion(left->getBasicType(), right->getBasicType()); | |||
6543 | ||||
6544 | // Implicit type casting only supported for GL shaders | |||
6545 | if (!isBitShift && conversion != ImplicitTypeConversion::Same && | |||
6546 | (!IsDesktopGLSpec(mShaderSpec) || !IsValidImplicitConversion(conversion, op))) | |||
6547 | { | |||
6548 | return false; | |||
6549 | } | |||
6550 | ||||
6551 | // Check that: | |||
6552 | // 1. Type sizes match exactly on ops that require that. | |||
6553 | // 2. Restrictions for structs that contain arrays or samplers are respected. | |||
6554 | // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected. | |||
6555 | switch (op) | |||
6556 | { | |||
6557 | case EOpAssign: | |||
6558 | case EOpInitialize: | |||
6559 | case EOpEqual: | |||
6560 | case EOpNotEqual: | |||
6561 | // ESSL 1.00 sections 5.7, 5.8, 5.9 | |||
6562 | if (mShaderVersion < 300 && left->getType().isStructureContainingArrays()) | |||
6563 | { | |||
6564 | error(loc, "undefined operation for structs containing arrays", | |||
6565 | GetOperatorString(op)); | |||
6566 | return false; | |||
6567 | } | |||
6568 | // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, | |||
6569 | // we interpret the spec so that this extends to structs containing samplers, | |||
6570 | // similarly to ESSL 1.00 spec. | |||
6571 | if ((mShaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && | |||
6572 | left->getType().isStructureContainingSamplers()) | |||
6573 | { | |||
6574 | error(loc, "undefined operation for structs containing samplers", | |||
6575 | GetOperatorString(op)); | |||
6576 | return false; | |||
6577 | } | |||
6578 | ||||
6579 | if ((left->getNominalSize() != right->getNominalSize()) || | |||
6580 | (left->getSecondarySize() != right->getSecondarySize())) | |||
6581 | { | |||
6582 | error(loc, "dimension mismatch", GetOperatorString(op)); | |||
6583 | return false; | |||
6584 | } | |||
6585 | break; | |||
6586 | case EOpLessThan: | |||
6587 | case EOpGreaterThan: | |||
6588 | case EOpLessThanEqual: | |||
6589 | case EOpGreaterThanEqual: | |||
6590 | if (!left->isScalar() || !right->isScalar()) | |||
6591 | { | |||
6592 | error(loc, "comparison operator only defined for scalars", GetOperatorString(op)); | |||
6593 | return false; | |||
6594 | } | |||
6595 | break; | |||
6596 | case EOpAdd: | |||
6597 | case EOpSub: | |||
6598 | case EOpDiv: | |||
6599 | case EOpIMod: | |||
6600 | case EOpBitShiftLeft: | |||
6601 | case EOpBitShiftRight: | |||
6602 | case EOpBitwiseAnd: | |||
6603 | case EOpBitwiseXor: | |||
6604 | case EOpBitwiseOr: | |||
6605 | case EOpAddAssign: | |||
6606 | case EOpSubAssign: | |||
6607 | case EOpDivAssign: | |||
6608 | case EOpIModAssign: | |||
6609 | case EOpBitShiftLeftAssign: | |||
6610 | case EOpBitShiftRightAssign: | |||
6611 | case EOpBitwiseAndAssign: | |||
6612 | case EOpBitwiseXorAssign: | |||
6613 | case EOpBitwiseOrAssign: | |||
6614 | if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) | |||
6615 | { | |||
6616 | return false; | |||
6617 | } | |||
6618 | ||||
6619 | // Are the sizes compatible? | |||
6620 | if (left->getNominalSize() != right->getNominalSize() || | |||
6621 | left->getSecondarySize() != right->getSecondarySize()) | |||
6622 | { | |||
6623 | // If the nominal sizes of operands do not match: | |||
6624 | // One of them must be a scalar. | |||
6625 | if (!left->isScalar() && !right->isScalar()) | |||
6626 | return false; | |||
6627 | ||||
6628 | // In the case of compound assignment other than multiply-assign, | |||
6629 | // the right side needs to be a scalar. Otherwise a vector/matrix | |||
6630 | // would be assigned to a scalar. A scalar can't be shifted by a | |||
6631 | // vector either. | |||
6632 | if (!right->isScalar() && | |||
6633 | (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) | |||
6634 | return false; | |||
6635 | } | |||
6636 | break; | |||
6637 | default: | |||
6638 | break; | |||
6639 | } | |||
6640 | ||||
6641 | return true; | |||
6642 | } | |||
6643 | ||||
6644 | bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op, | |||
6645 | const TType &left, | |||
6646 | const TType &right) | |||
6647 | { | |||
6648 | switch (op) | |||
6649 | { | |||
6650 | case EOpMul: | |||
6651 | case EOpMulAssign: | |||
6652 | return left.getNominalSize() == right.getNominalSize() && | |||
6653 | left.getSecondarySize() == right.getSecondarySize(); | |||
6654 | case EOpVectorTimesScalar: | |||
6655 | return true; | |||
6656 | case EOpVectorTimesScalarAssign: | |||
6657 | ASSERT(!left.isMatrix() && !right.isMatrix())(!left.isMatrix() && !right.isMatrix() ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6657, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6657 << "): " << "!left.isMatrix() && !right.isMatrix()" )); | |||
6658 | return left.isVector() && !right.isVector(); | |||
6659 | case EOpVectorTimesMatrix: | |||
6660 | return left.getNominalSize() == right.getRows(); | |||
6661 | case EOpVectorTimesMatrixAssign: | |||
6662 | ASSERT(!left.isMatrix() && right.isMatrix())(!left.isMatrix() && right.isMatrix() ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6662, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6662 << "): " << "!left.isMatrix() && right.isMatrix()" )); | |||
6663 | return left.isVector() && left.getNominalSize() == right.getRows() && | |||
6664 | left.getNominalSize() == right.getCols(); | |||
6665 | case EOpMatrixTimesVector: | |||
6666 | return left.getCols() == right.getNominalSize(); | |||
6667 | case EOpMatrixTimesScalar: | |||
6668 | return true; | |||
6669 | case EOpMatrixTimesScalarAssign: | |||
6670 | ASSERT(left.isMatrix() && !right.isMatrix())(left.isMatrix() && !right.isMatrix() ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6670, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6670 << "): " << "left.isMatrix() && !right.isMatrix()" )); | |||
6671 | return !right.isVector(); | |||
6672 | case EOpMatrixTimesMatrix: | |||
6673 | return left.getCols() == right.getRows(); | |||
6674 | case EOpMatrixTimesMatrixAssign: | |||
6675 | ASSERT(left.isMatrix() && right.isMatrix())(left.isMatrix() && right.isMatrix() ? static_cast< void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage( ::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv:: LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6675, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6675 << "): " << "left.isMatrix() && right.isMatrix()" )); | |||
6676 | // We need to check two things: | |||
6677 | // 1. The matrix multiplication step is valid. | |||
6678 | // 2. The result will have the same number of columns as the lvalue. | |||
6679 | return left.getCols() == right.getRows() && left.getCols() == right.getCols(); | |||
6680 | ||||
6681 | default: | |||
6682 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6682, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6682 << ")"; } while (0); | |||
6683 | return false; | |||
6684 | } | |||
6685 | } | |||
6686 | ||||
6687 | TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, | |||
6688 | TIntermTyped *left, | |||
6689 | TIntermTyped *right, | |||
6690 | const TSourceLoc &loc) | |||
6691 | { | |||
6692 | if (!binaryOpCommonCheck(op, left, right, loc)) | |||
6693 | return nullptr; | |||
6694 | ||||
6695 | switch (op) | |||
6696 | { | |||
6697 | case EOpEqual: | |||
6698 | case EOpNotEqual: | |||
6699 | case EOpLessThan: | |||
6700 | case EOpGreaterThan: | |||
6701 | case EOpLessThanEqual: | |||
6702 | case EOpGreaterThanEqual: | |||
6703 | break; | |||
6704 | case EOpLogicalOr: | |||
6705 | case EOpLogicalXor: | |||
6706 | case EOpLogicalAnd: | |||
6707 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6708, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6708 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )) | |||
6708 | !right->getType().getStruct())(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6708, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6708 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )); | |||
6709 | if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar()) | |||
6710 | { | |||
6711 | return nullptr; | |||
6712 | } | |||
6713 | // Basic types matching should have been already checked. | |||
6714 | ASSERT(right->getBasicType() == EbtBool)(right->getBasicType() == EbtBool ? static_cast<void> (0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6714, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6714 << "): " << "right->getBasicType() == EbtBool" )); | |||
6715 | break; | |||
6716 | case EOpAdd: | |||
6717 | case EOpSub: | |||
6718 | case EOpDiv: | |||
6719 | case EOpMul: | |||
6720 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6721, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6721 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )) | |||
6721 | !right->getType().getStruct())(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6721, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6721 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )); | |||
6722 | if (left->getBasicType() == EbtBool) | |||
6723 | { | |||
6724 | return nullptr; | |||
6725 | } | |||
6726 | break; | |||
6727 | case EOpIMod: | |||
6728 | ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6729, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6729 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )) | |||
6729 | !right->getType().getStruct())(!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType ().getStruct() ? static_cast<void>(0) : (!((::gl::priv:: ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6729, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6729 << "): " << "!left->isArray() && !right->isArray() && !left->getType().getStruct() && !right->getType().getStruct()" )); | |||
6730 | // Note that this is only for the % operator, not for mod() | |||
6731 | if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) | |||
6732 | { | |||
6733 | return nullptr; | |||
6734 | } | |||
6735 | break; | |||
6736 | default: | |||
6737 | break; | |||
6738 | } | |||
6739 | ||||
6740 | if (op == EOpMul) | |||
6741 | { | |||
6742 | op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType()); | |||
6743 | if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) | |||
6744 | { | |||
6745 | return nullptr; | |||
6746 | } | |||
6747 | } | |||
6748 | ||||
6749 | TIntermBinary *node = new TIntermBinary(op, left, right); | |||
6750 | ASSERT(op != EOpAssign)(op != EOpAssign ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6750, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6750 << "): " << "op != EOpAssign" )); | |||
6751 | markStaticReadIfSymbol(left); | |||
6752 | markStaticReadIfSymbol(right); | |||
6753 | node->setLine(loc); | |||
6754 | return expressionOrFoldedResult(node); | |||
6755 | } | |||
6756 | ||||
6757 | TIntermTyped *TParseContext::addBinaryMath(TOperator op, | |||
6758 | TIntermTyped *left, | |||
6759 | TIntermTyped *right, | |||
6760 | const TSourceLoc &loc) | |||
6761 | { | |||
6762 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); | |||
6763 | if (node == 0) | |||
6764 | { | |||
6765 | binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); | |||
6766 | return left; | |||
6767 | } | |||
6768 | return node; | |||
6769 | } | |||
6770 | ||||
6771 | TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, | |||
6772 | TIntermTyped *left, | |||
6773 | TIntermTyped *right, | |||
6774 | const TSourceLoc &loc) | |||
6775 | { | |||
6776 | TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); | |||
6777 | if (node == nullptr) | |||
6778 | { | |||
6779 | binaryOpError(loc, GetOperatorString(op), left->getType(), right->getType()); | |||
6780 | node = CreateBoolNode(false); | |||
6781 | node->setLine(loc); | |||
6782 | } | |||
6783 | return node; | |||
6784 | } | |||
6785 | ||||
6786 | TIntermTyped *TParseContext::addAssign(TOperator op, | |||
6787 | TIntermTyped *left, | |||
6788 | TIntermTyped *right, | |||
6789 | const TSourceLoc &loc) | |||
6790 | { | |||
6791 | checkCanBeLValue(loc, "assign", left); | |||
6792 | TIntermBinary *node = nullptr; | |||
6793 | if (binaryOpCommonCheck(op, left, right, loc)) | |||
6794 | { | |||
6795 | TIntermBinary *lValue = left->getAsBinaryNode(); | |||
6796 | if ((lValue != nullptr) && | |||
6797 | (lValue->getOp() == EOpIndexIndirect || lValue->getOp() == EOpIndexDirect) && | |||
6798 | IsTessellationControlShaderOutput(mShaderType, lValue->getLeft()->getQualifier())) | |||
6799 | { | |||
6800 | checkTCSOutVarIndexIsValid(lValue, loc); | |||
6801 | } | |||
6802 | ||||
6803 | if (op == EOpMulAssign) | |||
6804 | { | |||
6805 | op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType()); | |||
6806 | if (isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) | |||
6807 | { | |||
6808 | node = new TIntermBinary(op, left, right); | |||
6809 | } | |||
6810 | } | |||
6811 | else | |||
6812 | { | |||
6813 | node = new TIntermBinary(op, left, right); | |||
6814 | } | |||
6815 | } | |||
6816 | if (node == nullptr) | |||
6817 | { | |||
6818 | assignError(loc, "assign", left->getType(), right->getType()); | |||
6819 | return left; | |||
6820 | } | |||
6821 | if (op != EOpAssign) | |||
6822 | { | |||
6823 | markStaticReadIfSymbol(left); | |||
6824 | } | |||
6825 | markStaticReadIfSymbol(right); | |||
6826 | node->setLine(loc); | |||
6827 | return node; | |||
6828 | } | |||
6829 | ||||
6830 | TIntermTyped *TParseContext::addComma(TIntermTyped *left, | |||
6831 | TIntermTyped *right, | |||
6832 | const TSourceLoc &loc) | |||
6833 | { | |||
6834 | // WebGL2 section 5.26, the following results in an error: | |||
6835 | // "Sequence operator applied to void, arrays, or structs containing arrays" | |||
6836 | if (mShaderSpec == SH_WEBGL2_SPEC && | |||
6837 | (left->isArray() || left->getBasicType() == EbtVoid || | |||
6838 | left->getType().isStructureContainingArrays() || right->isArray() || | |||
6839 | right->getBasicType() == EbtVoid || right->getType().isStructureContainingArrays())) | |||
6840 | { | |||
6841 | error(loc, | |||
6842 | "sequence operator is not allowed for void, arrays, or structs containing arrays", | |||
6843 | ","); | |||
6844 | } | |||
6845 | ||||
6846 | TIntermBinary *commaNode = TIntermBinary::CreateComma(left, right, mShaderVersion); | |||
6847 | markStaticReadIfSymbol(left); | |||
6848 | markStaticReadIfSymbol(right); | |||
6849 | commaNode->setLine(loc); | |||
6850 | ||||
6851 | return expressionOrFoldedResult(commaNode); | |||
6852 | } | |||
6853 | ||||
6854 | TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) | |||
6855 | { | |||
6856 | switch (op) | |||
6857 | { | |||
6858 | case EOpContinue: | |||
6859 | if (mLoopNestingLevel <= 0) | |||
6860 | { | |||
6861 | error(loc, "continue statement only allowed in loops", ""); | |||
6862 | } | |||
6863 | break; | |||
6864 | case EOpBreak: | |||
6865 | if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) | |||
6866 | { | |||
6867 | error(loc, "break statement only allowed in loops and switch statements", ""); | |||
6868 | } | |||
6869 | break; | |||
6870 | case EOpReturn: | |||
6871 | if (mCurrentFunctionType->getBasicType() != EbtVoid) | |||
6872 | { | |||
6873 | error(loc, "non-void function must return a value", "return"); | |||
6874 | } | |||
6875 | if (mDeclaringMain) | |||
6876 | { | |||
6877 | errorIfPLSDeclared(loc, PLSIllegalOperations::ReturnFromMain); | |||
6878 | } | |||
6879 | break; | |||
6880 | case EOpKill: | |||
6881 | if (mShaderType != GL_FRAGMENT_SHADER0x8B30) | |||
6882 | { | |||
6883 | error(loc, "discard supported in fragment shaders only", "discard"); | |||
6884 | } | |||
6885 | else | |||
6886 | { | |||
6887 | errorIfPLSDeclared(loc, PLSIllegalOperations::Discard); | |||
6888 | } | |||
6889 | mHasDiscard = true; | |||
6890 | break; | |||
6891 | default: | |||
6892 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6892, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6892 << ")"; } while (0); | |||
6893 | break; | |||
6894 | } | |||
6895 | return addBranch(op, nullptr, loc); | |||
6896 | } | |||
6897 | ||||
6898 | TIntermBranch *TParseContext::addBranch(TOperator op, | |||
6899 | TIntermTyped *expression, | |||
6900 | const TSourceLoc &loc) | |||
6901 | { | |||
6902 | if (expression != nullptr) | |||
6903 | { | |||
6904 | markStaticReadIfSymbol(expression); | |||
6905 | ASSERT(op == EOpReturn)(op == EOpReturn ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6905, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6905 << "): " << "op == EOpReturn" )); | |||
6906 | mFunctionReturnsValue = true; | |||
6907 | if (mCurrentFunctionType->getBasicType() == EbtVoid) | |||
6908 | { | |||
6909 | error(loc, "void function cannot return a value", "return"); | |||
6910 | } | |||
6911 | else if (*mCurrentFunctionType != expression->getType()) | |||
6912 | { | |||
6913 | error(loc, "function return is not matching type:", "return"); | |||
6914 | } | |||
6915 | } | |||
6916 | TIntermBranch *node = new TIntermBranch(op, expression); | |||
6917 | node->setLine(loc); | |||
6918 | return node; | |||
6919 | } | |||
6920 | ||||
6921 | void TParseContext::appendStatement(TIntermBlock *block, TIntermNode *statement) | |||
6922 | { | |||
6923 | if (statement != nullptr) | |||
6924 | { | |||
6925 | markStaticReadIfSymbol(statement); | |||
6926 | block->appendStatement(statement); | |||
6927 | } | |||
6928 | } | |||
6929 | ||||
6930 | void TParseContext::checkTextureGather(TIntermAggregate *functionCall) | |||
6931 | { | |||
6932 | const TOperator op = functionCall->getOp(); | |||
6933 | const TFunction *func = functionCall->getFunction(); | |||
6934 | if (BuiltInGroup::IsTextureGather(op)) | |||
6935 | { | |||
6936 | bool isTextureGatherOffsetOrOffsets = | |||
6937 | BuiltInGroup::IsTextureGatherOffset(op) || BuiltInGroup::IsTextureGatherOffsets(op); | |||
6938 | TIntermNode *componentNode = nullptr; | |||
6939 | TIntermSequence *arguments = functionCall->getSequence(); | |||
6940 | ASSERT(arguments->size() >= 2u && arguments->size() <= 4u)(arguments->size() >= 2u && arguments->size( ) <= 4u ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6940, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6940 << "): " << "arguments->size() >= 2u && arguments->size() <= 4u" )); | |||
6941 | const TIntermTyped *sampler = arguments->front()->getAsTyped(); | |||
6942 | ASSERT(sampler != nullptr)(sampler != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6942, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6942 << "): " << "sampler != nullptr" )); | |||
6943 | switch (sampler->getBasicType()) | |||
6944 | { | |||
6945 | case EbtSampler2D: | |||
6946 | case EbtISampler2D: | |||
6947 | case EbtUSampler2D: | |||
6948 | case EbtSampler2DArray: | |||
6949 | case EbtISampler2DArray: | |||
6950 | case EbtUSampler2DArray: | |||
6951 | if ((!isTextureGatherOffsetOrOffsets && arguments->size() == 3u) || | |||
6952 | (isTextureGatherOffsetOrOffsets && arguments->size() == 4u)) | |||
6953 | { | |||
6954 | componentNode = arguments->back(); | |||
6955 | } | |||
6956 | break; | |||
6957 | case EbtSamplerCube: | |||
6958 | case EbtISamplerCube: | |||
6959 | case EbtUSamplerCube: | |||
6960 | case EbtSamplerCubeArray: | |||
6961 | case EbtISamplerCubeArray: | |||
6962 | case EbtUSamplerCubeArray: | |||
6963 | ASSERT(!isTextureGatherOffsetOrOffsets)(!isTextureGatherOffsetOrOffsets ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6963, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6963 << "): " << "!isTextureGatherOffsetOrOffsets" )); | |||
6964 | if (arguments->size() == 3u) | |||
6965 | { | |||
6966 | componentNode = arguments->back(); | |||
6967 | } | |||
6968 | break; | |||
6969 | case EbtSampler2DShadow: | |||
6970 | case EbtSampler2DArrayShadow: | |||
6971 | case EbtSamplerCubeShadow: | |||
6972 | case EbtSamplerCubeArrayShadow: | |||
6973 | break; | |||
6974 | default: | |||
6975 | UNREACHABLE()do { !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 6975, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: " << __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 6975 << ")"; } while (0); | |||
6976 | break; | |||
6977 | } | |||
6978 | if (componentNode) | |||
6979 | { | |||
6980 | const TIntermConstantUnion *componentConstantUnion = | |||
6981 | componentNode->getAsConstantUnion(); | |||
6982 | if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion) | |||
6983 | { | |||
6984 | error(functionCall->getLine(), "Texture component must be a constant expression", | |||
6985 | func->name()); | |||
6986 | } | |||
6987 | else | |||
6988 | { | |||
6989 | int component = componentConstantUnion->getIConst(0); | |||
6990 | if (component < 0 || component > 3) | |||
6991 | { | |||
6992 | error(functionCall->getLine(), "Component must be in the range [0;3]", | |||
6993 | func->name()); | |||
6994 | } | |||
6995 | } | |||
6996 | } | |||
6997 | } | |||
6998 | } | |||
6999 | ||||
7000 | void TParseContext::checkTextureOffset(TIntermAggregate *functionCall) | |||
7001 | { | |||
7002 | const TOperator op = functionCall->getOp(); | |||
7003 | const TFunction *func = functionCall->getFunction(); | |||
7004 | TIntermNode *offset = nullptr; | |||
7005 | TIntermSequence *arguments = functionCall->getSequence(); | |||
7006 | ||||
7007 | if (BuiltInGroup::IsTextureOffsetNoBias(op) || BuiltInGroup::IsTextureGatherOffsetNoComp(op) || | |||
7008 | BuiltInGroup::IsTextureGatherOffsetsNoComp(op)) | |||
7009 | { | |||
7010 | offset = arguments->back(); | |||
7011 | } | |||
7012 | else if (BuiltInGroup::IsTextureOffsetBias(op) || BuiltInGroup::IsTextureGatherOffsetComp(op) || | |||
7013 | BuiltInGroup::IsTextureGatherOffsetsComp(op)) | |||
7014 | { | |||
7015 | // A bias or comp parameter follows the offset parameter. | |||
7016 | ASSERT(arguments->size() >= 3)(arguments->size() >= 3 ? static_cast<void>(0) : ( !((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7016, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7016 << "): " << "arguments->size() >= 3" )); | |||
7017 | offset = (*arguments)[2]; | |||
7018 | } | |||
7019 | ||||
7020 | // If not one of the above built-ins, there's nothing to do here. | |||
7021 | if (offset == nullptr) | |||
7022 | { | |||
7023 | return; | |||
7024 | } | |||
7025 | ||||
7026 | bool isTextureGatherOffset = BuiltInGroup::IsTextureGatherOffset(op); | |||
7027 | bool isTextureGatherOffsets = BuiltInGroup::IsTextureGatherOffsets(op); | |||
7028 | bool useTextureGatherOffsetConstraints = isTextureGatherOffset || isTextureGatherOffsets; | |||
7029 | ||||
7030 | int minOffsetValue = | |||
7031 | useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset : mMinProgramTexelOffset; | |||
7032 | int maxOffsetValue = | |||
7033 | useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset : mMaxProgramTexelOffset; | |||
7034 | ||||
7035 | if (isTextureGatherOffsets) | |||
7036 | { | |||
7037 | // If textureGatherOffsets, the offsets parameter is an array, which is expected as an | |||
7038 | // aggregate constructor node or as a symbol node with a constant value. | |||
7039 | TIntermAggregate *offsetAggregate = offset->getAsAggregate(); | |||
7040 | TIntermSymbol *offsetSymbol = offset->getAsSymbolNode(); | |||
7041 | ||||
7042 | const TConstantUnion *offsetValues = offsetAggregate ? offsetAggregate->getConstantValue() | |||
7043 | : offsetSymbol ? offsetSymbol->getConstantValue() | |||
7044 | : nullptr; | |||
7045 | ||||
7046 | if (offsetValues == nullptr) | |||
7047 | { | |||
7048 | error(functionCall->getLine(), "Texture offsets must be a constant expression", | |||
7049 | func->name()); | |||
7050 | return; | |||
7051 | } | |||
7052 | ||||
7053 | constexpr unsigned int kOffsetsCount = 4; | |||
7054 | const TType &offsetType = | |||
7055 | offsetAggregate != nullptr ? offsetAggregate->getType() : offsetSymbol->getType(); | |||
7056 | if (offsetType.getNumArraySizes() != 1 || offsetType.getArraySizes()[0] != kOffsetsCount) | |||
7057 | { | |||
7058 | error(functionCall->getLine(), "Texture offsets must be an array of 4 elements", | |||
7059 | func->name()); | |||
7060 | return; | |||
7061 | } | |||
7062 | ||||
7063 | size_t size = offsetType.getObjectSize() / kOffsetsCount; | |||
7064 | for (unsigned int i = 0; i < kOffsetsCount; ++i) | |||
7065 | { | |||
7066 | checkSingleTextureOffset(offset->getLine(), &offsetValues[i * size], size, | |||
7067 | minOffsetValue, maxOffsetValue); | |||
7068 | } | |||
7069 | } | |||
7070 | else | |||
7071 | { | |||
7072 | // If textureOffset or textureGatherOffset, the offset is expected to be found as a constant | |||
7073 | // union. | |||
7074 | TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion(); | |||
7075 | ||||
7076 | // ES3.2 or ES3.1's EXT_gpu_shader5 allow non-const offsets to be passed to | |||
7077 | // textureGatherOffset. | |||
7078 | bool textureGatherOffsetMustBeConst = | |||
7079 | mShaderVersion <= 310 && !isExtensionEnabled(TExtension::EXT_gpu_shader5); | |||
7080 | ||||
7081 | bool isOffsetConst = | |||
7082 | offset->getAsTyped()->getQualifier() == EvqConst && offsetConstantUnion != nullptr; | |||
7083 | bool offsetMustBeConst = !isTextureGatherOffset || textureGatherOffsetMustBeConst; | |||
7084 | ||||
7085 | if (!isOffsetConst && offsetMustBeConst) | |||
7086 | { | |||
7087 | error(functionCall->getLine(), "Texture offset must be a constant expression", | |||
7088 | func->name()); | |||
7089 | return; | |||
7090 | } | |||
7091 | ||||
7092 | // We cannot verify non-constant offsets to textureGatherOffset. | |||
7093 | if (offsetConstantUnion == nullptr) | |||
7094 | { | |||
7095 | ASSERT(!offsetMustBeConst)(!offsetMustBeConst ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7095, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7095 << "): " << "!offsetMustBeConst" )); | |||
7096 | return; | |||
7097 | } | |||
7098 | ||||
7099 | size_t size = offsetConstantUnion->getType().getObjectSize(); | |||
7100 | const TConstantUnion *values = offsetConstantUnion->getConstantValue(); | |||
7101 | checkSingleTextureOffset(offset->getLine(), values, size, minOffsetValue, maxOffsetValue); | |||
7102 | } | |||
7103 | } | |||
7104 | ||||
7105 | void TParseContext::checkSingleTextureOffset(const TSourceLoc &line, | |||
7106 | const TConstantUnion *values, | |||
7107 | size_t size, | |||
7108 | int minOffsetValue, | |||
7109 | int maxOffsetValue) | |||
7110 | { | |||
7111 | for (size_t i = 0u; i < size; ++i) | |||
7112 | { | |||
7113 | ASSERT(values[i].getType() == EbtInt)(values[i].getType() == EbtInt ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL ))) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify () & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7113, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7113 << "): " << "values[i].getType() == EbtInt" )); | |||
7114 | int offsetValue = values[i].getIConst(); | |||
7115 | if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue) | |||
7116 | { | |||
7117 | std::stringstream tokenStream = sh::InitializeStream<std::stringstream>(); | |||
7118 | tokenStream << offsetValue; | |||
7119 | std::string token = tokenStream.str(); | |||
7120 | error(line, "Texture offset value out of valid range", token.c_str()); | |||
7121 | } | |||
7122 | } | |||
7123 | } | |||
7124 | ||||
7125 | void TParseContext::checkInterpolationFS(TIntermAggregate *functionCall) | |||
7126 | { | |||
7127 | const TFunction *func = functionCall->getFunction(); | |||
7128 | if (!BuiltInGroup::IsInterpolationFS(functionCall->getOp())) | |||
7129 | { | |||
7130 | return; | |||
7131 | } | |||
7132 | ||||
7133 | TIntermTyped *arg0 = nullptr; | |||
7134 | ||||
7135 | if (functionCall->getAsAggregate()) | |||
7136 | { | |||
7137 | const TIntermSequence *argp = functionCall->getSequence(); | |||
7138 | if (argp->size() > 0) | |||
7139 | arg0 = (*argp)[0]->getAsTyped(); | |||
7140 | } | |||
7141 | else | |||
7142 | { | |||
7143 | assert(functionCall->getAsUnaryNode())(static_cast <bool> (functionCall->getAsUnaryNode()) ? void (0) : __assert_fail ("functionCall->getAsUnaryNode()" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
7144 | arg0 = functionCall->getAsUnaryNode()->getOperand(); | |||
7145 | } | |||
7146 | ||||
7147 | // Make sure the first argument is an interpolant, or an array element of an interpolant | |||
7148 | if (!IsVaryingIn(arg0->getType().getQualifier())) | |||
7149 | { | |||
7150 | // It might still be an array element. | |||
7151 | const TIntermTyped *base = FindLValueBase(arg0); | |||
7152 | ||||
7153 | if (base == nullptr || (!IsVaryingIn(base->getType().getQualifier()))) | |||
7154 | error(arg0->getLine(), | |||
7155 | "first argument must be an interpolant, or interpolant-array element", | |||
7156 | func->name()); | |||
7157 | } | |||
7158 | } | |||
7159 | ||||
7160 | void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall) | |||
7161 | { | |||
7162 | const TFunction *func = functionCall->getFunction(); | |||
7163 | if (BuiltInGroup::IsAtomicMemory(functionCall->getOp())) | |||
7164 | { | |||
7165 | TIntermSequence *arguments = functionCall->getSequence(); | |||
7166 | TIntermTyped *memNode = (*arguments)[0]->getAsTyped(); | |||
7167 | ||||
7168 | if (IsBufferOrSharedVariable(memNode)) | |||
7169 | { | |||
7170 | return; | |||
7171 | } | |||
7172 | ||||
7173 | while (memNode->getAsBinaryNode() || memNode->getAsSwizzleNode()) | |||
7174 | { | |||
7175 | // Child 0 is "left" if binary, and the expression being swizzled if swizzle. | |||
7176 | // Note: we don't need to check that the binary operation is one of EOp*Index*, as any | |||
7177 | // other operation will result in a temp value which cannot be passed to this | |||
7178 | // out/inout parameter anyway. | |||
7179 | memNode = memNode->getChildNode(0)->getAsTyped(); | |||
7180 | if (IsBufferOrSharedVariable(memNode)) | |||
7181 | { | |||
7182 | return; | |||
7183 | } | |||
7184 | } | |||
7185 | ||||
7186 | error(memNode->getLine(), | |||
7187 | "The value passed to the mem argument of an atomic memory function does not " | |||
7188 | "correspond to a buffer or shared variable.", | |||
7189 | func->name()); | |||
7190 | } | |||
7191 | } | |||
7192 | ||||
7193 | // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers | |||
7194 | void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall) | |||
7195 | { | |||
7196 | const TOperator op = functionCall->getOp(); | |||
7197 | ||||
7198 | if (BuiltInGroup::IsImage(op)) | |||
7199 | { | |||
7200 | TIntermSequence *arguments = functionCall->getSequence(); | |||
7201 | TIntermTyped *imageNode = (*arguments)[0]->getAsTyped(); | |||
7202 | ||||
7203 | const TMemoryQualifier &memoryQualifier = imageNode->getMemoryQualifier(); | |||
7204 | ||||
7205 | if (BuiltInGroup::IsImageStore(op)) | |||
7206 | { | |||
7207 | if (memoryQualifier.readonly) | |||
7208 | { | |||
7209 | error(imageNode->getLine(), | |||
7210 | "'imageStore' cannot be used with images qualified as 'readonly'", | |||
7211 | GetImageArgumentToken(imageNode)); | |||
7212 | } | |||
7213 | } | |||
7214 | else if (BuiltInGroup::IsImageLoad(op)) | |||
7215 | { | |||
7216 | if (memoryQualifier.writeonly) | |||
7217 | { | |||
7218 | error(imageNode->getLine(), | |||
7219 | "'imageLoad' cannot be used with images qualified as 'writeonly'", | |||
7220 | GetImageArgumentToken(imageNode)); | |||
7221 | } | |||
7222 | } | |||
7223 | else if (BuiltInGroup::IsImageAtomic(op)) | |||
7224 | { | |||
7225 | if (memoryQualifier.readonly) | |||
7226 | { | |||
7227 | error(imageNode->getLine(), | |||
7228 | "'imageAtomic' cannot be used with images qualified as 'readonly'", | |||
7229 | GetImageArgumentToken(imageNode)); | |||
7230 | } | |||
7231 | if (memoryQualifier.writeonly) | |||
7232 | { | |||
7233 | error(imageNode->getLine(), | |||
7234 | "'imageAtomic' cannot be used with images qualified as 'writeonly'", | |||
7235 | GetImageArgumentToken(imageNode)); | |||
7236 | } | |||
7237 | } | |||
7238 | } | |||
7239 | } | |||
7240 | ||||
7241 | // GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters | |||
7242 | void TParseContext::checkImageMemoryAccessForUserDefinedFunctions( | |||
7243 | const TFunction *functionDefinition, | |||
7244 | const TIntermAggregate *functionCall) | |||
7245 | { | |||
7246 | ASSERT(functionCall->getOp() == EOpCallFunctionInAST)(functionCall->getOp() == EOpCallFunctionInAST ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7246, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7246 << "): " << "functionCall->getOp() == EOpCallFunctionInAST" )); | |||
7247 | ||||
7248 | const TIntermSequence &arguments = *functionCall->getSequence(); | |||
7249 | ||||
7250 | ASSERT(functionDefinition->getParamCount() == arguments.size())(functionDefinition->getParamCount() == arguments.size() ? static_cast<void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7250, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7250 << "): " << "functionDefinition->getParamCount() == arguments.size()" )); | |||
7251 | ||||
7252 | for (size_t i = 0; i < arguments.size(); ++i) | |||
7253 | { | |||
7254 | TIntermTyped *typedArgument = arguments[i]->getAsTyped(); | |||
7255 | const TType &functionArgumentType = typedArgument->getType(); | |||
7256 | const TType &functionParameterType = functionDefinition->getParam(i)->getType(); | |||
7257 | ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType())(functionArgumentType.getBasicType() == functionParameterType .getBasicType() ? static_cast<void>(0) : (!((::gl::priv ::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7257, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7257 << "): " << "functionArgumentType.getBasicType() == functionParameterType.getBasicType()" )); | |||
7258 | ||||
7259 | if (IsImage(functionArgumentType.getBasicType())) | |||
7260 | { | |||
7261 | const TMemoryQualifier &functionArgumentMemoryQualifier = | |||
7262 | functionArgumentType.getMemoryQualifier(); | |||
7263 | const TMemoryQualifier &functionParameterMemoryQualifier = | |||
7264 | functionParameterType.getMemoryQualifier(); | |||
7265 | if (functionArgumentMemoryQualifier.readonly && | |||
7266 | !functionParameterMemoryQualifier.readonly) | |||
7267 | { | |||
7268 | error(functionCall->getLine(), | |||
7269 | "Function call discards the 'readonly' qualifier from image", | |||
7270 | GetImageArgumentToken(typedArgument)); | |||
7271 | } | |||
7272 | ||||
7273 | if (functionArgumentMemoryQualifier.writeonly && | |||
7274 | !functionParameterMemoryQualifier.writeonly) | |||
7275 | { | |||
7276 | error(functionCall->getLine(), | |||
7277 | "Function call discards the 'writeonly' qualifier from image", | |||
7278 | GetImageArgumentToken(typedArgument)); | |||
7279 | } | |||
7280 | ||||
7281 | if (functionArgumentMemoryQualifier.coherent && | |||
7282 | !functionParameterMemoryQualifier.coherent) | |||
7283 | { | |||
7284 | error(functionCall->getLine(), | |||
7285 | "Function call discards the 'coherent' qualifier from image", | |||
7286 | GetImageArgumentToken(typedArgument)); | |||
7287 | } | |||
7288 | ||||
7289 | if (functionArgumentMemoryQualifier.volatileQualifier && | |||
7290 | !functionParameterMemoryQualifier.volatileQualifier) | |||
7291 | { | |||
7292 | error(functionCall->getLine(), | |||
7293 | "Function call discards the 'volatile' qualifier from image", | |||
7294 | GetImageArgumentToken(typedArgument)); | |||
7295 | } | |||
7296 | } | |||
7297 | } | |||
7298 | } | |||
7299 | ||||
7300 | TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) | |||
7301 | { | |||
7302 | if (fnCall->thisNode() != nullptr) | |||
7303 | { | |||
7304 | return addMethod(fnCall, loc); | |||
7305 | } | |||
7306 | if (fnCall->isConstructor()) | |||
7307 | { | |||
7308 | return addConstructor(fnCall, loc); | |||
7309 | } | |||
7310 | return addNonConstructorFunctionCall(fnCall, loc); | |||
7311 | } | |||
7312 | ||||
7313 | TIntermTyped *TParseContext::addMethod(TFunctionLookup *fnCall, const TSourceLoc &loc) | |||
7314 | { | |||
7315 | TIntermTyped *thisNode = fnCall->thisNode(); | |||
7316 | // It's possible for the name pointer in the TFunction to be null in case it gets parsed as | |||
7317 | // a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS | |||
7318 | // mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead. | |||
7319 | // So accessing fnCall->name() below is safe. | |||
7320 | if (fnCall->name() != "length") | |||
7321 | { | |||
7322 | error(loc, "invalid method", fnCall->name()); | |||
7323 | } | |||
7324 | else if (!fnCall->arguments().empty()) | |||
7325 | { | |||
7326 | error(loc, "method takes no parameters", "length"); | |||
7327 | } | |||
7328 | else if (!thisNode->isArray()) | |||
7329 | { | |||
7330 | error(loc, "length can only be called on arrays", "length"); | |||
7331 | } | |||
7332 | else if (thisNode->getQualifier() == EvqPerVertexIn && | |||
7333 | mGeometryShaderInputPrimitiveType == EptUndefined) | |||
7334 | { | |||
7335 | ASSERT(mShaderType == GL_GEOMETRY_SHADER_EXT)(mShaderType == 0x8DD9 ? static_cast<void>(0) : (!((::gl ::priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7335, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7335 << "): " << "mShaderType == GL_GEOMETRY_SHADER_EXT" )); | |||
7336 | error(loc, "missing input primitive declaration before calling length on gl_in", "length"); | |||
7337 | } | |||
7338 | else | |||
7339 | { | |||
7340 | TIntermUnary *node = new TIntermUnary(EOpArrayLength, thisNode, nullptr); | |||
7341 | markStaticReadIfSymbol(thisNode); | |||
7342 | node->setLine(loc); | |||
7343 | return node->fold(mDiagnostics); | |||
7344 | } | |||
7345 | return CreateZeroNode(TType(EbtInt, EbpUndefined, EvqConst)); | |||
7346 | } | |||
7347 | ||||
7348 | TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCall, | |||
7349 | const TSourceLoc &loc) | |||
7350 | { | |||
7351 | // First check whether the function has been hidden by a variable name or struct typename by | |||
7352 | // using the symbol looked up in the lexical phase. If the function is not hidden, look for one | |||
7353 | // with a matching argument list. | |||
7354 | if (fnCall->symbol() != nullptr && !fnCall->symbol()->isFunction()) | |||
7355 | { | |||
7356 | error(loc, "function name expected", fnCall->name()); | |||
7357 | } | |||
7358 | else | |||
7359 | { | |||
7360 | // There are no inner functions, so it's enough to look for user-defined functions in the | |||
7361 | // global scope. | |||
7362 | const TSymbol *symbol = symbolTable.findGlobal(fnCall->getMangledName()); | |||
7363 | ||||
7364 | if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec)) | |||
7365 | { | |||
7366 | // If using Desktop GL spec, need to check for implicit conversion | |||
7367 | symbol = symbolTable.findGlobalWithConversion( | |||
7368 | fnCall->getMangledNamesForImplicitConversions()); | |||
7369 | } | |||
7370 | ||||
7371 | if (symbol != nullptr) | |||
7372 | { | |||
7373 | // A user-defined function - could be an overloaded built-in as well. | |||
7374 | ASSERT(symbol->symbolType() == SymbolType::UserDefined)(symbol->symbolType() == SymbolType::UserDefined ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7374, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7374 << "): " << "symbol->symbolType() == SymbolType::UserDefined" )); | |||
7375 | const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); | |||
7376 | TIntermAggregate *callNode = | |||
7377 | TIntermAggregate::CreateFunctionCall(*fnCandidate, &fnCall->arguments()); | |||
7378 | callNode->setLine(loc); | |||
7379 | checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, callNode); | |||
7380 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); | |||
7381 | return callNode; | |||
7382 | } | |||
7383 | ||||
7384 | symbol = symbolTable.findBuiltIn(fnCall->getMangledName(), mShaderVersion); | |||
7385 | ||||
7386 | if (symbol == nullptr && IsDesktopGLSpec(mShaderSpec)) | |||
7387 | { | |||
7388 | // If using Desktop GL spec, need to check for implicit conversion | |||
7389 | symbol = symbolTable.findBuiltInWithConversion( | |||
7390 | fnCall->getMangledNamesForImplicitConversions(), mShaderVersion); | |||
7391 | } | |||
7392 | ||||
7393 | if (symbol != nullptr) | |||
7394 | { | |||
7395 | // A built-in function. | |||
7396 | ASSERT(symbol->symbolType() == SymbolType::BuiltIn)(symbol->symbolType() == SymbolType::BuiltIn ? static_cast <void>(0) : (!((::gl::priv::ShouldCreatePlatformLogMessage (::gl::LOG_FATAL))) ? static_cast<void>(0) : ::gl::priv ::LogMessageVoidify() & (::gl::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7396, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7396 << "): " << "symbol->symbolType() == SymbolType::BuiltIn" )); | |||
7397 | const TFunction *fnCandidate = static_cast<const TFunction *>(symbol); | |||
7398 | ||||
7399 | if (!fnCandidate->extensions().empty() && | |||
7400 | fnCandidate->extensions()[0] != TExtension::UNDEFINED) | |||
7401 | { | |||
7402 | checkCanUseOneOfExtensions(loc, fnCandidate->extensions()); | |||
7403 | } | |||
7404 | ||||
7405 | // All function calls are mapped to a built-in operation. | |||
7406 | TOperator op = fnCandidate->getBuiltInOp(); | |||
7407 | if (BuiltInGroup::IsMath(op) && fnCandidate->getParamCount() == 1) | |||
7408 | { | |||
7409 | // Treat it like a built-in unary operator. | |||
7410 | TIntermNode *unaryParamNode = fnCall->arguments().front(); | |||
7411 | TIntermTyped *callNode = | |||
7412 | createUnaryMath(op, unaryParamNode->getAsTyped(), loc, fnCandidate); | |||
7413 | ASSERT(callNode != nullptr)(callNode != nullptr ? static_cast<void>(0) : (!((::gl:: priv::ShouldCreatePlatformLogMessage(::gl::LOG_FATAL))) ? static_cast <void>(0) : ::gl::priv::LogMessageVoidify() & (::gl ::LogMessage("/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" , __FUNCTION__, 7413, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in " << __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/ParseContext.cpp" << ":" << 7413 << "): " << "callNode != nullptr" )); | |||
7414 | return callNode; | |||
7415 | } | |||
7416 | ||||
7417 | TIntermAggregate *callNode = | |||
7418 | TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, &fnCall->arguments()); | |||
7419 | callNode->setLine(loc); | |||
7420 | ||||
7421 | checkAtomicMemoryBuiltinFunctions(callNode); | |||
7422 | checkTextureOffset(callNode); | |||
7423 | checkTextureGather(callNode); | |||
7424 | checkInterpolationFS(callNode); | |||
7425 | checkImageMemoryAccessForBuiltinFunctions(callNode); | |||
7426 | ||||
7427 | // Some built-in functions have out parameters too. | |||
7428 | functionCallRValueLValueErrorCheck(fnCandidate, callNode); | |||
7429 | ||||
7430 | // See if we can constant fold a built-in. Note that this may be possible | |||
7431 | // even if it is not const-qualified. | |||
7432 | return callNode->fold(mDiagnostics); | |||
7433 | } | |||
7434 | else | |||
7435 | { | |||
7436 | error(loc, "no matching overloaded function found", fnCall->name()); | |||
7437 | } | |||
7438 | } | |||
7439 | ||||
7440 | // Error message was already written. Put on an unused node for error recovery. | |||
7441 | return CreateZeroNode(TType(EbtFloat, EbpMedium, EvqConst)); | |||
7442 | } | |||
7443 | ||||
7444 | TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, | |||
7445 | TIntermTyped *trueExpression, | |||
7446 | TIntermTyped *falseExpression, | |||
7447 | const TSourceLoc &loc) | |||
7448 | { | |||
7449 | if (!checkIsScalarBool(loc, cond)) | |||
7450 | { | |||
7451 | return falseExpression; | |||
7452 | } | |||
7453 | ||||
7454 | if (trueExpression->getType() != falseExpression->getType()) | |||
7455 | { | |||
7456 | TInfoSinkBase reasonStream; | |||
7457 | reasonStream << "mismatching ternary operator operand types '" << trueExpression->getType() | |||
7458 | << " and '" << falseExpression->getType() << "'"; | |||
7459 | error(loc, reasonStream.c_str(), "?:"); | |||
7460 | return falseExpression; | |||
7461 | } | |||
7462 | if (IsOpaqueType(trueExpression->getBasicType())) | |||
7463 | { | |||
7464 | // ESSL 1.00 section 4.1.7 | |||
7465 | // ESSL 3.00.6 section 4.1.7 | |||
7466 | // Opaque/sampler types are not allowed in most types of expressions, including ternary. | |||
7467 | // Note that structs containing opaque types don't need to be checked as structs are | |||
7468 | // forbidden below. | |||
7469 | error(loc, "ternary operator is not allowed for opaque types", "?:"); | |||
7470 | return falseExpression; | |||
7471 | } | |||
7472 | ||||
7473 | if (cond->getMemoryQualifier().writeonly || trueExpression->getMemoryQualifier().writeonly || | |||
7474 | falseExpression->getMemoryQualifier().writeonly) | |||
7475 | { | |||
7476 | error(loc, "ternary operator is not allowed for variables with writeonly", "?:"); | |||
7477 | return falseExpression; | |||
7478 | } | |||
7479 | ||||
7480 | // ESSL 1.00.17 sections 5.2 and 5.7: | |||
7481 | // Ternary operator is not among the operators allowed for structures/arrays. | |||
7482 | // ESSL 3.00.6 section 5.7: | |||
7483 | // Ternary operator support is optional for arrays. No certainty that it works across all | |||
7484 | // devices with struct either, so we err on the side of caution here. TODO (oetuaho@nvidia.com): | |||
7485 | // Would be nice to make the spec and implementation agree completely here. | |||
7486 | if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct) | |||
7487 | { | |||
7488 | error(loc, "ternary operator is not allowed for structures or arrays", "?:"); | |||
7489 | return falseExpression; | |||
7490 | } | |||
7491 | if (trueExpression->getBasicType() == EbtInterfaceBlock) | |||
7492 | { | |||
7493 | error(loc, "ternary operator is not allowed for interface blocks", "?:"); | |||
7494 | return falseExpression; | |||
7495 | } | |||
7496 | ||||
7497 | // WebGL2 section 5.26, the following results in an error: | |||
7498 | // "Ternary operator applied to void, arrays, or structs containing arrays" | |||
7499 | if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid) | |||
7500 | { | |||
7501 | error(loc, "ternary operator is not allowed for void", "?:"); | |||
7502 | return falseExpression; | |||
7503 | } | |||
7504 | ||||
7505 | TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression); | |||
7506 | markStaticReadIfSymbol(cond); | |||
7507 | markStaticReadIfSymbol(trueExpression); | |||
7508 | markStaticReadIfSymbol(falseExpression); | |||
7509 | node->setLine(loc); | |||
7510 | return expressionOrFoldedResult(node); | |||
7511 | } | |||
7512 | ||||
7513 | // | |||
7514 | // Parse an array of strings using yyparse. | |||
7515 | // | |||
7516 | // Returns 0 for success. | |||
7517 | // | |||
7518 | int PaParseStrings(size_t count, | |||
7519 | const char *const string[], | |||
7520 | const int length[], | |||
7521 | TParseContext *context) | |||
7522 | { | |||
7523 | if ((count == 0) || (string == nullptr)) | |||
7524 | return 1; | |||
7525 | ||||
7526 | if (glslang_initialize(context)) | |||
7527 | return 1; | |||
7528 | ||||
7529 | int error = glslang_scan(count, string, length, context); | |||
7530 | if (!error) | |||
7531 | error = glslang_parse(context); | |||
7532 | ||||
7533 | glslang_finalize(context); | |||
7534 | ||||
7535 | return (error == 0) && (context->numErrors() == 0) ? 0 : 1; | |||
7536 | } | |||
7537 | ||||
7538 | } // namespace sh |