Home | History | Annotate | Download | only in translator
      1 //
      2 // Copyright (c) 2002-2014 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/translator/Intermediate.h"
     16 #include "compiler/translator/RemoveTree.h"
     17 #include "compiler/translator/SymbolTable.h"
     18 
     19 ////////////////////////////////////////////////////////////////////////////
     20 //
     21 // First set of functions are to help build the intermediate representation.
     22 // These functions are not member functions of the nodes.
     23 // They are called from parser productions.
     24 //
     25 /////////////////////////////////////////////////////////////////////////////
     26 
     27 //
     28 // Add a terminal node for an identifier in an expression.
     29 //
     30 // Returns the added node.
     31 //
     32 TIntermSymbol *TIntermediate::addSymbol(
     33     int id, const TString &name, const TType &type, const TSourceLoc &line)
     34 {
     35     TIntermSymbol *node = new TIntermSymbol(id, name, type);
     36     node->setLine(line);
     37 
     38     return node;
     39 }
     40 
     41 //
     42 // Connect two nodes with a new parent that does a binary operation on the nodes.
     43 //
     44 // Returns the added node.
     45 //
     46 TIntermTyped *TIntermediate::addBinaryMath(
     47     TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
     48 {
     49     switch (op)
     50     {
     51       case EOpEqual:
     52       case EOpNotEqual:
     53         if (left->isArray())
     54             return NULL;
     55         break;
     56       case EOpLessThan:
     57       case EOpGreaterThan:
     58       case EOpLessThanEqual:
     59       case EOpGreaterThanEqual:
     60         if (left->isMatrix() || left->isArray() || left->isVector() ||
     61             left->getBasicType() == EbtStruct)
     62         {
     63             return NULL;
     64         }
     65         break;
     66       case EOpLogicalOr:
     67       case EOpLogicalXor:
     68       case EOpLogicalAnd:
     69         if (left->getBasicType() != EbtBool ||
     70             left->isMatrix() || left->isArray() || left->isVector())
     71         {
     72             return NULL;
     73         }
     74         break;
     75       case EOpAdd:
     76       case EOpSub:
     77       case EOpDiv:
     78       case EOpMul:
     79         if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
     80             return NULL;
     81       default:
     82         break;
     83     }
     84 
     85     if (left->getBasicType() != right->getBasicType())
     86     {
     87         return NULL;
     88     }
     89 
     90     //
     91     // Need a new node holding things together then.  Make
     92     // one and promote it to the right type.
     93     //
     94     TIntermBinary *node = new TIntermBinary(op);
     95     node->setLine(line);
     96 
     97     node->setLeft(left);
     98     node->setRight(right);
     99     if (!node->promote(mInfoSink))
    100         return NULL;
    101 
    102     //
    103     // See if we can fold constants.
    104     //
    105     TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
    106     TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
    107     if (leftTempConstant && rightTempConstant)
    108     {
    109         TIntermTyped *typedReturnNode =
    110             leftTempConstant->fold(node->getOp(), rightTempConstant, mInfoSink);
    111 
    112         if (typedReturnNode)
    113             return typedReturnNode;
    114     }
    115 
    116     return node;
    117 }
    118 
    119 //
    120 // Connect two nodes through an assignment.
    121 //
    122 // Returns the added node.
    123 //
    124 TIntermTyped *TIntermediate::addAssign(
    125     TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
    126 {
    127     if (left->getType().getStruct() || right->getType().getStruct())
    128     {
    129         if (left->getType() != right->getType())
    130         {
    131             return NULL;
    132         }
    133     }
    134 
    135     TIntermBinary *node = new TIntermBinary(op);
    136     node->setLine(line);
    137 
    138     node->setLeft(left);
    139     node->setRight(right);
    140     if (!node->promote(mInfoSink))
    141         return NULL;
    142 
    143     return node;
    144 }
    145 
    146 //
    147 // Connect two nodes through an index operator, where the left node is the base
    148 // of an array or struct, and the right node is a direct or indirect offset.
    149 //
    150 // Returns the added node.
    151 // The caller should set the type of the returned node.
    152 //
    153 TIntermTyped *TIntermediate::addIndex(
    154     TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
    155 {
    156     TIntermBinary *node = new TIntermBinary(op);
    157     node->setLine(line);
    158     node->setLeft(base);
    159     node->setRight(index);
    160 
    161     // caller should set the type
    162 
    163     return node;
    164 }
    165 
    166 //
    167 // Add one node as the parent of another that it operates on.
    168 //
    169 // Returns the added node.
    170 //
    171 TIntermTyped *TIntermediate::addUnaryMath(
    172     TOperator op, TIntermNode *childNode, const TSourceLoc &line)
    173 {
    174     TIntermUnary *node;
    175     TIntermTyped *child = childNode->getAsTyped();
    176 
    177     if (child == NULL)
    178     {
    179         mInfoSink.info.message(EPrefixInternalError, line,
    180                                "Bad type in AddUnaryMath");
    181         return NULL;
    182     }
    183 
    184     switch (op)
    185     {
    186       case EOpLogicalNot:
    187         if (child->getType().getBasicType() != EbtBool ||
    188             child->getType().isMatrix() ||
    189             child->getType().isArray() ||
    190             child->getType().isVector())
    191         {
    192             return NULL;
    193         }
    194         break;
    195 
    196       case EOpPostIncrement:
    197       case EOpPreIncrement:
    198       case EOpPostDecrement:
    199       case EOpPreDecrement:
    200       case EOpNegative:
    201         if (child->getType().getBasicType() == EbtStruct ||
    202             child->getType().isArray())
    203         {
    204             return NULL;
    205         }
    206       default:
    207         break;
    208     }
    209 
    210     TIntermConstantUnion *childTempConstant = 0;
    211     if (child->getAsConstantUnion())
    212         childTempConstant = child->getAsConstantUnion();
    213 
    214     //
    215     // Make a new node for the operator.
    216     //
    217     node = new TIntermUnary(op);
    218     node->setLine(line);
    219     node->setOperand(child);
    220 
    221     if (!node->promote(mInfoSink))
    222         return 0;
    223 
    224     if (childTempConstant)
    225     {
    226         TIntermTyped *newChild = childTempConstant->fold(op, 0, mInfoSink);
    227 
    228         if (newChild)
    229             return newChild;
    230     }
    231 
    232     return node;
    233 }
    234 
    235 //
    236 // This is the safe way to change the operator on an aggregate, as it
    237 // does lots of error checking and fixing.  Especially for establishing
    238 // a function call's operation on it's set of parameters.  Sequences
    239 // of instructions are also aggregates, but they just direnctly set
    240 // their operator to EOpSequence.
    241 //
    242 // Returns an aggregate node, which could be the one passed in if
    243 // it was already an aggregate but no operator was set.
    244 //
    245 TIntermAggregate *TIntermediate::setAggregateOperator(
    246     TIntermNode *node, TOperator op, const TSourceLoc &line)
    247 {
    248     TIntermAggregate *aggNode;
    249 
    250     //
    251     // Make sure we have an aggregate.  If not turn it into one.
    252     //
    253     if (node)
    254     {
    255         aggNode = node->getAsAggregate();
    256         if (aggNode == NULL || aggNode->getOp() != EOpNull)
    257         {
    258             //
    259             // Make an aggregate containing this node.
    260             //
    261             aggNode = new TIntermAggregate();
    262             aggNode->getSequence()->push_back(node);
    263         }
    264     }
    265     else
    266     {
    267         aggNode = new TIntermAggregate();
    268     }
    269 
    270     //
    271     // Set the operator.
    272     //
    273     aggNode->setOp(op);
    274     aggNode->setLine(line);
    275 
    276     return aggNode;
    277 }
    278 
    279 //
    280 // Safe way to combine two nodes into an aggregate.  Works with null pointers,
    281 // a node that's not a aggregate yet, etc.
    282 //
    283 // Returns the resulting aggregate, unless 0 was passed in for
    284 // both existing nodes.
    285 //
    286 TIntermAggregate *TIntermediate::growAggregate(
    287     TIntermNode *left, TIntermNode *right, const TSourceLoc &line)
    288 {
    289     if (left == NULL && right == NULL)
    290         return NULL;
    291 
    292     TIntermAggregate *aggNode = NULL;
    293     if (left)
    294         aggNode = left->getAsAggregate();
    295     if (!aggNode || aggNode->getOp() != EOpNull)
    296     {
    297         aggNode = new TIntermAggregate;
    298         if (left)
    299             aggNode->getSequence()->push_back(left);
    300     }
    301 
    302     if (right)
    303         aggNode->getSequence()->push_back(right);
    304 
    305     aggNode->setLine(line);
    306 
    307     return aggNode;
    308 }
    309 
    310 //
    311 // Turn an existing node into an aggregate.
    312 //
    313 // Returns an aggregate, unless NULL was passed in for the existing node.
    314 //
    315 TIntermAggregate *TIntermediate::makeAggregate(
    316     TIntermNode *node, const TSourceLoc &line)
    317 {
    318     if (node == NULL)
    319         return NULL;
    320 
    321     TIntermAggregate *aggNode = new TIntermAggregate;
    322     aggNode->getSequence()->push_back(node);
    323 
    324     aggNode->setLine(line);
    325 
    326     return aggNode;
    327 }
    328 
    329 //
    330 // For "if" test nodes.  There are three children; a condition,
    331 // a true path, and a false path.  The two paths are in the
    332 // nodePair.
    333 //
    334 // Returns the selection node created.
    335 //
    336 TIntermNode *TIntermediate::addSelection(
    337     TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line)
    338 {
    339     //
    340     // For compile time constant selections, prune the code and
    341     // test now.
    342     //
    343 
    344     if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion())
    345     {
    346         if (cond->getAsConstantUnion()->getBConst(0) == true)
    347         {
    348             return nodePair.node1 ? setAggregateOperator(
    349                 nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
    350         }
    351         else
    352         {
    353             return nodePair.node2 ? setAggregateOperator(
    354                 nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
    355         }
    356     }
    357 
    358     TIntermSelection *node = new TIntermSelection(
    359         cond, nodePair.node1, nodePair.node2);
    360     node->setLine(line);
    361 
    362     return node;
    363 }
    364 
    365 TIntermTyped *TIntermediate::addComma(
    366     TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line)
    367 {
    368     if (left->getType().getQualifier() == EvqConst &&
    369         right->getType().getQualifier() == EvqConst)
    370     {
    371         return right;
    372     }
    373     else
    374     {
    375         TIntermTyped *commaAggregate = growAggregate(left, right, line);
    376         commaAggregate->getAsAggregate()->setOp(EOpComma);
    377         commaAggregate->setType(right->getType());
    378         commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
    379         return commaAggregate;
    380     }
    381 }
    382 
    383 //
    384 // For "?:" test nodes.  There are three children; a condition,
    385 // a true path, and a false path.  The two paths are specified
    386 // as separate parameters.
    387 //
    388 // Returns the selection node created, or 0 if one could not be.
    389 //
    390 TIntermTyped *TIntermediate::addSelection(
    391     TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
    392     const TSourceLoc &line)
    393 {
    394     if (!cond || !trueBlock || !falseBlock ||
    395         trueBlock->getType() != falseBlock->getType())
    396     {
    397         return NULL;
    398     }
    399 
    400     //
    401     // See if all the operands are constant, then fold it otherwise not.
    402     //
    403 
    404     if (cond->getAsConstantUnion() &&
    405         trueBlock->getAsConstantUnion() &&
    406         falseBlock->getAsConstantUnion())
    407     {
    408         if (cond->getAsConstantUnion()->getBConst(0))
    409             return trueBlock;
    410         else
    411             return falseBlock;
    412     }
    413 
    414     //
    415     // Make a selection node.
    416     //
    417     TIntermSelection *node = new TIntermSelection(
    418         cond, trueBlock, falseBlock, trueBlock->getType());
    419     node->getTypePointer()->setQualifier(EvqTemporary);
    420     node->setLine(line);
    421 
    422     return node;
    423 }
    424 
    425 //
    426 // Constant terminal nodes.  Has a union that contains bool, float or int constants
    427 //
    428 // Returns the constant union node created.
    429 //
    430 
    431 TIntermConstantUnion *TIntermediate::addConstantUnion(
    432     ConstantUnion *unionArrayPointer, const TType &t, const TSourceLoc &line)
    433 {
    434     TIntermConstantUnion *node = new TIntermConstantUnion(unionArrayPointer, t);
    435     node->setLine(line);
    436 
    437     return node;
    438 }
    439 
    440 TIntermTyped *TIntermediate::addSwizzle(
    441     TVectorFields &fields, const TSourceLoc &line)
    442 {
    443 
    444     TIntermAggregate *node = new TIntermAggregate(EOpSequence);
    445 
    446     node->setLine(line);
    447     TIntermConstantUnion *constIntNode;
    448     TIntermSequence *sequenceVector = node->getSequence();
    449     ConstantUnion *unionArray;
    450 
    451     for (int i = 0; i < fields.num; i++)
    452     {
    453         unionArray = new ConstantUnion[1];
    454         unionArray->setIConst(fields.offsets[i]);
    455         constIntNode = addConstantUnion(
    456             unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
    457         sequenceVector->push_back(constIntNode);
    458     }
    459 
    460     return node;
    461 }
    462 
    463 //
    464 // Create loop nodes.
    465 //
    466 TIntermNode *TIntermediate::addLoop(
    467     TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
    468     TIntermNode *body, const TSourceLoc &line)
    469 {
    470     TIntermNode *node = new TIntermLoop(type, init, cond, expr, body);
    471     node->setLine(line);
    472 
    473     return node;
    474 }
    475 
    476 //
    477 // Add branches.
    478 //
    479 TIntermBranch* TIntermediate::addBranch(
    480     TOperator branchOp, const TSourceLoc &line)
    481 {
    482     return addBranch(branchOp, 0, line);
    483 }
    484 
    485 TIntermBranch* TIntermediate::addBranch(
    486     TOperator branchOp, TIntermTyped *expression, const TSourceLoc &line)
    487 {
    488     TIntermBranch *node = new TIntermBranch(branchOp, expression);
    489     node->setLine(line);
    490 
    491     return node;
    492 }
    493 
    494 //
    495 // This is to be executed once the final root is put on top by the parsing
    496 // process.
    497 //
    498 bool TIntermediate::postProcess(TIntermNode *root)
    499 {
    500     if (root == NULL)
    501         return true;
    502 
    503     //
    504     // First, finish off the top level sequence, if any
    505     //
    506     TIntermAggregate *aggRoot = root->getAsAggregate();
    507     if (aggRoot && aggRoot->getOp() == EOpNull)
    508         aggRoot->setOp(EOpSequence);
    509 
    510     return true;
    511 }
    512 
    513 //
    514 // This deletes the tree.
    515 //
    516 void TIntermediate::remove(TIntermNode *root)
    517 {
    518     if (root)
    519         RemoveAllTreeNodes(root);
    520 }
    521