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