blob: 6e7f6dea65fed7e020d9dae31a5b119b129b0567 [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
15#include "compiler/localintermediate.h"
16#include "compiler/QualifierAlive.h"
17#include "compiler/RemoveTree.h"
John Baumand4ae8632014-05-06 16:18:33 -040018#include "compiler/SymbolTable.h"
John Bauman66b8ab22014-05-06 15:57:45 -040019
20bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
21
22static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
23 return left > right ? left : right;
24}
25
26const char* getOperatorString(TOperator op) {
27 switch (op) {
28 case EOpInitialize: return "=";
29 case EOpAssign: return "=";
30 case EOpAddAssign: return "+=";
31 case EOpSubAssign: return "-=";
32 case EOpDivAssign: return "/=";
33
34 // Fall-through.
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -040035 case EOpMulAssign:
John Bauman66b8ab22014-05-06 15:57:45 -040036 case EOpVectorTimesMatrixAssign:
37 case EOpVectorTimesScalarAssign:
38 case EOpMatrixTimesScalarAssign:
39 case EOpMatrixTimesMatrixAssign: return "*=";
40
41 // Fall-through.
42 case EOpIndexDirect:
43 case EOpIndexIndirect: return "[]";
44
45 case EOpIndexDirectStruct: return ".";
46 case EOpVectorSwizzle: return ".";
47 case EOpAdd: return "+";
48 case EOpSub: return "-";
49 case EOpMul: return "*";
50 case EOpDiv: return "/";
51 case EOpMod: UNIMPLEMENTED(); break;
52 case EOpEqual: return "==";
53 case EOpNotEqual: return "!=";
54 case EOpLessThan: return "<";
55 case EOpGreaterThan: return ">";
56 case EOpLessThanEqual: return "<=";
57 case EOpGreaterThanEqual: return ">=";
58
59 // Fall-through.
60 case EOpVectorTimesScalar:
61 case EOpVectorTimesMatrix:
62 case EOpMatrixTimesVector:
63 case EOpMatrixTimesScalar:
64 case EOpMatrixTimesMatrix: return "*";
65
66 case EOpLogicalOr: return "||";
67 case EOpLogicalXor: return "^^";
68 case EOpLogicalAnd: return "&&";
69 case EOpNegative: return "-";
70 case EOpVectorLogicalNot: return "not";
71 case EOpLogicalNot: return "!";
72 case EOpPostIncrement: return "++";
73 case EOpPostDecrement: return "--";
74 case EOpPreIncrement: return "++";
75 case EOpPreDecrement: return "--";
76
77 // Fall-through.
78 case EOpConvIntToBool:
79 case EOpConvFloatToBool: return "bool";
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -040080
John Bauman66b8ab22014-05-06 15:57:45 -040081 // Fall-through.
82 case EOpConvBoolToFloat:
83 case EOpConvIntToFloat: return "float";
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -040084
John Bauman66b8ab22014-05-06 15:57:45 -040085 // Fall-through.
86 case EOpConvFloatToInt:
87 case EOpConvBoolToInt: return "int";
88
89 case EOpRadians: return "radians";
90 case EOpDegrees: return "degrees";
91 case EOpSin: return "sin";
92 case EOpCos: return "cos";
93 case EOpTan: return "tan";
94 case EOpAsin: return "asin";
95 case EOpAcos: return "acos";
96 case EOpAtan: return "atan";
97 case EOpExp: return "exp";
98 case EOpLog: return "log";
99 case EOpExp2: return "exp2";
100 case EOpLog2: return "log2";
101 case EOpSqrt: return "sqrt";
102 case EOpInverseSqrt: return "inversesqrt";
103 case EOpAbs: return "abs";
104 case EOpSign: return "sign";
105 case EOpFloor: return "floor";
106 case EOpCeil: return "ceil";
107 case EOpFract: return "fract";
108 case EOpLength: return "length";
109 case EOpNormalize: return "normalize";
110 case EOpDFdx: return "dFdx";
111 case EOpDFdy: return "dFdy";
112 case EOpFwidth: return "fwidth";
113 case EOpAny: return "any";
114 case EOpAll: return "all";
115
116 default: break;
117 }
118 return "";
119}
120
121////////////////////////////////////////////////////////////////////////////
122//
123// First set of functions are to help build the intermediate representation.
124// These functions are not member functions of the nodes.
125// They are called from parser productions.
126//
127/////////////////////////////////////////////////////////////////////////////
128
129//
130// Add a terminal node for an identifier in an expression.
131//
132// Returns the added node.
133//
134TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
135{
136 TIntermSymbol* node = new TIntermSymbol(id, name, type);
137 node->setLine(line);
138
139 return node;
140}
141
142//
143// Connect two nodes with a new parent that does a binary operation on the nodes.
144//
145// Returns the added node.
146//
John Baumand4ae8632014-05-06 16:18:33 -0400147TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
John Bauman66b8ab22014-05-06 15:57:45 -0400148{
149 switch (op) {
150 case EOpEqual:
151 case EOpNotEqual:
152 if (left->isArray())
153 return 0;
154 break;
155 case EOpLessThan:
156 case EOpGreaterThan:
157 case EOpLessThanEqual:
158 case EOpGreaterThanEqual:
159 if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
160 return 0;
161 }
162 break;
163 case EOpLogicalOr:
164 case EOpLogicalXor:
165 case EOpLogicalAnd:
166 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
167 return 0;
168 }
169 break;
170 case EOpAdd:
171 case EOpSub:
172 case EOpDiv:
173 case EOpMul:
174 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
175 return 0;
176 default: break;
177 }
178
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400179 if (left->getBasicType() != right->getBasicType())
180 {
181 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400182 }
183
184 //
185 // Need a new node holding things together then. Make
186 // one and promote it to the right type.
187 //
188 TIntermBinary* node = new TIntermBinary(op);
189 if (line == 0)
190 line = right->getLine();
191 node->setLine(line);
192
193 node->setLeft(left);
194 node->setRight(right);
195 if (!node->promote(infoSink))
196 return 0;
197
198 //
199 // See if we can fold constants.
200 //
John Bauman66b8ab22014-05-06 15:57:45 -0400201 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
202 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
203 if (leftTempConstant && rightTempConstant) {
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400204 TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400205
206 if (typedReturnNode)
207 return typedReturnNode;
208 }
209
210 return node;
211}
212
213//
214// Connect two nodes through an assignment.
215//
216// Returns the added node.
217//
218TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
219{
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400220 if (left->getType().getStruct() || right->getType().getStruct())
221 {
222 if (left->getType() != right->getType())
223 {
224 return 0;
225 }
226 }
227
John Bauman66b8ab22014-05-06 15:57:45 -0400228 TIntermBinary* node = new TIntermBinary(op);
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400229 if(line == 0)
John Bauman66b8ab22014-05-06 15:57:45 -0400230 line = left->getLine();
231 node->setLine(line);
232
John Bauman66b8ab22014-05-06 15:57:45 -0400233 node->setLeft(left);
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400234 node->setRight(right);
John Bauman66b8ab22014-05-06 15:57:45 -0400235 if (! node->promote(infoSink))
236 return 0;
237
238 return node;
239}
240
241//
242// Connect two nodes through an index operator, where the left node is the base
243// of an array or struct, and the right node is a direct or indirect offset.
244//
245// Returns the added node.
246// The caller should set the type of the returned node.
247//
248TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
249{
250 TIntermBinary* node = new TIntermBinary(op);
251 if (line == 0)
252 line = index->getLine();
253 node->setLine(line);
254 node->setLeft(base);
255 node->setRight(index);
256
257 // caller should set the type
258
259 return node;
260}
261
262//
263// Add one node as the parent of another that it operates on.
264//
265// Returns the added node.
266//
John Baumand4ae8632014-05-06 16:18:33 -0400267TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line)
John Bauman66b8ab22014-05-06 15:57:45 -0400268{
269 TIntermUnary* node;
270 TIntermTyped* child = childNode->getAsTyped();
271
272 if (child == 0) {
273 infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
274 return 0;
275 }
276
277 switch (op) {
278 case EOpLogicalNot:
279 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
280 return 0;
281 }
282 break;
283
284 case EOpPostIncrement:
285 case EOpPreIncrement:
286 case EOpPostDecrement:
287 case EOpPreDecrement:
288 case EOpNegative:
289 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
290 return 0;
291 default: break;
292 }
293
John Bauman66b8ab22014-05-06 15:57:45 -0400294 TIntermConstantUnion *childTempConstant = 0;
295 if (child->getAsConstantUnion())
296 childTempConstant = child->getAsConstantUnion();
297
298 //
299 // Make a new node for the operator.
300 //
301 node = new TIntermUnary(op);
302 if (line == 0)
303 line = child->getLine();
304 node->setLine(line);
305 node->setOperand(child);
306
307 if (! node->promote(infoSink))
308 return 0;
309
310 if (childTempConstant) {
311 TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
312
313 if (newChild)
314 return newChild;
315 }
316
317 return node;
318}
319
320//
321// This is the safe way to change the operator on an aggregate, as it
322// does lots of error checking and fixing. Especially for establishing
323// a function call's operation on it's set of parameters. Sequences
324// of instructions are also aggregates, but they just direnctly set
325// their operator to EOpSequence.
326//
327// Returns an aggregate node, which could be the one passed in if
328// it was already an aggregate but no operator was set.
329//
330TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
331{
332 TIntermAggregate* aggNode;
333
334 //
335 // Make sure we have an aggregate. If not turn it into one.
336 //
337 if (node) {
338 aggNode = node->getAsAggregate();
339 if (aggNode == 0 || aggNode->getOp() != EOpNull) {
340 //
341 // Make an aggregate containing this node.
342 //
343 aggNode = new TIntermAggregate();
344 aggNode->getSequence().push_back(node);
345 if (line == 0)
346 line = node->getLine();
347 }
348 } else
349 aggNode = new TIntermAggregate();
350
351 //
352 // Set the operator.
353 //
354 aggNode->setOp(op);
355 if (line != 0)
356 aggNode->setLine(line);
357
358 return aggNode;
359}
360
361//
362// Convert one type to another.
363//
364// Returns the node representing the conversion, which could be the same
365// node passed in if no conversion was needed.
366//
367// Return 0 if a conversion can't be done.
368//
369TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
370{
371 //
372 // Does the base type allow operation?
373 //
Nicolas Capense9c5e4f2014-05-28 22:46:43 -0400374 if (node->getBasicType() == EbtVoid || IsSampler(node->getBasicType()))
375 {
376 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400377 }
378
379 //
380 // Otherwise, if types are identical, no problem
381 //
382 if (type == node->getType())
383 return node;
384
385 //
386 // If one's a structure, then no conversions.
387 //
388 if (type.getStruct() || node->getType().getStruct())
389 return 0;
390
391 //
392 // If one's an array, then no conversions.
393 //
394 if (type.isArray() || node->getType().isArray())
395 return 0;
396
397 TBasicType promoteTo;
398
399 switch (op) {
400 //
401 // Explicit conversions
402 //
403 case EOpConstructBool:
404 promoteTo = EbtBool;
405 break;
406 case EOpConstructFloat:
407 promoteTo = EbtFloat;
408 break;
409 case EOpConstructInt:
410 promoteTo = EbtInt;
411 break;
412 default:
413 //
414 // implicit conversions were removed from the language.
415 //
416 if (type.getBasicType() != node->getType().getBasicType())
417 return 0;
418 //
419 // Size and structure could still differ, but that's
420 // handled by operator promotion.
421 //
422 return node;
423 }
424
425 if (node->getAsConstantUnion()) {
426
427 return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
428 } else {
429
430 //
431 // Add a new newNode for the conversion.
432 //
433 TIntermUnary* newNode = 0;
434
435 TOperator newOp = EOpNull;
436 switch (promoteTo) {
437 case EbtFloat:
438 switch (node->getBasicType()) {
439 case EbtInt: newOp = EOpConvIntToFloat; break;
440 case EbtBool: newOp = EOpConvBoolToFloat; break;
441 default:
442 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
443 return 0;
444 }
445 break;
446 case EbtBool:
447 switch (node->getBasicType()) {
448 case EbtInt: newOp = EOpConvIntToBool; break;
449 case EbtFloat: newOp = EOpConvFloatToBool; break;
450 default:
451 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
452 return 0;
453 }
454 break;
455 case EbtInt:
456 switch (node->getBasicType()) {
457 case EbtBool: newOp = EOpConvBoolToInt; break;
458 case EbtFloat: newOp = EOpConvFloatToInt; break;
459 default:
460 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
461 return 0;
462 }
463 break;
464 default:
465 infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine());
466 return 0;
467 }
468
469 TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
470 newNode = new TIntermUnary(newOp, type);
471 newNode->setLine(node->getLine());
472 newNode->setOperand(node);
473
474 return newNode;
475 }
476}
477
478//
479// Safe way to combine two nodes into an aggregate. Works with null pointers,
480// a node that's not a aggregate yet, etc.
481//
482// Returns the resulting aggregate, unless 0 was passed in for
483// both existing nodes.
484//
485TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
486{
487 if (left == 0 && right == 0)
488 return 0;
489
490 TIntermAggregate* aggNode = 0;
491 if (left)
492 aggNode = left->getAsAggregate();
493 if (!aggNode || aggNode->getOp() != EOpNull) {
494 aggNode = new TIntermAggregate;
495 if (left)
496 aggNode->getSequence().push_back(left);
497 }
498
499 if (right)
500 aggNode->getSequence().push_back(right);
501
502 if (line != 0)
503 aggNode->setLine(line);
504
505 return aggNode;
506}
507
508//
509// Turn an existing node into an aggregate.
510//
511// Returns an aggregate, unless 0 was passed in for the existing node.
512//
513TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
514{
515 if (node == 0)
516 return 0;
517
518 TIntermAggregate* aggNode = new TIntermAggregate;
519 aggNode->getSequence().push_back(node);
520
521 if (line != 0)
522 aggNode->setLine(line);
523 else
524 aggNode->setLine(node->getLine());
525
526 return aggNode;
527}
528
529//
530// For "if" test nodes. There are three children; a condition,
531// a true path, and a false path. The two paths are in the
532// nodePair.
533//
534// Returns the selection node created.
535//
536TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
537{
538 //
539 // For compile time constant selections, prune the code and
540 // test now.
541 //
542
543 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
544 if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst() == true)
545 return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
546 else
547 return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
548 }
549
550 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
551 node->setLine(line);
552
553 return node;
554}
555
556
557TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
558{
559 if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
560 return right;
561 } else {
562 TIntermTyped *commaAggregate = growAggregate(left, right, line);
563 commaAggregate->getAsAggregate()->setOp(EOpComma);
564 commaAggregate->setType(right->getType());
565 commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
566 return commaAggregate;
567 }
568}
569
570//
571// For "?:" test nodes. There are three children; a condition,
572// a true path, and a false path. The two paths are specified
573// as separate parameters.
574//
575// Returns the selection node created, or 0 if one could not be.
576//
577TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
578{
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400579 if (trueBlock->getType() != falseBlock->getType())
580 {
581 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400582 }
583
584 //
585 // See if all the operands are constant, then fold it otherwise not.
586 //
587
588 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
589 if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
590 return trueBlock;
591 else
592 return falseBlock;
593 }
594
595 //
596 // Make a selection node.
597 //
598 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
599 node->getTypePointer()->setQualifier(EvqTemporary);
600 node->setLine(line);
601
602 return node;
603}
604
605//
606// Constant terminal nodes. Has a union that contains bool, float or int constants
607//
608// Returns the constant union node created.
609//
610
611TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line)
612{
613 TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
614 node->setLine(line);
615
616 return node;
617}
618
619TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
620{
621
622 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
623
624 node->setLine(line);
625 TIntermConstantUnion* constIntNode;
626 TIntermSequence &sequenceVector = node->getSequence();
627 ConstantUnion* unionArray;
628
629 for (int i = 0; i < fields.num; i++) {
630 unionArray = new ConstantUnion[1];
631 unionArray->setIConst(fields.offsets[i]);
632 constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
633 sequenceVector.push_back(constIntNode);
634 }
635
636 return node;
637}
638
639//
640// Create loop nodes.
641//
642TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line)
643{
644 TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
645 node->setLine(line);
646
647 return node;
648}
649
650//
651// Add branches.
652//
653TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
654{
655 return addBranch(branchOp, 0, line);
656}
657
658TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
659{
660 TIntermBranch* node = new TIntermBranch(branchOp, expression);
661 node->setLine(line);
662
663 return node;
664}
665
666//
667// This is to be executed once the final root is put on top by the parsing
668// process.
669//
670bool TIntermediate::postProcess(TIntermNode* root)
671{
672 if (root == 0)
673 return true;
674
675 //
676 // First, finish off the top level sequence, if any
677 //
678 TIntermAggregate* aggRoot = root->getAsAggregate();
679 if (aggRoot && aggRoot->getOp() == EOpNull)
680 aggRoot->setOp(EOpSequence);
681
682 return true;
683}
684
685//
686// This deletes the tree.
687//
688void TIntermediate::remove(TIntermNode* root)
689{
690 if (root)
691 RemoveAllTreeNodes(root);
692}
693
694////////////////////////////////////////////////////////////////
695//
696// Member functions of the nodes used for building the tree.
697//
698////////////////////////////////////////////////////////////////
699
700//
701// Say whether or not an operation node changes the value of a variable.
702//
703// Returns true if state is modified.
704//
705bool TIntermOperator::modifiesState() const
706{
707 switch (op) {
708 case EOpPostIncrement:
709 case EOpPostDecrement:
710 case EOpPreIncrement:
711 case EOpPreDecrement:
712 case EOpAssign:
713 case EOpAddAssign:
714 case EOpSubAssign:
715 case EOpMulAssign:
716 case EOpVectorTimesMatrixAssign:
717 case EOpVectorTimesScalarAssign:
718 case EOpMatrixTimesScalarAssign:
719 case EOpMatrixTimesMatrixAssign:
720 case EOpDivAssign:
721 return true;
722 default:
723 return false;
724 }
725}
726
727//
728// returns true if the operator is for one of the constructors
729//
730bool TIntermOperator::isConstructor() const
731{
732 switch (op) {
733 case EOpConstructVec2:
734 case EOpConstructVec3:
735 case EOpConstructVec4:
736 case EOpConstructMat2:
737 case EOpConstructMat3:
738 case EOpConstructMat4:
739 case EOpConstructFloat:
740 case EOpConstructIVec2:
741 case EOpConstructIVec3:
742 case EOpConstructIVec4:
743 case EOpConstructInt:
744 case EOpConstructBVec2:
745 case EOpConstructBVec3:
746 case EOpConstructBVec4:
747 case EOpConstructBool:
748 case EOpConstructStruct:
749 return true;
750 default:
751 return false;
752 }
753}
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400754
John Bauman66b8ab22014-05-06 15:57:45 -0400755//
756// Make sure the type of a unary operator is appropriate for its
757// combination of operation and operand type.
758//
759// Returns false in nothing makes sense.
760//
761bool TIntermUnary::promote(TInfoSink&)
762{
763 switch (op) {
764 case EOpLogicalNot:
765 if (operand->getBasicType() != EbtBool)
766 return false;
767 break;
768 case EOpNegative:
769 case EOpPostIncrement:
770 case EOpPostDecrement:
771 case EOpPreIncrement:
772 case EOpPreDecrement:
773 if (operand->getBasicType() == EbtBool)
774 return false;
775 break;
776
777 // operators for built-ins are already type checked against their prototype
778 case EOpAny:
779 case EOpAll:
780 case EOpVectorLogicalNot:
781 return true;
782
783 default:
784 if (operand->getBasicType() != EbtFloat)
785 return false;
786 }
787
788 setType(operand->getType());
789
790 // Unary operations results in temporary variables unless const.
791 if (operand->getQualifier() != EvqConst) {
792 getTypePointer()->setQualifier(EvqTemporary);
793 }
794
795 return true;
796}
797
798//
799// Establishes the type of the resultant operation, as well as
800// makes the operator the correct one for the operands.
801//
802// Returns false if operator can't work on operands.
803//
804bool TIntermBinary::promote(TInfoSink& infoSink)
805{
806 // This function only handles scalars, vectors, and matrices.
807 if (left->isArray() || right->isArray()) {
808 infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
809 return false;
810 }
811
812 // GLSL ES 2.0 does not support implicit type casting.
813 // So the basic type should always match.
814 if (left->getBasicType() != right->getBasicType())
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400815 {
John Bauman66b8ab22014-05-06 15:57:45 -0400816 return false;
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400817 }
John Bauman66b8ab22014-05-06 15:57:45 -0400818
819 //
820 // Base assumption: just make the type the same as the left
821 // operand. Then only deviations from this need be coded.
822 //
823 setType(left->getType());
824
825 // The result gets promoted to the highest precision.
826 TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
827 getTypePointer()->setPrecision(higherPrecision);
828
829 // Binary operations results in temporary variables unless both
830 // operands are const.
831 if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
832 getTypePointer()->setQualifier(EvqTemporary);
833 }
834
835 int size = std::max(left->getNominalSize(), right->getNominalSize());
836
837 //
838 // All scalars. Code after this test assumes this case is removed!
839 //
840 if (size == 1) {
841 switch (op) {
842 //
843 // Promote to conditional
844 //
845 case EOpEqual:
846 case EOpNotEqual:
847 case EOpLessThan:
848 case EOpGreaterThan:
849 case EOpLessThanEqual:
850 case EOpGreaterThanEqual:
851 setType(TType(EbtBool, EbpUndefined));
852 break;
853
854 //
855 // And and Or operate on conditionals
856 //
857 case EOpLogicalAnd:
858 case EOpLogicalOr:
859 // Both operands must be of type bool.
860 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
861 return false;
862 setType(TType(EbtBool, EbpUndefined));
863 break;
864
865 default:
866 break;
867 }
868 return true;
869 }
870
871 // If we reach here, at least one of the operands is vector or matrix.
872 // The other operand could be a scalar, vector, or matrix.
873 // Are the sizes compatible?
874 //
875 if (left->getNominalSize() != right->getNominalSize()) {
876 // If the nominal size of operands do not match:
877 // One of them must be scalar.
878 if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
879 return false;
880 // Operator cannot be of type pure assignment.
881 if (op == EOpAssign || op == EOpInitialize)
882 return false;
883 }
884
885 //
886 // Can these two operands be combined?
887 //
888 TBasicType basicType = left->getBasicType();
889 switch (op) {
890 case EOpMul:
891 if (!left->isMatrix() && right->isMatrix()) {
892 if (left->isVector())
893 op = EOpVectorTimesMatrix;
894 else {
895 op = EOpMatrixTimesScalar;
896 setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
897 }
898 } else if (left->isMatrix() && !right->isMatrix()) {
899 if (right->isVector()) {
900 op = EOpMatrixTimesVector;
901 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
902 } else {
903 op = EOpMatrixTimesScalar;
904 }
905 } else if (left->isMatrix() && right->isMatrix()) {
906 op = EOpMatrixTimesMatrix;
907 } else if (!left->isMatrix() && !right->isMatrix()) {
908 if (left->isVector() && right->isVector()) {
909 // leave as component product
910 } else if (left->isVector() || right->isVector()) {
911 op = EOpVectorTimesScalar;
912 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
913 }
914 } else {
915 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
916 return false;
917 }
918 break;
919 case EOpMulAssign:
920 if (!left->isMatrix() && right->isMatrix()) {
921 if (left->isVector())
922 op = EOpVectorTimesMatrixAssign;
923 else {
924 return false;
925 }
926 } else if (left->isMatrix() && !right->isMatrix()) {
927 if (right->isVector()) {
928 return false;
929 } else {
930 op = EOpMatrixTimesScalarAssign;
931 }
932 } else if (left->isMatrix() && right->isMatrix()) {
933 op = EOpMatrixTimesMatrixAssign;
934 } else if (!left->isMatrix() && !right->isMatrix()) {
935 if (left->isVector() && right->isVector()) {
936 // leave as component product
937 } else if (left->isVector() || right->isVector()) {
938 if (! left->isVector())
939 return false;
940 op = EOpVectorTimesScalarAssign;
941 setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
942 }
943 } else {
944 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
945 return false;
946 }
947 break;
948
949 case EOpAssign:
950 case EOpInitialize:
951 case EOpAdd:
952 case EOpSub:
953 case EOpDiv:
954 case EOpAddAssign:
955 case EOpSubAssign:
956 case EOpDivAssign:
957 if ((left->isMatrix() && right->isVector()) ||
958 (left->isVector() && right->isMatrix()))
959 return false;
960 setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
961 break;
962
963 case EOpEqual:
964 case EOpNotEqual:
965 case EOpLessThan:
966 case EOpGreaterThan:
967 case EOpLessThanEqual:
968 case EOpGreaterThanEqual:
969 if ((left->isMatrix() && right->isVector()) ||
970 (left->isVector() && right->isMatrix()))
971 return false;
972 setType(TType(EbtBool, EbpUndefined));
973 break;
974
975 default:
976 return false;
977 }
978
979 return true;
980}
981
982bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
983{
984 const TTypeList* fields = leftNodeType.getStruct();
985
986 size_t structSize = fields->size();
987 int index = 0;
988
989 for (size_t j = 0; j < structSize; j++) {
990 int size = (*fields)[j].type->getObjectSize();
991 for (int i = 0; i < size; i++) {
992 if ((*fields)[j].type->getBasicType() == EbtStruct) {
993 if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
994 return false;
995 } else {
996 if (leftUnionArray[index] != rightUnionArray[index])
997 return false;
998 index++;
999 }
1000
1001 }
1002 }
1003 return true;
1004}
1005
1006bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1007{
1008 if (leftNodeType.isArray()) {
1009 TType typeWithoutArrayness = leftNodeType;
1010 typeWithoutArrayness.clearArrayness();
1011
1012 int arraySize = leftNodeType.getArraySize();
1013
1014 for (int i = 0; i < arraySize; ++i) {
1015 int offset = typeWithoutArrayness.getObjectSize() * i;
1016 if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1017 return false;
1018 }
1019 } else
1020 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
1021
1022 return true;
1023}
1024
1025//
1026// The fold functions see if an operation on a constant can be done in place,
1027// without generating run-time code.
1028//
1029// Returns the node to keep using, which may or may not be the node passed in.
1030//
1031
1032TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1033{
1034 ConstantUnion *unionArray = getUnionArrayPointer();
1035 int objectSize = getType().getObjectSize();
1036
1037 if (constantNode) { // binary operations
1038 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1039 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1040 TType returnType = getType();
1041
1042 // for a case like float f = 1.2 + vec4(2,3,4,5);
1043 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1044 rightUnionArray = new ConstantUnion[objectSize];
1045 for (int i = 0; i < objectSize; ++i)
1046 rightUnionArray[i] = *node->getUnionArrayPointer();
1047 returnType = getType();
1048 } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1049 // for a case like float f = vec4(2,3,4,5) + 1.2;
1050 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1051 for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
1052 unionArray[i] = *getUnionArrayPointer();
1053 returnType = node->getType();
1054 objectSize = constantNode->getType().getObjectSize();
1055 }
1056
1057 ConstantUnion* tempConstArray = 0;
1058 TIntermConstantUnion *tempNode;
1059
1060 bool boolNodeFlag = false;
1061 switch(op) {
1062 case EOpAdd:
1063 tempConstArray = new ConstantUnion[objectSize];
1064 {// support MSVC++6.0
1065 for (int i = 0; i < objectSize; i++)
1066 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1067 }
1068 break;
1069 case EOpSub:
1070 tempConstArray = new ConstantUnion[objectSize];
1071 {// support MSVC++6.0
1072 for (int i = 0; i < objectSize; i++)
1073 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1074 }
1075 break;
1076
1077 case EOpMul:
1078 case EOpVectorTimesScalar:
1079 case EOpMatrixTimesScalar:
1080 tempConstArray = new ConstantUnion[objectSize];
1081 {// support MSVC++6.0
1082 for (int i = 0; i < objectSize; i++)
1083 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1084 }
1085 break;
1086 case EOpMatrixTimesMatrix:
1087 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1088 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1089 return 0;
1090 }
1091 {// support MSVC++6.0
1092 int size = getNominalSize();
1093 tempConstArray = new ConstantUnion[size*size];
1094 for (int row = 0; row < size; row++) {
1095 for (int column = 0; column < size; column++) {
1096 tempConstArray[size * column + row].setFConst(0.0f);
1097 for (int i = 0; i < size; i++) {
1098 tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1099 }
1100 }
1101 }
1102 }
1103 break;
1104 case EOpDiv:
1105 tempConstArray = new ConstantUnion[objectSize];
1106 {// support MSVC++6.0
1107 for (int i = 0; i < objectSize; i++) {
1108 switch (getType().getBasicType()) {
1109 case EbtFloat:
1110 if (rightUnionArray[i] == 0.0f) {
1111 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1112 tempConstArray[i].setFConst(FLT_MAX);
1113 } else
1114 tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1115 break;
1116
1117 case EbtInt:
1118 if (rightUnionArray[i] == 0) {
1119 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1120 tempConstArray[i].setIConst(INT_MAX);
1121 } else
1122 tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1123 break;
1124 default:
1125 infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
1126 return 0;
1127 }
1128 }
1129 }
1130 break;
1131
1132 case EOpMatrixTimesVector:
1133 if (node->getBasicType() != EbtFloat) {
1134 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
1135 return 0;
1136 }
1137 tempConstArray = new ConstantUnion[getNominalSize()];
1138
1139 {// support MSVC++6.0
1140 for (int size = getNominalSize(), i = 0; i < size; i++) {
1141 tempConstArray[i].setFConst(0.0f);
1142 for (int j = 0; j < size; j++) {
1143 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1144 }
1145 }
1146 }
1147
1148 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1149 tempNode->setLine(getLine());
1150
1151 return tempNode;
1152
1153 case EOpVectorTimesMatrix:
1154 if (getType().getBasicType() != EbtFloat) {
1155 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
1156 return 0;
1157 }
1158
1159 tempConstArray = new ConstantUnion[getNominalSize()];
1160 {// support MSVC++6.0
1161 for (int size = getNominalSize(), i = 0; i < size; i++) {
1162 tempConstArray[i].setFConst(0.0f);
1163 for (int j = 0; j < size; j++) {
1164 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1165 }
1166 }
1167 }
1168 break;
1169
1170 case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1171 tempConstArray = new ConstantUnion[objectSize];
1172 {// support MSVC++6.0
1173 for (int i = 0; i < objectSize; i++)
1174 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1175 }
1176 break;
1177
1178 case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1179 tempConstArray = new ConstantUnion[objectSize];
1180 {// support MSVC++6.0
1181 for (int i = 0; i < objectSize; i++)
1182 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1183 }
1184 break;
1185
1186 case EOpLogicalXor:
1187 tempConstArray = new ConstantUnion[objectSize];
1188 {// support MSVC++6.0
1189 for (int i = 0; i < objectSize; i++)
1190 switch (getType().getBasicType()) {
1191 case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1192 default: assert(false && "Default missing");
1193 }
1194 }
1195 break;
1196
1197 case EOpLessThan:
1198 assert(objectSize == 1);
1199 tempConstArray = new ConstantUnion[1];
1200 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1201 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1202 break;
1203 case EOpGreaterThan:
1204 assert(objectSize == 1);
1205 tempConstArray = new ConstantUnion[1];
1206 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1207 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1208 break;
1209 case EOpLessThanEqual:
1210 {
1211 assert(objectSize == 1);
1212 ConstantUnion constant;
1213 constant.setBConst(*unionArray > *rightUnionArray);
1214 tempConstArray = new ConstantUnion[1];
1215 tempConstArray->setBConst(!constant.getBConst());
1216 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1217 break;
1218 }
1219 case EOpGreaterThanEqual:
1220 {
1221 assert(objectSize == 1);
1222 ConstantUnion constant;
1223 constant.setBConst(*unionArray < *rightUnionArray);
1224 tempConstArray = new ConstantUnion[1];
1225 tempConstArray->setBConst(!constant.getBConst());
1226 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1227 break;
1228 }
1229
1230 case EOpEqual:
1231 if (getType().getBasicType() == EbtStruct) {
1232 if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1233 boolNodeFlag = true;
1234 } else {
1235 for (int i = 0; i < objectSize; i++) {
1236 if (unionArray[i] != rightUnionArray[i]) {
1237 boolNodeFlag = true;
1238 break; // break out of for loop
1239 }
1240 }
1241 }
1242
1243 tempConstArray = new ConstantUnion[1];
1244 if (!boolNodeFlag) {
1245 tempConstArray->setBConst(true);
1246 }
1247 else {
1248 tempConstArray->setBConst(false);
1249 }
1250
1251 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1252 tempNode->setLine(getLine());
1253
1254 return tempNode;
1255
1256 case EOpNotEqual:
1257 if (getType().getBasicType() == EbtStruct) {
1258 if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1259 boolNodeFlag = true;
1260 } else {
1261 for (int i = 0; i < objectSize; i++) {
1262 if (unionArray[i] == rightUnionArray[i]) {
1263 boolNodeFlag = true;
1264 break; // break out of for loop
1265 }
1266 }
1267 }
1268
1269 tempConstArray = new ConstantUnion[1];
1270 if (!boolNodeFlag) {
1271 tempConstArray->setBConst(true);
1272 }
1273 else {
1274 tempConstArray->setBConst(false);
1275 }
1276
1277 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
1278 tempNode->setLine(getLine());
1279
1280 return tempNode;
1281
1282 default:
1283 infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
1284 return 0;
1285 }
1286 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1287 tempNode->setLine(getLine());
1288
1289 return tempNode;
1290 } else {
1291 //
1292 // Do unary operations
1293 //
1294 TIntermConstantUnion *newNode = 0;
1295 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1296 for (int i = 0; i < objectSize; i++) {
1297 switch(op) {
1298 case EOpNegative:
1299 switch (getType().getBasicType()) {
1300 case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1301 case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1302 default:
1303 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1304 return 0;
1305 }
1306 break;
1307 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1308 switch (getType().getBasicType()) {
1309 case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1310 default:
1311 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1312 return 0;
1313 }
1314 break;
1315 default:
1316 return 0;
1317 }
1318 }
1319 newNode = new TIntermConstantUnion(tempConstArray, getType());
1320 newNode->setLine(getLine());
1321 return newNode;
1322 }
1323}
1324
1325TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1326{
1327 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1328 int size = node->getType().getObjectSize();
1329
1330 ConstantUnion *leftUnionArray = new ConstantUnion[size];
1331
1332 for (int i=0; i < size; i++) {
1333
1334 switch (promoteTo) {
1335 case EbtFloat:
1336 switch (node->getType().getBasicType()) {
1337 case EbtInt:
1338 leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst()));
1339 break;
1340 case EbtBool:
1341 leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst()));
1342 break;
1343 case EbtFloat:
1344 leftUnionArray[i] = rightUnionArray[i];
1345 break;
1346 default:
1347 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1348 return 0;
1349 }
1350 break;
1351 case EbtInt:
1352 switch (node->getType().getBasicType()) {
1353 case EbtInt:
1354 leftUnionArray[i] = rightUnionArray[i];
1355 break;
1356 case EbtBool:
1357 leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
1358 break;
1359 case EbtFloat:
1360 leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst()));
1361 break;
1362 default:
1363 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1364 return 0;
1365 }
1366 break;
1367 case EbtBool:
1368 switch (node->getType().getBasicType()) {
1369 case EbtInt:
1370 leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
1371 break;
1372 case EbtBool:
1373 leftUnionArray[i] = rightUnionArray[i];
1374 break;
1375 case EbtFloat:
1376 leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f);
1377 break;
1378 default:
1379 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1380 return 0;
1381 }
1382
1383 break;
1384 default:
1385 infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
1386 return 0;
1387 }
1388
1389 }
1390
1391 const TType& t = node->getType();
1392
1393 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
1394}
1395