1//
2// Copyright (c) 2002-2011 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
13namespace sh
14{
15
16class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
17{
18 public:
19 BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
20 : TIntermTraverser(true, false, false), mEmulator(emulator)
21 {}
22
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
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
52BuiltInFunctionEmulator::BuiltInFunctionEmulator() {}
53
54void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
55 const char *emulatedFunctionDefinition)
56{
57 mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
58}
59
60void 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
69bool BuiltInFunctionEmulator::isOutputEmpty() const
70{
71 return (mFunctions.size() == 0);
72}
73
74void 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
85const 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
105bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
106{
107 ASSERT(function != nullptr);
108 return setFunctionCalled(function->uniqueId().get());
109}
110
111bool 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
133void 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
144void BuiltInFunctionEmulator::cleanup()
145{
146 mFunctions.clear();
147 mFunctionDependencies.clear();
148}
149
150void BuiltInFunctionEmulator::addFunctionMap(BuiltinQueryFunc queryFunc)
151{
152 mQueryFunctions.push_back(queryFunc);
153}
154
155// static
156void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
157{
158 ASSERT(name[strlen(name) - 1] != '(');
159 out << name << "_emu";
160}
161
162} // namespace sh
163