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 built-in functions mapped to ops, not just the ones that are
37         // currently identified as problematic.
38         if (node->isConstructor() || node->isFunctionCall())
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