1 //
2 // Copyright 2002 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/translator/BuiltInFunctionEmulator.h"
8 #include "angle_gl.h"
9 #include "compiler/translator/StaticType.h"
10 #include "compiler/translator/Symbol.h"
11 #include "compiler/translator/tree_util/IntermTraverse.h"
12
13 namespace sh
14 {
15
16 class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
17 {
18 public:
BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator & emulator)19 BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
20 : TIntermTraverser(true, false, false), mEmulator(emulator)
21 {}
22
visitUnary(Visit visit,TIntermUnary * node)23 bool visitUnary(Visit visit, TIntermUnary *node) override
24 {
25 if (node->getFunction())
26 {
27 bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
28 if (needToEmulate)
29 node->setUseEmulatedFunction();
30 }
31 return true;
32 }
33
visitAggregate(Visit visit,TIntermAggregate * node)34 bool visitAggregate(Visit visit, TIntermAggregate *node) override
35 {
36 // Here we handle all the math built-in functions, not just the ones that are currently
37 // identified as problematic.
38 if (!BuiltInGroup::IsMath(node->getOp()))
39 {
40 return true;
41 }
42 bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
43 if (needToEmulate)
44 node->setUseEmulatedFunction();
45 return true;
46 }
47
48 private:
49 BuiltInFunctionEmulator &mEmulator;
50 };
51
BuiltInFunctionEmulator()52 BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
53
addEmulatedFunction(const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)54 void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
55 const char *emulatedFunctionDefinition)
56 {
57 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
58 }
59
addEmulatedFunctionWithDependency(const TSymbolUniqueId & dependency,const TSymbolUniqueId & uniqueId,const char * emulatedFunctionDefinition)60 void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
61 const TSymbolUniqueId &dependency,
62 const TSymbolUniqueId &uniqueId,
63 const char *emulatedFunctionDefinition)
64 {
65 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
66 mFunctionDependencies[uniqueId.get()] = dependency.get();
67 }
68
isOutputEmpty() const69 bool BuiltInFunctionEmulator::isOutputEmpty() const
70 {
71 return (mFunctions.size() == 0);
72 }
73
outputEmulatedFunctions(TInfoSinkBase & out) const74 void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
75 {
76 for (const auto &function : mFunctions)
77 {
78 const char *body = findEmulatedFunction(function);
79 ASSERT(body);
80 out << body;
81 out << "\n\n";
82 }
83 }
84
findEmulatedFunction(int uniqueId) const85 const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const
86 {
87 for (const auto &queryFunction : mQueryFunctions)
88 {
89 const char *result = queryFunction(uniqueId);
90 if (result)
91 {
92 return result;
93 }
94 }
95
96 const auto &result = mEmulatedFunctions.find(uniqueId);
97 if (result != mEmulatedFunctions.end())
98 {
99 return result->second.c_str();
100 }
101
102 return nullptr;
103 }
104
setFunctionCalled(const TFunction * function)105 bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
106 {
107 ASSERT(function != nullptr);
108 return setFunctionCalled(function->uniqueId().get());
109 }
110
setFunctionCalled(int uniqueId)111 bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId)
112 {
113 if (!findEmulatedFunction(uniqueId))
114 {
115 return false;
116 }
117
118 for (size_t i = 0; i < mFunctions.size(); ++i)
119 {
120 if (mFunctions[i] == uniqueId)
121 return true;
122 }
123 // If the function depends on another, mark the dependency as called.
124 auto dependency = mFunctionDependencies.find(uniqueId);
125 if (dependency != mFunctionDependencies.end())
126 {
127 setFunctionCalled((*dependency).second);
128 }
129 mFunctions.push_back(uniqueId);
130 return true;
131 }
132
markBuiltInFunctionsForEmulation(TIntermNode * root)133 void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
134 {
135 ASSERT(root);
136
137 if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
138 return;
139
140 BuiltInFunctionEmulationMarker marker(*this);
141 root->traverse(&marker);
142 }
143
cleanup()144 void BuiltInFunctionEmulator::cleanup()
145 {
146 mFunctions.clear();
147 mFunctionDependencies.clear();
148 }
149
addFunctionMap(BuiltinQueryFunc queryFunc)150 void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
151 {
152 mQueryFunctions.push_back(queryFunc);
153 }
154
155 // static
WriteEmulatedFunctionName(TInfoSinkBase & out,const char * name)156 void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
157 {
158 ASSERT(name[strlen(name) - 1] != '(');
159 out << name << "_emu";
160 }
161
162 } // namespace sh
163