1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // 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 |
6 | // |
7 | // 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. |
14 | |
15 | // |
16 | // Build the intermediate representation. |
17 | // |
18 | |
19 | #include <float.h> |
20 | #include <limits.h> |
21 | #include <algorithm> |
22 | |
23 | #include "localintermediate.h" |
24 | #include "SymbolTable.h" |
25 | #include "Common/Math.hpp" |
26 | |
27 | bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); |
28 | |
29 | static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){ |
30 | return left > right ? left : right; |
31 | } |
32 | |
33 | static 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: |
60 | UNREACHABLE(op); |
61 | return false; |
62 | } |
63 | } |
64 | |
65 | TOperator TypeToConstructorOperator(const TType &type) |
66 | { |
67 | switch(type.getBasicType()) |
68 | { |
69 | case EbtFloat: |
70 | if(type.isMatrix()) |
71 | { |
72 | switch(type.getNominalSize()) |
73 | { |
74 | case 2: |
75 | switch(type.getSecondarySize()) |
76 | { |
77 | case 2: |
78 | return EOpConstructMat2; |
79 | case 3: |
80 | return EOpConstructMat2x3; |
81 | case 4: |
82 | return EOpConstructMat2x4; |
83 | default: |
84 | break; |
85 | } |
86 | break; |
87 | |
88 | case 3: |
89 | switch(type.getSecondarySize()) |
90 | { |
91 | case 2: |
92 | return EOpConstructMat3x2; |
93 | case 3: |
94 | return EOpConstructMat3; |
95 | case 4: |
96 | return EOpConstructMat3x4; |
97 | default: |
98 | break; |
99 | } |
100 | break; |
101 | |
102 | case 4: |
103 | switch(type.getSecondarySize()) |
104 | { |
105 | case 2: |
106 | return EOpConstructMat4x2; |
107 | case 3: |
108 | return EOpConstructMat4x3; |
109 | case 4: |
110 | return EOpConstructMat4; |
111 | default: |
112 | break; |
113 | } |
114 | break; |
115 | } |
116 | } |
117 | else |
118 | { |
119 | switch(type.getNominalSize()) |
120 | { |
121 | case 1: |
122 | return EOpConstructFloat; |
123 | case 2: |
124 | return EOpConstructVec2; |
125 | case 3: |
126 | return EOpConstructVec3; |
127 | case 4: |
128 | return EOpConstructVec4; |
129 | default: |
130 | break; |
131 | } |
132 | } |
133 | break; |
134 | |
135 | case EbtInt: |
136 | switch(type.getNominalSize()) |
137 | { |
138 | case 1: |
139 | return EOpConstructInt; |
140 | case 2: |
141 | return EOpConstructIVec2; |
142 | case 3: |
143 | return EOpConstructIVec3; |
144 | case 4: |
145 | return EOpConstructIVec4; |
146 | default: |
147 | break; |
148 | } |
149 | break; |
150 | |
151 | case EbtUInt: |
152 | switch(type.getNominalSize()) |
153 | { |
154 | case 1: |
155 | return EOpConstructUInt; |
156 | case 2: |
157 | return EOpConstructUVec2; |
158 | case 3: |
159 | return EOpConstructUVec3; |
160 | case 4: |
161 | return EOpConstructUVec4; |
162 | default: |
163 | break; |
164 | } |
165 | break; |
166 | |
167 | case EbtBool: |
168 | switch(type.getNominalSize()) |
169 | { |
170 | case 1: |
171 | return EOpConstructBool; |
172 | case 2: |
173 | return EOpConstructBVec2; |
174 | case 3: |
175 | return EOpConstructBVec3; |
176 | case 4: |
177 | return EOpConstructBVec4; |
178 | default: |
179 | break; |
180 | } |
181 | break; |
182 | |
183 | case EbtStruct: |
184 | return EOpConstructStruct; |
185 | |
186 | default: |
187 | break; |
188 | } |
189 | |
190 | return EOpNull; |
191 | } |
192 | |
193 | const char* getOperatorString(TOperator op) { |
194 | switch (op) { |
195 | case EOpInitialize: return "=" ; |
196 | case EOpAssign: return "=" ; |
197 | case EOpAddAssign: return "+=" ; |
198 | case EOpSubAssign: return "-=" ; |
199 | case EOpDivAssign: return "/=" ; |
200 | case EOpIModAssign: return "%=" ; |
201 | case EOpBitShiftLeftAssign: return "<<=" ; |
202 | case EOpBitShiftRightAssign: return ">>=" ; |
203 | case EOpBitwiseAndAssign: return "&=" ; |
204 | case EOpBitwiseXorAssign: return "^=" ; |
205 | case EOpBitwiseOrAssign: return "|=" ; |
206 | |
207 | // Fall-through. |
208 | case EOpMulAssign: |
209 | case EOpVectorTimesMatrixAssign: |
210 | case EOpVectorTimesScalarAssign: |
211 | case EOpMatrixTimesScalarAssign: |
212 | case EOpMatrixTimesMatrixAssign: return "*=" ; |
213 | |
214 | // Fall-through. |
215 | case EOpIndexDirect: |
216 | case EOpIndexIndirect: return "[]" ; |
217 | |
218 | case EOpIndexDirectStruct: return "." ; |
219 | case EOpVectorSwizzle: return "." ; |
220 | case EOpAdd: return "+" ; |
221 | case EOpSub: return "-" ; |
222 | case EOpMul: return "*" ; |
223 | case EOpDiv: return "/" ; |
224 | case EOpMod: UNIMPLEMENTED(); break; |
225 | case EOpEqual: return "==" ; |
226 | case EOpNotEqual: return "!=" ; |
227 | case EOpLessThan: return "<" ; |
228 | case EOpGreaterThan: return ">" ; |
229 | case EOpLessThanEqual: return "<=" ; |
230 | case EOpGreaterThanEqual: return ">=" ; |
231 | |
232 | // Fall-through. |
233 | case EOpVectorTimesScalar: |
234 | case EOpVectorTimesMatrix: |
235 | case EOpMatrixTimesVector: |
236 | case EOpMatrixTimesScalar: |
237 | case EOpMatrixTimesMatrix: return "*" ; |
238 | |
239 | case EOpLogicalOr: return "||" ; |
240 | case EOpLogicalXor: return "^^" ; |
241 | case EOpLogicalAnd: return "&&" ; |
242 | case EOpIMod: return "%" ; |
243 | case EOpBitShiftLeft: return "<<" ; |
244 | case EOpBitShiftRight: return ">>" ; |
245 | case EOpBitwiseAnd: return "&" ; |
246 | case EOpBitwiseXor: return "^" ; |
247 | case EOpBitwiseOr: return "|" ; |
248 | case EOpNegative: return "-" ; |
249 | case EOpVectorLogicalNot: return "not" ; |
250 | case EOpLogicalNot: return "!" ; |
251 | case EOpBitwiseNot: return "~" ; |
252 | case EOpPostIncrement: return "++" ; |
253 | case EOpPostDecrement: return "--" ; |
254 | case EOpPreIncrement: return "++" ; |
255 | case EOpPreDecrement: return "--" ; |
256 | |
257 | case EOpRadians: return "radians" ; |
258 | case EOpDegrees: return "degrees" ; |
259 | case EOpSin: return "sin" ; |
260 | case EOpCos: return "cos" ; |
261 | case EOpTan: return "tan" ; |
262 | case EOpAsin: return "asin" ; |
263 | case EOpAcos: return "acos" ; |
264 | case EOpAtan: return "atan" ; |
265 | case EOpSinh: return "sinh" ; |
266 | case EOpCosh: return "cosh" ; |
267 | case EOpTanh: return "tanh" ; |
268 | case EOpAsinh: return "asinh" ; |
269 | case EOpAcosh: return "acosh" ; |
270 | case EOpAtanh: return "atanh" ; |
271 | case EOpExp: return "exp" ; |
272 | case EOpLog: return "log" ; |
273 | case EOpExp2: return "exp2" ; |
274 | case EOpLog2: return "log2" ; |
275 | case EOpSqrt: return "sqrt" ; |
276 | case EOpInverseSqrt: return "inversesqrt" ; |
277 | case EOpAbs: return "abs" ; |
278 | case EOpSign: return "sign" ; |
279 | case EOpFloor: return "floor" ; |
280 | case EOpTrunc: return "trunc" ; |
281 | case EOpRound: return "round" ; |
282 | case EOpRoundEven: return "roundEven" ; |
283 | case EOpCeil: return "ceil" ; |
284 | case EOpFract: return "fract" ; |
285 | case EOpLength: return "length" ; |
286 | case EOpNormalize: return "normalize" ; |
287 | case EOpDFdx: return "dFdx" ; |
288 | case EOpDFdy: return "dFdy" ; |
289 | case EOpFwidth: return "fwidth" ; |
290 | case EOpAny: return "any" ; |
291 | case EOpAll: return "all" ; |
292 | case EOpIsNan: return "isnan" ; |
293 | case EOpIsInf: return "isinf" ; |
294 | case EOpOuterProduct: return "outerProduct" ; |
295 | case EOpTranspose: return "transpose" ; |
296 | case EOpDeterminant: return "determinant" ; |
297 | case EOpInverse: return "inverse" ; |
298 | |
299 | default: break; |
300 | } |
301 | return "" ; |
302 | } |
303 | |
304 | //////////////////////////////////////////////////////////////////////////// |
305 | // |
306 | // First set of functions are to help build the intermediate representation. |
307 | // These functions are not member functions of the nodes. |
308 | // They are called from parser productions. |
309 | // |
310 | ///////////////////////////////////////////////////////////////////////////// |
311 | |
312 | // |
313 | // Add a terminal node for an identifier in an expression. |
314 | // |
315 | // Returns the added node. |
316 | // |
317 | TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc &line) |
318 | { |
319 | TIntermSymbol* node = new TIntermSymbol(id, name, type); |
320 | node->setLine(line); |
321 | |
322 | return node; |
323 | } |
324 | |
325 | // |
326 | // Connect two nodes with a new parent that does a binary operation on the nodes. |
327 | // |
328 | // Returns the added node. |
329 | // |
330 | TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line) |
331 | { |
332 | bool isBitShift = false; |
333 | switch (op) { |
334 | case EOpEqual: |
335 | case EOpNotEqual: |
336 | break; |
337 | case EOpLessThan: |
338 | case EOpGreaterThan: |
339 | case EOpLessThanEqual: |
340 | case EOpGreaterThanEqual: |
341 | if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { |
342 | return 0; |
343 | } |
344 | break; |
345 | case EOpLogicalOr: |
346 | case EOpLogicalXor: |
347 | case EOpLogicalAnd: |
348 | if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { |
349 | return 0; |
350 | } |
351 | break; |
352 | case EOpBitwiseOr: |
353 | case EOpBitwiseXor: |
354 | case EOpBitwiseAnd: |
355 | if (!IsInteger(left->getBasicType()) || left->isMatrix() || left->isArray()) { |
356 | return 0; |
357 | } |
358 | break; |
359 | case EOpAdd: |
360 | case EOpSub: |
361 | case EOpDiv: |
362 | case EOpMul: |
363 | if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) { |
364 | return 0; |
365 | } |
366 | break; |
367 | case EOpIMod: |
368 | // Note that this is only for the % operator, not for mod() |
369 | if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) { |
370 | return 0; |
371 | } |
372 | break; |
373 | case EOpBitShiftLeft: |
374 | case EOpBitShiftRight: |
375 | case EOpBitShiftLeftAssign: |
376 | case EOpBitShiftRightAssign: |
377 | // Unsigned can be bit-shifted by signed and vice versa, but we need to |
378 | // check that the basic type is an integer type. |
379 | isBitShift = true; |
380 | if(!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) |
381 | { |
382 | return 0; |
383 | } |
384 | break; |
385 | default: break; |
386 | } |
387 | |
388 | if(!isBitShift && left->getBasicType() != right->getBasicType()) |
389 | { |
390 | return 0; |
391 | } |
392 | |
393 | // |
394 | // Need a new node holding things together then. Make |
395 | // one and promote it to the right type. |
396 | // |
397 | TIntermBinary* node = new TIntermBinary(op); |
398 | node->setLine(line); |
399 | |
400 | node->setLeft(left); |
401 | node->setRight(right); |
402 | if (!node->promote(infoSink)) |
403 | { |
404 | delete node; |
405 | return 0; |
406 | } |
407 | |
408 | // |
409 | // See if we can fold constants. |
410 | // |
411 | TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); |
412 | TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); |
413 | if (leftTempConstant && rightTempConstant) { |
414 | TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); |
415 | |
416 | if (typedReturnNode) |
417 | return typedReturnNode; |
418 | } |
419 | |
420 | return node; |
421 | } |
422 | |
423 | // |
424 | // Connect two nodes through an assignment. |
425 | // |
426 | // Returns the added node. |
427 | // |
428 | TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line) |
429 | { |
430 | if (left->getType().getStruct() || right->getType().getStruct()) |
431 | { |
432 | if (left->getType() != right->getType()) |
433 | { |
434 | return 0; |
435 | } |
436 | } |
437 | |
438 | TIntermBinary* node = new TIntermBinary(op); |
439 | node->setLine(line); |
440 | |
441 | node->setLeft(left); |
442 | node->setRight(right); |
443 | if (! node->promote(infoSink)) |
444 | return 0; |
445 | |
446 | return node; |
447 | } |
448 | |
449 | // |
450 | // Connect two nodes through an index operator, where the left node is the base |
451 | // of an array or struct, and the right node is a direct or indirect offset. |
452 | // |
453 | // Returns the added node. |
454 | // The caller should set the type of the returned node. |
455 | // |
456 | TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc &line) |
457 | { |
458 | TIntermBinary* node = new TIntermBinary(op); |
459 | node->setLine(line); |
460 | node->setLeft(base); |
461 | node->setRight(index); |
462 | |
463 | // caller should set the type |
464 | |
465 | return node; |
466 | } |
467 | |
468 | // |
469 | // Add one node as the parent of another that it operates on. |
470 | // |
471 | // Returns the added node. |
472 | // |
473 | TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, const TSourceLoc &line, const TType *funcReturnType) |
474 | { |
475 | if (child == 0) { |
476 | infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath" , line); |
477 | return 0; |
478 | } |
479 | |
480 | switch (op) { |
481 | case EOpBitwiseNot: |
482 | if (!IsInteger(child->getType().getBasicType()) || child->getType().isMatrix() || child->getType().isArray()) { |
483 | return 0; |
484 | } |
485 | break; |
486 | |
487 | case EOpLogicalNot: |
488 | if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { |
489 | return 0; |
490 | } |
491 | break; |
492 | |
493 | case EOpPostIncrement: |
494 | case EOpPreIncrement: |
495 | case EOpPostDecrement: |
496 | case EOpPreDecrement: |
497 | case EOpNegative: |
498 | if (!child->getType().isScalar() && !child->getType().isVector() && !child->getType().isMatrix()) |
499 | return 0; |
500 | default: break; |
501 | } |
502 | |
503 | TIntermConstantUnion *childTempConstant = 0; |
504 | if (child->getAsConstantUnion()) |
505 | childTempConstant = child->getAsConstantUnion(); |
506 | |
507 | // |
508 | // Make a new node for the operator. |
509 | // |
510 | TIntermUnary *node = new TIntermUnary(op); |
511 | node->setLine(line); |
512 | node->setOperand(child); |
513 | |
514 | if (! node->promote(infoSink, funcReturnType)) |
515 | return 0; |
516 | |
517 | if (childTempConstant) { |
518 | TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); |
519 | |
520 | if (newChild) |
521 | return newChild; |
522 | } |
523 | |
524 | return node; |
525 | } |
526 | |
527 | // |
528 | // This is the safe way to change the operator on an aggregate, as it |
529 | // does lots of error checking and fixing. Especially for establishing |
530 | // a function call's operation on its set of parameters. Sequences |
531 | // of instructions are also aggregates, but they just directly set |
532 | // their operator to EOpSequence. |
533 | // |
534 | // Returns an aggregate node, which could be the one passed in if |
535 | // it was already an aggregate but no operator was set. |
536 | // |
537 | TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc &line) |
538 | { |
539 | TIntermAggregate* aggNode; |
540 | |
541 | // |
542 | // Make sure we have an aggregate. If not turn it into one. |
543 | // |
544 | if (node) { |
545 | aggNode = node->getAsAggregate(); |
546 | if (aggNode == 0 || aggNode->getOp() != EOpNull) { |
547 | // |
548 | // Make an aggregate containing this node. |
549 | // |
550 | aggNode = new TIntermAggregate(); |
551 | aggNode->getSequence().push_back(node); |
552 | } |
553 | } else |
554 | aggNode = new TIntermAggregate(); |
555 | |
556 | // |
557 | // Set the operator. |
558 | // |
559 | aggNode->setOp(op); |
560 | |
561 | return aggNode; |
562 | } |
563 | |
564 | // |
565 | // Safe way to combine two nodes into an aggregate. Works with null pointers, |
566 | // a node that's not a aggregate yet, etc. |
567 | // |
568 | // Returns the resulting aggregate, unless 0 was passed in for |
569 | // both existing nodes. |
570 | // |
571 | TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc &line) |
572 | { |
573 | if (left == 0 && right == 0) |
574 | return 0; |
575 | |
576 | TIntermAggregate* aggNode = 0; |
577 | if (left) |
578 | aggNode = left->getAsAggregate(); |
579 | if (!aggNode || aggNode->getOp() != EOpNull) { |
580 | aggNode = new TIntermAggregate; |
581 | if (left) |
582 | aggNode->getSequence().push_back(left); |
583 | } |
584 | |
585 | if (right) |
586 | aggNode->getSequence().push_back(right); |
587 | |
588 | aggNode->setLine(line); |
589 | |
590 | return aggNode; |
591 | } |
592 | |
593 | // |
594 | // Turn an existing node into an aggregate. |
595 | // |
596 | // Returns an aggregate, unless 0 was passed in for the existing node. |
597 | // |
598 | TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc &line) |
599 | { |
600 | if (node == 0) |
601 | return 0; |
602 | |
603 | TIntermAggregate* aggNode = new TIntermAggregate; |
604 | aggNode->getSequence().push_back(node); |
605 | |
606 | aggNode->setLine(line); |
607 | |
608 | return aggNode; |
609 | } |
610 | |
611 | // |
612 | // For "if" test nodes. There are three children; a condition, |
613 | // a true path, and a false path. The two paths are in the |
614 | // nodePair. |
615 | // |
616 | // Returns the selection node created. |
617 | // |
618 | TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc &line) |
619 | { |
620 | // |
621 | // For compile time constant selections, prune the code and |
622 | // test now. |
623 | // |
624 | |
625 | if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { |
626 | if (cond->getAsConstantUnion()->getBConst(0) == true) |
627 | return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : nullptr; |
628 | else |
629 | return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : nullptr; |
630 | } |
631 | |
632 | TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); |
633 | node->setLine(line); |
634 | |
635 | return node; |
636 | } |
637 | |
638 | |
639 | TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc &line) |
640 | { |
641 | if (left->getType().getQualifier() == EvqConstExpr && right->getType().getQualifier() == EvqConstExpr) { |
642 | return right; |
643 | } else { |
644 | TIntermTyped *commaAggregate = growAggregate(left, right, line); |
645 | commaAggregate->getAsAggregate()->setOp(EOpComma); |
646 | commaAggregate->setType(right->getType()); |
647 | commaAggregate->getTypePointer()->setQualifier(EvqTemporary); |
648 | return commaAggregate; |
649 | } |
650 | } |
651 | |
652 | // |
653 | // For "?:" test nodes. There are three children; a condition, |
654 | // a true path, and a false path. The two paths are specified |
655 | // as separate parameters. |
656 | // |
657 | // Returns the selection node created, or 0 if one could not be. |
658 | // |
659 | TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc &line) |
660 | { |
661 | if (trueBlock->getType() != falseBlock->getType()) |
662 | { |
663 | return 0; |
664 | } |
665 | |
666 | // |
667 | // See if all the operands are constant, then fold it otherwise not. |
668 | // |
669 | |
670 | if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { |
671 | if (cond->getAsConstantUnion()->getBConst(0)) |
672 | return trueBlock; |
673 | else |
674 | return falseBlock; |
675 | } |
676 | |
677 | // |
678 | // Make a selection node. |
679 | // |
680 | TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); |
681 | node->getTypePointer()->setQualifier(EvqTemporary); |
682 | node->setLine(line); |
683 | |
684 | return node; |
685 | } |
686 | |
687 | TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line) |
688 | { |
689 | TIntermSwitch *node = new TIntermSwitch(init, statementList); |
690 | node->setLine(line); |
691 | |
692 | return node; |
693 | } |
694 | |
695 | TIntermCase *TIntermediate::addCase(TIntermTyped *condition, const TSourceLoc &line) |
696 | { |
697 | TIntermCase *node = new TIntermCase(condition); |
698 | node->setLine(line); |
699 | |
700 | return node; |
701 | } |
702 | |
703 | // |
704 | // Constant terminal nodes. Has a union that contains bool, float or int constants |
705 | // |
706 | // Returns the constant union node created. |
707 | // |
708 | |
709 | TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc &line) |
710 | { |
711 | TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); |
712 | node->setLine(line); |
713 | |
714 | return node; |
715 | } |
716 | |
717 | TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc &line) |
718 | { |
719 | |
720 | TIntermAggregate* node = new TIntermAggregate(EOpSequence); |
721 | |
722 | node->setLine(line); |
723 | TIntermConstantUnion* constIntNode; |
724 | TIntermSequence &sequenceVector = node->getSequence(); |
725 | ConstantUnion* unionArray; |
726 | |
727 | for (int i = 0; i < fields.num; i++) { |
728 | unionArray = new ConstantUnion[1]; |
729 | unionArray->setIConst(fields.offsets[i]); |
730 | constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConstExpr), line); |
731 | sequenceVector.push_back(constIntNode); |
732 | } |
733 | |
734 | return node; |
735 | } |
736 | |
737 | // |
738 | // Create loop nodes. |
739 | // |
740 | TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc &line) |
741 | { |
742 | TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); |
743 | node->setLine(line); |
744 | |
745 | return node; |
746 | } |
747 | |
748 | // |
749 | // Add branches. |
750 | // |
751 | TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc &line) |
752 | { |
753 | return addBranch(branchOp, 0, line); |
754 | } |
755 | |
756 | TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc &line) |
757 | { |
758 | TIntermBranch* node = new TIntermBranch(branchOp, expression); |
759 | node->setLine(line); |
760 | |
761 | return node; |
762 | } |
763 | |
764 | // |
765 | // This is to be executed once the final root is put on top by the parsing |
766 | // process. |
767 | // |
768 | bool TIntermediate::postProcess(TIntermNode* root) |
769 | { |
770 | if (root == 0) |
771 | return true; |
772 | |
773 | // |
774 | // First, finish off the top level sequence, if any |
775 | // |
776 | TIntermAggregate* aggRoot = root->getAsAggregate(); |
777 | if (aggRoot && aggRoot->getOp() == EOpNull) |
778 | aggRoot->setOp(EOpSequence); |
779 | |
780 | return true; |
781 | } |
782 | |
783 | //////////////////////////////////////////////////////////////// |
784 | // |
785 | // Member functions of the nodes used for building the tree. |
786 | // |
787 | //////////////////////////////////////////////////////////////// |
788 | |
789 | // static |
790 | TIntermTyped *TIntermTyped::CreateIndexNode(int index) |
791 | { |
792 | ConstantUnion *u = new ConstantUnion[1]; |
793 | u[0].setIConst(index); |
794 | |
795 | TType type(EbtInt, EbpUndefined, EvqConstExpr, 1); |
796 | TIntermConstantUnion *node = new TIntermConstantUnion(u, type); |
797 | return node; |
798 | } |
799 | |
800 | // |
801 | // Say whether or not an operation node changes the value of a variable. |
802 | // |
803 | // Returns true if state is modified. |
804 | // |
805 | bool TIntermOperator::modifiesState() const |
806 | { |
807 | switch (op) { |
808 | case EOpPostIncrement: |
809 | case EOpPostDecrement: |
810 | case EOpPreIncrement: |
811 | case EOpPreDecrement: |
812 | case EOpAssign: |
813 | case EOpAddAssign: |
814 | case EOpSubAssign: |
815 | case EOpMulAssign: |
816 | case EOpVectorTimesMatrixAssign: |
817 | case EOpVectorTimesScalarAssign: |
818 | case EOpMatrixTimesScalarAssign: |
819 | case EOpMatrixTimesMatrixAssign: |
820 | case EOpDivAssign: |
821 | case EOpIModAssign: |
822 | case EOpBitShiftLeftAssign: |
823 | case EOpBitShiftRightAssign: |
824 | case EOpBitwiseAndAssign: |
825 | case EOpBitwiseXorAssign: |
826 | case EOpBitwiseOrAssign: |
827 | return true; |
828 | default: |
829 | return false; |
830 | } |
831 | } |
832 | |
833 | // |
834 | // returns true if the operator is for one of the constructors |
835 | // |
836 | bool TIntermOperator::isConstructor() const |
837 | { |
838 | switch (op) { |
839 | case EOpConstructVec2: |
840 | case EOpConstructVec3: |
841 | case EOpConstructVec4: |
842 | case EOpConstructMat2: |
843 | case EOpConstructMat2x3: |
844 | case EOpConstructMat2x4: |
845 | case EOpConstructMat3x2: |
846 | case EOpConstructMat3: |
847 | case EOpConstructMat3x4: |
848 | case EOpConstructMat4x2: |
849 | case EOpConstructMat4x3: |
850 | case EOpConstructMat4: |
851 | case EOpConstructFloat: |
852 | case EOpConstructIVec2: |
853 | case EOpConstructIVec3: |
854 | case EOpConstructIVec4: |
855 | case EOpConstructInt: |
856 | case EOpConstructUVec2: |
857 | case EOpConstructUVec3: |
858 | case EOpConstructUVec4: |
859 | case EOpConstructUInt: |
860 | case EOpConstructBVec2: |
861 | case EOpConstructBVec3: |
862 | case EOpConstructBVec4: |
863 | case EOpConstructBool: |
864 | case EOpConstructStruct: |
865 | return true; |
866 | default: |
867 | return false; |
868 | } |
869 | } |
870 | |
871 | // |
872 | // Make sure the type of a unary operator is appropriate for its |
873 | // combination of operation and operand type. |
874 | // |
875 | // Returns false in nothing makes sense. |
876 | // |
877 | bool TIntermUnary::promote(TInfoSink&, const TType *funcReturnType) |
878 | { |
879 | setType(funcReturnType ? *funcReturnType : operand->getType()); |
880 | |
881 | // Unary operations result in temporary variables unless const. |
882 | if(type.getQualifier() != EvqConstExpr) |
883 | { |
884 | type.setQualifier(EvqTemporary); |
885 | } |
886 | |
887 | switch (op) { |
888 | case EOpLogicalNot: |
889 | if (operand->getBasicType() != EbtBool) |
890 | return false; |
891 | break; |
892 | case EOpBitwiseNot: |
893 | if (!IsInteger(operand->getBasicType())) |
894 | return false; |
895 | break; |
896 | case EOpNegative: |
897 | case EOpPostIncrement: |
898 | case EOpPostDecrement: |
899 | case EOpPreIncrement: |
900 | case EOpPreDecrement: |
901 | if (operand->getBasicType() == EbtBool) |
902 | return false; |
903 | break; |
904 | |
905 | // operators for built-ins are already type checked against their prototype |
906 | case EOpAny: |
907 | case EOpAll: |
908 | case EOpVectorLogicalNot: |
909 | case EOpAbs: |
910 | case EOpSign: |
911 | case EOpIsNan: |
912 | case EOpIsInf: |
913 | case EOpFloatBitsToInt: |
914 | case EOpFloatBitsToUint: |
915 | case EOpIntBitsToFloat: |
916 | case EOpUintBitsToFloat: |
917 | case EOpPackSnorm2x16: |
918 | case EOpPackUnorm2x16: |
919 | case EOpPackHalf2x16: |
920 | case EOpUnpackSnorm2x16: |
921 | case EOpUnpackUnorm2x16: |
922 | case EOpUnpackHalf2x16: |
923 | return true; |
924 | |
925 | default: |
926 | if (operand->getBasicType() != EbtFloat) |
927 | return false; |
928 | } |
929 | |
930 | return true; |
931 | } |
932 | |
933 | // |
934 | // Establishes the type of the resultant operation, as well as |
935 | // makes the operator the correct one for the operands. |
936 | // |
937 | // Returns false if operator can't work on operands. |
938 | // |
939 | bool TIntermBinary::promote(TInfoSink& infoSink) |
940 | { |
941 | ASSERT(left->isArray() == right->isArray()); |
942 | |
943 | // GLSL ES 2.0 does not support implicit type casting. |
944 | // So the basic type should always match. |
945 | // GLSL ES 3.0 supports integer shift operands of different signedness. |
946 | if(op != EOpBitShiftLeft && |
947 | op != EOpBitShiftRight && |
948 | op != EOpBitShiftLeftAssign && |
949 | op != EOpBitShiftRightAssign && |
950 | left->getBasicType() != right->getBasicType()) |
951 | { |
952 | return false; |
953 | } |
954 | |
955 | // |
956 | // Base assumption: just make the type the same as the left |
957 | // operand. Then only deviations from this need be coded. |
958 | // |
959 | setType(left->getType()); |
960 | |
961 | // The result gets promoted to the highest precision. |
962 | TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); |
963 | getTypePointer()->setPrecision(higherPrecision); |
964 | |
965 | // Binary operations results in temporary variables unless both |
966 | // operands are const. |
967 | if (left->getQualifier() != EvqConstExpr || right->getQualifier() != EvqConstExpr) { |
968 | getTypePointer()->setQualifier(EvqTemporary); |
969 | } |
970 | |
971 | int primarySize = std::max(left->getNominalSize(), right->getNominalSize()); |
972 | |
973 | // |
974 | // All scalars. Code after this test assumes this case is removed! |
975 | // |
976 | if (primarySize == 1) { |
977 | switch (op) { |
978 | // |
979 | // Promote to conditional |
980 | // |
981 | case EOpEqual: |
982 | case EOpNotEqual: |
983 | case EOpLessThan: |
984 | case EOpGreaterThan: |
985 | case EOpLessThanEqual: |
986 | case EOpGreaterThanEqual: |
987 | setType(TType(EbtBool, EbpUndefined)); |
988 | break; |
989 | |
990 | // |
991 | // And and Or operate on conditionals |
992 | // |
993 | case EOpLogicalAnd: |
994 | case EOpLogicalOr: |
995 | case EOpLogicalXor: |
996 | // Both operands must be of type bool. |
997 | if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) |
998 | return false; |
999 | setType(TType(EbtBool, EbpUndefined)); |
1000 | break; |
1001 | |
1002 | default: |
1003 | break; |
1004 | } |
1005 | return true; |
1006 | } |
1007 | |
1008 | // If we reach here, at least one of the operands is vector or matrix. |
1009 | // The other operand could be a scalar, vector, or matrix. |
1010 | // Can these two operands be combined? |
1011 | // |
1012 | TBasicType basicType = left->getBasicType(); |
1013 | switch (op) { |
1014 | case EOpMul: |
1015 | if (!left->isMatrix() && right->isMatrix()) { |
1016 | if (left->isVector()) |
1017 | { |
1018 | op = EOpVectorTimesMatrix; |
1019 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1020 | static_cast<unsigned char>(right->getNominalSize()), 1)); |
1021 | } |
1022 | else { |
1023 | op = EOpMatrixTimesScalar; |
1024 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1025 | static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(right->getSecondarySize()))); |
1026 | } |
1027 | } else if (left->isMatrix() && !right->isMatrix()) { |
1028 | if (right->isVector()) { |
1029 | op = EOpMatrixTimesVector; |
1030 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1031 | static_cast<unsigned char>(left->getSecondarySize()), 1)); |
1032 | } else { |
1033 | op = EOpMatrixTimesScalar; |
1034 | } |
1035 | } else if (left->isMatrix() && right->isMatrix()) { |
1036 | op = EOpMatrixTimesMatrix; |
1037 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1038 | static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(left->getSecondarySize()))); |
1039 | } else if (!left->isMatrix() && !right->isMatrix()) { |
1040 | if (left->isVector() && right->isVector()) { |
1041 | // leave as component product |
1042 | } else if (left->isVector() || right->isVector()) { |
1043 | op = EOpVectorTimesScalar; |
1044 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1045 | static_cast<unsigned char>(primarySize), 1)); |
1046 | } |
1047 | } else { |
1048 | infoSink.info.message(EPrefixInternalError, "Missing elses" , getLine()); |
1049 | return false; |
1050 | } |
1051 | |
1052 | if(!ValidateMultiplication(op, left->getType(), right->getType())) |
1053 | { |
1054 | return false; |
1055 | } |
1056 | break; |
1057 | case EOpMulAssign: |
1058 | if (!left->isMatrix() && right->isMatrix()) { |
1059 | if (left->isVector()) |
1060 | op = EOpVectorTimesMatrixAssign; |
1061 | else { |
1062 | return false; |
1063 | } |
1064 | } else if (left->isMatrix() && !right->isMatrix()) { |
1065 | if (right->isVector()) { |
1066 | return false; |
1067 | } else { |
1068 | op = EOpMatrixTimesScalarAssign; |
1069 | } |
1070 | } else if (left->isMatrix() && right->isMatrix()) { |
1071 | op = EOpMatrixTimesMatrixAssign; |
1072 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1073 | static_cast<unsigned char>(right->getNominalSize()), static_cast<unsigned char>(left->getSecondarySize()))); |
1074 | } else if (!left->isMatrix() && !right->isMatrix()) { |
1075 | if (left->isVector() && right->isVector()) { |
1076 | // leave as component product |
1077 | } else if (left->isVector() || right->isVector()) { |
1078 | if (! left->isVector()) |
1079 | return false; |
1080 | op = EOpVectorTimesScalarAssign; |
1081 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1082 | static_cast<unsigned char>(left->getNominalSize()), 1)); |
1083 | } |
1084 | } else { |
1085 | infoSink.info.message(EPrefixInternalError, "Missing elses" , getLine()); |
1086 | return false; |
1087 | } |
1088 | |
1089 | if(!ValidateMultiplication(op, left->getType(), right->getType())) |
1090 | { |
1091 | return false; |
1092 | } |
1093 | break; |
1094 | |
1095 | case EOpAssign: |
1096 | case EOpInitialize: |
1097 | // No more additional checks are needed. |
1098 | if ((left->getNominalSize() != right->getNominalSize()) || |
1099 | (left->getSecondarySize() != right->getSecondarySize())) |
1100 | return false; |
1101 | break; |
1102 | case EOpAdd: |
1103 | case EOpSub: |
1104 | case EOpDiv: |
1105 | case EOpIMod: |
1106 | case EOpBitShiftLeft: |
1107 | case EOpBitShiftRight: |
1108 | case EOpBitwiseAnd: |
1109 | case EOpBitwiseXor: |
1110 | case EOpBitwiseOr: |
1111 | case EOpAddAssign: |
1112 | case EOpSubAssign: |
1113 | case EOpDivAssign: |
1114 | case EOpIModAssign: |
1115 | case EOpBitShiftLeftAssign: |
1116 | case EOpBitShiftRightAssign: |
1117 | case EOpBitwiseAndAssign: |
1118 | case EOpBitwiseXorAssign: |
1119 | case EOpBitwiseOrAssign: |
1120 | if ((left->isMatrix() && right->isVector()) || |
1121 | (left->isVector() && right->isMatrix())) |
1122 | return false; |
1123 | |
1124 | // Are the sizes compatible? |
1125 | if(left->getNominalSize() != right->getNominalSize() || |
1126 | left->getSecondarySize() != right->getSecondarySize()) |
1127 | { |
1128 | // If the nominal sizes of operands do not match: |
1129 | // One of them must be a scalar. |
1130 | if(!left->isScalar() && !right->isScalar()) |
1131 | return false; |
1132 | |
1133 | // In the case of compound assignment other than multiply-assign, |
1134 | // the right side needs to be a scalar. Otherwise a vector/matrix |
1135 | // would be assigned to a scalar. A scalar can't be shifted by a |
1136 | // vector either. |
1137 | if(!right->isScalar() && (modifiesState() || op == EOpBitShiftLeft || op == EOpBitShiftRight)) |
1138 | return false; |
1139 | } |
1140 | |
1141 | { |
1142 | const int secondarySize = std::max( |
1143 | left->getSecondarySize(), right->getSecondarySize()); |
1144 | setType(TType(basicType, higherPrecision, EvqTemporary, |
1145 | static_cast<unsigned char>(primarySize), static_cast<unsigned char>(secondarySize))); |
1146 | if(left->isArray()) |
1147 | { |
1148 | ASSERT(left->getArraySize() == right->getArraySize()); |
1149 | type.setArraySize(left->getArraySize()); |
1150 | } |
1151 | } |
1152 | break; |
1153 | |
1154 | case EOpEqual: |
1155 | case EOpNotEqual: |
1156 | case EOpLessThan: |
1157 | case EOpGreaterThan: |
1158 | case EOpLessThanEqual: |
1159 | case EOpGreaterThanEqual: |
1160 | if ((left->getNominalSize() != right->getNominalSize()) || |
1161 | (left->getSecondarySize() != right->getSecondarySize())) |
1162 | return false; |
1163 | setType(TType(EbtBool, EbpUndefined)); |
1164 | break; |
1165 | |
1166 | case EOpOuterProduct: |
1167 | if(!left->isVector() || !right->isVector()) |
1168 | return false; |
1169 | setType(TType(EbtFloat, right->getNominalSize(), left->getNominalSize())); |
1170 | break; |
1171 | |
1172 | case EOpTranspose: |
1173 | if(!right->isMatrix()) |
1174 | return false; |
1175 | setType(TType(EbtFloat, right->getSecondarySize(), right->getNominalSize())); |
1176 | break; |
1177 | |
1178 | case EOpDeterminant: |
1179 | if(!right->isMatrix()) |
1180 | return false; |
1181 | setType(TType(EbtFloat)); |
1182 | break; |
1183 | |
1184 | case EOpInverse: |
1185 | if(!right->isMatrix() || right->getNominalSize() != right->getSecondarySize()) |
1186 | return false; |
1187 | setType(right->getType()); |
1188 | break; |
1189 | |
1190 | default: |
1191 | return false; |
1192 | } |
1193 | |
1194 | return true; |
1195 | } |
1196 | |
1197 | bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) |
1198 | { |
1199 | const TFieldList& fields = leftNodeType.getStruct()->fields(); |
1200 | |
1201 | size_t structSize = fields.size(); |
1202 | int index = 0; |
1203 | |
1204 | for (size_t j = 0; j < structSize; j++) { |
1205 | size_t size = fields[j]->type()->getObjectSize(); |
1206 | for(size_t i = 0; i < size; i++) { |
1207 | if (fields[j]->type()->getBasicType() == EbtStruct) { |
1208 | if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index])) |
1209 | return false; |
1210 | } else { |
1211 | if (leftUnionArray[index] != rightUnionArray[index]) |
1212 | return false; |
1213 | index++; |
1214 | } |
1215 | |
1216 | } |
1217 | } |
1218 | return true; |
1219 | } |
1220 | |
1221 | bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) |
1222 | { |
1223 | if (leftNodeType.isArray()) { |
1224 | TType typeWithoutArrayness = leftNodeType; |
1225 | typeWithoutArrayness.clearArrayness(); |
1226 | |
1227 | int arraySize = leftNodeType.getArraySize(); |
1228 | |
1229 | for (int i = 0; i < arraySize; ++i) { |
1230 | size_t offset = typeWithoutArrayness.getObjectSize() * i; |
1231 | if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) |
1232 | return false; |
1233 | } |
1234 | } else |
1235 | return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); |
1236 | |
1237 | return true; |
1238 | } |
1239 | |
1240 | float determinant2(float m00, float m01, float m10, float m11) |
1241 | { |
1242 | return m00 * m11 - m01 * m10; |
1243 | } |
1244 | |
1245 | float determinant3(float m00, float m01, float m02, |
1246 | float m10, float m11, float m12, |
1247 | float m20, float m21, float m22) |
1248 | { |
1249 | return m00 * determinant2(m11, m12, m21, m22) - |
1250 | m10 * determinant2(m01, m02, m21, m22) + |
1251 | m20 * determinant2(m01, m02, m11, m12); |
1252 | } |
1253 | |
1254 | float determinant4(float m00, float m01, float m02, float m03, |
1255 | float m10, float m11, float m12, float m13, |
1256 | float m20, float m21, float m22, float m23, |
1257 | float m30, float m31, float m32, float m33) |
1258 | { |
1259 | return m00 * determinant3(m11, m12, m13, m21, m22, m23, m31, m32, m33) - |
1260 | m10 * determinant3(m01, m02, m03, m21, m22, m23, m31, m32, m33) + |
1261 | m20 * determinant3(m01, m02, m03, m11, m12, m13, m31, m32, m33) - |
1262 | m30 * determinant3(m01, m02, m03, m11, m12, m13, m21, m22, m23); |
1263 | } |
1264 | |
1265 | float ComputeDeterminant(int size, ConstantUnion* unionArray) |
1266 | { |
1267 | switch(size) |
1268 | { |
1269 | case 2: |
1270 | return determinant2(unionArray[0].getFConst(), |
1271 | unionArray[1].getFConst(), |
1272 | unionArray[2].getFConst(), |
1273 | unionArray[3].getFConst()); |
1274 | case 3: |
1275 | return determinant3(unionArray[0].getFConst(), |
1276 | unionArray[1].getFConst(), |
1277 | unionArray[2].getFConst(), |
1278 | unionArray[3].getFConst(), |
1279 | unionArray[4].getFConst(), |
1280 | unionArray[5].getFConst(), |
1281 | unionArray[6].getFConst(), |
1282 | unionArray[7].getFConst(), |
1283 | unionArray[8].getFConst()); |
1284 | case 4: |
1285 | return determinant4(unionArray[0].getFConst(), |
1286 | unionArray[1].getFConst(), |
1287 | unionArray[2].getFConst(), |
1288 | unionArray[3].getFConst(), |
1289 | unionArray[4].getFConst(), |
1290 | unionArray[5].getFConst(), |
1291 | unionArray[6].getFConst(), |
1292 | unionArray[7].getFConst(), |
1293 | unionArray[8].getFConst(), |
1294 | unionArray[9].getFConst(), |
1295 | unionArray[10].getFConst(), |
1296 | unionArray[11].getFConst(), |
1297 | unionArray[12].getFConst(), |
1298 | unionArray[13].getFConst(), |
1299 | unionArray[14].getFConst(), |
1300 | unionArray[15].getFConst()); |
1301 | default: |
1302 | UNREACHABLE(size); |
1303 | return 0.0f; |
1304 | } |
1305 | } |
1306 | |
1307 | ConstantUnion* CreateInverse(TIntermConstantUnion* node, ConstantUnion* unionArray) |
1308 | { |
1309 | ConstantUnion* tempConstArray = 0; |
1310 | int size = node->getNominalSize(); |
1311 | float determinant = ComputeDeterminant(size, unionArray); |
1312 | if(determinant != 0.0f) |
1313 | { |
1314 | float invDet = 1.0f / determinant; |
1315 | tempConstArray = new ConstantUnion[size*size]; |
1316 | switch(size) |
1317 | { |
1318 | case 2: |
1319 | { |
1320 | float m00 = unionArray[0].getFConst(); // Matrix is: |
1321 | float m01 = unionArray[1].getFConst(); // (m00, m01) |
1322 | float m10 = unionArray[2].getFConst(); // (m10, m11) |
1323 | float m11 = unionArray[3].getFConst(); |
1324 | tempConstArray[0].setFConst( invDet * m11); |
1325 | tempConstArray[1].setFConst(-invDet * m01); |
1326 | tempConstArray[2].setFConst(-invDet * m10); |
1327 | tempConstArray[3].setFConst( invDet * m00); |
1328 | } |
1329 | break; |
1330 | case 3: |
1331 | { |
1332 | float m00 = unionArray[0].getFConst(); // Matrix is: |
1333 | float m01 = unionArray[1].getFConst(); // (m00, m01, m02) |
1334 | float m02 = unionArray[2].getFConst(); // (m10, m11, m12) |
1335 | float m10 = unionArray[3].getFConst(); // (m20, m21, m22) |
1336 | float m11 = unionArray[4].getFConst(); |
1337 | float m12 = unionArray[5].getFConst(); |
1338 | float m20 = unionArray[6].getFConst(); |
1339 | float m21 = unionArray[7].getFConst(); |
1340 | float m22 = unionArray[8].getFConst(); |
1341 | tempConstArray[0].setFConst(invDet * determinant2(m11, m12, m21, m22)); // m00 = invDet * (m11 * m22 - m12 * m21) |
1342 | tempConstArray[1].setFConst(invDet * determinant2(m12, m10, m22, m20)); // m01 = -invDet * (m10 * m22 - m12 * m20) |
1343 | tempConstArray[2].setFConst(invDet * determinant2(m10, m11, m20, m21)); // m02 = invDet * (m10 * m21 - m11 * m20) |
1344 | tempConstArray[3].setFConst(invDet * determinant2(m21, m22, m01, m02)); // m10 = -invDet * (m01 * m22 - m02 * m21) |
1345 | tempConstArray[4].setFConst(invDet * determinant2(m00, m02, m20, m22)); // m11 = invDet * (m00 * m22 - m02 * m20) |
1346 | tempConstArray[5].setFConst(invDet * determinant2(m20, m21, m00, m01)); // m12 = -invDet * (m00 * m21 - m01 * m20) |
1347 | tempConstArray[6].setFConst(invDet * determinant2(m01, m02, m11, m12)); // m20 = invDet * (m01 * m12 - m02 * m11) |
1348 | tempConstArray[7].setFConst(invDet * determinant2(m10, m12, m00, m02)); // m21 = -invDet * (m00 * m12 - m02 * m10) |
1349 | tempConstArray[8].setFConst(invDet * determinant2(m00, m01, m10, m11)); // m22 = invDet * (m00 * m11 - m01 * m10) |
1350 | } |
1351 | break; |
1352 | case 4: |
1353 | { |
1354 | float m00 = unionArray[0].getFConst(); // Matrix is: |
1355 | float m01 = unionArray[1].getFConst(); // (m00, m01, m02, m03) |
1356 | float m02 = unionArray[2].getFConst(); // (m10, m11, m12, m13) |
1357 | float m03 = unionArray[3].getFConst(); // (m20, m21, m22, m23) |
1358 | float m10 = unionArray[4].getFConst(); // (m30, m31, m32, m33) |
1359 | float m11 = unionArray[5].getFConst(); |
1360 | float m12 = unionArray[6].getFConst(); |
1361 | float m13 = unionArray[7].getFConst(); |
1362 | float m20 = unionArray[8].getFConst(); |
1363 | float m21 = unionArray[9].getFConst(); |
1364 | float m22 = unionArray[10].getFConst(); |
1365 | float m23 = unionArray[11].getFConst(); |
1366 | float m30 = unionArray[12].getFConst(); |
1367 | float m31 = unionArray[13].getFConst(); |
1368 | float m32 = unionArray[14].getFConst(); |
1369 | float m33 = unionArray[15].getFConst(); |
1370 | tempConstArray[ 0].setFConst( invDet * determinant3(m11, m12, m13, m21, m22, m23, m31, m32, m33)); // m00 |
1371 | tempConstArray[ 1].setFConst(-invDet * determinant3(m10, m12, m13, m20, m22, m23, m30, m32, m33)); // m01 |
1372 | tempConstArray[ 2].setFConst( invDet * determinant3(m10, m11, m13, m20, m21, m23, m30, m31, m33)); // m02 |
1373 | tempConstArray[ 3].setFConst(-invDet * determinant3(m10, m11, m12, m20, m21, m22, m30, m31, m32)); // m03 |
1374 | tempConstArray[ 4].setFConst( invDet * determinant3(m01, m02, m03, m21, m22, m23, m31, m32, m33)); // m10 |
1375 | tempConstArray[ 5].setFConst(-invDet * determinant3(m00, m02, m03, m20, m22, m23, m30, m32, m33)); // m11 |
1376 | tempConstArray[ 6].setFConst( invDet * determinant3(m00, m01, m03, m20, m21, m23, m30, m31, m33)); // m12 |
1377 | tempConstArray[ 7].setFConst(-invDet * determinant3(m00, m01, m02, m20, m21, m22, m30, m31, m32)); // m13 |
1378 | tempConstArray[ 8].setFConst( invDet * determinant3(m01, m02, m03, m11, m12, m13, m31, m32, m33)); // m20 |
1379 | tempConstArray[ 9].setFConst(-invDet * determinant3(m00, m02, m03, m10, m12, m13, m30, m32, m33)); // m21 |
1380 | tempConstArray[10].setFConst( invDet * determinant3(m00, m01, m03, m10, m11, m13, m30, m31, m33)); // m22 |
1381 | tempConstArray[11].setFConst(-invDet * determinant3(m00, m01, m02, m10, m11, m12, m30, m31, m32)); // m23 |
1382 | tempConstArray[12].setFConst( invDet * determinant3(m01, m02, m03, m11, m12, m13, m21, m22, m23)); // m30 |
1383 | tempConstArray[13].setFConst(-invDet * determinant3(m00, m02, m03, m10, m12, m13, m20, m22, m23)); // m31 |
1384 | tempConstArray[14].setFConst( invDet * determinant3(m00, m01, m03, m10, m11, m13, m20, m21, m23)); // m32 |
1385 | tempConstArray[15].setFConst(-invDet * determinant3(m00, m01, m02, m10, m11, m12, m20, m21, m22)); // m33 |
1386 | } |
1387 | break; |
1388 | default: |
1389 | UNREACHABLE(size); |
1390 | } |
1391 | } |
1392 | return tempConstArray; |
1393 | } |
1394 | |
1395 | // |
1396 | // The fold functions see if an operation on a constant can be done in place, |
1397 | // without generating run-time code. |
1398 | // |
1399 | // Returns the node to keep using, which may or may not be the node passed in. |
1400 | // |
1401 | |
1402 | TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) |
1403 | { |
1404 | ConstantUnion *unionArray = getUnionArrayPointer(); |
1405 | size_t objectSize = getType().getObjectSize(); |
1406 | |
1407 | if (constantNode) { // binary operations |
1408 | TIntermConstantUnion *node = constantNode->getAsConstantUnion(); |
1409 | ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); |
1410 | TType returnType = getType(); |
1411 | |
1412 | // for a case like float f = 1.2 + vec4(2,3,4,5); |
1413 | if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { |
1414 | rightUnionArray = new ConstantUnion[objectSize]; |
1415 | for (size_t i = 0; i < objectSize; ++i) |
1416 | rightUnionArray[i] = *node->getUnionArrayPointer(); |
1417 | returnType = getType(); |
1418 | } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { |
1419 | // for a case like float f = vec4(2,3,4,5) + 1.2; |
1420 | unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; |
1421 | for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) |
1422 | unionArray[i] = *getUnionArrayPointer(); |
1423 | returnType = node->getType(); |
1424 | objectSize = constantNode->getType().getObjectSize(); |
1425 | } |
1426 | |
1427 | ConstantUnion* tempConstArray = 0; |
1428 | TIntermConstantUnion *tempNode; |
1429 | |
1430 | switch(op) { |
1431 | case EOpAdd: |
1432 | tempConstArray = new ConstantUnion[objectSize]; |
1433 | {// support MSVC++6.0 |
1434 | for (size_t i = 0; i < objectSize; i++) |
1435 | tempConstArray[i] = unionArray[i] + rightUnionArray[i]; |
1436 | } |
1437 | break; |
1438 | case EOpSub: |
1439 | tempConstArray = new ConstantUnion[objectSize]; |
1440 | {// support MSVC++6.0 |
1441 | for (size_t i = 0; i < objectSize; i++) |
1442 | tempConstArray[i] = unionArray[i] - rightUnionArray[i]; |
1443 | } |
1444 | break; |
1445 | |
1446 | case EOpMul: |
1447 | case EOpVectorTimesScalar: |
1448 | case EOpMatrixTimesScalar: |
1449 | tempConstArray = new ConstantUnion[objectSize]; |
1450 | {// support MSVC++6.0 |
1451 | for (size_t i = 0; i < objectSize; i++) |
1452 | tempConstArray[i] = unionArray[i] * rightUnionArray[i]; |
1453 | } |
1454 | break; |
1455 | case EOpMatrixTimesMatrix: |
1456 | if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { |
1457 | infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply" , getLine()); |
1458 | return 0; |
1459 | } |
1460 | {// support MSVC++6.0 |
1461 | int leftNumCols = getNominalSize(); |
1462 | int leftNumRows = getSecondarySize(); |
1463 | int rightNumCols = node->getNominalSize(); |
1464 | int rightNumRows = node->getSecondarySize(); |
1465 | if(leftNumCols != rightNumRows) { |
1466 | infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply" , getLine()); |
1467 | return 0; |
1468 | } |
1469 | int tempNumCols = rightNumCols; |
1470 | int tempNumRows = leftNumRows; |
1471 | int tempNumAdds = leftNumCols; |
1472 | tempConstArray = new ConstantUnion[tempNumCols*tempNumRows]; |
1473 | for (int row = 0; row < tempNumRows; row++) { |
1474 | for (int column = 0; column < tempNumCols; column++) { |
1475 | tempConstArray[tempNumRows * column + row].setFConst(0.0f); |
1476 | for (int i = 0; i < tempNumAdds; i++) { |
1477 | tempConstArray[tempNumRows * column + row].setFConst(tempConstArray[tempNumRows * column + row].getFConst() + unionArray[i * leftNumRows + row].getFConst() * (rightUnionArray[column * rightNumRows + i].getFConst())); |
1478 | } |
1479 | } |
1480 | } |
1481 | // update return type for matrix product |
1482 | returnType.setNominalSize(static_cast<unsigned char>(tempNumCols)); |
1483 | returnType.setSecondarySize(static_cast<unsigned char>(tempNumRows)); |
1484 | } |
1485 | break; |
1486 | |
1487 | case EOpOuterProduct: |
1488 | { |
1489 | int leftSize = getNominalSize(); |
1490 | int rightSize = node->getNominalSize(); |
1491 | tempConstArray = new ConstantUnion[leftSize*rightSize]; |
1492 | for(int row = 0; row < leftSize; row++) { |
1493 | for(int column = 0; column < rightSize; column++) { |
1494 | tempConstArray[leftSize * column + row].setFConst(unionArray[row].getFConst() * rightUnionArray[column].getFConst()); |
1495 | } |
1496 | } |
1497 | // update return type for outer product |
1498 | returnType.setNominalSize(static_cast<unsigned char>(rightSize)); |
1499 | returnType.setSecondarySize(static_cast<unsigned char>(leftSize)); |
1500 | } |
1501 | break; |
1502 | |
1503 | case EOpTranspose: |
1504 | { |
1505 | int rightCol = node->getNominalSize(); |
1506 | int rightRow = node->getSecondarySize(); |
1507 | tempConstArray = new ConstantUnion[rightCol*rightRow]; |
1508 | for(int row = 0; row < rightRow; row++) { |
1509 | for(int column = 0; column < rightCol; column++) { |
1510 | tempConstArray[rightRow * column + row].setFConst(rightUnionArray[rightCol * row + column].getFConst()); |
1511 | } |
1512 | } |
1513 | // update return type for transpose |
1514 | returnType.setNominalSize(static_cast<unsigned char>(rightRow)); |
1515 | returnType.setSecondarySize(static_cast<unsigned char>(rightCol)); |
1516 | } |
1517 | break; |
1518 | |
1519 | case EOpDeterminant: |
1520 | { |
1521 | ASSERT(node->getNominalSize() == node->getSecondarySize()); |
1522 | |
1523 | tempConstArray = new ConstantUnion[1]; |
1524 | tempConstArray[0].setFConst(ComputeDeterminant(node->getNominalSize(), rightUnionArray)); |
1525 | // update return type for determinant |
1526 | returnType.setNominalSize(1); |
1527 | returnType.setSecondarySize(1); |
1528 | } |
1529 | break; |
1530 | |
1531 | case EOpInverse: |
1532 | { |
1533 | ASSERT(node->getNominalSize() == node->getSecondarySize()); |
1534 | |
1535 | tempConstArray = CreateInverse(node, rightUnionArray); |
1536 | if(!tempConstArray) |
1537 | { |
1538 | // Singular matrix, just copy |
1539 | tempConstArray = new ConstantUnion[objectSize]; |
1540 | for(size_t i = 0; i < objectSize; i++) |
1541 | tempConstArray[i] = rightUnionArray[i]; |
1542 | } |
1543 | } |
1544 | break; |
1545 | |
1546 | case EOpDiv: |
1547 | case EOpIMod: |
1548 | tempConstArray = new ConstantUnion[objectSize]; |
1549 | {// support MSVC++6.0 |
1550 | for (size_t i = 0; i < objectSize; i++) { |
1551 | switch (getType().getBasicType()) { |
1552 | case EbtFloat: |
1553 | if (rightUnionArray[i] == 0.0f) { |
1554 | infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding" , getLine()); |
1555 | tempConstArray[i].setFConst(FLT_MAX); |
1556 | } else { |
1557 | ASSERT(op == EOpDiv); |
1558 | tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); |
1559 | } |
1560 | break; |
1561 | |
1562 | case EbtInt: |
1563 | if (rightUnionArray[i] == 0) { |
1564 | infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding" , getLine()); |
1565 | tempConstArray[i].setIConst(INT_MAX); |
1566 | } else { |
1567 | if(op == EOpDiv) { |
1568 | tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); |
1569 | } else { |
1570 | ASSERT(op == EOpIMod); |
1571 | tempConstArray[i].setIConst(unionArray[i].getIConst() % rightUnionArray[i].getIConst()); |
1572 | } |
1573 | } |
1574 | break; |
1575 | case EbtUInt: |
1576 | if (rightUnionArray[i] == 0) { |
1577 | infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding" , getLine()); |
1578 | tempConstArray[i].setUConst(UINT_MAX); |
1579 | } else { |
1580 | if(op == EOpDiv) { |
1581 | tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst()); |
1582 | } else { |
1583 | ASSERT(op == EOpIMod); |
1584 | tempConstArray[i].setUConst(unionArray[i].getUConst() % rightUnionArray[i].getUConst()); |
1585 | } |
1586 | } |
1587 | break; |
1588 | default: |
1589 | infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"" , getLine()); |
1590 | return 0; |
1591 | } |
1592 | } |
1593 | } |
1594 | break; |
1595 | |
1596 | case EOpMatrixTimesVector: |
1597 | if (node->getBasicType() != EbtFloat) { |
1598 | infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector" , getLine()); |
1599 | return 0; |
1600 | } |
1601 | tempConstArray = new ConstantUnion[getSecondarySize()]; |
1602 | |
1603 | {// support MSVC++6.0 |
1604 | for (int rows = getSecondarySize(), i = 0; i < rows; i++) { |
1605 | tempConstArray[i].setFConst(0.0f); |
1606 | for (int cols = getNominalSize(), j = 0; j < cols; j++) { |
1607 | tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*rows + i].getFConst()) * rightUnionArray[j].getFConst())); |
1608 | } |
1609 | } |
1610 | } |
1611 | |
1612 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtFloat, EbpUndefined, EvqConstExpr, getSecondarySize())); |
1613 | tempNode->setLine(getLine()); |
1614 | |
1615 | return tempNode; |
1616 | |
1617 | case EOpVectorTimesMatrix: |
1618 | if (getType().getBasicType() != EbtFloat) { |
1619 | infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix" , getLine()); |
1620 | return 0; |
1621 | } |
1622 | |
1623 | tempConstArray = new ConstantUnion[node->getNominalSize()]; |
1624 | {// support MSVC++6.0 |
1625 | for (int cols = node->getNominalSize(), i = 0; i < cols; i++) { |
1626 | tempConstArray[i].setFConst(0.0f); |
1627 | for (int rows = node->getSecondarySize(), j = 0; j < rows; j++) { |
1628 | tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*rows + j].getFConst())); |
1629 | } |
1630 | } |
1631 | } |
1632 | |
1633 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtFloat, EbpUndefined, EvqConstExpr, node->getNominalSize())); |
1634 | tempNode->setLine(getLine()); |
1635 | return tempNode; |
1636 | |
1637 | case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently |
1638 | tempConstArray = new ConstantUnion[objectSize]; |
1639 | {// support MSVC++6.0 |
1640 | for (size_t i = 0; i < objectSize; i++) |
1641 | tempConstArray[i] = unionArray[i] && rightUnionArray[i]; |
1642 | } |
1643 | break; |
1644 | |
1645 | case EOpLogicalOr: // this code is written for possible future use, will not get executed currently |
1646 | tempConstArray = new ConstantUnion[objectSize]; |
1647 | {// support MSVC++6.0 |
1648 | for (size_t i = 0; i < objectSize; i++) |
1649 | tempConstArray[i] = unionArray[i] || rightUnionArray[i]; |
1650 | } |
1651 | break; |
1652 | |
1653 | case EOpLogicalXor: |
1654 | tempConstArray = new ConstantUnion[objectSize]; |
1655 | {// support MSVC++6.0 |
1656 | for (size_t i = 0; i < objectSize; i++) |
1657 | switch (getType().getBasicType()) { |
1658 | case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; |
1659 | default: assert(false && "Default missing" ); |
1660 | } |
1661 | } |
1662 | break; |
1663 | |
1664 | case EOpBitwiseAnd: |
1665 | tempConstArray = new ConstantUnion[objectSize]; |
1666 | for(size_t i = 0; i < objectSize; i++) |
1667 | tempConstArray[i] = unionArray[i] & rightUnionArray[i]; |
1668 | break; |
1669 | case EOpBitwiseXor: |
1670 | tempConstArray = new ConstantUnion[objectSize]; |
1671 | for(size_t i = 0; i < objectSize; i++) |
1672 | tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; |
1673 | break; |
1674 | case EOpBitwiseOr: |
1675 | tempConstArray = new ConstantUnion[objectSize]; |
1676 | for(size_t i = 0; i < objectSize; i++) |
1677 | tempConstArray[i] = unionArray[i] | rightUnionArray[i]; |
1678 | break; |
1679 | case EOpBitShiftLeft: |
1680 | tempConstArray = new ConstantUnion[objectSize]; |
1681 | for(size_t i = 0; i < objectSize; i++) |
1682 | tempConstArray[i] = unionArray[i] << rightUnionArray[i]; |
1683 | break; |
1684 | case EOpBitShiftRight: |
1685 | tempConstArray = new ConstantUnion[objectSize]; |
1686 | for(size_t i = 0; i < objectSize; i++) |
1687 | tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; |
1688 | break; |
1689 | |
1690 | case EOpLessThan: |
1691 | tempConstArray = new ConstantUnion[objectSize]; |
1692 | for(size_t i = 0; i < objectSize; i++) |
1693 | tempConstArray[i].setBConst(unionArray[i] < rightUnionArray[i]); |
1694 | returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize); |
1695 | break; |
1696 | case EOpGreaterThan: |
1697 | tempConstArray = new ConstantUnion[objectSize]; |
1698 | for(size_t i = 0; i < objectSize; i++) |
1699 | tempConstArray[i].setBConst(unionArray[i] > rightUnionArray[i]); |
1700 | returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize); |
1701 | break; |
1702 | case EOpLessThanEqual: |
1703 | tempConstArray = new ConstantUnion[objectSize]; |
1704 | for(size_t i = 0; i < objectSize; i++) |
1705 | tempConstArray[i].setBConst(unionArray[i] <= rightUnionArray[i]); |
1706 | returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize); |
1707 | break; |
1708 | case EOpGreaterThanEqual: |
1709 | tempConstArray = new ConstantUnion[objectSize]; |
1710 | for(size_t i = 0; i < objectSize; i++) |
1711 | tempConstArray[i].setBConst(unionArray[i] >= rightUnionArray[i]); |
1712 | returnType = TType(EbtBool, EbpUndefined, EvqConstExpr, objectSize); |
1713 | break; |
1714 | case EOpEqual: |
1715 | tempConstArray = new ConstantUnion[1]; |
1716 | |
1717 | if(getType().getBasicType() == EbtStruct) { |
1718 | tempConstArray->setBConst(CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)); |
1719 | } else { |
1720 | bool boolNodeFlag = true; |
1721 | for (size_t i = 0; i < objectSize; i++) { |
1722 | if (unionArray[i] != rightUnionArray[i]) { |
1723 | boolNodeFlag = false; |
1724 | break; // break out of for loop |
1725 | } |
1726 | } |
1727 | tempConstArray->setBConst(boolNodeFlag); |
1728 | } |
1729 | |
1730 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr)); |
1731 | tempNode->setLine(getLine()); |
1732 | |
1733 | return tempNode; |
1734 | |
1735 | case EOpNotEqual: |
1736 | tempConstArray = new ConstantUnion[1]; |
1737 | |
1738 | if(getType().getBasicType() == EbtStruct) { |
1739 | tempConstArray->setBConst(!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)); |
1740 | } else { |
1741 | bool boolNodeFlag = false; |
1742 | for (size_t i = 0; i < objectSize; i++) { |
1743 | if (unionArray[i] != rightUnionArray[i]) { |
1744 | boolNodeFlag = true; |
1745 | break; // break out of for loop |
1746 | } |
1747 | } |
1748 | tempConstArray->setBConst(boolNodeFlag); |
1749 | } |
1750 | |
1751 | tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConstExpr)); |
1752 | tempNode->setLine(getLine()); |
1753 | |
1754 | return tempNode; |
1755 | case EOpMax: |
1756 | tempConstArray = new ConstantUnion[objectSize]; |
1757 | {// support MSVC++6.0 |
1758 | for (size_t i = 0; i < objectSize; i++) |
1759 | tempConstArray[i] = unionArray[i] > rightUnionArray[i] ? unionArray[i] : rightUnionArray[i]; |
1760 | } |
1761 | break; |
1762 | case EOpMin: |
1763 | tempConstArray = new ConstantUnion[objectSize]; |
1764 | {// support MSVC++6.0 |
1765 | for (size_t i = 0; i < objectSize; i++) |
1766 | tempConstArray[i] = unionArray[i] < rightUnionArray[i] ? unionArray[i] : rightUnionArray[i]; |
1767 | } |
1768 | break; |
1769 | default: |
1770 | return 0; |
1771 | } |
1772 | tempNode = new TIntermConstantUnion(tempConstArray, returnType); |
1773 | tempNode->setLine(getLine()); |
1774 | |
1775 | return tempNode; |
1776 | } else { |
1777 | // |
1778 | // Do unary operations |
1779 | // |
1780 | TIntermConstantUnion *newNode = 0; |
1781 | ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; |
1782 | TType type = getType(); |
1783 | TBasicType basicType = type.getBasicType(); |
1784 | for (size_t i = 0; i < objectSize; i++) { |
1785 | switch(op) { |
1786 | case EOpNegative: |
1787 | switch (basicType) { |
1788 | case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; |
1789 | case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; |
1790 | default: |
1791 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1792 | return 0; |
1793 | } |
1794 | break; |
1795 | case EOpLogicalNot: // this code is written for possible future use, will not get executed currently |
1796 | switch (basicType) { |
1797 | case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; |
1798 | default: |
1799 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1800 | return 0; |
1801 | } |
1802 | break; |
1803 | case EOpBitwiseNot: |
1804 | switch(basicType) { |
1805 | case EbtInt: tempConstArray[i].setIConst(~unionArray[i].getIConst()); break; |
1806 | case EbtUInt: tempConstArray[i].setUConst(~unionArray[i].getUConst()); break; |
1807 | default: |
1808 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1809 | return 0; |
1810 | } |
1811 | break; |
1812 | case EOpRadians: |
1813 | switch(basicType) { |
1814 | case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 1.74532925e-2f); break; |
1815 | default: |
1816 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1817 | return 0; |
1818 | } |
1819 | break; |
1820 | case EOpDegrees: |
1821 | switch(basicType) { |
1822 | case EbtFloat: tempConstArray[i].setFConst(unionArray[i].getFConst() * 5.72957795e+1f); break; |
1823 | default: |
1824 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1825 | return 0; |
1826 | } |
1827 | break; |
1828 | case EOpSin: |
1829 | switch(basicType) { |
1830 | case EbtFloat: tempConstArray[i].setFConst(sinf(unionArray[i].getFConst())); break; |
1831 | default: |
1832 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1833 | return 0; |
1834 | } |
1835 | break; |
1836 | case EOpCos: |
1837 | switch(basicType) { |
1838 | case EbtFloat: tempConstArray[i].setFConst(cosf(unionArray[i].getFConst())); break; |
1839 | default: |
1840 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1841 | return 0; |
1842 | } |
1843 | break; |
1844 | case EOpTan: |
1845 | switch(basicType) { |
1846 | case EbtFloat: tempConstArray[i].setFConst(tanf(unionArray[i].getFConst())); break; |
1847 | default: |
1848 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1849 | return 0; |
1850 | } |
1851 | break; |
1852 | case EOpAsin: |
1853 | switch(basicType) { |
1854 | case EbtFloat: tempConstArray[i].setFConst(asinf(unionArray[i].getFConst())); break; |
1855 | default: |
1856 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1857 | return 0; |
1858 | } |
1859 | break; |
1860 | case EOpAcos: |
1861 | switch(basicType) { |
1862 | case EbtFloat: tempConstArray[i].setFConst(acosf(unionArray[i].getFConst())); break; |
1863 | default: |
1864 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1865 | return 0; |
1866 | } |
1867 | break; |
1868 | case EOpAtan: |
1869 | switch(basicType) { |
1870 | case EbtFloat: tempConstArray[i].setFConst(atanf(unionArray[i].getFConst())); break; |
1871 | default: |
1872 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1873 | return 0; |
1874 | } |
1875 | break; |
1876 | case EOpSinh: |
1877 | switch(basicType) { |
1878 | case EbtFloat: tempConstArray[i].setFConst(sinhf(unionArray[i].getFConst())); break; |
1879 | default: |
1880 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1881 | return 0; |
1882 | } |
1883 | break; |
1884 | case EOpCosh: |
1885 | switch(basicType) { |
1886 | case EbtFloat: tempConstArray[i].setFConst(coshf(unionArray[i].getFConst())); break; |
1887 | default: |
1888 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1889 | return 0; |
1890 | } |
1891 | break; |
1892 | case EOpTanh: |
1893 | switch(basicType) { |
1894 | case EbtFloat: tempConstArray[i].setFConst(tanhf(unionArray[i].getFConst())); break; |
1895 | default: |
1896 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1897 | return 0; |
1898 | } |
1899 | break; |
1900 | case EOpAsinh: |
1901 | switch(basicType) { |
1902 | case EbtFloat: tempConstArray[i].setFConst(asinhf(unionArray[i].getFConst())); break; |
1903 | default: |
1904 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1905 | return 0; |
1906 | } |
1907 | break; |
1908 | case EOpAcosh: |
1909 | switch(basicType) { |
1910 | case EbtFloat: tempConstArray[i].setFConst(acoshf(unionArray[i].getFConst())); break; |
1911 | default: |
1912 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1913 | return 0; |
1914 | } |
1915 | break; |
1916 | case EOpAtanh: |
1917 | switch(basicType) { |
1918 | case EbtFloat: tempConstArray[i].setFConst(atanhf(unionArray[i].getFConst())); break; |
1919 | default: |
1920 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1921 | return 0; |
1922 | } |
1923 | break; |
1924 | case EOpLog: |
1925 | switch(basicType) { |
1926 | case EbtFloat: tempConstArray[i].setFConst(logf(unionArray[i].getFConst())); break; |
1927 | default: |
1928 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1929 | return 0; |
1930 | } |
1931 | break; |
1932 | case EOpLog2: |
1933 | switch(basicType) { |
1934 | case EbtFloat: tempConstArray[i].setFConst(sw::log2(unionArray[i].getFConst())); break; |
1935 | default: |
1936 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1937 | return 0; |
1938 | } |
1939 | break; |
1940 | case EOpExp: |
1941 | switch(basicType) { |
1942 | case EbtFloat: tempConstArray[i].setFConst(expf(unionArray[i].getFConst())); break; |
1943 | default: |
1944 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1945 | return 0; |
1946 | } |
1947 | break; |
1948 | case EOpExp2: |
1949 | switch(basicType) { |
1950 | case EbtFloat: tempConstArray[i].setFConst(exp2f(unionArray[i].getFConst())); break; |
1951 | default: |
1952 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1953 | return 0; |
1954 | } |
1955 | break; |
1956 | case EOpSqrt: |
1957 | switch(basicType) { |
1958 | case EbtFloat: tempConstArray[i].setFConst(sqrtf(unionArray[i].getFConst())); break; |
1959 | default: |
1960 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1961 | return 0; |
1962 | } |
1963 | break; |
1964 | case EOpInverseSqrt: |
1965 | switch(basicType) { |
1966 | case EbtFloat: tempConstArray[i].setFConst(1.0f / sqrtf(unionArray[i].getFConst())); break; |
1967 | default: |
1968 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1969 | return 0; |
1970 | } |
1971 | break; |
1972 | case EOpFloatBitsToInt: |
1973 | switch(basicType) { |
1974 | case EbtFloat: |
1975 | tempConstArray[i].setIConst(sw::bit_cast<int>(unionArray[i].getFConst())); |
1976 | type.setBasicType(EbtInt); |
1977 | break; |
1978 | default: |
1979 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1980 | return 0; |
1981 | } |
1982 | break; |
1983 | break; |
1984 | case EOpFloatBitsToUint: |
1985 | switch(basicType) { |
1986 | case EbtFloat: |
1987 | tempConstArray[i].setUConst(sw::bit_cast<unsigned int>(unionArray[i].getFConst())); |
1988 | type.setBasicType(EbtUInt); |
1989 | break; |
1990 | default: |
1991 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
1992 | return 0; |
1993 | } |
1994 | break; |
1995 | case EOpIntBitsToFloat: |
1996 | switch(basicType) { |
1997 | case EbtInt: |
1998 | tempConstArray[i].setFConst(sw::bit_cast<float>(unionArray[i].getIConst())); |
1999 | type.setBasicType(EbtFloat); |
2000 | break; |
2001 | default: |
2002 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
2003 | return 0; |
2004 | } |
2005 | break; |
2006 | case EOpUintBitsToFloat: |
2007 | switch(basicType) { |
2008 | case EbtUInt: |
2009 | tempConstArray[i].setFConst(sw::bit_cast<float>(unionArray[i].getUConst())); |
2010 | type.setBasicType(EbtFloat); |
2011 | break; |
2012 | default: |
2013 | infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant" , getLine()); |
2014 | return 0; |
2015 | } |
2016 | break; |
2017 | default: |
2018 | return 0; |
2019 | } |
2020 | } |
2021 | newNode = new TIntermConstantUnion(tempConstArray, type); |
2022 | newNode->setLine(getLine()); |
2023 | return newNode; |
2024 | } |
2025 | } |
2026 | |
2027 | TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) |
2028 | { |
2029 | size_t size = node->getType().getObjectSize(); |
2030 | |
2031 | ConstantUnion *leftUnionArray = new ConstantUnion[size]; |
2032 | |
2033 | for(size_t i = 0; i < size; i++) { |
2034 | switch (promoteTo) { |
2035 | case EbtFloat: |
2036 | switch (node->getType().getBasicType()) { |
2037 | case EbtInt: |
2038 | leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i))); |
2039 | break; |
2040 | case EbtUInt: |
2041 | leftUnionArray[i].setFConst(static_cast<float>(node->getUConst(i))); |
2042 | break; |
2043 | case EbtBool: |
2044 | leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i))); |
2045 | break; |
2046 | case EbtFloat: |
2047 | leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i))); |
2048 | break; |
2049 | default: |
2050 | infoSink.info.message(EPrefixInternalError, "Cannot promote" , node->getLine()); |
2051 | return 0; |
2052 | } |
2053 | break; |
2054 | case EbtInt: |
2055 | switch (node->getType().getBasicType()) { |
2056 | case EbtInt: |
2057 | leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i))); |
2058 | break; |
2059 | case EbtUInt: |
2060 | leftUnionArray[i].setIConst(static_cast<int>(node->getUConst(i))); |
2061 | break; |
2062 | case EbtBool: |
2063 | leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i))); |
2064 | break; |
2065 | case EbtFloat: |
2066 | leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i))); |
2067 | break; |
2068 | default: |
2069 | infoSink.info.message(EPrefixInternalError, "Cannot promote" , node->getLine()); |
2070 | return 0; |
2071 | } |
2072 | break; |
2073 | case EbtUInt: |
2074 | switch (node->getType().getBasicType()) { |
2075 | case EbtInt: |
2076 | leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getIConst(i))); |
2077 | break; |
2078 | case EbtUInt: |
2079 | leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getUConst(i))); |
2080 | break; |
2081 | case EbtBool: |
2082 | leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getBConst(i))); |
2083 | break; |
2084 | case EbtFloat: |
2085 | leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getFConst(i))); |
2086 | break; |
2087 | default: |
2088 | infoSink.info.message(EPrefixInternalError, "Cannot promote" , node->getLine()); |
2089 | return 0; |
2090 | } |
2091 | break; |
2092 | case EbtBool: |
2093 | switch (node->getType().getBasicType()) { |
2094 | case EbtInt: |
2095 | leftUnionArray[i].setBConst(node->getIConst(i) != 0); |
2096 | break; |
2097 | case EbtUInt: |
2098 | leftUnionArray[i].setBConst(node->getUConst(i) != 0); |
2099 | break; |
2100 | case EbtBool: |
2101 | leftUnionArray[i].setBConst(node->getBConst(i)); |
2102 | break; |
2103 | case EbtFloat: |
2104 | leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); |
2105 | break; |
2106 | default: |
2107 | infoSink.info.message(EPrefixInternalError, "Cannot promote" , node->getLine()); |
2108 | return 0; |
2109 | } |
2110 | |
2111 | break; |
2112 | default: |
2113 | infoSink.info.message(EPrefixInternalError, "Incorrect data type found" , node->getLine()); |
2114 | return 0; |
2115 | } |
2116 | |
2117 | } |
2118 | |
2119 | const TType& t = node->getType(); |
2120 | |
2121 | return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine()); |
2122 | } |
2123 | |
2124 | |