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 constexpr char kBinaryBlob[] = "<binary blob>";
IsBinaryBlob(const std::string & code)22 bool IsBinaryBlob(const std::string &code)
23 {
24 return code == kBinaryBlob;
25 }
26
GetSymbolTableMangledName(TIntermAggregate * node)27 ImmutableString GetSymbolTableMangledName(TIntermAggregate *node)
28 {
29 ASSERT(!node->isConstructor());
30 return TFunctionLookup::GetMangledName(node->getFunction()->name().data(),
31 *node->getSequence());
32 }
33
34 class FunctionCallFinder : public TIntermTraverser
35 {
36 public:
FunctionCallFinder(const char * functionMangledName)37 FunctionCallFinder(const char *functionMangledName)
38 : TIntermTraverser(true, false, false),
39 mFunctionMangledName(functionMangledName),
40 mNodeFound(nullptr)
41 {}
42
visitAggregate(Visit visit,TIntermAggregate * node)43 bool visitAggregate(Visit visit, TIntermAggregate *node) override
44 {
45 if (!node->isConstructor() && GetSymbolTableMangledName(node) == mFunctionMangledName)
46 {
47 mNodeFound = node;
48 return false;
49 }
50 return true;
51 }
52
isFound() const53 bool isFound() const { return mNodeFound != nullptr; }
getNode() const54 const TIntermAggregate *getNode() const { return mNodeFound; }
55
56 private:
57 const char *mFunctionMangledName;
58 TIntermAggregate *mNodeFound;
59 };
60
61 } // anonymous namespace
62
compileTestShader(GLenum type,ShShaderSpec spec,ShShaderOutput output,const std::string & shaderString,ShBuiltInResources * resources,ShCompileOptions compileOptions,std::string * translatedCode,std::string * infoLog)63 bool compileTestShader(GLenum type,
64 ShShaderSpec spec,
65 ShShaderOutput output,
66 const std::string &shaderString,
67 ShBuiltInResources *resources,
68 ShCompileOptions compileOptions,
69 std::string *translatedCode,
70 std::string *infoLog)
71 {
72 sh::TCompiler *translator = sh::ConstructCompiler(type, spec, output);
73 if (!translator->Init(*resources))
74 {
75 SafeDelete(translator);
76 return false;
77 }
78
79 const char *shaderStrings[] = {shaderString.c_str()};
80
81 bool compilationSuccess =
82 translator->compile(shaderStrings, 1, SH_OBJECT_CODE | compileOptions);
83 TInfoSink &infoSink = translator->getInfoSink();
84 if (translatedCode)
85 {
86 *translatedCode = infoSink.obj.isBinary() ? kBinaryBlob : infoSink.obj.c_str();
87 }
88 if (infoLog)
89 {
90 *infoLog = infoSink.info.c_str();
91 }
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 // No meaningful check for binary blobs
171 if (IsBinaryBlob(code->second))
172 {
173 return true;
174 }
175
176 if (match)
177 {
178 return std::regex_search(code->second, *match, regexToFind);
179 }
180 else
181 {
182 return std::regex_search(code->second, regexToFind);
183 }
184 }
185
foundInCode(ShShaderOutput output,const char * stringToFind) const186 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output, const char *stringToFind) const
187 {
188 const auto code = mOutputCode.find(output);
189 EXPECT_NE(mOutputCode.end(), code);
190 if (code == mOutputCode.end())
191 {
192 return std::string::npos;
193 }
194
195 // No meaningful check for binary blobs
196 if (IsBinaryBlob(code->second))
197 {
198 return true;
199 }
200
201 return code->second.find(stringToFind) != std::string::npos;
202 }
203
foundInCodeInOrder(ShShaderOutput output,std::vector<const char * > stringsToFind)204 bool MatchOutputCodeTest::foundInCodeInOrder(ShShaderOutput output,
205 std::vector<const char *> stringsToFind)
206 {
207 const auto code = mOutputCode.find(output);
208 EXPECT_NE(mOutputCode.end(), code);
209 if (code == mOutputCode.end())
210 {
211 return false;
212 }
213
214 // No meaningful check for binary blobs
215 if (IsBinaryBlob(code->second))
216 {
217 return true;
218 }
219
220 size_t currentPos = 0;
221 for (const char *stringToFind : stringsToFind)
222 {
223 auto position = code->second.find(stringToFind, currentPos);
224 if (position == std::string::npos)
225 {
226 return false;
227 }
228 currentPos = position + strlen(stringToFind);
229 }
230 return true;
231 }
232
foundInCode(ShShaderOutput output,const char * stringToFind,const int expectedOccurrences) const233 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output,
234 const char *stringToFind,
235 const int expectedOccurrences) const
236 {
237 const auto code = mOutputCode.find(output);
238 EXPECT_NE(mOutputCode.end(), code);
239 if (code == mOutputCode.end())
240 {
241 return false;
242 }
243
244 // No meaningful check for binary blobs
245 if (IsBinaryBlob(code->second))
246 {
247 return true;
248 }
249
250 size_t currentPos = 0;
251 int occurencesLeft = expectedOccurrences;
252
253 const size_t searchStringLength = strlen(stringToFind);
254
255 while (occurencesLeft-- > 0)
256 {
257 auto position = code->second.find(stringToFind, currentPos);
258 if (position == std::string::npos)
259 {
260 return false;
261 }
262 // Search strings should not overlap.
263 currentPos = position + searchStringLength;
264 }
265 // Make sure that there aren't extra occurrences.
266 return code->second.find(stringToFind, currentPos) == std::string::npos;
267 }
268
foundInCode(const char * stringToFind) const269 bool MatchOutputCodeTest::foundInCode(const char *stringToFind) const
270 {
271 for (auto &code : mOutputCode)
272 {
273 if (!foundInCode(code.first, stringToFind))
274 {
275 return false;
276 }
277 }
278 return true;
279 }
280
foundInCodeRegex(const std::regex & regexToFind,std::smatch * match) const281 bool MatchOutputCodeTest::foundInCodeRegex(const std::regex ®exToFind, std::smatch *match) const
282 {
283 for (auto &code : mOutputCode)
284 {
285 if (!foundInCodeRegex(code.first, regexToFind, match))
286 {
287 return false;
288 }
289 }
290 return true;
291 }
292
foundInCode(const char * stringToFind,const int expectedOccurrences) const293 bool MatchOutputCodeTest::foundInCode(const char *stringToFind, const int expectedOccurrences) const
294 {
295 for (auto &code : mOutputCode)
296 {
297 if (!foundInCode(code.first, stringToFind, expectedOccurrences))
298 {
299 return false;
300 }
301 }
302 return true;
303 }
304
foundInCodeInOrder(std::vector<const char * > stringsToFind)305 bool MatchOutputCodeTest::foundInCodeInOrder(std::vector<const char *> stringsToFind)
306 {
307 for (auto &code : mOutputCode)
308 {
309 if (!foundInCodeInOrder(code.first, stringsToFind))
310 {
311 return false;
312 }
313 }
314 return true;
315 }
316
notFoundInCode(const char * stringToFind) const317 bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
318 {
319 for (auto &code : mOutputCode)
320 {
321 // No meaningful check for binary blobs
322 if (IsBinaryBlob(code.second))
323 {
324 continue;
325 }
326
327 if (foundInCode(code.first, stringToFind))
328 {
329 return false;
330 }
331 }
332 return true;
333 }
334
FindFunctionCallNode(TIntermNode * root,const TString & functionMangledName)335 const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionMangledName)
336 {
337 FunctionCallFinder finder(functionMangledName.c_str());
338 root->traverse(&finder);
339 return finder.getNode();
340 }
341
342 } // namespace sh
343