• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regexToFind,
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 &regexToFind, 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