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