1 : //
2 : // Copyright (c) 2002-2012 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 :
7 : #include "compiler/BuiltInFunctionEmulator.h"
8 : #include "compiler/DetectRecursion.h"
9 : #include "compiler/ForLoopUnroll.h"
10 : #include "compiler/Initialize.h"
11 : #include "compiler/MapLongVariableNames.h"
12 : #include "compiler/ParseHelper.h"
13 : #include "compiler/ShHandle.h"
14 : #include "compiler/ValidateLimitations.h"
15 :
16 : namespace {
17 0 : bool InitializeSymbolTable(
18 : const TBuiltInStrings& builtInStrings,
19 : ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
20 : TInfoSink& infoSink, TSymbolTable& symbolTable)
21 : {
22 0 : TIntermediate intermediate(infoSink);
23 0 : TExtensionBehavior extBehavior;
24 0 : InitExtensionBehavior(resources, extBehavior);
25 : // The builtins deliberately don't specify precisions for the function
26 : // arguments and return types. For that reason we don't try to check them.
27 0 : TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
28 :
29 0 : GlobalParseContext = &parseContext;
30 :
31 0 : assert(symbolTable.isEmpty());
32 : //
33 : // Parse the built-ins. This should only happen once per
34 : // language symbol table.
35 : //
36 : // Push the symbol table to give it an initial scope. This
37 : // push should not have a corresponding pop, so that built-ins
38 : // are preserved, and the test for an empty table fails.
39 : //
40 0 : symbolTable.push();
41 :
42 0 : for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
43 : {
44 0 : const char* builtInShaders = i->c_str();
45 0 : int builtInLengths = static_cast<int>(i->size());
46 0 : if (builtInLengths <= 0)
47 0 : continue;
48 :
49 0 : if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
50 : {
51 0 : infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
52 0 : return false;
53 : }
54 : }
55 :
56 0 : IdentifyBuiltIns(type, spec, resources, symbolTable);
57 :
58 0 : return true;
59 : }
60 :
61 : class TScopedPoolAllocator {
62 : public:
63 0 : TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
64 0 : : mAllocator(allocator), mPushPopAllocator(pushPop) {
65 0 : if (mPushPopAllocator) mAllocator->push();
66 0 : SetGlobalPoolAllocator(mAllocator);
67 0 : }
68 0 : ~TScopedPoolAllocator() {
69 0 : SetGlobalPoolAllocator(NULL);
70 0 : if (mPushPopAllocator) mAllocator->pop();
71 0 : }
72 :
73 : private:
74 : TPoolAllocator* mAllocator;
75 : bool mPushPopAllocator;
76 : };
77 : } // namespace
78 :
79 0 : TShHandleBase::TShHandleBase() {
80 0 : allocator.push();
81 0 : SetGlobalPoolAllocator(&allocator);
82 0 : }
83 :
84 0 : TShHandleBase::~TShHandleBase() {
85 0 : SetGlobalPoolAllocator(NULL);
86 0 : allocator.popAll();
87 0 : }
88 :
89 0 : TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
90 : : shaderType(type),
91 : shaderSpec(spec),
92 0 : builtInFunctionEmulator(type)
93 : {
94 0 : longNameMap = LongNameMap::GetInstance();
95 0 : }
96 :
97 0 : TCompiler::~TCompiler()
98 : {
99 0 : ASSERT(longNameMap);
100 0 : longNameMap->Release();
101 0 : }
102 :
103 0 : bool TCompiler::Init(const ShBuiltInResources& resources)
104 : {
105 0 : TScopedPoolAllocator scopedAlloc(&allocator, false);
106 :
107 : // Generate built-in symbol table.
108 0 : if (!InitBuiltInSymbolTable(resources))
109 0 : return false;
110 0 : InitExtensionBehavior(resources, extensionBehavior);
111 :
112 0 : return true;
113 : }
114 :
115 0 : bool TCompiler::compile(const char* const shaderStrings[],
116 : const int numStrings,
117 : int compileOptions)
118 : {
119 0 : TScopedPoolAllocator scopedAlloc(&allocator, true);
120 0 : clearResults();
121 :
122 0 : if (numStrings == 0)
123 0 : return true;
124 :
125 : // If compiling for WebGL, validate loop and indexing as well.
126 0 : if (shaderSpec == SH_WEBGL_SPEC)
127 0 : compileOptions |= SH_VALIDATE_LOOP_INDEXING;
128 :
129 : // First string is path of source file if flag is set. The actual source follows.
130 0 : const char* sourcePath = NULL;
131 0 : int firstSource = 0;
132 0 : if (compileOptions & SH_SOURCE_PATH)
133 : {
134 0 : sourcePath = shaderStrings[0];
135 0 : ++firstSource;
136 : }
137 :
138 0 : TIntermediate intermediate(infoSink);
139 : TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
140 : shaderType, shaderSpec, compileOptions, true,
141 0 : sourcePath, infoSink);
142 0 : GlobalParseContext = &parseContext;
143 :
144 : // We preserve symbols at the built-in level from compile-to-compile.
145 : // Start pushing the user-defined symbols at global level.
146 0 : symbolTable.push();
147 0 : if (!symbolTable.atGlobalLevel())
148 0 : infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
149 :
150 : // Parse shader.
151 : bool success =
152 0 : (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
153 0 : (parseContext.treeRoot != NULL);
154 0 : if (success) {
155 0 : TIntermNode* root = parseContext.treeRoot;
156 0 : success = intermediate.postProcess(root);
157 :
158 0 : if (success)
159 0 : success = detectRecursion(root);
160 :
161 0 : if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
162 0 : success = validateLimitations(root);
163 :
164 : // Unroll for-loop markup needs to happen after validateLimitations pass.
165 0 : if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
166 0 : ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
167 :
168 : // Built-in function emulation needs to happen after validateLimitations pass.
169 0 : if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
170 0 : builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
171 :
172 : // Call mapLongVariableNames() before collectAttribsUniforms() so in
173 : // collectAttribsUniforms() we already have the mapped symbol names and
174 : // we could composite mapped and original variable names.
175 0 : if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
176 0 : mapLongVariableNames(root);
177 :
178 0 : if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
179 0 : collectAttribsUniforms(root);
180 :
181 0 : if (success && (compileOptions & SH_INTERMEDIATE_TREE))
182 0 : intermediate.outputTree(root);
183 :
184 0 : if (success && (compileOptions & SH_OBJECT_CODE))
185 0 : translate(root);
186 : }
187 :
188 : // Cleanup memory.
189 0 : intermediate.remove(parseContext.treeRoot);
190 : // Ensure symbol table is returned to the built-in level,
191 : // throwing away all but the built-ins.
192 0 : while (!symbolTable.atBuiltInLevel())
193 0 : symbolTable.pop();
194 :
195 0 : return success;
196 : }
197 :
198 0 : bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
199 : {
200 0 : TBuiltIns builtIns;
201 :
202 0 : builtIns.initialize(shaderType, shaderSpec, resources);
203 0 : return InitializeSymbolTable(builtIns.getBuiltInStrings(),
204 0 : shaderType, shaderSpec, resources, infoSink, symbolTable);
205 : }
206 :
207 0 : void TCompiler::clearResults()
208 : {
209 0 : infoSink.info.erase();
210 0 : infoSink.obj.erase();
211 0 : infoSink.debug.erase();
212 :
213 0 : attribs.clear();
214 0 : uniforms.clear();
215 :
216 0 : builtInFunctionEmulator.Cleanup();
217 0 : }
218 :
219 0 : bool TCompiler::detectRecursion(TIntermNode* root)
220 : {
221 0 : DetectRecursion detect;
222 0 : root->traverse(&detect);
223 0 : switch (detect.detectRecursion()) {
224 : case DetectRecursion::kErrorNone:
225 0 : return true;
226 : case DetectRecursion::kErrorMissingMain:
227 0 : infoSink.info.message(EPrefixError, "Missing main()");
228 0 : return false;
229 : case DetectRecursion::kErrorRecursion:
230 0 : infoSink.info.message(EPrefixError, "Function recursion detected");
231 0 : return false;
232 : default:
233 0 : UNREACHABLE();
234 : return false;
235 : }
236 : }
237 :
238 0 : bool TCompiler::validateLimitations(TIntermNode* root) {
239 0 : ValidateLimitations validate(shaderType, infoSink.info);
240 0 : root->traverse(&validate);
241 0 : return validate.numErrors() == 0;
242 : }
243 :
244 0 : void TCompiler::collectAttribsUniforms(TIntermNode* root)
245 : {
246 0 : CollectAttribsUniforms collect(attribs, uniforms);
247 0 : root->traverse(&collect);
248 0 : }
249 :
250 0 : void TCompiler::mapLongVariableNames(TIntermNode* root)
251 : {
252 0 : ASSERT(longNameMap);
253 0 : MapLongVariableNames map(longNameMap);
254 0 : root->traverse(&map);
255 0 : }
256 :
257 0 : int TCompiler::getMappedNameMaxLength() const
258 : {
259 0 : return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
260 : }
261 :
262 0 : const TExtensionBehavior& TCompiler::getExtensionBehavior() const
263 : {
264 0 : return extensionBehavior;
265 : }
266 :
267 0 : const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
268 : {
269 0 : return builtInFunctionEmulator;
270 : }
|