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