summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/DetectRecursion.cpp
blob: c09780dd92d58a1b4a01f0f5da9c24949203576c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//
// Copyright (c) 2002-2011 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/DetectRecursion.h"

DetectRecursion::FunctionNode::FunctionNode(const TString& fname)
    : name(fname),
      visit(PreVisit)
{
}

const TString& DetectRecursion::FunctionNode::getName() const
{
    return name;
}

void DetectRecursion::FunctionNode::addCallee(
    DetectRecursion::FunctionNode* callee)
{
    for (size_t i = 0; i < callees.size(); ++i) {
        if (callees[i] == callee)
            return;
    }
    callees.push_back(callee);
}

bool DetectRecursion::FunctionNode::detectRecursion()
{
    ASSERT(visit == PreVisit);
    visit = InVisit;
    for (size_t i = 0; i < callees.size(); ++i) {
        switch (callees[i]->visit) {
            case InVisit:
                // cycle detected, i.e., recursion detected.
                return true;
            case PostVisit:
                break;
            case PreVisit: {
                bool recursion = callees[i]->detectRecursion();
                if (recursion)
                    return true;
                break;
            }
            default:
                UNREACHABLE();
                break;
        }
    }
    visit = PostVisit;
    return false;
}

DetectRecursion::DetectRecursion()
    : currentFunction(NULL)
{
}

DetectRecursion::~DetectRecursion()
{
    for (size_t i = 0; i < functions.size(); ++i)
        delete functions[i];
}

bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node)
{
    switch (node->getOp())
    {
        case EOpPrototype:
            // Function declaration.
            // Don't add FunctionNode here because node->getName() is the
            // unmangled function name.
            break;
        case EOpFunction: {
            // Function definition.
            if (visit == PreVisit) {
                currentFunction = findFunctionByName(node->getName());
                if (currentFunction == NULL) {
                    currentFunction = new FunctionNode(node->getName());
                    functions.push_back(currentFunction);
                }
            }
            break;
        }
        case EOpFunctionCall: {
            // Function call.
            if (visit == PreVisit) {
                ASSERT(currentFunction != NULL);
                FunctionNode* func = findFunctionByName(node->getName());
                if (func == NULL) {
                    func = new FunctionNode(node->getName());
                    functions.push_back(func);
                }
                currentFunction->addCallee(func);
            }
            break;
        }
        default:
            break;
    }
    return true;
}

DetectRecursion::ErrorCode DetectRecursion::detectRecursion()
{
    FunctionNode* main = findFunctionByName("main(");
    if (main == NULL)
        return kErrorMissingMain;
    if (main->detectRecursion())
        return kErrorRecursion;
    return kErrorNone;
}

DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName(
    const TString& name)
{
    for (size_t i = 0; i < functions.size(); ++i) {
        if (functions[i]->getName() == name)
            return functions[i];
    }
    return NULL;
}