blob: 903991645ba0679d1fad7983891e8b38a0a6112f [file] [log] [blame]
John Baumand4ae8632014-05-06 16:18:33 -04001//
2// Copyright (c) 2002-2013 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/AnalyzeCallDepth.h"
8
9AnalyzeCallDepth::FunctionNode::FunctionNode(TIntermAggregate *node) : node(node)
10{
11 visit = PreVisit;
12 callDepth = 0;
13}
14
15const TString &AnalyzeCallDepth::FunctionNode::getName() const
16{
17 return node->getName();
18}
19
20void AnalyzeCallDepth::FunctionNode::addCallee(AnalyzeCallDepth::FunctionNode *callee)
21{
22 for(size_t i = 0; i < callees.size(); i++)
23 {
24 if(callees[i] == callee)
25 {
26 return;
27 }
28 }
29
30 callees.push_back(callee);
31}
32
33unsigned int AnalyzeCallDepth::FunctionNode::analyzeCallDepth(AnalyzeCallDepth *analyzeCallDepth)
34{
35 ASSERT(visit == PreVisit);
36 ASSERT(analyzeCallDepth);
37
38 callDepth = 0;
39 visit = InVisit;
40
41 for(size_t i = 0; i < callees.size(); i++)
42 {
43 switch(callees[i]->visit)
44 {
45 case InVisit:
46 // Cycle detected (recursion)
47 return UINT_MAX;
48 case PostVisit:
49 callDepth = std::max(callDepth, 1 + callees[i]->getLastDepth());
50 break;
51 case PreVisit:
52 callDepth = std::max(callDepth, 1 + callees[i]->analyzeCallDepth(analyzeCallDepth));
53 break;
54 default:
55 UNREACHABLE();
56 break;
57 }
58 }
59
60 visit = PostVisit;
61 return callDepth;
62}
63
64unsigned int AnalyzeCallDepth::FunctionNode::getLastDepth() const
65{
66 return callDepth;
67}
68
69void AnalyzeCallDepth::FunctionNode::removeIfUnreachable()
70{
71 if(visit == PreVisit)
72 {
73 node->setOp(EOpPrototype);
74 node->getSequence().resize(1); // Remove function body
75 }
76}
77
78AnalyzeCallDepth::AnalyzeCallDepth(TIntermNode *root)
79 : TIntermTraverser(true, false, true, false),
80 currentFunction(0)
81{
82 root->traverse(this);
83}
84
85AnalyzeCallDepth::~AnalyzeCallDepth()
86{
87 for(size_t i = 0; i < functions.size(); i++)
88 {
89 delete functions[i];
90 }
91}
92
93bool AnalyzeCallDepth::visitAggregate(Visit visit, TIntermAggregate *node)
94{
95 switch(node->getOp())
96 {
97 case EOpFunction: // Function definition
98 {
99 if(visit == PreVisit)
100 {
101 currentFunction = findFunctionByName(node->getName());
102
103 if(!currentFunction)
104 {
105 currentFunction = new FunctionNode(node);
106 functions.push_back(currentFunction);
107 }
108 }
109 else if(visit == PostVisit)
110 {
111 currentFunction = 0;
112 }
113 }
114 break;
115 case EOpFunctionCall:
116 {
117 if(!node->isUserDefined())
118 {
Nicolas Capens7aba0a32014-05-06 16:33:20 -0400119 return true; // Check the arguments for function calls
John Baumand4ae8632014-05-06 16:18:33 -0400120 }
121
122 if(visit == PreVisit)
123 {
124 FunctionNode *function = findFunctionByName(node->getName());
125
126 if(!function)
127 {
128 function = new FunctionNode(node);
129 functions.push_back(function);
130 }
131
132 if(currentFunction)
133 {
134 currentFunction->addCallee(function);
135 }
136 else
137 {
138 globalFunctionCalls.insert(function);
139 }
140 }
141 }
142 break;
143 default:
144 break;
145 }
146
147 return true;
148}
149
150unsigned int AnalyzeCallDepth::analyzeCallDepth()
151{
152 FunctionNode *main = findFunctionByName("main(");
153
154 if(!main)
155 {
156 return 0;
157 }
158
159 unsigned int depth = 1 + main->analyzeCallDepth(this);
160
161 for(FunctionSet::iterator globalCall = globalFunctionCalls.begin(); globalCall != globalFunctionCalls.end(); globalCall++)
162 {
163 unsigned int globalDepth = 1 + (*globalCall)->analyzeCallDepth(this);
164
165 if(globalDepth > depth)
166 {
167 depth = globalDepth;
168 }
169 }
170
171 for(size_t i = 0; i < functions.size(); i++)
172 {
173 functions[i]->removeIfUnreachable();
174 }
175
176 return depth;
177}
178
179AnalyzeCallDepth::FunctionNode *AnalyzeCallDepth::findFunctionByName(const TString &name)
180{
181 for(size_t i = 0; i < functions.size(); i++)
182 {
183 if(functions[i]->getName() == name)
184 {
185 return functions[i];
186 }
187 }
188
189 return 0;
190}
191