blob: c85aaaf8b4b316e673a3b342b891d8eecfece4fe [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// 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 "localintermediate.h"
12#include "QualifierAlive.h"
13#include "RemoveTree.h"
14#include <float.h>
15
16bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray);
17
18////////////////////////////////////////////////////////////////////////////
19//
20// First set of functions are to help build the intermediate representation.
21// These functions are not member functions of the nodes.
22// They are called from parser productions.
23//
24/////////////////////////////////////////////////////////////////////////////
25
26//
27// Add a terminal node for an identifier in an expression.
28//
29// Returns the added node.
30//
31TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
32{
alokp@chromium.org2cf17712010-03-30 20:33:18 +000033 TIntermSymbol* node = new TIntermSymbol(id, name, type);
34 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000035
alokp@chromium.org2cf17712010-03-30 20:33:18 +000036 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000037}
38
39//
40// Connect two nodes with a new parent that does a binary operation on the nodes.
41//
42// Returns the added node.
43//
44TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable)
45{
alokp@chromium.org2cf17712010-03-30 20:33:18 +000046 switch (op) {
47 case EOpLessThan:
48 case EOpGreaterThan:
49 case EOpLessThanEqual:
50 case EOpGreaterThanEqual:
51 if (left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector() || left->getType().getBasicType() == EbtStruct) {
52 return 0;
53 }
54 break;
55 case EOpLogicalOr:
56 case EOpLogicalXor:
57 case EOpLogicalAnd:
58 if (left->getType().getBasicType() != EbtBool || left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector()) {
59 return 0;
60 }
61 break;
62 case EOpAdd:
63 case EOpSub:
64 case EOpDiv:
65 case EOpMul:
66 if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool)
67 return 0;
68 default: break;
69 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000070
alokp@chromium.org2cf17712010-03-30 20:33:18 +000071 //
72 // First try converting the children to compatible types.
73 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000074
alokp@chromium.org2cf17712010-03-30 20:33:18 +000075 if (!(left->getType().getStruct() && right->getType().getStruct())) {
76 TIntermTyped* child = addConversion(op, left->getType(), right);
77 if (child)
78 right = child;
79 else {
80 child = addConversion(op, right->getType(), left);
81 if (child)
82 left = child;
83 else
84 return 0;
85 }
86 } else {
87 if (left->getType() != right->getType())
88 return 0;
89 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000090
91
alokp@chromium.org2cf17712010-03-30 20:33:18 +000092 //
93 // Need a new node holding things together then. Make
94 // one and promote it to the right type.
95 //
96 TIntermBinary* node = new TIntermBinary(op);
97 if (line == 0)
98 line = right->getLine();
99 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000101 node->setLeft(left);
102 node->setRight(right);
103 if (! node->promote(infoSink))
104 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000105
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000106 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
107 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000108
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000109 if (leftTempConstant)
110 leftTempConstant = left->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000111
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000112 if (rightTempConstant)
113 rightTempConstant = right->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000115 //
116 // See if we can fold constants.
117 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000118
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000119 TIntermTyped* typedReturnNode = 0;
120 if ( leftTempConstant && rightTempConstant) {
121 typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000123 if (typedReturnNode)
124 return typedReturnNode;
125 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000127 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128}
129
130//
131// Connect two nodes through an assignment.
132//
133// Returns the added node.
134//
135TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
136{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000137 //
138 // Like adding binary math, except the conversion can only go
139 // from right to left.
140 //
141 TIntermBinary* node = new TIntermBinary(op);
142 if (line == 0)
143 line = left->getLine();
144 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000146 TIntermTyped* child = addConversion(op, left->getType(), right);
147 if (child == 0)
148 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000150 node->setLeft(left);
151 node->setRight(child);
152 if (! node->promote(infoSink))
153 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000155 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156}
157
158//
159// Connect two nodes through an index operator, where the left node is the base
160// of an array or struct, and the right node is a direct or indirect offset.
161//
162// Returns the added node.
163// The caller should set the type of the returned node.
164//
165TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
166{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000167 TIntermBinary* node = new TIntermBinary(op);
168 if (line == 0)
169 line = index->getLine();
170 node->setLine(line);
171 node->setLeft(base);
172 node->setRight(index);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000174 // caller should set the type
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000175
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000176 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000177}
178
179//
180// Add one node as the parent of another that it operates on.
181//
182// Returns the added node.
183//
184TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable)
185{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000186 TIntermUnary* node;
187 TIntermTyped* child = childNode->getAsTyped();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000189 if (child == 0) {
190 infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
191 return 0;
192 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000194 switch (op) {
195 case EOpLogicalNot:
196 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
197 return 0;
198 }
199 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000201 case EOpPostIncrement:
202 case EOpPreIncrement:
203 case EOpPostDecrement:
204 case EOpPreDecrement:
205 case EOpNegative:
206 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
207 return 0;
208 default: break;
209 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000210
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000211 //
212 // Do we need to promote the operand?
213 //
214 // Note: Implicit promotions were removed from the language.
215 //
216 TBasicType newType = EbtVoid;
217 switch (op) {
218 case EOpConstructInt: newType = EbtInt; break;
219 case EOpConstructBool: newType = EbtBool; break;
220 case EOpConstructFloat: newType = EbtFloat; break;
221 default: break;
222 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000224 if (newType != EbtVoid) {
225 child = addConversion(op, TType(newType, EvqTemporary, child->getNominalSize(),
226 child->isMatrix(),
227 child->isArray()),
228 child);
229 if (child == 0)
230 return 0;
231 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000232
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000233 //
234 // For constructors, we are now done, it's all in the conversion.
235 //
236 switch (op) {
237 case EOpConstructInt:
238 case EOpConstructBool:
239 case EOpConstructFloat:
240 return child;
241 default: break;
242 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000243
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000244 TIntermConstantUnion *childTempConstant = 0;
245 if (child->getAsConstantUnion())
246 childTempConstant = child->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000247
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000248 //
249 // Make a new node for the operator.
250 //
251 node = new TIntermUnary(op);
252 if (line == 0)
253 line = child->getLine();
254 node->setLine(line);
255 node->setOperand(child);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000257 if (! node->promote(infoSink))
258 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000260 if (childTempConstant) {
261 TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000262
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000263 if (newChild)
264 return newChild;
265 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000266
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000267 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268}
269
270//
271// This is the safe way to change the operator on an aggregate, as it
272// does lots of error checking and fixing. Especially for establishing
273// a function call's operation on it's set of parameters. Sequences
274// of instructions are also aggregates, but they just direnctly set
275// their operator to EOpSequence.
276//
277// Returns an aggregate node, which could be the one passed in if
278// it was already an aggregate.
279//
280TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
281{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000282 TIntermAggregate* aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000284 //
285 // Make sure we have an aggregate. If not turn it into one.
286 //
287 if (node) {
288 aggNode = node->getAsAggregate();
289 if (aggNode == 0 || aggNode->getOp() != EOpNull) {
290 //
291 // Make an aggregate containing this node.
292 //
293 aggNode = new TIntermAggregate();
294 aggNode->getSequence().push_back(node);
295 if (line == 0)
296 line = node->getLine();
297 }
298 } else
299 aggNode = new TIntermAggregate();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000301 //
302 // Set the operator.
303 //
304 aggNode->setOperator(op);
305 if (line != 0)
306 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000308 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309}
310
311//
312// Convert one type to another.
313//
314// Returns the node representing the conversion, which could be the same
315// node passed in if no conversion was needed.
316//
317// Return 0 if a conversion can't be done.
318//
319TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
320{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000321 //
322 // Does the base type allow operation?
323 //
324 switch (node->getBasicType()) {
325 case EbtVoid:
326 case EbtSampler2D:
327 case EbtSamplerCube:
328 return 0;
329 default: break;
330 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000332 //
333 // Otherwise, if types are identical, no problem
334 //
335 if (type == node->getType())
336 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000338 //
339 // If one's a structure, then no conversions.
340 //
341 if (type.getStruct() || node->getType().getStruct())
342 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000344 //
345 // If one's an array, then no conversions.
346 //
347 if (type.isArray() || node->getType().isArray())
348 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000349
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000350 TBasicType promoteTo;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000351
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000352 switch (op) {
353 //
354 // Explicit conversions
355 //
356 case EOpConstructBool:
357 promoteTo = EbtBool;
358 break;
359 case EOpConstructFloat:
360 promoteTo = EbtFloat;
361 break;
362 case EOpConstructInt:
363 promoteTo = EbtInt;
364 break;
365 default:
366 //
367 // implicit conversions were removed from the language.
368 //
369 if (type.getBasicType() != node->getType().getBasicType())
370 return 0;
371 //
372 // Size and structure could still differ, but that's
373 // handled by operator promotion.
374 //
375 return node;
376 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000377
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000378 if (node->getAsConstantUnion()) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000379
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000380 return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
381 } else {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000383 //
384 // Add a new newNode for the conversion.
385 //
386 TIntermUnary* newNode = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000388 TOperator newOp = EOpNull;
389 switch (promoteTo) {
390 case EbtFloat:
391 switch (node->getBasicType()) {
392 case EbtInt: newOp = EOpConvIntToFloat; break;
393 case EbtBool: newOp = EOpConvBoolToFloat; break;
394 default:
395 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
396 return 0;
397 }
398 break;
399 case EbtBool:
400 switch (node->getBasicType()) {
401 case EbtInt: newOp = EOpConvIntToBool; break;
402 case EbtFloat: newOp = EOpConvFloatToBool; break;
403 default:
404 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
405 return 0;
406 }
407 break;
408 case EbtInt:
409 switch (node->getBasicType()) {
410 case EbtBool: newOp = EOpConvBoolToInt; break;
411 case EbtFloat: newOp = EOpConvFloatToInt; break;
412 default:
413 infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
414 return 0;
415 }
416 break;
417 default:
418 infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine());
419 return 0;
420 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000421
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000422 TType type(promoteTo, EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
423 newNode = new TIntermUnary(newOp, type);
424 newNode->setLine(node->getLine());
425 newNode->setOperand(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000427 return newNode;
428 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000429}
430
431//
432// Safe way to combine two nodes into an aggregate. Works with null pointers,
433// a node that's not a aggregate yet, etc.
434//
435// Returns the resulting aggregate, unless 0 was passed in for
436// both existing nodes.
437//
438TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
439{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000440 if (left == 0 && right == 0)
441 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000443 TIntermAggregate* aggNode = 0;
444 if (left)
445 aggNode = left->getAsAggregate();
446 if (!aggNode || aggNode->getOp() != EOpNull) {
447 aggNode = new TIntermAggregate;
448 if (left)
449 aggNode->getSequence().push_back(left);
450 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000451
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000452 if (right)
453 aggNode->getSequence().push_back(right);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000455 if (line != 0)
456 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000457
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000458 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459}
460
461//
462// Turn an existing node into an aggregate.
463//
464// Returns an aggregate, unless 0 was passed in for the existing node.
465//
466TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
467{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000468 if (node == 0)
469 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000470
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000471 TIntermAggregate* aggNode = new TIntermAggregate;
472 aggNode->getSequence().push_back(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000474 if (line != 0)
475 aggNode->setLine(line);
476 else
477 aggNode->setLine(node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000479 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000480}
481
482//
483// For "if" test nodes. There are three children; a condition,
484// a true path, and a false path. The two paths are in the
485// nodePair.
486//
487// Returns the selection node created.
488//
489TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
490{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000491 //
492 // For compile time constant selections, prune the code and
493 // test now.
494 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000496 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
497 if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
498 return nodePair.node1;
499 else
500 return nodePair.node2;
501 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000503 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
504 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000506 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000507}
508
509
510TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
511{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000512 if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
513 return right;
514 } else {
515 TIntermTyped *commaAggregate = growAggregate(left, right, line);
516 commaAggregate->getAsAggregate()->setOperator(EOpComma);
517 commaAggregate->setType(right->getType());
518 commaAggregate->getTypePointer()->changeQualifier(EvqTemporary);
519 return commaAggregate;
520 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521}
522
523//
524// For "?:" test nodes. There are three children; a condition,
525// a true path, and a false path. The two paths are specified
526// as separate parameters.
527//
528// Returns the selection node created, or 0 if one could not be.
529//
530TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
531{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000532 //
533 // Get compatible types.
534 //
535 TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
536 if (child)
537 falseBlock = child;
538 else {
539 child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
540 if (child)
541 trueBlock = child;
542 else
543 return 0;
544 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000546 //
547 // See if all the operands are constant, then fold it otherwise not.
548 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000549
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000550 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
551 if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
552 return trueBlock;
553 else
554 return falseBlock;
555 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000556
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000557 //
558 // Make a selection node.
559 //
560 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
561 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000563 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000564}
565
566//
567// Constant terminal nodes. Has a union that contains bool, float or int constants
568//
569// Returns the constant union node created.
570//
571
572TIntermConstantUnion* TIntermediate::addConstantUnion(constUnion* unionArrayPointer, const TType& t, TSourceLoc line)
573{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000574 TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
575 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000577 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578}
579
580TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
581{
582
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000583 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000585 node->setLine(line);
586 TIntermConstantUnion* constIntNode;
587 TIntermSequence &sequenceVector = node->getSequence();
588 constUnion* unionArray;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000589
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000590 for (int i = 0; i < fields.num; i++) {
591 unionArray = new constUnion[1];
592 unionArray->setIConst(fields.offsets[i]);
593 constIntNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), line);
594 sequenceVector.push_back(constIntNode);
595 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000596
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000597 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000598}
599
600//
601// Create loop nodes.
602//
603TIntermNode* TIntermediate::addLoop(TIntermNode *init, TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc line)
604{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000605 TIntermNode* node = new TIntermLoop(init, body, test, terminal, testFirst);
606 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000607
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000608 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000609}
610
611//
612// Add branches.
613//
614TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
615{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000616 return addBranch(branchOp, 0, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000617}
618
619TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
620{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000621 TIntermBranch* node = new TIntermBranch(branchOp, expression);
622 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000624 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000625}
626
627//
628// This is to be executed once the final root is put on top by the parsing
629// process.
630//
631bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language)
632{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000633 if (root == 0)
634 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000635
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000636 //
637 // First, finish off the top level sequence, if any
638 //
639 TIntermAggregate* aggRoot = root->getAsAggregate();
640 if (aggRoot && aggRoot->getOp() == EOpNull)
641 aggRoot->setOperator(EOpSequence);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000642
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000643 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000644}
645
646//
647// This deletes the tree.
648//
649void TIntermediate::remove(TIntermNode* root)
650{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000651 if (root)
652 RemoveAllTreeNodes(root);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000653}
654
655////////////////////////////////////////////////////////////////
656//
657// Member functions of the nodes used for building the tree.
658//
659////////////////////////////////////////////////////////////////
660
661//
662// Say whether or not an operation node changes the value of a variable.
663//
664// Returns true if state is modified.
665//
666bool TIntermOperator::modifiesState() const
667{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000668 switch (op) {
669 case EOpPostIncrement:
670 case EOpPostDecrement:
671 case EOpPreIncrement:
672 case EOpPreDecrement:
673 case EOpAssign:
674 case EOpAddAssign:
675 case EOpSubAssign:
676 case EOpMulAssign:
677 case EOpVectorTimesMatrixAssign:
678 case EOpVectorTimesScalarAssign:
679 case EOpMatrixTimesScalarAssign:
680 case EOpMatrixTimesMatrixAssign:
681 case EOpDivAssign:
682 return true;
683 default:
684 return false;
685 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000686}
687
688//
689// returns true if the operator is for one of the constructors
690//
691bool TIntermOperator::isConstructor() const
692{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000693 switch (op) {
694 case EOpConstructVec2:
695 case EOpConstructVec3:
696 case EOpConstructVec4:
697 case EOpConstructMat2:
698 case EOpConstructMat3:
699 case EOpConstructMat4:
700 case EOpConstructFloat:
701 case EOpConstructIVec2:
702 case EOpConstructIVec3:
703 case EOpConstructIVec4:
704 case EOpConstructInt:
705 case EOpConstructBVec2:
706 case EOpConstructBVec3:
707 case EOpConstructBVec4:
708 case EOpConstructBool:
709 case EOpConstructStruct:
710 return true;
711 default:
712 return false;
713 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000714}
715//
716// Make sure the type of a unary operator is appropriate for its
717// combination of operation and operand type.
718//
719// Returns false in nothing makes sense.
720//
721bool TIntermUnary::promote(TInfoSink&)
722{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000723 switch (op) {
724 case EOpLogicalNot:
725 if (operand->getBasicType() != EbtBool)
726 return false;
727 break;
728 case EOpNegative:
729 case EOpPostIncrement:
730 case EOpPostDecrement:
731 case EOpPreIncrement:
732 case EOpPreDecrement:
733 if (operand->getBasicType() == EbtBool)
734 return false;
735 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000736
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000737 // operators for built-ins are already type checked against their prototype
738 case EOpAny:
739 case EOpAll:
740 case EOpVectorLogicalNot:
741 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000742
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000743 default:
744 if (operand->getBasicType() != EbtFloat)
745 return false;
746 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000747
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000748 setType(operand->getType());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000749
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000750 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000751}
752
753//
754// Establishes the type of the resultant operation, as well as
755// makes the operator the correct one for the operands.
756//
757// Returns false if operator can't work on operands.
758//
759bool TIntermBinary::promote(TInfoSink& infoSink)
760{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000761 int size = left->getNominalSize();
762 if (right->getNominalSize() > size)
763 size = right->getNominalSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000764
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000765 TBasicType type = left->getBasicType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000766
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000767 //
768 // Arrays have to be exact matches.
769 //
770 if ((left->isArray() || right->isArray()) && (left->getType() != right->getType()))
771 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000772
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000773 //
774 // Base assumption: just make the type the same as the left
775 // operand. Then only deviations from this need be coded.
776 //
daniel@transgaming.comfe565152010-04-10 05:29:07 +0000777 setType(left->getType());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000778
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000779 //
780 // Array operations.
781 //
782 if (left->isArray()) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000783
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000784 switch (op) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000785
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000786 //
787 // Promote to conditional
788 //
789 case EOpEqual:
790 case EOpNotEqual:
791 setType(TType(EbtBool));
792 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000793
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000794 //
795 // Set array information.
796 //
797 case EOpAssign:
798 case EOpInitialize:
799 getTypePointer()->setArraySize(left->getType().getArraySize());
800 getTypePointer()->setArrayInformationType(left->getType().getArrayInformationType());
801 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000802
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000803 default:
804 return false;
805 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000806
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000807 return true;
808 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000809
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000810 //
811 // All scalars. Code after this test assumes this case is removed!
812 //
813 if (size == 1) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000814
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000815 switch (op) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000817 //
818 // Promote to conditional
819 //
820 case EOpEqual:
821 case EOpNotEqual:
822 case EOpLessThan:
823 case EOpGreaterThan:
824 case EOpLessThanEqual:
825 case EOpGreaterThanEqual:
826 setType(TType(EbtBool));
827 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000828
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000829 //
830 // And and Or operate on conditionals
831 //
832 case EOpLogicalAnd:
833 case EOpLogicalOr:
834 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
835 return false;
836 setType(TType(EbtBool));
837 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000838
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000839 //
840 // Everything else should have matching types
841 //
842 default:
843 if (left->getBasicType() != right->getBasicType() ||
844 left->isMatrix() != right->isMatrix())
845 return false;
846 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000847
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000848 return true;
849 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000850
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000851 //
852 // Are the sizes compatible?
853 //
854 if ( left->getNominalSize() != size && left->getNominalSize() != 1 ||
855 right->getNominalSize() != size && right->getNominalSize() != 1)
856 return false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000857
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000858 //
859 // Can these two operands be combined?
860 //
861 switch (op) {
862 case EOpMul:
863 if (!left->isMatrix() && right->isMatrix()) {
864 if (left->isVector())
865 op = EOpVectorTimesMatrix;
866 else {
867 op = EOpMatrixTimesScalar;
868 setType(TType(type, EvqTemporary, size, true));
869 }
870 } else if (left->isMatrix() && !right->isMatrix()) {
871 if (right->isVector()) {
872 op = EOpMatrixTimesVector;
873 setType(TType(type, EvqTemporary, size, false));
874 } else {
875 op = EOpMatrixTimesScalar;
876 }
877 } else if (left->isMatrix() && right->isMatrix()) {
878 op = EOpMatrixTimesMatrix;
879 } else if (!left->isMatrix() && !right->isMatrix()) {
880 if (left->isVector() && right->isVector()) {
881 // leave as component product
882 } else if (left->isVector() || right->isVector()) {
883 op = EOpVectorTimesScalar;
884 setType(TType(type, EvqTemporary, size, false));
885 }
886 } else {
887 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
888 return false;
889 }
890 break;
891 case EOpMulAssign:
892 if (!left->isMatrix() && right->isMatrix()) {
893 if (left->isVector())
894 op = EOpVectorTimesMatrixAssign;
895 else {
896 return false;
897 }
898 } else if (left->isMatrix() && !right->isMatrix()) {
899 if (right->isVector()) {
900 return false;
901 } else {
902 op = EOpMatrixTimesScalarAssign;
903 }
904 } else if (left->isMatrix() && right->isMatrix()) {
905 op = EOpMatrixTimesMatrixAssign;
906 } else if (!left->isMatrix() && !right->isMatrix()) {
907 if (left->isVector() && right->isVector()) {
908 // leave as component product
909 } else if (left->isVector() || right->isVector()) {
910 if (! left->isVector())
911 return false;
912 op = EOpVectorTimesScalarAssign;
913 setType(TType(type, EvqTemporary, size, false));
914 }
915 } else {
916 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
917 return false;
918 }
919 break;
920 case EOpAssign:
921 case EOpInitialize:
922 if (left->getNominalSize() != right->getNominalSize())
923 return false;
924 // fall through
925 case EOpAdd:
926 case EOpSub:
927 case EOpDiv:
928 case EOpAddAssign:
929 case EOpSubAssign:
930 case EOpDivAssign:
931 if (left->isMatrix() && right->isVector() ||
932 left->isVector() && right->isMatrix() ||
933 left->getBasicType() != right->getBasicType())
934 return false;
935 setType(TType(type, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
936 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000937
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000938 case EOpEqual:
939 case EOpNotEqual:
940 case EOpLessThan:
941 case EOpGreaterThan:
942 case EOpLessThanEqual:
943 case EOpGreaterThanEqual:
944 if (left->isMatrix() && right->isVector() ||
945 left->isVector() && right->isMatrix() ||
946 left->getBasicType() != right->getBasicType())
947 return false;
948 setType(TType(EbtBool));
949 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000950
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000951 default:
952 return false;
953 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000955 //
956 // One more check for assignment. The Resulting type has to match the left operand.
957 //
958 switch (op) {
959 case EOpAssign:
960 case EOpInitialize:
961 case EOpAddAssign:
962 case EOpSubAssign:
963 case EOpMulAssign:
964 case EOpDivAssign:
965 if (getType() != left->getType())
966 return false;
967 break;
968 default:
969 break;
970 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000971
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000972 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000973}
974
975bool CompareStruct(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray)
976{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000977 TTypeList* fields = leftNodeType.getStruct();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000978
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000979 size_t structSize = fields->size();
980 int index = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000981
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000982 for (size_t j = 0; j < structSize; j++) {
983 int size = (*fields)[j].type->getObjectSize();
984 for (int i = 0; i < size; i++) {
985 if ((*fields)[j].type->getBasicType() == EbtStruct) {
986 if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
987 return false;
988 } else {
989 if (leftUnionArray[index] != rightUnionArray[index])
990 return false;
991 index++;
992 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000993
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000994 }
995 }
996 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997}
998
999bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray)
1000{
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001001 if (leftNodeType.isArray()) {
1002 TType typeWithoutArrayness = leftNodeType;
1003 typeWithoutArrayness.clearArrayness();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001004
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001005 int arraySize = leftNodeType.getArraySize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001006
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001007 for (int i = 0; i < arraySize; ++i) {
1008 int offset = typeWithoutArrayness.getObjectSize() * i;
1009 if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1010 return false;
1011 }
1012 } else
1013 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001015 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001016}
1017
1018//
1019// The fold functions see if an operation on a constant can be done in place,
1020// without generating run-time code.
1021//
1022// Returns the node to keep using, which may or may not be the node passed in.
1023//
1024
1025TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1026{
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001027 constUnion *unionArray = getUnionArrayPointer();
1028 int objectSize = getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001030 if (constantNode) { // binary operations
1031 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1032 constUnion *rightUnionArray = node->getUnionArrayPointer();
1033 TType returnType = getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001034
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001035 // for a case like float f = 1.2 + vec4(2,3,4,5);
1036 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1037 rightUnionArray = new constUnion[objectSize];
1038 for (int i = 0; i < objectSize; ++i)
1039 rightUnionArray[i] = *node->getUnionArrayPointer();
1040 returnType = getType();
1041 } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1042 // for a case like float f = vec4(2,3,4,5) + 1.2;
1043 unionArray = new constUnion[constantNode->getType().getObjectSize()];
1044 for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
1045 unionArray[i] = *getUnionArrayPointer();
1046 returnType = node->getType();
1047 objectSize = constantNode->getType().getObjectSize();
1048 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001050 constUnion* tempConstArray = 0;
1051 TIntermConstantUnion *tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001052
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001053 bool boolNodeFlag = false;
1054 switch(op) {
1055 case EOpAdd:
1056 tempConstArray = new constUnion[objectSize];
1057 {// support MSVC++6.0
1058 for (int i = 0; i < objectSize; i++)
1059 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1060 }
1061 break;
1062 case EOpSub:
1063 tempConstArray = new constUnion[objectSize];
1064 {// support MSVC++6.0
1065 for (int i = 0; i < objectSize; i++)
1066 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1067 }
1068 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001070 case EOpMul:
1071 case EOpVectorTimesScalar:
1072 case EOpMatrixTimesScalar:
1073 tempConstArray = new constUnion[objectSize];
1074 {// support MSVC++6.0
1075 for (int i = 0; i < objectSize; i++)
1076 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1077 }
1078 break;
1079 case EOpMatrixTimesMatrix:
1080 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1081 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1082 return 0;
1083 }
1084 {// support MSVC++6.0
1085 int size = getNominalSize();
1086 tempConstArray = new constUnion[size*size];
1087 for (int row = 0; row < size; row++) {
1088 for (int column = 0; column < size; column++) {
1089 tempConstArray[size * column + row].setFConst(0.0f);
1090 for (int i = 0; i < size; i++) {
1091 tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
1092 }
1093 }
1094 }
1095 }
1096 break;
1097 case EOpDiv:
1098 tempConstArray = new constUnion[objectSize];
1099 {// support MSVC++6.0
1100 for (int i = 0; i < objectSize; i++) {
1101 switch (getType().getBasicType()) {
1102 case EbtFloat:
1103 if (rightUnionArray[i] == 0.0f) {
1104 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1105 tempConstArray[i].setFConst(FLT_MAX);
1106 } else
1107 tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1108 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001109
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001110 case EbtInt:
1111 if (rightUnionArray[i] == 0) {
1112 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1113 tempConstArray[i].setIConst(INT_MAX);
1114 } else
1115 tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1116 break;
1117 default:
1118 infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
1119 return 0;
1120 }
1121 }
1122 }
1123 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001124
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001125 case EOpMatrixTimesVector:
1126 if (node->getBasicType() != EbtFloat) {
1127 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
1128 return 0;
1129 }
1130 tempConstArray = new constUnion[getNominalSize()];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001132 {// support MSVC++6.0
1133 for (int size = getNominalSize(), i = 0; i < size; i++) {
1134 tempConstArray[i].setFConst(0.0f);
1135 for (int j = 0; j < size; j++) {
1136 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1137 }
1138 }
1139 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001140
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001141 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1142 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001143
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001144 return tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001146 case EOpVectorTimesMatrix:
1147 if (getType().getBasicType() != EbtFloat) {
1148 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
1149 return 0;
1150 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001151
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001152 tempConstArray = new constUnion[getNominalSize()];
1153 {// support MSVC++6.0
1154 for (int size = getNominalSize(), i = 0; i < size; i++) {
1155 tempConstArray[i].setFConst(0.0f);
1156 for (int j = 0; j < size; j++) {
1157 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1158 }
1159 }
1160 }
1161 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001162
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001163 case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1164 tempConstArray = new constUnion[objectSize];
1165 {// support MSVC++6.0
1166 for (int i = 0; i < objectSize; i++)
1167 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1168 }
1169 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001170
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001171 case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1172 tempConstArray = new constUnion[objectSize];
1173 {// support MSVC++6.0
1174 for (int i = 0; i < objectSize; i++)
1175 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1176 }
1177 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001178
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001179 case EOpLogicalXor:
1180 tempConstArray = new constUnion[objectSize];
1181 {// support MSVC++6.0
1182 for (int i = 0; i < objectSize; i++)
1183 switch (getType().getBasicType()) {
1184 case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1185 default: assert(false && "Default missing");
1186 }
1187 }
1188 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001189
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001190 case EOpLessThan:
1191 assert(objectSize == 1);
1192 tempConstArray = new constUnion[1];
1193 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1194 returnType = TType(EbtBool, EvqConst);
1195 break;
1196 case EOpGreaterThan:
1197 assert(objectSize == 1);
1198 tempConstArray = new constUnion[1];
1199 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1200 returnType = TType(EbtBool, EvqConst);
1201 break;
1202 case EOpLessThanEqual:
1203 {
1204 assert(objectSize == 1);
1205 constUnion constant;
1206 constant.setBConst(*unionArray > *rightUnionArray);
1207 tempConstArray = new constUnion[1];
1208 tempConstArray->setBConst(!constant.getBConst());
1209 returnType = TType(EbtBool, EvqConst);
1210 break;
1211 }
1212 case EOpGreaterThanEqual:
1213 {
1214 assert(objectSize == 1);
1215 constUnion constant;
1216 constant.setBConst(*unionArray < *rightUnionArray);
1217 tempConstArray = new constUnion[1];
1218 tempConstArray->setBConst(!constant.getBConst());
1219 returnType = TType(EbtBool, EvqConst);
1220 break;
1221 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001222
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001223 case EOpEqual:
1224 if (getType().getBasicType() == EbtStruct) {
1225 if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1226 boolNodeFlag = true;
1227 } else {
1228 for (int i = 0; i < objectSize; i++) {
1229 if (unionArray[i] != rightUnionArray[i]) {
1230 boolNodeFlag = true;
1231 break; // break out of for loop
1232 }
1233 }
1234 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001235
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001236 tempConstArray = new constUnion[1];
1237 if (!boolNodeFlag) {
1238 tempConstArray->setBConst(true);
1239 }
1240 else {
1241 tempConstArray->setBConst(false);
1242 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001243
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001244 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst));
1245 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001246
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001247 return tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001248
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001249 case EOpNotEqual:
1250 if (getType().getBasicType() == EbtStruct) {
1251 if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
1252 boolNodeFlag = true;
1253 } else {
1254 for (int i = 0; i < objectSize; i++) {
1255 if (unionArray[i] == rightUnionArray[i]) {
1256 boolNodeFlag = true;
1257 break; // break out of for loop
1258 }
1259 }
1260 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001261
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001262 tempConstArray = new constUnion[1];
1263 if (!boolNodeFlag) {
1264 tempConstArray->setBConst(true);
1265 }
1266 else {
1267 tempConstArray->setBConst(false);
1268 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001269
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001270 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst));
1271 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001272
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001273 return tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001274
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001275 default:
1276 infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
1277 return 0;
1278 }
1279 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1280 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001281
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001282 return tempNode;
1283 } else {
1284 //
1285 // Do unary operations
1286 //
1287 TIntermConstantUnion *newNode = 0;
1288 constUnion* tempConstArray = new constUnion[objectSize];
1289 for (int i = 0; i < objectSize; i++) {
1290 switch(op) {
1291 case EOpNegative:
1292 switch (getType().getBasicType()) {
1293 case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1294 case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1295 default:
1296 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1297 return 0;
1298 }
1299 break;
1300 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1301 switch (getType().getBasicType()) {
1302 case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1303 default:
1304 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1305 return 0;
1306 }
1307 break;
1308 default:
1309 return 0;
1310 }
1311 }
1312 newNode = new TIntermConstantUnion(tempConstArray, getType());
1313 newNode->setLine(getLine());
1314 return newNode;
1315 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001317 return this;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001318}
1319
1320TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1321{
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001322 constUnion *rightUnionArray = node->getUnionArrayPointer();
1323 int size = node->getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001324
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001325 constUnion *leftUnionArray = new constUnion[size];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001326
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001327 for (int i=0; i < size; i++) {
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001328
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001329 switch (promoteTo) {
1330 case EbtFloat:
1331 switch (node->getType().getBasicType()) {
1332 case EbtInt:
1333 leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst()));
1334 break;
1335 case EbtBool:
1336 leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst()));
1337 break;
1338 case EbtFloat:
1339 leftUnionArray[i] = rightUnionArray[i];
1340 break;
1341 default:
1342 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1343 return 0;
1344 }
1345 break;
1346 case EbtInt:
1347 switch (node->getType().getBasicType()) {
1348 case EbtInt:
1349 leftUnionArray[i] = rightUnionArray[i];
1350 break;
1351 case EbtBool:
1352 leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
1353 break;
1354 case EbtFloat:
1355 leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst()));
1356 break;
1357 default:
1358 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1359 return 0;
1360 }
1361 break;
1362 case EbtBool:
1363 switch (node->getType().getBasicType()) {
1364 case EbtInt:
1365 leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
1366 break;
1367 case EbtBool:
1368 leftUnionArray[i] = rightUnionArray[i];
1369 break;
1370 case EbtFloat:
1371 leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f);
1372 break;
1373 default:
1374 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1375 return 0;
1376 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001377
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001378 break;
1379 default:
1380 infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
1381 return 0;
1382 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001383
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001384 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001385
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001386 const TType& t = node->getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001387
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001388 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001389}
1390
1391void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
1392{
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001393 assert(!pragmaTable);
1394 pragmaTable = new TPragmaTable();
1395 *pragmaTable = pTable;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001396}