Edit

kc3-lang/angle/src/compiler/translator/intermOut.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-01-02 17:34:40
    Hash : d68924e5
    Message : Use GetOperatorString when writing GLSL unary built-in calls GetOperatorString is now used when writing GLSL for built-in calls that fall under TIntermUnary. Component-wise not TOperator enum is renamed for consistency. This also cleans up some unnecessary creation of string objects when writing built-in functions. BUG=angleproject:1682 TEST=angle_unittests, angle_end2end_tests, WebGL conformance tests Change-Id: I89b2ef222bf5af479d4977417f320789b58ace85 Reviewed-on: https://chromium-review.googlesource.com/424552 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/intermOut.cpp
  • //
    // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "compiler/translator/Intermediate.h"
    #include "compiler/translator/SymbolTable.h"
    
    namespace sh
    {
    
    namespace
    {
    
    void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
    {
        const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
        out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
            << info->getId() << ")";
    }
    
    //
    // Two purposes:
    // 1.  Show an example of how to iterate tree.  Functions can
    //     also directly call Traverse() on children themselves to
    //     have finer grained control over the process than shown here.
    //     See the last function for how to get started.
    // 2.  Print out a text based description of the tree.
    //
    
    //
    // Use this class to carry along data from node to node in
    // the traversal
    //
    class TOutputTraverser : public TIntermTraverser
    {
      public:
        TOutputTraverser(TInfoSinkBase &i) : TIntermTraverser(true, false, false), sink(i) {}
        TInfoSinkBase &sink;
    
      protected:
        void visitSymbol(TIntermSymbol *) override;
        void visitConstantUnion(TIntermConstantUnion *) override;
        bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
        bool visitBinary(Visit visit, TIntermBinary *) override;
        bool visitUnary(Visit visit, TIntermUnary *) override;
        bool visitTernary(Visit visit, TIntermTernary *node) override;
        bool visitIfElse(Visit visit, TIntermIfElse *node) override;
        bool visitSwitch(Visit visit, TIntermSwitch *node) override;
        bool visitCase(Visit visit, TIntermCase *node) override;
        bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
        bool visitAggregate(Visit visit, TIntermAggregate *) override;
        bool visitBlock(Visit visit, TIntermBlock *) override;
        bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
        bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
        bool visitLoop(Visit visit, TIntermLoop *) override;
        bool visitBranch(Visit visit, TIntermBranch *) override;
    };
    
    //
    // Helper functions for printing, not part of traversing.
    //
    void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
    {
        int i;
    
        sink.location(node->getLine().first_file, node->getLine().first_line);
    
        for (i = 0; i < depth; ++i)
            sink << "  ";
    }
    
    }  // namespace anonymous
    
    //
    // The rest of the file are the traversal functions.  The last one
    // is the one that starts the traversal.
    //
    // Return true from interior nodes to have the external traversal
    // continue on to children.  If you process children yourself,
    // return false.
    //
    
    void TOutputTraverser::visitSymbol(TIntermSymbol *node)
    {
        OutputTreeText(sink, node, mDepth);
    
        sink << "'" << node->getSymbol() << "' ";
        sink << "(" << node->getCompleteString() << ")\n";
    }
    
    bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
    {
        TInfoSinkBase &out = sink;
        OutputTreeText(out, node, mDepth);
        out << "vector swizzle";
        return true;
    }
    
    bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        switch (node->getOp())
        {
            case EOpComma:
                out << "comma";
                break;
            case EOpAssign:
                out << "move second child to first child";
                break;
            case EOpInitialize:
                out << "initialize first child with second child";
                break;
            case EOpAddAssign:
                out << "add second child into first child";
                break;
            case EOpSubAssign:
                out << "subtract second child into first child";
                break;
            case EOpMulAssign:
                out << "multiply second child into first child";
                break;
            case EOpVectorTimesMatrixAssign:
                out << "matrix mult second child into first child";
                break;
            case EOpVectorTimesScalarAssign:
                out << "vector scale second child into first child";
                break;
            case EOpMatrixTimesScalarAssign:
                out << "matrix scale second child into first child";
                break;
            case EOpMatrixTimesMatrixAssign:
                out << "matrix mult second child into first child";
                break;
            case EOpDivAssign:
                out << "divide second child into first child";
                break;
            case EOpIModAssign:
                out << "modulo second child into first child";
                break;
            case EOpBitShiftLeftAssign:
                out << "bit-wise shift first child left by second child";
                break;
            case EOpBitShiftRightAssign:
                out << "bit-wise shift first child right by second child";
                break;
            case EOpBitwiseAndAssign:
                out << "bit-wise and second child into first child";
                break;
            case EOpBitwiseXorAssign:
                out << "bit-wise xor second child into first child";
                break;
            case EOpBitwiseOrAssign:
                out << "bit-wise or second child into first child";
                break;
    
            case EOpIndexDirect:
                out << "direct index";
                break;
            case EOpIndexIndirect:
                out << "indirect index";
                break;
            case EOpIndexDirectStruct:
                out << "direct index for structure";
                break;
            case EOpIndexDirectInterfaceBlock:
                out << "direct index for interface block";
                break;
    
            case EOpAdd:
                out << "add";
                break;
            case EOpSub:
                out << "subtract";
                break;
            case EOpMul:
                out << "component-wise multiply";
                break;
            case EOpDiv:
                out << "divide";
                break;
            case EOpIMod:
                out << "modulo";
                break;
            case EOpBitShiftLeft:
                out << "bit-wise shift left";
                break;
            case EOpBitShiftRight:
                out << "bit-wise shift right";
                break;
            case EOpBitwiseAnd:
                out << "bit-wise and";
                break;
            case EOpBitwiseXor:
                out << "bit-wise xor";
                break;
            case EOpBitwiseOr:
                out << "bit-wise or";
                break;
    
            case EOpEqual:
                out << "Compare Equal";
                break;
            case EOpNotEqual:
                out << "Compare Not Equal";
                break;
            case EOpLessThan:
                out << "Compare Less Than";
                break;
            case EOpGreaterThan:
                out << "Compare Greater Than";
                break;
            case EOpLessThanEqual:
                out << "Compare Less Than or Equal";
                break;
            case EOpGreaterThanEqual:
                out << "Compare Greater Than or Equal";
                break;
    
            case EOpVectorTimesScalar:
                out << "vector-scale";
                break;
            case EOpVectorTimesMatrix:
                out << "vector-times-matrix";
                break;
            case EOpMatrixTimesVector:
                out << "matrix-times-vector";
                break;
            case EOpMatrixTimesScalar:
                out << "matrix-scale";
                break;
            case EOpMatrixTimesMatrix:
                out << "matrix-multiply";
                break;
    
            case EOpLogicalOr:
                out << "logical-or";
                break;
            case EOpLogicalXor:
                out << "logical-xor";
                break;
            case EOpLogicalAnd:
                out << "logical-and";
                break;
            default:
                out << "<unknown op>";
        }
    
        out << " (" << node->getCompleteString() << ")";
    
        out << "\n";
    
        // Special handling for direct indexes. Because constant
        // unions are not aware they are struct indexes, treat them
        // here where we have that contextual knowledge.
        if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
        {
            mDepth++;
            node->getLeft()->traverse(this);
            mDepth--;
    
            TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
            ASSERT(intermConstantUnion);
    
            OutputTreeText(out, intermConstantUnion, mDepth + 1);
    
            // The following code finds the field name from the constant union
            const TConstantUnion *constantUnion   = intermConstantUnion->getUnionArrayPointer();
            const TStructure *structure           = node->getLeft()->getType().getStruct();
            const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
            ASSERT(structure || interfaceBlock);
    
            const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
    
            const TField *field = fields[constantUnion->getIConst()];
    
            out << constantUnion->getIConst() << " (field '" << field->name() << "')";
    
            return false;
        }
    
        return true;
    }
    
    bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        switch (node->getOp())
        {
            case EOpNegative:
                out << "Negate value";
                break;
            case EOpPositive:
                out << "Positive sign";
                break;
            case EOpLogicalNot:
                out << "negation";
                break;
            case EOpBitwiseNot:
                out << "bit-wise not";
                break;
    
            case EOpPostIncrement:
                out << "Post-Increment";
                break;
            case EOpPostDecrement:
                out << "Post-Decrement";
                break;
            case EOpPreIncrement:
                out << "Pre-Increment";
                break;
            case EOpPreDecrement:
                out << "Pre-Decrement";
                break;
    
            case EOpRadians:
                out << "radians";
                break;
            case EOpDegrees:
                out << "degrees";
                break;
            case EOpSin:
                out << "sine";
                break;
            case EOpCos:
                out << "cosine";
                break;
            case EOpTan:
                out << "tangent";
                break;
            case EOpAsin:
                out << "arc sine";
                break;
            case EOpAcos:
                out << "arc cosine";
                break;
            case EOpAtan:
                out << "arc tangent";
                break;
    
            case EOpSinh:
                out << "hyperbolic sine";
                break;
            case EOpCosh:
                out << "hyperbolic cosine";
                break;
            case EOpTanh:
                out << "hyperbolic tangent";
                break;
            case EOpAsinh:
                out << "arc hyperbolic sine";
                break;
            case EOpAcosh:
                out << "arc hyperbolic cosine";
                break;
            case EOpAtanh:
                out << "arc hyperbolic tangent";
                break;
    
            case EOpExp:
                out << "exp";
                break;
            case EOpLog:
                out << "log";
                break;
            case EOpExp2:
                out << "exp2";
                break;
            case EOpLog2:
                out << "log2";
                break;
            case EOpSqrt:
                out << "sqrt";
                break;
            case EOpInverseSqrt:
                out << "inverse sqrt";
                break;
    
            case EOpAbs:
                out << "Absolute value";
                break;
            case EOpSign:
                out << "Sign";
                break;
            case EOpFloor:
                out << "Floor";
                break;
            case EOpTrunc:
                out << "Truncate";
                break;
            case EOpRound:
                out << "Round";
                break;
            case EOpRoundEven:
                out << "Round half even";
                break;
            case EOpCeil:
                out << "Ceiling";
                break;
            case EOpFract:
                out << "Fraction";
                break;
            case EOpIsNan:
                out << "Is not a number";
                break;
            case EOpIsInf:
                out << "Is infinity";
                break;
    
            case EOpFloatBitsToInt:
                out << "float bits to int";
                break;
            case EOpFloatBitsToUint:
                out << "float bits to uint";
                break;
            case EOpIntBitsToFloat:
                out << "int bits to float";
                break;
            case EOpUintBitsToFloat:
                out << "uint bits to float";
                break;
    
            case EOpPackSnorm2x16:
                out << "pack Snorm 2x16";
                break;
            case EOpPackUnorm2x16:
                out << "pack Unorm 2x16";
                break;
            case EOpPackHalf2x16:
                out << "pack half 2x16";
                break;
    
            case EOpUnpackSnorm2x16:
                out << "unpack Snorm 2x16";
                break;
            case EOpUnpackUnorm2x16:
                out << "unpack Unorm 2x16";
                break;
            case EOpUnpackHalf2x16:
                out << "unpack half 2x16";
                break;
    
            case EOpLength:
                out << "length";
                break;
            case EOpNormalize:
                out << "normalize";
                break;
            // case EOpDPdx:           out << "dPdx";                 break;
            // case EOpDPdy:           out << "dPdy";                 break;
            // case EOpFwidth:         out << "fwidth";               break;
    
            case EOpDeterminant:
                out << "determinant";
                break;
            case EOpTranspose:
                out << "transpose";
                break;
            case EOpInverse:
                out << "inverse";
                break;
    
            case EOpAny:
                out << "any";
                break;
            case EOpAll:
                out << "all";
                break;
            case EOpLogicalNotComponentWise:
                out << "component-wise not";
                break;
    
            default:
                out.prefix(SH_ERROR);
                out << "Bad unary op";
        }
    
        out << " (" << node->getCompleteString() << ")";
    
        out << "\n";
    
        return true;
    }
    
    bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
    {
        TInfoSinkBase &out = sink;
        OutputTreeText(out, node, mDepth);
        OutputFunction(out, "Function Definition", node->getFunctionSymbolInfo());
        out << "\n";
        return true;
    }
    
    bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
    {
        TInfoSinkBase &out = sink;
        OutputTreeText(out, node, mDepth);
        out << "Invariant Declaration:\n";
        return true;
    }
    
    bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        if (node->getOp() == EOpNull)
        {
            out.prefix(SH_ERROR);
            out << "node is still EOpNull!\n";
            return true;
        }
    
        switch (node->getOp())
        {
            case EOpFunctionCall:
                OutputFunction(out, "Function Call", node->getFunctionSymbolInfo());
                break;
            case EOpParameters:
                out << "Function Parameters: ";
                break;
            case EOpPrototype:
                OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
                break;
    
            case EOpConstructFloat:
                out << "Construct float";
                break;
            case EOpConstructVec2:
                out << "Construct vec2";
                break;
            case EOpConstructVec3:
                out << "Construct vec3";
                break;
            case EOpConstructVec4:
                out << "Construct vec4";
                break;
            case EOpConstructBool:
                out << "Construct bool";
                break;
            case EOpConstructBVec2:
                out << "Construct bvec2";
                break;
            case EOpConstructBVec3:
                out << "Construct bvec3";
                break;
            case EOpConstructBVec4:
                out << "Construct bvec4";
                break;
            case EOpConstructInt:
                out << "Construct int";
                break;
            case EOpConstructIVec2:
                out << "Construct ivec2";
                break;
            case EOpConstructIVec3:
                out << "Construct ivec3";
                break;
            case EOpConstructIVec4:
                out << "Construct ivec4";
                break;
            case EOpConstructUInt:
                out << "Construct uint";
                break;
            case EOpConstructUVec2:
                out << "Construct uvec2";
                break;
            case EOpConstructUVec3:
                out << "Construct uvec3";
                break;
            case EOpConstructUVec4:
                out << "Construct uvec4";
                break;
            case EOpConstructMat2:
                out << "Construct mat2";
                break;
            case EOpConstructMat2x3:
                out << "Construct mat2x3";
                break;
            case EOpConstructMat2x4:
                out << "Construct mat2x4";
                break;
            case EOpConstructMat3x2:
                out << "Construct mat3x2";
                break;
            case EOpConstructMat3:
                out << "Construct mat3";
                break;
            case EOpConstructMat3x4:
                out << "Construct mat3x4";
                break;
            case EOpConstructMat4x2:
                out << "Construct mat4x2";
                break;
            case EOpConstructMat4x3:
                out << "Construct mat4x3";
                break;
            case EOpConstructMat4:
                out << "Construct mat4";
                break;
            case EOpConstructStruct:
                out << "Construct structure";
                break;
    
            case EOpEqualComponentWise:
                out << "component-wise equal";
                break;
            case EOpNotEqualComponentWise:
                out << "component-wise not equal";
                break;
            case EOpLessThanComponentWise:
                out << "component-wise less than";
                break;
            case EOpGreaterThanComponentWise:
                out << "component-wise greater than";
                break;
            case EOpLessThanEqualComponentWise:
                out << "component-wise less than or equal";
                break;
            case EOpGreaterThanEqualComponentWise:
                out << "component-wise greater than or equal";
                break;
    
            case EOpMod:
                out << "mod";
                break;
            case EOpModf:
                out << "modf";
                break;
            case EOpPow:
                out << "pow";
                break;
    
            case EOpAtan:
                out << "arc tangent";
                break;
    
            case EOpMin:
                out << "min";
                break;
            case EOpMax:
                out << "max";
                break;
            case EOpClamp:
                out << "clamp";
                break;
            case EOpMix:
                out << "mix";
                break;
            case EOpStep:
                out << "step";
                break;
            case EOpSmoothStep:
                out << "smoothstep";
                break;
    
            case EOpDistance:
                out << "distance";
                break;
            case EOpDot:
                out << "dot-product";
                break;
            case EOpCross:
                out << "cross-product";
                break;
            case EOpFaceForward:
                out << "face-forward";
                break;
            case EOpReflect:
                out << "reflect";
                break;
            case EOpRefract:
                out << "refract";
                break;
            case EOpMulMatrixComponentWise:
                out << "component-wise multiply";
                break;
    
            case EOpOuterProduct:
                out << "outer product";
                break;
    
            default:
                out.prefix(SH_ERROR);
                out << "Bad aggregation op";
        }
    
        if (node->getOp() != EOpParameters)
            out << " (" << node->getCompleteString() << ")";
    
        out << "\n";
    
        return true;
    }
    
    bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
        out << "Code block\n";
    
        return true;
    }
    
    bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
        out << "Declaration\n";
    
        return true;
    }
    
    bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        out << "Ternary selection";
        out << " (" << node->getCompleteString() << ")\n";
    
        ++mDepth;
    
        OutputTreeText(sink, node, mDepth);
        out << "Condition\n";
        node->getCondition()->traverse(this);
    
        OutputTreeText(sink, node, mDepth);
        if (node->getTrueExpression())
        {
            out << "true case\n";
            node->getTrueExpression()->traverse(this);
        }
        if (node->getFalseExpression())
        {
            OutputTreeText(sink, node, mDepth);
            out << "false case\n";
            node->getFalseExpression()->traverse(this);
        }
    
        --mDepth;
    
        return false;
    }
    
    bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        out << "If test\n";
    
        ++mDepth;
    
        OutputTreeText(sink, node, mDepth);
        out << "Condition\n";
        node->getCondition()->traverse(this);
    
        OutputTreeText(sink, node, mDepth);
        if (node->getTrueBlock())
        {
            out << "true case\n";
            node->getTrueBlock()->traverse(this);
        }
        else
        {
            out << "true case is null\n";
        }
    
        if (node->getFalseBlock())
        {
            OutputTreeText(sink, node, mDepth);
            out << "false case\n";
            node->getFalseBlock()->traverse(this);
        }
    
        --mDepth;
    
        return false;
    }
    
    bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        out << "Switch\n";
    
        return true;
    }
    
    bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        if (node->getCondition() == nullptr)
        {
            out << "Default\n";
        }
        else
        {
            out << "Case\n";
        }
    
        return true;
    }
    
    void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
    {
        TInfoSinkBase &out = sink;
    
        size_t size = node->getType().getObjectSize();
    
        for (size_t i = 0; i < size; i++)
        {
            OutputTreeText(out, node, mDepth);
            switch (node->getUnionArrayPointer()[i].getType())
            {
                case EbtBool:
                    if (node->getUnionArrayPointer()[i].getBConst())
                        out << "true";
                    else
                        out << "false";
    
                    out << " ("
                        << "const bool"
                        << ")";
                    out << "\n";
                    break;
                case EbtFloat:
                    out << node->getUnionArrayPointer()[i].getFConst();
                    out << " (const float)\n";
                    break;
                case EbtInt:
                    out << node->getUnionArrayPointer()[i].getIConst();
                    out << " (const int)\n";
                    break;
                case EbtUInt:
                    out << node->getUnionArrayPointer()[i].getUConst();
                    out << " (const uint)\n";
                    break;
                default:
                    out.prefix(SH_ERROR);
                    out << "Unknown constant";
                    break;
            }
        }
    }
    
    bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        out << "Loop with condition ";
        if (node->getType() == ELoopDoWhile)
            out << "not ";
        out << "tested first\n";
    
        ++mDepth;
    
        OutputTreeText(sink, node, mDepth);
        if (node->getCondition())
        {
            out << "Loop Condition\n";
            node->getCondition()->traverse(this);
        }
        else
        {
            out << "No loop condition\n";
        }
    
        OutputTreeText(sink, node, mDepth);
        if (node->getBody())
        {
            out << "Loop Body\n";
            node->getBody()->traverse(this);
        }
        else
        {
            out << "No loop body\n";
        }
    
        if (node->getExpression())
        {
            OutputTreeText(sink, node, mDepth);
            out << "Loop Terminal Expression\n";
            node->getExpression()->traverse(this);
        }
    
        --mDepth;
    
        return false;
    }
    
    bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
    {
        TInfoSinkBase &out = sink;
    
        OutputTreeText(out, node, mDepth);
    
        switch (node->getFlowOp())
        {
            case EOpKill:
                out << "Branch: Kill";
                break;
            case EOpBreak:
                out << "Branch: Break";
                break;
            case EOpContinue:
                out << "Branch: Continue";
                break;
            case EOpReturn:
                out << "Branch: Return";
                break;
            default:
                out << "Branch: Unknown Branch";
                break;
        }
    
        if (node->getExpression())
        {
            out << " with expression\n";
            ++mDepth;
            node->getExpression()->traverse(this);
            --mDepth;
        }
        else
        {
            out << "\n";
        }
    
        return false;
    }
    
    //
    // This function is the one to call externally to start the traversal.
    // Individual functions can be initialized to 0 to skip processing of that
    // type of node. Its children will still be processed.
    //
    void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
    {
        TOutputTraverser it(infoSink);
    
        ASSERT(root);
    
        root->traverse(&it);
    }
    
    }  // namespace sh