Coverage Report

Created: 2026-04-12 06:30

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