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 } 1443