Bug Summary

File:root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp
Warning:line 745, column 17
Value stored to 'preString' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name OutputGLSLBase.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D ANGLE_PLATFORM_EXPORT= -D __NDK_FPABI__= -D ANGLE_SKIP_DXGI_1_2_CHECK -D ANGLE_ENABLE_KEYEDMUTEX -D ANGLE_TRANSLATOR_ESSL_ONLY -D ANGLE_DISABLE_POOL_ALLOC -D ANGLE_ENABLE_APPLE_WORKAROUNDS -D ANGLE_ENABLE_ESSL -D ANGLE_ENABLE_GLSL -D ANGLE_ENABLE_HLSL -D ANGLE_ENABLE_SHARE_CONTEXT_LOCK=1 -D ANGLE_VMA_VERSION=2003000 -D CR_CLANG_REVISION="llvmorg-16-init-6578-g0d30e92f-2" -D DYNAMIC_ANNOTATIONS_ENABLED=0 -D NOMINMAX -D UNICODE -D WINVER=0x0A00 -D _ATL_NO_OPENGL -D _CRT_NONSTDC_NO_WARNINGS -D _CRT_RAND_S -D _CRT_SECURE_NO_DEPRECATE -D _HAS_EXCEPTIONS=0 -D _SCL_SECURE_NO_DEPRECATE -D _SECURE_ATL -D _UNICODE -D _WINSOCK_DEPRECATED_NO_WARNINGS -I /root/firefox-clang/gfx/angle/targets/translator -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/angle/targets/translator -I /root/firefox-clang/gfx/angle/checkout/include -I /root/firefox-clang/gfx/angle/checkout/src -I /root/firefox-clang/gfx/angle/checkout/src/common/third_party/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-final-dtor-non-final-class -Wno-implicit-const-int-float-conversion -Wno-range-loop-construct -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-30-093548-1913035-1 -x c++ /root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp
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/OutputGLSLBase.h"
8
9#include "angle_gl.h"
10#include "common/debug.h"
11#include "common/mathutil.h"
12#include "compiler/translator/Compiler.h"
13#include "compiler/translator/util.h"
14
15#include <cfloat>
16
17namespace sh
18{
19
20namespace
21{
22
23bool isSingleStatement(TIntermNode *node)
24{
25 if (node->getAsFunctionDefinition())
26 {
27 return false;
28 }
29 else if (node->getAsBlock())
30 {
31 return false;
32 }
33 else if (node->getAsIfElseNode())
34 {
35 return false;
36 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
41 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
49 else if (node->getAsPreprocessorDirective())
50 {
51 return false;
52 }
53 return true;
54}
55
56class CommaSeparatedListItemPrefixGenerator
57{
58 public:
59 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
60
61 private:
62 bool mFirst;
63
64 template <typename Stream>
65 friend Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen);
66};
67
68template <typename Stream>
69Stream &operator<<(Stream &out, CommaSeparatedListItemPrefixGenerator &gen)
70{
71 if (gen.mFirst)
72 {
73 gen.mFirst = false;
74 }
75 else
76 {
77 out << ", ";
78 }
79 return out;
80}
81
82} // namespace
83
84TOutputGLSLBase::TOutputGLSLBase(TCompiler *compiler,
85 TInfoSinkBase &objSink,
86 const ShCompileOptions &compileOptions)
87 : TIntermTraverser(true, true, true, &compiler->getSymbolTable()),
88 mObjSink(objSink),
89 mDeclaringVariable(false),
90 mHashFunction(compiler->getHashFunction()),
91 mNameMap(compiler->getNameMap()),
92 mShaderType(compiler->getShaderType()),
93 mShaderVersion(compiler->getShaderVersion()),
94 mOutput(compiler->getOutputType()),
95 mHighPrecisionSupported(compiler->isHighPrecisionSupported()),
96 // If pixel local storage introduces new fragment outputs, we are now required to specify a
97 // location for _all_ fragment outputs, including previously valid outputs that had an
98 // implicit location of zero.
99 mAlwaysSpecifyFragOutLocation(compiler->hasPixelLocalStorageUniforms() &&
100 compileOptions.pls.type ==
101 ShPixelLocalStorageType::FramebufferFetch),
102 mCompileOptions(compileOptions)
103{}
104
105void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
106{
107 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
108 {
109 TInfoSinkBase &out = objSink();
110 out << "invariant ";
111 }
112}
113
114void TOutputGLSLBase::writePreciseQualifier(const TType &type)
115{
116 TInfoSinkBase &out = objSink();
117 out << "precise ";
118}
119
120void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
121{
122 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
123 {
124 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
125 }
126 else
127 {
128 out << std::min(FLT_MAX3.40282347e+38F, std::max(-FLT_MAX3.40282347e+38F, f));
129 }
130}
131
132void TOutputGLSLBase::writeTriplet(Visit visit,
133 const char *preStr,
134 const char *inStr,
135 const char *postStr)
136{
137 TInfoSinkBase &out = objSink();
138 if (visit == PreVisit && preStr)
139 out << preStr;
140 else if (visit == InVisit && inStr)
141 out << inStr;
142 else if (visit == PostVisit && postStr)
143 out << postStr;
144}
145
146void TOutputGLSLBase::writeFunctionTriplet(Visit visit,
147 const ImmutableString &functionName,
148 bool useEmulatedFunction)
149{
150 TInfoSinkBase &out = objSink();
151 if (visit == PreVisit)
152 {
153 if (useEmulatedFunction)
154 {
155 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, functionName.data());
156 }
157 else
158 {
159 out << functionName;
160 }
161 out << "(";
162 }
163 else
164 {
165 writeTriplet(visit, nullptr, ", ", ")");
166 }
167}
168
169// Outputs what goes inside layout(), except for location and binding qualifiers, as they are
170// handled differently between GL GLSL and Vulkan GLSL.
171std::string TOutputGLSLBase::getCommonLayoutQualifiers(TIntermSymbol *variable)
172{
173 std::ostringstream out;
174 CommaSeparatedListItemPrefixGenerator listItemPrefix;
175
176 const TType &type = variable->getType();
177 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
178
179 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqFragmentInOut)
180 {
181 if (layoutQualifier.index >= 0)
182 {
183 out << listItemPrefix << "index = " << layoutQualifier.index;
184 }
185 if (layoutQualifier.yuv)
186 {
187 out << listItemPrefix << "yuv";
188 }
189 }
190
191 if (type.getQualifier() == EvqFragmentInOut && layoutQualifier.noncoherent)
192 {
193 out << listItemPrefix << "noncoherent";
194 }
195
196 if (IsImage(type.getBasicType()))
197 {
198 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
199 {
200 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform)(type.getQualifier() == EvqTemporary || type.getQualifier() ==
EvqUniform ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 200, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 200 << "): " << "type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform"
))
;
201 out << listItemPrefix
202 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
203 }
204 }
205
206 if (IsAtomicCounter(type.getBasicType()))
207 {
208 out << listItemPrefix << "offset = " << layoutQualifier.offset;
209 }
210
211 return out.str();
212}
213
214// Outputs memory qualifiers applied to images, buffers and its fields, as well as image function
215// arguments.
216std::string TOutputGLSLBase::getMemoryQualifiers(const TType &type)
217{
218 std::ostringstream out;
219
220 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
221 if (memoryQualifier.readonly)
222 {
223 out << "readonly ";
224 }
225
226 if (memoryQualifier.writeonly)
227 {
228 out << "writeonly ";
229 }
230
231 if (memoryQualifier.coherent)
232 {
233 out << "coherent ";
234 }
235
236 if (memoryQualifier.restrictQualifier)
237 {
238 out << "restrict ";
239 }
240
241 if (memoryQualifier.volatileQualifier)
242 {
243 out << "volatile ";
244 }
245
246 return out.str();
247}
248
249void TOutputGLSLBase::writeLayoutQualifier(TIntermSymbol *variable)
250{
251 const TType &type = variable->getType();
252
253 if (!needsToWriteLayoutQualifier(type))
254 {
255 return;
256 }
257
258 if (type.getBasicType() == EbtInterfaceBlock)
259 {
260 declareInterfaceBlockLayout(type);
261 return;
262 }
263
264 TInfoSinkBase &out = objSink();
265 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
266 out << "layout(";
267
268 CommaSeparatedListItemPrefixGenerator listItemPrefix;
269
270 if (IsFragmentOutput(type.getQualifier()) || type.getQualifier() == EvqVertexIn ||
271 IsVarying(type.getQualifier()))
272 {
273 if (layoutQualifier.location >= 0 ||
274 (mAlwaysSpecifyFragOutLocation && IsFragmentOutput(type.getQualifier())))
275 {
276 out << listItemPrefix << "location = " << std::max(layoutQualifier.location, 0);
277 }
278 }
279
280 if (IsOpaqueType(type.getBasicType()))
281 {
282 if (layoutQualifier.binding >= 0)
283 {
284 out << listItemPrefix << "binding = " << layoutQualifier.binding;
285 }
286 }
287
288 std::string otherQualifiers = getCommonLayoutQualifiers(variable);
289 if (!otherQualifiers.empty())
290 {
291 out << listItemPrefix << otherQualifiers;
292 }
293
294 out << ") ";
295}
296
297void TOutputGLSLBase::writeFieldLayoutQualifier(const TField *field)
298{
299 if (!field->type()->isMatrix() && !field->type()->isStructureContainingMatrices())
300 {
301 return;
302 }
303
304 TInfoSinkBase &out = objSink();
305
306 out << "layout(";
307 switch (field->type()->getLayoutQualifier().matrixPacking)
308 {
309 case EmpUnspecified:
310 case EmpColumnMajor:
311 // Default matrix packing is column major.
312 out << "column_major";
313 break;
314
315 case EmpRowMajor:
316 out << "row_major";
317 break;
318
319 default:
320 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/OutputGLSLBase.cpp"
, __FUNCTION__, 320, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 320 << ")"; } while (0)
;
321 break;
322 }
323 out << ") ";
324}
325
326void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol)
327{
328 const char *result = mapQualifierToString(qualifier);
329 if (result && result[0] != '\0')
330 {
331 objSink() << result << " ";
332 }
333
334 objSink() << getMemoryQualifiers(type);
335}
336
337const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
338{
339 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
340 mCompileOptions.removeInvariantAndCentroidForESSL3)
341 {
342 switch (qualifier)
343 {
344 // The return string is consistent with sh::getQualifierString() from
345 // BaseTypes.h minus the "centroid" keyword.
346 case EvqCentroid:
347 return "";
348 case EvqCentroidIn:
349 return "smooth in";
350 case EvqCentroidOut:
351 return "smooth out";
352 default:
353 break;
354 }
355 }
356 if (sh::IsGLSL130OrNewer(mOutput))
357 {
358 switch (qualifier)
359 {
360 case EvqAttribute:
361 return "in";
362 case EvqVaryingIn:
363 return "in";
364 case EvqVaryingOut:
365 return "out";
366 default:
367 break;
368 }
369 }
370
371 switch (qualifier)
372 {
373 // gl_ClipDistance / gl_CullDistance require different qualifiers based on shader type.
374 case EvqClipDistance:
375 case EvqCullDistance:
376 return mShaderType == GL_FRAGMENT_SHADER0x8B30 ? "in" : "out";
377
378 // gl_LastFragColor / gl_LastFragData have no qualifiers.
379 case EvqLastFragData:
380 case EvqLastFragColor:
381 return nullptr;
382
383 default:
384 return sh::getQualifierString(qualifier);
385 }
386}
387
388namespace
389{
390
391constexpr char kIndent[] = " "; // 10x2 spaces
392constexpr int kIndentWidth = 2;
393constexpr int kMaxIndentLevel = sizeof(kIndent) / kIndentWidth;
394
395} // namespace
396
397const char *TOutputGLSLBase::getIndentPrefix(int extraIndentation)
398{
399 int indentDepth = std::min(kMaxIndentLevel, getCurrentBlockDepth() + extraIndentation);
400 ASSERT(indentDepth >= 0)(indentDepth >= 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/OutputGLSLBase.cpp"
, __FUNCTION__, 400, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 400 << "): " << "indentDepth >= 0"
))
;
401 return kIndent + (kMaxIndentLevel - indentDepth) * kIndentWidth;
402}
403
404void TOutputGLSLBase::writeVariableType(const TType &type,
405 const TSymbol *symbol,
406 bool isFunctionArgument)
407{
408 TQualifier qualifier = type.getQualifier();
409 TInfoSinkBase &out = objSink();
410 if (type.isInvariant())
411 {
412 writeInvariantQualifier(type);
413 }
414 if (type.isPrecise())
415 {
416 writePreciseQualifier(type);
417 }
418 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
419 {
420 writeQualifier(qualifier, type, symbol);
421 }
422 if (isFunctionArgument)
423 {
424 // Function arguments are the only place (other than image/SSBO/field declaration) where
425 // memory qualifiers can appear.
426 out << getMemoryQualifiers(type);
427 }
428
429 // Declare the struct.
430 if (type.isStructSpecifier())
431 {
432 const TStructure *structure = type.getStruct();
433
434 declareStruct(structure);
435 }
436 else if (type.getBasicType() == EbtInterfaceBlock)
437 {
438 declareInterfaceBlock(type);
439 }
440 else
441 {
442 if (writeVariablePrecision(type.getPrecision()))
443 out << " ";
444 out << getTypeName(type);
445 }
446}
447
448void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
449{
450 TInfoSinkBase &out = objSink();
451 size_t paramCount = func->getParamCount();
452 for (size_t i = 0; i < paramCount; ++i)
453 {
454 const TVariable *param = func->getParam(i);
455 const TType &type = param->getType();
456 writeVariableType(type, param, true);
457
458 if (param->symbolType() != SymbolType::Empty)
459 {
460 out << " " << hashName(param);
461 }
462 if (type.isArray())
463 {
464 out << ArrayString(type);
465 }
466
467 // Put a comma if this is not the last argument.
468 if (i != paramCount - 1)
469 out << ", ";
470 }
471}
472
473const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
474 const TConstantUnion *pConstUnion)
475{
476 TInfoSinkBase &out = objSink();
477
478 if (type.getBasicType() == EbtStruct)
479 {
480 const TStructure *structure = type.getStruct();
481 out << hashName(structure) << "(";
482
483 const TFieldList &fields = structure->fields();
484 for (size_t i = 0; i < fields.size(); ++i)
485 {
486 const TType *fieldType = fields[i]->type();
487 ASSERT(fieldType != nullptr)(fieldType != 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/OutputGLSLBase.cpp"
, __FUNCTION__, 487, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 487 << "): " << "fieldType != nullptr"
))
;
488 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
489 if (i != fields.size() - 1)
490 out << ", ";
491 }
492 out << ")";
493 }
494 else
495 {
496 size_t size = type.getObjectSize();
497 bool writeType = size > 1;
498 if (writeType)
499 out << getTypeName(type) << "(";
500 for (size_t i = 0; i < size; ++i, ++pConstUnion)
501 {
502 switch (pConstUnion->getType())
503 {
504 case EbtFloat:
505 writeFloat(out, pConstUnion->getFConst());
506 break;
507 case EbtInt:
508 out << pConstUnion->getIConst();
509 break;
510 case EbtUInt:
511 out << pConstUnion->getUConst() << "u";
512 break;
513 case EbtBool:
514 out << pConstUnion->getBConst();
515 break;
516 case EbtYuvCscStandardEXT:
517 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
518 break;
519 default:
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/OutputGLSLBase.cpp"
, __FUNCTION__, 520, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 520 << ")"; } while (0)
;
521 }
522 if (i != size - 1)
523 out << ", ";
524 }
525 if (writeType)
526 out << ")";
527 }
528 return pConstUnion;
529}
530
531void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
532{
533 TInfoSinkBase &out = objSink();
534 if (visit == PreVisit)
535 {
536 if (type.isArray())
537 {
538 out << getTypeName(type);
539 out << ArrayString(type);
540 out << "(";
541 }
542 else
543 {
544 out << getTypeName(type) << "(";
545 }
546 }
547 else
548 {
549 writeTriplet(visit, nullptr, ", ", ")");
550 }
551}
552
553void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
554{
555 TInfoSinkBase &out = objSink();
556 out << hashName(&node->variable());
557
558 if (mDeclaringVariable && node->getType().isArray())
559 out << ArrayString(node->getType());
560}
561
562void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
563{
564 writeConstantUnion(node->getType(), node->getConstantValue());
565}
566
567bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
568{
569 TInfoSinkBase &out = objSink();
570 if (visit == PostVisit)
571 {
572 out << ".";
573 node->writeOffsetsAsXYZW(&out);
574 }
575 return true;
576}
577
578bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
579{
580 bool visitChildren = true;
581 TInfoSinkBase &out = objSink();
582 switch (node->getOp())
583 {
584 case EOpComma:
585 writeTriplet(visit, "(", ", ", ")");
586 break;
587 case EOpInitialize:
588 if (visit == InVisit)
589 {
590 out << " = ";
591 // RHS of initialize is not being declared.
592 mDeclaringVariable = false;
593 }
594 break;
595 case EOpAssign:
596 writeTriplet(visit, "(", " = ", ")");
597 break;
598 case EOpAddAssign:
599 writeTriplet(visit, "(", " += ", ")");
600 break;
601 case EOpSubAssign:
602 writeTriplet(visit, "(", " -= ", ")");
603 break;
604 case EOpDivAssign:
605 writeTriplet(visit, "(", " /= ", ")");
606 break;
607 case EOpIModAssign:
608 writeTriplet(visit, "(", " %= ", ")");
609 break;
610 // Notice the fall-through.
611 case EOpMulAssign:
612 case EOpVectorTimesMatrixAssign:
613 case EOpVectorTimesScalarAssign:
614 case EOpMatrixTimesScalarAssign:
615 case EOpMatrixTimesMatrixAssign:
616 writeTriplet(visit, "(", " *= ", ")");
617 break;
618 case EOpBitShiftLeftAssign:
619 writeTriplet(visit, "(", " <<= ", ")");
620 break;
621 case EOpBitShiftRightAssign:
622 writeTriplet(visit, "(", " >>= ", ")");
623 break;
624 case EOpBitwiseAndAssign:
625 writeTriplet(visit, "(", " &= ", ")");
626 break;
627 case EOpBitwiseXorAssign:
628 writeTriplet(visit, "(", " ^= ", ")");
629 break;
630 case EOpBitwiseOrAssign:
631 writeTriplet(visit, "(", " |= ", ")");
632 break;
633
634 case EOpIndexDirect:
635 case EOpIndexIndirect:
636 writeTriplet(visit, nullptr, "[", "]");
637 break;
638 case EOpIndexDirectStruct:
639 if (visit == InVisit)
640 {
641 // Here we are writing out "foo.bar", where "foo" is struct
642 // and "bar" is field. In AST, it is represented as a binary
643 // node, where left child represents "foo" and right child "bar".
644 // The node itself represents ".". The struct field "bar" is
645 // actually stored as an index into TStructure::fields.
646 out << ".";
647 const TStructure *structure = node->getLeft()->getType().getStruct();
648 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
649 const TField *field = structure->fields()[index->getIConst(0)];
650
651 out << hashFieldName(field);
652 visitChildren = false;
653 }
654 break;
655 case EOpIndexDirectInterfaceBlock:
656 if (visit == InVisit)
657 {
658 out << ".";
659 const TInterfaceBlock *interfaceBlock =
660 node->getLeft()->getType().getInterfaceBlock();
661 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
662 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
663 out << hashFieldName(field);
664 visitChildren = false;
665 }
666 break;
667
668 case EOpAdd:
669 writeTriplet(visit, "(", " + ", ")");
670 break;
671 case EOpSub:
672 writeTriplet(visit, "(", " - ", ")");
673 break;
674 case EOpMul:
675 writeTriplet(visit, "(", " * ", ")");
676 break;
677 case EOpDiv:
678 writeTriplet(visit, "(", " / ", ")");
679 break;
680 case EOpIMod:
681 writeTriplet(visit, "(", " % ", ")");
682 break;
683 case EOpBitShiftLeft:
684 writeTriplet(visit, "(", " << ", ")");
685 break;
686 case EOpBitShiftRight:
687 writeTriplet(visit, "(", " >> ", ")");
688 break;
689 case EOpBitwiseAnd:
690 writeTriplet(visit, "(", " & ", ")");
691 break;
692 case EOpBitwiseXor:
693 writeTriplet(visit, "(", " ^ ", ")");
694 break;
695 case EOpBitwiseOr:
696 writeTriplet(visit, "(", " | ", ")");
697 break;
698
699 case EOpEqual:
700 writeTriplet(visit, "(", " == ", ")");
701 break;
702 case EOpNotEqual:
703 writeTriplet(visit, "(", " != ", ")");
704 break;
705 case EOpLessThan:
706 writeTriplet(visit, "(", " < ", ")");
707 break;
708 case EOpGreaterThan:
709 writeTriplet(visit, "(", " > ", ")");
710 break;
711 case EOpLessThanEqual:
712 writeTriplet(visit, "(", " <= ", ")");
713 break;
714 case EOpGreaterThanEqual:
715 writeTriplet(visit, "(", " >= ", ")");
716 break;
717
718 // Notice the fall-through.
719 case EOpVectorTimesScalar:
720 case EOpVectorTimesMatrix:
721 case EOpMatrixTimesVector:
722 case EOpMatrixTimesScalar:
723 case EOpMatrixTimesMatrix:
724 writeTriplet(visit, "(", " * ", ")");
725 break;
726
727 case EOpLogicalOr:
728 writeTriplet(visit, "(", " || ", ")");
729 break;
730 case EOpLogicalXor:
731 writeTriplet(visit, "(", " ^^ ", ")");
732 break;
733 case EOpLogicalAnd:
734 writeTriplet(visit, "(", " && ", ")");
735 break;
736 default:
737 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/OutputGLSLBase.cpp"
, __FUNCTION__, 737, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 737 << ")"; } while (0)
;
738 }
739
740 return visitChildren;
741}
742
743bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
744{
745 const char *preString = "";
Value stored to 'preString' during its initialization is never read
746 const char *postString = ")";
747
748 switch (node->getOp())
749 {
750 case EOpNegative:
751 preString = "(-";
752 break;
753 case EOpPositive:
754 preString = "(+";
755 break;
756 case EOpLogicalNot:
757 preString = "(!";
758 break;
759 case EOpBitwiseNot:
760 preString = "(~";
761 break;
762
763 case EOpPostIncrement:
764 preString = "(";
765 postString = "++)";
766 break;
767 case EOpPostDecrement:
768 preString = "(";
769 postString = "--)";
770 break;
771 case EOpPreIncrement:
772 preString = "(++";
773 break;
774 case EOpPreDecrement:
775 preString = "(--";
776 break;
777 case EOpArrayLength:
778 preString = "((";
779 postString = ").length())";
780 break;
781
782 default:
783 writeFunctionTriplet(visit, node->getFunction()->name(),
784 node->getUseEmulatedFunction());
785 return true;
786 }
787
788 writeTriplet(visit, preString, nullptr, postString);
789
790 return true;
791}
792
793bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
794{
795 TInfoSinkBase &out = objSink();
796 // Notice two brackets at the beginning and end. The outer ones
797 // encapsulate the whole ternary expression. This preserves the
798 // order of precedence when ternary expressions are used in a
799 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
800 out << "((";
801 node->getCondition()->traverse(this);
802 out << ") ? (";
803 node->getTrueExpression()->traverse(this);
804 out << ") : (";
805 node->getFalseExpression()->traverse(this);
806 out << "))";
807 return false;
808}
809
810bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
811{
812 TInfoSinkBase &out = objSink();
813
814 out << "if (";
815 node->getCondition()->traverse(this);
816 out << ")\n";
817
818 visitCodeBlock(node->getTrueBlock());
819
820 if (node->getFalseBlock())
821 {
822 out << getIndentPrefix() << "else\n";
823 visitCodeBlock(node->getFalseBlock());
824 }
825 return false;
826}
827
828bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
829{
830 ASSERT(node->getStatementList())(node->getStatementList() ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 830, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 830 << "): " << "node->getStatementList()"
))
;
831 writeTriplet(visit, "switch (", ") ", nullptr);
832 // The curly braces get written when visiting the statementList aggregate
833 return true;
834}
835
836bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
837{
838 if (node->hasCondition())
839 {
840 writeTriplet(visit, "case (", nullptr, "):\n");
841 return true;
842 }
843 else
844 {
845 TInfoSinkBase &out = objSink();
846 out << "default:\n";
847 return false;
848 }
849}
850
851bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
852{
853 TInfoSinkBase &out = objSink();
854 // Scope the blocks except when at the global scope.
855 if (getCurrentTraversalDepth() > 0)
856 {
857 out << "{\n";
858 }
859
860 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
861 iter != node->getSequence()->end(); ++iter)
862 {
863 TIntermNode *curNode = *iter;
864 ASSERT(curNode != nullptr)(curNode != 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/OutputGLSLBase.cpp"
, __FUNCTION__, 864, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 864 << "): " << "curNode != nullptr"
))
;
865
866 out << getIndentPrefix(curNode->getAsCaseNode() ? -1 : 0);
867
868 curNode->traverse(this);
869
870 if (isSingleStatement(curNode))
871 out << ";\n";
872 }
873
874 // Scope the blocks except when at the global scope.
875 if (getCurrentTraversalDepth() > 0)
876 {
877 out << getIndentPrefix(-1) << "}\n";
878 }
879 return false;
880}
881
882bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
883{
884 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
885 prototype->traverse(this);
886 visitCodeBlock(node->getBody());
887
888 // Fully processed; no need to visit children.
889 return false;
890}
891
892bool TOutputGLSLBase::visitGlobalQualifierDeclaration(Visit visit,
893 TIntermGlobalQualifierDeclaration *node)
894{
895 TInfoSinkBase &out = objSink();
896 ASSERT(visit == PreVisit)(visit == PreVisit ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 896, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 896 << "): " << "visit == PreVisit"
))
;
897 const TIntermSymbol *symbol = node->getSymbol();
898 out << (node->isPrecise() ? "precise " : "invariant ") << hashName(&symbol->variable());
899 return false;
900}
901
902void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
903{
904 TInfoSinkBase &out = objSink();
905
906 const TType &type = node->getType();
907 writeVariableType(type, node->getFunction(), false);
908 if (type.isArray())
909 out << ArrayString(type);
910
911 out << " " << hashFunctionNameIfNeeded(node->getFunction());
912
913 out << "(";
914 writeFunctionParameters(node->getFunction());
915 out << ")";
916}
917
918bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
919{
920 bool visitChildren = true;
921 if (node->getOp() == EOpConstruct)
922 {
923 writeConstructorTriplet(visit, node->getType());
924 }
925 else
926 {
927 // Function call.
928 ImmutableString functionName = node->getFunction()->name();
929 if (visit == PreVisit)
930 {
931 // No raw function is expected.
932 ASSERT(node->getOp() != EOpCallInternalRawFunction)(node->getOp() != EOpCallInternalRawFunction ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 932, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 932 << "): " << "node->getOp() != EOpCallInternalRawFunction"
))
;
933
934 if (node->getOp() == EOpCallFunctionInAST)
935 {
936 functionName = hashFunctionNameIfNeeded(node->getFunction());
937 }
938 else
939 {
940 functionName =
941 translateTextureFunction(node->getFunction()->name(), mCompileOptions);
942 }
943 }
944 writeFunctionTriplet(visit, functionName, node->getUseEmulatedFunction());
945 }
946 return visitChildren;
947}
948
949bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
950{
951 TInfoSinkBase &out = objSink();
952
953 // Variable declaration.
954 if (visit == PreVisit)
955 {
956 const TIntermSequence &sequence = *(node->getSequence());
957 TIntermTyped *decl = sequence.front()->getAsTyped();
958 TIntermSymbol *symbolNode = decl->getAsSymbolNode();
959 if (symbolNode == nullptr)
960 {
961 ASSERT(decl->getAsBinaryNode() && decl->getAsBinaryNode()->getOp() == EOpInitialize)(decl->getAsBinaryNode() && decl->getAsBinaryNode
()->getOp() == EOpInitialize ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 961, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 961 << "): " << "decl->getAsBinaryNode() && decl->getAsBinaryNode()->getOp() == EOpInitialize"
))
;
962 symbolNode = decl->getAsBinaryNode()->getLeft()->getAsSymbolNode();
963 }
964 ASSERT(symbolNode)(symbolNode ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 964, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 964 << "): " << "symbolNode"
))
;
965
966 if (symbolNode->getName() != "gl_ClipDistance" &&
967 symbolNode->getName() != "gl_CullDistance")
968 {
969 // gl_Clip/CullDistance re-declaration doesn't need layout.
970 writeLayoutQualifier(symbolNode);
971 }
972
973 writeVariableType(symbolNode->getType(), &symbolNode->variable(), false);
974 if (symbolNode->variable().symbolType() != SymbolType::Empty)
975 {
976 out << " ";
977 }
978 mDeclaringVariable = true;
979 }
980 else if (visit == InVisit)
981 {
982 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/OutputGLSLBase.cpp"
, __FUNCTION__, 982, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 982 << ")"; } while (0)
;
983 }
984 else
985 {
986 mDeclaringVariable = false;
987 }
988 return true;
989}
990
991bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
992{
993 TInfoSinkBase &out = objSink();
994
995 TLoopType loopType = node->getType();
996
997 if (loopType == ELoopFor) // for loop
998 {
999 out << "for (";
1000 if (node->getInit())
1001 node->getInit()->traverse(this);
1002 out << "; ";
1003
1004 if (node->getCondition())
1005 node->getCondition()->traverse(this);
1006 out << "; ";
1007
1008 if (node->getExpression())
1009 node->getExpression()->traverse(this);
1010 out << ")\n";
1011
1012 visitCodeBlock(node->getBody());
1013 }
1014 else if (loopType == ELoopWhile) // while loop
1015 {
1016 out << "while (";
1017 ASSERT(node->getCondition() != nullptr)(node->getCondition() != 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1017, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1017 << "): " << "node->getCondition() != nullptr"
))
;
1018 node->getCondition()->traverse(this);
1019 out << ")\n";
1020
1021 visitCodeBlock(node->getBody());
1022 }
1023 else // do-while loop
1024 {
1025 ASSERT(loopType == ELoopDoWhile)(loopType == 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1025, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1025 << "): " << "loopType == ELoopDoWhile"
))
;
1026 out << "do\n";
1027
1028 visitCodeBlock(node->getBody());
1029
1030 out << "while (";
1031 ASSERT(node->getCondition() != nullptr)(node->getCondition() != 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1031, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1031 << "): " << "node->getCondition() != nullptr"
))
;
1032 node->getCondition()->traverse(this);
1033 out << ");\n";
1034 }
1035
1036 // No need to visit children. They have been already processed in
1037 // this function.
1038 return false;
1039}
1040
1041bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
1042{
1043 switch (node->getFlowOp())
1044 {
1045 case EOpKill:
1046 writeTriplet(visit, "discard", nullptr, nullptr);
1047 break;
1048 case EOpBreak:
1049 writeTriplet(visit, "break", nullptr, nullptr);
1050 break;
1051 case EOpContinue:
1052 writeTriplet(visit, "continue", nullptr, nullptr);
1053 break;
1054 case EOpReturn:
1055 writeTriplet(visit, "return ", nullptr, nullptr);
1056 break;
1057 default:
1058 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1058, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1058 << ")"; } while (0)
;
1059 }
1060
1061 return true;
1062}
1063
1064void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
1065{
1066 TInfoSinkBase &out = objSink();
1067 if (node != nullptr)
1068 {
1069 out << getIndentPrefix();
1070 node->traverse(this);
1071 // Single statements not part of a sequence need to be terminated
1072 // with semi-colon.
1073 if (isSingleStatement(node))
1074 out << ";\n";
1075 }
1076 else
1077 {
1078 out << "{\n}\n"; // Empty code block.
1079 }
1080}
1081
1082void TOutputGLSLBase::visitPreprocessorDirective(TIntermPreprocessorDirective *node)
1083{
1084 TInfoSinkBase &out = objSink();
1085
1086 out << "\n";
1087
1088 switch (node->getDirective())
1089 {
1090 case PreprocessorDirective::Define:
1091 out << "#define";
1092 break;
1093 case PreprocessorDirective::Endif:
1094 out << "#endif";
1095 break;
1096 case PreprocessorDirective::If:
1097 out << "#if";
1098 break;
1099 case PreprocessorDirective::Ifdef:
1100 out << "#ifdef";
1101 break;
1102
1103 default:
1104 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1104, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1104 << ")"; } while (0)
;
1105 break;
1106 }
1107
1108 if (!node->getCommand().empty())
1109 {
1110 out << " " << node->getCommand();
1111 }
1112
1113 out << "\n";
1114}
1115
1116ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
1117{
1118 if (type.getBasicType() == EbtSamplerVideoWEBGL)
1119 {
1120 // TODO(http://anglebug.com/3889): translate SamplerVideoWEBGL into different token
1121 // when necessary (e.g. on Android devices)
1122 return ImmutableString("sampler2D");
1123 }
1124
1125 return GetTypeName(type, mHashFunction, &mNameMap);
1126}
1127
1128ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
1129{
1130 return HashName(symbol, mHashFunction, &mNameMap);
1131}
1132
1133ImmutableString TOutputGLSLBase::hashFieldName(const TField *field)
1134{
1135 ASSERT(field->symbolType() != SymbolType::Empty)(field->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/OutputGLSLBase.cpp"
, __FUNCTION__, 1135, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1135 << "): " << "field->symbolType() != SymbolType::Empty"
))
;
1136 if (field->symbolType() == SymbolType::UserDefined)
1137 {
1138 return HashName(field->name(), mHashFunction, &mNameMap);
1139 }
1140
1141 return field->name();
1142}
1143
1144ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
1145{
1146 if (func->isMain())
1147 {
1148 return func->name();
1149 }
1150 else
1151 {
1152 return hashName(func);
1153 }
1154}
1155
1156void TOutputGLSLBase::declareStruct(const TStructure *structure)
1157{
1158 TInfoSinkBase &out = objSink();
1159
1160 out << "struct ";
1161
1162 if (structure->symbolType() != SymbolType::Empty)
1163 {
1164 out << hashName(structure) << " ";
1165 }
1166 out << "{\n";
1167 const TFieldList &fields = structure->fields();
1168 for (size_t i = 0; i < fields.size(); ++i)
1169 {
1170 out << getIndentPrefix(1);
1171 const TField *field = fields[i];
1172 const TType &fieldType = *field->type();
1173 if (writeVariablePrecision(fieldType.getPrecision()))
1174 {
1175 out << " ";
1176 }
1177 if (fieldType.isPrecise())
1178 {
1179 writePreciseQualifier(fieldType);
1180 }
1181 out << getTypeName(fieldType) << " " << hashFieldName(field);
1182 if (fieldType.isArray())
1183 {
1184 out << ArrayString(fieldType);
1185 }
1186 out << ";\n";
1187 }
1188 out << getIndentPrefix() << "}";
1189}
1190
1191void TOutputGLSLBase::declareInterfaceBlockLayout(const TType &type)
1192{
1193 // 4.4.5 Uniform and Shader Storage Block Layout Qualifiers in GLSL 4.5 spec.
1194 // Layout qualifiers can be used for uniform and shader storage blocks,
1195 // but not for non-block uniform declarations.
1196 if (IsShaderIoBlock(type.getQualifier()))
1197 {
1198 return;
1199 }
1200
1201 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1202 TInfoSinkBase &out = objSink();
1203
1204 out << "layout(";
1205
1206 switch (interfaceBlock->blockStorage())
1207 {
1208 case EbsUnspecified:
1209 case EbsShared:
1210 // Default block storage is shared.
1211 out << "shared";
1212 break;
1213
1214 case EbsPacked:
1215 out << "packed";
1216 break;
1217
1218 case EbsStd140:
1219 out << "std140";
1220 break;
1221
1222 case EbsStd430:
1223 out << "std430";
1224 break;
1225
1226 default:
1227 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1227, ::gl::LOG_FATAL).stream()) << "\t! Unreachable reached: "
<< __FUNCTION__ << "(" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1227 << ")"; } while (0)
;
1228 break;
1229 }
1230
1231 if (interfaceBlock->blockBinding() >= 0)
1232 {
1233 out << ", ";
1234 out << "binding = " << interfaceBlock->blockBinding();
1235 }
1236
1237 out << ") ";
1238}
1239
1240const char *getVariableInterpolation(TQualifier qualifier)
1241{
1242 switch (qualifier)
1243 {
1244 case EvqSmoothOut:
1245 return "smooth out ";
1246 case EvqFlatOut:
1247 return "flat out ";
1248 case EvqNoPerspectiveOut:
1249 return "noperspective out ";
1250 case EvqCentroidOut:
1251 return "centroid out ";
1252 case EvqSmoothIn:
1253 return "smooth in ";
1254 case EvqFlatIn:
1255 return "flat in ";
1256 case EvqNoPerspectiveIn:
1257 return "noperspective in ";
1258 case EvqCentroidIn:
1259 return "centroid in ";
1260 default:
1261 break;
1262 }
1263 return nullptr;
1264}
1265
1266void TOutputGLSLBase::declareInterfaceBlock(const TType &type)
1267{
1268 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
1269 TInfoSinkBase &out = objSink();
1270
1271 out << hashName(interfaceBlock) << "{\n";
1272 const TFieldList &fields = interfaceBlock->fields();
1273 for (const TField *field : fields)
1274 {
1275 out << getIndentPrefix(1);
1276 if (!IsShaderIoBlock(type.getQualifier()) && type.getQualifier() != EvqPatchIn &&
1277 type.getQualifier() != EvqPatchOut)
1278 {
1279 writeFieldLayoutQualifier(field);
1280 }
1281
1282 const TType &fieldType = *field->type();
1283
1284 out << getMemoryQualifiers(fieldType);
1285 if (writeVariablePrecision(fieldType.getPrecision()))
1286 out << " ";
1287 if (fieldType.isInvariant())
1288 {
1289 writeInvariantQualifier(fieldType);
1290 }
1291 if (fieldType.isPrecise())
1292 {
1293 writePreciseQualifier(fieldType);
1294 }
1295
1296 const char *qualifier = getVariableInterpolation(fieldType.getQualifier());
1297 if (qualifier != nullptr)
1298 out << qualifier;
1299
1300 out << getTypeName(fieldType) << " " << hashFieldName(field);
1301
1302 if (fieldType.isArray())
1303 out << ArrayString(fieldType);
1304 out << ";\n";
1305 }
1306 out << "}";
1307}
1308
1309void WritePragma(TInfoSinkBase &out, const ShCompileOptions &compileOptions, const TPragma &pragma)
1310{
1311 if (!compileOptions.flattenPragmaSTDGLInvariantAll)
1312 {
1313 if (pragma.stdgl.invariantAll)
1314 out << "#pragma STDGL invariant(all)\n";
1315 }
1316}
1317
1318void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1319 sh::TLayoutPrimitiveType inputPrimitive,
1320 int invocations,
1321 sh::TLayoutPrimitiveType outputPrimitive,
1322 int maxVertices)
1323{
1324 // Omit 'invocations = 1'
1325 if (inputPrimitive != EptUndefined || invocations > 1)
1326 {
1327 out << "layout (";
1328
1329 if (inputPrimitive != EptUndefined)
1330 {
1331 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1332 }
1333
1334 if (invocations > 1)
1335 {
1336 if (inputPrimitive != EptUndefined)
1337 {
1338 out << ", ";
1339 }
1340 out << "invocations = " << invocations;
1341 }
1342 out << ") in;\n";
1343 }
1344
1345 if (outputPrimitive != EptUndefined || maxVertices != -1)
1346 {
1347 out << "layout (";
1348
1349 if (outputPrimitive != EptUndefined)
1350 {
1351 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1352 }
1353
1354 if (maxVertices != -1)
1355 {
1356 if (outputPrimitive != EptUndefined)
1357 {
1358 out << ", ";
1359 }
1360 out << "max_vertices = " << maxVertices;
1361 }
1362 out << ") out;\n";
1363 }
1364}
1365
1366void WriteTessControlShaderLayoutQualifiers(TInfoSinkBase &out, int inputVertices)
1367{
1368 if (inputVertices != 0)
1369 {
1370 out << "layout (vertices = " << inputVertices << ") out;\n";
1371 }
1372}
1373
1374void WriteTessEvaluationShaderLayoutQualifiers(TInfoSinkBase &out,
1375 sh::TLayoutTessEvaluationType inputPrimitive,
1376 sh::TLayoutTessEvaluationType inputVertexSpacing,
1377 sh::TLayoutTessEvaluationType inputOrdering,
1378 sh::TLayoutTessEvaluationType inputPoint)
1379{
1380 if (inputPrimitive != EtetUndefined)
1381 {
1382 out << "layout (";
1383 out << getTessEvaluationShaderTypeString(inputPrimitive);
1384 if (inputVertexSpacing != EtetUndefined)
1385 {
1386 out << ", " << getTessEvaluationShaderTypeString(inputVertexSpacing);
1387 }
1388 if (inputOrdering != EtetUndefined)
1389 {
1390 out << ", " << getTessEvaluationShaderTypeString(inputOrdering);
1391 }
1392 if (inputPoint != EtetUndefined)
1393 {
1394 out << ", " << getTessEvaluationShaderTypeString(inputPoint);
1395 }
1396 out << ") in;\n";
1397 }
1398}
1399
1400// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1401// variables with specified layout qualifiers are copied. Additional checks are needed against the
1402// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1403// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1404// NeedsToWriteLayoutQualifier.
1405bool TOutputGLSLBase::needsToWriteLayoutQualifier(const TType &type)
1406{
1407 if (type.getBasicType() == EbtInterfaceBlock)
1408 {
1409 return true;
1410 }
1411
1412 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1413
1414 if (IsFragmentOutput(type.getQualifier()) || type.getQualifier() == EvqVertexIn ||
1415 IsVarying(type.getQualifier()))
1416 {
1417 if (layoutQualifier.location >= 0 ||
1418 (mAlwaysSpecifyFragOutLocation && IsFragmentOutput(type.getQualifier())))
1419 {
1420 return true;
1421 }
1422 }
1423
1424 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqFragmentInOut)
1425 {
1426 if (layoutQualifier.index >= 0)
1427 {
1428 return true;
1429 }
1430 if (layoutQualifier.yuv)
1431 {
1432 return true;
1433 }
1434 }
1435
1436 if (type.getQualifier() == EvqFragmentInOut && layoutQualifier.noncoherent)
1437 {
1438 return true;
1439 }
1440
1441 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1442 {
1443 return true;
1444 }
1445
1446 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1447 {
1448 return true;
1449 }
1450 return false;
1451}
1452
1453void EmitEarlyFragmentTestsGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
1454{
1455 if (compiler.isEarlyFragmentTestsSpecified())
1456 {
1457 sink << "layout (early_fragment_tests) in;\n";
1458 }
1459}
1460
1461void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
1462{
1463 if (compiler.isComputeShaderLocalSizeDeclared())
1464 {
1465 const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize();
1466 sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
1467 << ", local_size_z=" << localSize[2] << ") in;\n";
1468 }
1469}
1470
1471void EmitMultiviewGLSL(const TCompiler &compiler,
1472 const ShCompileOptions &compileOptions,
1473 const TExtension extension,
1474 const TBehavior behavior,
1475 TInfoSinkBase &sink)
1476{
1477 ASSERT(behavior != EBhUndefined)(behavior != EBhUndefined ? 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/OutputGLSLBase.cpp"
, __FUNCTION__, 1477, ::gl::LOG_FATAL).stream()) << "\t! Assert failed in "
<< __FUNCTION__ << " (" << "/root/firefox-clang/gfx/angle/checkout/src/compiler/translator/OutputGLSLBase.cpp"
<< ":" << 1477 << "): " << "behavior != EBhUndefined"
))
;
1478 if (behavior == EBhDisable)
1479 return;
1480
1481 const bool isVertexShader = (compiler.getShaderType() == GL_VERTEX_SHADER0x8B31);
1482 if (compileOptions.initializeBuiltinsForInstancedMultiview)
1483 {
1484 // Emit ARB_shader_viewport_layer_array/NV_viewport_array2 in a vertex shader if the
1485 // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
1486 // OVR_multiview(2) extension is requested.
1487 if (isVertexShader && compileOptions.selectViewInNvGLSLVertexShader)
1488 {
1489 sink << "#if defined(GL_ARB_shader_viewport_layer_array)\n"
1490 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
1491 << "#elif defined(GL_NV_viewport_array2)\n"
1492 << "#extension GL_NV_viewport_array2 : require\n"
1493 << "#endif\n";
1494 }
1495 }
1496 else
1497 {
1498 sink << "#extension GL_OVR_multiview";
1499 if (extension == TExtension::OVR_multiview2)
1500 {
1501 sink << "2";
1502 }
1503 sink << " : " << GetBehaviorString(behavior) << "\n";
1504
1505 const auto &numViews = compiler.getNumViews();
1506 if (isVertexShader && numViews != -1)
1507 {
1508 sink << "layout(num_views=" << numViews << ") in;\n";
1509 }
1510 }
1511}
1512
1513} // namespace sh