Home | History | Annotate | Download | only in compiler
      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:
     28 	TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
     29 		: mAllocator(allocator), mPushPopAllocator(pushPop)
     30 	{
     31 		if (mPushPopAllocator) mAllocator->push();
     32 		SetGlobalPoolAllocator(mAllocator);
     33 	}
     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 //
     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 
     70 	MaxCallStackDepth = UINT_MAX;
     71 }
     72 
     73 TCompiler::TCompiler(GLenum type)
     74 	: shaderType(type),
     75 	  maxCallStackDepth(UINT_MAX)
     76 {
     77 	allocator.push();
     78 	SetGlobalPoolAllocator(&allocator);
     79 }
     80 
     81 TCompiler::~TCompiler()
     82 {
     83 	SetGlobalPoolAllocator(nullptr);
     84 	allocator.popAll();
     85 }
     86 
     87 bool TCompiler::Init(const ShBuiltInResources& resources)
     88 {
     89 	shaderVersion = 100;
     90 	maxCallStackDepth = resources.MaxCallStackDepth;
     91 	TScopedPoolAllocator scopedAlloc(&allocator, false);
     92 
     93 	// Generate built-in symbol table.
     94 	if (!InitBuiltInSymbolTable(resources))
     95 		return false;
     96 	InitExtensionBehavior(resources, extensionBehavior);
     97 
     98 	return true;
     99 }
    100 
    101 bool TCompiler::compile(const char* const shaderStrings[],
    102                         const int numStrings,
    103                         int compileOptions)
    104 {
    105 	TScopedPoolAllocator scopedAlloc(&allocator, true);
    106 	clearResults();
    107 
    108 	if (numStrings == 0)
    109 		return true;
    110 
    111 	// First string is path of source file if flag is set. The actual source follows.
    112 	const char* sourcePath = nullptr;
    113 	int firstSource = 0;
    114 	if (compileOptions & SH_SOURCE_PATH)
    115 	{
    116 		sourcePath = shaderStrings[0];
    117 		++firstSource;
    118 	}
    119 
    120 	TIntermediate intermediate(infoSink);
    121 	TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
    122 	                           shaderType, compileOptions, true,
    123 	                           sourcePath, infoSink);
    124 	SetGlobalParseContext(&parseContext);
    125 
    126 	// We preserve symbols at the built-in level from compile-to-compile.
    127 	// Start pushing the user-defined symbols at global level.
    128 	symbolTable.push();
    129 	if (!symbolTable.atGlobalLevel())
    130 		infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
    131 
    132 	// Parse shader.
    133 	bool success =
    134 		(PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
    135 		(parseContext.getTreeRoot() != nullptr);
    136 
    137 	shaderVersion = parseContext.getShaderVersion();
    138 
    139 	if (success) {
    140 		TIntermNode* root = parseContext.getTreeRoot();
    141 		success = intermediate.postProcess(root);
    142 
    143 		if (success)
    144 			success = validateCallDepth(root, infoSink);
    145 
    146 		if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
    147 			success = validateLimitations(root);
    148 
    149 		if (success && (compileOptions & SH_INTERMEDIATE_TREE))
    150 			intermediate.outputTree(root);
    151 
    152 		if (success && (compileOptions & SH_OBJECT_CODE))
    153 			success = translate(root);
    154 	}
    155 
    156 	// Ensure symbol table is returned to the built-in level,
    157 	// throwing away all but the built-ins.
    158 	while (!symbolTable.atBuiltInLevel())
    159 		symbolTable.pop();
    160 
    161 	return success;
    162 }
    163 
    164 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
    165 {
    166 	assert(symbolTable.isEmpty());
    167 	symbolTable.push();   // COMMON_BUILTINS
    168 	symbolTable.push();   // ESSL1_BUILTINS
    169 	symbolTable.push();   // ESSL3_BUILTINS
    170 
    171 	TPublicType integer;
    172 	integer.type = EbtInt;
    173 	integer.primarySize = 1;
    174 	integer.secondarySize = 1;
    175 	integer.array = false;
    176 
    177 	TPublicType floatingPoint;
    178 	floatingPoint.type = EbtFloat;
    179 	floatingPoint.primarySize = 1;
    180 	floatingPoint.secondarySize = 1;
    181 	floatingPoint.array = false;
    182 
    183 	switch(shaderType)
    184 	{
    185 	case GL_FRAGMENT_SHADER:
    186 		symbolTable.setDefaultPrecision(integer, EbpMedium);
    187 		break;
    188 	case GL_VERTEX_SHADER:
    189 		symbolTable.setDefaultPrecision(integer, EbpHigh);
    190 		symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
    191 		break;
    192 	default: assert(false && "Language not supported");
    193 	}
    194 
    195 	InsertBuiltInFunctions(shaderType, resources, symbolTable);
    196 
    197 	IdentifyBuiltIns(shaderType, resources, symbolTable);
    198 
    199 	return true;
    200 }
    201 
    202 void TCompiler::clearResults()
    203 {
    204 	infoSink.info.erase();
    205 	infoSink.obj.erase();
    206 	infoSink.debug.erase();
    207 }
    208 
    209 bool TCompiler::validateCallDepth(TIntermNode *root, TInfoSink &infoSink)
    210 {
    211 	AnalyzeCallDepth validator(root);
    212 
    213 	unsigned int depth = validator.analyzeCallDepth();
    214 
    215 	if(depth == 0)
    216 	{
    217 		infoSink.info.prefix(EPrefixError);
    218 		infoSink.info << "Missing main()";
    219 		return false;
    220 	}
    221 	else if(depth == UINT_MAX)
    222 	{
    223 		infoSink.info.prefix(EPrefixError);
    224 		infoSink.info << "Function recursion detected";
    225 		return false;
    226 	}
    227 	else if(depth > maxCallStackDepth)
    228 	{
    229 		infoSink.info.prefix(EPrefixError);
    230 		infoSink.info << "Function call stack too deep (depth was ";
    231 		infoSink.info << depth;
    232 		infoSink.info << " while maximum call stack depth is ";
    233 		infoSink.info << maxCallStackDepth;
    234 		infoSink.info << ")";
    235 		return false;
    236 	}
    237 
    238 	return true;
    239 }
    240 
    241 bool TCompiler::validateLimitations(TIntermNode* root) {
    242 	ValidateLimitations validate(shaderType, infoSink.info);
    243 	root->traverse(&validate);
    244 	return validate.numErrors() == 0;
    245 }
    246 
    247 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    248 {
    249 	return extensionBehavior;
    250 }
    251 
    252 bool InitCompilerGlobals()
    253 {
    254 	if(!InitializePoolIndex())
    255 	{
    256 		assert(0 && "InitCompilerGlobals(): Failed to initalize global pool");
    257 		return false;
    258 	}
    259 
    260 	if(!InitializeParseContextIndex())
    261 	{
    262 		assert(0 && "InitCompilerGlobals(): Failed to initalize parse context");
    263 		return false;
    264 	}
    265 
    266 	return true;
    267 }
    268 
    269 void FreeCompilerGlobals()
    270 {
    271 	FreeParseContextIndex();
    272 	FreePoolIndex();
    273 }
    274