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