1 //
2 // Copyright 2020 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 <cstring>
8 #include <unordered_map>
9 #include <unordered_set>
10
11 #include "compiler/translator/TranslatorMetalDirect/DiscoverDependentFunctions.h"
12 #include "compiler/translator/TranslatorMetalDirect/DiscoverEnclosingFunctionTraverser.h"
13 #include "compiler/translator/TranslatorMetalDirect/MapFunctionsToDefinitions.h"
14
15 using namespace sh;
16
17 ////////////////////////////////////////////////////////////////////////////////
18
19 namespace
20 {
21
22 class Discoverer : public DiscoverEnclosingFunctionTraverser
23 {
24 private:
25 const std::function<bool(const TVariable &)> &mVars;
26 const FunctionToDefinition &mFuncToDef;
27 std::unordered_set<const TFunction *> mNonDepFunctions;
28
29 public:
30 std::unordered_set<const TFunction *> mDepFunctions;
31
32 public:
Discoverer(const std::function<bool (const TVariable &)> & vars,const FunctionToDefinition & funcToDef)33 Discoverer(const std::function<bool(const TVariable &)> &vars,
34 const FunctionToDefinition &funcToDef)
35 : DiscoverEnclosingFunctionTraverser(true, false, true), mVars(vars), mFuncToDef(funcToDef)
36 {}
37
visitSymbol(TIntermSymbol * symbolNode)38 void visitSymbol(TIntermSymbol *symbolNode) override
39 {
40 const TVariable &var = symbolNode->variable();
41 if (!mVars(var))
42 {
43 return;
44 }
45 const TFunction *owner = discoverEnclosingFunction(symbolNode);
46 ASSERT(owner);
47 mDepFunctions.insert(owner);
48 }
49
visitAggregate(Visit visit,TIntermAggregate * aggregateNode)50 bool visitAggregate(Visit visit, TIntermAggregate *aggregateNode) override
51 {
52 if (visit != Visit::PreVisit)
53 {
54 return true;
55 }
56
57 if (!aggregateNode->isConstructor())
58 {
59 const TFunction *func = aggregateNode->getFunction();
60
61 if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
62 {
63 return true;
64 }
65
66 if (mDepFunctions.find(func) == mDepFunctions.end())
67 {
68 auto it = mFuncToDef.find(func);
69 if (it == mFuncToDef.end())
70 {
71 return true;
72 }
73
74 // Recursion is banned in GLSL, so I believe AngleIR has this property too.
75 // This implementation assumes (direct and mutual) recursion is prohibited.
76 TIntermFunctionDefinition &funcDefNode = *it->second;
77 funcDefNode.traverse(this);
78 if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
79 {
80 return true;
81 }
82 ASSERT(mDepFunctions.find(func) != mDepFunctions.end());
83 }
84
85 const TFunction *owner = discoverEnclosingFunction(aggregateNode);
86 ASSERT(owner);
87 mDepFunctions.insert(owner);
88 }
89
90 return true;
91 }
92
visitFunctionDefinition(Visit visit,TIntermFunctionDefinition * funcDefNode)93 bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *funcDefNode) override
94 {
95 const TFunction *func = funcDefNode->getFunction();
96
97 if (visit != Visit::PostVisit)
98 {
99 if (mDepFunctions.find(func) != mDepFunctions.end())
100 {
101 return false;
102 }
103
104 if (mNonDepFunctions.find(func) != mNonDepFunctions.end())
105 {
106 return false;
107 }
108
109 return true;
110 }
111
112 if (mDepFunctions.find(func) == mDepFunctions.end())
113 {
114 mNonDepFunctions.insert(func);
115 }
116
117 return true;
118 }
119 };
120
121 } // namespace
122
DiscoverDependentFunctions(TIntermBlock & root,const std::function<bool (const TVariable &)> & vars)123 std::unordered_set<const TFunction *> sh::DiscoverDependentFunctions(
124 TIntermBlock &root,
125 const std::function<bool(const TVariable &)> &vars)
126 {
127 const FunctionToDefinition funcToDef = MapFunctionsToDefinitions(root);
128 Discoverer discoverer(vars, funcToDef);
129 root.traverse(&discoverer);
130 return std::move(discoverer.mDepFunctions);
131 }
132