tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OutputTree.cpp (20641B)


      1 //
      2 // Copyright 2002 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/SymbolTable.h"
      8 #include "compiler/translator/tree_util/IntermTraverse.h"
      9 
     10 namespace sh
     11 {
     12 
     13 namespace
     14 {
     15 
     16 void OutputFunction(TInfoSinkBase &out, const char *str, const TFunction *func)
     17 {
     18    const char *internal =
     19        (func->symbolType() == SymbolType::AngleInternal) ? " (internal function)" : "";
     20    out << str << internal << ": " << func->name() << " (symbol id " << func->uniqueId().get()
     21        << ")";
     22 }
     23 
     24 // Two purposes:
     25 // 1.  Show an example of how to iterate tree.  Functions can also directly call traverse() on
     26 //     children themselves to have finer grained control over the process than shown here, though
     27 //     that's not recommended if it can be avoided.
     28 // 2.  Print out a text based description of the tree.
     29 
     30 // The traverser subclass is used to carry along data from node to node in the traversal.
     31 class TOutputTraverser : public TIntermTraverser
     32 {
     33  public:
     34    TOutputTraverser(TInfoSinkBase &out)
     35        : TIntermTraverser(true, false, false), mOut(out), mIndentDepth(0)
     36    {}
     37 
     38  protected:
     39    void visitSymbol(TIntermSymbol *) override;
     40    void visitConstantUnion(TIntermConstantUnion *) override;
     41    bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
     42    bool visitBinary(Visit visit, TIntermBinary *) override;
     43    bool visitUnary(Visit visit, TIntermUnary *) override;
     44    bool visitTernary(Visit visit, TIntermTernary *node) override;
     45    bool visitIfElse(Visit visit, TIntermIfElse *node) override;
     46    bool visitSwitch(Visit visit, TIntermSwitch *node) override;
     47    bool visitCase(Visit visit, TIntermCase *node) override;
     48    void visitFunctionPrototype(TIntermFunctionPrototype *node) override;
     49    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
     50    bool visitAggregate(Visit visit, TIntermAggregate *) override;
     51    bool visitBlock(Visit visit, TIntermBlock *) override;
     52    bool visitGlobalQualifierDeclaration(Visit visit,
     53                                         TIntermGlobalQualifierDeclaration *node) override;
     54    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
     55    bool visitLoop(Visit visit, TIntermLoop *) override;
     56    bool visitBranch(Visit visit, TIntermBranch *) override;
     57 
     58    int getCurrentIndentDepth() const { return mIndentDepth + getCurrentTraversalDepth(); }
     59 
     60    TInfoSinkBase &mOut;
     61    int mIndentDepth;
     62 };
     63 
     64 //
     65 // Helper functions for printing, not part of traversing.
     66 //
     67 void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth)
     68 {
     69    int i;
     70 
     71    out.location(node->getLine().first_file, node->getLine().first_line);
     72 
     73    for (i = 0; i < depth; ++i)
     74        out << "  ";
     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(mOut, node, getCurrentIndentDepth());
     89 
     90    if (node->variable().symbolType() == SymbolType::Empty)
     91    {
     92        mOut << "''";
     93    }
     94    else
     95    {
     96        mOut << "'" << node->getName() << "' ";
     97    }
     98    mOut << "(symbol id " << node->uniqueId().get() << ") ";
     99    mOut << "(" << node->getType() << ")";
    100    mOut << "\n";
    101 }
    102 
    103 bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
    104 {
    105    OutputTreeText(mOut, node, getCurrentIndentDepth());
    106    mOut << "vector swizzle (";
    107    node->writeOffsetsAsXYZW(&mOut);
    108    mOut << ")";
    109 
    110    mOut << " (" << node->getType() << ")";
    111    mOut << "\n";
    112    return true;
    113 }
    114 
    115 bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
    116 {
    117    OutputTreeText(mOut, node, getCurrentIndentDepth());
    118 
    119    switch (node->getOp())
    120    {
    121        case EOpComma:
    122            mOut << "comma";
    123            break;
    124        case EOpAssign:
    125            mOut << "move second child to first child";
    126            break;
    127        case EOpInitialize:
    128            mOut << "initialize first child with second child";
    129            break;
    130        case EOpAddAssign:
    131            mOut << "add second child into first child";
    132            break;
    133        case EOpSubAssign:
    134            mOut << "subtract second child into first child";
    135            break;
    136        case EOpMulAssign:
    137            mOut << "multiply second child into first child";
    138            break;
    139        case EOpVectorTimesMatrixAssign:
    140            mOut << "matrix mult second child into first child";
    141            break;
    142        case EOpVectorTimesScalarAssign:
    143            mOut << "vector scale second child into first child";
    144            break;
    145        case EOpMatrixTimesScalarAssign:
    146            mOut << "matrix scale second child into first child";
    147            break;
    148        case EOpMatrixTimesMatrixAssign:
    149            mOut << "matrix mult second child into first child";
    150            break;
    151        case EOpDivAssign:
    152            mOut << "divide second child into first child";
    153            break;
    154        case EOpIModAssign:
    155            mOut << "modulo second child into first child";
    156            break;
    157        case EOpBitShiftLeftAssign:
    158            mOut << "bit-wise shift first child left by second child";
    159            break;
    160        case EOpBitShiftRightAssign:
    161            mOut << "bit-wise shift first child right by second child";
    162            break;
    163        case EOpBitwiseAndAssign:
    164            mOut << "bit-wise and second child into first child";
    165            break;
    166        case EOpBitwiseXorAssign:
    167            mOut << "bit-wise xor second child into first child";
    168            break;
    169        case EOpBitwiseOrAssign:
    170            mOut << "bit-wise or second child into first child";
    171            break;
    172 
    173        case EOpIndexDirect:
    174            mOut << "direct index";
    175            break;
    176        case EOpIndexIndirect:
    177            mOut << "indirect index";
    178            break;
    179        case EOpIndexDirectStruct:
    180            mOut << "direct index for structure";
    181            break;
    182        case EOpIndexDirectInterfaceBlock:
    183            mOut << "direct index for interface block";
    184            break;
    185 
    186        case EOpAdd:
    187            mOut << "add";
    188            break;
    189        case EOpSub:
    190            mOut << "subtract";
    191            break;
    192        case EOpMul:
    193            mOut << "component-wise multiply";
    194            break;
    195        case EOpDiv:
    196            mOut << "divide";
    197            break;
    198        case EOpIMod:
    199            mOut << "modulo";
    200            break;
    201        case EOpBitShiftLeft:
    202            mOut << "bit-wise shift left";
    203            break;
    204        case EOpBitShiftRight:
    205            mOut << "bit-wise shift right";
    206            break;
    207        case EOpBitwiseAnd:
    208            mOut << "bit-wise and";
    209            break;
    210        case EOpBitwiseXor:
    211            mOut << "bit-wise xor";
    212            break;
    213        case EOpBitwiseOr:
    214            mOut << "bit-wise or";
    215            break;
    216 
    217        case EOpEqual:
    218            mOut << "Compare Equal";
    219            break;
    220        case EOpNotEqual:
    221            mOut << "Compare Not Equal";
    222            break;
    223        case EOpLessThan:
    224            mOut << "Compare Less Than";
    225            break;
    226        case EOpGreaterThan:
    227            mOut << "Compare Greater Than";
    228            break;
    229        case EOpLessThanEqual:
    230            mOut << "Compare Less Than or Equal";
    231            break;
    232        case EOpGreaterThanEqual:
    233            mOut << "Compare Greater Than or Equal";
    234            break;
    235 
    236        case EOpVectorTimesScalar:
    237            mOut << "vector-scale";
    238            break;
    239        case EOpVectorTimesMatrix:
    240            mOut << "vector-times-matrix";
    241            break;
    242        case EOpMatrixTimesVector:
    243            mOut << "matrix-times-vector";
    244            break;
    245        case EOpMatrixTimesScalar:
    246            mOut << "matrix-scale";
    247            break;
    248        case EOpMatrixTimesMatrix:
    249            mOut << "matrix-multiply";
    250            break;
    251 
    252        case EOpLogicalOr:
    253            mOut << "logical-or";
    254            break;
    255        case EOpLogicalXor:
    256            mOut << "logical-xor";
    257            break;
    258        case EOpLogicalAnd:
    259            mOut << "logical-and";
    260            break;
    261        default:
    262            mOut << "<unknown op>";
    263    }
    264 
    265    mOut << " (" << node->getType() << ")";
    266 
    267    mOut << "\n";
    268 
    269    // Special handling for direct indexes. Because constant
    270    // unions are not aware they are struct indexes, treat them
    271    // here where we have that contextual knowledge.
    272    if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
    273    {
    274        node->getLeft()->traverse(this);
    275 
    276        TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
    277        ASSERT(intermConstantUnion);
    278 
    279        OutputTreeText(mOut, intermConstantUnion, getCurrentIndentDepth() + 1);
    280 
    281        // The following code finds the field name from the constant union
    282        const TConstantUnion *constantUnion   = intermConstantUnion->getConstantValue();
    283        const TStructure *structure           = node->getLeft()->getType().getStruct();
    284        const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
    285        ASSERT(structure || interfaceBlock);
    286 
    287        const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
    288 
    289        const TField *field = fields[constantUnion->getIConst()];
    290 
    291        mOut << constantUnion->getIConst() << " (field '" << field->name() << "')";
    292 
    293        mOut << "\n";
    294 
    295        return false;
    296    }
    297 
    298    return true;
    299 }
    300 
    301 bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
    302 {
    303    OutputTreeText(mOut, node, getCurrentIndentDepth());
    304 
    305    const TOperator op = node->getOp();
    306 
    307    switch (op)
    308    {
    309        // Give verbose names for ops that have special syntax and some built-in functions that are
    310        // easy to confuse with others, but mostly use GLSL names for functions.
    311        case EOpNegative:
    312            mOut << "Negate value";
    313            break;
    314        case EOpPositive:
    315            mOut << "Positive sign";
    316            break;
    317        case EOpLogicalNot:
    318            mOut << "negation";
    319            break;
    320        case EOpBitwiseNot:
    321            mOut << "bit-wise not";
    322            break;
    323 
    324        case EOpPostIncrement:
    325            mOut << "Post-Increment";
    326            break;
    327        case EOpPostDecrement:
    328            mOut << "Post-Decrement";
    329            break;
    330        case EOpPreIncrement:
    331            mOut << "Pre-Increment";
    332            break;
    333        case EOpPreDecrement:
    334            mOut << "Pre-Decrement";
    335            break;
    336 
    337        case EOpArrayLength:
    338            mOut << "Array length";
    339            break;
    340 
    341        case EOpNotComponentWise:
    342            mOut << "component-wise not";
    343            break;
    344 
    345        default:
    346            if (BuiltInGroup::IsBuiltIn(op))
    347            {
    348                OutputFunction(mOut, "Call a built-in function", node->getFunction());
    349            }
    350            else
    351            {
    352                mOut << GetOperatorString(node->getOp());
    353            }
    354            break;
    355    }
    356 
    357    mOut << " (" << node->getType() << ")";
    358 
    359    mOut << "\n";
    360 
    361    return true;
    362 }
    363 
    364 bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
    365 {
    366    OutputTreeText(mOut, node, getCurrentIndentDepth());
    367    mOut << "Function Definition:\n";
    368    return true;
    369 }
    370 
    371 bool TOutputTraverser::visitGlobalQualifierDeclaration(Visit visit,
    372                                                       TIntermGlobalQualifierDeclaration *node)
    373 {
    374    OutputTreeText(mOut, node, getCurrentIndentDepth());
    375    if (node->isPrecise())
    376    {
    377        mOut << "Precise Declaration:\n";
    378    }
    379    else
    380    {
    381        mOut << "Invariant Declaration:\n";
    382    }
    383    return true;
    384 }
    385 
    386 void TOutputTraverser::visitFunctionPrototype(TIntermFunctionPrototype *node)
    387 {
    388    OutputTreeText(mOut, node, getCurrentIndentDepth());
    389    OutputFunction(mOut, "Function Prototype", node->getFunction());
    390    mOut << " (" << node->getType() << ")";
    391    mOut << "\n";
    392    size_t paramCount = node->getFunction()->getParamCount();
    393    for (size_t i = 0; i < paramCount; ++i)
    394    {
    395        const TVariable *param = node->getFunction()->getParam(i);
    396        OutputTreeText(mOut, node, getCurrentIndentDepth() + 1);
    397        mOut << "parameter: " << param->name() << " (" << param->getType() << ")\n";
    398    }
    399 }
    400 
    401 bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
    402 {
    403    OutputTreeText(mOut, node, getCurrentIndentDepth());
    404 
    405    const TOperator op = node->getOp();
    406 
    407    if (op == EOpNull)
    408    {
    409        mOut.prefix(SH_ERROR);
    410        mOut << "node is still EOpNull!\n";
    411        return true;
    412    }
    413 
    414    // Give verbose names for some built-in functions that are easy to confuse with others, but
    415    // mostly use GLSL names for functions.
    416    switch (op)
    417    {
    418        case EOpCallFunctionInAST:
    419            OutputFunction(mOut, "Call a user-defined function", node->getFunction());
    420            break;
    421        case EOpCallInternalRawFunction:
    422            OutputFunction(mOut, "Call an internal function with raw implementation",
    423                           node->getFunction());
    424            break;
    425 
    426        case EOpConstruct:
    427            // The type of the constructor will be printed below.
    428            mOut << "Construct";
    429            break;
    430 
    431        case EOpEqualComponentWise:
    432            mOut << "component-wise equal";
    433            break;
    434        case EOpNotEqualComponentWise:
    435            mOut << "component-wise not equal";
    436            break;
    437        case EOpLessThanComponentWise:
    438            mOut << "component-wise less than";
    439            break;
    440        case EOpGreaterThanComponentWise:
    441            mOut << "component-wise greater than";
    442            break;
    443        case EOpLessThanEqualComponentWise:
    444            mOut << "component-wise less than or equal";
    445            break;
    446        case EOpGreaterThanEqualComponentWise:
    447            mOut << "component-wise greater than or equal";
    448            break;
    449 
    450        case EOpDot:
    451            mOut << "dot product";
    452            break;
    453        case EOpCross:
    454            mOut << "cross product";
    455            break;
    456        case EOpMatrixCompMult:
    457            mOut << "component-wise multiply";
    458            break;
    459 
    460        default:
    461            if (BuiltInGroup::IsBuiltIn(op))
    462            {
    463                OutputFunction(mOut, "Call a built-in function", node->getFunction());
    464            }
    465            else
    466            {
    467                mOut << GetOperatorString(node->getOp());
    468            }
    469            break;
    470    }
    471 
    472    mOut << " (" << node->getType() << ")";
    473 
    474    mOut << "\n";
    475 
    476    return true;
    477 }
    478 
    479 bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
    480 {
    481    OutputTreeText(mOut, node, getCurrentIndentDepth());
    482    mOut << "Code block\n";
    483 
    484    return true;
    485 }
    486 
    487 bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
    488 {
    489    OutputTreeText(mOut, node, getCurrentIndentDepth());
    490    mOut << "Declaration\n";
    491 
    492    return true;
    493 }
    494 
    495 bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
    496 {
    497    OutputTreeText(mOut, node, getCurrentIndentDepth());
    498 
    499    mOut << "Ternary selection";
    500    mOut << " (" << node->getType() << ")\n";
    501 
    502    ++mIndentDepth;
    503 
    504    OutputTreeText(mOut, node, getCurrentIndentDepth());
    505    mOut << "Condition\n";
    506    node->getCondition()->traverse(this);
    507 
    508    OutputTreeText(mOut, node, getCurrentIndentDepth());
    509    if (node->getTrueExpression())
    510    {
    511        mOut << "true case\n";
    512        node->getTrueExpression()->traverse(this);
    513    }
    514    if (node->getFalseExpression())
    515    {
    516        OutputTreeText(mOut, node, getCurrentIndentDepth());
    517        mOut << "false case\n";
    518        node->getFalseExpression()->traverse(this);
    519    }
    520 
    521    --mIndentDepth;
    522 
    523    return false;
    524 }
    525 
    526 bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
    527 {
    528    OutputTreeText(mOut, node, getCurrentIndentDepth());
    529 
    530    mOut << "If test\n";
    531 
    532    ++mIndentDepth;
    533 
    534    OutputTreeText(mOut, node, getCurrentIndentDepth());
    535    mOut << "Condition\n";
    536    node->getCondition()->traverse(this);
    537 
    538    OutputTreeText(mOut, node, getCurrentIndentDepth());
    539    if (node->getTrueBlock())
    540    {
    541        mOut << "true case\n";
    542        node->getTrueBlock()->traverse(this);
    543    }
    544    else
    545    {
    546        mOut << "true case is null\n";
    547    }
    548 
    549    if (node->getFalseBlock())
    550    {
    551        OutputTreeText(mOut, node, getCurrentIndentDepth());
    552        mOut << "false case\n";
    553        node->getFalseBlock()->traverse(this);
    554    }
    555 
    556    --mIndentDepth;
    557 
    558    return false;
    559 }
    560 
    561 bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
    562 {
    563    OutputTreeText(mOut, node, getCurrentIndentDepth());
    564 
    565    mOut << "Switch\n";
    566 
    567    return true;
    568 }
    569 
    570 bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
    571 {
    572    OutputTreeText(mOut, node, getCurrentIndentDepth());
    573 
    574    if (node->getCondition() == nullptr)
    575    {
    576        mOut << "Default\n";
    577    }
    578    else
    579    {
    580        mOut << "Case\n";
    581    }
    582 
    583    return true;
    584 }
    585 
    586 void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
    587 {
    588    size_t size = node->getType().getObjectSize();
    589 
    590    for (size_t i = 0; i < size; i++)
    591    {
    592        OutputTreeText(mOut, node, getCurrentIndentDepth());
    593        switch (node->getConstantValue()[i].getType())
    594        {
    595            case EbtBool:
    596                if (node->getConstantValue()[i].getBConst())
    597                    mOut << "true";
    598                else
    599                    mOut << "false";
    600 
    601                mOut << " ("
    602                     << "const bool"
    603                     << ")";
    604                mOut << "\n";
    605                break;
    606            case EbtFloat:
    607                mOut << node->getConstantValue()[i].getFConst();
    608                mOut << " (const float)\n";
    609                break;
    610            case EbtInt:
    611                mOut << node->getConstantValue()[i].getIConst();
    612                mOut << " (const int)\n";
    613                break;
    614            case EbtUInt:
    615                mOut << node->getConstantValue()[i].getUConst();
    616                mOut << " (const uint)\n";
    617                break;
    618            case EbtYuvCscStandardEXT:
    619                mOut << getYuvCscStandardEXTString(
    620                    node->getConstantValue()[i].getYuvCscStandardEXTConst());
    621                mOut << " (const yuvCscStandardEXT)\n";
    622                break;
    623            default:
    624                mOut.prefix(SH_ERROR);
    625                mOut << "Unknown constant\n";
    626                break;
    627        }
    628    }
    629 }
    630 
    631 bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
    632 {
    633    OutputTreeText(mOut, node, getCurrentIndentDepth());
    634 
    635    mOut << "Loop with condition ";
    636    if (node->getType() == ELoopDoWhile)
    637        mOut << "not ";
    638    mOut << "tested first\n";
    639 
    640    ++mIndentDepth;
    641 
    642    OutputTreeText(mOut, node, getCurrentIndentDepth());
    643    if (node->getCondition())
    644    {
    645        mOut << "Loop Condition\n";
    646        node->getCondition()->traverse(this);
    647    }
    648    else
    649    {
    650        mOut << "No loop condition\n";
    651    }
    652 
    653    OutputTreeText(mOut, node, getCurrentIndentDepth());
    654    if (node->getBody())
    655    {
    656        mOut << "Loop Body\n";
    657        node->getBody()->traverse(this);
    658    }
    659    else
    660    {
    661        mOut << "No loop body\n";
    662    }
    663 
    664    if (node->getExpression())
    665    {
    666        OutputTreeText(mOut, node, getCurrentIndentDepth());
    667        mOut << "Loop Terminal Expression\n";
    668        node->getExpression()->traverse(this);
    669    }
    670 
    671    --mIndentDepth;
    672 
    673    return false;
    674 }
    675 
    676 bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
    677 {
    678    OutputTreeText(mOut, node, getCurrentIndentDepth());
    679 
    680    switch (node->getFlowOp())
    681    {
    682        case EOpKill:
    683            mOut << "Branch: Kill";
    684            break;
    685        case EOpBreak:
    686            mOut << "Branch: Break";
    687            break;
    688        case EOpContinue:
    689            mOut << "Branch: Continue";
    690            break;
    691        case EOpReturn:
    692            mOut << "Branch: Return";
    693            break;
    694        default:
    695            mOut << "Branch: Unknown Branch";
    696            break;
    697    }
    698 
    699    if (node->getExpression())
    700    {
    701        mOut << " with expression\n";
    702        ++mIndentDepth;
    703        node->getExpression()->traverse(this);
    704        --mIndentDepth;
    705    }
    706    else
    707    {
    708        mOut << "\n";
    709    }
    710 
    711    return false;
    712 }
    713 
    714 }  // anonymous namespace
    715 
    716 void OutputTree(TIntermNode *root, TInfoSinkBase &out)
    717 {
    718    TOutputTraverser it(out);
    719    ASSERT(root);
    720    root->traverse(&it);
    721 }
    722 
    723 }  // namespace sh