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 #include "compiler/translator/Intermediate.h"
      8 #include "compiler/translator/SymbolTable.h"
      9 
     10 namespace
     11 {
     12 
     13 //
     14 // Two purposes:
     15 // 1.  Show an example of how to iterate tree.  Functions can
     16 //     also directly call Traverse() on children themselves to
     17 //     have finer grained control over the process than shown here.
     18 //     See the last function for how to get started.
     19 // 2.  Print out a text based description of the tree.
     20 //
     21 
     22 //
     23 // Use this class to carry along data from node to node in
     24 // the traversal
     25 //
     26 class TOutputTraverser : public TIntermTraverser
     27 {
     28   public:
     29     TOutputTraverser(TInfoSinkBase &i)
     30         : sink(i) { }
     31     TInfoSinkBase& sink;
     32 
     33   protected:
     34     void visitSymbol(TIntermSymbol *);
     35     void visitConstantUnion(TIntermConstantUnion *);
     36     bool visitBinary(Visit visit, TIntermBinary *);
     37     bool visitUnary(Visit visit, TIntermUnary *);
     38     bool visitSelection(Visit visit, TIntermSelection *);
     39     bool visitAggregate(Visit visit, TIntermAggregate *);
     40     bool visitLoop(Visit visit, TIntermLoop *);
     41     bool visitBranch(Visit visit, TIntermBranch *);
     42 };
     43 
     44 //
     45 // Helper functions for printing, not part of traversing.
     46 //
     47 void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
     48 {
     49     int i;
     50 
     51     sink.location(node->getLine());
     52 
     53     for (i = 0; i < depth; ++i)
     54         sink << "  ";
     55 }
     56 
     57 }  // namespace anonymous
     58 
     59 
     60 TString TType::getCompleteString() const
     61 {
     62     TStringStream stream;
     63 
     64     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
     65         stream << getQualifierString() << " " << getPrecisionString() << " ";
     66     if (array)
     67         stream << "array[" << getArraySize() << "] of ";
     68     if (isMatrix())
     69         stream << getCols() << "X" << getRows() << " matrix of ";
     70     else if (isVector())
     71         stream << getNominalSize() << "-component vector of ";
     72 
     73     stream << getBasicString();
     74     return stream.str();
     75 }
     76 
     77 //
     78 // The rest of the file are the traversal functions.  The last one
     79 // is the one that starts the traversal.
     80 //
     81 // Return true from interior nodes to have the external traversal
     82 // continue on to children.  If you process children yourself,
     83 // return false.
     84 //
     85 
     86 void TOutputTraverser::visitSymbol(TIntermSymbol *node)
     87 {
     88     OutputTreeText(sink, node, mDepth);
     89 
     90     sink << "'" << node->getSymbol() << "' ";
     91     sink << "(" << node->getCompleteString() << ")\n";
     92 }
     93 
     94 bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
     95 {
     96     TInfoSinkBase& out = sink;
     97 
     98     OutputTreeText(out, node, mDepth);
     99 
    100     switch (node->getOp())
    101     {
    102       case EOpAssign:
    103         out << "move second child to first child";
    104         break;
    105       case EOpInitialize:
    106         out << "initialize first child with second child";
    107         break;
    108       case EOpAddAssign:
    109         out << "add second child into first child";
    110         break;
    111       case EOpSubAssign:
    112         out << "subtract second child into first child";
    113         break;
    114       case EOpMulAssign:
    115         out << "multiply second child into first child";
    116         break;
    117       case EOpVectorTimesMatrixAssign:
    118         out << "matrix mult second child into first child";
    119         break;
    120       case EOpVectorTimesScalarAssign:
    121         out << "vector scale second child into first child";
    122         break;
    123       case EOpMatrixTimesScalarAssign:
    124         out << "matrix scale second child into first child";
    125         break;
    126       case EOpMatrixTimesMatrixAssign:
    127         out << "matrix mult second child into first child";
    128         break;
    129       case EOpDivAssign:
    130         out << "divide second child into first child";
    131         break;
    132       case EOpIndexDirect:
    133         out << "direct index";
    134         break;
    135       case EOpIndexIndirect:
    136         out << "indirect index";
    137         break;
    138       case EOpIndexDirectStruct:
    139         out << "direct index for structure";
    140         break;
    141       case EOpIndexDirectInterfaceBlock:
    142         out << "direct index for interface block";
    143         break;
    144       case EOpVectorSwizzle:
    145         out << "vector swizzle";
    146         break;
    147 
    148       case EOpAdd:
    149         out << "add";
    150         break;
    151       case EOpSub:
    152         out << "subtract";
    153         break;
    154       case EOpMul:
    155         out << "component-wise multiply";
    156         break;
    157       case EOpDiv:
    158         out << "divide";
    159         break;
    160       case EOpEqual:
    161         out << "Compare Equal";
    162         break;
    163       case EOpNotEqual:
    164         out << "Compare Not Equal";
    165         break;
    166       case EOpLessThan:
    167         out << "Compare Less Than";
    168         break;
    169       case EOpGreaterThan:
    170         out << "Compare Greater Than";
    171         break;
    172       case EOpLessThanEqual:
    173         out << "Compare Less Than or Equal";
    174         break;
    175       case EOpGreaterThanEqual:
    176         out << "Compare Greater Than or Equal";
    177         break;
    178 
    179       case EOpVectorTimesScalar:
    180         out << "vector-scale";
    181         break;
    182       case EOpVectorTimesMatrix:
    183         out << "vector-times-matrix";
    184         break;
    185       case EOpMatrixTimesVector:
    186         out << "matrix-times-vector";
    187         break;
    188       case EOpMatrixTimesScalar:
    189         out << "matrix-scale";
    190         break;
    191       case EOpMatrixTimesMatrix:
    192         out << "matrix-multiply";
    193         break;
    194 
    195       case EOpLogicalOr:
    196         out << "logical-or";
    197         break;
    198       case EOpLogicalXor:
    199         out << "logical-xor";
    200         break;
    201       case EOpLogicalAnd:
    202         out << "logical-and";
    203         break;
    204       default:
    205         out << "<unknown op>";
    206     }
    207 
    208     out << " (" << node->getCompleteString() << ")";
    209 
    210     out << "\n";
    211 
    212     return true;
    213 }
    214 
    215 bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
    216 {
    217     TInfoSinkBase& out = sink;
    218 
    219     OutputTreeText(out, node, mDepth);
    220 
    221     switch (node->getOp())
    222     {
    223       case EOpNegative:       out << "Negate value";         break;
    224       case EOpVectorLogicalNot:
    225       case EOpLogicalNot:     out << "Negate conditional";   break;
    226 
    227       case EOpPostIncrement:  out << "Post-Increment";       break;
    228       case EOpPostDecrement:  out << "Post-Decrement";       break;
    229       case EOpPreIncrement:   out << "Pre-Increment";        break;
    230       case EOpPreDecrement:   out << "Pre-Decrement";        break;
    231 
    232       case EOpRadians:        out << "radians";              break;
    233       case EOpDegrees:        out << "degrees";              break;
    234       case EOpSin:            out << "sine";                 break;
    235       case EOpCos:            out << "cosine";               break;
    236       case EOpTan:            out << "tangent";              break;
    237       case EOpAsin:           out << "arc sine";             break;
    238       case EOpAcos:           out << "arc cosine";           break;
    239       case EOpAtan:           out << "arc tangent";          break;
    240 
    241       case EOpExp:            out << "exp";                  break;
    242       case EOpLog:            out << "log";                  break;
    243       case EOpExp2:           out << "exp2";                 break;
    244       case EOpLog2:           out << "log2";                 break;
    245       case EOpSqrt:           out << "sqrt";                 break;
    246       case EOpInverseSqrt:    out << "inverse sqrt";         break;
    247 
    248       case EOpAbs:            out << "Absolute value";       break;
    249       case EOpSign:           out << "Sign";                 break;
    250       case EOpFloor:          out << "Floor";                break;
    251       case EOpCeil:           out << "Ceiling";              break;
    252       case EOpFract:          out << "Fraction";             break;
    253 
    254       case EOpLength:         out << "length";               break;
    255       case EOpNormalize:      out << "normalize";            break;
    256       // case EOpDPdx:           out << "dPdx";                 break;
    257       // case EOpDPdy:           out << "dPdy";                 break;
    258       // case EOpFwidth:         out << "fwidth";               break;
    259 
    260       case EOpAny:            out << "any";                  break;
    261       case EOpAll:            out << "all";                  break;
    262 
    263       default:
    264         out.prefix(EPrefixError);
    265         out << "Bad unary op";
    266     }
    267 
    268     out << " (" << node->getCompleteString() << ")";
    269 
    270     out << "\n";
    271 
    272     return true;
    273 }
    274 
    275 bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
    276 {
    277     TInfoSinkBase &out = sink;
    278 
    279     if (node->getOp() == EOpNull)
    280     {
    281         out.prefix(EPrefixError);
    282         out << "node is still EOpNull!";
    283         return true;
    284     }
    285 
    286     OutputTreeText(out, node, mDepth);
    287 
    288     switch (node->getOp())
    289     {
    290       case EOpSequence:      out << "Sequence\n"; return true;
    291       case EOpComma:         out << "Comma\n"; return true;
    292       case EOpFunction:      out << "Function Definition: " << node->getName(); break;
    293       case EOpFunctionCall:  out << "Function Call: " << node->getName(); break;
    294       case EOpParameters:    out << "Function Parameters: ";              break;
    295 
    296       case EOpConstructFloat: out << "Construct float"; break;
    297       case EOpConstructVec2:  out << "Construct vec2";  break;
    298       case EOpConstructVec3:  out << "Construct vec3";  break;
    299       case EOpConstructVec4:  out << "Construct vec4";  break;
    300       case EOpConstructBool:  out << "Construct bool";  break;
    301       case EOpConstructBVec2: out << "Construct bvec2"; break;
    302       case EOpConstructBVec3: out << "Construct bvec3"; break;
    303       case EOpConstructBVec4: out << "Construct bvec4"; break;
    304       case EOpConstructInt:   out << "Construct int";   break;
    305       case EOpConstructIVec2: out << "Construct ivec2"; break;
    306       case EOpConstructIVec3: out << "Construct ivec3"; break;
    307       case EOpConstructIVec4: out << "Construct ivec4"; break;
    308       case EOpConstructUInt:  out << "Construct uint";  break;
    309       case EOpConstructUVec2: out << "Construct uvec2"; break;
    310       case EOpConstructUVec3: out << "Construct uvec3"; break;
    311       case EOpConstructUVec4: out << "Construct uvec4"; break;
    312       case EOpConstructMat2:  out << "Construct mat2";  break;
    313       case EOpConstructMat3:  out << "Construct mat3";  break;
    314       case EOpConstructMat4:  out << "Construct mat4";  break;
    315       case EOpConstructStruct:  out << "Construct structure";  break;
    316 
    317       case EOpLessThan:         out << "Compare Less Than";             break;
    318       case EOpGreaterThan:      out << "Compare Greater Than";          break;
    319       case EOpLessThanEqual:    out << "Compare Less Than or Equal";    break;
    320       case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
    321       case EOpVectorEqual:      out << "Equal";                         break;
    322       case EOpVectorNotEqual:   out << "NotEqual";                      break;
    323 
    324       case EOpMod:           out << "mod";         break;
    325       case EOpPow:           out << "pow";         break;
    326 
    327       case EOpAtan:          out << "arc tangent"; break;
    328 
    329       case EOpMin:           out << "min";         break;
    330       case EOpMax:           out << "max";         break;
    331       case EOpClamp:         out << "clamp";       break;
    332       case EOpMix:           out << "mix";         break;
    333       case EOpStep:          out << "step";        break;
    334       case EOpSmoothStep:    out << "smoothstep";  break;
    335 
    336       case EOpDistance:      out << "distance";                break;
    337       case EOpDot:           out << "dot-product";             break;
    338       case EOpCross:         out << "cross-product";           break;
    339       case EOpFaceForward:   out << "face-forward";            break;
    340       case EOpReflect:       out << "reflect";                 break;
    341       case EOpRefract:       out << "refract";                 break;
    342       case EOpMul:           out << "component-wise multiply"; break;
    343 
    344       case EOpDeclaration:   out << "Declaration: ";   break;
    345       case EOpInvariantDeclaration: out << "Invariant Declaration: "; break;
    346 
    347       default:
    348         out.prefix(EPrefixError);
    349         out << "Bad aggregation op";
    350     }
    351 
    352     if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
    353         out << " (" << node->getCompleteString() << ")";
    354 
    355     out << "\n";
    356 
    357     return true;
    358 }
    359 
    360 bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node)
    361 {
    362     TInfoSinkBase &out = sink;
    363 
    364     OutputTreeText(out, node, mDepth);
    365 
    366     out << "Test condition and select";
    367     out << " (" << node->getCompleteString() << ")\n";
    368 
    369     ++mDepth;
    370 
    371     OutputTreeText(sink, node, mDepth);
    372     out << "Condition\n";
    373     node->getCondition()->traverse(this);
    374 
    375     OutputTreeText(sink, node, mDepth);
    376     if (node->getTrueBlock())
    377     {
    378         out << "true case\n";
    379         node->getTrueBlock()->traverse(this);
    380     }
    381     else
    382     {
    383         out << "true case is null\n";
    384     }
    385 
    386     if (node->getFalseBlock())
    387     {
    388         OutputTreeText(sink, node, mDepth);
    389         out << "false case\n";
    390         node->getFalseBlock()->traverse(this);
    391     }
    392 
    393     --mDepth;
    394 
    395     return false;
    396 }
    397 
    398 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
    399 {
    400     TInfoSinkBase &out = sink;
    401 
    402     size_t size = node->getType().getObjectSize();
    403 
    404     for (size_t i = 0; i < size; i++)
    405     {
    406         OutputTreeText(out, node, mDepth);
    407         switch (node->getUnionArrayPointer()[i].getType())
    408         {
    409           case EbtBool:
    410             if (node->getUnionArrayPointer()[i].getBConst())
    411                 out << "true";
    412             else
    413                 out << "false";
    414 
    415             out << " (" << "const bool" << ")";
    416             out << "\n";
    417             break;
    418           case EbtFloat:
    419             out << node->getUnionArrayPointer()[i].getFConst();
    420             out << " (const float)\n";
    421             break;
    422           case EbtInt:
    423             out << node->getUnionArrayPointer()[i].getIConst();
    424             out << " (const int)\n";
    425             break;
    426           case EbtUInt:
    427             out << node->getUnionArrayPointer()[i].getUConst();
    428             out << " (const uint)\n";
    429             break;
    430           default:
    431             out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
    432             break;
    433         }
    434     }
    435 }
    436 
    437 bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
    438 {
    439     TInfoSinkBase &out = sink;
    440 
    441     OutputTreeText(out, node, mDepth);
    442 
    443     out << "Loop with condition ";
    444     if (node->getType() == ELoopDoWhile)
    445         out << "not ";
    446     out << "tested first\n";
    447 
    448     ++mDepth;
    449 
    450     OutputTreeText(sink, node, mDepth);
    451     if (node->getCondition())
    452     {
    453         out << "Loop Condition\n";
    454         node->getCondition()->traverse(this);
    455     }
    456     else
    457     {
    458         out << "No loop condition\n";
    459     }
    460 
    461     OutputTreeText(sink, node, mDepth);
    462     if (node->getBody())
    463     {
    464         out << "Loop Body\n";
    465         node->getBody()->traverse(this);
    466     }
    467     else
    468     {
    469         out << "No loop body\n";
    470     }
    471 
    472     if (node->getExpression())
    473     {
    474         OutputTreeText(sink, node, mDepth);
    475         out << "Loop Terminal Expression\n";
    476         node->getExpression()->traverse(this);
    477     }
    478 
    479     --mDepth;
    480 
    481     return false;
    482 }
    483 
    484 bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
    485 {
    486     TInfoSinkBase &out = sink;
    487 
    488     OutputTreeText(out, node, mDepth);
    489 
    490     switch (node->getFlowOp())
    491     {
    492       case EOpKill:      out << "Branch: Kill";           break;
    493       case EOpBreak:     out << "Branch: Break";          break;
    494       case EOpContinue:  out << "Branch: Continue";       break;
    495       case EOpReturn:    out << "Branch: Return";         break;
    496       default:           out << "Branch: Unknown Branch"; break;
    497     }
    498 
    499     if (node->getExpression())
    500     {
    501         out << " with expression\n";
    502         ++mDepth;
    503         node->getExpression()->traverse(this);
    504         --mDepth;
    505     }
    506     else
    507     {
    508         out << "\n";
    509     }
    510 
    511     return false;
    512 }
    513 
    514 //
    515 // This function is the one to call externally to start the traversal.
    516 // Individual functions can be initialized to 0 to skip processing of that
    517 // type of node.  It's children will still be processed.
    518 //
    519 void TIntermediate::outputTree(TIntermNode *root)
    520 {
    521     if (root == NULL)
    522         return;
    523 
    524     TOutputTraverser it(mInfoSink.info);
    525 
    526     root->traverse(&it);
    527 }
    528