blob: dbbfb19f0a64d3d6b9ada19b51dd69b8eccd90cb [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
John Bauman66b8ab22014-05-06 15:57:45 -04002//
Nicolas Capens0bac2852016-05-07 06:09:58 -04003// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
John Bauman66b8ab22014-05-06 15:57:45 -04006//
Nicolas Capens0bac2852016-05-07 06:09:58 -04007// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
John Bauman66b8ab22014-05-06 15:57:45 -040014
15//
16// Build the intermediate representation.
17//
18
19#include <float.h>
20#include <limits.h>
21#include <algorithm>
22
Nicolas Capenscc863da2015-01-21 15:50:55 -050023#include "localintermediate.h"
24#include "SymbolTable.h"
Alexis Hetu2ce222c2016-05-02 11:20:52 -040025#include "Common/Math.hpp"
John Bauman66b8ab22014-05-06 15:57:45 -040026
27bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
28
29static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
Nicolas Capens0bac2852016-05-07 06:09:58 -040030 return left > right ? left : right;
John Bauman66b8ab22014-05-06 15:57:45 -040031}
32
Alexis Hetu00106d42015-04-23 11:45:35 -040033static bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
34{
35 switch(op)
36 {
37 case EOpMul:
38 case EOpMulAssign:
39 return left.getNominalSize() == right.getNominalSize() &&
40 left.getSecondarySize() == right.getSecondarySize();
41 case EOpVectorTimesScalar:
42 case EOpVectorTimesScalarAssign:
43 return true;
44 case EOpVectorTimesMatrix:
45 return left.getNominalSize() == right.getSecondarySize();
46 case EOpVectorTimesMatrixAssign:
47 return left.getNominalSize() == right.getSecondarySize() &&
48 left.getNominalSize() == right.getNominalSize();
49 case EOpMatrixTimesVector:
50 return left.getNominalSize() == right.getNominalSize();
51 case EOpMatrixTimesScalar:
52 case EOpMatrixTimesScalarAssign:
53 return true;
54 case EOpMatrixTimesMatrix:
55 return left.getNominalSize() == right.getSecondarySize();
56 case EOpMatrixTimesMatrixAssign:
57 return left.getNominalSize() == right.getNominalSize() &&
58 left.getSecondarySize() == right.getSecondarySize();
59 default:
Nicolas Capens3713cd42015-06-22 10:41:54 -040060 UNREACHABLE(op);
Alexis Hetu00106d42015-04-23 11:45:35 -040061 return false;
62 }
63}
64
John Bauman66b8ab22014-05-06 15:57:45 -040065const char* getOperatorString(TOperator op) {
Nicolas Capens0bac2852016-05-07 06:09:58 -040066 switch (op) {
67 case EOpInitialize: return "=";
68 case EOpAssign: return "=";
69 case EOpAddAssign: return "+=";
70 case EOpSubAssign: return "-=";
71 case EOpDivAssign: return "/=";
72 case EOpIModAssign: return "%=";
73 case EOpBitShiftLeftAssign: return "<<=";
74 case EOpBitShiftRightAssign: return ">>=";
75 case EOpBitwiseAndAssign: return "&=";
76 case EOpBitwiseXorAssign: return "^=";
77 case EOpBitwiseOrAssign: return "|=";
John Bauman66b8ab22014-05-06 15:57:45 -040078
Nicolas Capens0bac2852016-05-07 06:09:58 -040079 // Fall-through.
80 case EOpMulAssign:
81 case EOpVectorTimesMatrixAssign:
82 case EOpVectorTimesScalarAssign:
83 case EOpMatrixTimesScalarAssign:
84 case EOpMatrixTimesMatrixAssign: return "*=";
John Bauman66b8ab22014-05-06 15:57:45 -040085
Nicolas Capens0bac2852016-05-07 06:09:58 -040086 // Fall-through.
87 case EOpIndexDirect:
88 case EOpIndexIndirect: return "[]";
John Bauman66b8ab22014-05-06 15:57:45 -040089
Nicolas Capens0bac2852016-05-07 06:09:58 -040090 case EOpIndexDirectStruct: return ".";
91 case EOpVectorSwizzle: return ".";
92 case EOpAdd: return "+";
93 case EOpSub: return "-";
94 case EOpMul: return "*";
95 case EOpDiv: return "/";
96 case EOpMod: UNIMPLEMENTED(); break;
97 case EOpEqual: return "==";
98 case EOpNotEqual: return "!=";
99 case EOpLessThan: return "<";
100 case EOpGreaterThan: return ">";
101 case EOpLessThanEqual: return "<=";
102 case EOpGreaterThanEqual: return ">=";
John Bauman66b8ab22014-05-06 15:57:45 -0400103
Nicolas Capens0bac2852016-05-07 06:09:58 -0400104 // Fall-through.
105 case EOpVectorTimesScalar:
106 case EOpVectorTimesMatrix:
107 case EOpMatrixTimesVector:
108 case EOpMatrixTimesScalar:
109 case EOpMatrixTimesMatrix: return "*";
John Bauman66b8ab22014-05-06 15:57:45 -0400110
Nicolas Capens0bac2852016-05-07 06:09:58 -0400111 case EOpLogicalOr: return "||";
112 case EOpLogicalXor: return "^^";
113 case EOpLogicalAnd: return "&&";
114 case EOpIMod: return "%";
115 case EOpBitShiftLeft: return "<<";
116 case EOpBitShiftRight: return ">>";
117 case EOpBitwiseAnd: return "&";
118 case EOpBitwiseXor: return "^";
119 case EOpBitwiseOr: return "|";
120 case EOpNegative: return "-";
121 case EOpVectorLogicalNot: return "not";
122 case EOpLogicalNot: return "!";
123 case EOpBitwiseNot: return "~";
124 case EOpPostIncrement: return "++";
125 case EOpPostDecrement: return "--";
126 case EOpPreIncrement: return "++";
127 case EOpPreDecrement: return "--";
John Bauman66b8ab22014-05-06 15:57:45 -0400128
Nicolas Capens0bac2852016-05-07 06:09:58 -0400129 case EOpRadians: return "radians";
130 case EOpDegrees: return "degrees";
131 case EOpSin: return "sin";
132 case EOpCos: return "cos";
133 case EOpTan: return "tan";
134 case EOpAsin: return "asin";
135 case EOpAcos: return "acos";
136 case EOpAtan: return "atan";
137 case EOpSinh: return "sinh";
138 case EOpCosh: return "cosh";
139 case EOpTanh: return "tanh";
140 case EOpAsinh: return "asinh";
141 case EOpAcosh: return "acosh";
142 case EOpAtanh: return "atanh";
143 case EOpExp: return "exp";
144 case EOpLog: return "log";
145 case EOpExp2: return "exp2";
146 case EOpLog2: return "log2";
147 case EOpSqrt: return "sqrt";
148 case EOpInverseSqrt: return "inversesqrt";
149 case EOpAbs: return "abs";
150 case EOpSign: return "sign";
151 case EOpFloor: return "floor";
152 case EOpTrunc: return "trunc";
153 case EOpRound: return "round";
154 case EOpRoundEven: return "roundEven";
155 case EOpCeil: return "ceil";
156 case EOpFract: return "fract";
157 case EOpLength: return "length";
158 case EOpNormalize: return "normalize";
159 case EOpDFdx: return "dFdx";
160 case EOpDFdy: return "dFdy";
161 case EOpFwidth: return "fwidth";
162 case EOpAny: return "any";
163 case EOpAll: return "all";
164 case EOpIsNan: return "isnan";
165 case EOpIsInf: return "isinf";
166 case EOpOuterProduct: return "outerProduct";
167 case EOpTranspose: return "transpose";
168 case EOpDeterminant: return "determinant";
169 case EOpInverse: return "inverse";
John Bauman66b8ab22014-05-06 15:57:45 -0400170
Nicolas Capens0bac2852016-05-07 06:09:58 -0400171 default: break;
172 }
173 return "";
John Bauman66b8ab22014-05-06 15:57:45 -0400174}
175
176////////////////////////////////////////////////////////////////////////////
177//
178// First set of functions are to help build the intermediate representation.
179// These functions are not member functions of the nodes.
180// They are called from parser productions.
181//
182/////////////////////////////////////////////////////////////////////////////
183
184//
185// Add a terminal node for an identifier in an expression.
186//
187// Returns the added node.
188//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400189TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400190{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400191 TIntermSymbol* node = new TIntermSymbol(id, name, type);
192 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400193
Nicolas Capens0bac2852016-05-07 06:09:58 -0400194 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400195}
196
197//
198// Connect two nodes with a new parent that does a binary operation on the nodes.
199//
200// Returns the added node.
201//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400202TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400203{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400204 bool isBitShift = false;
205 switch (op) {
206 case EOpEqual:
207 case EOpNotEqual:
208 if (left->isArray())
209 return 0;
210 break;
211 case EOpLessThan:
212 case EOpGreaterThan:
213 case EOpLessThanEqual:
214 case EOpGreaterThanEqual:
215 if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
216 return 0;
217 }
218 break;
219 case EOpLogicalOr:
220 case EOpLogicalXor:
221 case EOpLogicalAnd:
222 if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
223 return 0;
224 }
225 break;
226 case EOpBitwiseOr:
227 case EOpBitwiseXor:
228 case EOpBitwiseAnd:
229 if (!IsInteger(left->getBasicType()) || left->isMatrix() || left->isArray()) {
230 return 0;
231 }
232 break;
233 case EOpAdd:
234 case EOpSub:
235 case EOpDiv:
236 case EOpMul:
237 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) {
238 return 0;
239 }
240 break;
241 case EOpIMod:
242 // Note that this is only for the % operator, not for mod()
243 if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) {
244 return 0;
245 }
246 break;
247 case EOpBitShiftLeft:
248 case EOpBitShiftRight:
249 case EOpBitShiftLeftAssign:
250 case EOpBitShiftRightAssign:
251 // Unsigned can be bit-shifted by signed and vice versa, but we need to
252 // check that the basic type is an integer type.
253 isBitShift = true;
254 if(!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType()))
255 {
256 return 0;
257 }
258 break;
259 default: break;
260 }
John Bauman66b8ab22014-05-06 15:57:45 -0400261
Nicolas Capens0bac2852016-05-07 06:09:58 -0400262 if(!isBitShift && left->getBasicType() != right->getBasicType())
263 {
264 return 0;
265 }
John Bauman66b8ab22014-05-06 15:57:45 -0400266
Nicolas Capens0bac2852016-05-07 06:09:58 -0400267 //
268 // Need a new node holding things together then. Make
269 // one and promote it to the right type.
270 //
271 TIntermBinary* node = new TIntermBinary(op);
272 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400273
Nicolas Capens0bac2852016-05-07 06:09:58 -0400274 node->setLeft(left);
275 node->setRight(right);
276 if (!node->promote(infoSink))
277 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400278
Nicolas Capens0bac2852016-05-07 06:09:58 -0400279 //
280 // See if we can fold constants.
281 //
282 TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
283 TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
284 if (leftTempConstant && rightTempConstant) {
285 TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400286
Nicolas Capens0bac2852016-05-07 06:09:58 -0400287 if (typedReturnNode)
288 return typedReturnNode;
289 }
John Bauman66b8ab22014-05-06 15:57:45 -0400290
Nicolas Capens0bac2852016-05-07 06:09:58 -0400291 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400292}
293
294//
295// Connect two nodes through an assignment.
296//
297// Returns the added node.
298//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400299TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400300{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400301 if (left->getType().getStruct() || right->getType().getStruct())
302 {
303 if (left->getType() != right->getType())
304 {
305 return 0;
306 }
307 }
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400308
Nicolas Capens0bac2852016-05-07 06:09:58 -0400309 TIntermBinary* node = new TIntermBinary(op);
310 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400311
Nicolas Capens0bac2852016-05-07 06:09:58 -0400312 node->setLeft(left);
313 node->setRight(right);
314 if (! node->promote(infoSink))
315 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400316
Nicolas Capens0bac2852016-05-07 06:09:58 -0400317 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400318}
319
320//
321// Connect two nodes through an index operator, where the left node is the base
322// of an array or struct, and the right node is a direct or indirect offset.
323//
324// Returns the added node.
325// The caller should set the type of the returned node.
326//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400327TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400328{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400329 TIntermBinary* node = new TIntermBinary(op);
330 node->setLine(line);
331 node->setLeft(base);
332 node->setRight(index);
John Bauman66b8ab22014-05-06 15:57:45 -0400333
Nicolas Capens0bac2852016-05-07 06:09:58 -0400334 // caller should set the type
John Bauman66b8ab22014-05-06 15:57:45 -0400335
Nicolas Capens0bac2852016-05-07 06:09:58 -0400336 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400337}
338
339//
340// Add one node as the parent of another that it operates on.
341//
342// Returns the added node.
343//
Nicolas Capensd3d9b9c2016-04-10 01:53:59 -0400344TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, const TSourceLoc &line, const TType *funcReturnType)
John Bauman66b8ab22014-05-06 15:57:45 -0400345{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400346 if (child == 0) {
347 infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
348 return 0;
349 }
John Bauman66b8ab22014-05-06 15:57:45 -0400350
Nicolas Capens0bac2852016-05-07 06:09:58 -0400351 switch (op) {
352 case EOpBitwiseNot:
353 if (!IsInteger(child->getType().getBasicType()) || child->getType().isMatrix() || child->getType().isArray()) {
354 return 0;
355 }
356 break;
Alexis Hetud061e422015-05-13 16:37:50 -0400357
Nicolas Capens0bac2852016-05-07 06:09:58 -0400358 case EOpLogicalNot:
359 if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
360 return 0;
361 }
362 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400363
Nicolas Capens0bac2852016-05-07 06:09:58 -0400364 case EOpPostIncrement:
365 case EOpPreIncrement:
366 case EOpPostDecrement:
367 case EOpPreDecrement:
368 case EOpNegative:
369 if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
370 return 0;
371 default: break;
372 }
John Bauman66b8ab22014-05-06 15:57:45 -0400373
Nicolas Capens0bac2852016-05-07 06:09:58 -0400374 TIntermConstantUnion *childTempConstant = 0;
375 if (child->getAsConstantUnion())
376 childTempConstant = child->getAsConstantUnion();
John Bauman66b8ab22014-05-06 15:57:45 -0400377
Nicolas Capens0bac2852016-05-07 06:09:58 -0400378 //
379 // Make a new node for the operator.
380 //
381 TIntermUnary *node = new TIntermUnary(op);
382 node->setLine(line);
383 node->setOperand(child);
John Bauman66b8ab22014-05-06 15:57:45 -0400384
Nicolas Capens0bac2852016-05-07 06:09:58 -0400385 if (! node->promote(infoSink, funcReturnType))
386 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400387
Nicolas Capens0bac2852016-05-07 06:09:58 -0400388 if (childTempConstant) {
389 TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
John Bauman66b8ab22014-05-06 15:57:45 -0400390
Nicolas Capens0bac2852016-05-07 06:09:58 -0400391 if (newChild)
392 return newChild;
393 }
John Bauman66b8ab22014-05-06 15:57:45 -0400394
Nicolas Capens0bac2852016-05-07 06:09:58 -0400395 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400396}
397
398//
399// This is the safe way to change the operator on an aggregate, as it
400// does lots of error checking and fixing. Especially for establishing
401// a function call's operation on it's set of parameters. Sequences
402// of instructions are also aggregates, but they just direnctly set
403// their operator to EOpSequence.
404//
405// Returns an aggregate node, which could be the one passed in if
406// it was already an aggregate but no operator was set.
407//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400408TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400409{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400410 TIntermAggregate* aggNode;
John Bauman66b8ab22014-05-06 15:57:45 -0400411
Nicolas Capens0bac2852016-05-07 06:09:58 -0400412 //
413 // Make sure we have an aggregate. If not turn it into one.
414 //
415 if (node) {
416 aggNode = node->getAsAggregate();
417 if (aggNode == 0 || aggNode->getOp() != EOpNull) {
418 //
419 // Make an aggregate containing this node.
420 //
421 aggNode = new TIntermAggregate();
422 aggNode->getSequence().push_back(node);
423 }
424 } else
425 aggNode = new TIntermAggregate();
John Bauman66b8ab22014-05-06 15:57:45 -0400426
Nicolas Capens0bac2852016-05-07 06:09:58 -0400427 //
428 // Set the operator.
429 //
430 aggNode->setOp(op);
John Bauman66b8ab22014-05-06 15:57:45 -0400431
Nicolas Capens0bac2852016-05-07 06:09:58 -0400432 return aggNode;
John Bauman66b8ab22014-05-06 15:57:45 -0400433}
434
435//
John Bauman66b8ab22014-05-06 15:57:45 -0400436// Safe way to combine two nodes into an aggregate. Works with null pointers,
437// a node that's not a aggregate yet, etc.
438//
439// Returns the resulting aggregate, unless 0 was passed in for
440// both existing nodes.
441//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400442TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400443{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400444 if (left == 0 && right == 0)
445 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400446
Nicolas Capens0bac2852016-05-07 06:09:58 -0400447 TIntermAggregate* aggNode = 0;
448 if (left)
449 aggNode = left->getAsAggregate();
450 if (!aggNode || aggNode->getOp() != EOpNull) {
451 aggNode = new TIntermAggregate;
452 if (left)
453 aggNode->getSequence().push_back(left);
454 }
John Bauman66b8ab22014-05-06 15:57:45 -0400455
Nicolas Capens0bac2852016-05-07 06:09:58 -0400456 if (right)
457 aggNode->getSequence().push_back(right);
John Bauman66b8ab22014-05-06 15:57:45 -0400458
Nicolas Capens0bac2852016-05-07 06:09:58 -0400459 aggNode->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400460
Nicolas Capens0bac2852016-05-07 06:09:58 -0400461 return aggNode;
John Bauman66b8ab22014-05-06 15:57:45 -0400462}
463
464//
465// Turn an existing node into an aggregate.
466//
467// Returns an aggregate, unless 0 was passed in for the existing node.
468//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400469TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400470{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400471 if (node == 0)
472 return 0;
John Bauman66b8ab22014-05-06 15:57:45 -0400473
Nicolas Capens0bac2852016-05-07 06:09:58 -0400474 TIntermAggregate* aggNode = new TIntermAggregate;
475 aggNode->getSequence().push_back(node);
John Bauman66b8ab22014-05-06 15:57:45 -0400476
Nicolas Capens0bac2852016-05-07 06:09:58 -0400477 aggNode->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400478
Nicolas Capens0bac2852016-05-07 06:09:58 -0400479 return aggNode;
John Bauman66b8ab22014-05-06 15:57:45 -0400480}
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//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400489TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400490{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400491 //
492 // For compile time constant selections, prune the code and
493 // test now.
494 //
John Bauman66b8ab22014-05-06 15:57:45 -0400495
Nicolas Capens0bac2852016-05-07 06:09:58 -0400496 if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
497 if (cond->getAsConstantUnion()->getBConst(0) == true)
498 return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : nullptr;
499 else
500 return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : nullptr;
501 }
John Bauman66b8ab22014-05-06 15:57:45 -0400502
Nicolas Capens0bac2852016-05-07 06:09:58 -0400503 TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
504 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400505
Nicolas Capens0bac2852016-05-07 06:09:58 -0400506 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400507}
508
509
Alexis Hetu253fdd12015-07-07 15:12:46 -0400510TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400511{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400512 if (left->getType().getQualifier() == EvqConstExpr && right->getType().getQualifier() == EvqConstExpr) {
513 return right;
514 } else {
515 TIntermTyped *commaAggregate = growAggregate(left, right, line);
516 commaAggregate->getAsAggregate()->setOp(EOpComma);
517 commaAggregate->setType(right->getType());
518 commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
519 return commaAggregate;
520 }
John Bauman66b8ab22014-05-06 15:57:45 -0400521}
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//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400530TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400531{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400532 if (trueBlock->getType() != falseBlock->getType())
533 {
534 return 0;
535 }
John Bauman66b8ab22014-05-06 15:57:45 -0400536
Nicolas Capens0bac2852016-05-07 06:09:58 -0400537 //
538 // See if all the operands are constant, then fold it otherwise not.
539 //
John Bauman66b8ab22014-05-06 15:57:45 -0400540
Nicolas Capens0bac2852016-05-07 06:09:58 -0400541 if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
542 if (cond->getAsConstantUnion()->getBConst(0))
543 return trueBlock;
544 else
545 return falseBlock;
546 }
John Bauman66b8ab22014-05-06 15:57:45 -0400547
Nicolas Capens0bac2852016-05-07 06:09:58 -0400548 //
549 // Make a selection node.
550 //
551 TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
552 node->getTypePointer()->setQualifier(EvqTemporary);
553 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400554
Nicolas Capens0bac2852016-05-07 06:09:58 -0400555 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400556}
557
Alexis Hetu76a343a2015-06-04 17:21:22 -0400558TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
559{
560 TIntermSwitch *node = new TIntermSwitch(init, statementList);
561 node->setLine(line);
562
563 return node;
564}
565
566TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line)
567{
568 TIntermCase *node = new TIntermCase(condition);
569 node->setLine(line);
570
571 return node;
572}
573
John Bauman66b8ab22014-05-06 15:57:45 -0400574//
575// Constant terminal nodes. Has a union that contains bool, float or int constants
576//
577// Returns the constant union node created.
578//
579
Alexis Hetu253fdd12015-07-07 15:12:46 -0400580TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400581{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400582 TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
583 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400584
Nicolas Capens0bac2852016-05-07 06:09:58 -0400585 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400586}
587
Alexis Hetu253fdd12015-07-07 15:12:46 -0400588TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400589{
590
Nicolas Capens0bac2852016-05-07 06:09:58 -0400591 TIntermAggregate* node = new TIntermAggregate(EOpSequence);
John Bauman66b8ab22014-05-06 15:57:45 -0400592
Nicolas Capens0bac2852016-05-07 06:09:58 -0400593 node->setLine(line);
594 TIntermConstantUnion* constIntNode;
595 TIntermSequence &sequenceVector = node->getSequence();
596 ConstantUnion* unionArray;
John Bauman66b8ab22014-05-06 15:57:45 -0400597
Nicolas Capens0bac2852016-05-07 06:09:58 -0400598 for (int i = 0; i < fields.num; i++) {
599 unionArray = new ConstantUnion[1];
600 unionArray->setIConst(fields.offsets[i]);
601 constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), line);
602 sequenceVector.push_back(constIntNode);
603 }
John Bauman66b8ab22014-05-06 15:57:45 -0400604
Nicolas Capens0bac2852016-05-07 06:09:58 -0400605 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400606}
607
608//
609// Create loop nodes.
610//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400611TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400612{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400613 TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
614 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400615
Nicolas Capens0bac2852016-05-07 06:09:58 -0400616 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400617}
618
619//
620// Add branches.
621//
Alexis Hetu253fdd12015-07-07 15:12:46 -0400622TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400623{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400624 return addBranch(branchOp, 0, line);
John Bauman66b8ab22014-05-06 15:57:45 -0400625}
626
Alexis Hetu253fdd12015-07-07 15:12:46 -0400627TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc &line)
John Bauman66b8ab22014-05-06 15:57:45 -0400628{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400629 TIntermBranch* node = new TIntermBranch(branchOp, expression);
630 node->setLine(line);
John Bauman66b8ab22014-05-06 15:57:45 -0400631
Nicolas Capens0bac2852016-05-07 06:09:58 -0400632 return node;
John Bauman66b8ab22014-05-06 15:57:45 -0400633}
634
635//
636// This is to be executed once the final root is put on top by the parsing
637// process.
638//
639bool TIntermediate::postProcess(TIntermNode* root)
640{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400641 if (root == 0)
642 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400643
Nicolas Capens0bac2852016-05-07 06:09:58 -0400644 //
645 // First, finish off the top level sequence, if any
646 //
647 TIntermAggregate* aggRoot = root->getAsAggregate();
648 if (aggRoot && aggRoot->getOp() == EOpNull)
649 aggRoot->setOp(EOpSequence);
John Bauman66b8ab22014-05-06 15:57:45 -0400650
Nicolas Capens0bac2852016-05-07 06:09:58 -0400651 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400652}
653
John Bauman66b8ab22014-05-06 15:57:45 -0400654////////////////////////////////////////////////////////////////
655//
656// Member functions of the nodes used for building the tree.
657//
658////////////////////////////////////////////////////////////////
659
660//
661// Say whether or not an operation node changes the value of a variable.
662//
663// Returns true if state is modified.
664//
665bool TIntermOperator::modifiesState() const
666{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400667 switch (op) {
668 case EOpPostIncrement:
669 case EOpPostDecrement:
670 case EOpPreIncrement:
671 case EOpPreDecrement:
672 case EOpAssign:
673 case EOpAddAssign:
674 case EOpSubAssign:
675 case EOpMulAssign:
676 case EOpVectorTimesMatrixAssign:
677 case EOpVectorTimesScalarAssign:
678 case EOpMatrixTimesScalarAssign:
679 case EOpMatrixTimesMatrixAssign:
680 case EOpDivAssign:
681 case EOpIModAssign:
682 case EOpBitShiftLeftAssign:
683 case EOpBitShiftRightAssign:
684 case EOpBitwiseAndAssign:
685 case EOpBitwiseXorAssign:
686 case EOpBitwiseOrAssign:
687 return true;
688 default:
689 return false;
690 }
John Bauman66b8ab22014-05-06 15:57:45 -0400691}
692
693//
694// returns true if the operator is for one of the constructors
695//
696bool TIntermOperator::isConstructor() const
697{
Nicolas Capens0bac2852016-05-07 06:09:58 -0400698 switch (op) {
699 case EOpConstructVec2:
700 case EOpConstructVec3:
701 case EOpConstructVec4:
702 case EOpConstructMat2:
703 case EOpConstructMat2x3:
704 case EOpConstructMat2x4:
705 case EOpConstructMat3x2:
706 case EOpConstructMat3:
707 case EOpConstructMat3x4:
708 case EOpConstructMat4x2:
709 case EOpConstructMat4x3:
710 case EOpConstructMat4:
711 case EOpConstructFloat:
712 case EOpConstructIVec2:
713 case EOpConstructIVec3:
714 case EOpConstructIVec4:
715 case EOpConstructInt:
716 case EOpConstructUVec2:
717 case EOpConstructUVec3:
718 case EOpConstructUVec4:
719 case EOpConstructUInt:
720 case EOpConstructBVec2:
721 case EOpConstructBVec3:
722 case EOpConstructBVec4:
723 case EOpConstructBool:
724 case EOpConstructStruct:
725 return true;
726 default:
727 return false;
728 }
John Bauman66b8ab22014-05-06 15:57:45 -0400729}
Nicolas Capens7c0ec1e2014-06-12 12:18:44 -0400730
John Bauman66b8ab22014-05-06 15:57:45 -0400731//
732// Make sure the type of a unary operator is appropriate for its
733// combination of operation and operand type.
734//
735// Returns false in nothing makes sense.
736//
Nicolas Capensd3d9b9c2016-04-10 01:53:59 -0400737bool TIntermUnary::promote(TInfoSink&, const TType *funcReturnType)
John Bauman66b8ab22014-05-06 15:57:45 -0400738{
Nicolas Capensd3d9b9c2016-04-10 01:53:59 -0400739 setType(funcReturnType ? *funcReturnType : operand->getType());
740
741 // Unary operations result in temporary variables unless const.
Nicolas Capens0bac2852016-05-07 06:09:58 -0400742 if(type.getQualifier() != EvqConstExpr)
Nicolas Capensd3d9b9c2016-04-10 01:53:59 -0400743 {
Nicolas Capens0bac2852016-05-07 06:09:58 -0400744 type.setQualifier(EvqTemporary);
745 }
Nicolas Capensd3d9b9c2016-04-10 01:53:59 -0400746
Nicolas Capens0bac2852016-05-07 06:09:58 -0400747 switch (op) {
748 case EOpLogicalNot:
749 if (operand->getBasicType() != EbtBool)
750 return false;
751 break;
752 case EOpBitwiseNot:
753 if (!IsInteger(operand->getBasicType()))
754 return false;
755 break;
756 case EOpNegative:
757 case EOpPostIncrement:
758 case EOpPostDecrement:
759 case EOpPreIncrement:
760 case EOpPreDecrement:
761 if (operand->getBasicType() == EbtBool)
762 return false;
763 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400764
Nicolas Capens0bac2852016-05-07 06:09:58 -0400765 // operators for built-ins are already type checked against their prototype
766 case EOpAny:
767 case EOpAll:
768 case EOpVectorLogicalNot:
Alexis Hetu0f448072016-03-18 10:56:08 -0400769 case EOpAbs:
770 case EOpSign:
771 case EOpIsNan:
772 case EOpIsInf:
773 case EOpFloatBitsToInt:
774 case EOpFloatBitsToUint:
775 case EOpIntBitsToFloat:
776 case EOpUintBitsToFloat:
777 case EOpPackSnorm2x16:
778 case EOpPackUnorm2x16:
779 case EOpPackHalf2x16:
780 case EOpUnpackSnorm2x16:
781 case EOpUnpackUnorm2x16:
782 case EOpUnpackHalf2x16:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400783 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400784
Nicolas Capens0bac2852016-05-07 06:09:58 -0400785 default:
786 if (operand->getBasicType() != EbtFloat)
787 return false;
788 }
John Bauman66b8ab22014-05-06 15:57:45 -0400789
Nicolas Capens0bac2852016-05-07 06:09:58 -0400790 return true;
John Bauman66b8ab22014-05-06 15:57:45 -0400791}
792
793//
794// Establishes the type of the resultant operation, as well as
795// makes the operator the correct one for the operands.
796//
797// Returns false if operator can't work on operands.
798//
799bool TIntermBinary::promote(TInfoSink& infoSink)
800{
Alexis Hetue5246692015-06-18 12:34:52 -0400801 ASSERT(left->isArray() == right->isArray());
John Bauman66b8ab22014-05-06 15:57:45 -0400802
Nicolas Capens0bac2852016-05-07 06:09:58 -0400803 // GLSL ES 2.0 does not support implicit type casting.
804 // So the basic type should always match.
Alexis Hetu92ab1982015-08-18 15:28:27 -0400805 // GLSL ES 3.0 supports integer shift operands of different signedness.
806 if(op != EOpBitShiftLeft &&
807 op != EOpBitShiftRight &&
808 op != EOpBitShiftLeftAssign &&
809 op != EOpBitShiftRightAssign &&
810 left->getBasicType() != right->getBasicType())
Nicolas Capens0bac2852016-05-07 06:09:58 -0400811 {
812 return false;
813 }
John Bauman66b8ab22014-05-06 15:57:45 -0400814
Nicolas Capens0bac2852016-05-07 06:09:58 -0400815 //
816 // Base assumption: just make the type the same as the left
817 // operand. Then only deviations from this need be coded.
818 //
819 setType(left->getType());
John Bauman66b8ab22014-05-06 15:57:45 -0400820
Nicolas Capens0bac2852016-05-07 06:09:58 -0400821 // The result gets promoted to the highest precision.
822 TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
823 getTypePointer()->setPrecision(higherPrecision);
John Bauman66b8ab22014-05-06 15:57:45 -0400824
Nicolas Capens0bac2852016-05-07 06:09:58 -0400825 // Binary operations results in temporary variables unless both
826 // operands are const.
827 if (left->getQualifier() != EvqConstExpr || right->getQualifier() != EvqConstExpr) {
828 getTypePointer()->setQualifier(EvqTemporary);
829 }
John Bauman66b8ab22014-05-06 15:57:45 -0400830
Nicolas Capens0bac2852016-05-07 06:09:58 -0400831 int primarySize = std::max(left->getNominalSize(), right->getNominalSize());
John Bauman66b8ab22014-05-06 15:57:45 -0400832
Nicolas Capens0bac2852016-05-07 06:09:58 -0400833 //
834 // All scalars. Code after this test assumes this case is removed!
835 //
836 if (primarySize == 1) {
837 switch (op) {
838 //
839 // Promote to conditional
840 //
841 case EOpEqual:
842 case EOpNotEqual:
843 case EOpLessThan:
844 case EOpGreaterThan:
845 case EOpLessThanEqual:
846 case EOpGreaterThanEqual:
847 setType(TType(EbtBool, EbpUndefined));
848 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400849
Nicolas Capens0bac2852016-05-07 06:09:58 -0400850 //
851 // And and Or operate on conditionals
852 //
853 case EOpLogicalAnd:
854 case EOpLogicalOr:
855 case EOpLogicalXor:
856 // Both operands must be of type bool.
857 if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
858 return false;
859 setType(TType(EbtBool, EbpUndefined));
860 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400861
Nicolas Capens0bac2852016-05-07 06:09:58 -0400862 default:
863 break;
864 }
865 return true;
866 }
John Bauman66b8ab22014-05-06 15:57:45 -0400867
Nicolas Capens0bac2852016-05-07 06:09:58 -0400868 // If we reach here, at least one of the operands is vector or matrix.
869 // The other operand could be a scalar, vector, or matrix.
870 // Can these two operands be combined?
871 //
872 TBasicType basicType = left->getBasicType();
873 switch (op) {
874 case EOpMul:
875 if (!left->isMatrix() && right->isMatrix()) {
876 if (left->isVector())
877 {
878 op = EOpVectorTimesMatrix;
879 setType(TType(basicType, higherPrecision, EvqTemporary,
880 static_cast<unsigned char>(right->getNominalSize()), 1));
881 }
882 else {
883 op = EOpMatrixTimesScalar;
884 setType(TType(basicType, higherPrecision, EvqTemporary,
885 static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(right->getSecondarySize())));
886 }
887 } else if (left->isMatrix() && !right->isMatrix()) {
888 if (right->isVector()) {
889 op = EOpMatrixTimesVector;
890 setType(TType(basicType, higherPrecision, EvqTemporary,
891 static_cast<unsigned char>(left->getSecondarySize()), 1));
892 } else {
893 op = EOpMatrixTimesScalar;
894 }
895 } else if (left->isMatrix() && right->isMatrix()) {
896 op = EOpMatrixTimesMatrix;
897 setType(TType(basicType, higherPrecision, EvqTemporary,
898 static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(left->getSecondarySize())));
899 } else if (!left->isMatrix() && !right->isMatrix()) {
900 if (left->isVector() && right->isVector()) {
901 // leave as component product
902 } else if (left->isVector() || right->isVector()) {
903 op = EOpVectorTimesScalar;
904 setType(TType(basicType, higherPrecision, EvqTemporary,
905 static_cast<unsigned char>(primarySize), 1));
906 }
907 } else {
908 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
909 return false;
910 }
Alexis Hetu00106d42015-04-23 11:45:35 -0400911
Nicolas Capens0bac2852016-05-07 06:09:58 -0400912 if(!ValidateMultiplication(op, left->getType(), right->getType()))
913 {
914 return false;
915 }
916 break;
917 case EOpMulAssign:
918 if (!left->isMatrix() && right->isMatrix()) {
919 if (left->isVector())
920 op = EOpVectorTimesMatrixAssign;
921 else {
922 return false;
923 }
924 } else if (left->isMatrix() && !right->isMatrix()) {
925 if (right->isVector()) {
926 return false;
927 } else {
928 op = EOpMatrixTimesScalarAssign;
929 }
930 } else if (left->isMatrix() && right->isMatrix()) {
931 op = EOpMatrixTimesMatrixAssign;
932 setType(TType(basicType, higherPrecision, EvqTemporary,
933 static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(left->getSecondarySize())));
934 } else if (!left->isMatrix() && !right->isMatrix()) {
935 if (left->isVector() && right->isVector()) {
936 // leave as component product
937 } else if (left->isVector() || right->isVector()) {
938 if (! left->isVector())
939 return false;
940 op = EOpVectorTimesScalarAssign;
941 setType(TType(basicType, higherPrecision, EvqTemporary,
942 static_cast<unsigned char>(left->getNominalSize()), 1));
943 }
944 } else {
945 infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
946 return false;
947 }
Alexis Hetu00106d42015-04-23 11:45:35 -0400948
Nicolas Capens0bac2852016-05-07 06:09:58 -0400949 if(!ValidateMultiplication(op, left->getType(), right->getType()))
950 {
951 return false;
952 }
953 break;
John Bauman66b8ab22014-05-06 15:57:45 -0400954
Nicolas Capens0bac2852016-05-07 06:09:58 -0400955 case EOpAssign:
956 case EOpInitialize:
957 // No more additional checks are needed.
958 if ((left->getNominalSize() != right->getNominalSize()) ||
959 (left->getSecondarySize() != right->getSecondarySize()))
960 return false;
961 break;
962 case EOpAdd:
963 case EOpSub:
964 case EOpDiv:
965 case EOpIMod:
966 case EOpBitShiftLeft:
967 case EOpBitShiftRight:
968 case EOpBitwiseAnd:
969 case EOpBitwiseXor:
970 case EOpBitwiseOr:
971 case EOpAddAssign:
972 case EOpSubAssign:
973 case EOpDivAssign:
974 case EOpIModAssign:
975 case EOpBitShiftLeftAssign:
976 case EOpBitShiftRightAssign:
977 case EOpBitwiseAndAssign:
978 case EOpBitwiseXorAssign:
979 case EOpBitwiseOrAssign:
980 if ((left->isMatrix() && right->isVector()) ||
981 (left->isVector() && right->isMatrix()))
982 return false;
Alexis Hetud061e422015-05-13 16:37:50 -0400983
Nicolas Capens0bac2852016-05-07 06:09:58 -0400984 // Are the sizes compatible?
985 if(left->getNominalSize() != right->getNominalSize() ||
986 left->getSecondarySize() != right->getSecondarySize())
987 {
988 // If the nominal sizes of operands do not match:
989 // One of them must be a scalar.
990 if(!left->isScalar() && !right->isScalar())
991 return false;
Alexis Hetud061e422015-05-13 16:37:50 -0400992
Nicolas Capens0bac2852016-05-07 06:09:58 -0400993 // In the case of compound assignment other than multiply-assign,
994 // the right side needs to be a scalar. Otherwise a vector/matrix
995 // would be assigned to a scalar. A scalar can't be shifted by a
996 // vector either.
997 if(!right->isScalar() && (modifiesState() || op == EOpBitShiftLeft || op == EOpBitShiftRight))
998 return false;
999 }
Alexis Hetud061e422015-05-13 16:37:50 -04001000
Nicolas Capens0bac2852016-05-07 06:09:58 -04001001 {
1002 const int secondarySize = std::max(
1003 left->getSecondarySize(), right->getSecondarySize());
1004 setType(TType(basicType, higherPrecision, EvqTemporary,
1005 static_cast<unsigned char>(primarySize), static_cast<unsigned char>(secondarySize)));
1006 if(left->isArray())
1007 {
1008 ASSERT(left->getArraySize() == right->getArraySize());
1009 type.setArraySize(left->getArraySize());
1010 }
1011 }
1012 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001013
Nicolas Capens0bac2852016-05-07 06:09:58 -04001014 case EOpEqual:
1015 case EOpNotEqual:
1016 case EOpLessThan:
1017 case EOpGreaterThan:
1018 case EOpLessThanEqual:
1019 case EOpGreaterThanEqual:
1020 if ((left->getNominalSize() != right->getNominalSize()) ||
1021 (left->getSecondarySize() != right->getSecondarySize()))
1022 return false;
1023 setType(TType(EbtBool, EbpUndefined));
1024 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001025
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001026 case EOpOuterProduct:
1027 if(!left->isVector() || !right->isVector())
1028 return false;
1029 setType(TType(EbtFloat, right->getNominalSize(), left->getNominalSize()));
1030 break;
1031
1032 case EOpTranspose:
1033 if(!right->isMatrix())
1034 return false;
1035 setType(TType(EbtFloat, right->getSecondarySize(), right->getNominalSize()));
1036 break;
1037
1038 case EOpDeterminant:
1039 if(!right->isMatrix())
1040 return false;
1041 setType(TType(EbtFloat));
1042 break;
1043
1044 case EOpInverse:
1045 if(!right->isMatrix() || right->getNominalSize() != right->getSecondarySize())
1046 return false;
1047 setType(right->getType());
1048 break;
1049
Nicolas Capens0bac2852016-05-07 06:09:58 -04001050 default:
1051 return false;
1052 }
Nicolas Capens5e0c3542016-04-05 17:18:24 -04001053
Nicolas Capens0bac2852016-05-07 06:09:58 -04001054 return true;
John Bauman66b8ab22014-05-06 15:57:45 -04001055}
1056
1057bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1058{
Nicolas Capens0bac2852016-05-07 06:09:58 -04001059 const TFieldList& fields = leftNodeType.getStruct()->fields();
John Bauman66b8ab22014-05-06 15:57:45 -04001060
Nicolas Capens0bac2852016-05-07 06:09:58 -04001061 size_t structSize = fields.size();
1062 int index = 0;
John Bauman66b8ab22014-05-06 15:57:45 -04001063
Nicolas Capens0bac2852016-05-07 06:09:58 -04001064 for (size_t j = 0; j < structSize; j++) {
1065 size_t size = fields[j]->type()->getObjectSize();
1066 for(size_t i = 0; i < size; i++) {
1067 if (fields[j]->type()->getBasicType() == EbtStruct) {
1068 if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
1069 return false;
1070 } else {
1071 if (leftUnionArray[index] != rightUnionArray[index])
1072 return false;
1073 index++;
1074 }
John Bauman66b8ab22014-05-06 15:57:45 -04001075
Nicolas Capens0bac2852016-05-07 06:09:58 -04001076 }
1077 }
1078 return true;
John Bauman66b8ab22014-05-06 15:57:45 -04001079}
1080
1081bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
1082{
Nicolas Capens0bac2852016-05-07 06:09:58 -04001083 if (leftNodeType.isArray()) {
1084 TType typeWithoutArrayness = leftNodeType;
1085 typeWithoutArrayness.clearArrayness();
John Bauman66b8ab22014-05-06 15:57:45 -04001086
Nicolas Capens0bac2852016-05-07 06:09:58 -04001087 int arraySize = leftNodeType.getArraySize();
John Bauman66b8ab22014-05-06 15:57:45 -04001088
Nicolas Capens0bac2852016-05-07 06:09:58 -04001089 for (int i = 0; i < arraySize; ++i) {
1090 size_t offset = typeWithoutArrayness.getObjectSize() * i;
1091 if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
1092 return false;
1093 }
1094 } else
1095 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
John Bauman66b8ab22014-05-06 15:57:45 -04001096
Nicolas Capens0bac2852016-05-07 06:09:58 -04001097 return true;
John Bauman66b8ab22014-05-06 15:57:45 -04001098}
1099
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001100float determinant2(float m00, float m01, float m10, float m11)
1101{
1102 return m00 * m11 - m01 * m10;
1103}
1104
1105float determinant3(float m00, float m01, float m02,
Nicolas Capens0bac2852016-05-07 06:09:58 -04001106 float m10, float m11, float m12,
1107 float m20, float m21, float m22)
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001108{
1109 return m00 * determinant2(m11, m12, m21, m22) -
Nicolas Capens0bac2852016-05-07 06:09:58 -04001110 m10 * determinant2(m01, m02, m21, m22) +
1111 m20 * determinant2(m01, m02, m11, m12);
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001112}
1113
1114float determinant4(float m00, float m01, float m02, float m03,
Nicolas Capens0bac2852016-05-07 06:09:58 -04001115 float m10, float m11, float m12, float m13,
1116 float m20, float m21, float m22, float m23,
1117 float m30, float m31, float m32, float m33)
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001118{
1119 return m00 * determinant3(m11, m12, m13, m21, m22, m23, m31, m32, m33) -
Nicolas Capens0bac2852016-05-07 06:09:58 -04001120 m10 * determinant3(m01, m02, m03, m21, m22, m23, m31, m32, m33) +
1121 m20 * determinant3(m01, m02, m03, m11, m12, m13, m31, m32, m33) -
1122 m30 * determinant3(m01, m02, m03, m11, m12, m13, m21, m22, m23);
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001123}
1124
1125float ComputeDeterminant(int size, ConstantUnion* unionArray)
1126{
1127 switch(size)
1128 {
1129 case 2:
1130 return determinant2(unionArray[0].getFConst(),
Nicolas Capens0bac2852016-05-07 06:09:58 -04001131 unionArray[1].getFConst(),
1132 unionArray[2].getFConst(),
1133 unionArray[3].getFConst());
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001134 case 3:
1135 return determinant3(unionArray[0].getFConst(),
Nicolas Capens0bac2852016-05-07 06:09:58 -04001136 unionArray[1].getFConst(),
1137 unionArray[2].getFConst(),
1138 unionArray[3].getFConst(),
1139 unionArray[4].getFConst(),
1140 unionArray[5].getFConst(),
1141 unionArray[6].getFConst(),
1142 unionArray[7].getFConst(),
1143 unionArray[8].getFConst());
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001144 case 4:
1145 return determinant4(unionArray[0].getFConst(),
Nicolas Capens0bac2852016-05-07 06:09:58 -04001146 unionArray[1].getFConst(),
1147 unionArray[2].getFConst(),
1148 unionArray[3].getFConst(),
1149 unionArray[4].getFConst(),
1150 unionArray[5].getFConst(),
1151 unionArray[6].getFConst(),
1152 unionArray[7].getFConst(),
1153 unionArray[8].getFConst(),
1154 unionArray[9].getFConst(),
1155 unionArray[10].getFConst(),
1156 unionArray[11].getFConst(),
1157 unionArray[12].getFConst(),
1158 unionArray[13].getFConst(),
1159 unionArray[14].getFConst(),
1160 unionArray[15].getFConst());
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001161 default:
Nicolas Capens3713cd42015-06-22 10:41:54 -04001162 UNREACHABLE(size);
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001163 return 0.0f;
1164 }
1165}
1166
1167ConstantUnion* CreateInverse(TIntermConstantUnion* node, ConstantUnion* unionArray)
1168{
1169 ConstantUnion* tempConstArray = 0;
1170 int size = node->getNominalSize();
1171 float determinant = ComputeDeterminant(size, unionArray);
1172 if(determinant != 0.0f)
1173 {
1174 float invDet = 1.0f / determinant;
1175 tempConstArray = new ConstantUnion[size*size];
1176 switch(size)
1177 {
1178 case 2:
1179 {
1180 float m00 = unionArray[0].getFConst(); // Matrix is:
1181 float m01 = unionArray[1].getFConst(); // (m00, m01)
1182 float m10 = unionArray[2].getFConst(); // (m10, m11)
1183 float m11 = unionArray[3].getFConst();
1184 tempConstArray[0].setFConst( invDet * m11);
1185 tempConstArray[1].setFConst(-invDet * m01);
1186 tempConstArray[2].setFConst(-invDet * m10);
1187 tempConstArray[3].setFConst( invDet * m00);
1188 }
1189 break;
1190 case 3:
1191 {
1192 float m00 = unionArray[0].getFConst(); // Matrix is:
1193 float m01 = unionArray[1].getFConst(); // (m00, m01, m02)
1194 float m02 = unionArray[2].getFConst(); // (m10, m11, m12)
1195 float m10 = unionArray[3].getFConst(); // (m20, m21, m22)
1196 float m11 = unionArray[4].getFConst();
1197 float m12 = unionArray[5].getFConst();
1198 float m20 = unionArray[6].getFConst();
1199 float m21 = unionArray[7].getFConst();
1200 float m22 = unionArray[8].getFConst();
1201 tempConstArray[0].setFConst(invDet * determinant2(m11, m12, m21, m22)); // m00 = invDet * (m11 * m22 - m12 * m21)
1202 tempConstArray[1].setFConst(invDet * determinant2(m12, m10, m22, m20)); // m01 = -invDet * (m10 * m22 - m12 * m20)
1203 tempConstArray[2].setFConst(invDet * determinant2(m10, m11, m20, m21)); // m02 = invDet * (m10 * m21 - m11 * m20)
1204 tempConstArray[3].setFConst(invDet * determinant2(m21, m22, m01, m02)); // m10 = -invDet * (m01 * m22 - m02 * m21)
1205 tempConstArray[4].setFConst(invDet * determinant2(m00, m02, m20, m22)); // m11 = invDet * (m00 * m22 - m02 * m20)
1206 tempConstArray[5].setFConst(invDet * determinant2(m20, m21, m00, m01)); // m12 = -invDet * (m00 * m21 - m01 * m20)
1207 tempConstArray[6].setFConst(invDet * determinant2(m01, m02, m11, m12)); // m20 = invDet * (m01 * m12 - m02 * m11)
1208 tempConstArray[7].setFConst(invDet * determinant2(m10, m12, m00, m02)); // m21 = -invDet * (m00 * m12 - m02 * m10)
1209 tempConstArray[8].setFConst(invDet * determinant2(m00, m01, m10, m11)); // m22 = invDet * (m00 * m11 - m01 * m10)
1210 }
1211 break;
1212 case 4:
1213 {
1214 float m00 = unionArray[0].getFConst(); // Matrix is:
1215 float m01 = unionArray[1].getFConst(); // (m00, m01, m02, m03)
1216 float m02 = unionArray[2].getFConst(); // (m10, m11, m12, m13)
1217 float m03 = unionArray[3].getFConst(); // (m20, m21, m22, m23)
1218 float m10 = unionArray[4].getFConst(); // (m30, m31, m32, m33)
1219 float m11 = unionArray[5].getFConst();
1220 float m12 = unionArray[6].getFConst();
1221 float m13 = unionArray[7].getFConst();
1222 float m20 = unionArray[8].getFConst();
1223 float m21 = unionArray[9].getFConst();
1224 float m22 = unionArray[10].getFConst();
1225 float m23 = unionArray[11].getFConst();
1226 float m30 = unionArray[12].getFConst();
1227 float m31 = unionArray[13].getFConst();
1228 float m32 = unionArray[14].getFConst();
1229 float m33 = unionArray[15].getFConst();
1230 tempConstArray[ 0].setFConst( invDet * determinant3(m11, m12, m13, m21, m22, m23, m31, m32, m33)); // m00
1231 tempConstArray[ 1].setFConst(-invDet * determinant3(m10, m12, m13, m20, m22, m23, m30, m32, m33)); // m01
1232 tempConstArray[ 2].setFConst( invDet * determinant3(m10, m11, m13, m20, m21, m23, m30, m31, m33)); // m02
1233 tempConstArray[ 3].setFConst(-invDet * determinant3(m10, m11, m12, m20, m21, m22, m30, m31, m32)); // m03
1234 tempConstArray[ 4].setFConst( invDet * determinant3(m01, m02, m03, m21, m22, m23, m31, m32, m33)); // m10
1235 tempConstArray[ 5].setFConst(-invDet * determinant3(m00, m02, m03, m20, m22, m23, m30, m32, m33)); // m11
1236 tempConstArray[ 6].setFConst( invDet * determinant3(m00, m01, m03, m20, m21, m23, m30, m31, m33)); // m12
1237 tempConstArray[ 7].setFConst(-invDet * determinant3(m00, m01, m02, m20, m21, m22, m30, m31, m32)); // m13
1238 tempConstArray[ 8].setFConst( invDet * determinant3(m01, m02, m03, m11, m12, m13, m31, m32, m33)); // m20
1239 tempConstArray[ 9].setFConst(-invDet * determinant3(m00, m02, m03, m10, m12, m13, m30, m32, m33)); // m21
1240 tempConstArray[10].setFConst( invDet * determinant3(m00, m01, m03, m10, m11, m13, m30, m31, m33)); // m22
1241 tempConstArray[11].setFConst(-invDet * determinant3(m00, m01, m02, m10, m11, m12, m30, m31, m32)); // m23
1242 tempConstArray[12].setFConst( invDet * determinant3(m01, m02, m03, m11, m12, m13, m21, m22, m23)); // m30
1243 tempConstArray[13].setFConst(-invDet * determinant3(m00, m02, m03, m10, m12, m13, m20, m22, m23)); // m31
1244 tempConstArray[14].setFConst( invDet * determinant3(m00, m01, m03, m10, m11, m13, m20, m21, m23)); // m32
1245 tempConstArray[15].setFConst(-invDet * determinant3(m00, m01, m02, m10, m11, m12, m20, m21, m22)); // m33
1246 }
1247 break;
1248 default:
Nicolas Capens3713cd42015-06-22 10:41:54 -04001249 UNREACHABLE(size);
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001250 }
1251 }
1252 return tempConstArray;
1253}
1254
John Bauman66b8ab22014-05-06 15:57:45 -04001255//
1256// The fold functions see if an operation on a constant can be done in place,
1257// without generating run-time code.
1258//
1259// Returns the node to keep using, which may or may not be the node passed in.
1260//
1261
1262TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
1263{
Nicolas Capens0bac2852016-05-07 06:09:58 -04001264 ConstantUnion *unionArray = getUnionArrayPointer();
1265 size_t objectSize = getType().getObjectSize();
John Bauman66b8ab22014-05-06 15:57:45 -04001266
Nicolas Capens0bac2852016-05-07 06:09:58 -04001267 if (constantNode) { // binary operations
1268 TIntermConstantUnion *node = constantNode->getAsConstantUnion();
1269 ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
1270 TType returnType = getType();
John Bauman66b8ab22014-05-06 15:57:45 -04001271
Nicolas Capens0bac2852016-05-07 06:09:58 -04001272 // for a case like float f = 1.2 + vec4(2,3,4,5);
1273 if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
1274 rightUnionArray = new ConstantUnion[objectSize];
1275 for (size_t i = 0; i < objectSize; ++i)
1276 rightUnionArray[i] = *node->getUnionArrayPointer();
1277 returnType = getType();
1278 } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
1279 // for a case like float f = vec4(2,3,4,5) + 1.2;
1280 unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
1281 for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
1282 unionArray[i] = *getUnionArrayPointer();
1283 returnType = node->getType();
1284 objectSize = constantNode->getType().getObjectSize();
1285 }
John Bauman66b8ab22014-05-06 15:57:45 -04001286
Nicolas Capens0bac2852016-05-07 06:09:58 -04001287 ConstantUnion* tempConstArray = 0;
1288 TIntermConstantUnion *tempNode;
John Bauman66b8ab22014-05-06 15:57:45 -04001289
Nicolas Capens0bac2852016-05-07 06:09:58 -04001290 switch(op) {
1291 case EOpAdd:
1292 tempConstArray = new ConstantUnion[objectSize];
1293 {// support MSVC++6.0
1294 for (size_t i = 0; i < objectSize; i++)
1295 tempConstArray[i] = unionArray[i] + rightUnionArray[i];
1296 }
1297 break;
1298 case EOpSub:
1299 tempConstArray = new ConstantUnion[objectSize];
1300 {// support MSVC++6.0
1301 for (size_t i = 0; i < objectSize; i++)
1302 tempConstArray[i] = unionArray[i] - rightUnionArray[i];
1303 }
1304 break;
John Bauman66b8ab22014-05-06 15:57:45 -04001305
Nicolas Capens0bac2852016-05-07 06:09:58 -04001306 case EOpMul:
1307 case EOpVectorTimesScalar:
1308 case EOpMatrixTimesScalar:
1309 tempConstArray = new ConstantUnion[objectSize];
1310 {// support MSVC++6.0
1311 for (size_t i = 0; i < objectSize; i++)
1312 tempConstArray[i] = unionArray[i] * rightUnionArray[i];
1313 }
1314 break;
1315 case EOpMatrixTimesMatrix:
1316 if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
1317 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1318 return 0;
1319 }
1320 {// support MSVC++6.0
1321 int leftNumCols = getNominalSize();
1322 int leftNumRows = getSecondarySize();
1323 int rightNumCols = node->getNominalSize();
1324 int rightNumRows = node->getSecondarySize();
1325 if(leftNumCols != rightNumRows) {
1326 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
1327 return 0;
1328 }
1329 int tempNumCols = rightNumCols;
1330 int tempNumRows = leftNumRows;
1331 int tempNumAdds = leftNumCols;
1332 tempConstArray = new ConstantUnion[tempNumCols*tempNumRows];
1333 for (int row = 0; row < tempNumRows; row++) {
1334 for (int column = 0; column < tempNumCols; column++) {
1335 tempConstArray[tempNumRows * column + row].setFConst(0.0f);
1336 for (int i = 0; i < tempNumAdds; i++) {
1337 tempConstArray[tempNumRows * column + row].setFConst(tempConstArray[tempNumRows * column + row].getFConst() + unionArray[i * leftNumRows + row].getFConst() * (rightUnionArray[column * rightNumRows + i].getFConst()));
1338 }
1339 }
1340 }
1341 // update return type for matrix product
1342 returnType.setNominalSize(static_cast<unsigned char>(tempNumCols));
1343 returnType.setSecondarySize(static_cast<unsigned char>(tempNumRows));
1344 }
1345 break;
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001346
1347 case EOpOuterProduct:
1348 {
1349 int leftSize = getNominalSize();
1350 int rightSize = node->getNominalSize();
1351 tempConstArray = new ConstantUnion[leftSize*rightSize];
1352 for(int row = 0; row < leftSize; row++) {
1353 for(int column = 0; column < rightSize; column++) {
1354 tempConstArray[leftSize * column + row].setFConst(unionArray[row].getFConst() * rightUnionArray[column].getFConst());
1355 }
1356 }
1357 // update return type for outer product
1358 returnType.setNominalSize(static_cast<unsigned char>(rightSize));
1359 returnType.setSecondarySize(static_cast<unsigned char>(leftSize));
1360 }
1361 break;
1362
1363 case EOpTranspose:
1364 {
1365 int rightCol = node->getNominalSize();
1366 int rightRow = node->getSecondarySize();
1367 tempConstArray = new ConstantUnion[rightCol*rightRow];
1368 for(int row = 0; row < rightRow; row++) {
1369 for(int column = 0; column < rightCol; column++) {
1370 tempConstArray[rightRow * column + row].setFConst(rightUnionArray[rightCol * row + column].getFConst());
1371 }
1372 }
1373 // update return type for transpose
1374 returnType.setNominalSize(static_cast<unsigned char>(rightRow));
1375 returnType.setSecondarySize(static_cast<unsigned char>(rightCol));
1376 }
1377 break;
1378
1379 case EOpDeterminant:
1380 {
1381 ASSERT(node->getNominalSize() == node->getSecondarySize());
1382
1383 tempConstArray = new ConstantUnion[1];
1384 tempConstArray[0].setFConst(ComputeDeterminant(node->getNominalSize(), rightUnionArray));
1385 // update return type for determinant
1386 returnType.setNominalSize(1);
1387 returnType.setSecondarySize(1);
1388 }
1389 break;
1390
1391 case EOpInverse:
1392 {
1393 ASSERT(node->getNominalSize() == node->getSecondarySize());
1394
1395 tempConstArray = CreateInverse(node, rightUnionArray);
1396 if(!tempConstArray)
1397 {
1398 // Singular matrix, just copy
1399 tempConstArray = new ConstantUnion[objectSize];
Alexis Hetuab752792016-04-21 16:11:31 -04001400 for(size_t i = 0; i < objectSize; i++)
Alexis Hetu3815b6c2015-05-27 11:21:37 -04001401 tempConstArray[i] = rightUnionArray[i];
1402 }
1403 }
1404 break;
1405
Nicolas Capens0bac2852016-05-07 06:09:58 -04001406 case EOpDiv:
1407 case EOpIMod:
Nicolas Capens5e0c3542016-04-05 17:18:24 -04001408 tempConstArray = new ConstantUnion[objectSize];
Nicolas Capens0bac2852016-05-07 06:09:58 -04001409 {// support MSVC++6.0
1410 for (size_t i = 0; i < objectSize; i++) {
1411 switch (getType().getBasicType()) {
1412 case EbtFloat:
1413 if (rightUnionArray[i] == 0.0f) {
1414 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1415 tempConstArray[i].setFConst(FLT_MAX);
1416 } else {
1417 ASSERT(op == EOpDiv);
1418 tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
1419 }
1420 break;
1421
1422 case EbtInt:
1423 if (rightUnionArray[i] == 0) {
1424 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1425 tempConstArray[i].setIConst(INT_MAX);
1426 } else {
1427 if(op == EOpDiv) {
1428 tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
1429 } else {
1430 ASSERT(op == EOpIMod);
1431 tempConstArray[i].setIConst(unionArray[i].getIConst() % rightUnionArray[i].getIConst());
1432 }
1433 }
1434 break;
1435 case EbtUInt:
1436 if (rightUnionArray[i] == 0) {
1437 infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
1438 tempConstArray[i].setUConst(UINT_MAX);
1439 } else {
1440 if(op == EOpDiv) {
1441 tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst());
1442 } else {
1443 ASSERT(op == EOpIMod);
1444 tempConstArray[i].setUConst(unionArray[i].getUConst() % rightUnionArray[i].getUConst());
1445 }
1446 }
1447 break;
1448 default:
1449 infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
1450 return 0;
1451 }
1452 }
1453 }
1454 break;
1455
1456 case EOpMatrixTimesVector:
1457 if (node->getBasicType() != EbtFloat) {
1458 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
1459 return 0;
1460 }
1461 tempConstArray = new ConstantUnion[getNominalSize()];
1462
1463 {// support MSVC++6.0
1464 for (int size = getNominalSize(), i = 0; i < size; i++) {
1465 tempConstArray[i].setFConst(0.0f);
1466 for (int j = 0; j < size; j++) {
1467 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
1468 }
1469 }
1470 }
1471
1472 tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
1473 tempNode->setLine(getLine());
1474
1475 return tempNode;
1476
1477 case EOpVectorTimesMatrix:
1478 if (getType().getBasicType() != EbtFloat) {
1479 infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
1480 return 0;
1481 }
1482
1483 tempConstArray = new ConstantUnion[getNominalSize()];
1484 {// support MSVC++6.0
1485 for (int size = getNominalSize(), i = 0; i < size; i++) {
1486 tempConstArray[i].setFConst(0.0f);
1487 for (int j = 0; j < size; j++) {
1488 tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
1489 }
1490 }
1491 }
1492 break;
1493
1494 case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
1495 tempConstArray = new ConstantUnion[objectSize];
1496 {// support MSVC++6.0
1497 for (size_t i = 0; i < objectSize; i++)
1498 tempConstArray[i] = unionArray[i] && rightUnionArray[i];
1499 }
1500 break;
1501
1502 case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
1503 tempConstArray = new ConstantUnion[objectSize];
1504 {// support MSVC++6.0
1505 for (size_t i = 0; i < objectSize; i++)
1506 tempConstArray[i] = unionArray[i] || rightUnionArray[i];
1507 }
1508 break;
1509
1510 case EOpLogicalXor:
1511 tempConstArray = new ConstantUnion[objectSize];
1512 {// support MSVC++6.0
1513 for (size_t i = 0; i < objectSize; i++)
1514 switch (getType().getBasicType()) {
1515 case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
1516 default: assert(false && "Default missing");
1517 }
1518 }
1519 break;
1520
1521 case EOpBitwiseAnd:
1522 tempConstArray = new ConstantUnion[objectSize];
1523 for(size_t i = 0; i < objectSize; i++)
1524 tempConstArray[i] = unionArray[i] & rightUnionArray[i];
1525 break;
1526 case EOpBitwiseXor:
1527 tempConstArray = new ConstantUnion[objectSize];
1528 for(size_t i = 0; i < objectSize; i++)
1529 tempConstArray[i] = unionArray[i] ^ rightUnionArray[i];
1530 break;
1531 case EOpBitwiseOr:
1532 tempConstArray = new ConstantUnion[objectSize];
1533 for(size_t i = 0; i < objectSize; i++)
1534 tempConstArray[i] = unionArray[i] | rightUnionArray[i];
1535 break;
1536 case EOpBitShiftLeft:
1537 tempConstArray = new ConstantUnion[objectSize];
1538 for(size_t i = 0; i < objectSize; i++)
1539 tempConstArray[i] = unionArray[i] << rightUnionArray[i];
1540 break;
1541 case EOpBitShiftRight:
1542 tempConstArray = new ConstantUnion[objectSize];
1543 for(size_t i = 0; i < objectSize; i++)
1544 tempConstArray[i] = unionArray[i] >> rightUnionArray[i];
1545 break;
1546
1547 case EOpLessThan:
1548 tempConstArray = new ConstantUnion[objectSize];
1549 for(size_t i = 0; i < objectSize; i++)
1550 tempConstArray[i].setBConst(unionArray[i] < rightUnionArray[i]);
1551 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize);
1552 break;
1553 case EOpGreaterThan:
1554 tempConstArray = new ConstantUnion[objectSize];
1555 for(size_t i = 0; i < objectSize; i++)
Nicolas Capens5e0c3542016-04-05 17:18:24 -04001556 tempConstArray[i].setBConst(unionArray[i] > rightUnionArray[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001557 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize);
1558 break;
1559 case EOpLessThanEqual:
1560 tempConstArray = new ConstantUnion[objectSize];
1561 for(size_t i = 0; i < objectSize; i++)
Nicolas Capens5e0c3542016-04-05 17:18:24 -04001562 tempConstArray[i].setBConst(unionArray[i] <= rightUnionArray[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001563 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize);
1564 break;
1565 case EOpGreaterThanEqual:
1566 tempConstArray = new ConstantUnion[objectSize];
1567 for(size_t i = 0; i < objectSize; i++)
Nicolas Capens5e0c3542016-04-05 17:18:24 -04001568 tempConstArray[i].setBConst(unionArray[i] >= rightUnionArray[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001569 returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize);
1570 break;
1571 case EOpEqual:
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001572 tempConstArray = new ConstantUnion[1];
1573
1574 if(getType().getBasicType() == EbtStruct) {
1575 tempConstArray->setBConst(CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray));
Nicolas Capens0bac2852016-05-07 06:09:58 -04001576 } else {
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001577 bool boolNodeFlag = true;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001578 for (size_t i = 0; i < objectSize; i++) {
1579 if (unionArray[i] != rightUnionArray[i]) {
1580 boolNodeFlag = false;
1581 break; // break out of for loop
1582 }
1583 }
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001584 tempConstArray->setBConst(boolNodeFlag);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001585 }
John Bauman66b8ab22014-05-06 15:57:45 -04001586
Nicolas Capens0bac2852016-05-07 06:09:58 -04001587 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr));
1588 tempNode->setLine(getLine());
John Bauman66b8ab22014-05-06 15:57:45 -04001589
Nicolas Capens0bac2852016-05-07 06:09:58 -04001590 return tempNode;
John Bauman66b8ab22014-05-06 15:57:45 -04001591
Nicolas Capens0bac2852016-05-07 06:09:58 -04001592 case EOpNotEqual:
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001593 tempConstArray = new ConstantUnion[1];
1594
1595 if(getType().getBasicType() == EbtStruct) {
1596 tempConstArray->setBConst(!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray));
Nicolas Capens0bac2852016-05-07 06:09:58 -04001597 } else {
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001598 bool boolNodeFlag = false;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001599 for (size_t i = 0; i < objectSize; i++) {
1600 if (unionArray[i] != rightUnionArray[i]) {
1601 boolNodeFlag = true;
1602 break; // break out of for loop
1603 }
1604 }
Alexis Hetu26ea8f52016-04-28 12:45:48 -04001605 tempConstArray->setBConst(boolNodeFlag);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001606 }
John Bauman66b8ab22014-05-06 15:57:45 -04001607
Nicolas Capens0bac2852016-05-07 06:09:58 -04001608 tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr));
1609 tempNode->setLine(getLine());
John Bauman66b8ab22014-05-06 15:57:45 -04001610
Nicolas Capens0bac2852016-05-07 06:09:58 -04001611 return tempNode;
Nicolas Capens91dfb972016-04-09 23:45:12 -04001612 case EOpMax:
Nicolas Capens0bac2852016-05-07 06:09:58 -04001613 tempConstArray = new ConstantUnion[objectSize];
1614 {// support MSVC++6.0
1615 for (size_t i = 0; i < objectSize; i++)
1616 tempConstArray[i] = unionArray[i] > rightUnionArray[i] ? unionArray[i] : rightUnionArray[i];
1617 }
1618 break;
1619 case EOpMin:
1620 tempConstArray = new ConstantUnion[objectSize];
1621 {// support MSVC++6.0
1622 for (size_t i = 0; i < objectSize; i++)
1623 tempConstArray[i] = unionArray[i] < rightUnionArray[i] ? unionArray[i] : rightUnionArray[i];
1624 }
1625 break;
1626 default:
1627 return 0;
1628 }
1629 tempNode = new TIntermConstantUnion(tempConstArray, returnType);
1630 tempNode->setLine(getLine());
John Bauman66b8ab22014-05-06 15:57:45 -04001631
Nicolas Capens0bac2852016-05-07 06:09:58 -04001632 return tempNode;
1633 } else {
1634 //
1635 // Do unary operations
1636 //
1637 TIntermConstantUnion *newNode = 0;
1638 ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
1639 for (size_t i = 0; i < objectSize; i++) {
1640 switch(op) {
1641 case EOpNegative:
1642 switch (getType().getBasicType()) {
1643 case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
1644 case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
1645 default:
1646 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1647 return 0;
1648 }
1649 break;
1650 case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
1651 switch (getType().getBasicType()) {
1652 case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
1653 default:
1654 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1655 return 0;
1656 }
1657 break;
1658 case EOpBitwiseNot:
1659 switch(getType().getBasicType()) {
1660 case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break;
1661 case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break;
1662 default:
1663 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1664 return 0;
1665 }
1666 break;
Alexis Hetu6c6b4702016-04-26 16:30:22 -04001667 case EOpRadians:
1668 switch(getType().getBasicType()) {
1669 case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 1.74532925e-2f); break;
1670 default:
1671 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1672 return 0;
1673 }
1674 break;
1675 case EOpDegrees:
1676 switch(getType().getBasicType()) {
1677 case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 5.72957795e+1f); break;
1678 default:
1679 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1680 return 0;
1681 }
1682 break;
1683 case EOpSin:
1684 switch(getType().getBasicType()) {
1685 case EbtFloat: tempConstArray[i].setFConst(sinf(unionArray[i].getFConst())); break;
1686 default:
1687 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1688 return 0;
1689 }
1690 break;
1691 case EOpCos:
1692 switch(getType().getBasicType()) {
1693 case EbtFloat: tempConstArray[i].setFConst(cosf(unionArray[i].getFConst())); break;
1694 default:
1695 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1696 return 0;
1697 }
1698 break;
1699 case EOpTan:
1700 switch(getType().getBasicType()) {
1701 case EbtFloat: tempConstArray[i].setFConst(tanf(unionArray[i].getFConst())); break;
1702 default:
1703 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1704 return 0;
1705 }
1706 break;
1707 case EOpAsin:
1708 switch(getType().getBasicType()) {
1709 case EbtFloat: tempConstArray[i].setFConst(asinf(unionArray[i].getFConst())); break;
1710 default:
1711 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1712 return 0;
1713 }
1714 break;
1715 case EOpAcos:
1716 switch(getType().getBasicType()) {
1717 case EbtFloat: tempConstArray[i].setFConst(acosf(unionArray[i].getFConst())); break;
1718 default:
1719 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1720 return 0;
1721 }
1722 break;
1723 case EOpAtan:
1724 switch(getType().getBasicType()) {
1725 case EbtFloat: tempConstArray[i].setFConst(atanf(unionArray[i].getFConst())); break;
1726 default:
1727 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1728 return 0;
1729 }
1730 break;
1731 case EOpSinh:
1732 switch(getType().getBasicType()) {
1733 case EbtFloat: tempConstArray[i].setFConst(sinhf(unionArray[i].getFConst())); break;
1734 default:
1735 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1736 return 0;
1737 }
1738 break;
1739 case EOpCosh:
1740 switch(getType().getBasicType()) {
1741 case EbtFloat: tempConstArray[i].setFConst(coshf(unionArray[i].getFConst())); break;
1742 default:
1743 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1744 return 0;
1745 }
1746 break;
1747 case EOpTanh:
1748 switch(getType().getBasicType()) {
1749 case EbtFloat: tempConstArray[i].setFConst(tanhf(unionArray[i].getFConst())); break;
1750 default:
1751 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1752 return 0;
1753 }
1754 break;
1755 case EOpAsinh:
1756 switch(getType().getBasicType()) {
1757 case EbtFloat: tempConstArray[i].setFConst(asinhf(unionArray[i].getFConst())); break;
1758 default:
1759 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1760 return 0;
1761 }
1762 break;
1763 case EOpAcosh:
1764 switch(getType().getBasicType()) {
1765 case EbtFloat: tempConstArray[i].setFConst(acoshf(unionArray[i].getFConst())); break;
1766 default:
1767 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1768 return 0;
1769 }
1770 break;
1771 case EOpAtanh:
1772 switch(getType().getBasicType()) {
1773 case EbtFloat: tempConstArray[i].setFConst(atanhf(unionArray[i].getFConst())); break;
1774 default:
1775 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1776 return 0;
1777 }
1778 break;
1779 case EOpLog:
1780 switch(getType().getBasicType()) {
1781 case EbtFloat: tempConstArray[i].setFConst(logf(unionArray[i].getFConst())); break;
1782 default:
1783 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1784 return 0;
1785 }
1786 break;
1787 case EOpLog2:
1788 switch(getType().getBasicType()) {
Alexis Hetu2ce222c2016-05-02 11:20:52 -04001789 case EbtFloat: tempConstArray[i].setFConst(sw::log2(unionArray[i].getFConst())); break;
Alexis Hetu6c6b4702016-04-26 16:30:22 -04001790 default:
1791 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1792 return 0;
1793 }
1794 break;
1795 case EOpExp:
1796 switch(getType().getBasicType()) {
1797 case EbtFloat: tempConstArray[i].setFConst(expf(unionArray[i].getFConst())); break;
1798 default:
1799 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1800 return 0;
1801 }
1802 break;
1803 case EOpExp2:
1804 switch(getType().getBasicType()) {
1805 case EbtFloat: tempConstArray[i].setFConst(exp2f(unionArray[i].getFConst())); break;
1806 default:
1807 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1808 return 0;
1809 }
1810 break;
1811 case EOpSqrt:
1812 switch(getType().getBasicType()) {
1813 case EbtFloat: tempConstArray[i].setFConst(sqrtf(unionArray[i].getFConst())); break;
1814 default:
1815 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1816 return 0;
1817 }
1818 break;
1819 case EOpInverseSqrt:
1820 switch(getType().getBasicType()) {
1821 case EbtFloat: tempConstArray[i].setFConst(1.0f / sqrtf(unionArray[i].getFConst())); break;
1822 default:
1823 infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
1824 return 0;
1825 }
1826 break;
1827 default:
Nicolas Capens0bac2852016-05-07 06:09:58 -04001828 return 0;
1829 }
1830 }
1831 newNode = new TIntermConstantUnion(tempConstArray, getType());
1832 newNode->setLine(getLine());
1833 return newNode;
1834 }
John Bauman66b8ab22014-05-06 15:57:45 -04001835}
1836
1837TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
1838{
Nicolas Capens0bac2852016-05-07 06:09:58 -04001839 size_t size = node->getType().getObjectSize();
John Bauman66b8ab22014-05-06 15:57:45 -04001840
Nicolas Capens0bac2852016-05-07 06:09:58 -04001841 ConstantUnion *leftUnionArray = new ConstantUnion[size];
John Bauman66b8ab22014-05-06 15:57:45 -04001842
Nicolas Capens0bac2852016-05-07 06:09:58 -04001843 for(size_t i = 0; i < size; i++) {
1844 switch (promoteTo) {
1845 case EbtFloat:
1846 switch (node->getType().getBasicType()) {
1847 case EbtInt:
1848 leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
1849 break;
1850 case EbtUInt:
1851 leftUnionArray[i].setFConst(static_cast<float>(node->getUConst(i)));
1852 break;
1853 case EbtBool:
1854 leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
1855 break;
1856 case EbtFloat:
1857 leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
1858 break;
1859 default:
1860 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1861 return 0;
1862 }
1863 break;
1864 case EbtInt:
1865 switch (node->getType().getBasicType()) {
1866 case EbtInt:
1867 leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
1868 break;
1869 case EbtUInt:
1870 leftUnionArray[i].setIConst(static_cast<int>(node->getUConst(i)));
1871 break;
1872 case EbtBool:
1873 leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
1874 break;
1875 case EbtFloat:
1876 leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
1877 break;
1878 default:
1879 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1880 return 0;
1881 }
1882 break;
1883 case EbtUInt:
1884 switch (node->getType().getBasicType()) {
1885 case EbtInt:
1886 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getIConst(i)));
1887 break;
1888 case EbtUInt:
1889 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getUConst(i)));
1890 break;
1891 case EbtBool:
1892 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getBConst(i)));
1893 break;
1894 case EbtFloat:
1895 leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getFConst(i)));
1896 break;
1897 default:
1898 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1899 return 0;
1900 }
1901 break;
1902 case EbtBool:
1903 switch (node->getType().getBasicType()) {
1904 case EbtInt:
1905 leftUnionArray[i].setBConst(node->getIConst(i) != 0);
1906 break;
1907 case EbtUInt:
1908 leftUnionArray[i].setBConst(node->getUConst(i) != 0);
1909 break;
1910 case EbtBool:
1911 leftUnionArray[i].setBConst(node->getBConst(i));
1912 break;
1913 case EbtFloat:
1914 leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
1915 break;
1916 default:
1917 infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
1918 return 0;
1919 }
John Bauman66b8ab22014-05-06 15:57:45 -04001920
Nicolas Capens0bac2852016-05-07 06:09:58 -04001921 break;
1922 default:
1923 infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
1924 return 0;
1925 }
John Bauman66b8ab22014-05-06 15:57:45 -04001926
Nicolas Capens0bac2852016-05-07 06:09:58 -04001927 }
John Bauman66b8ab22014-05-06 15:57:45 -04001928
Nicolas Capens0bac2852016-05-07 06:09:58 -04001929 const TType& t = node->getType();
John Bauman66b8ab22014-05-06 15:57:45 -04001930
Alexis Hetub14178b2015-04-13 13:23:20 -04001931 return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine());
John Bauman66b8ab22014-05-06 15:57:45 -04001932}
1933