blob: fad11c6b496354a316650ac7ad827ac26308313b [file] [log] [blame]
John Bauman66b8ab22014-05-06 15:57:45 -04001//
John Baumand4ae8632014-05-06 16:18:33 -04002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
John Bauman66b8ab22014-05-06 15:57:45 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
13#include <algorithm>
14
Nicolas Capenscc863da2015-01-21 15:50:55 -050015#include "localintermediate.h"
16#include "SymbolTable.h"
John Bauman66b8ab22014-05-06 15:57:45 -040017
18bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
19
20static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
21 return left > right ? left : right;
22}
23
24const char* getOperatorString(TOperator op) {
25 switch (op) {
26 case EOpInitialize: return "=";
27 case EOpAssign: return "=";
28 case EOpAddAssign: return "+=";
29 case EOpSubAssign: return "-=";
30 case EOpDivAssign: return "/=";
Alexis Hetu17809052015-05-13 11:28:22 -040031 case EOpIModAssign: return "%=";
32 case EOpBitShiftLeftAssign: return "<<=";
33 case EOpBitShiftRightAssign: return ">>=";
34 case EOpBitwiseAndAssign: return "&=";
35 case EOpBitwiseXorAssign: return "^=";
36 case EOpBitwiseOrAssign: return "|=";
John Bauman66b8ab22014-05-06 15:57:45 -040037
38 // Fall-through.
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -040039 case EOpMulAssign:
John Bauman66b8ab22014-05-06 15:57:45 -040040 case EOpVectorTimesMatrixAssign:
41 case EOpVectorTimesScalarAssign:
42 case EOpMatrixTimesScalarAssign:
43 case EOpMatrixTimesMatrixAssign: return "*=";
44
45 // Fall-through.
46 case EOpIndexDirect:
47 case EOpIndexIndirect: return "[]";
48
49 case EOpIndexDirectStruct: return ".";
50 case EOpVectorSwizzle: return ".";
51 case EOpAdd: return "+";
52 case EOpSub: return "-";
53 case EOpMul: return "*";
54 case EOpDiv: return "/";
55 case EOpMod: UNIMPLEMENTED(); break;
56 case EOpEqual: return "==";
57 case EOpNotEqual: return "!=";
58 case EOpLessThan: return "<";
59 case EOpGreaterThan: return ">";
60 case EOpLessThanEqual: return "<=";
61 case EOpGreaterThanEqual: return ">=";
62
63 // Fall-through.
64 case EOpVectorTimesScalar:
65 case EOpVectorTimesMatrix:
66 case EOpMatrixTimesVector:
67 case EOpMatrixTimesScalar:
68 case EOpMatrixTimesMatrix: return "*";
69
70 case EOpLogicalOr: return "||";
71 case EOpLogicalXor: return "^^";
72 case EOpLogicalAnd: return "&&";
Alexis Hetu17809052015-05-13 11:28:22 -040073 case EOpIMod: return "%";
74 case EOpBitShiftLeft: return "<<";
75 case EOpBitShiftRight: return ">>";
76 case EOpBitwiseAnd: return "&";
77 case EOpBitwiseXor: return "^";
78 case EOpBitwiseOr: return "|";
John Bauman66b8ab22014-05-06 15:57:45 -040079 case EOpNegative: return "-";
80 case EOpVectorLogicalNot: return "not";
81 case EOpLogicalNot: return "!";
Alexis Hetu17809052015-05-13 11:28:22 -040082 case EOpBitwiseNot: return "~";
John Bauman66b8ab22014-05-06 15:57:45 -040083 case EOpPostIncrement: return "++";
84 case EOpPostDecrement: return "--";
85 case EOpPreIncrement: return "++";
86 case EOpPreDecrement: return "--";
87
John Bauman66b8ab22014-05-06 15:57:45 -040088 case EOpRadians: return "radians";
89 case EOpDegrees: return "degrees";
90 case EOpSin: return "sin";
91 case EOpCos: return "cos";
92 case EOpTan: return "tan";
93 case EOpAsin: return "asin";
94 case EOpAcos: return "acos";
95 case EOpAtan: return "atan";
Alexis Hetuaf1970c2015-04-17 14:26:07 -040096 case EOpSinh: return "sinh";
97 case EOpCosh: return "cosh";
98 case EOpTanh: return "tanh";
99 case EOpAsinh: return "asinh";
100 case EOpAcosh: return "acosh";
101 case EOpAtanh: return "atanh";
John Bauman66b8ab22014-05-06 15:57:45 -0400102 case EOpExp: return "exp";
103 case EOpLog: return "log";
104 case EOpExp2: return "exp2";
105 case EOpLog2: return "log2";
106 case EOpSqrt: return "sqrt";
107 case EOpInverseSqrt: return "inversesqrt";
108 case EOpAbs: return "abs";
109 case EOpSign: return "sign";
110 case EOpFloor: return "floor";
Alexis Hetuaf1970c2015-04-17 14:26:07 -0400111 case EOpTrunc: return "trunc";
112 case EOpRound: return "round";
113 case EOpRoundEven: return "roundEven";
John Bauman66b8ab22014-05-06 15:57:45 -0400114 case EOpCeil: return "ceil";
115 case EOpFract: return "fract";
116 case EOpLength: return "length";
117 case EOpNormalize: return "normalize";
118 case EOpDFdx: return "dFdx";
119 case EOpDFdy: return "dFdy";
120 case EOpFwidth: return "fwidth";
121 case EOpAny: return "any";
122 case EOpAll: return "all";
Alexis Hetuaf1970c2015-04-17 14:26:07 -0400123 case EOpIsNan: return "isnan";
124 case EOpIsInf: return "isinf";
John Bauman66b8ab22014-05-06 15:57:45 -0400125
126 default: break;
127 }
128 return "";
129}
130
131////////////////////////////////////////////////////////////////////////////
132//
133// First set of functions are to help build the intermediate representation.
134// These functions are not member functions of the nodes.
135// They are called from parser productions.
136//
137/////////////////////////////////////////////////////////////////////////////
138
139//
140// Add a terminal node for an identifier in an expression.
141//
142// Returns the added node.
143//
144TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
145{
146 TIntermSymbol* node = new TIntermSymbol(id, name, type);
147 node->setLine(line);
148
149 return node;
150}
151
152//
153// Connect two nodes with a new parent that does a binary operation on the nodes.
154//
155// Returns the added node.
156//
John Baumand4ae8632014-05-06 16:18:33 -0400157TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
John Bauman66b8ab22014-05-06 15:57:45 -0400158{
159 switch (op) {
160 case EOpEqual:
161 case EOpNotEqual:
162 if (left->isArray())
163 return 0;
164 break;
165 case EOpLessThan:
166 case EOpGreaterThan:
167 case EOpLessThanEqual:
168 case EOpGreaterThanEqual:
169 if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
170 return 0;
171 }
172 break;
173 case EOpLogicalOr:
174 case EOpLogicalXor:
175 case EOpLogicalAnd:
176 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
177 return 0;
178 }
179 break;
Alexis Hetud061e422015-05-13 16:37:50 -0400180 case EOpBitwiseOr:
181 case EOpBitwiseXor:
182 case EOpBitwiseAnd:
183 if ((left->getBasicType() != EbtInt && left->getBasicType() != EbtUInt) || left->isMatrix() || left->isArray()) {
184 return 0;
185 }
186 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400187 case EOpAdd:
188 case EOpSub:
189 case EOpDiv:
190 case EOpMul:
Alexis Hetud061e422015-05-13 16:37:50 -0400191 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) {
John Bauman66b8ab22014-05-06 15:57:45 -0400192 return 0;
Alexis Hetud061e422015-05-13 16:37:50 -0400193 }
194 break;
195 case EOpIMod:
196 // Note that this is only for the % operator, not for mod()
197 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) {
198 return 0;
199 }
200 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400201 default: break;
202 }
203
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400204 if (left->getBasicType() != right->getBasicType())
205 {
206 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400207 }
208
209 //
210 // Need a new node holding things together then. Make
211 // one and promote it to the right type.
212 //
213 TIntermBinary* node = new TIntermBinary(op);
214 if (line == 0)
215 line = right->getLine();
216 node->setLine(line);
217
218 node->setLeft(left);
219 node->setRight(right);
220 if (!node->promote(infoSink))
221 return 0;
222
223 //
224 // See if we can fold constants.
225 //
John Bauman66b8ab22014-05-06 15:57:45 -0400226 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
227 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
228 if (leftTempConstant && rightTempConstant) {
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400229 TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400230
231 if (typedReturnNode)
232 return typedReturnNode;
233 }
234
235 return node;
236}
237
238//
239// Connect two nodes through an assignment.
240//
241// Returns the added node.
242//
243TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
244{
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400245 if (left->getType().getStruct() || right->getType().getStruct())
246 {
247 if (left->getType() != right->getType())
248 {
249 return 0;
250 }
251 }
252
John Bauman66b8ab22014-05-06 15:57:45 -0400253 TIntermBinary* node = new TIntermBinary(op);
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400254 if(line == 0)
John Bauman66b8ab22014-05-06 15:57:45 -0400255 line = left->getLine();
256 node->setLine(line);
257
John Bauman66b8ab22014-05-06 15:57:45 -0400258 node->setLeft(left);
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400259 node->setRight(right);
John Bauman66b8ab22014-05-06 15:57:45 -0400260 if (! node->promote(infoSink))
261 return 0;
262
263 return node;
264}
265
266//
267// Connect two nodes through an index operator, where the left node is the base
268// of an array or struct, and the right node is a direct or indirect offset.
269//
270// Returns the added node.
271// The caller should set the type of the returned node.
272//
273TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
274{
275 TIntermBinary* node = new TIntermBinary(op);
276 if (line == 0)
277 line = index->getLine();
278 node->setLine(line);
279 node->setLeft(base);
280 node->setRight(index);
281
282 // caller should set the type
283
284 return node;
285}
286
287//
288// Add one node as the parent of another that it operates on.
289//
290// Returns the added node.
291//
John Baumand4ae8632014-05-06 16:18:33 -0400292TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line)
John Bauman66b8ab22014-05-06 15:57:45 -0400293{
294 TIntermUnary* node;
295 TIntermTyped* child = childNode->getAsTyped();
296
297 if (child == 0) {
298 infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
299 return 0;
300 }
301
302 switch (op) {
Alexis Hetud061e422015-05-13 16:37:50 -0400303 case EOpBitwiseNot:
304 if ((child->getType().getBasicType() != EbtInt && child->getType().getBasicType() != EbtUInt) || child->getType().isMatrix() || child->getType().isArray()) {
305 return 0;
306 }
307 break;
308
John Bauman66b8ab22014-05-06 15:57:45 -0400309 case EOpLogicalNot:
310 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
311 return 0;
312 }
313 break;
314
315 case EOpPostIncrement:
316 case EOpPreIncrement:
317 case EOpPostDecrement:
318 case EOpPreDecrement:
319 case EOpNegative:
320 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
321 return 0;
322 default: break;
323 }
324
John Bauman66b8ab22014-05-06 15:57:45 -0400325 TIntermConstantUnion *childTempConstant = 0;
326 if (child->getAsConstantUnion())
327 childTempConstant = child->getAsConstantUnion();
328
329 //
330 // Make a new node for the operator.
331 //
332 node = new TIntermUnary(op);
333 if (line == 0)
334 line = child->getLine();
335 node->setLine(line);
336 node->setOperand(child);
337
338 if (! node->promote(infoSink))
339 return 0;
340
341 if (childTempConstant) {
342 TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
343
344 if (newChild)
345 return newChild;
346 }
347
348 return node;
349}
350
351//
352// This is the safe way to change the operator on an aggregate, as it
353// does lots of error checking and fixing. Especially for establishing
354// a function call's operation on it's set of parameters. Sequences
355// of instructions are also aggregates, but they just direnctly set
356// their operator to EOpSequence.
357//
358// Returns an aggregate node, which could be the one passed in if
359// it was already an aggregate but no operator was set.
360//
361TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
362{
363 TIntermAggregate* aggNode;
364
365 //
366 // Make sure we have an aggregate. If not turn it into one.
367 //
368 if (node) {
369 aggNode = node->getAsAggregate();
370 if (aggNode == 0 || aggNode->getOp() != EOpNull) {
371 //
372 // Make an aggregate containing this node.
373 //
374 aggNode = new TIntermAggregate();
375 aggNode->getSequence().push_back(node);
376 if (line == 0)
377 line = node->getLine();
378 }
379 } else
380 aggNode = new TIntermAggregate();
381
382 //
383 // Set the operator.
384 //
385 aggNode->setOp(op);
386 if (line != 0)
387 aggNode->setLine(line);
388
389 return aggNode;
390}
391
392//
John Bauman66b8ab22014-05-06 15:57:45 -0400393// Safe way to combine two nodes into an aggregate. Works with null pointers,
394// a node that's not a aggregate yet, etc.
395//
396// Returns the resulting aggregate, unless 0 was passed in for
397// both existing nodes.
398//
399TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
400{
401 if (left == 0 && right == 0)
402 return 0;
403
404 TIntermAggregate* aggNode = 0;
405 if (left)
406 aggNode = left->getAsAggregate();
407 if (!aggNode || aggNode->getOp() != EOpNull) {
408 aggNode = new TIntermAggregate;
409 if (left)
410 aggNode->getSequence().push_back(left);
411 }
412
413 if (right)
414 aggNode->getSequence().push_back(right);
415
416 if (line != 0)
417 aggNode->setLine(line);
418
419 return aggNode;
420}
421
422//
423// Turn an existing node into an aggregate.
424//
425// Returns an aggregate, unless 0 was passed in for the existing node.
426//
427TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
428{
429 if (node == 0)
430 return 0;
431
432 TIntermAggregate* aggNode = new TIntermAggregate;
433 aggNode->getSequence().push_back(node);
434
435 if (line != 0)
436 aggNode->setLine(line);
437 else
438 aggNode->setLine(node->getLine());
439
440 return aggNode;
441}
442
443//
444// For "if" test nodes. There are three children; a condition,
445// a true path, and a false path. The two paths are in the
446// nodePair.
447//
448// Returns the selection node created.
449//
450TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
451{
452 //
453 // For compile time constant selections, prune the code and
454 // test now.
455 //
456
457 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
Nicolas Capens198529d2015-02-10 13:54:19 -0500458 if (cond->getAsConstantUnion()->getBConst(0) == true)
John Bauman66b8ab22014-05-06 15:57:45 -0400459 return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
460 else
461 return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
462 }
463
464 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
465 node->setLine(line);
466
467 return node;
468}
469
470
471TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
472{
Nicolas Capens31ad2aa2015-02-26 13:14:27 -0500473 if (left->getType().getQualifier() == EvqConstExpr && right->getType().getQualifier() == EvqConstExpr) {
John Bauman66b8ab22014-05-06 15:57:45 -0400474 return right;
475 } else {
476 TIntermTyped *commaAggregate = growAggregate(left, right, line);
477 commaAggregate->getAsAggregate()->setOp(EOpComma);
478 commaAggregate->setType(right->getType());
479 commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
480 return commaAggregate;
481 }
482}
483
484//
485// For "?:" test nodes. There are three children; a condition,
486// a true path, and a false path. The two paths are specified
487// as separate parameters.
488//
489// Returns the selection node created, or 0 if one could not be.
490//
491TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
492{
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400493 if (trueBlock->getType() != falseBlock->getType())
494 {
495 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400496 }
497
498 //
499 // See if all the operands are constant, then fold it otherwise not.
500 //
501
502 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
Nicolas Capens198529d2015-02-10 13:54:19 -0500503 if (cond->getAsConstantUnion()->getBConst(0))
John Bauman66b8ab22014-05-06 15:57:45 -0400504 return trueBlock;
505 else
506 return falseBlock;
507 }
508
509 //
510 // Make a selection node.
511 //
512 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
513 node->getTypePointer()->setQualifier(EvqTemporary);
514 node->setLine(line);
515
516 return node;
517}
518
519//
520// Constant terminal nodes. Has a union that contains bool, float or int constants
521//
522// Returns the constant union node created.
523//
524
525TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line)
526{
527 TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
528 node->setLine(line);
529
530 return node;
531}
532
533TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
534{
535
536 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
537
538 node->setLine(line);
539 TIntermConstantUnion* constIntNode;
540 TIntermSequence &sequenceVector = node->getSequence();
541 ConstantUnion* unionArray;
542
543 for (int i = 0; i < fields.num; i++) {
544 unionArray = new ConstantUnion[1];
545 unionArray->setIConst(fields.offsets[i]);
Nicolas Capens31ad2aa2015-02-26 13:14:27 -0500546 constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), line);
John Bauman66b8ab22014-05-06 15:57:45 -0400547 sequenceVector.push_back(constIntNode);
548 }
549
550 return node;
551}
552
553//
554// Create loop nodes.
555//
556TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line)
557{
558 TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
559 node->setLine(line);
560
561 return node;
562}
563
564//
565// Add branches.
566//
567TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
568{
569 return addBranch(branchOp, 0, line);
570}
571
572TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
573{
574 TIntermBranch* node = new TIntermBranch(branchOp, expression);
575 node->setLine(line);
576
577 return node;
578}
579
580//
581// This is to be executed once the final root is put on top by the parsing
582// process.
583//
584bool TIntermediate::postProcess(TIntermNode* root)
585{
586 if (root == 0)
587 return true;
588
589 //
590 // First, finish off the top level sequence, if any
591 //
592 TIntermAggregate* aggRoot = root->getAsAggregate();
593 if (aggRoot && aggRoot->getOp() == EOpNull)
594 aggRoot->setOp(EOpSequence);
595
596 return true;
597}
598
John Bauman66b8ab22014-05-06 15:57:45 -0400599////////////////////////////////////////////////////////////////
600//
601// Member functions of the nodes used for building the tree.
602//
603////////////////////////////////////////////////////////////////
604
605//
606// Say whether or not an operation node changes the value of a variable.
607//
608// Returns true if state is modified.
609//
610bool TIntermOperator::modifiesState() const
611{
612 switch (op) {
613 case EOpPostIncrement:
614 case EOpPostDecrement:
615 case EOpPreIncrement:
616 case EOpPreDecrement:
617 case EOpAssign:
618 case EOpAddAssign:
619 case EOpSubAssign:
620 case EOpMulAssign:
621 case EOpVectorTimesMatrixAssign:
622 case EOpVectorTimesScalarAssign:
623 case EOpMatrixTimesScalarAssign:
624 case EOpMatrixTimesMatrixAssign:
625 case EOpDivAssign:
Alexis Hetu17809052015-05-13 11:28:22 -0400626 case EOpIModAssign:
627 case EOpBitShiftLeftAssign:
628 case EOpBitShiftRightAssign:
629 case EOpBitwiseAndAssign:
630 case EOpBitwiseXorAssign:
631 case EOpBitwiseOrAssign:
John Bauman66b8ab22014-05-06 15:57:45 -0400632 return true;
633 default:
634 return false;
635 }
636}
637
638//
639// returns true if the operator is for one of the constructors
640//
641bool TIntermOperator::isConstructor() const
642{
643 switch (op) {
644 case EOpConstructVec2:
645 case EOpConstructVec3:
646 case EOpConstructVec4:
647 case EOpConstructMat2:
648 case EOpConstructMat3:
649 case EOpConstructMat4:
650 case EOpConstructFloat:
651 case EOpConstructIVec2:
652 case EOpConstructIVec3:
653 case EOpConstructIVec4:
654 case EOpConstructInt:
Nicolas Capense4b1b1d2015-02-17 17:26:01 -0500655 case EOpConstructUVec2:
656 case EOpConstructUVec3:
657 case EOpConstructUVec4:
Nicolas Capens3c20f802015-02-17 17:17:20 -0500658 case EOpConstructUInt:
John Bauman66b8ab22014-05-06 15:57:45 -0400659 case EOpConstructBVec2:
660 case EOpConstructBVec3:
661 case EOpConstructBVec4:
662 case EOpConstructBool:
663 case EOpConstructStruct:
664 return true;
665 default:
666 return false;
667 }
668}
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400669
John Bauman66b8ab22014-05-06 15:57:45 -0400670//
671// Make sure the type of a unary operator is appropriate for its
672// combination of operation and operand type.
673//
674// Returns false in nothing makes sense.
675//
676bool TIntermUnary::promote(TInfoSink&)
677{
678 switch (op) {
679 case EOpLogicalNot:
680 if (operand->getBasicType() != EbtBool)
681 return false;
682 break;
Alexis Hetud061e422015-05-13 16:37:50 -0400683 case EOpBitwiseNot:
684 if(operand->getBasicType() != EbtInt && operand->getBasicType() != EbtUInt)
685 return false;
686 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400687 case EOpNegative:
688 case EOpPostIncrement:
689 case EOpPostDecrement:
690 case EOpPreIncrement:
691 case EOpPreDecrement:
692 if (operand->getBasicType() == EbtBool)
693 return false;
694 break;
695
696 // operators for built-ins are already type checked against their prototype
697 case EOpAny:
698 case EOpAll:
699 case EOpVectorLogicalNot:
700 return true;
701
702 default:
703 if (operand->getBasicType() != EbtFloat)
704 return false;
705 }
706
707 setType(operand->getType());
708
709 // Unary operations results in temporary variables unless const.
Nicolas Capens31ad2aa2015-02-26 13:14:27 -0500710 if (operand->getQualifier() != EvqConstExpr) {
John Bauman66b8ab22014-05-06 15:57:45 -0400711 getTypePointer()->setQualifier(EvqTemporary);
712 }
713
714 return true;
715}
716
717//
718// Establishes the type of the resultant operation, as well as
719// makes the operator the correct one for the operands.
720//
721// Returns false if operator can't work on operands.
722//
723bool TIntermBinary::promote(TInfoSink& infoSink)
724{
725 // This function only handles scalars, vectors, and matrices.
726 if (left->isArray() || right->isArray()) {
727 infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
728 return false;
729 }
730
731 // GLSL ES 2.0 does not support implicit type casting.
732 // So the basic type should always match.
733 if (left->getBasicType() != right->getBasicType())
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400734 {
John Bauman66b8ab22014-05-06 15:57:45 -0400735 return false;
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400736 }
John Bauman66b8ab22014-05-06 15:57:45 -0400737
738 //
739 // Base assumption: just make the type the same as the left
740 // operand. Then only deviations from this need be coded.
741 //
742 setType(left->getType());
743
744 // The result gets promoted to the highest precision.
745 TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
746 getTypePointer()->setPrecision(higherPrecision);
747
748 // Binary operations results in temporary variables unless both
749 // operands are const.
Nicolas Capens31ad2aa2015-02-26 13:14:27 -0500750 if (left->getQualifier() != EvqConstExpr || right->getQualifier() != EvqConstExpr) {
John Bauman66b8ab22014-05-06 15:57:45 -0400751 getTypePointer()->setQualifier(EvqTemporary);
752 }
753
Alexis Hetud061e422015-05-13 16:37:50 -0400754 int primarySize = std::max(left->getNominalSize(), right->getNominalSize());
755 int secondarySize = std::max(left->getSecondarySize(), right->getSecondarySize());
John Bauman66b8ab22014-05-06 15:57:45 -0400756
757 //
758 // All scalars. Code after this test assumes this case is removed!
759 //
Alexis Hetud061e422015-05-13 16:37:50 -0400760 if (primarySize == 1) {
John Bauman66b8ab22014-05-06 15:57:45 -0400761 switch (op) {
762 //
763 // Promote to conditional
764 //
765 case EOpEqual:
766 case EOpNotEqual:
767 case EOpLessThan:
768 case EOpGreaterThan:
769 case EOpLessThanEqual:
770 case EOpGreaterThanEqual:
771 setType(TType(EbtBool, EbpUndefined));
772 break;
773
774 //
775 // And and Or operate on conditionals
776 //
777 case EOpLogicalAnd:
778 case EOpLogicalOr:
Alexis Hetud061e422015-05-13 16:37:50 -0400779 case EOpLogicalXor:
John Bauman66b8ab22014-05-06 15:57:45 -0400780 // Both operands must be of type bool.
781 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
782 return false;
783 setType(TType(EbtBool, EbpUndefined));
784 break;
785
786 default:
787 break;
788 }
789 return true;
790 }
791
792 // If we reach here, at least one of the operands is vector or matrix.
793 // The other operand could be a scalar, vector, or matrix.
794 // Are the sizes compatible?
795 //
796 if (left->getNominalSize() != right->getNominalSize()) {
797 // If the nominal size of operands do not match:
798 // One of them must be scalar.
799 if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
800 return false;
801 // Operator cannot be of type pure assignment.
802 if (op == EOpAssign || op == EOpInitialize)
803 return false;
804 }
805
Alexis Hetub14178b2015-04-13 13:23:20 -0400806 if (left->getSecondarySize() != right->getSecondarySize()) {
807 // Operator cannot be of type pure assignment.
808 if (op == EOpAssign || op == EOpInitialize)
809 return false;
810 }
811
John Bauman66b8ab22014-05-06 15:57:45 -0400812 //
813 // Can these two operands be combined?
814 //
815 TBasicType basicType = left->getBasicType();
816 switch (op) {
817 case EOpMul:
818 if (!left->isMatrix() && right->isMatrix()) {
819 if (left->isVector())
820 op = EOpVectorTimesMatrix;
821 else {
822 op = EOpMatrixTimesScalar;
Alexis Hetud061e422015-05-13 16:37:50 -0400823 setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, secondarySize));
John Bauman66b8ab22014-05-06 15:57:45 -0400824 }
825 } else if (left->isMatrix() && !right->isMatrix()) {
826 if (right->isVector()) {
827 op = EOpMatrixTimesVector;
Alexis Hetud061e422015-05-13 16:37:50 -0400828 setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
John Bauman66b8ab22014-05-06 15:57:45 -0400829 } else {
830 op = EOpMatrixTimesScalar;
831 }
832 } else if (left->isMatrix() && right->isMatrix()) {
833 op = EOpMatrixTimesMatrix;
834 } else if (!left->isMatrix() && !right->isMatrix()) {
835 if (left->isVector() && right->isVector()) {
836 // leave as component product
837 } else if (left->isVector() || right->isVector()) {
838 op = EOpVectorTimesScalar;
Alexis Hetud061e422015-05-13 16:37:50 -0400839 setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
John Bauman66b8ab22014-05-06 15:57:45 -0400840 }
841 } else {
842 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
843 return false;
844 }
845 break;
846 case EOpMulAssign:
847 if (!left->isMatrix() && right->isMatrix()) {
848 if (left->isVector())
849 op = EOpVectorTimesMatrixAssign;
850 else {
851 return false;
852 }
853 } else if (left->isMatrix() && !right->isMatrix()) {
854 if (right->isVector()) {
855 return false;
856 } else {
857 op = EOpMatrixTimesScalarAssign;
858 }
859 } else if (left->isMatrix() && right->isMatrix()) {
860 op = EOpMatrixTimesMatrixAssign;
861 } else if (!left->isMatrix() && !right->isMatrix()) {
862 if (left->isVector() && right->isVector()) {
863 // leave as component product
864 } else if (left->isVector() || right->isVector()) {
865 if (! left->isVector())
866 return false;
867 op = EOpVectorTimesScalarAssign;
Alexis Hetud061e422015-05-13 16:37:50 -0400868 setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, 1));
John Bauman66b8ab22014-05-06 15:57:45 -0400869 }
870 } else {
871 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
872 return false;
873 }
874 break;
875
876 case EOpAssign:
877 case EOpInitialize:
878 case EOpAdd:
879 case EOpSub:
880 case EOpDiv:
Alexis Hetud061e422015-05-13 16:37:50 -0400881 case EOpIMod:
882 case EOpBitShiftLeft:
883 case EOpBitShiftRight:
884 case EOpBitwiseAnd:
885 case EOpBitwiseXor:
886 case EOpBitwiseOr:
John Bauman66b8ab22014-05-06 15:57:45 -0400887 case EOpAddAssign:
888 case EOpSubAssign:
889 case EOpDivAssign:
Alexis Hetu17809052015-05-13 11:28:22 -0400890 case EOpIModAssign:
891 case EOpBitShiftLeftAssign:
892 case EOpBitShiftRightAssign:
893 case EOpBitwiseAndAssign:
894 case EOpBitwiseXorAssign:
895 case EOpBitwiseOrAssign:
John Bauman66b8ab22014-05-06 15:57:45 -0400896 if ((left->isMatrix() && right->isVector()) ||
897 (left->isVector() && right->isMatrix()))
898 return false;
Alexis Hetud061e422015-05-13 16:37:50 -0400899
900 // Are the sizes compatible?
901 if(left->getNominalSize() != right->getNominalSize() ||
902 left->getSecondarySize() != right->getSecondarySize())
903 {
904 // If the nominal sizes of operands do not match:
905 // One of them must be a scalar.
906 if(!left->isScalar() && !right->isScalar())
907 return false;
908
909 // In the case of compound assignment other than multiply-assign,
910 // the right side needs to be a scalar. Otherwise a vector/matrix
911 // would be assigned to a scalar. A scalar can't be shifted by a
912 // vector either.
913 if(!right->isScalar() && (modifiesState() || op == EOpBitShiftLeft || op == EOpBitShiftRight))
914 return false;
915 }
916
917 {
918 setType(TType(basicType, higherPrecision, EvqTemporary,
919 static_cast<unsigned char>(primarySize), static_cast<unsigned char>(secondarySize)));
920 if(left->isArray())
921 {
922 ASSERT(left->getArraySize() == right->getArraySize());
923 type.setArraySize(left->getArraySize());
924 }
925 }
926
927 setType(TType(basicType, higherPrecision, EvqTemporary, primarySize, secondarySize));
John Bauman66b8ab22014-05-06 15:57:45 -0400928 break;
929
930 case EOpEqual:
931 case EOpNotEqual:
932 case EOpLessThan:
933 case EOpGreaterThan:
934 case EOpLessThanEqual:
935 case EOpGreaterThanEqual:
936 if ((left->isMatrix() && right->isVector()) ||
937 (left->isVector() && right->isMatrix()))
938 return false;
939 setType(TType(EbtBool, EbpUndefined));
940 break;
941
942 default:
943 return false;
944 }
945
946 return true;
947}
948
949bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
950{
951 const TTypeList* fields = leftNodeType.getStruct();
952
953 size_t structSize = fields->size();
954 int index = 0;
955
956 for (size_t j = 0; j < structSize; j++) {
957 int size = (*fields)[j].type->getObjectSize();
958 for (int i = 0; i < size; i++) {
959 if ((*fields)[j].type->getBasicType() == EbtStruct) {
960 if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
961 return false;
962 } else {
963 if (leftUnionArray[index] != rightUnionArray[index])
964 return false;
965 index++;
966 }
967
968 }
969 }
970 return true;
971}
972
973bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
974{
975 if (leftNodeType.isArray()) {
976 TType typeWithoutArrayness = leftNodeType;
977 typeWithoutArrayness.clearArrayness();
978
979 int arraySize = leftNodeType.getArraySize();
980
981 for (int i = 0; i < arraySize; ++i) {
982 int offset = typeWithoutArrayness.getObjectSize() * i;
983 if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
984 return false;
985 }
986 } else
987 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
988
989 return true;
990}
991
992//
993// The fold functions see if an operation on a constant can be done in place,
994// without generating run-time code.
995//
996// Returns the node to keep using, which may or may not be the node passed in.
997//
998
999TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1000{
1001 ConstantUnion *unionArray = getUnionArrayPointer();
1002 int objectSize = getType().getObjectSize();
1003
1004 if (constantNode) { // binary operations
1005 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1006 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1007 TType returnType = getType();
1008
1009 // for a case like float f = 1.2 + vec4(2,3,4,5);
1010 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1011 rightUnionArray = new ConstantUnion[objectSize];
1012 for (int i = 0; i < objectSize; ++i)
1013 rightUnionArray[i] = *node->getUnionArrayPointer();
1014 returnType = getType();
1015 } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1016 // for a case like float f = vec4(2,3,4,5) + 1.2;
1017 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1018 for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
1019 unionArray[i] = *getUnionArrayPointer();
1020 returnType = node->getType();
1021 objectSize = constantNode->getType().getObjectSize();
1022 }
1023
1024 ConstantUnion* tempConstArray = 0;
1025 TIntermConstantUnion *tempNode;
1026
1027 bool boolNodeFlag = false;
1028 switch(op) {
1029 case EOpAdd:
1030 tempConstArray = new ConstantUnion[objectSize];
1031 {// support MSVC++6.0
1032 for (int i = 0; i < objectSize; i++)
1033 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1034 }
1035 break;
1036 case EOpSub:
1037 tempConstArray = new ConstantUnion[objectSize];
1038 {// support MSVC++6.0
1039 for (int i = 0; i < objectSize; i++)
1040 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1041 }
1042 break;
1043
1044 case EOpMul:
1045 case EOpVectorTimesScalar:
1046 case EOpMatrixTimesScalar:
1047 tempConstArray = new ConstantUnion[objectSize];
1048 {// support MSVC++6.0
1049 for (int i = 0; i < objectSize; i++)
1050 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1051 }
1052 break;
1053 case EOpMatrixTimesMatrix:
1054 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1055 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1056 return 0;
1057 }
1058 {// support MSVC++6.0
1059 int size = getNominalSize();
1060 tempConstArray = new ConstantUnion[size*size];
1061 for (int row = 0; row < size; row++) {
1062 for (int column = 0; column < size; column++) {
1063 tempConstArray[size * column + row].setFConst(0.0f);
1064 for (int i = 0; i < size; i++) {
1065 tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1066 }
1067 }
1068 }
1069 }
1070 break;
1071 case EOpDiv:
Alexis Hetud061e422015-05-13 16:37:50 -04001072 case EOpIMod:
John Bauman66b8ab22014-05-06 15:57:45 -04001073 tempConstArray = new ConstantUnion[objectSize];
1074 {// support MSVC++6.0
1075 for (int i = 0; i < objectSize; i++) {
1076 switch (getType().getBasicType()) {
Alexis Hetud061e422015-05-13 16:37:50 -04001077 case EbtFloat:
1078 if (rightUnionArray[i] == 0.0f) {
1079 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1080 tempConstArray[i].setFConst(FLT_MAX);
1081 } else {
1082 ASSERT(op == EOpDiv);
1083 tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1084 }
1085 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001086
Alexis Hetud061e422015-05-13 16:37:50 -04001087 case EbtInt:
1088 if (rightUnionArray[i] == 0) {
1089 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1090 tempConstArray[i].setIConst(INT_MAX);
1091 } else {
1092 if(op == EOpDiv) {
1093 tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1094 } else {
1095 ASSERT(op == EOpIMod);
1096 tempConstArray[i].setIConst(unionArray[i].getIConst() % rightUnionArray[i].getIConst());
1097 }
1098 }
1099 break;
1100 case EbtUInt:
1101 if (rightUnionArray[i] == 0) {
1102 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1103 tempConstArray[i].setUConst(UINT_MAX);
1104 } else {
1105 if(op == EOpDiv) {
1106 tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
1107 } else {
1108 ASSERT(op == EOpIMod);
1109 tempConstArray[i].setUConst(unionArray[i].getUConst() % rightUnionArray[i].getUConst());
1110 }
1111 }
1112 break;
1113 default:
1114 infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
1115 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -04001116 }
1117 }
1118 }
1119 break;
1120
1121 case EOpMatrixTimesVector:
1122 if (node->getBasicType() != EbtFloat) {
1123 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
1124 return 0;
1125 }
1126 tempConstArray = new ConstantUnion[getNominalSize()];
1127
1128 {// support MSVC++6.0
1129 for (int size = getNominalSize(), i = 0; i < size; i++) {
1130 tempConstArray[i].setFConst(0.0f);
1131 for (int j = 0; j < size; j++) {
1132 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1133 }
1134 }
1135 }
1136
1137 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1138 tempNode->setLine(getLine());
1139
1140 return tempNode;
1141
1142 case EOpVectorTimesMatrix:
1143 if (getType().getBasicType() != EbtFloat) {
1144 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
1145 return 0;
1146 }
1147
1148 tempConstArray = new ConstantUnion[getNominalSize()];
1149 {// support MSVC++6.0
1150 for (int size = getNominalSize(), i = 0; i < size; i++) {
1151 tempConstArray[i].setFConst(0.0f);
1152 for (int j = 0; j < size; j++) {
1153 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1154 }
1155 }
1156 }
1157 break;
1158
1159 case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1160 tempConstArray = new ConstantUnion[objectSize];
1161 {// support MSVC++6.0
1162 for (int i = 0; i < objectSize; i++)
1163 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1164 }
1165 break;
1166
1167 case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1168 tempConstArray = new ConstantUnion[objectSize];
1169 {// support MSVC++6.0
1170 for (int i = 0; i < objectSize; i++)
1171 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1172 }
1173 break;
1174
1175 case EOpLogicalXor:
1176 tempConstArray = new ConstantUnion[objectSize];
1177 {// support MSVC++6.0
1178 for (int i = 0; i < objectSize; i++)
1179 switch (getType().getBasicType()) {
Alexis Hetud061e422015-05-13 16:37:50 -04001180 case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1181 default: assert(false && "Default missing");
John Bauman66b8ab22014-05-06 15:57:45 -04001182 }
1183 }
1184 break;
1185
Alexis Hetud061e422015-05-13 16:37:50 -04001186 case EOpBitwiseAnd:
1187 tempConstArray = new ConstantUnion[objectSize];
1188 for(int i = 0; i < objectSize; i++)
1189 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1190 break;
1191 case EOpBitwiseXor:
1192 tempConstArray = new ConstantUnion[objectSize];
1193 for(int i = 0; i < objectSize; i++)
1194 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1195 break;
1196 case EOpBitwiseOr:
1197 tempConstArray = new ConstantUnion[objectSize];
1198 for(int i = 0; i < objectSize; i++)
1199 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1200 break;
1201 case EOpBitShiftLeft:
1202 tempConstArray = new ConstantUnion[objectSize];
1203 for(int i = 0; i < objectSize; i++)
1204 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1205 break;
1206 case EOpBitShiftRight:
1207 tempConstArray = new ConstantUnion[objectSize];
1208 for(int i = 0; i < objectSize; i++)
1209 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1210 break;
1211
John Bauman66b8ab22014-05-06 15:57:45 -04001212 case EOpLessThan:
1213 assert(objectSize == 1);
1214 tempConstArray = new ConstantUnion[1];
1215 tempConstArray->setBConst(*unionArray < *rightUnionArray);
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001216 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr);
John Bauman66b8ab22014-05-06 15:57:45 -04001217 break;
1218 case EOpGreaterThan:
1219 assert(objectSize == 1);
1220 tempConstArray = new ConstantUnion[1];
1221 tempConstArray->setBConst(*unionArray > *rightUnionArray);
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001222 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr);
John Bauman66b8ab22014-05-06 15:57:45 -04001223 break;
1224 case EOpLessThanEqual:
1225 {
1226 assert(objectSize == 1);
1227 ConstantUnion constant;
1228 constant.setBConst(*unionArray > *rightUnionArray);
1229 tempConstArray = new ConstantUnion[1];
1230 tempConstArray->setBConst(!constant.getBConst());
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001231 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr);
John Bauman66b8ab22014-05-06 15:57:45 -04001232 break;
1233 }
1234 case EOpGreaterThanEqual:
1235 {
1236 assert(objectSize == 1);
1237 ConstantUnion constant;
1238 constant.setBConst(*unionArray < *rightUnionArray);
1239 tempConstArray = new ConstantUnion[1];
1240 tempConstArray->setBConst(!constant.getBConst());
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001241 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr);
John Bauman66b8ab22014-05-06 15:57:45 -04001242 break;
1243 }
1244
1245 case EOpEqual:
1246 if (getType().getBasicType() == EbtStruct) {
1247 if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1248 boolNodeFlag = true;
1249 } else {
1250 for (int i = 0; i < objectSize; i++) {
1251 if (unionArray[i] != rightUnionArray[i]) {
1252 boolNodeFlag = true;
1253 break; // break out of for loop
1254 }
1255 }
1256 }
1257
1258 tempConstArray = new ConstantUnion[1];
1259 if (!boolNodeFlag) {
1260 tempConstArray->setBConst(true);
1261 }
1262 else {
1263 tempConstArray->setBConst(false);
1264 }
1265
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001266 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr));
John Bauman66b8ab22014-05-06 15:57:45 -04001267 tempNode->setLine(getLine());
1268
1269 return tempNode;
1270
1271 case EOpNotEqual:
1272 if (getType().getBasicType() == EbtStruct) {
1273 if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1274 boolNodeFlag = true;
1275 } else {
1276 for (int i = 0; i < objectSize; i++) {
1277 if (unionArray[i] == rightUnionArray[i]) {
1278 boolNodeFlag = true;
1279 break; // break out of for loop
1280 }
1281 }
1282 }
1283
1284 tempConstArray = new ConstantUnion[1];
1285 if (!boolNodeFlag) {
1286 tempConstArray->setBConst(true);
1287 }
1288 else {
1289 tempConstArray->setBConst(false);
1290 }
1291
Nicolas Capens31ad2aa2015-02-26 13:14:27 -05001292 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr));
John Bauman66b8ab22014-05-06 15:57:45 -04001293 tempNode->setLine(getLine());
1294
1295 return tempNode;
1296
1297 default:
1298 infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
1299 return 0;
1300 }
1301 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1302 tempNode->setLine(getLine());
1303
1304 return tempNode;
1305 } else {
1306 //
1307 // Do unary operations
1308 //
1309 TIntermConstantUnion *newNode = 0;
1310 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1311 for (int i = 0; i < objectSize; i++) {
1312 switch(op) {
1313 case EOpNegative:
1314 switch (getType().getBasicType()) {
1315 case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1316 case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1317 default:
1318 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1319 return 0;
1320 }
1321 break;
1322 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1323 switch (getType().getBasicType()) {
1324 case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1325 default:
1326 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1327 return 0;
1328 }
1329 break;
Alexis Hetud061e422015-05-13 16:37:50 -04001330 case EOpBitwiseNot:
1331 switch(getType().getBasicType()) {
1332 case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break;
1333 case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break;
1334 default:
1335 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1336 return 0;
1337 }
1338 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001339 default:
1340 return 0;
1341 }
1342 }
1343 newNode = new TIntermConstantUnion(tempConstArray, getType());
1344 newNode->setLine(getLine());
1345 return newNode;
1346 }
1347}
1348
1349TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1350{
John Bauman66b8ab22014-05-06 15:57:45 -04001351 int size = node->getType().getObjectSize();
1352
1353 ConstantUnion *leftUnionArray = new ConstantUnion[size];
1354
1355 for (int i=0; i < size; i++) {
1356
1357 switch (promoteTo) {
1358 case EbtFloat:
1359 switch (node->getType().getBasicType()) {
1360 case EbtInt:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001361 leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001362 break;
Nicolas Capens3c20f802015-02-17 17:17:20 -05001363 case EbtUInt:
1364 leftUnionArray[i].setFConst(static_cast<float>(node->getUConst(i)));
1365 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001366 case EbtBool:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001367 leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001368 break;
1369 case EbtFloat:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001370 leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001371 break;
1372 default:
1373 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1374 return 0;
1375 }
1376 break;
1377 case EbtInt:
1378 switch (node->getType().getBasicType()) {
1379 case EbtInt:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001380 leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001381 break;
Nicolas Capens3c20f802015-02-17 17:17:20 -05001382 case EbtUInt:
1383 leftUnionArray[i].setIConst(static_cast<int>(node->getUConst(i)));
1384 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001385 case EbtBool:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001386 leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001387 break;
1388 case EbtFloat:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001389 leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
John Bauman66b8ab22014-05-06 15:57:45 -04001390 break;
1391 default:
1392 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1393 return 0;
1394 }
1395 break;
Nicolas Capens3c20f802015-02-17 17:17:20 -05001396 case EbtUInt:
1397 switch (node->getType().getBasicType()) {
1398 case EbtInt:
1399 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getIConst(i)));
1400 break;
1401 case EbtUInt:
1402 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getUConst(i)));
1403 break;
1404 case EbtBool:
1405 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getBConst(i)));
1406 break;
1407 case EbtFloat:
1408 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getFConst(i)));
1409 break;
1410 default:
1411 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1412 return 0;
1413 }
1414 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001415 case EbtBool:
1416 switch (node->getType().getBasicType()) {
1417 case EbtInt:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001418 leftUnionArray[i].setBConst(node->getIConst(i) != 0);
John Bauman66b8ab22014-05-06 15:57:45 -04001419 break;
Nicolas Capens3c20f802015-02-17 17:17:20 -05001420 case EbtUInt:
1421 leftUnionArray[i].setBConst(node->getUConst(i) != 0);
1422 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001423 case EbtBool:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001424 leftUnionArray[i].setBConst(node->getBConst(i));
John Bauman66b8ab22014-05-06 15:57:45 -04001425 break;
1426 case EbtFloat:
Nicolas Capens55b22d62015-02-10 13:58:40 -05001427 leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
John Bauman66b8ab22014-05-06 15:57:45 -04001428 break;
1429 default:
1430 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1431 return 0;
1432 }
1433
1434 break;
1435 default:
1436 infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
1437 return 0;
1438 }
1439
1440 }
1441
1442 const TType& t = node->getType();
1443
Alexis Hetub14178b2015-04-13 13:23:20 -04001444 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine());
John Bauman66b8ab22014-05-06 15:57:45 -04001445}
1446