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,const 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 const 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 ShCompileOptions options = compileOptions;
82 options.objectCode = true;
83 bool compilationSuccess = translator->compile(shaderStrings, 1, options);
84 TInfoSink &infoSink = translator->getInfoSink();
85 if (translatedCode)
86 {
87 *translatedCode = infoSink.obj.isBinary() ? kBinaryBlob : infoSink.obj.c_str();
88 }
89 if (infoLog)
90 {
91 *infoLog = infoSink.info.c_str();
92 }
93 SafeDelete(translator);
94 return compilationSuccess;
95 }
96
compileTestShader(GLenum type,ShShaderSpec spec,ShShaderOutput output,const std::string & shaderString,const ShCompileOptions & compileOptions,std::string * translatedCode,std::string * infoLog)97 bool compileTestShader(GLenum type,
98 ShShaderSpec spec,
99 ShShaderOutput output,
100 const std::string &shaderString,
101 const ShCompileOptions &compileOptions,
102 std::string *translatedCode,
103 std::string *infoLog)
104 {
105 ShBuiltInResources resources;
106 sh::InitBuiltInResources(&resources);
107 resources.FragmentPrecisionHigh = 1;
108 return compileTestShader(type, spec, output, shaderString, &resources, compileOptions,
109 translatedCode, infoLog);
110 }
111
MatchOutputCodeTest(GLenum shaderType,ShShaderOutput outputType)112 MatchOutputCodeTest::MatchOutputCodeTest(GLenum shaderType, ShShaderOutput outputType)
113 : mShaderType(shaderType), mDefaultCompileOptions{}
114 {
115 sh::InitBuiltInResources(&mResources);
116 mResources.FragmentPrecisionHigh = 1;
117 mOutputCode[outputType] = std::string();
118 }
119
setDefaultCompileOptions(const ShCompileOptions & defaultCompileOptions)120 void MatchOutputCodeTest::setDefaultCompileOptions(const ShCompileOptions &defaultCompileOptions)
121 {
122 mDefaultCompileOptions = defaultCompileOptions;
123 }
124
addOutputType(const ShShaderOutput outputType)125 void MatchOutputCodeTest::addOutputType(const ShShaderOutput outputType)
126 {
127 mOutputCode[outputType] = std::string();
128 }
129
getResources()130 ShBuiltInResources *MatchOutputCodeTest::getResources()
131 {
132 return &mResources;
133 }
134
compile(const std::string & shaderString)135 void MatchOutputCodeTest::compile(const std::string &shaderString)
136 {
137 compile(shaderString, mDefaultCompileOptions);
138 }
139
compile(const std::string & shaderString,const ShCompileOptions & compileOptions)140 void MatchOutputCodeTest::compile(const std::string &shaderString,
141 const ShCompileOptions &compileOptions)
142 {
143 std::string infoLog;
144 for (auto &code : mOutputCode)
145 {
146 bool compilationSuccess =
147 compileWithSettings(code.first, shaderString, compileOptions, &code.second, &infoLog);
148 if (!compilationSuccess)
149 {
150 FAIL() << "Shader compilation failed:\n" << infoLog;
151 }
152 }
153 }
154
compileWithSettings(ShShaderOutput output,const std::string & shaderString,const ShCompileOptions & compileOptions,std::string * translatedCode,std::string * infoLog)155 bool MatchOutputCodeTest::compileWithSettings(ShShaderOutput output,
156 const std::string &shaderString,
157 const ShCompileOptions &compileOptions,
158 std::string *translatedCode,
159 std::string *infoLog)
160 {
161 return compileTestShader(mShaderType, SH_GLES3_1_SPEC, output, shaderString, &mResources,
162 compileOptions, translatedCode, infoLog);
163 }
164
foundInCodeRegex(ShShaderOutput output,const std::regex & regexToFind,std::smatch * match) const165 bool MatchOutputCodeTest::foundInCodeRegex(ShShaderOutput output,
166 const std::regex ®exToFind,
167 std::smatch *match) const
168 {
169 const auto code = mOutputCode.find(output);
170 EXPECT_NE(mOutputCode.end(), code);
171 if (code == mOutputCode.end())
172 {
173 return std::string::npos;
174 }
175
176 // No meaningful check for binary blobs
177 if (IsBinaryBlob(code->second))
178 {
179 return true;
180 }
181
182 if (match)
183 {
184 return std::regex_search(code->second, *match, regexToFind);
185 }
186 else
187 {
188 return std::regex_search(code->second, regexToFind);
189 }
190 }
191
foundInCode(ShShaderOutput output,const char * stringToFind) const192 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output, const char *stringToFind) const
193 {
194 const auto code = mOutputCode.find(output);
195 EXPECT_NE(mOutputCode.end(), code);
196 if (code == mOutputCode.end())
197 {
198 return std::string::npos;
199 }
200
201 // No meaningful check for binary blobs
202 if (IsBinaryBlob(code->second))
203 {
204 return true;
205 }
206
207 return code->second.find(stringToFind) != std::string::npos;
208 }
209
foundInCodeInOrder(ShShaderOutput output,std::vector<const char * > stringsToFind)210 bool MatchOutputCodeTest::foundInCodeInOrder(ShShaderOutput output,
211 std::vector<const char *> stringsToFind)
212 {
213 const auto code = mOutputCode.find(output);
214 EXPECT_NE(mOutputCode.end(), code);
215 if (code == mOutputCode.end())
216 {
217 return false;
218 }
219
220 // No meaningful check for binary blobs
221 if (IsBinaryBlob(code->second))
222 {
223 return true;
224 }
225
226 size_t currentPos = 0;
227 for (const char *stringToFind : stringsToFind)
228 {
229 auto position = code->second.find(stringToFind, currentPos);
230 if (position == std::string::npos)
231 {
232 return false;
233 }
234 currentPos = position + strlen(stringToFind);
235 }
236 return true;
237 }
238
foundInCode(ShShaderOutput output,const char * stringToFind,const int expectedOccurrences) const239 bool MatchOutputCodeTest::foundInCode(ShShaderOutput output,
240 const char *stringToFind,
241 const int expectedOccurrences) const
242 {
243 const auto code = mOutputCode.find(output);
244 EXPECT_NE(mOutputCode.end(), code);
245 if (code == mOutputCode.end())
246 {
247 return false;
248 }
249
250 // No meaningful check for binary blobs
251 if (IsBinaryBlob(code->second))
252 {
253 return true;
254 }
255
256 size_t currentPos = 0;
257 int occurencesLeft = expectedOccurrences;
258
259 const size_t searchStringLength = strlen(stringToFind);
260
261 while (occurencesLeft-- > 0)
262 {
263 auto position = code->second.find(stringToFind, currentPos);
264 if (position == std::string::npos)
265 {
266 return false;
267 }
268 // Search strings should not overlap.
269 currentPos = position + searchStringLength;
270 }
271 // Make sure that there aren't extra occurrences.
272 return code->second.find(stringToFind, currentPos) == std::string::npos;
273 }
274
foundInCode(const char * stringToFind) const275 bool MatchOutputCodeTest::foundInCode(const char *stringToFind) const
276 {
277 for (auto &code : mOutputCode)
278 {
279 if (!foundInCode(code.first, stringToFind))
280 {
281 return false;
282 }
283 }
284 return true;
285 }
286
foundInCodeRegex(const std::regex & regexToFind,std::smatch * match) const287 bool MatchOutputCodeTest::foundInCodeRegex(const std::regex ®exToFind, std::smatch *match) const
288 {
289 for (auto &code : mOutputCode)
290 {
291 if (!foundInCodeRegex(code.first, regexToFind, match))
292 {
293 return false;
294 }
295 }
296 return true;
297 }
298
foundInCode(const char * stringToFind,const int expectedOccurrences) const299 bool MatchOutputCodeTest::foundInCode(const char *stringToFind, const int expectedOccurrences) const
300 {
301 for (auto &code : mOutputCode)
302 {
303 if (!foundInCode(code.first, stringToFind, expectedOccurrences))
304 {
305 return false;
306 }
307 }
308 return true;
309 }
310
foundInCodeInOrder(std::vector<const char * > stringsToFind)311 bool MatchOutputCodeTest::foundInCodeInOrder(std::vector<const char *> stringsToFind)
312 {
313 for (auto &code : mOutputCode)
314 {
315 if (!foundInCodeInOrder(code.first, stringsToFind))
316 {
317 return false;
318 }
319 }
320 return true;
321 }
322
notFoundInCode(const char * stringToFind) const323 bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
324 {
325 for (auto &code : mOutputCode)
326 {
327 // No meaningful check for binary blobs
328 if (IsBinaryBlob(code.second))
329 {
330 continue;
331 }
332
333 if (foundInCode(code.first, stringToFind))
334 {
335 return false;
336 }
337 }
338 return true;
339 }
340
FindFunctionCallNode(TIntermNode * root,const TString & functionMangledName)341 const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionMangledName)
342 {
343 FunctionCallFinder finder(functionMangledName.c_str());
344 root->traverse(&finder);
345 return finder.getNode();
346 }
347
348 } // namespace sh
349