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 	OES_EGL_image_external_essl3 = 0;
     70 
     71 	MaxCallStackDepth = UINT_MAX;
     72 }
     73 
     74 TCompiler::TCompiler(GLenum type)
     75 	: shaderType(type),
     76 	  maxCallStackDepth(UINT_MAX)
     77 {
     78 	allocator.push();
     79 	SetGlobalPoolAllocator(&allocator);
     80 }
     81 
     82 TCompiler::~TCompiler()
     83 {
     84 	SetGlobalPoolAllocator(nullptr);
     85 	allocator.popAll();
     86 }
     87 
     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 
    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 
    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 
    203 void TCompiler::clearResults()
    204 {
    205 	infoSink.info.erase();
    206 	infoSink.obj.erase();
    207 	infoSink.debug.erase();
    208 }
    209 
    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 
    242 bool TCompiler::validateLimitations(TIntermNode* root) {
    243 	ValidateLimitations validate(shaderType, infoSink.info);
    244 	root->traverse(&validate);
    245 	return validate.numErrors() == 0;
    246 }
    247 
    248 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
    249 {
    250 	return extensionBehavior;
    251 }
    252 
    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 
    270 void FreeCompilerGlobals()
    271 {
    272 	FreeParseContextIndex();
    273 	FreePoolIndex();
    274 }
    275