1 //
2 // Copyright 2015 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 // compiler_test.cpp:
7 // utilities for compiler unit tests.
8
9 #include "tests/test_utils/compiler_test.h"
10
11 #include "angle_gl.h"
12 #include "compiler/translator/Compiler.h"
13 #include "compiler/translator/FunctionLookup.h"
14 #include "compiler/translator/tree_util/IntermTraverse.h"
15
16 namespace sh
17 {
18
19 namespace
20 {
21
GetSymbolTableMangledName(TIntermAggregate * node)22 ImmutableString GetSymbolTableMangledName(TIntermAggregate *node)
23 {
24 ASSERT(!node->isConstructor());
25 switch (node->getOp())
26 {
27 case EOpCallInternalRawFunction:
28 case EOpCallBuiltInFunction:
29 case EOpCallFunctionInAST:
30 return TFunctionLookup::GetMangledName(node->getFunction()->name().data(),
31 *node->getSequence());
32 default:
33 const char *opString = GetOperatorString(node->getOp());
34 return TFunctionLookup::GetMangledName(opString, *node->getSequence());
35 }
36 }
37
38 class FunctionCallFinder : public TIntermTraverser
39 {
40 public:
FunctionCallFinder(const char * functionMangledName)41 FunctionCallFinder(const char *functionMangledName)
42 : TIntermTraverser(true, false, false),
43 mFunctionMangledName(functionMangledName),
44 mNodeFound(nullptr)
45 {}
46
visitAggregate(Visit visit,TIntermAggregate * node)47 bool visitAggregate(Visit visit, TIntermAggregate *node) override
48 {
49 if (node->isFunctionCall() && GetSymbolTableMangledName(node) == mFunctionMangledName)
50 {
51 mNodeFound = node;
52 return false;
53 }
54 return true;
55 }
56
isFound() const57 bool isFound() const { return mNodeFound != nullptr; }
getNode() const58 const TIntermAggregate *getNode() const { return mNodeFound; }
59
60 private:
61 const char *mFunctionMangledName;
62 TIntermAggregate *mNodeFound;
63 };
64
65 } // anonymous namespace
66
compileTestShader(GLenum type,ShShaderSpec spec,ShShaderOutput output,const std::string & shaderString,ShBuiltInResources * resources,ShCompileOptions compileOptions,std::string * translatedCode,std::string * infoLog)67 bool compileTestShader(GLenum type,
68 ShShaderSpec spec,
69 ShShaderOutput output,
70 const std::string &shaderString,
71 ShBuiltInResources *resources,
72 ShCompileOptions compileOptions,
73 std::string *translatedCode,
74 std::string *infoLog)
75 {
76 sh::TCompiler *translator = sh::ConstructCompiler(type, spec, output);
77 if (!translator->Init(*resources))
78 {
79 SafeDelete(translator);
80 return false;
81 }
82
83 const char *shaderStrings[] = {shaderString.c_str()};
84
85 bool compilationSuccess =
86 translator->compile(shaderStrings, 1, SH_OBJECT_CODE | compileOptions);
87 TInfoSink &infoSink = translator->getInfoSink();
88 if (translatedCode)
89 *translatedCode = infoSink.obj.c_str();
90 if (infoLog)
91 *infoLog = infoSink.info.c_str();
92 SafeDelete(translator);
93 return compilationSuccess;
94 }
95
compileTestShader(GLenum type,ShShaderSpec spec,ShShaderOutput output,const std::string & shaderString,ShCompileOptions compileOptions,std::string * translatedCode,std::string * infoLog)96 bool compileTestShader(GLenum type,
97 ShShaderSpec spec,
98 ShShaderOutput output,
99 const std::string &shaderString,
100 ShCompileOptions compileOptions,
101 std::string *translatedCode,
102 std::string *infoLog)
103 {
104 ShBuiltInResources resources;
105 sh::InitBuiltInResources(&resources);
106 return compileTestShader(type, spec, output, shaderString, &resources, compileOptions,
107 translatedCode, infoLog);
108 }
109
MatchOutputCodeTest(GLenum shaderType,ShCompileOptions defaultCompileOptions,ShShaderOutput outputType)110 MatchOutputCodeTest::MatchOutputCodeTest(GLenum shaderType,
111 ShCompileOptions defaultCompileOptions,
112 ShShaderOutput outputType)
113 : mShaderType(shaderType), mDefaultCompileOptions(defaultCompileOptions)
114 {
115 sh::InitBuiltInResources(&mResources);
116 mOutputCode[outputType] = std::string();
117 }
118
addOutputType(const ShShaderOutput outputType)119 void MatchOutputCodeTest::addOutputType(const ShShaderOutput outputType)
120 {
121 mOutputCode[outputType] = std::string();
122 }
123
getResources()124 ShBuiltInResources *MatchOutputCodeTest::getResources()
125 {
126 return &mResources;
127 }
128
compile(const std::string & shaderString)129 void MatchOutputCodeTest::compile(const std::string &shaderString)
130 {
131 compile(shaderString, mDefaultCompileOptions);
132 }
133
compile(const std::string & shaderString,const ShCompileOptions compileOptions)134 void MatchOutputCodeTest::compile(const std::string &shaderString,
135 const ShCompileOptions compileOptions)
136 {
137 std::string infoLog;
138 for (auto &code : mOutputCode)
139 {
140 bool compilationSuccess =
141 compileWithSettings(code.first, shaderString, compileOptions, &code.second, &infoLog);
142 if (!compilationSuccess)
143 {
144 FAIL() << "Shader compilation failed:\n" << infoLog;
145 }
146 }
147 }
148
compileWithSettings(ShShaderOutput output,const std::string & shaderString,const ShCompileOptions compileOptions,std::string * translatedCode,std::string * infoLog)149 bool MatchOutputCodeTest::compileWithSettings(ShShaderOutput output,
150 const std::string &shaderString,
151 const ShCompileOptions compileOptions,
152 std::string *translatedCode,
153 std::string *infoLog)
154 {
155 return compileTestShader(mShaderType, SH_GLES3_1_SPEC, output, shaderString, &mResources,
156 compileOptions, translatedCode, infoLog);
157 }
158
foundInCodeRegex(ShShaderOutput output,const std::regex & regexToFind,std::smatch * match) const159 bool MatchOutputCodeTest::foundInCodeRegex(ShShaderOutput output,
160 const std::regex ®exToFind,
161 std::smatch *match) const
162 {
163 const auto code = mOutputCode.find(output);
164 EXPECT_NE(mOutputCode.end(), code);
165 if (code == mOutputCode.end())
166 {
167 return std::string::npos;
168 }
169
170 if (match)
171 {
172 return std::regex_search(code->second, *match, regexToFind);
173 }
174 else
175 {
176 return std::regex_search(code->second, regexToFind);
177 }
178 }
179
foundInCode(ShShaderOutput output,const char * stringToFind) const180 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output, const char *stringToFind) const
181 {
182 const auto code = mOutputCode.find(output);
183 EXPECT_NE(mOutputCode.end(), code);
184 if (code == mOutputCode.end())
185 {
186 return std::string::npos;
187 }
188 return code->second.find(stringToFind) != std::string::npos;
189 }
190
foundInCodeInOrder(ShShaderOutput output,std::vector<const char * > stringsToFind)191 bool MatchOutputCodeTest::foundInCodeInOrder(ShShaderOutput output,
192 std::vector<const char *> stringsToFind)
193 {
194 const auto code = mOutputCode.find(output);
195 EXPECT_NE(mOutputCode.end(), code);
196 if (code == mOutputCode.end())
197 {
198 return false;
199 }
200
201 size_t currentPos = 0;
202 for (const char *stringToFind : stringsToFind)
203 {
204 auto position = code->second.find(stringToFind, currentPos);
205 if (position == std::string::npos)
206 {
207 return false;
208 }
209 currentPos = position + strlen(stringToFind);
210 }
211 return true;
212 }
213
foundInCode(ShShaderOutput output,const char * stringToFind,const int expectedOccurrences) const214 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output,
215 const char *stringToFind,
216 const int expectedOccurrences) const
217 {
218 const auto code = mOutputCode.find(output);
219 EXPECT_NE(mOutputCode.end(), code);
220 if (code == mOutputCode.end())
221 {
222 return false;
223 }
224
225 size_t currentPos = 0;
226 int occurencesLeft = expectedOccurrences;
227
228 const size_t searchStringLength = strlen(stringToFind);
229
230 while (occurencesLeft-- > 0)
231 {
232 auto position = code->second.find(stringToFind, currentPos);
233 if (position == std::string::npos)
234 {
235 return false;
236 }
237 // Search strings should not overlap.
238 currentPos = position + searchStringLength;
239 }
240 // Make sure that there aren't extra occurrences.
241 return code->second.find(stringToFind, currentPos) == std::string::npos;
242 }
243
foundInCode(const char * stringToFind) const244 bool MatchOutputCodeTest::foundInCode(const char *stringToFind) const
245 {
246 for (auto &code : mOutputCode)
247 {
248 if (!foundInCode(code.first, stringToFind))
249 {
250 return false;
251 }
252 }
253 return true;
254 }
255
foundInCodeRegex(const std::regex & regexToFind,std::smatch * match) const256 bool MatchOutputCodeTest::foundInCodeRegex(const std::regex ®exToFind, std::smatch *match) const
257 {
258 for (auto &code : mOutputCode)
259 {
260 if (!foundInCodeRegex(code.first, regexToFind, match))
261 {
262 return false;
263 }
264 }
265 return true;
266 }
267
foundInCode(const char * stringToFind,const int expectedOccurrences) const268 bool MatchOutputCodeTest::foundInCode(const char *stringToFind, const int expectedOccurrences) const
269 {
270 for (auto &code : mOutputCode)
271 {
272 if (!foundInCode(code.first, stringToFind, expectedOccurrences))
273 {
274 return false;
275 }
276 }
277 return true;
278 }
279
foundInCodeInOrder(std::vector<const char * > stringsToFind)280 bool MatchOutputCodeTest::foundInCodeInOrder(std::vector<const char *> stringsToFind)
281 {
282 for (auto &code : mOutputCode)
283 {
284 if (!foundInCodeInOrder(code.first, stringsToFind))
285 {
286 return false;
287 }
288 }
289 return true;
290 }
291
notFoundInCode(const char * stringToFind) const292 bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
293 {
294 for (auto &code : mOutputCode)
295 {
296 if (foundInCode(code.first, stringToFind))
297 {
298 return false;
299 }
300 }
301 return true;
302 }
303
FindFunctionCallNode(TIntermNode * root,const TString & functionMangledName)304 const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionMangledName)
305 {
306 FunctionCallFinder finder(functionMangledName.c_str());
307 root->traverse(&finder);
308 return finder.getNode();
309 }
310
311 } // namespace sh
312