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