blob: 16b7bd9f23594b822c16e2a5924db710163d0474 [file] [log] [blame]
alokp@chromium.org07620a52010-09-23 17:53:56 +00001//
2// Copyright (c) 2002-2010 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
zmo@google.comb1762df2011-07-30 02:04:23 +00007#include "compiler/DetectRecursion.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +00008#include "compiler/Initialize.h"
9#include "compiler/ParseHelper.h"
10#include "compiler/ShHandle.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000011#include "compiler/ValidateLimitations.h"
zmo@google.comfd747b82011-04-23 01:30:07 +000012#include "compiler/MapLongVariableNames.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000013
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000014namespace {
15bool InitializeSymbolTable(
16 const TBuiltInStrings& builtInStrings,
17 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
18 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000019{
20 TIntermediate intermediate(infoSink);
21 TExtensionBehavior extBehavior;
zmo@google.com09c323a2011-08-12 18:22:25 +000022 InitExtensionBehavior(resources, extBehavior);
zmo@google.comdc4b4f82011-06-17 00:42:53 +000023 // The builtins deliberately don't specify precisions for the function
24 // arguments and return types. For that reason we don't try to check them.
25 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000026
27 GlobalParseContext = &parseContext;
28
alokp@chromium.org07620a52010-09-23 17:53:56 +000029 assert(symbolTable.isEmpty());
30 //
31 // Parse the built-ins. This should only happen once per
32 // language symbol table.
33 //
34 // Push the symbol table to give it an initial scope. This
35 // push should not have a corresponding pop, so that built-ins
36 // are preserved, and the test for an empty table fails.
37 //
38 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000039
40 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
41 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000042 const char* builtInShaders = i->c_str();
43 int builtInLengths = static_cast<int>(i->size());
44 if (builtInLengths <= 0)
45 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000046
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000047 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000048 {
49 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
50 return false;
51 }
52 }
53
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000054 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000055
alokp@chromium.org07620a52010-09-23 17:53:56 +000056 return true;
57}
58
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000059class TScopedPoolAllocator {
60public:
61 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
62 : mAllocator(allocator), mPushPopAllocator(pushPop) {
63 if (mPushPopAllocator) mAllocator->push();
64 SetGlobalPoolAllocator(mAllocator);
65 }
66 ~TScopedPoolAllocator() {
67 SetGlobalPoolAllocator(NULL);
68 if (mPushPopAllocator) mAllocator->pop();
69 }
70
71private:
72 TPoolAllocator* mAllocator;
73 bool mPushPopAllocator;
74};
75} // namespace
76
77TShHandleBase::TShHandleBase() {
78 allocator.push();
79 SetGlobalPoolAllocator(&allocator);
80}
81
82TShHandleBase::~TShHandleBase() {
83 SetGlobalPoolAllocator(NULL);
84 allocator.popAll();
85}
86
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000087TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
88 : shaderType(type),
89 shaderSpec(spec)
90{
91}
92
93TCompiler::~TCompiler()
94{
95}
96
97bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +000098{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000099 TScopedPoolAllocator scopedAlloc(&allocator, false);
100
alokp@chromium.org07620a52010-09-23 17:53:56 +0000101 // Generate built-in symbol table.
102 if (!InitBuiltInSymbolTable(resources))
103 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000104 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000105
alokp@chromium.org07620a52010-09-23 17:53:56 +0000106 return true;
107}
108
109bool TCompiler::compile(const char* const shaderStrings[],
110 const int numStrings,
111 int compileOptions)
112{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000113 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000114 clearResults();
115
116 if (numStrings == 0)
117 return true;
118
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000119 // If compiling for WebGL, validate loop and indexing as well.
120 if (shaderSpec == SH_WEBGL_SPEC)
121 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000122
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000123 // First string is path of source file if flag is set. The actual source follows.
124 const char* sourcePath = NULL;
125 int firstSource = 0;
126 if (compileOptions & SH_SOURCE_PATH)
127 {
128 sourcePath = shaderStrings[0];
129 ++firstSource;
130 }
131
alokp@chromium.org07620a52010-09-23 17:53:56 +0000132 TIntermediate intermediate(infoSink);
133 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000134 shaderType, shaderSpec, compileOptions, true,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000135 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000136 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000137
138 // We preserve symbols at the built-in level from compile-to-compile.
139 // Start pushing the user-defined symbols at global level.
140 symbolTable.push();
141 if (!symbolTable.atGlobalLevel())
142 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
143
144 // Parse shader.
145 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000146 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000147 (parseContext.treeRoot != NULL);
148 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000149 TIntermNode* root = parseContext.treeRoot;
150 success = intermediate.postProcess(root);
151
zmo@google.comb1762df2011-07-30 02:04:23 +0000152 if (success)
153 success = detectRecursion(root);
154
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000155 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
156 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000157
zmo@google.comfd747b82011-04-23 01:30:07 +0000158 // Call mapLongVariableNames() before collectAttribsUniforms() so in
159 // collectAttribsUniforms() we already have the mapped symbol names and
160 // we could composite mapped and original variable names.
zmo@google.comb1762df2011-07-30 02:04:23 +0000161 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
zmo@google.comfd747b82011-04-23 01:30:07 +0000162 mapLongVariableNames(root);
163
164 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
165 collectAttribsUniforms(root);
166
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000167 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000168 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000169
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000170 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000171 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000172 }
173
174 // Cleanup memory.
175 intermediate.remove(parseContext.treeRoot);
176 // Ensure symbol table is returned to the built-in level,
177 // throwing away all but the built-ins.
178 while (!symbolTable.atBuiltInLevel())
179 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000180
181 return success;
182}
183
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000184bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000185{
186 TBuiltIns builtIns;
187
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000188 builtIns.initialize(shaderType, shaderSpec, resources);
189 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
190 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000191}
192
193void TCompiler::clearResults()
194{
195 infoSink.info.erase();
196 infoSink.obj.erase();
197 infoSink.debug.erase();
198
199 attribs.clear();
200 uniforms.clear();
201}
202
zmo@google.comb1762df2011-07-30 02:04:23 +0000203bool TCompiler::detectRecursion(TIntermNode* root)
204{
205 DetectRecursion detect;
206 root->traverse(&detect);
207 switch (detect.detectRecursion()) {
208 case DetectRecursion::kErrorNone:
209 return true;
210 case DetectRecursion::kErrorMissingMain:
211 infoSink.info.message(EPrefixError, "Missing main()");
212 return false;
213 case DetectRecursion::kErrorRecursion:
214 infoSink.info.message(EPrefixError, "Function recursion detected");
215 return false;
216 default:
217 UNREACHABLE();
218 return false;
219 }
220}
221
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000222bool TCompiler::validateLimitations(TIntermNode* root) {
223 ValidateLimitations validate(shaderType, infoSink.info);
224 root->traverse(&validate);
225 return validate.numErrors() == 0;
226}
227
alokp@chromium.org07620a52010-09-23 17:53:56 +0000228void TCompiler::collectAttribsUniforms(TIntermNode* root)
229{
230 CollectAttribsUniforms collect(attribs, uniforms);
231 root->traverse(&collect);
232}
zmo@google.comfd747b82011-04-23 01:30:07 +0000233
234void TCompiler::mapLongVariableNames(TIntermNode* root)
235{
zmo@google.com24c08c42011-05-27 17:40:48 +0000236 MapLongVariableNames map(varyingLongNameMap);
zmo@google.comfd747b82011-04-23 01:30:07 +0000237 root->traverse(&map);
238}
239
240int TCompiler::getMappedNameMaxLength() const
241{
242 return MAX_IDENTIFIER_NAME_SIZE + 1;
243}
zmo@google.com5601ea02011-06-10 18:23:25 +0000244
245const TExtensionBehavior& TCompiler::getExtensionBehavior() const
246{
247 return extensionBehavior;
248}