blob: fa0c9f7748918f7a789d52641086c7603af853dd [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// 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
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011#include <float.h>
alokp@chromium.org1bcc3fd2010-05-19 17:08:44 +000012#include <limits.h>
alokp@chromium.org32cfaf42010-08-23 21:01:13 +000013#include <algorithm>
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000014
Geoff Lang17732822013-08-29 13:46:49 -040015#include "compiler/translator/HashNames.h"
16#include "compiler/translator/localintermediate.h"
17#include "compiler/translator/QualifierAlive.h"
18#include "compiler/translator/RemoveTree.h"
19#include "compiler/translator/SymbolTable.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000020
Zhenyao Moe40d1e92014-07-16 17:40:36 -070021namespace
22{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023
Zhenyao Moe40d1e92014-07-16 17:40:36 -070024TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
Zhenyao Mo7cab38b2013-10-15 12:59:30 -070025{
daniel@transgaming.com9abe9562010-06-24 13:02:21 +000026 return left > right ? left : right;
daniel@transgaming.coma5d76232010-05-17 09:58:47 +000027}
alokp@chromium.org32cfaf42010-08-23 21:01:13 +000028
Zhenyao Moe40d1e92014-07-16 17:40:36 -070029bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
Zhenyao Mo7cab38b2013-10-15 12:59:30 -070030{
Zhenyao Moe40d1e92014-07-16 17:40:36 -070031 switch (op)
32 {
33 case EOpMul:
34 case EOpMulAssign:
35 return left.getNominalSize() == right.getNominalSize() &&
36 left.getSecondarySize() == right.getSecondarySize();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000037 case EOpVectorTimesScalar:
Zhenyao Moe40d1e92014-07-16 17:40:36 -070038 case EOpVectorTimesScalarAssign:
39 return true;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000040 case EOpVectorTimesMatrix:
Zhenyao Moe40d1e92014-07-16 17:40:36 -070041 return left.getNominalSize() == right.getRows();
42 case EOpVectorTimesMatrixAssign:
43 return left.getNominalSize() == right.getRows() &&
44 left.getNominalSize() == right.getCols();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000045 case EOpMatrixTimesVector:
Zhenyao Moe40d1e92014-07-16 17:40:36 -070046 return left.getCols() == right.getNominalSize();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000047 case EOpMatrixTimesScalar:
Zhenyao Moe40d1e92014-07-16 17:40:36 -070048 case EOpMatrixTimesScalarAssign:
49 return true;
50 case EOpMatrixTimesMatrix:
51 return left.getCols() == right.getRows();
52 case EOpMatrixTimesMatrixAssign:
53 return left.getCols() == right.getCols() &&
54 left.getRows() == right.getRows();
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000055
Zhenyao Moe40d1e92014-07-16 17:40:36 -070056 default:
57 UNREACHABLE();
58 return false;
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000059 }
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000060}
61
Zhenyao Moe40d1e92014-07-16 17:40:36 -070062bool CompareStructure(const TType& leftNodeType,
63 ConstantUnion *rightUnionArray,
64 ConstantUnion *leftUnionArray);
65
66bool CompareStruct(const TType &leftNodeType,
67 ConstantUnion *rightUnionArray,
68 ConstantUnion *leftUnionArray)
69{
70 const TFieldList &fields = leftNodeType.getStruct()->fields();
71
72 size_t structSize = fields.size();
73 size_t index = 0;
74
75 for (size_t j = 0; j < structSize; j++)
76 {
77 size_t size = fields[j]->type()->getObjectSize();
78 for (size_t i = 0; i < size; i++)
79 {
80 if (fields[j]->type()->getBasicType() == EbtStruct)
81 {
82 if (!CompareStructure(*fields[j]->type(),
83 &rightUnionArray[index],
84 &leftUnionArray[index]))
85 {
86 return false;
87 }
88 }
89 else
90 {
91 if (leftUnionArray[index] != rightUnionArray[index])
92 return false;
93 index++;
94 }
95 }
96 }
97 return true;
98}
99
100bool CompareStructure(const TType &leftNodeType,
101 ConstantUnion *rightUnionArray,
102 ConstantUnion *leftUnionArray)
103{
104 if (leftNodeType.isArray())
105 {
106 TType typeWithoutArrayness = leftNodeType;
107 typeWithoutArrayness.clearArrayness();
108
109 size_t arraySize = leftNodeType.getArraySize();
110
111 for (size_t i = 0; i < arraySize; ++i)
112 {
113 size_t offset = typeWithoutArrayness.getObjectSize() * i;
114 if (!CompareStruct(typeWithoutArrayness,
115 &rightUnionArray[offset],
116 &leftUnionArray[offset]))
117 {
118 return false;
119 }
120 }
121 }
122 else
123 {
124 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
125 }
126 return true;
127}
128
129} // namespace anonymous
130
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131////////////////////////////////////////////////////////////////////////////
132//
133// First set of functions are to help build the intermediate representation.
134// These functions are not member functions of the nodes.
135// They are called from parser productions.
136//
137/////////////////////////////////////////////////////////////////////////////
138
139//
140// Add a terminal node for an identifier in an expression.
141//
142// Returns the added node.
143//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700144TIntermSymbol *TIntermediate::addSymbol(
145 int id, const TString &name, const TType &type, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000146{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700147 TIntermSymbol *node = new TIntermSymbol(id, name, type);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000148 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000150 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151}
152
153//
154// Connect two nodes with a new parent that does a binary operation on the nodes.
155//
156// Returns the added node.
157//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700158TIntermTyped *TIntermediate::addBinaryMath(
159 TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700161 switch (op)
162 {
163 case EOpEqual:
164 case EOpNotEqual:
165 if (left->isArray())
166 return NULL;
167 break;
168 case EOpLessThan:
169 case EOpGreaterThan:
170 case EOpLessThanEqual:
171 case EOpGreaterThanEqual:
172 if (left->isMatrix() || left->isArray() || left->isVector() ||
173 left->getBasicType() == EbtStruct)
174 {
175 return NULL;
176 }
177 break;
178 case EOpLogicalOr:
179 case EOpLogicalXor:
180 case EOpLogicalAnd:
181 if (left->getBasicType() != EbtBool ||
182 left->isMatrix() || left->isArray() || left->isVector())
183 {
184 return NULL;
185 }
186 break;
187 case EOpAdd:
188 case EOpSub:
189 case EOpDiv:
190 case EOpMul:
191 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
192 return NULL;
193 default:
194 break;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000195 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400197 if (left->getBasicType() != right->getBasicType())
198 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700199 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000200 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000202 //
203 // Need a new node holding things together then. Make
204 // one and promote it to the right type.
205 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700206 TIntermBinary *node = new TIntermBinary(op);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000207 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000208
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000209 node->setLeft(left);
210 node->setRight(right);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700211 if (!node->promote(mInfoSink))
212 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000213
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000214 //
215 // See if we can fold constants.
216 //
alokp@chromium.org8f0f24a2010-09-01 21:06:24 +0000217 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
218 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700219 if (leftTempConstant && rightTempConstant)
220 {
221 TIntermTyped *typedReturnNode =
222 leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000224 if (typedReturnNode)
225 return typedReturnNode;
226 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000227
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000228 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000229}
230
231//
232// Connect two nodes through an assignment.
233//
234// Returns the added node.
235//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700236TIntermTyped *TIntermediate::addAssign(
237 TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000238{
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400239 if (left->getType().getStruct() || right->getType().getStruct())
240 {
241 if (left->getType() != right->getType())
242 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700243 return NULL;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400244 }
245 }
246
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700247 TIntermBinary *node = new TIntermBinary(op);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000248 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000249
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000250 node->setLeft(left);
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400251 node->setRight(right);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700252 if (!node->promote(mInfoSink))
253 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000254
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000255 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000256}
257
258//
259// Connect two nodes through an index operator, where the left node is the base
260// of an array or struct, and the right node is a direct or indirect offset.
261//
262// Returns the added node.
263// The caller should set the type of the returned node.
264//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700265TIntermTyped *TIntermediate::addIndex(
266 TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700268 TIntermBinary *node = new TIntermBinary(op);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000269 node->setLine(line);
270 node->setLeft(base);
271 node->setRight(index);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000273 // caller should set the type
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000274
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000275 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276}
277
278//
279// Add one node as the parent of another that it operates on.
280//
281// Returns the added node.
282//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700283TIntermTyped *TIntermediate::addUnaryMath(
284 TOperator op, TIntermNode *childNode, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000285{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700286 TIntermUnary *node;
287 TIntermTyped *child = childNode->getAsTyped();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700289 if (child == NULL)
290 {
291 mInfoSink.info.message(EPrefixInternalError, line,
292 "Bad type in AddUnaryMath");
293 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000294 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000295
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700296 switch (op)
297 {
298 case EOpLogicalNot:
299 if (child->getType().getBasicType() != EbtBool ||
300 child->getType().isMatrix() ||
301 child->getType().isArray() ||
302 child->getType().isVector())
303 {
304 return NULL;
305 }
306 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700308 case EOpPostIncrement:
309 case EOpPreIncrement:
310 case EOpPostDecrement:
311 case EOpPreDecrement:
312 case EOpNegative:
313 if (child->getType().getBasicType() == EbtStruct ||
314 child->getType().isArray())
315 {
316 return NULL;
317 }
318 default:
319 break;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000320 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000321
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000322 TIntermConstantUnion *childTempConstant = 0;
323 if (child->getAsConstantUnion())
324 childTempConstant = child->getAsConstantUnion();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000326 //
327 // Make a new node for the operator.
328 //
329 node = new TIntermUnary(op);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000330 node->setLine(line);
331 node->setOperand(child);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000332
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700333 if (!node->promote(mInfoSink))
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000334 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700336 if (childTempConstant)
337 {
338 TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000339
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000340 if (newChild)
341 return newChild;
342 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000344 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345}
346
347//
348// This is the safe way to change the operator on an aggregate, as it
349// does lots of error checking and fixing. Especially for establishing
350// a function call's operation on it's set of parameters. Sequences
351// of instructions are also aggregates, but they just direnctly set
352// their operator to EOpSequence.
353//
354// Returns an aggregate node, which could be the one passed in if
daniel@transgaming.com978702d2012-04-04 15:05:58 +0000355// it was already an aggregate but no operator was set.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000356//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700357TIntermAggregate *TIntermediate::setAggregateOperator(
358 TIntermNode *node, TOperator op, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000359{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700360 TIntermAggregate *aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000362 //
363 // Make sure we have an aggregate. If not turn it into one.
364 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700365 if (node)
366 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000367 aggNode = node->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700368 if (aggNode == NULL || aggNode->getOp() != EOpNull)
369 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000370 //
371 // Make an aggregate containing this node.
372 //
373 aggNode = new TIntermAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700374 aggNode->getSequence()->push_back(node);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000375 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700376 }
377 else
378 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000379 aggNode = new TIntermAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700380 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000382 //
383 // Set the operator.
384 //
alokp@chromium.org58e54292010-08-24 21:40:03 +0000385 aggNode->setOp(op);
Jamie Madill075edd82013-07-08 13:30:19 -0400386 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000387
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000388 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000389}
390
391//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392// Safe way to combine two nodes into an aggregate. Works with null pointers,
393// a node that's not a aggregate yet, etc.
394//
395// Returns the resulting aggregate, unless 0 was passed in for
396// both existing nodes.
397//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700398TIntermAggregate *TIntermediate::growAggregate(
399 TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700401 if (left == NULL && right == NULL)
402 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000403
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700404 TIntermAggregate *aggNode = NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000405 if (left)
406 aggNode = left->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700407 if (!aggNode || aggNode->getOp() != EOpNull)
408 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000409 aggNode = new TIntermAggregate;
410 if (left)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700411 aggNode->getSequence()->push_back(left);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000412 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000414 if (right)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700415 aggNode->getSequence()->push_back(right);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000416
Jamie Madill075edd82013-07-08 13:30:19 -0400417 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000419 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000420}
421
422//
423// Turn an existing node into an aggregate.
424//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700425// Returns an aggregate, unless NULL was passed in for the existing node.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700427TIntermAggregate *TIntermediate::makeAggregate(
428 TIntermNode *node, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000429{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700430 if (node == NULL)
431 return NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000432
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700433 TIntermAggregate *aggNode = new TIntermAggregate;
434 aggNode->getSequence()->push_back(node);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435
Jamie Madill075edd82013-07-08 13:30:19 -0400436 aggNode->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000438 return aggNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439}
440
441//
442// For "if" test nodes. There are three children; a condition,
443// a true path, and a false path. The two paths are in the
444// nodePair.
445//
446// Returns the selection node created.
447//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700448TIntermNode *TIntermediate::addSelection(
449 TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000451 //
452 // For compile time constant selections, prune the code and
453 // test now.
454 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700456 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion())
457 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000458 if (cond->getAsConstantUnion()->getBConst(0) == true)
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700459 {
460 return nodePair.node1 ? setAggregateOperator(
461 nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
462 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000463 else
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700464 {
465 return nodePair.node2 ? setAggregateOperator(
466 nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
467 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000468 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000469
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700470 TIntermSelection *node = new TIntermSelection(
471 cond, nodePair.node1, nodePair.node2);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000472 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000473
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000474 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475}
476
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700477TIntermTyped *TIntermediate::addComma(
478 TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000479{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700480 if (left->getType().getQualifier() == EvqConst &&
481 right->getType().getQualifier() == EvqConst)
482 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000483 return right;
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700484 }
485 else
486 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000487 TIntermTyped *commaAggregate = growAggregate(left, right, line);
alokp@chromium.org58e54292010-08-24 21:40:03 +0000488 commaAggregate->getAsAggregate()->setOp(EOpComma);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000489 commaAggregate->setType(right->getType());
alokp@chromium.org58e54292010-08-24 21:40:03 +0000490 commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000491 return commaAggregate;
492 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000493}
494
495//
496// For "?:" test nodes. There are three children; a condition,
497// a true path, and a false path. The two paths are specified
498// as separate parameters.
499//
500// Returns the selection node created, or 0 if one could not be.
501//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700502TIntermTyped *TIntermediate::addSelection(
503 TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
504 const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700506 if (!cond || !trueBlock || !falseBlock ||
507 trueBlock->getType() != falseBlock->getType())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400508 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700509 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000510 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000511
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000512 //
513 // See if all the operands are constant, then fold it otherwise not.
514 //
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000515
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700516 if (cond->getAsConstantUnion() &&
517 trueBlock->getAsConstantUnion() &&
518 falseBlock->getAsConstantUnion())
519 {
shannon.woods%transgaming.com@gtempaccount.comc0d0c222013-04-13 03:29:36 +0000520 if (cond->getAsConstantUnion()->getBConst(0))
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000521 return trueBlock;
522 else
523 return falseBlock;
524 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000525
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000526 //
527 // Make a selection node.
528 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700529 TIntermSelection *node = new TIntermSelection(
530 cond, trueBlock, falseBlock, trueBlock->getType());
daniel@transgaming.com43affc52012-03-28 14:55:39 +0000531 node->getTypePointer()->setQualifier(EvqTemporary);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000532 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000533
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000534 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000535}
536
537//
538// Constant terminal nodes. Has a union that contains bool, float or int constants
539//
540// Returns the constant union node created.
541//
542
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700543TIntermConstantUnion *TIntermediate::addConstantUnion(
544 ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700546 TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000547 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000548
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000549 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000550}
551
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700552TIntermTyped *TIntermediate::addSwizzle(
553 TVectorFields &fields, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000554{
555
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700556 TIntermAggregate *node = new TIntermAggregate(EOpSequence);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000557
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000558 node->setLine(line);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700559 TIntermConstantUnion *constIntNode;
560 TIntermSequence *sequenceVector = node->getSequence();
561 ConstantUnion *unionArray;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700563 for (int i = 0; i < fields.num; i++)
564 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +0000565 unionArray = new ConstantUnion[1];
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000566 unionArray->setIConst(fields.offsets[i]);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700567 constIntNode = addConstantUnion(
568 unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
569 sequenceVector->push_back(constIntNode);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000570 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000571
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000572 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000573}
574
575//
576// Create loop nodes.
577//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700578TIntermNode *TIntermediate::addLoop(
579 TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
580 TIntermNode *body, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000581{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700582 TIntermNode *node = new TIntermLoop(type, init, cond, expr, body);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000583 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000584
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000585 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000586}
587
588//
589// Add branches.
590//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700591TIntermBranch* TIntermediate::addBranch(
592 TOperator branchOp, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000593{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000594 return addBranch(branchOp, 0, line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000595}
596
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700597TIntermBranch* TIntermediate::addBranch(
598 TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700600 TIntermBranch *node = new TIntermBranch(branchOp, expression);
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000601 node->setLine(line);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000602
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000603 return node;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000604}
605
606//
607// This is to be executed once the final root is put on top by the parsing
608// process.
609//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700610bool TIntermediate::postProcess(TIntermNode *root)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000611{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700612 if (root == NULL)
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000613 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000614
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000615 //
616 // First, finish off the top level sequence, if any
617 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700618 TIntermAggregate *aggRoot = root->getAsAggregate();
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000619 if (aggRoot && aggRoot->getOp() == EOpNull)
alokp@chromium.org58e54292010-08-24 21:40:03 +0000620 aggRoot->setOp(EOpSequence);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000621
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000622 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000623}
624
625//
626// This deletes the tree.
627//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700628void TIntermediate::remove(TIntermNode *root)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000629{
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000630 if (root)
631 RemoveAllTreeNodes(root);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632}
633
634////////////////////////////////////////////////////////////////
635//
636// Member functions of the nodes used for building the tree.
637//
638////////////////////////////////////////////////////////////////
639
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700640#define REPLACE_IF_IS(node, type, original, replacement) \
641 if (node == original) { \
642 node = static_cast<type *>(replacement); \
643 return true; \
644 }
645
646bool TIntermLoop::replaceChildNode(
647 TIntermNode *original, TIntermNode *replacement)
648{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700649 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
650 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
651 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
652 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700653 return false;
654}
655
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700656void TIntermLoop::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400657{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700658 if (mInit)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400659 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700660 nodeQueue->push(mInit);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400661 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700662 if (mCond)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400663 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700664 nodeQueue->push(mCond);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400665 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700666 if (mExpr)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400667 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700668 nodeQueue->push(mExpr);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400669 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700670 if (mBody)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400671 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700672 nodeQueue->push(mBody);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400673 }
674}
675
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700676bool TIntermBranch::replaceChildNode(
677 TIntermNode *original, TIntermNode *replacement)
678{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700679 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700680 return false;
681}
682
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700683void TIntermBranch::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400684{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700685 if (mExpression)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400686 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700687 nodeQueue->push(mExpression);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400688 }
689}
690
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700691bool TIntermBinary::replaceChildNode(
692 TIntermNode *original, TIntermNode *replacement)
693{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700694 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
695 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700696 return false;
697}
698
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700699void TIntermBinary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400700{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700701 if (mLeft)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400702 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700703 nodeQueue->push(mLeft);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400704 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700705 if (mRight)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400706 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700707 nodeQueue->push(mRight);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400708 }
709}
710
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700711bool TIntermUnary::replaceChildNode(
712 TIntermNode *original, TIntermNode *replacement)
713{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700714 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700715 return false;
716}
717
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700718void TIntermUnary::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400719{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700720 if (mOperand)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400721 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700722 nodeQueue->push(mOperand);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400723 }
724}
725
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700726bool TIntermAggregate::replaceChildNode(
727 TIntermNode *original, TIntermNode *replacement)
728{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700729 for (size_t ii = 0; ii < mSequence.size(); ++ii)
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700730 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700731 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700732 }
733 return false;
734}
735
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700736void TIntermAggregate::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400737{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700738 for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400739 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700740 nodeQueue->push(mSequence[childIndex]);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400741 }
742}
743
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700744bool TIntermSelection::replaceChildNode(
745 TIntermNode *original, TIntermNode *replacement)
746{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700747 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
748 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
749 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700750 return false;
751}
752
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700753void TIntermSelection::enqueueChildren(std::queue<TIntermNode *> *nodeQueue) const
Jamie Madilldd0d3422014-03-26 14:01:56 -0400754{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700755 if (mCondition)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400756 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700757 nodeQueue->push(mCondition);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400758 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700759 if (mTrueBlock)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400760 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700761 nodeQueue->push(mTrueBlock);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400762 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700763 if (mFalseBlock)
Jamie Madilldd0d3422014-03-26 14:01:56 -0400764 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700765 nodeQueue->push(mFalseBlock);
Jamie Madilldd0d3422014-03-26 14:01:56 -0400766 }
767}
768
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000769//
770// Say whether or not an operation node changes the value of a variable.
771//
Jamie Madillf4b79ba2013-11-26 10:38:18 -0500772bool TIntermOperator::isAssignment() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000773{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700774 switch (mOp)
775 {
776 case EOpPostIncrement:
777 case EOpPostDecrement:
778 case EOpPreIncrement:
779 case EOpPreDecrement:
780 case EOpAssign:
781 case EOpAddAssign:
782 case EOpSubAssign:
783 case EOpMulAssign:
784 case EOpVectorTimesMatrixAssign:
785 case EOpVectorTimesScalarAssign:
786 case EOpMatrixTimesScalarAssign:
787 case EOpMatrixTimesMatrixAssign:
788 case EOpDivAssign:
789 return true;
790 default:
791 return false;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000792 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000793}
794
795//
796// returns true if the operator is for one of the constructors
797//
798bool TIntermOperator::isConstructor() const
799{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700800 switch (mOp)
801 {
802 case EOpConstructVec2:
803 case EOpConstructVec3:
804 case EOpConstructVec4:
805 case EOpConstructMat2:
806 case EOpConstructMat3:
807 case EOpConstructMat4:
808 case EOpConstructFloat:
809 case EOpConstructIVec2:
810 case EOpConstructIVec3:
811 case EOpConstructIVec4:
812 case EOpConstructInt:
813 case EOpConstructUVec2:
814 case EOpConstructUVec3:
815 case EOpConstructUVec4:
816 case EOpConstructUInt:
817 case EOpConstructBVec2:
818 case EOpConstructBVec3:
819 case EOpConstructBVec4:
820 case EOpConstructBool:
821 case EOpConstructStruct:
822 return true;
823 default:
824 return false;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000825 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000826}
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700827
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000828//
829// Make sure the type of a unary operator is appropriate for its
830// combination of operation and operand type.
831//
832// Returns false in nothing makes sense.
833//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700834bool TIntermUnary::promote(TInfoSink &)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835{
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700836 switch (mOp)
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000837 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700838 case EOpLogicalNot:
839 if (mOperand->getBasicType() != EbtBool)
840 return false;
841 break;
842 case EOpNegative:
843 case EOpPostIncrement:
844 case EOpPostDecrement:
845 case EOpPreIncrement:
846 case EOpPreDecrement:
847 if (mOperand->getBasicType() == EbtBool)
848 return false;
849 break;
850
851 // operators for built-ins are already type checked against their prototype
852 case EOpAny:
853 case EOpAll:
854 case EOpVectorLogicalNot:
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000855 return true;
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000856
857 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700858 if (mOperand->getBasicType() != EbtFloat)
859 return false;
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000860 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700861
862 setType(mOperand->getType());
863 mType.setQualifier(EvqTemporary);
864
865 return true;
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000866}
867
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000868//
869// Establishes the type of the resultant operation, as well as
870// makes the operator the correct one for the operands.
871//
872// Returns false if operator can't work on operands.
873//
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700874bool TIntermBinary::promote(TInfoSink &infoSink)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000875{
alokp@chromium.org8f0f24a2010-09-01 21:06:24 +0000876 // This function only handles scalars, vectors, and matrices.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700877 if (mLeft->isArray() || mRight->isArray())
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000878 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700879 infoSink.info.message(EPrefixInternalError, getLine(),
880 "Invalid operation for arrays");
alokp@chromium.org8f0f24a2010-09-01 21:06:24 +0000881 return false;
882 }
883
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000884 // GLSL ES 2.0 does not support implicit type casting.
885 // So the basic type should always match.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700886 if (mLeft->getBasicType() != mRight->getBasicType())
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400887 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000888 return false;
Nicolas Capens6ed8d8a2014-06-11 11:25:20 -0400889 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000890
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000891 //
892 // Base assumption: just make the type the same as the left
893 // operand. Then only deviations from this need be coded.
894 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700895 setType(mLeft->getType());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000896
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000897 // The result gets promoted to the highest precision.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700898 TPrecision higherPrecision = GetHigherPrecision(
899 mLeft->getPrecision(), mRight->getPrecision());
alokp@chromium.org58e54292010-08-24 21:40:03 +0000900 getTypePointer()->setPrecision(higherPrecision);
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000901
902 // Binary operations results in temporary variables unless both
903 // operands are const.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700904 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000905 {
alokp@chromium.org58e54292010-08-24 21:40:03 +0000906 getTypePointer()->setQualifier(EvqTemporary);
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000907 }
daniel@transgaming.coma5d76232010-05-17 09:58:47 +0000908
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700909 const int nominalSize =
910 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000911
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000912 //
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000913 // All scalars or structs. Code after this test assumes this case is removed!
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000914 //
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000915 if (nominalSize == 1)
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000916 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700917 switch (mOp)
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000918 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700919 //
920 // Promote to conditional
921 //
922 case EOpEqual:
923 case EOpNotEqual:
924 case EOpLessThan:
925 case EOpGreaterThan:
926 case EOpLessThanEqual:
927 case EOpGreaterThanEqual:
928 setType(TType(EbtBool, EbpUndefined));
929 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000930
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700931 //
932 // And and Or operate on conditionals
933 //
934 case EOpLogicalAnd:
935 case EOpLogicalOr:
936 // Both operands must be of type bool.
937 if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
938 {
939 return false;
940 }
941 setType(TType(EbtBool, EbpUndefined));
942 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000943
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700944 default:
945 break;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000946 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000947 return true;
948 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000949
alokp@chromium.org32cfaf42010-08-23 21:01:13 +0000950 // If we reach here, at least one of the operands is vector or matrix.
951 // The other operand could be a scalar, vector, or matrix.
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000952 // Can these two operands be combined?
953 //
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700954 TBasicType basicType = mLeft->getBasicType();
955 switch (mOp)
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000956 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700957 case EOpMul:
958 if (!mLeft->isMatrix() && mRight->isMatrix())
959 {
960 if (mLeft->isVector())
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000961 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700962 mOp = EOpVectorTimesMatrix;
963 setType(TType(basicType, higherPrecision, EvqTemporary,
964 mRight->getCols(), 1));
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000965 }
966 else
967 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700968 mOp = EOpMatrixTimesScalar;
969 setType(TType(basicType, higherPrecision, EvqTemporary,
970 mRight->getCols(), mRight->getRows()));
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000971 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700972 }
973 else if (mLeft->isMatrix() && !mRight->isMatrix())
974 {
975 if (mRight->isVector())
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000976 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700977 mOp = EOpMatrixTimesVector;
978 setType(TType(basicType, higherPrecision, EvqTemporary,
979 mLeft->getRows(), 1));
shannonwoods@chromium.orgb7dc4032013-05-30 00:18:18 +0000980 }
981 else
982 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700983 mOp = EOpMatrixTimesScalar;
alokp@chromium.org2cf17712010-03-30 20:33:18 +0000984 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700985 }
986 else if (mLeft->isMatrix() && mRight->isMatrix())
987 {
988 mOp = EOpMatrixTimesMatrix;
989 setType(TType(basicType, higherPrecision, EvqTemporary,
990 mRight->getCols(), mLeft->getRows()));
991 }
992 else if (!mLeft->isMatrix() && !mRight->isMatrix())
993 {
994 if (mLeft->isVector() && mRight->isVector())
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000995 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700996 // leave as component product
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000997 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700998 else if (mLeft->isVector() || mRight->isVector())
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +0000999 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001000 mOp = EOpVectorTimesScalar;
1001 setType(TType(basicType, higherPrecision, EvqTemporary,
1002 nominalSize, 1));
shannonwoods@chromium.org09e09882013-05-30 00:18:25 +00001003 }
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001004 }
1005 else
1006 {
1007 infoSink.info.message(EPrefixInternalError, getLine(),
1008 "Missing elses");
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001009 return false;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001010 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001012 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
1013 {
1014 return false;
1015 }
1016 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001018 case EOpMulAssign:
1019 if (!mLeft->isMatrix() && mRight->isMatrix())
1020 {
1021 if (mLeft->isVector())
1022 {
1023 mOp = EOpVectorTimesMatrixAssign;
1024 }
1025 else
1026 {
1027 return false;
1028 }
1029 }
1030 else if (mLeft->isMatrix() && !mRight->isMatrix())
1031 {
1032 if (mRight->isVector())
1033 {
1034 return false;
1035 }
1036 else
1037 {
1038 mOp = EOpMatrixTimesScalarAssign;
1039 }
1040 }
1041 else if (mLeft->isMatrix() && mRight->isMatrix())
1042 {
1043 mOp = EOpMatrixTimesMatrixAssign;
1044 setType(TType(basicType, higherPrecision, EvqTemporary,
1045 mRight->getCols(), mLeft->getRows()));
1046 }
1047 else if (!mLeft->isMatrix() && !mRight->isMatrix())
1048 {
1049 if (mLeft->isVector() && mRight->isVector())
1050 {
1051 // leave as component product
1052 }
1053 else if (mLeft->isVector() || mRight->isVector())
1054 {
1055 if (!mLeft->isVector())
1056 return false;
1057 mOp = EOpVectorTimesScalarAssign;
1058 setType(TType(basicType, higherPrecision, EvqTemporary,
1059 mLeft->getNominalSize(), 1));
1060 }
1061 }
1062 else
1063 {
1064 infoSink.info.message(EPrefixInternalError, getLine(),
1065 "Missing elses");
1066 return false;
1067 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001069 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
1070 {
1071 return false;
1072 }
1073 break;
1074
1075 case EOpAssign:
1076 case EOpInitialize:
1077 case EOpAdd:
1078 case EOpSub:
1079 case EOpDiv:
1080 case EOpAddAssign:
1081 case EOpSubAssign:
1082 case EOpDivAssign:
1083 if ((mLeft->isMatrix() && mRight->isVector()) ||
1084 (mLeft->isVector() && mRight->isMatrix()))
1085 {
1086 return false;
1087 }
1088
1089 // Are the sizes compatible?
1090 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
1091 mLeft->getSecondarySize() != mRight->getSecondarySize())
1092 {
1093 // If the nominal size of operands do not match:
1094 // One of them must be scalar.
1095 if (!mLeft->isScalar() && !mRight->isScalar())
1096 return false;
1097
1098 // Operator cannot be of type pure assignment.
1099 if (mOp == EOpAssign || mOp == EOpInitialize)
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001100 return false;
1101 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001102
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001103 {
1104 const int secondarySize = std::max(
1105 mLeft->getSecondarySize(), mRight->getSecondarySize());
1106 setType(TType(basicType, higherPrecision, EvqTemporary,
1107 nominalSize, secondarySize));
1108 }
1109 break;
1110
1111 case EOpEqual:
1112 case EOpNotEqual:
1113 case EOpLessThan:
1114 case EOpGreaterThan:
1115 case EOpLessThanEqual:
1116 case EOpGreaterThanEqual:
1117 if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
1118 (mLeft->getSecondarySize() != mRight->getSecondarySize()))
1119 {
1120 return false;
1121 }
1122 setType(TType(EbtBool, EbpUndefined));
1123 break;
1124
1125 default:
1126 return false;
1127 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001128 return true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001129}
1130
1131//
1132// The fold functions see if an operation on a constant can be done in place,
1133// without generating run-time code.
1134//
1135// Returns the node to keep using, which may or may not be the node passed in.
1136//
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001137TIntermTyped *TIntermConstantUnion::fold(
1138 TOperator op, TIntermTyped *constantNode, TInfoSink &infoSink)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139{
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001140 ConstantUnion *unionArray = getUnionArrayPointer();
Nicolas Capensbd0ea9c2014-03-04 13:53:29 -05001141
1142 if (!unionArray)
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001143 return NULL;
Nicolas Capensbd0ea9c2014-03-04 13:53:29 -05001144
Jamie Madill94bf7f22013-07-08 13:31:15 -04001145 size_t objectSize = getType().getObjectSize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001146
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001147 if (constantNode)
1148 {
1149 // binary operations
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001150 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001151 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001152 TType returnType = getType();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001153
Nicolas Capensbd0ea9c2014-03-04 13:53:29 -05001154 if (!rightUnionArray)
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001155 return NULL;
Nicolas Capensbd0ea9c2014-03-04 13:53:29 -05001156
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001157 // for a case like float f = 1.2 + vec4(2,3,4,5);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001158 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1)
1159 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001160 rightUnionArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001161 for (size_t i = 0; i < objectSize; ++i)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001162 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001163 rightUnionArray[i] = *node->getUnionArrayPointer();
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001164 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001165 returnType = getType();
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001166 }
1167 else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1)
1168 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001169 // for a case like float f = vec4(2,3,4,5) + 1.2;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001170 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001171 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001172 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001173 unionArray[i] = *getUnionArrayPointer();
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001174 }
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001175 returnType = node->getType();
1176 objectSize = constantNode->getType().getObjectSize();
1177 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001178
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001179 ConstantUnion *tempConstArray = NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001180 TIntermConstantUnion *tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001181
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001182 bool boolNodeFlag = false;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001183 switch(op)
1184 {
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001185 case EOpAdd:
1186 tempConstArray = new ConstantUnion[objectSize];
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001187 for (size_t i = 0; i < objectSize; i++)
1188 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001189 break;
1190 case EOpSub:
1191 tempConstArray = new ConstantUnion[objectSize];
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001192 for (size_t i = 0; i < objectSize; i++)
1193 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001194 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001195
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001196 case EOpMul:
1197 case EOpVectorTimesScalar:
1198 case EOpMatrixTimesScalar:
1199 tempConstArray = new ConstantUnion[objectSize];
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001200 for (size_t i = 0; i < objectSize; i++)
1201 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001202 break;
1203
1204 case EOpMatrixTimesMatrix:
1205 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001206 if (getType().getBasicType() != EbtFloat ||
1207 node->getBasicType() != EbtFloat)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001208 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001209 infoSink.info.message(
1210 EPrefixInternalError, getLine(),
1211 "Constant Folding cannot be done for matrix multiply");
1212 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001213 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001214
Shannon Woods3841b8e2013-09-10 18:23:12 -04001215 const int leftCols = getCols();
1216 const int leftRows = getRows();
1217 const int rightCols = constantNode->getType().getCols();
1218 const int rightRows = constantNode->getType().getRows();
1219 const int resultCols = rightCols;
1220 const int resultRows = leftRows;
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001221
1222 tempConstArray = new ConstantUnion[resultCols*resultRows];
1223 for (int row = 0; row < resultRows; row++)
1224 {
1225 for (int column = 0; column < resultCols; column++)
1226 {
1227 tempConstArray[resultRows * column + row].setFConst(0.0f);
1228 for (int i = 0; i < leftCols; i++)
1229 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001230 tempConstArray[resultRows * column + row].setFConst(
1231 tempConstArray[resultRows * column + row].getFConst() +
1232 unionArray[i * leftRows + row].getFConst() *
1233 rightUnionArray[column * rightRows + i].getFConst());
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001234 }
1235 }
1236 }
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001237
1238 // update return type for matrix product
1239 returnType.setPrimarySize(resultCols);
1240 returnType.setSecondarySize(resultRows);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001241 }
1242 break;
1243
1244 case EOpDiv:
1245 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001246 tempConstArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001247 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001248 {
1249 switch (getType().getBasicType())
1250 {
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001251 case EbtFloat:
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001252 if (rightUnionArray[i] == 0.0f)
1253 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001254 infoSink.info.message(
1255 EPrefixWarning, getLine(),
1256 "Divide by zero error during constant folding");
1257 tempConstArray[i].setFConst(
1258 unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001259 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001260 else
1261 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001262 tempConstArray[i].setFConst(
1263 unionArray[i].getFConst() /
1264 rightUnionArray[i].getFConst());
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001265 }
1266 break;
1267
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001268 case EbtInt:
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001269 if (rightUnionArray[i] == 0)
1270 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001271 infoSink.info.message(
1272 EPrefixWarning, getLine(),
1273 "Divide by zero error during constant folding");
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001274 tempConstArray[i].setIConst(INT_MAX);
1275 }
1276 else
1277 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001278 tempConstArray[i].setIConst(
1279 unionArray[i].getIConst() /
1280 rightUnionArray[i].getIConst());
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001281 }
1282 break;
1283
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001284 case EbtUInt:
1285 if (rightUnionArray[i] == 0)
1286 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001287 infoSink.info.message(
1288 EPrefixWarning, getLine(),
1289 "Divide by zero error during constant folding");
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001290 tempConstArray[i].setUConst(UINT_MAX);
1291 }
1292 else
1293 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001294 tempConstArray[i].setUConst(
1295 unionArray[i].getUConst() /
1296 rightUnionArray[i].getUConst());
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +00001297 }
1298 break;
1299
1300 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001301 infoSink.info.message(
1302 EPrefixInternalError, getLine(),
1303 "Constant folding cannot be done for \"/\"");
1304 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001305 }
1306 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001307 }
1308 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001309
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001310 case EOpMatrixTimesVector:
1311 {
1312 if (node->getBasicType() != EbtFloat)
1313 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001314 infoSink.info.message(
1315 EPrefixInternalError, getLine(),
1316 "Constant Folding cannot be done for matrix times vector");
1317 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001318 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001319
Shannon Woods3841b8e2013-09-10 18:23:12 -04001320 const int matrixCols = getCols();
1321 const int matrixRows = getRows();
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001322
1323 tempConstArray = new ConstantUnion[matrixRows];
1324
1325 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1326 {
1327 tempConstArray[matrixRow].setFConst(0.0f);
1328 for (int col = 0; col < matrixCols; col++)
1329 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001330 tempConstArray[matrixRow].setFConst(
1331 tempConstArray[matrixRow].getFConst() +
1332 unionArray[col * matrixRows + matrixRow].getFConst() *
1333 rightUnionArray[col].getFConst());
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001334 }
1335 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001336
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001337 returnType = node->getType();
1338 returnType.setPrimarySize(matrixRows);
1339
1340 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001341 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001342
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001343 return tempNode;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001344 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001345
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001346 case EOpVectorTimesMatrix:
1347 {
1348 if (getType().getBasicType() != EbtFloat)
1349 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001350 infoSink.info.message(
1351 EPrefixInternalError, getLine(),
1352 "Constant Folding cannot be done for vector times matrix");
1353 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001354 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001355
Shannon Woods3841b8e2013-09-10 18:23:12 -04001356 const int matrixCols = constantNode->getType().getCols();
1357 const int matrixRows = constantNode->getType().getRows();
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001358
1359 tempConstArray = new ConstantUnion[matrixCols];
1360
1361 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001362 {
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001363 tempConstArray[matrixCol].setFConst(0.0f);
1364 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001365 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001366 tempConstArray[matrixCol].setFConst(
1367 tempConstArray[matrixCol].getFConst() +
1368 unionArray[matrixRow].getFConst() *
1369 rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst());
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001370 }
1371 }
shannonwoods@chromium.org50733332013-05-30 00:19:07 +00001372
1373 returnType.setPrimarySize(matrixCols);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001374 }
1375 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001376
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001377 case EOpLogicalAnd:
1378 // this code is written for possible future use,
1379 // will not get executed currently
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001380 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001381 tempConstArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001382 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001383 {
1384 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001385 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001386 }
1387 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001388
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001389 case EOpLogicalOr:
1390 // this code is written for possible future use,
1391 // will not get executed currently
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001392 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001393 tempConstArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001394 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001395 {
1396 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001397 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001398 }
1399 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001400
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001401 case EOpLogicalXor:
1402 {
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001403 tempConstArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001404 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001405 {
1406 switch (getType().getBasicType())
1407 {
1408 case EbtBool:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001409 tempConstArray[i].setBConst(
1410 unionArray[i] == rightUnionArray[i] ? false : true);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001411 break;
1412 default:
1413 UNREACHABLE();
1414 break;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001415 }
1416 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001417 }
1418 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001419
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001420 case EOpLessThan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001421 ASSERT(objectSize == 1);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001422 tempConstArray = new ConstantUnion[1];
1423 tempConstArray->setBConst(*unionArray < *rightUnionArray);
1424 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1425 break;
1426
1427 case EOpGreaterThan:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001428 ASSERT(objectSize == 1);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001429 tempConstArray = new ConstantUnion[1];
1430 tempConstArray->setBConst(*unionArray > *rightUnionArray);
1431 returnType = TType(EbtBool, EbpUndefined, EvqConst);
1432 break;
1433
1434 case EOpLessThanEqual:
1435 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001436 ASSERT(objectSize == 1);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001437 ConstantUnion constant;
1438 constant.setBConst(*unionArray > *rightUnionArray);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001439 tempConstArray = new ConstantUnion[1];
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001440 tempConstArray->setBConst(!constant.getBConst());
daniel@transgaming.coma5d76232010-05-17 09:58:47 +00001441 returnType = TType(EbtBool, EbpUndefined, EvqConst);
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001442 break;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001443 }
1444
1445 case EOpGreaterThanEqual:
1446 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001447 ASSERT(objectSize == 1);
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001448 ConstantUnion constant;
1449 constant.setBConst(*unionArray < *rightUnionArray);
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001450 tempConstArray = new ConstantUnion[1];
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001451 tempConstArray->setBConst(!constant.getBConst());
daniel@transgaming.coma5d76232010-05-17 09:58:47 +00001452 returnType = TType(EbtBool, EbpUndefined, EvqConst);
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001453 break;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001454 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001455
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001456 case EOpEqual:
1457 if (getType().getBasicType() == EbtStruct)
1458 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001459 if (!CompareStructure(node->getType(),
1460 node->getUnionArrayPointer(),
1461 unionArray))
1462 {
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001463 boolNodeFlag = true;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001464 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001465 }
1466 else
1467 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001468 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001469 {
1470 if (unionArray[i] != rightUnionArray[i])
1471 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001472 boolNodeFlag = true;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001473 break; // break out of for loop
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001474 }
1475 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001476 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001477
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001478 tempConstArray = new ConstantUnion[1];
1479 if (!boolNodeFlag)
1480 {
1481 tempConstArray->setBConst(true);
1482 }
1483 else
1484 {
1485 tempConstArray->setBConst(false);
1486 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001487
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001488 tempNode = new TIntermConstantUnion(
1489 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001490 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001491
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001492 return tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001494 case EOpNotEqual:
1495 if (getType().getBasicType() == EbtStruct)
1496 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001497 if (CompareStructure(node->getType(),
1498 node->getUnionArrayPointer(),
1499 unionArray))
1500 {
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001501 boolNodeFlag = true;
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001502 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001503 }
1504 else
1505 {
Jamie Madill94bf7f22013-07-08 13:31:15 -04001506 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001507 {
1508 if (unionArray[i] == rightUnionArray[i])
1509 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001510 boolNodeFlag = true;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001511 break; // break out of for loop
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001512 }
1513 }
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001514 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001515
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001516 tempConstArray = new ConstantUnion[1];
1517 if (!boolNodeFlag)
1518 {
1519 tempConstArray->setBConst(true);
1520 }
1521 else
1522 {
1523 tempConstArray->setBConst(false);
1524 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001525
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001526 tempNode = new TIntermConstantUnion(
1527 tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001528 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001529
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001530 return tempNode;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001531
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001532 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001533 infoSink.info.message(
1534 EPrefixInternalError, getLine(),
1535 "Invalid operator for constant folding");
1536 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001537 }
1538 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1539 tempNode->setLine(getLine());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001540
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001541 return tempNode;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001542 }
1543 else
1544 {
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001545 //
1546 // Do unary operations
1547 //
1548 TIntermConstantUnion *newNode = 0;
alokp@chromium.org6ff56fd2010-05-05 16:37:50 +00001549 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
Jamie Madill94bf7f22013-07-08 13:31:15 -04001550 for (size_t i = 0; i < objectSize; i++)
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001551 {
1552 switch(op)
1553 {
1554 case EOpNegative:
1555 switch (getType().getBasicType())
1556 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001557 case EbtFloat:
1558 tempConstArray[i].setFConst(-unionArray[i].getFConst());
1559 break;
1560 case EbtInt:
1561 tempConstArray[i].setIConst(-unionArray[i].getIConst());
1562 break;
1563 case EbtUInt:
1564 tempConstArray[i].setUConst(static_cast<unsigned int>(
1565 -static_cast<int>(unionArray[i].getUConst())));
1566 break;
Nicolas Capensc0f7c612013-06-05 11:46:09 -04001567 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001568 infoSink.info.message(
1569 EPrefixInternalError, getLine(),
1570 "Unary operation not folded into constant");
1571 return NULL;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001572 }
1573 break;
1574
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001575 case EOpLogicalNot:
1576 // this code is written for possible future use,
1577 // will not get executed currently
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001578 switch (getType().getBasicType())
1579 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001580 case EbtBool:
1581 tempConstArray[i].setBConst(!unionArray[i].getBConst());
1582 break;
Nicolas Capensc0f7c612013-06-05 11:46:09 -04001583 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001584 infoSink.info.message(
1585 EPrefixInternalError, getLine(),
1586 "Unary operation not folded into constant");
1587 return NULL;
shannonwoods@chromium.org9fc85b12013-05-30 00:19:00 +00001588 }
1589 break;
1590
1591 default:
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001592 return NULL;
alokp@chromium.org2cf17712010-03-30 20:33:18 +00001593 }
1594 }
1595 newNode = new TIntermConstantUnion(tempConstArray, getType());
1596 newNode->setLine(getLine());
1597 return newNode;
1598 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001599}
1600
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001601// static
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001602TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001603{
1604 if (hashFunction == NULL || name.empty())
1605 return name;
1606 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
1607 TStringStream stream;
1608 stream << HASHED_NAME_PREFIX << std::hex << number;
1609 TString hashedName = stream.str();
1610 return hashedName;
1611}