blob: 0456fa3517565b3fa6e8cbd097ef4917ddb874ea [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.comdc4b4f82011-06-17 00:42:53 +000022 // The builtins deliberately don't specify precisions for the function
23 // arguments and return types. For that reason we don't try to check them.
24 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000025
26 GlobalParseContext = &parseContext;
27
alokp@chromium.org07620a52010-09-23 17:53:56 +000028 assert(symbolTable.isEmpty());
29 //
30 // Parse the built-ins. This should only happen once per
31 // language symbol table.
32 //
33 // Push the symbol table to give it an initial scope. This
34 // push should not have a corresponding pop, so that built-ins
35 // are preserved, and the test for an empty table fails.
36 //
37 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000038
39 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
40 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000041 const char* builtInShaders = i->c_str();
42 int builtInLengths = static_cast<int>(i->size());
43 if (builtInLengths <= 0)
44 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000045
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000046 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000047 {
48 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
49 return false;
50 }
51 }
52
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000053 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000054
alokp@chromium.org07620a52010-09-23 17:53:56 +000055 return true;
56}
57
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000058class TScopedPoolAllocator {
59public:
60 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
61 : mAllocator(allocator), mPushPopAllocator(pushPop) {
62 if (mPushPopAllocator) mAllocator->push();
63 SetGlobalPoolAllocator(mAllocator);
64 }
65 ~TScopedPoolAllocator() {
66 SetGlobalPoolAllocator(NULL);
67 if (mPushPopAllocator) mAllocator->pop();
68 }
69
70private:
71 TPoolAllocator* mAllocator;
72 bool mPushPopAllocator;
73};
74} // namespace
75
76TShHandleBase::TShHandleBase() {
77 allocator.push();
78 SetGlobalPoolAllocator(&allocator);
79}
80
81TShHandleBase::~TShHandleBase() {
82 SetGlobalPoolAllocator(NULL);
83 allocator.popAll();
84}
85
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000086TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
87 : shaderType(type),
88 shaderSpec(spec)
89{
90}
91
92TCompiler::~TCompiler()
93{
94}
95
96bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +000097{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000098 TScopedPoolAllocator scopedAlloc(&allocator, false);
99
alokp@chromium.org07620a52010-09-23 17:53:56 +0000100 // Generate built-in symbol table.
101 if (!InitBuiltInSymbolTable(resources))
102 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000103 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000104
alokp@chromium.org07620a52010-09-23 17:53:56 +0000105 return true;
106}
107
108bool TCompiler::compile(const char* const shaderStrings[],
109 const int numStrings,
110 int compileOptions)
111{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000112 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000113 clearResults();
114
115 if (numStrings == 0)
116 return true;
117
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000118 // If compiling for WebGL, validate loop and indexing as well.
119 if (shaderSpec == SH_WEBGL_SPEC)
120 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000121
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000122 // First string is path of source file if flag is set. The actual source follows.
123 const char* sourcePath = NULL;
124 int firstSource = 0;
125 if (compileOptions & SH_SOURCE_PATH)
126 {
127 sourcePath = shaderStrings[0];
128 ++firstSource;
129 }
130
alokp@chromium.org07620a52010-09-23 17:53:56 +0000131 TIntermediate intermediate(infoSink);
132 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000133 shaderType, shaderSpec, compileOptions, true,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000134 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000135 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000136
137 // We preserve symbols at the built-in level from compile-to-compile.
138 // Start pushing the user-defined symbols at global level.
139 symbolTable.push();
140 if (!symbolTable.atGlobalLevel())
141 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
142
143 // Parse shader.
144 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000145 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000146 (parseContext.treeRoot != NULL);
147 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000148 TIntermNode* root = parseContext.treeRoot;
149 success = intermediate.postProcess(root);
150
zmo@google.comb1762df2011-07-30 02:04:23 +0000151 if (success)
152 success = detectRecursion(root);
153
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000154 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
155 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000156
zmo@google.comfd747b82011-04-23 01:30:07 +0000157 // Call mapLongVariableNames() before collectAttribsUniforms() so in
158 // collectAttribsUniforms() we already have the mapped symbol names and
159 // we could composite mapped and original variable names.
zmo@google.comb1762df2011-07-30 02:04:23 +0000160 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
zmo@google.comfd747b82011-04-23 01:30:07 +0000161 mapLongVariableNames(root);
162
163 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
164 collectAttribsUniforms(root);
165
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000166 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000167 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000168
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000169 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000170 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000171 }
172
173 // Cleanup memory.
174 intermediate.remove(parseContext.treeRoot);
175 // Ensure symbol table is returned to the built-in level,
176 // throwing away all but the built-ins.
177 while (!symbolTable.atBuiltInLevel())
178 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000179
180 return success;
181}
182
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000183bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000184{
185 TBuiltIns builtIns;
186
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000187 builtIns.initialize(shaderType, shaderSpec, resources);
188 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
189 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000190}
191
192void TCompiler::clearResults()
193{
194 infoSink.info.erase();
195 infoSink.obj.erase();
196 infoSink.debug.erase();
197
198 attribs.clear();
199 uniforms.clear();
200}
201
zmo@google.comb1762df2011-07-30 02:04:23 +0000202bool TCompiler::detectRecursion(TIntermNode* root)
203{
204 DetectRecursion detect;
205 root->traverse(&detect);
206 switch (detect.detectRecursion()) {
207 case DetectRecursion::kErrorNone:
208 return true;
209 case DetectRecursion::kErrorMissingMain:
210 infoSink.info.message(EPrefixError, "Missing main()");
211 return false;
212 case DetectRecursion::kErrorRecursion:
213 infoSink.info.message(EPrefixError, "Function recursion detected");
214 return false;
215 default:
216 UNREACHABLE();
217 return false;
218 }
219}
220
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000221bool TCompiler::validateLimitations(TIntermNode* root) {
222 ValidateLimitations validate(shaderType, infoSink.info);
223 root->traverse(&validate);
224 return validate.numErrors() == 0;
225}
226
alokp@chromium.org07620a52010-09-23 17:53:56 +0000227void TCompiler::collectAttribsUniforms(TIntermNode* root)
228{
229 CollectAttribsUniforms collect(attribs, uniforms);
230 root->traverse(&collect);
231}
zmo@google.comfd747b82011-04-23 01:30:07 +0000232
233void TCompiler::mapLongVariableNames(TIntermNode* root)
234{
zmo@google.com24c08c42011-05-27 17:40:48 +0000235 MapLongVariableNames map(varyingLongNameMap);
zmo@google.comfd747b82011-04-23 01:30:07 +0000236 root->traverse(&map);
237}
238
239int TCompiler::getMappedNameMaxLength() const
240{
241 return MAX_IDENTIFIER_NAME_SIZE + 1;
242}
zmo@google.com5601ea02011-06-10 18:23:25 +0000243
244const TExtensionBehavior& TCompiler::getExtensionBehavior() const
245{
246 return extensionBehavior;
247}