blob: d4f30faa8c378975cf50b2bc7c3c79a7a8f9d708 [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
Nicolas Capenscc863da2015-01-21 15:50:55 -05007#include "AnalyzeCallDepth.h"
John Baumand4ae8632014-05-06 16:18:33 -04008
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 {
Alexis Hetu395f00b2015-06-23 16:06:50 -040043 unsigned int calleeDepth = 0;
John Baumand4ae8632014-05-06 16:18:33 -040044 switch(callees[i]->visit)
45 {
46 case InVisit:
47 // Cycle detected (recursion)
48 return UINT_MAX;
49 case PostVisit:
Alexis Hetu395f00b2015-06-23 16:06:50 -040050 calleeDepth = callees[i]->getLastDepth();
John Baumand4ae8632014-05-06 16:18:33 -040051 break;
52 case PreVisit:
Alexis Hetu395f00b2015-06-23 16:06:50 -040053 calleeDepth = callees[i]->analyzeCallDepth(analyzeCallDepth);
John Baumand4ae8632014-05-06 16:18:33 -040054 break;
55 default:
Nicolas Capens3713cd42015-06-22 10:41:54 -040056 UNREACHABLE(callees[i]->visit);
John Baumand4ae8632014-05-06 16:18:33 -040057 break;
58 }
Alexis Hetu395f00b2015-06-23 16:06:50 -040059 if(calleeDepth != UINT_MAX) ++calleeDepth;
60 callDepth = std::max(callDepth, calleeDepth);
John Baumand4ae8632014-05-06 16:18:33 -040061 }
62
63 visit = PostVisit;
64 return callDepth;
65}
66
67unsigned int AnalyzeCallDepth::FunctionNode::getLastDepth() const
68{
69 return callDepth;
70}
71
72void AnalyzeCallDepth::FunctionNode::removeIfUnreachable()
73{
74 if(visit == PreVisit)
75 {
76 node->setOp(EOpPrototype);
77 node->getSequence().resize(1); // Remove function body
78 }
79}
80
81AnalyzeCallDepth::AnalyzeCallDepth(TIntermNode *root)
82 : TIntermTraverser(true, false, true, false),
83 currentFunction(0)
84{
85 root->traverse(this);
86}
87
88AnalyzeCallDepth::~AnalyzeCallDepth()
89{
90 for(size_t i = 0; i < functions.size(); i++)
91 {
92 delete functions[i];
93 }
94}
95
96bool AnalyzeCallDepth::visitAggregate(Visit visit, TIntermAggregate *node)
97{
98 switch(node->getOp())
99 {
100 case EOpFunction: // Function definition
101 {
102 if(visit == PreVisit)
103 {
104 currentFunction = findFunctionByName(node->getName());
105
106 if(!currentFunction)
107 {
108 currentFunction = new FunctionNode(node);
109 functions.push_back(currentFunction);
110 }
111 }
112 else if(visit == PostVisit)
113 {
114 currentFunction = 0;
115 }
116 }
117 break;
118 case EOpFunctionCall:
119 {
120 if(!node->isUserDefined())
121 {
Nicolas Capens7aba0a32014-05-06 16:33:20 -0400122 return true; // Check the arguments for function calls
John Baumand4ae8632014-05-06 16:18:33 -0400123 }
124
125 if(visit == PreVisit)
126 {
127 FunctionNode *function = findFunctionByName(node->getName());
128
129 if(!function)
130 {
131 function = new FunctionNode(node);
132 functions.push_back(function);
133 }
134
135 if(currentFunction)
136 {
137 currentFunction->addCallee(function);
138 }
139 else
140 {
141 globalFunctionCalls.insert(function);
142 }
143 }
144 }
145 break;
146 default:
147 break;
148 }
149
150 return true;
151}
152
153unsigned int AnalyzeCallDepth::analyzeCallDepth()
154{
155 FunctionNode *main = findFunctionByName("main(");
156
157 if(!main)
158 {
159 return 0;
160 }
161
Alexis Hetu395f00b2015-06-23 16:06:50 -0400162 unsigned int depth = main->analyzeCallDepth(this);
163 if(depth != UINT_MAX) ++depth;
John Baumand4ae8632014-05-06 16:18:33 -0400164
165 for(FunctionSet::iterator globalCall = globalFunctionCalls.begin(); globalCall != globalFunctionCalls.end(); globalCall++)
166 {
Alexis Hetu395f00b2015-06-23 16:06:50 -0400167 unsigned int globalDepth = (*globalCall)->analyzeCallDepth(this);
168 if(globalDepth != UINT_MAX) ++globalDepth;
John Baumand4ae8632014-05-06 16:18:33 -0400169
170 if(globalDepth > depth)
171 {
172 depth = globalDepth;
173 }
174 }
175
176 for(size_t i = 0; i < functions.size(); i++)
177 {
178 functions[i]->removeIfUnreachable();
179 }
180
181 return depth;
182}
183
184AnalyzeCallDepth::FunctionNode *AnalyzeCallDepth::findFunctionByName(const TString &name)
185{
186 for(size_t i = 0; i < functions.size(); i++)
187 {
188 if(functions[i]->getName() == name)
189 {
190 return functions[i];
191 }
192 }
193
194 return 0;
195}
196