1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "Compiler.h"
16 
17 #include "AnalyzeCallDepth.h"
18 #include "Initialize.h"
19 #include "InitializeParseContext.h"
20 #include "InitializeGlobals.h"
21 #include "ParseHelper.h"
22 #include "ValidateLimitations.h"
23 
24 namespace
25 {
26 class TScopedPoolAllocator {
27 public:
TScopedPoolAllocator(TPoolAllocator * allocator,bool pushPop)28 	TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
29 		: mAllocator(allocator), mPushPopAllocator(pushPop)
30 	{
31 		if (mPushPopAllocator) mAllocator->push();
32 		SetGlobalPoolAllocator(mAllocator);
33 	}
~TScopedPoolAllocator()34 	~TScopedPoolAllocator()
35 	{
36 		SetGlobalPoolAllocator(nullptr);
37 		if (mPushPopAllocator) mAllocator->pop();
38 	}
39 
40 private:
41 	TPoolAllocator* mAllocator;
42 	bool mPushPopAllocator;
43 };
44 }  // namespace
45 
46 //
47 // Initialize built-in resources with minimum expected values.
48 //
ShBuiltInResources()49 ShBuiltInResources::ShBuiltInResources()
50 {
51 	// Constants.
52 	MaxVertexAttribs = 8;
53 	MaxVertexUniformVectors = 128;
54 	MaxVaryingVectors = 8;
55 	MaxVertexTextureImageUnits = 0;
56 	MaxCombinedTextureImageUnits = 8;
57 	MaxTextureImageUnits = 8;
58 	MaxFragmentUniformVectors = 16;
59 	MaxDrawBuffers = 1;
60 	MaxVertexOutputVectors = 16;
61 	MaxFragmentInputVectors = 15;
62 	MinProgramTexelOffset = -8;
63 	MaxProgramTexelOffset = 7;
64 
65 	// Extensions.
66 	OES_standard_derivatives = 0;
67 	OES_fragment_precision_high = 0;
68 	OES_EGL_image_external = 0;
69 	OES_EGL_image_external_essl3 = 0;
70 
71 	MaxCallStackDepth = UINT_MAX;
72 }
73 
TCompiler(GLenum type)74 TCompiler::TCompiler(GLenum type)
75 	: shaderType(type),
76 	  maxCallStackDepth(UINT_MAX)
77 {
78 	allocator.push();
79 	SetGlobalPoolAllocator(&allocator);
80 }
81 
~TCompiler()82 TCompiler::~TCompiler()
83 {
84 	SetGlobalPoolAllocator(nullptr);
85 	allocator.popAll();
86 }
87 
Init(const ShBuiltInResources & resources)88 bool TCompiler::Init(const ShBuiltInResources& resources)
89 {
90 	shaderVersion = 100;
91 	maxCallStackDepth = resources.MaxCallStackDepth;
92 	TScopedPoolAllocator scopedAlloc(&allocator, false);
93 
94 	// Generate built-in symbol table.
95 	if (!InitBuiltInSymbolTable(resources))
96 		return false;
97 	InitExtensionBehavior(resources, extensionBehavior);
98 
99 	return true;
100 }
101 
compile(const char * const shaderStrings[],const int numStrings,int compileOptions)102 bool TCompiler::compile(const char* const shaderStrings[],
103                         const int numStrings,
104                         int compileOptions)
105 {
106 	TScopedPoolAllocator scopedAlloc(&allocator, true);
107 	clearResults();
108 
109 	if (numStrings == 0)
110 		return true;
111 
112 	// First string is path of source file if flag is set. The actual source follows.
113 	const char* sourcePath = nullptr;
114 	int firstSource = 0;
115 	if (compileOptions & SH_SOURCE_PATH)
116 	{
117 		sourcePath = shaderStrings[0];
118 		++firstSource;
119 	}
120 
121 	TIntermediate intermediate(infoSink);
122 	TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
123 	                           shaderType, compileOptions, true,
124 	                           sourcePath, infoSink);
125 	SetGlobalParseContext(&parseContext);
126 
127 	// We preserve symbols at the built-in level from compile-to-compile.
128 	// Start pushing the user-defined symbols at global level.
129 	symbolTable.push();
130 	if (!symbolTable.atGlobalLevel())
131 		infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
132 
133 	// Parse shader.
134 	bool success =
135 		(PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
136 		(parseContext.getTreeRoot() != nullptr);
137 
138 	shaderVersion = parseContext.getShaderVersion();
139 
140 	if (success) {
141 		TIntermNode* root = parseContext.getTreeRoot();
142 		success = intermediate.postProcess(root);
143 
144 		if (success)
145 			success = validateCallDepth(root, infoSink);
146 
147 		if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
148 			success = validateLimitations(root);
149 
150 		if (success && (compileOptions & SH_INTERMEDIATE_TREE))
151 			intermediate.outputTree(root);
152 
153 		if (success && (compileOptions & SH_OBJECT_CODE))
154 			success = translate(root);
155 	}
156 
157 	// Ensure symbol table is returned to the built-in level,
158 	// throwing away all but the built-ins.
159 	while (!symbolTable.atBuiltInLevel())
160 		symbolTable.pop();
161 
162 	return success;
163 }
164 
InitBuiltInSymbolTable(const ShBuiltInResources & resources)165 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
166 {
167 	assert(symbolTable.isEmpty());
168 	symbolTable.push();   // COMMON_BUILTINS
169 	symbolTable.push();   // ESSL1_BUILTINS
170 	symbolTable.push();   // ESSL3_BUILTINS
171 
172 	TPublicType integer;
173 	integer.type = EbtInt;
174 	integer.primarySize = 1;
175 	integer.secondarySize = 1;
176 	integer.array = false;
177 
178 	TPublicType floatingPoint;
179 	floatingPoint.type = EbtFloat;
180 	floatingPoint.primarySize = 1;
181 	floatingPoint.secondarySize = 1;
182 	floatingPoint.array = false;
183 
184 	switch(shaderType)
185 	{
186 	case GL_FRAGMENT_SHADER:
187 		symbolTable.setDefaultPrecision(integer, EbpMedium);
188 		break;
189 	case GL_VERTEX_SHADER:
190 		symbolTable.setDefaultPrecision(integer, EbpHigh);
191 		symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
192 		break;
193 	default: assert(false && "Language not supported");
194 	}
195 
196 	InsertBuiltInFunctions(shaderType, resources, symbolTable);
197 
198 	IdentifyBuiltIns(shaderType, resources, symbolTable);
199 
200 	return true;
201 }
202 
clearResults()203 void TCompiler::clearResults()
204 {
205 	infoSink.info.erase();
206 	infoSink.obj.erase();
207 	infoSink.debug.erase();
208 }
209 
validateCallDepth(TIntermNode * root,TInfoSink & infoSink)210 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
211 {
212 	AnalyzeCallDepth validator(root);
213 
214 	unsigned int depth = validator.analyzeCallDepth();
215 
216 	if(depth == 0)
217 	{
218 		infoSink.info.prefix(EPrefixError);
219 		infoSink.info << "Missing main()";
220 		return false;
221 	}
222 	else if(depth == UINT_MAX)
223 	{
224 		infoSink.info.prefix(EPrefixError);
225 		infoSink.info << "Function recursion detected";
226 		return false;
227 	}
228 	else if(depth > maxCallStackDepth)
229 	{
230 		infoSink.info.prefix(EPrefixError);
231 		infoSink.info << "Function call stack too deep (depth was ";
232 		infoSink.info << depth;
233 		infoSink.info << " while maximum call stack depth is ";
234 		infoSink.info << maxCallStackDepth;
235 		infoSink.info << ")";
236 		return false;
237 	}
238 
239 	return true;
240 }
241 
validateLimitations(TIntermNode * root)242 bool TCompiler::validateLimitations(TIntermNode* root) {
243 	ValidateLimitations validate(shaderType, infoSink.info);
244 	root->traverse(&validate);
245 	return validate.numErrors() == 0;
246 }
247 
getExtensionBehavior() const248 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
249 {
250 	return extensionBehavior;
251 }
252 
InitCompilerGlobals()253 bool InitCompilerGlobals()
254 {
255 	if(!InitializePoolIndex())
256 	{
257 		assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
258 		return false;
259 	}
260 
261 	if(!InitializeParseContextIndex())
262 	{
263 		assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
264 		return false;
265 	}
266 
267 	return true;
268 }
269 
FreeCompilerGlobals()270 void FreeCompilerGlobals()
271 {
272 	FreeParseContextIndex();
273 	FreePoolIndex();
274 }
275