• 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 
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 &regexToFind,
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 &regexToFind, 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