blob: eafe70a0ea82dfb62b157d3406dc0838ecd2533d [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"
zmo@google.com0c6bb7a2011-08-17 19:39:58 +00008#include "compiler/ForLoopUnroll.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +00009#include "compiler/Initialize.h"
10#include "compiler/ParseHelper.h"
11#include "compiler/ShHandle.h"
alokp@chromium.orgb59a7782010-11-24 18:38:33 +000012#include "compiler/ValidateLimitations.h"
zmo@google.comfd747b82011-04-23 01:30:07 +000013#include "compiler/MapLongVariableNames.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000014
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000015namespace {
16bool InitializeSymbolTable(
17 const TBuiltInStrings& builtInStrings,
18 ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
19 TInfoSink& infoSink, TSymbolTable& symbolTable)
alokp@chromium.org07620a52010-09-23 17:53:56 +000020{
21 TIntermediate intermediate(infoSink);
22 TExtensionBehavior extBehavior;
zmo@google.com09c323a2011-08-12 18:22:25 +000023 InitExtensionBehavior(resources, extBehavior);
zmo@google.comdc4b4f82011-06-17 00:42:53 +000024 // The builtins deliberately don't specify precisions for the function
25 // arguments and return types. For that reason we don't try to check them.
26 TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +000027
28 GlobalParseContext = &parseContext;
29
alokp@chromium.org07620a52010-09-23 17:53:56 +000030 assert(symbolTable.isEmpty());
31 //
32 // Parse the built-ins. This should only happen once per
33 // language symbol table.
34 //
35 // Push the symbol table to give it an initial scope. This
36 // push should not have a corresponding pop, so that built-ins
37 // are preserved, and the test for an empty table fails.
38 //
39 symbolTable.push();
alokp@chromium.org07620a52010-09-23 17:53:56 +000040
41 for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
42 {
alokp@chromium.org570bfc72010-09-24 17:19:25 +000043 const char* builtInShaders = i->c_str();
44 int builtInLengths = static_cast<int>(i->size());
45 if (builtInLengths <= 0)
46 continue;
alokp@chromium.org07620a52010-09-23 17:53:56 +000047
alokp@chromium.org044a5cf2010-11-12 15:42:16 +000048 if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
alokp@chromium.org07620a52010-09-23 17:53:56 +000049 {
50 infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
51 return false;
52 }
53 }
54
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000055 IdentifyBuiltIns(type, spec, resources, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +000056
alokp@chromium.org07620a52010-09-23 17:53:56 +000057 return true;
58}
59
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +000060class TScopedPoolAllocator {
61public:
62 TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
63 : mAllocator(allocator), mPushPopAllocator(pushPop) {
64 if (mPushPopAllocator) mAllocator->push();
65 SetGlobalPoolAllocator(mAllocator);
66 }
67 ~TScopedPoolAllocator() {
68 SetGlobalPoolAllocator(NULL);
69 if (mPushPopAllocator) mAllocator->pop();
70 }
71
72private:
73 TPoolAllocator* mAllocator;
74 bool mPushPopAllocator;
75};
76} // namespace
77
78TShHandleBase::TShHandleBase() {
79 allocator.push();
80 SetGlobalPoolAllocator(&allocator);
81}
82
83TShHandleBase::~TShHandleBase() {
84 SetGlobalPoolAllocator(NULL);
85 allocator.popAll();
86}
87
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000088TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
89 : shaderType(type),
90 shaderSpec(spec)
91{
92}
93
94TCompiler::~TCompiler()
95{
96}
97
98bool TCompiler::Init(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +000099{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000100 TScopedPoolAllocator scopedAlloc(&allocator, false);
101
alokp@chromium.org07620a52010-09-23 17:53:56 +0000102 // Generate built-in symbol table.
103 if (!InitBuiltInSymbolTable(resources))
104 return false;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000105 InitExtensionBehavior(resources, extensionBehavior);
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000106
alokp@chromium.org07620a52010-09-23 17:53:56 +0000107 return true;
108}
109
110bool TCompiler::compile(const char* const shaderStrings[],
111 const int numStrings,
112 int compileOptions)
113{
alokp@chromium.orgbafcbaa2010-11-23 19:07:43 +0000114 TScopedPoolAllocator scopedAlloc(&allocator, true);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000115 clearResults();
116
117 if (numStrings == 0)
118 return true;
119
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000120 // If compiling for WebGL, validate loop and indexing as well.
121 if (shaderSpec == SH_WEBGL_SPEC)
122 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
alokp@chromium.org1f299542010-11-12 15:50:23 +0000123
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000124 // First string is path of source file if flag is set. The actual source follows.
125 const char* sourcePath = NULL;
126 int firstSource = 0;
127 if (compileOptions & SH_SOURCE_PATH)
128 {
129 sourcePath = shaderStrings[0];
130 ++firstSource;
131 }
132
alokp@chromium.org07620a52010-09-23 17:53:56 +0000133 TIntermediate intermediate(infoSink);
134 TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
zmo@google.comdc4b4f82011-06-17 00:42:53 +0000135 shaderType, shaderSpec, compileOptions, true,
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000136 sourcePath, infoSink);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000137 GlobalParseContext = &parseContext;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000138
139 // We preserve symbols at the built-in level from compile-to-compile.
140 // Start pushing the user-defined symbols at global level.
141 symbolTable.push();
142 if (!symbolTable.atGlobalLevel())
143 infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
144
145 // Parse shader.
146 bool success =
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000147 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
alokp@chromium.org07620a52010-09-23 17:53:56 +0000148 (parseContext.treeRoot != NULL);
149 if (success) {
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000150 TIntermNode* root = parseContext.treeRoot;
151 success = intermediate.postProcess(root);
152
zmo@google.comb1762df2011-07-30 02:04:23 +0000153 if (success)
154 success = detectRecursion(root);
155
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000156 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
157 success = validateLimitations(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000158
zmo@google.com0c6bb7a2011-08-17 19:39:58 +0000159 // Unroll for-loop markup needs to happen after validateLimitations pass.
160 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
161 ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
162
zmo@google.comfd747b82011-04-23 01:30:07 +0000163 // Call mapLongVariableNames() before collectAttribsUniforms() so in
164 // collectAttribsUniforms() we already have the mapped symbol names and
165 // we could composite mapped and original variable names.
zmo@google.comb1762df2011-07-30 02:04:23 +0000166 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
zmo@google.comfd747b82011-04-23 01:30:07 +0000167 mapLongVariableNames(root);
168
169 if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
170 collectAttribsUniforms(root);
171
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000172 if (success && (compileOptions & SH_INTERMEDIATE_TREE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000173 intermediate.outputTree(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000174
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000175 if (success && (compileOptions & SH_OBJECT_CODE))
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000176 translate(root);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000177 }
178
179 // Cleanup memory.
180 intermediate.remove(parseContext.treeRoot);
181 // Ensure symbol table is returned to the built-in level,
182 // throwing away all but the built-ins.
183 while (!symbolTable.atBuiltInLevel())
184 symbolTable.pop();
alokp@chromium.org07620a52010-09-23 17:53:56 +0000185
186 return success;
187}
188
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000189bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000190{
191 TBuiltIns builtIns;
192
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000193 builtIns.initialize(shaderType, shaderSpec, resources);
194 return InitializeSymbolTable(builtIns.getBuiltInStrings(),
195 shaderType, shaderSpec, resources, infoSink, symbolTable);
alokp@chromium.org07620a52010-09-23 17:53:56 +0000196}
197
198void TCompiler::clearResults()
199{
200 infoSink.info.erase();
201 infoSink.obj.erase();
202 infoSink.debug.erase();
203
204 attribs.clear();
205 uniforms.clear();
206}
207
zmo@google.comb1762df2011-07-30 02:04:23 +0000208bool TCompiler::detectRecursion(TIntermNode* root)
209{
210 DetectRecursion detect;
211 root->traverse(&detect);
212 switch (detect.detectRecursion()) {
213 case DetectRecursion::kErrorNone:
214 return true;
215 case DetectRecursion::kErrorMissingMain:
216 infoSink.info.message(EPrefixError, "Missing main()");
217 return false;
218 case DetectRecursion::kErrorRecursion:
219 infoSink.info.message(EPrefixError, "Function recursion detected");
220 return false;
221 default:
222 UNREACHABLE();
223 return false;
224 }
225}
226
alokp@chromium.orgb59a7782010-11-24 18:38:33 +0000227bool TCompiler::validateLimitations(TIntermNode* root) {
228 ValidateLimitations validate(shaderType, infoSink.info);
229 root->traverse(&validate);
230 return validate.numErrors() == 0;
231}
232
alokp@chromium.org07620a52010-09-23 17:53:56 +0000233void TCompiler::collectAttribsUniforms(TIntermNode* root)
234{
235 CollectAttribsUniforms collect(attribs, uniforms);
236 root->traverse(&collect);
237}
zmo@google.comfd747b82011-04-23 01:30:07 +0000238
239void TCompiler::mapLongVariableNames(TIntermNode* root)
240{
zmo@google.com24c08c42011-05-27 17:40:48 +0000241 MapLongVariableNames map(varyingLongNameMap);
zmo@google.comfd747b82011-04-23 01:30:07 +0000242 root->traverse(&map);
243}
244
245int TCompiler::getMappedNameMaxLength() const
246{
247 return MAX_IDENTIFIER_NAME_SIZE + 1;
248}
zmo@google.com5601ea02011-06-10 18:23:25 +0000249
250const TExtensionBehavior& TCompiler::getExtensionBehavior() const
251{
252 return extensionBehavior;
253}