1 //
2 // Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3 // Copyright (C) 2012-2015 LunarG, Inc.
4 // Copyright (C) 2015-2020 Google, Inc.
5 // Copyright (C) 2017 ARM Limited.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
11 // are met:
12 //
13 // Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // Redistributions in binary form must reproduce the above
17 // copyright notice, this list of conditions and the following
18 // disclaimer in the documentation and/or other materials provided
19 // with the distribution.
20 //
21 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22 // contributors may be used to endorse or promote products derived
23 // from this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 // POSSIBILITY OF SUCH DAMAGE.
37 //
38
39 //
40 // Build the intermediate representation.
41 //
42
43 #include "localintermediate.h"
44 #include "RemoveTree.h"
45 #include "SymbolTable.h"
46 #include "propagateNoContraction.h"
47
48 #include <cfloat>
49 #include <utility>
50 #include <tuple>
51
52 namespace glslang {
53
54 ////////////////////////////////////////////////////////////////////////////
55 //
56 // First set of functions are to help build the intermediate representation.
57 // These functions are not member functions of the nodes.
58 // They are called from parser productions.
59 //
60 /////////////////////////////////////////////////////////////////////////////
61
62 //
63 // Add a terminal node for an identifier in an expression.
64 //
65 // Returns the added node.
66 //
67
addSymbol(long long id,const TString & name,const TType & type,const TConstUnionArray & constArray,TIntermTyped * constSubtree,const TSourceLoc & loc)68 TIntermSymbol* TIntermediate::addSymbol(long long id, const TString& name, const TType& type, const TConstUnionArray& constArray,
69 TIntermTyped* constSubtree, const TSourceLoc& loc)
70 {
71 TIntermSymbol* node = new TIntermSymbol(id, name, type);
72 node->setLoc(loc);
73 node->setConstArray(constArray);
74 node->setConstSubtree(constSubtree);
75
76 return node;
77 }
78
addSymbol(const TIntermSymbol & intermSymbol)79 TIntermSymbol* TIntermediate::addSymbol(const TIntermSymbol& intermSymbol)
80 {
81 return addSymbol(intermSymbol.getId(),
82 intermSymbol.getName(),
83 intermSymbol.getType(),
84 intermSymbol.getConstArray(),
85 intermSymbol.getConstSubtree(),
86 intermSymbol.getLoc());
87 }
88
addSymbol(const TVariable & variable)89 TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable)
90 {
91 glslang::TSourceLoc loc; // just a null location
92 loc.init();
93
94 return addSymbol(variable, loc);
95 }
96
addSymbol(const TVariable & variable,const TSourceLoc & loc)97 TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, const TSourceLoc& loc)
98 {
99 return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), variable.getConstArray(), variable.getConstSubtree(), loc);
100 }
101
addSymbol(const TType & type,const TSourceLoc & loc)102 TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc)
103 {
104 TConstUnionArray unionArray; // just a null constant
105
106 return addSymbol(0, "", type, unionArray, nullptr, loc);
107 }
108
109 //
110 // Connect two nodes with a new parent that does a binary operation on the nodes.
111 //
112 // Returns the added node.
113 //
114 // Returns nullptr if the working conversions and promotions could not be found.
115 //
addBinaryMath(TOperator op,TIntermTyped * left,TIntermTyped * right,const TSourceLoc & loc)116 TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
117 {
118 // No operations work on blocks
119 if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
120 return nullptr;
121
122 // Convert "reference +/- int" and "reference - reference" to integer math
123 if (op == EOpAdd || op == EOpSub) {
124
125 // No addressing math on struct with unsized array.
126 if ((left->isReference() && left->getType().getReferentType()->containsUnsizedArray()) ||
127 (right->isReference() && right->getType().getReferentType()->containsUnsizedArray())) {
128 return nullptr;
129 }
130
131 if (left->isReference() && isTypeInt(right->getBasicType())) {
132 const TType& referenceType = left->getType();
133 TIntermConstantUnion* size = addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
134 left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
135
136 right = createConversion(EbtInt64, right);
137 right = addBinaryMath(EOpMul, right, size, loc);
138
139 TIntermTyped *node = addBinaryMath(op, left, right, loc);
140 node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
141 return node;
142 }
143 }
144
145 if (op == EOpAdd && right->isReference() && isTypeInt(left->getBasicType())) {
146 const TType& referenceType = right->getType();
147 TIntermConstantUnion* size =
148 addConstantUnion((unsigned long long)computeBufferReferenceTypeSize(right->getType()), loc, true);
149 right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
150
151 left = createConversion(EbtInt64, left);
152 left = addBinaryMath(EOpMul, left, size, loc);
153
154 TIntermTyped *node = addBinaryMath(op, left, right, loc);
155 node = addBuiltInFunctionCall(loc, EOpConvUint64ToPtr, true, node, referenceType);
156 return node;
157 }
158
159 if (op == EOpSub && left->isReference() && right->isReference()) {
160 TIntermConstantUnion* size =
161 addConstantUnion((long long)computeBufferReferenceTypeSize(left->getType()), loc, true);
162
163 left = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, left, TType(EbtUint64));
164 right = addBuiltInFunctionCall(loc, EOpConvPtrToUint64, true, right, TType(EbtUint64));
165
166 left = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, left, TType(EbtInt64));
167 right = addBuiltInFunctionCall(loc, EOpConvUint64ToInt64, true, right, TType(EbtInt64));
168
169 left = addBinaryMath(EOpSub, left, right, loc);
170
171 TIntermTyped *node = addBinaryMath(EOpDiv, left, size, loc);
172 return node;
173 }
174
175 // No other math operators supported on references
176 if (left->isReference() || right->isReference())
177 return nullptr;
178
179 // Try converting the children's base types to compatible types.
180 auto children = addPairConversion(op, left, right);
181 left = std::get<0>(children);
182 right = std::get<1>(children);
183
184 if (left == nullptr || right == nullptr)
185 return nullptr;
186
187 // Convert the children's type shape to be compatible.
188 addBiShapeConversion(op, left, right);
189 if (left == nullptr || right == nullptr)
190 return nullptr;
191
192 //
193 // Need a new node holding things together. Make
194 // one and promote it to the right type.
195 //
196 TIntermBinary* node = addBinaryNode(op, left, right, loc);
197 if (! promote(node))
198 return nullptr;
199
200 node->updatePrecision();
201
202 //
203 // If they are both (non-specialization) constants, they must be folded.
204 // (Unless it's the sequence (comma) operator, but that's handled in addComma().)
205 //
206 TIntermConstantUnion *leftTempConstant = node->getLeft()->getAsConstantUnion();
207 TIntermConstantUnion *rightTempConstant = node->getRight()->getAsConstantUnion();
208 if (leftTempConstant && rightTempConstant) {
209 TIntermTyped* folded = leftTempConstant->fold(node->getOp(), rightTempConstant);
210 if (folded)
211 return folded;
212 }
213
214 // If can propagate spec-constantness and if the operation is an allowed
215 // specialization-constant operation, make a spec-constant.
216 if (specConstantPropagates(*node->getLeft(), *node->getRight()) && isSpecializationOperation(*node))
217 node->getWritableType().getQualifier().makeSpecConstant();
218
219 // If must propagate nonuniform, make a nonuniform.
220 if ((node->getLeft()->getQualifier().isNonUniform() || node->getRight()->getQualifier().isNonUniform()) &&
221 isNonuniformPropagating(node->getOp()))
222 node->getWritableType().getQualifier().nonUniform = true;
223
224 return node;
225 }
226
227 //
228 // Low level: add binary node (no promotions or other argument modifications)
229 //
addBinaryNode(TOperator op,TIntermTyped * left,TIntermTyped * right,const TSourceLoc & loc) const230 TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right,
231 const TSourceLoc& loc) const
232 {
233 // build the node
234 TIntermBinary* node = new TIntermBinary(op);
235 node->setLoc(loc.line != 0 ? loc : left->getLoc());
236 node->setLeft(left);
237 node->setRight(right);
238
239 return node;
240 }
241
242 //
243 // like non-type form, but sets node's type.
244 //
addBinaryNode(TOperator op,TIntermTyped * left,TIntermTyped * right,const TSourceLoc & loc,const TType & type) const245 TIntermBinary* TIntermediate::addBinaryNode(TOperator op, TIntermTyped* left, TIntermTyped* right,
246 const TSourceLoc& loc, const TType& type) const
247 {
248 TIntermBinary* node = addBinaryNode(op, left, right, loc);
249 node->setType(type);
250 return node;
251 }
252
253 //
254 // Low level: add unary node (no promotions or other argument modifications)
255 //
addUnaryNode(TOperator op,TIntermTyped * child,const TSourceLoc & loc) const256 TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc) const
257 {
258 TIntermUnary* node = new TIntermUnary(op);
259 node->setLoc(loc.line != 0 ? loc : child->getLoc());
260 node->setOperand(child);
261
262 return node;
263 }
264
265 //
266 // like non-type form, but sets node's type.
267 //
addUnaryNode(TOperator op,TIntermTyped * child,const TSourceLoc & loc,const TType & type) const268 TIntermUnary* TIntermediate::addUnaryNode(TOperator op, TIntermTyped* child, const TSourceLoc& loc, const TType& type)
269 const
270 {
271 TIntermUnary* node = addUnaryNode(op, child, loc);
272 node->setType(type);
273 return node;
274 }
275
276 //
277 // Connect two nodes through an assignment.
278 //
279 // Returns the added node.
280 //
281 // Returns nullptr if the 'right' type could not be converted to match the 'left' type,
282 // or the resulting operation cannot be properly promoted.
283 //
addAssign(TOperator op,TIntermTyped * left,TIntermTyped * right,const TSourceLoc & loc)284 TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right,
285 const TSourceLoc& loc)
286 {
287 // No block assignment
288 if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
289 return nullptr;
290
291 // Convert "reference += int" to "reference = reference + int". We need this because the
292 // "reference + int" calculation involves a cast back to the original type, which makes it
293 // not an lvalue.
294 if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) {
295 if (!(right->getType().isScalar() && right->getType().isIntegerDomain()))
296 return nullptr;
297
298 TIntermTyped* node = addBinaryMath(op == EOpAddAssign ? EOpAdd : EOpSub, left, right, loc);
299 if (!node)
300 return nullptr;
301
302 TIntermSymbol* symbol = left->getAsSymbolNode();
303 left = addSymbol(*symbol);
304
305 node = addAssign(EOpAssign, left, node, loc);
306 return node;
307 }
308
309 //
310 // Like adding binary math, except the conversion can only go
311 // from right to left.
312 //
313
314 // convert base types, nullptr return means not possible
315 right = addConversion(op, left->getType(), right);
316 if (right == nullptr)
317 return nullptr;
318
319 // convert shape
320 right = addUniShapeConversion(op, left->getType(), right);
321
322 // build the node
323 TIntermBinary* node = addBinaryNode(op, left, right, loc);
324
325 if (! promote(node))
326 return nullptr;
327
328 node->updatePrecision();
329
330 return node;
331 }
332
333 //
334 // Connect two nodes through an index operator, where the left node is the base
335 // of an array or struct, and the right node is a direct or indirect offset.
336 //
337 // Returns the added node.
338 // The caller should set the type of the returned node.
339 //
addIndex(TOperator op,TIntermTyped * base,TIntermTyped * index,const TSourceLoc & loc)340 TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index,
341 const TSourceLoc& loc)
342 {
343 // caller should set the type
344 return addBinaryNode(op, base, index, loc);
345 }
346
347 //
348 // Add one node as the parent of another that it operates on.
349 //
350 // Returns the added node.
351 //
addUnaryMath(TOperator op,TIntermTyped * child,const TSourceLoc & loc)352 TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child,
353 const TSourceLoc& loc)
354 {
355 if (child == nullptr)
356 return nullptr;
357
358 if (child->getType().getBasicType() == EbtBlock)
359 return nullptr;
360
361 switch (op) {
362 case EOpLogicalNot:
363 if (getSource() == EShSourceHlsl) {
364 break; // HLSL can promote logical not
365 }
366
367 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
368 return nullptr;
369 }
370 break;
371
372 case EOpPostIncrement:
373 case EOpPreIncrement:
374 case EOpPostDecrement:
375 case EOpPreDecrement:
376 case EOpNegative:
377 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
378 return nullptr;
379 default: break; // some compilers want this
380 }
381
382 //
383 // Do we need to promote the operand?
384 //
385 TBasicType newType = EbtVoid;
386 switch (op) {
387 case EOpConstructBool: newType = EbtBool; break;
388 case EOpConstructFloat: newType = EbtFloat; break;
389 case EOpConstructInt: newType = EbtInt; break;
390 case EOpConstructUint: newType = EbtUint; break;
391 #ifndef GLSLANG_WEB
392 case EOpConstructInt8: newType = EbtInt8; break;
393 case EOpConstructUint8: newType = EbtUint8; break;
394 case EOpConstructInt16: newType = EbtInt16; break;
395 case EOpConstructUint16: newType = EbtUint16; break;
396 case EOpConstructInt64: newType = EbtInt64; break;
397 case EOpConstructUint64: newType = EbtUint64; break;
398 case EOpConstructDouble: newType = EbtDouble; break;
399 case EOpConstructFloat16: newType = EbtFloat16; break;
400 #endif
401 default: break; // some compilers want this
402 }
403
404 if (newType != EbtVoid) {
405 child = addConversion(op, TType(newType, EvqTemporary, child->getVectorSize(),
406 child->getMatrixCols(),
407 child->getMatrixRows(),
408 child->isVector()),
409 child);
410 if (child == nullptr)
411 return nullptr;
412 }
413
414 //
415 // For constructors, we are now done, it was all in the conversion.
416 // TODO: but, did this bypass constant folding?
417 //
418 switch (op) {
419 case EOpConstructInt8:
420 case EOpConstructUint8:
421 case EOpConstructInt16:
422 case EOpConstructUint16:
423 case EOpConstructInt:
424 case EOpConstructUint:
425 case EOpConstructInt64:
426 case EOpConstructUint64:
427 case EOpConstructBool:
428 case EOpConstructFloat:
429 case EOpConstructDouble:
430 case EOpConstructFloat16: {
431 TIntermUnary* unary_node = child->getAsUnaryNode();
432 if (unary_node != nullptr)
433 unary_node->updatePrecision();
434 return child;
435 }
436 default: break; // some compilers want this
437 }
438
439 //
440 // Make a new node for the operator.
441 //
442 TIntermUnary* node = addUnaryNode(op, child, loc);
443
444 if (! promote(node))
445 return nullptr;
446
447 node->updatePrecision();
448
449 // If it's a (non-specialization) constant, it must be folded.
450 if (node->getOperand()->getAsConstantUnion())
451 return node->getOperand()->getAsConstantUnion()->fold(op, node->getType());
452
453 // If it's a specialization constant, the result is too,
454 // if the operation is allowed for specialization constants.
455 if (node->getOperand()->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*node))
456 node->getWritableType().getQualifier().makeSpecConstant();
457
458 // If must propagate nonuniform, make a nonuniform.
459 if (node->getOperand()->getQualifier().isNonUniform() && isNonuniformPropagating(node->getOp()))
460 node->getWritableType().getQualifier().nonUniform = true;
461
462 return node;
463 }
464
addBuiltInFunctionCall(const TSourceLoc & loc,TOperator op,bool unary,TIntermNode * childNode,const TType & returnType)465 TIntermTyped* TIntermediate::addBuiltInFunctionCall(const TSourceLoc& loc, TOperator op, bool unary,
466 TIntermNode* childNode, const TType& returnType)
467 {
468 if (unary) {
469 //
470 // Treat it like a unary operator.
471 // addUnaryMath() should get the type correct on its own;
472 // including constness (which would differ from the prototype).
473 //
474 TIntermTyped* child = childNode->getAsTyped();
475 if (child == nullptr)
476 return nullptr;
477
478 if (child->getAsConstantUnion()) {
479 TIntermTyped* folded = child->getAsConstantUnion()->fold(op, returnType);
480 if (folded)
481 return folded;
482 }
483
484 return addUnaryNode(op, child, child->getLoc(), returnType);
485 } else {
486 // setAggregateOperater() calls fold() for constant folding
487 TIntermTyped* node = setAggregateOperator(childNode, op, returnType, loc);
488
489 return node;
490 }
491 }
492
493 //
494 // This is the safe way to change the operator on an aggregate, as it
495 // does lots of error checking and fixing. Especially for establishing
496 // a function call's operation on its set of parameters. Sequences
497 // of instructions are also aggregates, but they just directly set
498 // their operator to EOpSequence.
499 //
500 // Returns an aggregate node, which could be the one passed in if
501 // it was already an aggregate.
502 //
setAggregateOperator(TIntermNode * node,TOperator op,const TType & type,const TSourceLoc & loc)503 TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TType& type,
504 const TSourceLoc& loc)
505 {
506 TIntermAggregate* aggNode;
507
508 //
509 // Make sure we have an aggregate. If not turn it into one.
510 //
511 if (node != nullptr) {
512 aggNode = node->getAsAggregate();
513 if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
514 //
515 // Make an aggregate containing this node.
516 //
517 aggNode = new TIntermAggregate();
518 aggNode->getSequence().push_back(node);
519 }
520 } else
521 aggNode = new TIntermAggregate();
522
523 //
524 // Set the operator.
525 //
526 aggNode->setOperator(op);
527 if (loc.line != 0 || node != nullptr)
528 aggNode->setLoc(loc.line != 0 ? loc : node->getLoc());
529
530 aggNode->setType(type);
531
532 return fold(aggNode);
533 }
534
isConversionAllowed(TOperator op,TIntermTyped * node) const535 bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const
536 {
537 //
538 // Does the base type even allow the operation?
539 //
540 switch (node->getBasicType()) {
541 case EbtVoid:
542 return false;
543 case EbtAtomicUint:
544 case EbtSampler:
545 case EbtAccStruct:
546 // opaque types can be passed to functions
547 if (op == EOpFunction)
548 break;
549
550 // HLSL can assign samplers directly (no constructor)
551 if (getSource() == EShSourceHlsl && node->getBasicType() == EbtSampler)
552 break;
553
554 // samplers can get assigned via a sampler constructor
555 // (well, not yet, but code in the rest of this function is ready for it)
556 if (node->getBasicType() == EbtSampler && op == EOpAssign &&
557 node->getAsOperator() != nullptr && node->getAsOperator()->getOp() == EOpConstructTextureSampler)
558 break;
559
560 // otherwise, opaque types can't even be operated on, let alone converted
561 return false;
562 default:
563 break;
564 }
565
566 return true;
567 }
568
buildConvertOp(TBasicType dst,TBasicType src,TOperator & newOp) const569 bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& newOp) const
570 {
571 switch (dst) {
572 #ifndef GLSLANG_WEB
573 case EbtDouble:
574 switch (src) {
575 case EbtUint: newOp = EOpConvUintToDouble; break;
576 case EbtBool: newOp = EOpConvBoolToDouble; break;
577 case EbtFloat: newOp = EOpConvFloatToDouble; break;
578 case EbtInt: newOp = EOpConvIntToDouble; break;
579 case EbtInt8: newOp = EOpConvInt8ToDouble; break;
580 case EbtUint8: newOp = EOpConvUint8ToDouble; break;
581 case EbtInt16: newOp = EOpConvInt16ToDouble; break;
582 case EbtUint16: newOp = EOpConvUint16ToDouble; break;
583 case EbtFloat16: newOp = EOpConvFloat16ToDouble; break;
584 case EbtInt64: newOp = EOpConvInt64ToDouble; break;
585 case EbtUint64: newOp = EOpConvUint64ToDouble; break;
586 default:
587 return false;
588 }
589 break;
590 #endif
591 case EbtFloat:
592 switch (src) {
593 case EbtInt: newOp = EOpConvIntToFloat; break;
594 case EbtUint: newOp = EOpConvUintToFloat; break;
595 case EbtBool: newOp = EOpConvBoolToFloat; break;
596 #ifndef GLSLANG_WEB
597 case EbtDouble: newOp = EOpConvDoubleToFloat; break;
598 case EbtInt8: newOp = EOpConvInt8ToFloat; break;
599 case EbtUint8: newOp = EOpConvUint8ToFloat; break;
600 case EbtInt16: newOp = EOpConvInt16ToFloat; break;
601 case EbtUint16: newOp = EOpConvUint16ToFloat; break;
602 case EbtFloat16: newOp = EOpConvFloat16ToFloat; break;
603 case EbtInt64: newOp = EOpConvInt64ToFloat; break;
604 case EbtUint64: newOp = EOpConvUint64ToFloat; break;
605 #endif
606 default:
607 return false;
608 }
609 break;
610 #ifndef GLSLANG_WEB
611 case EbtFloat16:
612 switch (src) {
613 case EbtInt8: newOp = EOpConvInt8ToFloat16; break;
614 case EbtUint8: newOp = EOpConvUint8ToFloat16; break;
615 case EbtInt16: newOp = EOpConvInt16ToFloat16; break;
616 case EbtUint16: newOp = EOpConvUint16ToFloat16; break;
617 case EbtInt: newOp = EOpConvIntToFloat16; break;
618 case EbtUint: newOp = EOpConvUintToFloat16; break;
619 case EbtBool: newOp = EOpConvBoolToFloat16; break;
620 case EbtFloat: newOp = EOpConvFloatToFloat16; break;
621 case EbtDouble: newOp = EOpConvDoubleToFloat16; break;
622 case EbtInt64: newOp = EOpConvInt64ToFloat16; break;
623 case EbtUint64: newOp = EOpConvUint64ToFloat16; break;
624 default:
625 return false;
626 }
627 break;
628 #endif
629 case EbtBool:
630 switch (src) {
631 case EbtInt: newOp = EOpConvIntToBool; break;
632 case EbtUint: newOp = EOpConvUintToBool; break;
633 case EbtFloat: newOp = EOpConvFloatToBool; break;
634 #ifndef GLSLANG_WEB
635 case EbtDouble: newOp = EOpConvDoubleToBool; break;
636 case EbtInt8: newOp = EOpConvInt8ToBool; break;
637 case EbtUint8: newOp = EOpConvUint8ToBool; break;
638 case EbtInt16: newOp = EOpConvInt16ToBool; break;
639 case EbtUint16: newOp = EOpConvUint16ToBool; break;
640 case EbtFloat16: newOp = EOpConvFloat16ToBool; break;
641 case EbtInt64: newOp = EOpConvInt64ToBool; break;
642 case EbtUint64: newOp = EOpConvUint64ToBool; break;
643 #endif
644 default:
645 return false;
646 }
647 break;
648 #ifndef GLSLANG_WEB
649 case EbtInt8:
650 switch (src) {
651 case EbtUint8: newOp = EOpConvUint8ToInt8; break;
652 case EbtInt16: newOp = EOpConvInt16ToInt8; break;
653 case EbtUint16: newOp = EOpConvUint16ToInt8; break;
654 case EbtInt: newOp = EOpConvIntToInt8; break;
655 case EbtUint: newOp = EOpConvUintToInt8; break;
656 case EbtInt64: newOp = EOpConvInt64ToInt8; break;
657 case EbtUint64: newOp = EOpConvUint64ToInt8; break;
658 case EbtBool: newOp = EOpConvBoolToInt8; break;
659 case EbtFloat: newOp = EOpConvFloatToInt8; break;
660 case EbtDouble: newOp = EOpConvDoubleToInt8; break;
661 case EbtFloat16: newOp = EOpConvFloat16ToInt8; break;
662 default:
663 return false;
664 }
665 break;
666 case EbtUint8:
667 switch (src) {
668 case EbtInt8: newOp = EOpConvInt8ToUint8; break;
669 case EbtInt16: newOp = EOpConvInt16ToUint8; break;
670 case EbtUint16: newOp = EOpConvUint16ToUint8; break;
671 case EbtInt: newOp = EOpConvIntToUint8; break;
672 case EbtUint: newOp = EOpConvUintToUint8; break;
673 case EbtInt64: newOp = EOpConvInt64ToUint8; break;
674 case EbtUint64: newOp = EOpConvUint64ToUint8; break;
675 case EbtBool: newOp = EOpConvBoolToUint8; break;
676 case EbtFloat: newOp = EOpConvFloatToUint8; break;
677 case EbtDouble: newOp = EOpConvDoubleToUint8; break;
678 case EbtFloat16: newOp = EOpConvFloat16ToUint8; break;
679 default:
680 return false;
681 }
682 break;
683
684 case EbtInt16:
685 switch (src) {
686 case EbtUint8: newOp = EOpConvUint8ToInt16; break;
687 case EbtInt8: newOp = EOpConvInt8ToInt16; break;
688 case EbtUint16: newOp = EOpConvUint16ToInt16; break;
689 case EbtInt: newOp = EOpConvIntToInt16; break;
690 case EbtUint: newOp = EOpConvUintToInt16; break;
691 case EbtInt64: newOp = EOpConvInt64ToInt16; break;
692 case EbtUint64: newOp = EOpConvUint64ToInt16; break;
693 case EbtBool: newOp = EOpConvBoolToInt16; break;
694 case EbtFloat: newOp = EOpConvFloatToInt16; break;
695 case EbtDouble: newOp = EOpConvDoubleToInt16; break;
696 case EbtFloat16: newOp = EOpConvFloat16ToInt16; break;
697 default:
698 return false;
699 }
700 break;
701 case EbtUint16:
702 switch (src) {
703 case EbtInt8: newOp = EOpConvInt8ToUint16; break;
704 case EbtUint8: newOp = EOpConvUint8ToUint16; break;
705 case EbtInt16: newOp = EOpConvInt16ToUint16; break;
706 case EbtInt: newOp = EOpConvIntToUint16; break;
707 case EbtUint: newOp = EOpConvUintToUint16; break;
708 case EbtInt64: newOp = EOpConvInt64ToUint16; break;
709 case EbtUint64: newOp = EOpConvUint64ToUint16; break;
710 case EbtBool: newOp = EOpConvBoolToUint16; break;
711 case EbtFloat: newOp = EOpConvFloatToUint16; break;
712 case EbtDouble: newOp = EOpConvDoubleToUint16; break;
713 case EbtFloat16: newOp = EOpConvFloat16ToUint16; break;
714 default:
715 return false;
716 }
717 break;
718 #endif
719
720 case EbtInt:
721 switch (src) {
722 case EbtUint: newOp = EOpConvUintToInt; break;
723 case EbtBool: newOp = EOpConvBoolToInt; break;
724 case EbtFloat: newOp = EOpConvFloatToInt; break;
725 #ifndef GLSLANG_WEB
726 case EbtInt8: newOp = EOpConvInt8ToInt; break;
727 case EbtUint8: newOp = EOpConvUint8ToInt; break;
728 case EbtInt16: newOp = EOpConvInt16ToInt; break;
729 case EbtUint16: newOp = EOpConvUint16ToInt; break;
730 case EbtDouble: newOp = EOpConvDoubleToInt; break;
731 case EbtFloat16: newOp = EOpConvFloat16ToInt; break;
732 case EbtInt64: newOp = EOpConvInt64ToInt; break;
733 case EbtUint64: newOp = EOpConvUint64ToInt; break;
734 #endif
735 default:
736 return false;
737 }
738 break;
739 case EbtUint:
740 switch (src) {
741 case EbtInt: newOp = EOpConvIntToUint; break;
742 case EbtBool: newOp = EOpConvBoolToUint; break;
743 case EbtFloat: newOp = EOpConvFloatToUint; break;
744 #ifndef GLSLANG_WEB
745 case EbtInt8: newOp = EOpConvInt8ToUint; break;
746 case EbtUint8: newOp = EOpConvUint8ToUint; break;
747 case EbtInt16: newOp = EOpConvInt16ToUint; break;
748 case EbtUint16: newOp = EOpConvUint16ToUint; break;
749 case EbtDouble: newOp = EOpConvDoubleToUint; break;
750 case EbtFloat16: newOp = EOpConvFloat16ToUint; break;
751 case EbtInt64: newOp = EOpConvInt64ToUint; break;
752 case EbtUint64: newOp = EOpConvUint64ToUint; break;
753 #endif
754 default:
755 return false;
756 }
757 break;
758 #ifndef GLSLANG_WEB
759 case EbtInt64:
760 switch (src) {
761 case EbtInt8: newOp = EOpConvInt8ToInt64; break;
762 case EbtUint8: newOp = EOpConvUint8ToInt64; break;
763 case EbtInt16: newOp = EOpConvInt16ToInt64; break;
764 case EbtUint16: newOp = EOpConvUint16ToInt64; break;
765 case EbtInt: newOp = EOpConvIntToInt64; break;
766 case EbtUint: newOp = EOpConvUintToInt64; break;
767 case EbtBool: newOp = EOpConvBoolToInt64; break;
768 case EbtFloat: newOp = EOpConvFloatToInt64; break;
769 case EbtDouble: newOp = EOpConvDoubleToInt64; break;
770 case EbtFloat16: newOp = EOpConvFloat16ToInt64; break;
771 case EbtUint64: newOp = EOpConvUint64ToInt64; break;
772 default:
773 return false;
774 }
775 break;
776 case EbtUint64:
777 switch (src) {
778 case EbtInt8: newOp = EOpConvInt8ToUint64; break;
779 case EbtUint8: newOp = EOpConvUint8ToUint64; break;
780 case EbtInt16: newOp = EOpConvInt16ToUint64; break;
781 case EbtUint16: newOp = EOpConvUint16ToUint64; break;
782 case EbtInt: newOp = EOpConvIntToUint64; break;
783 case EbtUint: newOp = EOpConvUintToUint64; break;
784 case EbtBool: newOp = EOpConvBoolToUint64; break;
785 case EbtFloat: newOp = EOpConvFloatToUint64; break;
786 case EbtDouble: newOp = EOpConvDoubleToUint64; break;
787 case EbtFloat16: newOp = EOpConvFloat16ToUint64; break;
788 case EbtInt64: newOp = EOpConvInt64ToUint64; break;
789 default:
790 return false;
791 }
792 break;
793 #endif
794 default:
795 return false;
796 }
797 return true;
798 }
799
800 // This is 'mechanism' here, it does any conversion told.
801 // It is about basic type, not about shape.
802 // The policy comes from the shader or the calling code.
createConversion(TBasicType convertTo,TIntermTyped * node) const803 TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped* node) const
804 {
805 //
806 // Add a new newNode for the conversion.
807 //
808
809 #ifndef GLSLANG_WEB
810 bool convertToIntTypes = (convertTo == EbtInt8 || convertTo == EbtUint8 ||
811 convertTo == EbtInt16 || convertTo == EbtUint16 ||
812 convertTo == EbtInt || convertTo == EbtUint ||
813 convertTo == EbtInt64 || convertTo == EbtUint64);
814
815 bool convertFromIntTypes = (node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8 ||
816 node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16 ||
817 node->getBasicType() == EbtInt || node->getBasicType() == EbtUint ||
818 node->getBasicType() == EbtInt64 || node->getBasicType() == EbtUint64);
819
820 bool convertToFloatTypes = (convertTo == EbtFloat16 || convertTo == EbtFloat || convertTo == EbtDouble);
821
822 bool convertFromFloatTypes = (node->getBasicType() == EbtFloat16 ||
823 node->getBasicType() == EbtFloat ||
824 node->getBasicType() == EbtDouble);
825
826 if (((convertTo == EbtInt8 || convertTo == EbtUint8) && ! convertFromIntTypes) ||
827 ((node->getBasicType() == EbtInt8 || node->getBasicType() == EbtUint8) && ! convertToIntTypes)) {
828 if (! getArithemeticInt8Enabled()) {
829 return nullptr;
830 }
831 }
832
833 if (((convertTo == EbtInt16 || convertTo == EbtUint16) && ! convertFromIntTypes) ||
834 ((node->getBasicType() == EbtInt16 || node->getBasicType() == EbtUint16) && ! convertToIntTypes)) {
835 if (! getArithemeticInt16Enabled()) {
836 return nullptr;
837 }
838 }
839
840 if ((convertTo == EbtFloat16 && ! convertFromFloatTypes) ||
841 (node->getBasicType() == EbtFloat16 && ! convertToFloatTypes)) {
842 if (! getArithemeticFloat16Enabled()) {
843 return nullptr;
844 }
845 }
846 #endif
847
848 TIntermUnary* newNode = nullptr;
849 TOperator newOp = EOpNull;
850 if (!buildConvertOp(convertTo, node->getBasicType(), newOp)) {
851 return nullptr;
852 }
853
854 TType newType(convertTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
855 newNode = addUnaryNode(newOp, node, node->getLoc(), newType);
856
857 if (node->getAsConstantUnion()) {
858 #ifndef GLSLANG_WEB
859 // 8/16-bit storage extensions don't support 8/16-bit constants, so don't fold conversions
860 // to those types
861 if ((getArithemeticInt8Enabled() || !(convertTo == EbtInt8 || convertTo == EbtUint8)) &&
862 (getArithemeticInt16Enabled() || !(convertTo == EbtInt16 || convertTo == EbtUint16)) &&
863 (getArithemeticFloat16Enabled() || !(convertTo == EbtFloat16)))
864 #endif
865 {
866 TIntermTyped* folded = node->getAsConstantUnion()->fold(newOp, newType);
867 if (folded)
868 return folded;
869 }
870 }
871
872 // Propagate specialization-constant-ness, if allowed
873 if (node->getType().getQualifier().isSpecConstant() && isSpecializationOperation(*newNode))
874 newNode->getWritableType().getQualifier().makeSpecConstant();
875
876 return newNode;
877 }
878
addConversion(TBasicType convertTo,TIntermTyped * node) const879 TIntermTyped* TIntermediate::addConversion(TBasicType convertTo, TIntermTyped* node) const
880 {
881 return createConversion(convertTo, node);
882 }
883
884 // For converting a pair of operands to a binary operation to compatible
885 // types with each other, relative to the operation in 'op'.
886 // This does not cover assignment operations, which is asymmetric in that the
887 // left type is not changeable.
888 // See addConversion(op, type, node) for assignments and unary operation
889 // conversions.
890 //
891 // Generally, this is focused on basic type conversion, not shape conversion.
892 // See addShapeConversion() for shape conversions.
893 //
894 // Returns the converted pair of nodes.
895 // Returns <nullptr, nullptr> when there is no conversion.
896 std::tuple<TIntermTyped*, TIntermTyped*>
addPairConversion(TOperator op,TIntermTyped * node0,TIntermTyped * node1)897 TIntermediate::addPairConversion(TOperator op, TIntermTyped* node0, TIntermTyped* node1)
898 {
899 if (!isConversionAllowed(op, node0) || !isConversionAllowed(op, node1))
900 return std::make_tuple(nullptr, nullptr);
901
902 if (node0->getType() != node1->getType()) {
903 // If differing structure, then no conversions.
904 if (node0->isStruct() || node1->isStruct())
905 return std::make_tuple(nullptr, nullptr);
906
907 // If differing arrays, then no conversions.
908 if (node0->getType().isArray() || node1->getType().isArray())
909 return std::make_tuple(nullptr, nullptr);
910
911 // No implicit conversions for operations involving cooperative matrices
912 if (node0->getType().isCoopMat() || node1->getType().isCoopMat())
913 return std::make_tuple(node0, node1);
914 }
915
916 auto promoteTo = std::make_tuple(EbtNumTypes, EbtNumTypes);
917
918 switch (op) {
919 //
920 // List all the binary ops that can implicitly convert one operand to the other's type;
921 // This implements the 'policy' for implicit type conversion.
922 //
923 case EOpLessThan:
924 case EOpGreaterThan:
925 case EOpLessThanEqual:
926 case EOpGreaterThanEqual:
927 case EOpEqual:
928 case EOpNotEqual:
929
930 case EOpAdd:
931 case EOpSub:
932 case EOpMul:
933 case EOpDiv:
934 case EOpMod:
935
936 case EOpVectorTimesScalar:
937 case EOpVectorTimesMatrix:
938 case EOpMatrixTimesVector:
939 case EOpMatrixTimesScalar:
940
941 case EOpAnd:
942 case EOpInclusiveOr:
943 case EOpExclusiveOr:
944
945 case EOpSequence: // used by ?:
946
947 if (node0->getBasicType() == node1->getBasicType())
948 return std::make_tuple(node0, node1);
949
950 promoteTo = getConversionDestinationType(node0->getBasicType(), node1->getBasicType(), op);
951 if (std::get<0>(promoteTo) == EbtNumTypes || std::get<1>(promoteTo) == EbtNumTypes)
952 return std::make_tuple(nullptr, nullptr);
953
954 break;
955
956 case EOpLogicalAnd:
957 case EOpLogicalOr:
958 case EOpLogicalXor:
959 if (getSource() == EShSourceHlsl)
960 promoteTo = std::make_tuple(EbtBool, EbtBool);
961 else
962 return std::make_tuple(node0, node1);
963 break;
964
965 // There are no conversions needed for GLSL; the shift amount just needs to be an
966 // integer type, as does the base.
967 // HLSL can promote bools to ints to make this work.
968 case EOpLeftShift:
969 case EOpRightShift:
970 if (getSource() == EShSourceHlsl) {
971 TBasicType node0BasicType = node0->getBasicType();
972 if (node0BasicType == EbtBool)
973 node0BasicType = EbtInt;
974 if (node1->getBasicType() == EbtBool)
975 promoteTo = std::make_tuple(node0BasicType, EbtInt);
976 else
977 promoteTo = std::make_tuple(node0BasicType, node1->getBasicType());
978 } else {
979 if (isTypeInt(node0->getBasicType()) && isTypeInt(node1->getBasicType()))
980 return std::make_tuple(node0, node1);
981 else
982 return std::make_tuple(nullptr, nullptr);
983 }
984 break;
985
986 default:
987 if (node0->getType() == node1->getType())
988 return std::make_tuple(node0, node1);
989
990 return std::make_tuple(nullptr, nullptr);
991 }
992
993 TIntermTyped* newNode0;
994 TIntermTyped* newNode1;
995
996 if (std::get<0>(promoteTo) != node0->getType().getBasicType()) {
997 if (node0->getAsConstantUnion())
998 newNode0 = promoteConstantUnion(std::get<0>(promoteTo), node0->getAsConstantUnion());
999 else
1000 newNode0 = createConversion(std::get<0>(promoteTo), node0);
1001 } else
1002 newNode0 = node0;
1003
1004 if (std::get<1>(promoteTo) != node1->getType().getBasicType()) {
1005 if (node1->getAsConstantUnion())
1006 newNode1 = promoteConstantUnion(std::get<1>(promoteTo), node1->getAsConstantUnion());
1007 else
1008 newNode1 = createConversion(std::get<1>(promoteTo), node1);
1009 } else
1010 newNode1 = node1;
1011
1012 return std::make_tuple(newNode0, newNode1);
1013 }
1014
1015 //
1016 // Convert the node's type to the given type, as allowed by the operation involved: 'op'.
1017 // For implicit conversions, 'op' is not the requested conversion, it is the explicit
1018 // operation requiring the implicit conversion.
1019 //
1020 // Binary operation conversions should be handled by addConversion(op, node, node), not here.
1021 //
1022 // Returns a node representing the conversion, which could be the same
1023 // node passed in if no conversion was needed.
1024 //
1025 // Generally, this is focused on basic type conversion, not shape conversion.
1026 // See addShapeConversion() for shape conversions.
1027 //
1028 // Return nullptr if a conversion can't be done.
1029 //
addConversion(TOperator op,const TType & type,TIntermTyped * node)1030 TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
1031 {
1032 if (!isConversionAllowed(op, node))
1033 return nullptr;
1034
1035 // Otherwise, if types are identical, no problem
1036 if (type == node->getType())
1037 return node;
1038
1039 // If one's a structure, then no conversions.
1040 if (type.isStruct() || node->isStruct())
1041 return nullptr;
1042
1043 // If one's an array, then no conversions.
1044 if (type.isArray() || node->getType().isArray())
1045 return nullptr;
1046
1047 // Note: callers are responsible for other aspects of shape,
1048 // like vector and matrix sizes.
1049
1050 switch (op) {
1051 //
1052 // Explicit conversions (unary operations)
1053 //
1054 case EOpConstructBool:
1055 case EOpConstructFloat:
1056 case EOpConstructInt:
1057 case EOpConstructUint:
1058 #ifndef GLSLANG_WEB
1059 case EOpConstructDouble:
1060 case EOpConstructFloat16:
1061 case EOpConstructInt8:
1062 case EOpConstructUint8:
1063 case EOpConstructInt16:
1064 case EOpConstructUint16:
1065 case EOpConstructInt64:
1066 case EOpConstructUint64:
1067 break;
1068
1069 #endif
1070
1071 //
1072 // Implicit conversions
1073 //
1074 case EOpLogicalNot:
1075
1076 case EOpFunctionCall:
1077
1078 case EOpReturn:
1079 case EOpAssign:
1080 case EOpAddAssign:
1081 case EOpSubAssign:
1082 case EOpMulAssign:
1083 case EOpVectorTimesScalarAssign:
1084 case EOpMatrixTimesScalarAssign:
1085 case EOpDivAssign:
1086 case EOpModAssign:
1087 case EOpAndAssign:
1088 case EOpInclusiveOrAssign:
1089 case EOpExclusiveOrAssign:
1090
1091 case EOpAtan:
1092 case EOpClamp:
1093 case EOpCross:
1094 case EOpDistance:
1095 case EOpDot:
1096 case EOpDst:
1097 case EOpFaceForward:
1098 case EOpFma:
1099 case EOpFrexp:
1100 case EOpLdexp:
1101 case EOpMix:
1102 case EOpLit:
1103 case EOpMax:
1104 case EOpMin:
1105 case EOpMod:
1106 case EOpModf:
1107 case EOpPow:
1108 case EOpReflect:
1109 case EOpRefract:
1110 case EOpSmoothStep:
1111 case EOpStep:
1112
1113 case EOpSequence:
1114 case EOpConstructStruct:
1115 case EOpConstructCooperativeMatrix:
1116
1117 if (type.isReference() || node->getType().isReference()) {
1118 // types must match to assign a reference
1119 if (type == node->getType())
1120 return node;
1121 else
1122 return nullptr;
1123 }
1124
1125 if (type.getBasicType() == node->getType().getBasicType())
1126 return node;
1127
1128 if (! canImplicitlyPromote(node->getBasicType(), type.getBasicType(), op))
1129 return nullptr;
1130 break;
1131
1132 // For GLSL, there are no conversions needed; the shift amount just needs to be an
1133 // integer type, as do the base/result.
1134 // HLSL can convert the shift from a bool to an int.
1135 case EOpLeftShiftAssign:
1136 case EOpRightShiftAssign:
1137 {
1138 if (!(getSource() == EShSourceHlsl && node->getType().getBasicType() == EbtBool)) {
1139 if (isTypeInt(type.getBasicType()) && isTypeInt(node->getBasicType()))
1140 return node;
1141 else
1142 return nullptr;
1143 }
1144 break;
1145 }
1146
1147 default:
1148 // default is to require a match; all exceptions should have case statements above
1149
1150 if (type.getBasicType() == node->getType().getBasicType())
1151 return node;
1152 else
1153 return nullptr;
1154 }
1155
1156 bool canPromoteConstant = true;
1157 #ifndef GLSLANG_WEB
1158 // GL_EXT_shader_16bit_storage can't do OpConstantComposite with
1159 // 16-bit types, so disable promotion for those types.
1160 // Many issues with this, from JohnK:
1161 // - this isn't really right to discuss SPIR-V here
1162 // - this could easily be entirely about scalars, so is overstepping
1163 // - we should be looking at what the shader asked for, and saying whether or
1164 // not it can be done, in the parser, by calling requireExtensions(), not
1165 // changing language sementics on the fly by asking what extensions are in use
1166 // - at the time of this writing (14-Aug-2020), no test results are changed by this.
1167 switch (op) {
1168 case EOpConstructFloat16:
1169 canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1170 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16);
1171 break;
1172 case EOpConstructInt8:
1173 case EOpConstructUint8:
1174 canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1175 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8);
1176 break;
1177 case EOpConstructInt16:
1178 case EOpConstructUint16:
1179 canPromoteConstant = numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1180 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16);
1181 break;
1182 default:
1183 break;
1184 }
1185 #endif
1186
1187 if (canPromoteConstant && node->getAsConstantUnion())
1188 return promoteConstantUnion(type.getBasicType(), node->getAsConstantUnion());
1189
1190 //
1191 // Add a new newNode for the conversion.
1192 //
1193 TIntermTyped* newNode = createConversion(type.getBasicType(), node);
1194
1195 return newNode;
1196 }
1197
1198 // Convert the node's shape of type for the given type, as allowed by the
1199 // operation involved: 'op'. This is for situations where there is only one
1200 // direction to consider doing the shape conversion.
1201 //
1202 // This implements policy, it call addShapeConversion() for the mechanism.
1203 //
1204 // Generally, the AST represents allowed GLSL shapes, so this isn't needed
1205 // for GLSL. Bad shapes are caught in conversion or promotion.
1206 //
1207 // Return 'node' if no conversion was done. Promotion handles final shape
1208 // checking.
1209 //
addUniShapeConversion(TOperator op,const TType & type,TIntermTyped * node)1210 TIntermTyped* TIntermediate::addUniShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
1211 {
1212 // some source languages don't do this
1213 switch (getSource()) {
1214 case EShSourceHlsl:
1215 break;
1216 case EShSourceGlsl:
1217 default:
1218 return node;
1219 }
1220
1221 // some operations don't do this
1222 switch (op) {
1223 case EOpFunctionCall:
1224 case EOpReturn:
1225 break;
1226
1227 case EOpMulAssign:
1228 // want to support vector *= scalar native ops in AST and lower, not smear, similarly for
1229 // matrix *= scalar, etc.
1230
1231 case EOpAddAssign:
1232 case EOpSubAssign:
1233 case EOpDivAssign:
1234 case EOpAndAssign:
1235 case EOpInclusiveOrAssign:
1236 case EOpExclusiveOrAssign:
1237 case EOpRightShiftAssign:
1238 case EOpLeftShiftAssign:
1239 if (node->getVectorSize() == 1)
1240 return node;
1241 break;
1242
1243 case EOpAssign:
1244 break;
1245
1246 case EOpMix:
1247 break;
1248
1249 default:
1250 return node;
1251 }
1252
1253 return addShapeConversion(type, node);
1254 }
1255
1256 // Convert the nodes' shapes to be compatible for the operation 'op'.
1257 //
1258 // This implements policy, it call addShapeConversion() for the mechanism.
1259 //
1260 // Generally, the AST represents allowed GLSL shapes, so this isn't needed
1261 // for GLSL. Bad shapes are caught in conversion or promotion.
1262 //
addBiShapeConversion(TOperator op,TIntermTyped * & lhsNode,TIntermTyped * & rhsNode)1263 void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, TIntermTyped*& rhsNode)
1264 {
1265 // some source languages don't do this
1266 switch (getSource()) {
1267 case EShSourceHlsl:
1268 break;
1269 case EShSourceGlsl:
1270 default:
1271 return;
1272 }
1273
1274 // some operations don't do this
1275 // 'break' will mean attempt bidirectional conversion
1276 switch (op) {
1277 case EOpMulAssign:
1278 case EOpAssign:
1279 case EOpAddAssign:
1280 case EOpSubAssign:
1281 case EOpDivAssign:
1282 case EOpAndAssign:
1283 case EOpInclusiveOrAssign:
1284 case EOpExclusiveOrAssign:
1285 case EOpRightShiftAssign:
1286 case EOpLeftShiftAssign:
1287 // switch to unidirectional conversion (the lhs can't change)
1288 rhsNode = addUniShapeConversion(op, lhsNode->getType(), rhsNode);
1289 return;
1290
1291 case EOpMul:
1292 // matrix multiply does not change shapes
1293 if (lhsNode->isMatrix() && rhsNode->isMatrix())
1294 return;
1295 case EOpAdd:
1296 case EOpSub:
1297 case EOpDiv:
1298 // want to support vector * scalar native ops in AST and lower, not smear, similarly for
1299 // matrix * vector, etc.
1300 if (lhsNode->getVectorSize() == 1 || rhsNode->getVectorSize() == 1)
1301 return;
1302 break;
1303
1304 case EOpRightShift:
1305 case EOpLeftShift:
1306 // can natively support the right operand being a scalar and the left a vector,
1307 // but not the reverse
1308 if (rhsNode->getVectorSize() == 1)
1309 return;
1310 break;
1311
1312 case EOpLessThan:
1313 case EOpGreaterThan:
1314 case EOpLessThanEqual:
1315 case EOpGreaterThanEqual:
1316
1317 case EOpEqual:
1318 case EOpNotEqual:
1319
1320 case EOpLogicalAnd:
1321 case EOpLogicalOr:
1322 case EOpLogicalXor:
1323
1324 case EOpAnd:
1325 case EOpInclusiveOr:
1326 case EOpExclusiveOr:
1327
1328 case EOpMix:
1329 break;
1330
1331 default:
1332 return;
1333 }
1334
1335 // Do bidirectional conversions
1336 if (lhsNode->getType().isScalarOrVec1() || rhsNode->getType().isScalarOrVec1()) {
1337 if (lhsNode->getType().isScalarOrVec1())
1338 lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
1339 else
1340 rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
1341 }
1342 lhsNode = addShapeConversion(rhsNode->getType(), lhsNode);
1343 rhsNode = addShapeConversion(lhsNode->getType(), rhsNode);
1344 }
1345
1346 // Convert the node's shape of type for the given type, as allowed by the
1347 // operation involved: 'op'.
1348 //
1349 // Generally, the AST represents allowed GLSL shapes, so this isn't needed
1350 // for GLSL. Bad shapes are caught in conversion or promotion.
1351 //
1352 // Return 'node' if no conversion was done. Promotion handles final shape
1353 // checking.
1354 //
addShapeConversion(const TType & type,TIntermTyped * node)1355 TIntermTyped* TIntermediate::addShapeConversion(const TType& type, TIntermTyped* node)
1356 {
1357 // no conversion needed
1358 if (node->getType() == type)
1359 return node;
1360
1361 // structures and arrays don't change shape, either to or from
1362 if (node->getType().isStruct() || node->getType().isArray() ||
1363 type.isStruct() || type.isArray())
1364 return node;
1365
1366 // The new node that handles the conversion
1367 TOperator constructorOp = mapTypeToConstructorOp(type);
1368
1369 if (getSource() == EShSourceHlsl) {
1370 // HLSL rules for scalar, vector and matrix conversions:
1371 // 1) scalar can become anything, initializing every component with its value
1372 // 2) vector and matrix can become scalar, first element is used (warning: truncation)
1373 // 3) matrix can become matrix with less rows and/or columns (warning: truncation)
1374 // 4) vector can become vector with less rows size (warning: truncation)
1375 // 5a) vector 4 can become 2x2 matrix (special case) (same packing layout, its a reinterpret)
1376 // 5b) 2x2 matrix can become vector 4 (special case) (same packing layout, its a reinterpret)
1377
1378 const TType &sourceType = node->getType();
1379
1380 // rule 1 for scalar to matrix is special
1381 if (sourceType.isScalarOrVec1() && type.isMatrix()) {
1382
1383 // HLSL semantics: the scalar (or vec1) is replicated to every component of the matrix. Left to its
1384 // own devices, the constructor from a scalar would populate the diagonal. This forces replication
1385 // to every matrix element.
1386
1387 // Note that if the node is complex (e.g, a function call), we don't want to duplicate it here
1388 // repeatedly, so we copy it to a temp, then use the temp.
1389 const int matSize = type.computeNumComponents();
1390 TIntermAggregate* rhsAggregate = new TIntermAggregate();
1391
1392 const bool isSimple = (node->getAsSymbolNode() != nullptr) || (node->getAsConstantUnion() != nullptr);
1393
1394 if (!isSimple) {
1395 assert(0); // TODO: use node replicator service when available.
1396 }
1397
1398 for (int x = 0; x < matSize; ++x)
1399 rhsAggregate->getSequence().push_back(node);
1400
1401 return setAggregateOperator(rhsAggregate, constructorOp, type, node->getLoc());
1402 }
1403
1404 // rule 1 and 2
1405 if ((sourceType.isScalar() && !type.isScalar()) || (!sourceType.isScalar() && type.isScalar()))
1406 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1407
1408 // rule 3 and 5b
1409 if (sourceType.isMatrix()) {
1410 // rule 3
1411 if (type.isMatrix()) {
1412 if ((sourceType.getMatrixCols() != type.getMatrixCols() || sourceType.getMatrixRows() != type.getMatrixRows()) &&
1413 sourceType.getMatrixCols() >= type.getMatrixCols() && sourceType.getMatrixRows() >= type.getMatrixRows())
1414 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1415 // rule 5b
1416 } else if (type.isVector()) {
1417 if (type.getVectorSize() == 4 && sourceType.getMatrixCols() == 2 && sourceType.getMatrixRows() == 2)
1418 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1419 }
1420 }
1421
1422 // rule 4 and 5a
1423 if (sourceType.isVector()) {
1424 // rule 4
1425 if (type.isVector())
1426 {
1427 if (sourceType.getVectorSize() > type.getVectorSize())
1428 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1429 // rule 5a
1430 } else if (type.isMatrix()) {
1431 if (sourceType.getVectorSize() == 4 && type.getMatrixCols() == 2 && type.getMatrixRows() == 2)
1432 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1433 }
1434 }
1435 }
1436
1437 // scalar -> vector or vec1 -> vector or
1438 // vector -> scalar or
1439 // bigger vector -> smaller vector
1440 if ((node->getType().isScalarOrVec1() && type.isVector()) ||
1441 (node->getType().isVector() && type.isScalar()) ||
1442 (node->isVector() && type.isVector() && node->getVectorSize() > type.getVectorSize()))
1443 return setAggregateOperator(makeAggregate(node), constructorOp, type, node->getLoc());
1444
1445 return node;
1446 }
1447
isIntegralPromotion(TBasicType from,TBasicType to) const1448 bool TIntermediate::isIntegralPromotion(TBasicType from, TBasicType to) const
1449 {
1450 // integral promotions
1451 if (to == EbtInt) {
1452 switch(from) {
1453 case EbtInt8:
1454 case EbtInt16:
1455 case EbtUint8:
1456 case EbtUint16:
1457 return true;
1458 default:
1459 break;
1460 }
1461 }
1462 return false;
1463 }
1464
isFPPromotion(TBasicType from,TBasicType to) const1465 bool TIntermediate::isFPPromotion(TBasicType from, TBasicType to) const
1466 {
1467 // floating-point promotions
1468 if (to == EbtDouble) {
1469 switch(from) {
1470 case EbtFloat16:
1471 case EbtFloat:
1472 return true;
1473 default:
1474 break;
1475 }
1476 }
1477 return false;
1478 }
1479
isIntegralConversion(TBasicType from,TBasicType to) const1480 bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const
1481 {
1482 #ifdef GLSLANG_WEB
1483 return false;
1484 #endif
1485
1486 switch (from) {
1487 case EbtInt:
1488 switch(to) {
1489 case EbtUint:
1490 return version >= 400 || getSource() == EShSourceHlsl;
1491 case EbtInt64:
1492 case EbtUint64:
1493 return true;
1494 default:
1495 break;
1496 }
1497 break;
1498 case EbtUint:
1499 switch(to) {
1500 case EbtInt64:
1501 case EbtUint64:
1502 return true;
1503 default:
1504 break;
1505 }
1506 break;
1507 case EbtInt8:
1508 switch (to) {
1509 case EbtUint8:
1510 case EbtInt16:
1511 case EbtUint16:
1512 case EbtUint:
1513 case EbtInt64:
1514 case EbtUint64:
1515 return true;
1516 default:
1517 break;
1518 }
1519 break;
1520 case EbtUint8:
1521 switch (to) {
1522 case EbtInt16:
1523 case EbtUint16:
1524 case EbtUint:
1525 case EbtInt64:
1526 case EbtUint64:
1527 return true;
1528 default:
1529 break;
1530 }
1531 break;
1532 case EbtInt16:
1533 switch(to) {
1534 case EbtUint16:
1535 case EbtUint:
1536 case EbtInt64:
1537 case EbtUint64:
1538 return true;
1539 default:
1540 break;
1541 }
1542 break;
1543 case EbtUint16:
1544 switch(to) {
1545 case EbtUint:
1546 case EbtInt64:
1547 case EbtUint64:
1548 return true;
1549 default:
1550 break;
1551 }
1552 break;
1553 case EbtInt64:
1554 if (to == EbtUint64) {
1555 return true;
1556 }
1557 break;
1558 default:
1559 break;
1560 }
1561 return false;
1562 }
1563
isFPConversion(TBasicType from,TBasicType to) const1564 bool TIntermediate::isFPConversion(TBasicType from, TBasicType to) const
1565 {
1566 #ifdef GLSLANG_WEB
1567 return false;
1568 #endif
1569
1570 if (to == EbtFloat && from == EbtFloat16) {
1571 return true;
1572 } else {
1573 return false;
1574 }
1575 }
1576
isFPIntegralConversion(TBasicType from,TBasicType to) const1577 bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const
1578 {
1579 switch (from) {
1580 case EbtInt:
1581 case EbtUint:
1582 switch(to) {
1583 case EbtFloat:
1584 case EbtDouble:
1585 return true;
1586 default:
1587 break;
1588 }
1589 break;
1590 #ifndef GLSLANG_WEB
1591 case EbtInt8:
1592 case EbtUint8:
1593 case EbtInt16:
1594 case EbtUint16:
1595 switch (to) {
1596 case EbtFloat16:
1597 case EbtFloat:
1598 case EbtDouble:
1599 return true;
1600 default:
1601 break;
1602 }
1603 break;
1604 case EbtInt64:
1605 case EbtUint64:
1606 if (to == EbtDouble) {
1607 return true;
1608 }
1609 break;
1610 #endif
1611 default:
1612 break;
1613 }
1614 return false;
1615 }
1616
1617 //
1618 // See if the 'from' type is allowed to be implicitly converted to the
1619 // 'to' type. This is not about vector/array/struct, only about basic type.
1620 //
canImplicitlyPromote(TBasicType from,TBasicType to,TOperator op) const1621 bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperator op) const
1622 {
1623 if ((isEsProfile() && version < 310 ) || version == 110)
1624 return false;
1625
1626 if (from == to)
1627 return true;
1628
1629 // TODO: Move more policies into language-specific handlers.
1630 // Some languages allow more general (or potentially, more specific) conversions under some conditions.
1631 if (getSource() == EShSourceHlsl) {
1632 const bool fromConvertable = (from == EbtFloat || from == EbtDouble || from == EbtInt || from == EbtUint || from == EbtBool);
1633 const bool toConvertable = (to == EbtFloat || to == EbtDouble || to == EbtInt || to == EbtUint || to == EbtBool);
1634
1635 if (fromConvertable && toConvertable) {
1636 switch (op) {
1637 case EOpAndAssign: // assignments can perform arbitrary conversions
1638 case EOpInclusiveOrAssign: // ...
1639 case EOpExclusiveOrAssign: // ...
1640 case EOpAssign: // ...
1641 case EOpAddAssign: // ...
1642 case EOpSubAssign: // ...
1643 case EOpMulAssign: // ...
1644 case EOpVectorTimesScalarAssign: // ...
1645 case EOpMatrixTimesScalarAssign: // ...
1646 case EOpDivAssign: // ...
1647 case EOpModAssign: // ...
1648 case EOpReturn: // function returns can also perform arbitrary conversions
1649 case EOpFunctionCall: // conversion of a calling parameter
1650 case EOpLogicalNot:
1651 case EOpLogicalAnd:
1652 case EOpLogicalOr:
1653 case EOpLogicalXor:
1654 case EOpConstructStruct:
1655 return true;
1656 default:
1657 break;
1658 }
1659 }
1660 }
1661
1662 if (getSource() == EShSourceHlsl) {
1663 // HLSL
1664 if (from == EbtBool && (to == EbtInt || to == EbtUint || to == EbtFloat))
1665 return true;
1666 } else {
1667 // GLSL
1668 if (isIntegralPromotion(from, to) ||
1669 isFPPromotion(from, to) ||
1670 isIntegralConversion(from, to) ||
1671 isFPConversion(from, to) ||
1672 isFPIntegralConversion(from, to)) {
1673
1674 if (numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) ||
1675 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8) ||
1676 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int16) ||
1677 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int32) ||
1678 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int64) ||
1679 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float16) ||
1680 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float32) ||
1681 numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_float64)) {
1682 return true;
1683 }
1684 }
1685 }
1686
1687 if (isEsProfile()) {
1688 switch (to) {
1689 case EbtFloat:
1690 switch (from) {
1691 case EbtInt:
1692 case EbtUint:
1693 return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions);
1694 default:
1695 return false;
1696 }
1697 case EbtUint:
1698 switch (from) {
1699 case EbtInt:
1700 return numericFeatures.contains(TNumericFeatures::shader_implicit_conversions);
1701 default:
1702 return false;
1703 }
1704 default:
1705 return false;
1706 }
1707 } else {
1708 switch (to) {
1709 case EbtDouble:
1710 switch (from) {
1711 case EbtInt:
1712 case EbtUint:
1713 case EbtInt64:
1714 case EbtUint64:
1715 case EbtFloat:
1716 return version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64);
1717 case EbtInt16:
1718 case EbtUint16:
1719 return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
1720 numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1721 case EbtFloat16:
1722 return (version >= 400 || numericFeatures.contains(TNumericFeatures::gpu_shader_fp64)) &&
1723 numericFeatures.contains(TNumericFeatures::gpu_shader_half_float);
1724 default:
1725 return false;
1726 }
1727 case EbtFloat:
1728 switch (from) {
1729 case EbtInt:
1730 case EbtUint:
1731 return true;
1732 case EbtBool:
1733 return getSource() == EShSourceHlsl;
1734 case EbtInt16:
1735 case EbtUint16:
1736 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1737 case EbtFloat16:
1738 return numericFeatures.contains(TNumericFeatures::gpu_shader_half_float) ||
1739 getSource() == EShSourceHlsl;
1740 default:
1741 return false;
1742 }
1743 case EbtUint:
1744 switch (from) {
1745 case EbtInt:
1746 return version >= 400 || getSource() == EShSourceHlsl || IsRequestedExtension(E_GL_ARB_gpu_shader5);
1747 case EbtBool:
1748 return getSource() == EShSourceHlsl;
1749 case EbtInt16:
1750 case EbtUint16:
1751 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1752 default:
1753 return false;
1754 }
1755 case EbtInt:
1756 switch (from) {
1757 case EbtBool:
1758 return getSource() == EShSourceHlsl;
1759 case EbtInt16:
1760 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1761 default:
1762 return false;
1763 }
1764 case EbtUint64:
1765 switch (from) {
1766 case EbtInt:
1767 case EbtUint:
1768 case EbtInt64:
1769 return true;
1770 case EbtInt16:
1771 case EbtUint16:
1772 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1773 default:
1774 return false;
1775 }
1776 case EbtInt64:
1777 switch (from) {
1778 case EbtInt:
1779 return true;
1780 case EbtInt16:
1781 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1782 default:
1783 return false;
1784 }
1785 case EbtFloat16:
1786 switch (from) {
1787 case EbtInt16:
1788 case EbtUint16:
1789 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1790 default:
1791 break;
1792 }
1793 return false;
1794 case EbtUint16:
1795 switch (from) {
1796 case EbtInt16:
1797 return numericFeatures.contains(TNumericFeatures::gpu_shader_int16);
1798 default:
1799 break;
1800 }
1801 return false;
1802 default:
1803 return false;
1804 }
1805 }
1806
1807 return false;
1808 }
1809
canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType,TBasicType uintType)1810 static bool canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType, TBasicType uintType)
1811 {
1812 #ifdef GLSLANG_WEB
1813 return false;
1814 #endif
1815
1816 switch(sintType) {
1817 case EbtInt8:
1818 switch(uintType) {
1819 case EbtUint8:
1820 case EbtUint16:
1821 case EbtUint:
1822 case EbtUint64:
1823 return false;
1824 default:
1825 assert(false);
1826 return false;
1827 }
1828 break;
1829 case EbtInt16:
1830 switch(uintType) {
1831 case EbtUint8:
1832 return true;
1833 case EbtUint16:
1834 case EbtUint:
1835 case EbtUint64:
1836 return false;
1837 default:
1838 assert(false);
1839 return false;
1840 }
1841 break;
1842 case EbtInt:
1843 switch(uintType) {
1844 case EbtUint8:
1845 case EbtUint16:
1846 return true;
1847 case EbtUint:
1848 return false;
1849 default:
1850 assert(false);
1851 return false;
1852 }
1853 break;
1854 case EbtInt64:
1855 switch(uintType) {
1856 case EbtUint8:
1857 case EbtUint16:
1858 case EbtUint:
1859 return true;
1860 case EbtUint64:
1861 return false;
1862 default:
1863 assert(false);
1864 return false;
1865 }
1866 break;
1867 default:
1868 assert(false);
1869 return false;
1870 }
1871 }
1872
1873
getCorrespondingUnsignedType(TBasicType type)1874 static TBasicType getCorrespondingUnsignedType(TBasicType type)
1875 {
1876 #ifdef GLSLANG_WEB
1877 assert(type == EbtInt);
1878 return EbtUint;
1879 #endif
1880
1881 switch(type) {
1882 case EbtInt8:
1883 return EbtUint8;
1884 case EbtInt16:
1885 return EbtUint16;
1886 case EbtInt:
1887 return EbtUint;
1888 case EbtInt64:
1889 return EbtUint64;
1890 default:
1891 assert(false);
1892 return EbtNumTypes;
1893 }
1894 }
1895
1896 // Implements the following rules
1897 // - If either operand has type float64_t or derived from float64_t,
1898 // the other shall be converted to float64_t or derived type.
1899 // - Otherwise, if either operand has type float32_t or derived from
1900 // float32_t, the other shall be converted to float32_t or derived type.
1901 // - Otherwise, if either operand has type float16_t or derived from
1902 // float16_t, the other shall be converted to float16_t or derived type.
1903 // - Otherwise, if both operands have integer types the following rules
1904 // shall be applied to the operands:
1905 // - If both operands have the same type, no further conversion
1906 // is needed.
1907 // - Otherwise, if both operands have signed integer types or both
1908 // have unsigned integer types, the operand with the type of lesser
1909 // integer conversion rank shall be converted to the type of the
1910 // operand with greater rank.
1911 // - Otherwise, if the operand that has unsigned integer type has rank
1912 // greater than or equal to the rank of the type of the other
1913 // operand, the operand with signed integer type shall be converted
1914 // to the type of the operand with unsigned integer type.
1915 // - Otherwise, if the type of the operand with signed integer type can
1916 // represent all of the values of the type of the operand with
1917 // unsigned integer type, the operand with unsigned integer type
1918 // shall be converted to the type of the operand with signed
1919 // integer type.
1920 // - Otherwise, both operands shall be converted to the unsigned
1921 // integer type corresponding to the type of the operand with signed
1922 // integer type.
1923
getConversionDestinationType(TBasicType type0,TBasicType type1,TOperator op) const1924 std::tuple<TBasicType, TBasicType> TIntermediate::getConversionDestinationType(TBasicType type0, TBasicType type1, TOperator op) const
1925 {
1926 TBasicType res0 = EbtNumTypes;
1927 TBasicType res1 = EbtNumTypes;
1928
1929 if ((isEsProfile() &&
1930 (version < 310 || !numericFeatures.contains(TNumericFeatures::shader_implicit_conversions))) ||
1931 version == 110)
1932 return std::make_tuple(res0, res1);
1933
1934 if (getSource() == EShSourceHlsl) {
1935 if (canImplicitlyPromote(type1, type0, op)) {
1936 res0 = type0;
1937 res1 = type0;
1938 } else if (canImplicitlyPromote(type0, type1, op)) {
1939 res0 = type1;
1940 res1 = type1;
1941 }
1942 return std::make_tuple(res0, res1);
1943 }
1944
1945 if ((type0 == EbtDouble && canImplicitlyPromote(type1, EbtDouble, op)) ||
1946 (type1 == EbtDouble && canImplicitlyPromote(type0, EbtDouble, op)) ) {
1947 res0 = EbtDouble;
1948 res1 = EbtDouble;
1949 } else if ((type0 == EbtFloat && canImplicitlyPromote(type1, EbtFloat, op)) ||
1950 (type1 == EbtFloat && canImplicitlyPromote(type0, EbtFloat, op)) ) {
1951 res0 = EbtFloat;
1952 res1 = EbtFloat;
1953 } else if ((type0 == EbtFloat16 && canImplicitlyPromote(type1, EbtFloat16, op)) ||
1954 (type1 == EbtFloat16 && canImplicitlyPromote(type0, EbtFloat16, op)) ) {
1955 res0 = EbtFloat16;
1956 res1 = EbtFloat16;
1957 } else if (isTypeInt(type0) && isTypeInt(type1) &&
1958 (canImplicitlyPromote(type0, type1, op) || canImplicitlyPromote(type1, type0, op))) {
1959 if ((isTypeSignedInt(type0) && isTypeSignedInt(type1)) ||
1960 (isTypeUnsignedInt(type0) && isTypeUnsignedInt(type1))) {
1961 if (getTypeRank(type0) < getTypeRank(type1)) {
1962 res0 = type1;
1963 res1 = type1;
1964 } else {
1965 res0 = type0;
1966 res1 = type0;
1967 }
1968 } else if (isTypeUnsignedInt(type0) && (getTypeRank(type0) > getTypeRank(type1))) {
1969 res0 = type0;
1970 res1 = type0;
1971 } else if (isTypeUnsignedInt(type1) && (getTypeRank(type1) > getTypeRank(type0))) {
1972 res0 = type1;
1973 res1 = type1;
1974 } else if (isTypeSignedInt(type0)) {
1975 if (canSignedIntTypeRepresentAllUnsignedValues(type0, type1)) {
1976 res0 = type0;
1977 res1 = type0;
1978 } else {
1979 res0 = getCorrespondingUnsignedType(type0);
1980 res1 = getCorrespondingUnsignedType(type0);
1981 }
1982 } else if (isTypeSignedInt(type1)) {
1983 if (canSignedIntTypeRepresentAllUnsignedValues(type1, type0)) {
1984 res0 = type1;
1985 res1 = type1;
1986 } else {
1987 res0 = getCorrespondingUnsignedType(type1);
1988 res1 = getCorrespondingUnsignedType(type1);
1989 }
1990 }
1991 }
1992
1993 return std::make_tuple(res0, res1);
1994 }
1995
1996 //
1997 // Given a type, find what operation would fully construct it.
1998 //
mapTypeToConstructorOp(const TType & type) const1999 TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const
2000 {
2001 TOperator op = EOpNull;
2002
2003 if (type.getQualifier().isNonUniform())
2004 return EOpConstructNonuniform;
2005
2006 if (type.isCoopMat())
2007 return EOpConstructCooperativeMatrix;
2008
2009 switch (type.getBasicType()) {
2010 case EbtStruct:
2011 op = EOpConstructStruct;
2012 break;
2013 case EbtSampler:
2014 if (type.getSampler().isCombined())
2015 op = EOpConstructTextureSampler;
2016 break;
2017 case EbtFloat:
2018 if (type.isMatrix()) {
2019 switch (type.getMatrixCols()) {
2020 case 2:
2021 switch (type.getMatrixRows()) {
2022 case 2: op = EOpConstructMat2x2; break;
2023 case 3: op = EOpConstructMat2x3; break;
2024 case 4: op = EOpConstructMat2x4; break;
2025 default: break; // some compilers want this
2026 }
2027 break;
2028 case 3:
2029 switch (type.getMatrixRows()) {
2030 case 2: op = EOpConstructMat3x2; break;
2031 case 3: op = EOpConstructMat3x3; break;
2032 case 4: op = EOpConstructMat3x4; break;
2033 default: break; // some compilers want this
2034 }
2035 break;
2036 case 4:
2037 switch (type.getMatrixRows()) {
2038 case 2: op = EOpConstructMat4x2; break;
2039 case 3: op = EOpConstructMat4x3; break;
2040 case 4: op = EOpConstructMat4x4; break;
2041 default: break; // some compilers want this
2042 }
2043 break;
2044 default: break; // some compilers want this
2045 }
2046 } else {
2047 switch(type.getVectorSize()) {
2048 case 1: op = EOpConstructFloat; break;
2049 case 2: op = EOpConstructVec2; break;
2050 case 3: op = EOpConstructVec3; break;
2051 case 4: op = EOpConstructVec4; break;
2052 default: break; // some compilers want this
2053 }
2054 }
2055 break;
2056 case EbtInt:
2057 if (type.getMatrixCols()) {
2058 switch (type.getMatrixCols()) {
2059 case 2:
2060 switch (type.getMatrixRows()) {
2061 case 2: op = EOpConstructIMat2x2; break;
2062 case 3: op = EOpConstructIMat2x3; break;
2063 case 4: op = EOpConstructIMat2x4; break;
2064 default: break; // some compilers want this
2065 }
2066 break;
2067 case 3:
2068 switch (type.getMatrixRows()) {
2069 case 2: op = EOpConstructIMat3x2; break;
2070 case 3: op = EOpConstructIMat3x3; break;
2071 case 4: op = EOpConstructIMat3x4; break;
2072 default: break; // some compilers want this
2073 }
2074 break;
2075 case 4:
2076 switch (type.getMatrixRows()) {
2077 case 2: op = EOpConstructIMat4x2; break;
2078 case 3: op = EOpConstructIMat4x3; break;
2079 case 4: op = EOpConstructIMat4x4; break;
2080 default: break; // some compilers want this
2081 }
2082 break;
2083 }
2084 } else {
2085 switch(type.getVectorSize()) {
2086 case 1: op = EOpConstructInt; break;
2087 case 2: op = EOpConstructIVec2; break;
2088 case 3: op = EOpConstructIVec3; break;
2089 case 4: op = EOpConstructIVec4; break;
2090 default: break; // some compilers want this
2091 }
2092 }
2093 break;
2094 case EbtUint:
2095 if (type.getMatrixCols()) {
2096 switch (type.getMatrixCols()) {
2097 case 2:
2098 switch (type.getMatrixRows()) {
2099 case 2: op = EOpConstructUMat2x2; break;
2100 case 3: op = EOpConstructUMat2x3; break;
2101 case 4: op = EOpConstructUMat2x4; break;
2102 default: break; // some compilers want this
2103 }
2104 break;
2105 case 3:
2106 switch (type.getMatrixRows()) {
2107 case 2: op = EOpConstructUMat3x2; break;
2108 case 3: op = EOpConstructUMat3x3; break;
2109 case 4: op = EOpConstructUMat3x4; break;
2110 default: break; // some compilers want this
2111 }
2112 break;
2113 case 4:
2114 switch (type.getMatrixRows()) {
2115 case 2: op = EOpConstructUMat4x2; break;
2116 case 3: op = EOpConstructUMat4x3; break;
2117 case 4: op = EOpConstructUMat4x4; break;
2118 default: break; // some compilers want this
2119 }
2120 break;
2121 }
2122 } else {
2123 switch(type.getVectorSize()) {
2124 case 1: op = EOpConstructUint; break;
2125 case 2: op = EOpConstructUVec2; break;
2126 case 3: op = EOpConstructUVec3; break;
2127 case 4: op = EOpConstructUVec4; break;
2128 default: break; // some compilers want this
2129 }
2130 }
2131 break;
2132 case EbtBool:
2133 if (type.getMatrixCols()) {
2134 switch (type.getMatrixCols()) {
2135 case 2:
2136 switch (type.getMatrixRows()) {
2137 case 2: op = EOpConstructBMat2x2; break;
2138 case 3: op = EOpConstructBMat2x3; break;
2139 case 4: op = EOpConstructBMat2x4; break;
2140 default: break; // some compilers want this
2141 }
2142 break;
2143 case 3:
2144 switch (type.getMatrixRows()) {
2145 case 2: op = EOpConstructBMat3x2; break;
2146 case 3: op = EOpConstructBMat3x3; break;
2147 case 4: op = EOpConstructBMat3x4; break;
2148 default: break; // some compilers want this
2149 }
2150 break;
2151 case 4:
2152 switch (type.getMatrixRows()) {
2153 case 2: op = EOpConstructBMat4x2; break;
2154 case 3: op = EOpConstructBMat4x3; break;
2155 case 4: op = EOpConstructBMat4x4; break;
2156 default: break; // some compilers want this
2157 }
2158 break;
2159 }
2160 } else {
2161 switch(type.getVectorSize()) {
2162 case 1: op = EOpConstructBool; break;
2163 case 2: op = EOpConstructBVec2; break;
2164 case 3: op = EOpConstructBVec3; break;
2165 case 4: op = EOpConstructBVec4; break;
2166 default: break; // some compilers want this
2167 }
2168 }
2169 break;
2170 #ifndef GLSLANG_WEB
2171 case EbtDouble:
2172 if (type.getMatrixCols()) {
2173 switch (type.getMatrixCols()) {
2174 case 2:
2175 switch (type.getMatrixRows()) {
2176 case 2: op = EOpConstructDMat2x2; break;
2177 case 3: op = EOpConstructDMat2x3; break;
2178 case 4: op = EOpConstructDMat2x4; break;
2179 default: break; // some compilers want this
2180 }
2181 break;
2182 case 3:
2183 switch (type.getMatrixRows()) {
2184 case 2: op = EOpConstructDMat3x2; break;
2185 case 3: op = EOpConstructDMat3x3; break;
2186 case 4: op = EOpConstructDMat3x4; break;
2187 default: break; // some compilers want this
2188 }
2189 break;
2190 case 4:
2191 switch (type.getMatrixRows()) {
2192 case 2: op = EOpConstructDMat4x2; break;
2193 case 3: op = EOpConstructDMat4x3; break;
2194 case 4: op = EOpConstructDMat4x4; break;
2195 default: break; // some compilers want this
2196 }
2197 break;
2198 }
2199 } else {
2200 switch(type.getVectorSize()) {
2201 case 1: op = EOpConstructDouble; break;
2202 case 2: op = EOpConstructDVec2; break;
2203 case 3: op = EOpConstructDVec3; break;
2204 case 4: op = EOpConstructDVec4; break;
2205 default: break; // some compilers want this
2206 }
2207 }
2208 break;
2209 case EbtFloat16:
2210 if (type.getMatrixCols()) {
2211 switch (type.getMatrixCols()) {
2212 case 2:
2213 switch (type.getMatrixRows()) {
2214 case 2: op = EOpConstructF16Mat2x2; break;
2215 case 3: op = EOpConstructF16Mat2x3; break;
2216 case 4: op = EOpConstructF16Mat2x4; break;
2217 default: break; // some compilers want this
2218 }
2219 break;
2220 case 3:
2221 switch (type.getMatrixRows()) {
2222 case 2: op = EOpConstructF16Mat3x2; break;
2223 case 3: op = EOpConstructF16Mat3x3; break;
2224 case 4: op = EOpConstructF16Mat3x4; break;
2225 default: break; // some compilers want this
2226 }
2227 break;
2228 case 4:
2229 switch (type.getMatrixRows()) {
2230 case 2: op = EOpConstructF16Mat4x2; break;
2231 case 3: op = EOpConstructF16Mat4x3; break;
2232 case 4: op = EOpConstructF16Mat4x4; break;
2233 default: break; // some compilers want this
2234 }
2235 break;
2236 }
2237 }
2238 else {
2239 switch (type.getVectorSize()) {
2240 case 1: op = EOpConstructFloat16; break;
2241 case 2: op = EOpConstructF16Vec2; break;
2242 case 3: op = EOpConstructF16Vec3; break;
2243 case 4: op = EOpConstructF16Vec4; break;
2244 default: break; // some compilers want this
2245 }
2246 }
2247 break;
2248 case EbtInt8:
2249 switch(type.getVectorSize()) {
2250 case 1: op = EOpConstructInt8; break;
2251 case 2: op = EOpConstructI8Vec2; break;
2252 case 3: op = EOpConstructI8Vec3; break;
2253 case 4: op = EOpConstructI8Vec4; break;
2254 default: break; // some compilers want this
2255 }
2256 break;
2257 case EbtUint8:
2258 switch(type.getVectorSize()) {
2259 case 1: op = EOpConstructUint8; break;
2260 case 2: op = EOpConstructU8Vec2; break;
2261 case 3: op = EOpConstructU8Vec3; break;
2262 case 4: op = EOpConstructU8Vec4; break;
2263 default: break; // some compilers want this
2264 }
2265 break;
2266 case EbtInt16:
2267 switch(type.getVectorSize()) {
2268 case 1: op = EOpConstructInt16; break;
2269 case 2: op = EOpConstructI16Vec2; break;
2270 case 3: op = EOpConstructI16Vec3; break;
2271 case 4: op = EOpConstructI16Vec4; break;
2272 default: break; // some compilers want this
2273 }
2274 break;
2275 case EbtUint16:
2276 switch(type.getVectorSize()) {
2277 case 1: op = EOpConstructUint16; break;
2278 case 2: op = EOpConstructU16Vec2; break;
2279 case 3: op = EOpConstructU16Vec3; break;
2280 case 4: op = EOpConstructU16Vec4; break;
2281 default: break; // some compilers want this
2282 }
2283 break;
2284 case EbtInt64:
2285 switch(type.getVectorSize()) {
2286 case 1: op = EOpConstructInt64; break;
2287 case 2: op = EOpConstructI64Vec2; break;
2288 case 3: op = EOpConstructI64Vec3; break;
2289 case 4: op = EOpConstructI64Vec4; break;
2290 default: break; // some compilers want this
2291 }
2292 break;
2293 case EbtUint64:
2294 switch(type.getVectorSize()) {
2295 case 1: op = EOpConstructUint64; break;
2296 case 2: op = EOpConstructU64Vec2; break;
2297 case 3: op = EOpConstructU64Vec3; break;
2298 case 4: op = EOpConstructU64Vec4; break;
2299 default: break; // some compilers want this
2300 }
2301 break;
2302 case EbtReference:
2303 op = EOpConstructReference;
2304 break;
2305
2306 case EbtAccStruct:
2307 op = EOpConstructAccStruct;
2308 break;
2309 #endif
2310 default:
2311 break;
2312 }
2313
2314 return op;
2315 }
2316
2317 //
2318 // Safe way to combine two nodes into an aggregate. Works with null pointers,
2319 // a node that's not a aggregate yet, etc.
2320 //
2321 // Returns the resulting aggregate, unless nullptr was passed in for
2322 // both existing nodes.
2323 //
growAggregate(TIntermNode * left,TIntermNode * right)2324 TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right)
2325 {
2326 if (left == nullptr && right == nullptr)
2327 return nullptr;
2328
2329 TIntermAggregate* aggNode = nullptr;
2330 if (left != nullptr)
2331 aggNode = left->getAsAggregate();
2332 if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
2333 aggNode = new TIntermAggregate;
2334 if (left != nullptr)
2335 aggNode->getSequence().push_back(left);
2336 }
2337
2338 if (right != nullptr)
2339 aggNode->getSequence().push_back(right);
2340
2341 return aggNode;
2342 }
2343
growAggregate(TIntermNode * left,TIntermNode * right,const TSourceLoc & loc)2344 TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& loc)
2345 {
2346 TIntermAggregate* aggNode = growAggregate(left, right);
2347 if (aggNode)
2348 aggNode->setLoc(loc);
2349
2350 return aggNode;
2351 }
2352
2353 //
2354 // Turn an existing node into an aggregate.
2355 //
2356 // Returns an aggregate, unless nullptr was passed in for the existing node.
2357 //
makeAggregate(TIntermNode * node)2358 TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node)
2359 {
2360 if (node == nullptr)
2361 return nullptr;
2362
2363 TIntermAggregate* aggNode = new TIntermAggregate;
2364 aggNode->getSequence().push_back(node);
2365 aggNode->setLoc(node->getLoc());
2366
2367 return aggNode;
2368 }
2369
makeAggregate(TIntermNode * node,const TSourceLoc & loc)2370 TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& loc)
2371 {
2372 if (node == nullptr)
2373 return nullptr;
2374
2375 TIntermAggregate* aggNode = new TIntermAggregate;
2376 aggNode->getSequence().push_back(node);
2377 aggNode->setLoc(loc);
2378
2379 return aggNode;
2380 }
2381
2382 //
2383 // Make an aggregate with an empty sequence.
2384 //
makeAggregate(const TSourceLoc & loc)2385 TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
2386 {
2387 TIntermAggregate* aggNode = new TIntermAggregate;
2388 aggNode->setLoc(loc);
2389
2390 return aggNode;
2391 }
2392
2393 //
2394 // For "if" test nodes. There are three children; a condition,
2395 // a true path, and a false path. The two paths are in the
2396 // nodePair.
2397 //
2398 // Returns the selection node created.
2399 //
addSelection(TIntermTyped * cond,TIntermNodePair nodePair,const TSourceLoc & loc)2400 TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
2401 {
2402 //
2403 // Don't prune the false path for compile-time constants; it's needed
2404 // for static access analysis.
2405 //
2406
2407 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
2408 node->setLoc(loc);
2409
2410 return node;
2411 }
2412
addComma(TIntermTyped * left,TIntermTyped * right,const TSourceLoc & loc)2413 TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& loc)
2414 {
2415 // However, the lowest precedence operators of the sequence operator ( , ) and the assignment operators
2416 // ... are not included in the operators that can create a constant expression.
2417 //
2418 // if (left->getType().getQualifier().storage == EvqConst &&
2419 // right->getType().getQualifier().storage == EvqConst) {
2420
2421 // return right;
2422 //}
2423
2424 TIntermTyped *commaAggregate = growAggregate(left, right, loc);
2425 commaAggregate->getAsAggregate()->setOperator(EOpComma);
2426 commaAggregate->setType(right->getType());
2427 commaAggregate->getWritableType().getQualifier().makeTemporary();
2428
2429 return commaAggregate;
2430 }
2431
addMethod(TIntermTyped * object,const TType & type,const TString * name,const TSourceLoc & loc)2432 TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type, const TString* name, const TSourceLoc& loc)
2433 {
2434 TIntermMethod* method = new TIntermMethod(object, type, *name);
2435 method->setLoc(loc);
2436
2437 return method;
2438 }
2439
2440 //
2441 // For "?:" test nodes. There are three children; a condition,
2442 // a true path, and a false path. The two paths are specified
2443 // as separate parameters. For vector 'cond', the true and false
2444 // are not paths, but vectors to mix.
2445 //
2446 // Specialization constant operations include
2447 // - The ternary operator ( ? : )
2448 //
2449 // Returns the selection node created, or nullptr if one could not be.
2450 //
addSelection(TIntermTyped * cond,TIntermTyped * trueBlock,TIntermTyped * falseBlock,const TSourceLoc & loc)2451 TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock,
2452 const TSourceLoc& loc)
2453 {
2454 // If it's void, go to the if-then-else selection()
2455 if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
2456 TIntermNodePair pair = { trueBlock, falseBlock };
2457 TIntermSelection* selection = addSelection(cond, pair, loc);
2458 if (getSource() == EShSourceHlsl)
2459 selection->setNoShortCircuit();
2460
2461 return selection;
2462 }
2463
2464 //
2465 // Get compatible types.
2466 //
2467 auto children = addPairConversion(EOpSequence, trueBlock, falseBlock);
2468 trueBlock = std::get<0>(children);
2469 falseBlock = std::get<1>(children);
2470
2471 if (trueBlock == nullptr || falseBlock == nullptr)
2472 return nullptr;
2473
2474 // Handle a vector condition as a mix
2475 if (!cond->getType().isScalarOrVec1()) {
2476 TType targetVectorType(trueBlock->getType().getBasicType(), EvqTemporary,
2477 cond->getType().getVectorSize());
2478 // smear true/false operands as needed
2479 trueBlock = addUniShapeConversion(EOpMix, targetVectorType, trueBlock);
2480 falseBlock = addUniShapeConversion(EOpMix, targetVectorType, falseBlock);
2481
2482 // After conversion, types have to match.
2483 if (falseBlock->getType() != trueBlock->getType())
2484 return nullptr;
2485
2486 // make the mix operation
2487 TIntermAggregate* mix = makeAggregate(loc);
2488 mix = growAggregate(mix, falseBlock);
2489 mix = growAggregate(mix, trueBlock);
2490 mix = growAggregate(mix, cond);
2491 mix->setType(targetVectorType);
2492 mix->setOp(EOpMix);
2493
2494 return mix;
2495 }
2496
2497 // Now have a scalar condition...
2498
2499 // Convert true and false expressions to matching types
2500 addBiShapeConversion(EOpMix, trueBlock, falseBlock);
2501
2502 // After conversion, types have to match.
2503 if (falseBlock->getType() != trueBlock->getType())
2504 return nullptr;
2505
2506 // Eliminate the selection when the condition is a scalar and all operands are constant.
2507 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
2508 if (cond->getAsConstantUnion()->getConstArray()[0].getBConst())
2509 return trueBlock;
2510 else
2511 return falseBlock;
2512 }
2513
2514 //
2515 // Make a selection node.
2516 //
2517 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
2518 node->setLoc(loc);
2519 node->getQualifier().precision = std::max(trueBlock->getQualifier().precision, falseBlock->getQualifier().precision);
2520
2521 if ((cond->getQualifier().isConstant() && specConstantPropagates(*trueBlock, *falseBlock)) ||
2522 (cond->getQualifier().isSpecConstant() && trueBlock->getQualifier().isConstant() &&
2523 falseBlock->getQualifier().isConstant()))
2524 node->getQualifier().makeSpecConstant();
2525 else
2526 node->getQualifier().makeTemporary();
2527
2528 if (getSource() == EShSourceHlsl)
2529 node->setNoShortCircuit();
2530
2531 return node;
2532 }
2533
2534 //
2535 // Constant terminal nodes. Has a union that contains bool, float or int constants
2536 //
2537 // Returns the constant union node created.
2538 //
2539
addConstantUnion(const TConstUnionArray & unionArray,const TType & t,const TSourceLoc & loc,bool literal) const2540 TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, const TSourceLoc& loc, bool literal) const
2541 {
2542 TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
2543 node->getQualifier().storage = EvqConst;
2544 node->setLoc(loc);
2545 if (literal)
2546 node->setLiteral();
2547
2548 return node;
2549 }
addConstantUnion(signed char i8,const TSourceLoc & loc,bool literal) const2550 TIntermConstantUnion* TIntermediate::addConstantUnion(signed char i8, const TSourceLoc& loc, bool literal) const
2551 {
2552 TConstUnionArray unionArray(1);
2553 unionArray[0].setI8Const(i8);
2554
2555 return addConstantUnion(unionArray, TType(EbtInt8, EvqConst), loc, literal);
2556 }
2557
addConstantUnion(unsigned char u8,const TSourceLoc & loc,bool literal) const2558 TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned char u8, const TSourceLoc& loc, bool literal) const
2559 {
2560 TConstUnionArray unionArray(1);
2561 unionArray[0].setUConst(u8);
2562
2563 return addConstantUnion(unionArray, TType(EbtUint8, EvqConst), loc, literal);
2564 }
2565
addConstantUnion(signed short i16,const TSourceLoc & loc,bool literal) const2566 TIntermConstantUnion* TIntermediate::addConstantUnion(signed short i16, const TSourceLoc& loc, bool literal) const
2567 {
2568 TConstUnionArray unionArray(1);
2569 unionArray[0].setI16Const(i16);
2570
2571 return addConstantUnion(unionArray, TType(EbtInt16, EvqConst), loc, literal);
2572 }
2573
addConstantUnion(unsigned short u16,const TSourceLoc & loc,bool literal) const2574 TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned short u16, const TSourceLoc& loc, bool literal) const
2575 {
2576 TConstUnionArray unionArray(1);
2577 unionArray[0].setU16Const(u16);
2578
2579 return addConstantUnion(unionArray, TType(EbtUint16, EvqConst), loc, literal);
2580 }
2581
addConstantUnion(int i,const TSourceLoc & loc,bool literal) const2582 TIntermConstantUnion* TIntermediate::addConstantUnion(int i, const TSourceLoc& loc, bool literal) const
2583 {
2584 TConstUnionArray unionArray(1);
2585 unionArray[0].setIConst(i);
2586
2587 return addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc, literal);
2588 }
2589
addConstantUnion(unsigned int u,const TSourceLoc & loc,bool literal) const2590 TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned int u, const TSourceLoc& loc, bool literal) const
2591 {
2592 TConstUnionArray unionArray(1);
2593 unionArray[0].setUConst(u);
2594
2595 return addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc, literal);
2596 }
2597
addConstantUnion(long long i64,const TSourceLoc & loc,bool literal) const2598 TIntermConstantUnion* TIntermediate::addConstantUnion(long long i64, const TSourceLoc& loc, bool literal) const
2599 {
2600 TConstUnionArray unionArray(1);
2601 unionArray[0].setI64Const(i64);
2602
2603 return addConstantUnion(unionArray, TType(EbtInt64, EvqConst), loc, literal);
2604 }
2605
addConstantUnion(unsigned long long u64,const TSourceLoc & loc,bool literal) const2606 TIntermConstantUnion* TIntermediate::addConstantUnion(unsigned long long u64, const TSourceLoc& loc, bool literal) const
2607 {
2608 TConstUnionArray unionArray(1);
2609 unionArray[0].setU64Const(u64);
2610
2611 return addConstantUnion(unionArray, TType(EbtUint64, EvqConst), loc, literal);
2612 }
2613
addConstantUnion(bool b,const TSourceLoc & loc,bool literal) const2614 TIntermConstantUnion* TIntermediate::addConstantUnion(bool b, const TSourceLoc& loc, bool literal) const
2615 {
2616 TConstUnionArray unionArray(1);
2617 unionArray[0].setBConst(b);
2618
2619 return addConstantUnion(unionArray, TType(EbtBool, EvqConst), loc, literal);
2620 }
2621
addConstantUnion(double d,TBasicType baseType,const TSourceLoc & loc,bool literal) const2622 TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseType, const TSourceLoc& loc, bool literal) const
2623 {
2624 assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16);
2625
2626 TConstUnionArray unionArray(1);
2627 unionArray[0].setDConst(d);
2628
2629 return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
2630 }
2631
addConstantUnion(const TString * s,const TSourceLoc & loc,bool literal) const2632 TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const
2633 {
2634 TConstUnionArray unionArray(1);
2635 unionArray[0].setSConst(s);
2636
2637 return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal);
2638 }
2639
2640 // Put vector swizzle selectors onto the given sequence
pushSelector(TIntermSequence & sequence,const TVectorSelector & selector,const TSourceLoc & loc)2641 void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
2642 {
2643 TIntermConstantUnion* constIntNode = addConstantUnion(selector, loc);
2644 sequence.push_back(constIntNode);
2645 }
2646
2647 // Put matrix swizzle selectors onto the given sequence
pushSelector(TIntermSequence & sequence,const TMatrixSelector & selector,const TSourceLoc & loc)2648 void TIntermediate::pushSelector(TIntermSequence& sequence, const TMatrixSelector& selector, const TSourceLoc& loc)
2649 {
2650 TIntermConstantUnion* constIntNode = addConstantUnion(selector.coord1, loc);
2651 sequence.push_back(constIntNode);
2652 constIntNode = addConstantUnion(selector.coord2, loc);
2653 sequence.push_back(constIntNode);
2654 }
2655
2656 // Make an aggregate node that has a sequence of all selectors.
2657 template TIntermTyped* TIntermediate::addSwizzle<TVectorSelector>(TSwizzleSelectors<TVectorSelector>& selector, const TSourceLoc& loc);
2658 template TIntermTyped* TIntermediate::addSwizzle<TMatrixSelector>(TSwizzleSelectors<TMatrixSelector>& selector, const TSourceLoc& loc);
2659 template<typename selectorType>
addSwizzle(TSwizzleSelectors<selectorType> & selector,const TSourceLoc & loc)2660 TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors<selectorType>& selector, const TSourceLoc& loc)
2661 {
2662 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
2663
2664 node->setLoc(loc);
2665 TIntermSequence &sequenceVector = node->getSequence();
2666
2667 for (int i = 0; i < selector.size(); i++)
2668 pushSelector(sequenceVector, selector[i], loc);
2669
2670 return node;
2671 }
2672
2673 //
2674 // Follow the left branches down to the root of an l-value
2675 // expression (just "." and []).
2676 //
2677 // Return the base of the l-value (where following indexing quits working).
2678 // Return nullptr if a chain following dereferences cannot be followed.
2679 //
2680 // 'swizzleOkay' says whether or not it is okay to consider a swizzle
2681 // a valid part of the dereference chain.
2682 //
2683 // 'BufferReferenceOk' says if type is buffer_reference, the routine stop to find the most left node.
2684 //
2685 //
2686
findLValueBase(const TIntermTyped * node,bool swizzleOkay,bool bufferReferenceOk)2687 const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay , bool bufferReferenceOk)
2688 {
2689 do {
2690 const TIntermBinary* binary = node->getAsBinaryNode();
2691 if (binary == nullptr)
2692 return node;
2693 TOperator op = binary->getOp();
2694 if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle)
2695 return nullptr;
2696 if (! swizzleOkay) {
2697 if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle)
2698 return nullptr;
2699 if ((op == EOpIndexDirect || op == EOpIndexIndirect) &&
2700 (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) &&
2701 ! binary->getLeft()->getType().isArray())
2702 return nullptr;
2703 }
2704 node = node->getAsBinaryNode()->getLeft();
2705 if (bufferReferenceOk && node->isReference())
2706 return node;
2707 } while (true);
2708 }
2709
2710 //
2711 // Create while and do-while loop nodes.
2712 //
addLoop(TIntermNode * body,TIntermTyped * test,TIntermTyped * terminal,bool testFirst,const TSourceLoc & loc)2713 TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
2714 const TSourceLoc& loc)
2715 {
2716 TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
2717 node->setLoc(loc);
2718
2719 return node;
2720 }
2721
2722 //
2723 // Create a for-loop sequence.
2724 //
addForLoop(TIntermNode * body,TIntermNode * initializer,TIntermTyped * test,TIntermTyped * terminal,bool testFirst,const TSourceLoc & loc,TIntermLoop * & node)2725 TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
2726 TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
2727 {
2728 node = new TIntermLoop(body, test, terminal, testFirst);
2729 node->setLoc(loc);
2730
2731 // make a sequence of the initializer and statement, but try to reuse the
2732 // aggregate already created for whatever is in the initializer, if there is one
2733 TIntermAggregate* loopSequence = (initializer == nullptr ||
2734 initializer->getAsAggregate() == nullptr) ? makeAggregate(initializer, loc)
2735 : initializer->getAsAggregate();
2736 if (loopSequence != nullptr && (loopSequence->getOp() == EOpSequence || loopSequence->getOp() == EOpScope))
2737 loopSequence->setOp(EOpNull);
2738 loopSequence = growAggregate(loopSequence, node);
2739 loopSequence->setOperator(getDebugInfo() ? EOpScope : EOpSequence);
2740
2741 return loopSequence;
2742 }
2743
2744 //
2745 // Add branches.
2746 //
addBranch(TOperator branchOp,const TSourceLoc & loc)2747 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& loc)
2748 {
2749 return addBranch(branchOp, nullptr, loc);
2750 }
2751
addBranch(TOperator branchOp,TIntermTyped * expression,const TSourceLoc & loc)2752 TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& loc)
2753 {
2754 TIntermBranch* node = new TIntermBranch(branchOp, expression);
2755 node->setLoc(loc);
2756
2757 return node;
2758 }
2759
2760 // Propagate precision from formal function return type to actual return type,
2761 // and on to its subtree.
updatePrecision(TPrecisionQualifier parentPrecision)2762 void TIntermBranch::updatePrecision(TPrecisionQualifier parentPrecision)
2763 {
2764 TIntermTyped* exp = getExpression();
2765 if (exp == nullptr)
2766 return;
2767
2768 if (exp->getBasicType() == EbtInt || exp->getBasicType() == EbtUint ||
2769 exp->getBasicType() == EbtFloat) {
2770 if (parentPrecision != EpqNone && exp->getQualifier().precision == EpqNone) {
2771 exp->propagatePrecision(parentPrecision);
2772 }
2773 }
2774 }
2775
2776 //
2777 // This is to be executed after the final root is put on top by the parsing
2778 // process.
2779 //
postProcess(TIntermNode * root,EShLanguage)2780 bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/)
2781 {
2782 if (root == nullptr)
2783 return true;
2784
2785 // Finish off the top-level sequence
2786 TIntermAggregate* aggRoot = root->getAsAggregate();
2787 if (aggRoot && aggRoot->getOp() == EOpNull)
2788 aggRoot->setOperator(EOpSequence);
2789
2790 #ifndef GLSLANG_WEB
2791 // Propagate 'noContraction' label in backward from 'precise' variables.
2792 glslang::PropagateNoContraction(*this);
2793
2794 switch (textureSamplerTransformMode) {
2795 case EShTexSampTransKeep:
2796 break;
2797 case EShTexSampTransUpgradeTextureRemoveSampler:
2798 performTextureUpgradeAndSamplerRemovalTransformation(root);
2799 break;
2800 case EShTexSampTransCount:
2801 assert(0);
2802 break;
2803 }
2804 #endif
2805
2806 return true;
2807 }
2808
addSymbolLinkageNodes(TIntermAggregate * & linkage,EShLanguage language,TSymbolTable & symbolTable)2809 void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage language, TSymbolTable& symbolTable)
2810 {
2811 // Add top-level nodes for declarations that must be checked cross
2812 // compilation unit by a linker, yet might not have been referenced
2813 // by the AST.
2814 //
2815 // Almost entirely, translation of symbols is driven by what's present
2816 // in the AST traversal, not by translating the symbol table.
2817 //
2818 // However, there are some special cases:
2819 // - From the specification: "Special built-in inputs gl_VertexID and
2820 // gl_InstanceID are also considered active vertex attributes."
2821 // - Linker-based type mismatch error reporting needs to see all
2822 // uniforms/ins/outs variables and blocks.
2823 // - ftransform() can make gl_Vertex and gl_ModelViewProjectionMatrix active.
2824 //
2825
2826 // if (ftransformUsed) {
2827 // TODO: 1.1 lowering functionality: track ftransform() usage
2828 // addSymbolLinkageNode(root, symbolTable, "gl_Vertex");
2829 // addSymbolLinkageNode(root, symbolTable, "gl_ModelViewProjectionMatrix");
2830 //}
2831
2832 if (language == EShLangVertex) {
2833 // the names won't be found in the symbol table unless the versions are right,
2834 // so version logic does not need to be repeated here
2835 addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID");
2836 addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID");
2837 }
2838
2839 // Add a child to the root node for the linker objects
2840 linkage->setOperator(EOpLinkerObjects);
2841 treeRoot = growAggregate(treeRoot, linkage);
2842 }
2843
2844 //
2845 // Add the given name or symbol to the list of nodes at the end of the tree used
2846 // for link-time checking and external linkage.
2847 //
2848
addSymbolLinkageNode(TIntermAggregate * & linkage,TSymbolTable & symbolTable,const TString & name)2849 void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable& symbolTable, const TString& name)
2850 {
2851 TSymbol* symbol = symbolTable.find(name);
2852 if (symbol)
2853 addSymbolLinkageNode(linkage, *symbol->getAsVariable());
2854 }
2855
addSymbolLinkageNode(TIntermAggregate * & linkage,const TSymbol & symbol)2856 void TIntermediate::addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol& symbol)
2857 {
2858 const TVariable* variable = symbol.getAsVariable();
2859 if (! variable) {
2860 // This must be a member of an anonymous block, and we need to add the whole block
2861 const TAnonMember* anon = symbol.getAsAnonMember();
2862 variable = &anon->getAnonContainer();
2863 }
2864 TIntermSymbol* node = addSymbol(*variable);
2865 linkage = growAggregate(linkage, node);
2866 }
2867
2868 //
2869 // Add a caller->callee relationship to the call graph.
2870 // Assumes the strings are unique per signature.
2871 //
addToCallGraph(TInfoSink &,const TString & caller,const TString & callee)2872 void TIntermediate::addToCallGraph(TInfoSink& /*infoSink*/, const TString& caller, const TString& callee)
2873 {
2874 // Duplicates are okay, but faster to not keep them, and they come grouped by caller,
2875 // as long as new ones are push on the same end we check on for duplicates
2876 for (TGraph::const_iterator call = callGraph.begin(); call != callGraph.end(); ++call) {
2877 if (call->caller != caller)
2878 break;
2879 if (call->callee == callee)
2880 return;
2881 }
2882
2883 callGraph.emplace_front(caller, callee);
2884 }
2885
2886 //
2887 // This deletes the tree.
2888 //
removeTree()2889 void TIntermediate::removeTree()
2890 {
2891 if (treeRoot)
2892 RemoveAllTreeNodes(treeRoot);
2893 }
2894
2895 //
2896 // Implement the part of KHR_vulkan_glsl that lists the set of operations
2897 // that can result in a specialization constant operation.
2898 //
2899 // "5.x Specialization Constant Operations"
2900 //
2901 // Only some operations discussed in this section may be applied to a
2902 // specialization constant and still yield a result that is as
2903 // specialization constant. The operations allowed are listed below.
2904 // When a specialization constant is operated on with one of these
2905 // operators and with another constant or specialization constant, the
2906 // result is implicitly a specialization constant.
2907 //
2908 // - int(), uint(), and bool() constructors for type conversions
2909 // from any of the following types to any of the following types:
2910 // * int
2911 // * uint
2912 // * bool
2913 // - vector versions of the above conversion constructors
2914 // - allowed implicit conversions of the above
2915 // - swizzles (e.g., foo.yx)
2916 // - The following when applied to integer or unsigned integer types:
2917 // * unary negative ( - )
2918 // * binary operations ( + , - , * , / , % )
2919 // * shift ( <<, >> )
2920 // * bitwise operations ( & , | , ^ )
2921 // - The following when applied to integer or unsigned integer scalar types:
2922 // * comparison ( == , != , > , >= , < , <= )
2923 // - The following when applied to the Boolean scalar type:
2924 // * not ( ! )
2925 // * logical operations ( && , || , ^^ )
2926 // * comparison ( == , != )"
2927 //
2928 // This function just handles binary and unary nodes. Construction
2929 // rules are handled in construction paths that are not covered by the unary
2930 // and binary paths, while required conversions will still show up here
2931 // as unary converters in the from a construction operator.
2932 //
isSpecializationOperation(const TIntermOperator & node) const2933 bool TIntermediate::isSpecializationOperation(const TIntermOperator& node) const
2934 {
2935 // The operations resulting in floating point are quite limited
2936 // (However, some floating-point operations result in bool, like ">",
2937 // so are handled later.)
2938 if (node.getType().isFloatingDomain()) {
2939 switch (node.getOp()) {
2940 case EOpIndexDirect:
2941 case EOpIndexIndirect:
2942 case EOpIndexDirectStruct:
2943 case EOpVectorSwizzle:
2944 case EOpConvFloatToDouble:
2945 case EOpConvDoubleToFloat:
2946 case EOpConvFloat16ToFloat:
2947 case EOpConvFloatToFloat16:
2948 case EOpConvFloat16ToDouble:
2949 case EOpConvDoubleToFloat16:
2950 return true;
2951 default:
2952 return false;
2953 }
2954 }
2955
2956 // Check for floating-point arguments
2957 if (const TIntermBinary* bin = node.getAsBinaryNode())
2958 if (bin->getLeft() ->getType().isFloatingDomain() ||
2959 bin->getRight()->getType().isFloatingDomain())
2960 return false;
2961
2962 // So, for now, we can assume everything left is non-floating-point...
2963
2964 // Now check for integer/bool-based operations
2965 switch (node.getOp()) {
2966
2967 // dereference/swizzle
2968 case EOpIndexDirect:
2969 case EOpIndexIndirect:
2970 case EOpIndexDirectStruct:
2971 case EOpVectorSwizzle:
2972
2973 // (u)int* -> bool
2974 case EOpConvInt8ToBool:
2975 case EOpConvInt16ToBool:
2976 case EOpConvIntToBool:
2977 case EOpConvInt64ToBool:
2978 case EOpConvUint8ToBool:
2979 case EOpConvUint16ToBool:
2980 case EOpConvUintToBool:
2981 case EOpConvUint64ToBool:
2982
2983 // bool -> (u)int*
2984 case EOpConvBoolToInt8:
2985 case EOpConvBoolToInt16:
2986 case EOpConvBoolToInt:
2987 case EOpConvBoolToInt64:
2988 case EOpConvBoolToUint8:
2989 case EOpConvBoolToUint16:
2990 case EOpConvBoolToUint:
2991 case EOpConvBoolToUint64:
2992
2993 // int8_t -> (u)int*
2994 case EOpConvInt8ToInt16:
2995 case EOpConvInt8ToInt:
2996 case EOpConvInt8ToInt64:
2997 case EOpConvInt8ToUint8:
2998 case EOpConvInt8ToUint16:
2999 case EOpConvInt8ToUint:
3000 case EOpConvInt8ToUint64:
3001
3002 // int16_t -> (u)int*
3003 case EOpConvInt16ToInt8:
3004 case EOpConvInt16ToInt:
3005 case EOpConvInt16ToInt64:
3006 case EOpConvInt16ToUint8:
3007 case EOpConvInt16ToUint16:
3008 case EOpConvInt16ToUint:
3009 case EOpConvInt16ToUint64:
3010
3011 // int32_t -> (u)int*
3012 case EOpConvIntToInt8:
3013 case EOpConvIntToInt16:
3014 case EOpConvIntToInt64:
3015 case EOpConvIntToUint8:
3016 case EOpConvIntToUint16:
3017 case EOpConvIntToUint:
3018 case EOpConvIntToUint64:
3019
3020 // int64_t -> (u)int*
3021 case EOpConvInt64ToInt8:
3022 case EOpConvInt64ToInt16:
3023 case EOpConvInt64ToInt:
3024 case EOpConvInt64ToUint8:
3025 case EOpConvInt64ToUint16:
3026 case EOpConvInt64ToUint:
3027 case EOpConvInt64ToUint64:
3028
3029 // uint8_t -> (u)int*
3030 case EOpConvUint8ToInt8:
3031 case EOpConvUint8ToInt16:
3032 case EOpConvUint8ToInt:
3033 case EOpConvUint8ToInt64:
3034 case EOpConvUint8ToUint16:
3035 case EOpConvUint8ToUint:
3036 case EOpConvUint8ToUint64:
3037
3038 // uint16_t -> (u)int*
3039 case EOpConvUint16ToInt8:
3040 case EOpConvUint16ToInt16:
3041 case EOpConvUint16ToInt:
3042 case EOpConvUint16ToInt64:
3043 case EOpConvUint16ToUint8:
3044 case EOpConvUint16ToUint:
3045 case EOpConvUint16ToUint64:
3046
3047 // uint32_t -> (u)int*
3048 case EOpConvUintToInt8:
3049 case EOpConvUintToInt16:
3050 case EOpConvUintToInt:
3051 case EOpConvUintToInt64:
3052 case EOpConvUintToUint8:
3053 case EOpConvUintToUint16:
3054 case EOpConvUintToUint64:
3055
3056 // uint64_t -> (u)int*
3057 case EOpConvUint64ToInt8:
3058 case EOpConvUint64ToInt16:
3059 case EOpConvUint64ToInt:
3060 case EOpConvUint64ToInt64:
3061 case EOpConvUint64ToUint8:
3062 case EOpConvUint64ToUint16:
3063 case EOpConvUint64ToUint:
3064
3065 // unary operations
3066 case EOpNegative:
3067 case EOpLogicalNot:
3068 case EOpBitwiseNot:
3069
3070 // binary operations
3071 case EOpAdd:
3072 case EOpSub:
3073 case EOpMul:
3074 case EOpVectorTimesScalar:
3075 case EOpDiv:
3076 case EOpMod:
3077 case EOpRightShift:
3078 case EOpLeftShift:
3079 case EOpAnd:
3080 case EOpInclusiveOr:
3081 case EOpExclusiveOr:
3082 case EOpLogicalOr:
3083 case EOpLogicalXor:
3084 case EOpLogicalAnd:
3085 case EOpEqual:
3086 case EOpNotEqual:
3087 case EOpLessThan:
3088 case EOpGreaterThan:
3089 case EOpLessThanEqual:
3090 case EOpGreaterThanEqual:
3091 return true;
3092 default:
3093 return false;
3094 }
3095 }
3096
3097 // Is the operation one that must propagate nonuniform?
isNonuniformPropagating(TOperator op) const3098 bool TIntermediate::isNonuniformPropagating(TOperator op) const
3099 {
3100 // "* All Operators in Section 5.1 (Operators), except for assignment,
3101 // arithmetic assignment, and sequence
3102 // * Component selection in Section 5.5
3103 // * Matrix components in Section 5.6
3104 // * Structure and Array Operations in Section 5.7, except for the length
3105 // method."
3106 switch (op) {
3107 case EOpPostIncrement:
3108 case EOpPostDecrement:
3109 case EOpPreIncrement:
3110 case EOpPreDecrement:
3111
3112 case EOpNegative:
3113 case EOpLogicalNot:
3114 case EOpVectorLogicalNot:
3115 case EOpBitwiseNot:
3116
3117 case EOpAdd:
3118 case EOpSub:
3119 case EOpMul:
3120 case EOpDiv:
3121 case EOpMod:
3122 case EOpRightShift:
3123 case EOpLeftShift:
3124 case EOpAnd:
3125 case EOpInclusiveOr:
3126 case EOpExclusiveOr:
3127 case EOpEqual:
3128 case EOpNotEqual:
3129 case EOpLessThan:
3130 case EOpGreaterThan:
3131 case EOpLessThanEqual:
3132 case EOpGreaterThanEqual:
3133 case EOpVectorTimesScalar:
3134 case EOpVectorTimesMatrix:
3135 case EOpMatrixTimesVector:
3136 case EOpMatrixTimesScalar:
3137
3138 case EOpLogicalOr:
3139 case EOpLogicalXor:
3140 case EOpLogicalAnd:
3141
3142 case EOpIndexDirect:
3143 case EOpIndexIndirect:
3144 case EOpIndexDirectStruct:
3145 case EOpVectorSwizzle:
3146 return true;
3147
3148 default:
3149 break;
3150 }
3151
3152 return false;
3153 }
3154
3155 ////////////////////////////////////////////////////////////////
3156 //
3157 // Member functions of the nodes used for building the tree.
3158 //
3159 ////////////////////////////////////////////////////////////////
3160
3161 //
3162 // Say whether or not an operation node changes the value of a variable.
3163 //
3164 // Returns true if state is modified.
3165 //
modifiesState() const3166 bool TIntermOperator::modifiesState() const
3167 {
3168 switch (op) {
3169 case EOpPostIncrement:
3170 case EOpPostDecrement:
3171 case EOpPreIncrement:
3172 case EOpPreDecrement:
3173 case EOpAssign:
3174 case EOpAddAssign:
3175 case EOpSubAssign:
3176 case EOpMulAssign:
3177 case EOpVectorTimesMatrixAssign:
3178 case EOpVectorTimesScalarAssign:
3179 case EOpMatrixTimesScalarAssign:
3180 case EOpMatrixTimesMatrixAssign:
3181 case EOpDivAssign:
3182 case EOpModAssign:
3183 case EOpAndAssign:
3184 case EOpInclusiveOrAssign:
3185 case EOpExclusiveOrAssign:
3186 case EOpLeftShiftAssign:
3187 case EOpRightShiftAssign:
3188 return true;
3189 default:
3190 return false;
3191 }
3192 }
3193
3194 //
3195 // returns true if the operator is for one of the constructors
3196 //
isConstructor() const3197 bool TIntermOperator::isConstructor() const
3198 {
3199 return op > EOpConstructGuardStart && op < EOpConstructGuardEnd;
3200 }
3201
3202 //
3203 // Make sure the type of an operator is appropriate for its
3204 // combination of operation and operand type. This will invoke
3205 // promoteUnary, promoteBinary, etc as needed.
3206 //
3207 // Returns false if nothing makes sense.
3208 //
promote(TIntermOperator * node)3209 bool TIntermediate::promote(TIntermOperator* node)
3210 {
3211 if (node == nullptr)
3212 return false;
3213
3214 if (node->getAsUnaryNode())
3215 return promoteUnary(*node->getAsUnaryNode());
3216
3217 if (node->getAsBinaryNode())
3218 return promoteBinary(*node->getAsBinaryNode());
3219
3220 if (node->getAsAggregate())
3221 return promoteAggregate(*node->getAsAggregate());
3222
3223 return false;
3224 }
3225
3226 //
3227 // See TIntermediate::promote
3228 //
promoteUnary(TIntermUnary & node)3229 bool TIntermediate::promoteUnary(TIntermUnary& node)
3230 {
3231 const TOperator op = node.getOp();
3232 TIntermTyped* operand = node.getOperand();
3233
3234 switch (op) {
3235 case EOpLogicalNot:
3236 // Convert operand to a boolean type
3237 if (operand->getBasicType() != EbtBool) {
3238 // Add constructor to boolean type. If that fails, we can't do it, so return false.
3239 TIntermTyped* converted = addConversion(op, TType(EbtBool), operand);
3240 if (converted == nullptr)
3241 return false;
3242
3243 // Use the result of converting the node to a bool.
3244 node.setOperand(operand = converted); // also updates stack variable
3245 }
3246 break;
3247 case EOpBitwiseNot:
3248 if (!isTypeInt(operand->getBasicType()))
3249 return false;
3250 break;
3251 case EOpNegative:
3252 case EOpPostIncrement:
3253 case EOpPostDecrement:
3254 case EOpPreIncrement:
3255 case EOpPreDecrement:
3256 if (!isTypeInt(operand->getBasicType()) &&
3257 operand->getBasicType() != EbtFloat &&
3258 operand->getBasicType() != EbtFloat16 &&
3259 operand->getBasicType() != EbtDouble)
3260
3261 return false;
3262 break;
3263 default:
3264 // HLSL uses this path for initial function signature finding for built-ins
3265 // taking a single argument, which generally don't participate in
3266 // operator-based type promotion (type conversion will occur later).
3267 // For now, scalar argument cases are relying on the setType() call below.
3268 if (getSource() == EShSourceHlsl)
3269 break;
3270
3271 // GLSL only allows integer arguments for the cases identified above in the
3272 // case statements.
3273 if (operand->getBasicType() != EbtFloat)
3274 return false;
3275 }
3276
3277 node.setType(operand->getType());
3278 node.getWritableType().getQualifier().makeTemporary();
3279
3280 return true;
3281 }
3282
3283 // Propagate precision qualifiers *up* from children to parent.
updatePrecision()3284 void TIntermUnary::updatePrecision()
3285 {
3286 if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
3287 getBasicType() == EbtFloat) {
3288 if (operand->getQualifier().precision > getQualifier().precision)
3289 getQualifier().precision = operand->getQualifier().precision;
3290 }
3291 }
3292
3293 //
3294 // See TIntermediate::promote
3295 //
promoteBinary(TIntermBinary & node)3296 bool TIntermediate::promoteBinary(TIntermBinary& node)
3297 {
3298 TOperator op = node.getOp();
3299 TIntermTyped* left = node.getLeft();
3300 TIntermTyped* right = node.getRight();
3301
3302 // Arrays and structures have to be exact matches.
3303 if ((left->isArray() || right->isArray() || left->getBasicType() == EbtStruct || right->getBasicType() == EbtStruct)
3304 && left->getType() != right->getType())
3305 return false;
3306
3307 // Base assumption: just make the type the same as the left
3308 // operand. Only deviations from this will be coded.
3309 node.setType(left->getType());
3310 node.getWritableType().getQualifier().clear();
3311
3312 // Composite and opaque types don't having pending operator changes, e.g.,
3313 // array, structure, and samplers. Just establish final type and correctness.
3314 if (left->isArray() || left->getBasicType() == EbtStruct || left->getBasicType() == EbtSampler) {
3315 switch (op) {
3316 case EOpEqual:
3317 case EOpNotEqual:
3318 if (left->getBasicType() == EbtSampler) {
3319 // can't compare samplers
3320 return false;
3321 } else {
3322 // Promote to conditional
3323 node.setType(TType(EbtBool));
3324 }
3325
3326 return true;
3327
3328 case EOpAssign:
3329 // Keep type from above
3330
3331 return true;
3332
3333 default:
3334 return false;
3335 }
3336 }
3337
3338 //
3339 // We now have only scalars, vectors, and matrices to worry about.
3340 //
3341
3342 // HLSL implicitly promotes bool -> int for numeric operations.
3343 // (Implicit conversions to make the operands match each other's types were already done.)
3344 if (getSource() == EShSourceHlsl &&
3345 (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)) {
3346 switch (op) {
3347 case EOpLessThan:
3348 case EOpGreaterThan:
3349 case EOpLessThanEqual:
3350 case EOpGreaterThanEqual:
3351
3352 case EOpRightShift:
3353 case EOpLeftShift:
3354
3355 case EOpMod:
3356
3357 case EOpAnd:
3358 case EOpInclusiveOr:
3359 case EOpExclusiveOr:
3360
3361 case EOpAdd:
3362 case EOpSub:
3363 case EOpDiv:
3364 case EOpMul:
3365 if (left->getBasicType() == EbtBool)
3366 left = createConversion(EbtInt, left);
3367 if (right->getBasicType() == EbtBool)
3368 right = createConversion(EbtInt, right);
3369 if (left == nullptr || right == nullptr)
3370 return false;
3371 node.setLeft(left);
3372 node.setRight(right);
3373
3374 // Update the original base assumption on result type..
3375 node.setType(left->getType());
3376 node.getWritableType().getQualifier().clear();
3377
3378 break;
3379
3380 default:
3381 break;
3382 }
3383 }
3384
3385 // Do general type checks against individual operands (comparing left and right is coming up, checking mixed shapes after that)
3386 switch (op) {
3387 case EOpLessThan:
3388 case EOpGreaterThan:
3389 case EOpLessThanEqual:
3390 case EOpGreaterThanEqual:
3391 // Relational comparisons need numeric types and will promote to scalar Boolean.
3392 if (left->getBasicType() == EbtBool)
3393 return false;
3394
3395 node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
3396 break;
3397
3398 case EOpEqual:
3399 case EOpNotEqual:
3400 if (getSource() == EShSourceHlsl) {
3401 const int resultWidth = std::max(left->getVectorSize(), right->getVectorSize());
3402
3403 // In HLSL, == or != on vectors means component-wise comparison.
3404 if (resultWidth > 1) {
3405 op = (op == EOpEqual) ? EOpVectorEqual : EOpVectorNotEqual;
3406 node.setOp(op);
3407 }
3408
3409 node.setType(TType(EbtBool, EvqTemporary, resultWidth));
3410 } else {
3411 // All the above comparisons result in a bool (but not the vector compares)
3412 node.setType(TType(EbtBool));
3413 }
3414 break;
3415
3416 case EOpLogicalAnd:
3417 case EOpLogicalOr:
3418 case EOpLogicalXor:
3419 // logical ops operate only on Booleans or vectors of Booleans.
3420 if (left->getBasicType() != EbtBool || left->isMatrix())
3421 return false;
3422
3423 if (getSource() == EShSourceGlsl) {
3424 // logical ops operate only on scalar Booleans and will promote to scalar Boolean.
3425 if (left->isVector())
3426 return false;
3427 }
3428
3429 node.setType(TType(EbtBool, EvqTemporary, left->getVectorSize()));
3430 break;
3431
3432 case EOpRightShift:
3433 case EOpLeftShift:
3434 case EOpRightShiftAssign:
3435 case EOpLeftShiftAssign:
3436
3437 case EOpMod:
3438 case EOpModAssign:
3439
3440 case EOpAnd:
3441 case EOpInclusiveOr:
3442 case EOpExclusiveOr:
3443 case EOpAndAssign:
3444 case EOpInclusiveOrAssign:
3445 case EOpExclusiveOrAssign:
3446 if (getSource() == EShSourceHlsl)
3447 break;
3448
3449 // Check for integer-only operands.
3450 if (!isTypeInt(left->getBasicType()) && !isTypeInt(right->getBasicType()))
3451 return false;
3452 if (left->isMatrix() || right->isMatrix())
3453 return false;
3454
3455 break;
3456
3457 case EOpAdd:
3458 case EOpSub:
3459 case EOpDiv:
3460 case EOpMul:
3461 case EOpAddAssign:
3462 case EOpSubAssign:
3463 case EOpMulAssign:
3464 case EOpDivAssign:
3465 // check for non-Boolean operands
3466 if (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool)
3467 return false;
3468
3469 default:
3470 break;
3471 }
3472
3473 // Compare left and right, and finish with the cases where the operand types must match
3474 switch (op) {
3475 case EOpLessThan:
3476 case EOpGreaterThan:
3477 case EOpLessThanEqual:
3478 case EOpGreaterThanEqual:
3479
3480 case EOpEqual:
3481 case EOpNotEqual:
3482 case EOpVectorEqual:
3483 case EOpVectorNotEqual:
3484
3485 case EOpLogicalAnd:
3486 case EOpLogicalOr:
3487 case EOpLogicalXor:
3488 return left->getType() == right->getType();
3489
3490 case EOpMod:
3491 case EOpModAssign:
3492
3493 case EOpAnd:
3494 case EOpInclusiveOr:
3495 case EOpExclusiveOr:
3496 case EOpAndAssign:
3497 case EOpInclusiveOrAssign:
3498 case EOpExclusiveOrAssign:
3499
3500 case EOpAdd:
3501 case EOpSub:
3502 case EOpDiv:
3503
3504 case EOpAddAssign:
3505 case EOpSubAssign:
3506 case EOpDivAssign:
3507 // Quick out in case the types do match
3508 if (left->getType() == right->getType())
3509 return true;
3510
3511 // Fall through
3512
3513 case EOpMul:
3514 case EOpMulAssign:
3515 // At least the basic type has to match
3516 if (left->getBasicType() != right->getBasicType())
3517 return false;
3518
3519 default:
3520 break;
3521 }
3522
3523 if (left->getType().isCoopMat() || right->getType().isCoopMat()) {
3524 if (left->getType().isCoopMat() && right->getType().isCoopMat() &&
3525 *left->getType().getTypeParameters() != *right->getType().getTypeParameters()) {
3526 return false;
3527 }
3528 switch (op) {
3529 case EOpMul:
3530 case EOpMulAssign:
3531 if (left->getType().isCoopMat() && right->getType().isCoopMat()) {
3532 return false;
3533 }
3534 if (op == EOpMulAssign && right->getType().isCoopMat()) {
3535 return false;
3536 }
3537 node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar);
3538 if (right->getType().isCoopMat()) {
3539 node.setType(right->getType());
3540 }
3541 return true;
3542 case EOpAdd:
3543 case EOpSub:
3544 case EOpDiv:
3545 case EOpAssign:
3546 // These require both to be cooperative matrices
3547 if (!left->getType().isCoopMat() || !right->getType().isCoopMat()) {
3548 return false;
3549 }
3550 return true;
3551 default:
3552 break;
3553 }
3554 return false;
3555 }
3556
3557 // Finish handling the case, for all ops, where both operands are scalars.
3558 if (left->isScalar() && right->isScalar())
3559 return true;
3560
3561 // Finish handling the case, for all ops, where there are two vectors of different sizes
3562 if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize() && right->getVectorSize() > 1)
3563 return false;
3564
3565 //
3566 // We now have a mix of scalars, vectors, or matrices, for non-relational operations.
3567 //
3568
3569 // Can these two operands be combined, what is the resulting type?
3570 TBasicType basicType = left->getBasicType();
3571 switch (op) {
3572 case EOpMul:
3573 if (!left->isMatrix() && right->isMatrix()) {
3574 if (left->isVector()) {
3575 if (left->getVectorSize() != right->getMatrixRows())
3576 return false;
3577 node.setOp(op = EOpVectorTimesMatrix);
3578 node.setType(TType(basicType, EvqTemporary, right->getMatrixCols()));
3579 } else {
3580 node.setOp(op = EOpMatrixTimesScalar);
3581 node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), right->getMatrixRows()));
3582 }
3583 } else if (left->isMatrix() && !right->isMatrix()) {
3584 if (right->isVector()) {
3585 if (left->getMatrixCols() != right->getVectorSize())
3586 return false;
3587 node.setOp(op = EOpMatrixTimesVector);
3588 node.setType(TType(basicType, EvqTemporary, left->getMatrixRows()));
3589 } else {
3590 node.setOp(op = EOpMatrixTimesScalar);
3591 }
3592 } else if (left->isMatrix() && right->isMatrix()) {
3593 if (left->getMatrixCols() != right->getMatrixRows())
3594 return false;
3595 node.setOp(op = EOpMatrixTimesMatrix);
3596 node.setType(TType(basicType, EvqTemporary, 0, right->getMatrixCols(), left->getMatrixRows()));
3597 } else if (! left->isMatrix() && ! right->isMatrix()) {
3598 if (left->isVector() && right->isVector()) {
3599 ; // leave as component product
3600 } else if (left->isVector() || right->isVector()) {
3601 node.setOp(op = EOpVectorTimesScalar);
3602 if (right->isVector())
3603 node.setType(TType(basicType, EvqTemporary, right->getVectorSize()));
3604 }
3605 } else {
3606 return false;
3607 }
3608 break;
3609 case EOpMulAssign:
3610 if (! left->isMatrix() && right->isMatrix()) {
3611 if (left->isVector()) {
3612 if (left->getVectorSize() != right->getMatrixRows() || left->getVectorSize() != right->getMatrixCols())
3613 return false;
3614 node.setOp(op = EOpVectorTimesMatrixAssign);
3615 } else {
3616 return false;
3617 }
3618 } else if (left->isMatrix() && !right->isMatrix()) {
3619 if (right->isVector()) {
3620 return false;
3621 } else {
3622 node.setOp(op = EOpMatrixTimesScalarAssign);
3623 }
3624 } else if (left->isMatrix() && right->isMatrix()) {
3625 if (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixCols() != right->getMatrixRows())
3626 return false;
3627 node.setOp(op = EOpMatrixTimesMatrixAssign);
3628 } else if (!left->isMatrix() && !right->isMatrix()) {
3629 if (left->isVector() && right->isVector()) {
3630 // leave as component product
3631 } else if (left->isVector() || right->isVector()) {
3632 if (! left->isVector())
3633 return false;
3634 node.setOp(op = EOpVectorTimesScalarAssign);
3635 }
3636 } else {
3637 return false;
3638 }
3639 break;
3640
3641 case EOpRightShift:
3642 case EOpLeftShift:
3643 case EOpRightShiftAssign:
3644 case EOpLeftShiftAssign:
3645 if (right->isVector() && (! left->isVector() || right->getVectorSize() != left->getVectorSize()))
3646 return false;
3647 break;
3648
3649 case EOpAssign:
3650 if (left->getVectorSize() != right->getVectorSize() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows())
3651 return false;
3652 // fall through
3653
3654 case EOpAdd:
3655 case EOpSub:
3656 case EOpDiv:
3657 case EOpMod:
3658 case EOpAnd:
3659 case EOpInclusiveOr:
3660 case EOpExclusiveOr:
3661 case EOpAddAssign:
3662 case EOpSubAssign:
3663 case EOpDivAssign:
3664 case EOpModAssign:
3665 case EOpAndAssign:
3666 case EOpInclusiveOrAssign:
3667 case EOpExclusiveOrAssign:
3668
3669 if ((left->isMatrix() && right->isVector()) ||
3670 (left->isVector() && right->isMatrix()) ||
3671 left->getBasicType() != right->getBasicType())
3672 return false;
3673 if (left->isMatrix() && right->isMatrix() && (left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows()))
3674 return false;
3675 if (left->isVector() && right->isVector() && left->getVectorSize() != right->getVectorSize())
3676 return false;
3677 if (right->isVector() || right->isMatrix()) {
3678 node.getWritableType().shallowCopy(right->getType());
3679 node.getWritableType().getQualifier().makeTemporary();
3680 }
3681 break;
3682
3683 default:
3684 return false;
3685 }
3686
3687 //
3688 // One more check for assignment.
3689 //
3690 switch (op) {
3691 // The resulting type has to match the left operand.
3692 case EOpAssign:
3693 case EOpAddAssign:
3694 case EOpSubAssign:
3695 case EOpMulAssign:
3696 case EOpDivAssign:
3697 case EOpModAssign:
3698 case EOpAndAssign:
3699 case EOpInclusiveOrAssign:
3700 case EOpExclusiveOrAssign:
3701 case EOpLeftShiftAssign:
3702 case EOpRightShiftAssign:
3703 if (node.getType() != left->getType())
3704 return false;
3705 break;
3706 default:
3707 break;
3708 }
3709
3710 return true;
3711 }
3712
3713 //
3714 // See TIntermediate::promote
3715 //
promoteAggregate(TIntermAggregate & node)3716 bool TIntermediate::promoteAggregate(TIntermAggregate& node)
3717 {
3718 TOperator op = node.getOp();
3719 TIntermSequence& args = node.getSequence();
3720 const int numArgs = static_cast<int>(args.size());
3721
3722 // Presently, only hlsl does intrinsic promotions.
3723 if (getSource() != EShSourceHlsl)
3724 return true;
3725
3726 // set of opcodes that can be promoted in this manner.
3727 switch (op) {
3728 case EOpAtan:
3729 case EOpClamp:
3730 case EOpCross:
3731 case EOpDistance:
3732 case EOpDot:
3733 case EOpDst:
3734 case EOpFaceForward:
3735 // case EOpFindMSB: TODO:
3736 // case EOpFindLSB: TODO:
3737 case EOpFma:
3738 case EOpMod:
3739 case EOpFrexp:
3740 case EOpLdexp:
3741 case EOpMix:
3742 case EOpLit:
3743 case EOpMax:
3744 case EOpMin:
3745 case EOpModf:
3746 // case EOpGenMul: TODO:
3747 case EOpPow:
3748 case EOpReflect:
3749 case EOpRefract:
3750 // case EOpSinCos: TODO:
3751 case EOpSmoothStep:
3752 case EOpStep:
3753 break;
3754 default:
3755 return true;
3756 }
3757
3758 // TODO: array and struct behavior
3759
3760 // Try converting all nodes to the given node's type
3761 TIntermSequence convertedArgs(numArgs, nullptr);
3762
3763 // Try to convert all types to the nonConvArg type.
3764 for (int nonConvArg = 0; nonConvArg < numArgs; ++nonConvArg) {
3765 // Try converting all args to this arg's type
3766 for (int convArg = 0; convArg < numArgs; ++convArg) {
3767 convertedArgs[convArg] = addConversion(op, args[nonConvArg]->getAsTyped()->getType(),
3768 args[convArg]->getAsTyped());
3769 }
3770
3771 // If we successfully converted all the args, use the result.
3772 if (std::all_of(convertedArgs.begin(), convertedArgs.end(),
3773 [](const TIntermNode* node) { return node != nullptr; })) {
3774
3775 std::swap(args, convertedArgs);
3776 return true;
3777 }
3778 }
3779
3780 return false;
3781 }
3782
3783 // Propagate precision qualifiers *up* from children to parent, and then
3784 // back *down* again to the children's subtrees.
updatePrecision()3785 void TIntermAggregate::updatePrecision()
3786 {
3787 if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
3788 getBasicType() == EbtFloat) {
3789 TPrecisionQualifier maxPrecision = EpqNone;
3790 TIntermSequence operands = getSequence();
3791 for (unsigned int i = 0; i < operands.size(); ++i) {
3792 TIntermTyped* typedNode = operands[i]->getAsTyped();
3793 assert(typedNode);
3794 maxPrecision = std::max(maxPrecision, typedNode->getQualifier().precision);
3795 }
3796 getQualifier().precision = maxPrecision;
3797 for (unsigned int i = 0; i < operands.size(); ++i) {
3798 TIntermTyped* typedNode = operands[i]->getAsTyped();
3799 assert(typedNode);
3800 typedNode->propagatePrecision(maxPrecision);
3801 }
3802 }
3803 }
3804
3805 // Propagate precision qualifiers *up* from children to parent, and then
3806 // back *down* again to the children's subtrees.
updatePrecision()3807 void TIntermBinary::updatePrecision()
3808 {
3809 if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
3810 getBasicType() == EbtFloat) {
3811 if (op == EOpRightShift || op == EOpLeftShift) {
3812 // For shifts get precision from left side only and thus no need to propagate
3813 getQualifier().precision = left->getQualifier().precision;
3814 } else {
3815 getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision);
3816 if (getQualifier().precision != EpqNone) {
3817 left->propagatePrecision(getQualifier().precision);
3818 right->propagatePrecision(getQualifier().precision);
3819 }
3820 }
3821 }
3822 }
3823
3824 // Recursively propagate precision qualifiers *down* the subtree of the current node,
3825 // until reaching a node that already has a precision qualifier or otherwise does
3826 // not participate in precision propagation.
propagatePrecision(TPrecisionQualifier newPrecision)3827 void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
3828 {
3829 if (getQualifier().precision != EpqNone ||
3830 (getBasicType() != EbtInt && getBasicType() != EbtUint &&
3831 getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
3832 return;
3833
3834 getQualifier().precision = newPrecision;
3835
3836 TIntermBinary* binaryNode = getAsBinaryNode();
3837 if (binaryNode) {
3838 binaryNode->getLeft()->propagatePrecision(newPrecision);
3839 binaryNode->getRight()->propagatePrecision(newPrecision);
3840
3841 return;
3842 }
3843
3844 TIntermUnary* unaryNode = getAsUnaryNode();
3845 if (unaryNode) {
3846 unaryNode->getOperand()->propagatePrecision(newPrecision);
3847
3848 return;
3849 }
3850
3851 TIntermAggregate* aggregateNode = getAsAggregate();
3852 if (aggregateNode) {
3853 TIntermSequence operands = aggregateNode->getSequence();
3854 for (unsigned int i = 0; i < operands.size(); ++i) {
3855 TIntermTyped* typedNode = operands[i]->getAsTyped();
3856 if (! typedNode)
3857 break;
3858 typedNode->propagatePrecision(newPrecision);
3859 }
3860
3861 return;
3862 }
3863
3864 TIntermSelection* selectionNode = getAsSelectionNode();
3865 if (selectionNode) {
3866 TIntermTyped* typedNode = selectionNode->getTrueBlock()->getAsTyped();
3867 if (typedNode) {
3868 typedNode->propagatePrecision(newPrecision);
3869 typedNode = selectionNode->getFalseBlock()->getAsTyped();
3870 if (typedNode)
3871 typedNode->propagatePrecision(newPrecision);
3872 }
3873
3874 return;
3875 }
3876 }
3877
promoteConstantUnion(TBasicType promoteTo,TIntermConstantUnion * node) const3878 TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
3879 {
3880 const TConstUnionArray& rightUnionArray = node->getConstArray();
3881 int size = node->getType().computeNumComponents();
3882
3883 TConstUnionArray leftUnionArray(size);
3884
3885 for (int i=0; i < size; i++) {
3886
3887 #define PROMOTE(Set, CType, Get) leftUnionArray[i].Set(static_cast<CType>(rightUnionArray[i].Get()))
3888 #define PROMOTE_TO_BOOL(Get) leftUnionArray[i].setBConst(rightUnionArray[i].Get() != 0)
3889
3890 #ifdef GLSLANG_WEB
3891 #define TO_ALL(Get) \
3892 switch (promoteTo) { \
3893 case EbtFloat: PROMOTE(setDConst, double, Get); break; \
3894 case EbtInt: PROMOTE(setIConst, int, Get); break; \
3895 case EbtUint: PROMOTE(setUConst, unsigned int, Get); break; \
3896 case EbtBool: PROMOTE_TO_BOOL(Get); break; \
3897 default: return node; \
3898 }
3899 #else
3900 #define TO_ALL(Get) \
3901 switch (promoteTo) { \
3902 case EbtFloat16: PROMOTE(setDConst, double, Get); break; \
3903 case EbtFloat: PROMOTE(setDConst, double, Get); break; \
3904 case EbtDouble: PROMOTE(setDConst, double, Get); break; \
3905 case EbtInt8: PROMOTE(setI8Const, signed char, Get); break; \
3906 case EbtInt16: PROMOTE(setI16Const, short, Get); break; \
3907 case EbtInt: PROMOTE(setIConst, int, Get); break; \
3908 case EbtInt64: PROMOTE(setI64Const, long long, Get); break; \
3909 case EbtUint8: PROMOTE(setU8Const, unsigned char, Get); break; \
3910 case EbtUint16: PROMOTE(setU16Const, unsigned short, Get); break; \
3911 case EbtUint: PROMOTE(setUConst, unsigned int, Get); break; \
3912 case EbtUint64: PROMOTE(setU64Const, unsigned long long, Get); break; \
3913 case EbtBool: PROMOTE_TO_BOOL(Get); break; \
3914 default: return node; \
3915 }
3916 #endif
3917
3918 switch (node->getType().getBasicType()) {
3919 case EbtFloat: TO_ALL(getDConst); break;
3920 case EbtInt: TO_ALL(getIConst); break;
3921 case EbtUint: TO_ALL(getUConst); break;
3922 case EbtBool: TO_ALL(getBConst); break;
3923 #ifndef GLSLANG_WEB
3924 case EbtFloat16: TO_ALL(getDConst); break;
3925 case EbtDouble: TO_ALL(getDConst); break;
3926 case EbtInt8: TO_ALL(getI8Const); break;
3927 case EbtInt16: TO_ALL(getI16Const); break;
3928 case EbtInt64: TO_ALL(getI64Const); break;
3929 case EbtUint8: TO_ALL(getU8Const); break;
3930 case EbtUint16: TO_ALL(getU16Const); break;
3931 case EbtUint64: TO_ALL(getU64Const); break;
3932 #endif
3933 default: return node;
3934 }
3935 }
3936
3937 const TType& t = node->getType();
3938
3939 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier().storage, t.getVectorSize(), t.getMatrixCols(), t.getMatrixRows()),
3940 node->getLoc());
3941 }
3942
setPragmaTable(const TPragmaTable & pTable)3943 void TIntermAggregate::setPragmaTable(const TPragmaTable& pTable)
3944 {
3945 assert(pragmaTable == nullptr);
3946 pragmaTable = new TPragmaTable;
3947 *pragmaTable = pTable;
3948 }
3949
3950 // If either node is a specialization constant, while the other is
3951 // a constant (or specialization constant), the result is still
3952 // a specialization constant.
specConstantPropagates(const TIntermTyped & node1,const TIntermTyped & node2)3953 bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TIntermTyped& node2)
3954 {
3955 return (node1.getType().getQualifier().isSpecConstant() && node2.getType().getQualifier().isConstant()) ||
3956 (node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant());
3957 }
3958
3959 struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
visitSymbolglslang::TextureUpgradeAndSamplerRemovalTransform3960 void visitSymbol(TIntermSymbol* symbol) override {
3961 if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) {
3962 symbol->getWritableType().getSampler().setCombined(true);
3963 }
3964 }
visitAggregateglslang::TextureUpgradeAndSamplerRemovalTransform3965 bool visitAggregate(TVisit, TIntermAggregate* ag) override {
3966 using namespace std;
3967 TIntermSequence& seq = ag->getSequence();
3968 TQualifierList& qual = ag->getQualifierList();
3969
3970 // qual and seq are indexed using the same indices, so we have to modify both in lock-step
3971 assert(seq.size() == qual.size() || qual.empty());
3972
3973 size_t write = 0;
3974 for (size_t i = 0; i < seq.size(); ++i) {
3975 TIntermSymbol* symbol = seq[i]->getAsSymbolNode();
3976 if (symbol && symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()) {
3977 // remove pure sampler variables
3978 continue;
3979 }
3980
3981 TIntermNode* result = seq[i];
3982
3983 // replace constructors with sampler/textures
3984 TIntermAggregate *constructor = seq[i]->getAsAggregate();
3985 if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
3986 if (!constructor->getSequence().empty())
3987 result = constructor->getSequence()[0];
3988 }
3989
3990 // write new node & qualifier
3991 seq[write] = result;
3992 if (!qual.empty())
3993 qual[write] = qual[i];
3994 write++;
3995 }
3996
3997 seq.resize(write);
3998 if (!qual.empty())
3999 qual.resize(write);
4000
4001 return true;
4002 }
4003 };
4004
performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode * root)4005 void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root)
4006 {
4007 TextureUpgradeAndSamplerRemovalTransform transform;
4008 root->traverse(&transform);
4009 }
4010
getResourceName(TResourceType res)4011 const char* TIntermediate::getResourceName(TResourceType res)
4012 {
4013 switch (res) {
4014 case EResSampler: return "shift-sampler-binding";
4015 case EResTexture: return "shift-texture-binding";
4016 case EResImage: return "shift-image-binding";
4017 case EResUbo: return "shift-UBO-binding";
4018 case EResSsbo: return "shift-ssbo-binding";
4019 case EResUav: return "shift-uav-binding";
4020 default:
4021 assert(0); // internal error: should only be called with valid resource types.
4022 return nullptr;
4023 }
4024 }
4025
4026
4027 } // end namespace glslang
4028