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