diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/angle/src/compiler/translator | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/angle/src/compiler/translator')
117 files changed, 35162 insertions, 0 deletions
diff --git a/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch b/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch new file mode 100644 index 00000000000..7af91f57653 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/64bit-lexer-safety.patch @@ -0,0 +1,177 @@ +--- a/src/compiler/glslang_lex.cpp ++++ b/src/compiler/glslang_lex.cpp +@@ -68,6 +68,7 @@ typedef int16_t flex_int16_t; + typedef uint16_t flex_uint16_t; + typedef int32_t flex_int32_t; + typedef uint32_t flex_uint32_t; ++typedef uint64_t flex_uint64_t; + #else + typedef signed char flex_int8_t; + typedef short int flex_int16_t; +@@ -191,6 +192,11 @@ typedef void* yyscan_t; + typedef struct yy_buffer_state *YY_BUFFER_STATE; + #endif + ++#ifndef YY_TYPEDEF_YY_SIZE_T ++#define YY_TYPEDEF_YY_SIZE_T ++typedef size_t yy_size_t; ++#endif ++ + #define EOB_ACT_CONTINUE_SCAN 0 + #define EOB_ACT_END_OF_FILE 1 + #define EOB_ACT_LAST_MATCH 2 +@@ -204,7 +210,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; + */ + #define YY_LESS_LINENO(n) \ + do { \ +- int yyl;\ ++ yy_size_t yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ +@@ -226,11 +232,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; + + #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +-#ifndef YY_TYPEDEF_YY_SIZE_T +-#define YY_TYPEDEF_YY_SIZE_T +-typedef size_t yy_size_t; +-#endif +- + #ifndef YY_STRUCT_YY_BUFFER_STATE + #define YY_STRUCT_YY_BUFFER_STATE + struct yy_buffer_state +@@ -248,7 +249,7 @@ struct yy_buffer_state + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ +- int yy_n_chars; ++ yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to +@@ -327,7 +328,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + + YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); + YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); ++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); + + void *yyalloc (yy_size_t ,yyscan_t yyscanner ); + void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +@@ -378,7 +379,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + */ + #define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ +- yyleng = (size_t) (yy_cp - yy_bp); \ ++ yyleng = (yy_size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +@@ -1035,8 +1036,8 @@ struct yyguts_t + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; +- int yy_n_chars; +- int yyleng_r; ++ yy_size_t yy_n_chars; ++ yy_size_t yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; +@@ -1089,7 +1090,7 @@ FILE *yyget_out (yyscan_t yyscanner ); + + void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +-int yyget_leng (yyscan_t yyscanner ); ++yy_size_t yyget_leng (yyscan_t yyscanner ); + + char *yyget_text (yyscan_t yyscanner ); + +@@ -1158,7 +1159,7 @@ static int input (yyscan_t yyscanner ); + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ +- int n; \ ++ yy_size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ +@@ -1317,7 +1318,7 @@ yy_find_action: + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { +- int yyl; ++ yy_size_t yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + +@@ -2203,7 +2204,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) + + else + { +- int num_to_read = ++ yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) +@@ -2217,7 +2218,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) + + if ( b->yy_is_our_buffer ) + { +- int new_size = b->yy_buf_size * 2; ++ yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; +@@ -2248,7 +2249,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), +- yyg->yy_n_chars, (size_t) num_to_read ); ++ yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } +@@ -2373,7 +2374,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) + + else + { /* need more input */ +- int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) +@@ -2660,7 +2661,7 @@ void yypop_buffer_state (yyscan_t yyscanner) + */ + static void yyensure_buffer_stack (yyscan_t yyscanner) + { +- int num_to_alloc; ++ yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { +@@ -2758,12 +2759,11 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) ++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) + { + YY_BUFFER_STATE b; + char *buf; +- yy_size_t n; +- int i; ++ yy_size_t n, i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; +@@ -2913,7 +2913,7 @@ FILE *yyget_out (yyscan_t yyscanner) + /** Get the length of the current token. + * @param yyscanner The scanner object. + */ +-int yyget_leng (yyscan_t yyscanner) ++yy_size_t yyget_leng (yyscan_t yyscanner) + { + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; diff --git a/chromium/third_party/angle/src/compiler/translator/BaseTypes.h b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h new file mode 100644 index 00000000000..ba9ef5e609e --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h @@ -0,0 +1,471 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _BASICTYPES_INCLUDED_ +#define _BASICTYPES_INCLUDED_ + +#include <assert.h> + +// +// Precision qualifiers +// +enum TPrecision +{ + // These need to be kept sorted + EbpUndefined, + EbpLow, + EbpMedium, + EbpHigh +}; + +inline const char* getPrecisionString(TPrecision p) +{ + switch(p) + { + case EbpHigh: return "highp"; break; + case EbpMedium: return "mediump"; break; + case EbpLow: return "lowp"; break; + default: return "mediump"; break; // Safest fallback + } +} + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType +{ + EbtVoid, + EbtFloat, + EbtInt, + EbtUInt, + EbtBool, + EbtGVec4, // non type: represents vec4, ivec4 and uvec4 + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler2D, + EbtSampler3D, + EbtSamplerCube, + EbtSampler2DArray, + EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists. + EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists. + EbtISampler2D, + EbtISampler3D, + EbtISamplerCube, + EbtISampler2DArray, + EbtUSampler2D, + EbtUSampler3D, + EbtUSamplerCube, + EbtUSampler2DArray, + EbtSampler2DShadow, + EbtSamplerCubeShadow, + EbtSampler2DArrayShadow, + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtGSampler2D, // non type: represents sampler2D, isampler2D and usampler2D + EbtGSampler3D, // non type: represents sampler3D, isampler3D and usampler3D + EbtGSamplerCube, // non type: represents samplerCube, isamplerCube and usamplerCube + EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray and usampler2DArray + EbtStruct, + EbtInterfaceBlock, + EbtAddress, // should be deprecated?? + EbtInvariant // used as a type when qualifying a previously declared variable as being invariant +}; + +inline const char* getBasicString(TBasicType t) +{ + switch (t) + { + case EbtVoid: return "void"; break; + case EbtFloat: return "float"; break; + case EbtInt: return "int"; break; + case EbtUInt: return "uint"; break; + case EbtBool: return "bool"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSampler3D: return "sampler3D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtSamplerExternalOES: return "samplerExternalOES"; break; + case EbtSampler2DRect: return "sampler2DRect"; break; + case EbtSampler2DArray: return "sampler2DArray"; break; + case EbtISampler2D: return "isampler2D"; break; + case EbtISampler3D: return "isampler3D"; break; + case EbtISamplerCube: return "isamplerCube"; break; + case EbtISampler2DArray: return "isampler2DArray"; break; + case EbtUSampler2D: return "usampler2D"; break; + case EbtUSampler3D: return "usampler3D"; break; + case EbtUSamplerCube: return "usamplerCube"; break; + case EbtUSampler2DArray: return "usampler2DArray"; break; + case EbtSampler2DShadow: return "sampler2DShadow"; break; + case EbtSamplerCubeShadow: return "samplerCubeShadow"; break; + case EbtSampler2DArrayShadow: return "sampler2DArrayShadow"; break; + case EbtStruct: return "structure"; break; + case EbtInterfaceBlock: return "interface block"; break; + default: return "unknown type"; + } +} + +inline bool IsSampler(TBasicType type) +{ + return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; +} + +inline bool IsIntegerSampler(TBasicType type) +{ + switch (type) + { + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler2D(TBasicType type) +{ + switch (type) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerCube(TBasicType type) +{ + switch (type) + { + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + return true; + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISampler3D: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSampler3D(TBasicType type) +{ + switch (type) + { + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + return true; + case EbtSampler2D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + case EbtISampler2D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsSamplerArray(TBasicType type) +{ + switch (type) + { + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DArrayShadow: + return true; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DRect: + case EbtSamplerExternalOES: + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCube: + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool IsShadowSampler(TBasicType type) +{ + switch (type) + { + case EbtSampler2DShadow: + case EbtSamplerCubeShadow: + case EbtSampler2DArrayShadow: + return true; + case EbtISampler2D: + case EbtISampler3D: + case EbtISamplerCube: + case EbtISampler2DArray: + case EbtUSampler2D: + case EbtUSampler3D: + case EbtUSamplerCube: + case EbtUSampler2DArray: + case EbtSampler2D: + case EbtSampler3D: + case EbtSamplerCube: + case EbtSamplerExternalOES: + case EbtSampler2DRect: + case EbtSampler2DArray: + return false; + default: + assert(!IsSampler(type)); + } + + return false; +} + +inline bool SupportsPrecision(TBasicType type) +{ + return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); +} + +// +// Qualifiers and built-ins. These are mainly used to see what can be read +// or written, and by the machine dependent translator to know which registers +// to allocate variables in. Since built-ins tend to go to different registers +// than varying or uniform, it makes sense they are peers, not sub-classes. +// +enum TQualifier +{ + EvqTemporary, // For temporaries (within a function), read/write + EvqGlobal, // For globals read/write + EvqInternal, // For internal use, not visible to the user + EvqConst, // User defined constants and non-output parameters in functions + EvqAttribute, // Readonly + EvqVaryingIn, // readonly, fragment shaders only + EvqVaryingOut, // vertex shaders only read/write + EvqInvariantVaryingIn, // readonly, fragment shaders only + EvqInvariantVaryingOut, // vertex shaders only read/write + EvqUniform, // Readonly, vertex and fragment + + EvqVertexIn, // Vertex shader input + EvqFragmentOut, // Fragment shader output + EvqVertexOut, // Vertex shader output + EvqFragmentIn, // Fragment shader input + + // parameters + EvqIn, + EvqOut, + EvqInOut, + EvqConstReadOnly, + + // built-ins written by vertex shader + EvqPosition, + EvqPointSize, + + // built-ins read by fragment shader + EvqFragCoord, + EvqFrontFacing, + EvqPointCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragData, + EvqFragDepth, + + // GLSL ES 3.0 vertex output and fragment input + EvqSmooth, // Incomplete qualifier, smooth is the default + EvqFlat, // Incomplete qualifier + EvqSmoothOut = EvqSmooth, + EvqFlatOut = EvqFlat, + EvqCentroidOut, // Implies smooth + EvqSmoothIn, + EvqFlatIn, + EvqCentroidIn, // Implies smooth + + // end of list + EvqLast +}; + +enum TLayoutMatrixPacking +{ + EmpUnspecified, + EmpRowMajor, + EmpColumnMajor +}; + +enum TLayoutBlockStorage +{ + EbsUnspecified, + EbsShared, + EbsPacked, + EbsStd140 +}; + +struct TLayoutQualifier +{ + int location; + TLayoutMatrixPacking matrixPacking; + TLayoutBlockStorage blockStorage; + + static TLayoutQualifier create() + { + TLayoutQualifier layoutQualifier; + + layoutQualifier.location = -1; + layoutQualifier.matrixPacking = EmpUnspecified; + layoutQualifier.blockStorage = EbsUnspecified; + + return layoutQualifier; + } + + bool isEmpty() const + { + return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified; + } +}; + +// +// This is just for debug print out, carried along with the definitions above. +// +inline const char* getQualifierString(TQualifier q) +{ + switch(q) + { + case EvqTemporary: return "Temporary"; break; + case EvqGlobal: return "Global"; break; + case EvqConst: return "const"; break; + case EvqConstReadOnly: return "const"; break; + case EvqAttribute: return "attribute"; break; + case EvqVaryingIn: return "varying"; break; + case EvqVaryingOut: return "varying"; break; + case EvqInvariantVaryingIn: return "invariant varying"; break; + case EvqInvariantVaryingOut:return "invariant varying"; break; + case EvqUniform: return "uniform"; break; + case EvqVertexIn: return "in"; break; + case EvqFragmentOut: return "out"; break; + case EvqVertexOut: return "out"; break; + case EvqFragmentIn: return "in"; break; + case EvqIn: return "in"; break; + case EvqOut: return "out"; break; + case EvqInOut: return "inout"; break; + case EvqPosition: return "Position"; break; + case EvqPointSize: return "PointSize"; break; + case EvqFragCoord: return "FragCoord"; break; + case EvqFrontFacing: return "FrontFacing"; break; + case EvqFragColor: return "FragColor"; break; + case EvqFragData: return "FragData"; break; + case EvqFragDepth: return "FragDepth"; break; + case EvqSmoothOut: return "smooth out"; break; + case EvqCentroidOut: return "centroid out"; break; + case EvqFlatOut: return "flat out"; break; + case EvqSmoothIn: return "smooth in"; break; + case EvqCentroidIn: return "centroid in"; break; + case EvqFlatIn: return "flat in"; break; + default: return "unknown qualifier"; + } +} + +inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) +{ + switch (mpq) + { + case EmpUnspecified: return "mp_unspecified"; + case EmpRowMajor: return "row_major"; + case EmpColumnMajor: return "column_major"; + default: return "unknown matrix packing"; + } +} + +inline const char* getBlockStorageString(TLayoutBlockStorage bsq) +{ + switch (bsq) + { + case EbsUnspecified: return "bs_unspecified"; + case EbsShared: return "shared"; + case EbsPacked: return "packed"; + case EbsStd140: return "std140"; + default: return "unknown block storage"; + } +} + +inline const char* getInterpolationString(TQualifier q) +{ + switch(q) + { + case EvqSmoothOut: return "smooth"; break; + case EvqCentroidOut: return "centroid"; break; + case EvqFlatOut: return "flat"; break; + case EvqSmoothIn: return "smooth"; break; + case EvqCentroidIn: return "centroid"; break; + case EvqFlatIn: return "flat"; break; + default: return "unknown interpolation"; + } +} + +#endif // _BASICTYPES_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp new file mode 100644 index 00000000000..afbc16926ff --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -0,0 +1,406 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/BuiltInFunctionEmulator.h" + +#include "compiler/translator/SymbolTable.h" + +namespace { + +// we use macros here instead of function definitions to work around more GLSL +// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are +// problematic because if the argument has side-effects they will be repeatedly +// evaluated. This is unlikely to show up in real shaders, but is something to +// consider. +const char* kFunctionEmulationVertexSource[] = { + "#error no emulation for cos(float)", + "#error no emulation for cos(vec2)", + "#error no emulation for cos(vec3)", + "#error no emulation for cos(vec4)", + + "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", + "#error no emulation for distance(vec2, vec2)", + "#error no emulation for distance(vec3, vec3)", + "#error no emulation for distance(vec4, vec4)", + + "#define webgl_dot_emu(x, y) ((x) * (y))", + "#error no emulation for dot(vec2, vec2)", + "#error no emulation for dot(vec3, vec3)", + "#error no emulation for dot(vec4, vec4)", + + "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", + "#error no emulation for length(vec2)", + "#error no emulation for length(vec3)", + "#error no emulation for length(vec4)", + + "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", + "#error no emulation for normalize(vec2)", + "#error no emulation for normalize(vec3)", + "#error no emulation for normalize(vec4)", + + "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", + "#error no emulation for reflect(vec2, vec2)", + "#error no emulation for reflect(vec3, vec3)", + "#error no emulation for reflect(vec4, vec4)" +}; + +const char* kFunctionEmulationFragmentSource[] = { + "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }", + "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }", + "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }", + "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }", + + "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))", + "#error no emulation for distance(vec2, vec2)", + "#error no emulation for distance(vec3, vec3)", + "#error no emulation for distance(vec4, vec4)", + + "#define webgl_dot_emu(x, y) ((x) * (y))", + "#error no emulation for dot(vec2, vec2)", + "#error no emulation for dot(vec3, vec3)", + "#error no emulation for dot(vec4, vec4)", + + "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))", + "#error no emulation for length(vec2)", + "#error no emulation for length(vec3)", + "#error no emulation for length(vec4)", + + "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))", + "#error no emulation for normalize(vec2)", + "#error no emulation for normalize(vec3)", + "#error no emulation for normalize(vec4)", + + "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))", + "#error no emulation for reflect(vec2, vec2)", + "#error no emulation for reflect(vec3, vec3)", + "#error no emulation for reflect(vec4, vec4)" +}; + +const bool kFunctionEmulationVertexMask[] = { +#if defined(__APPLE__) + // Work around ATI driver bugs in Mac. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + true, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + true, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + true, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + true, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + true, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#else + // Work around D3D driver bug in Win. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + false, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + false, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + false, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + false, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + false, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#endif + false // TFunctionUnknown +}; + +const bool kFunctionEmulationFragmentMask[] = { +#if defined(__APPLE__) + // Work around ATI driver bugs in Mac. + true, // TFunctionCos1 + true, // TFunctionCos2 + true, // TFunctionCos3 + true, // TFunctionCos4 + true, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + true, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + true, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + true, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + true, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#else + // Work around D3D driver bug in Win. + false, // TFunctionCos1 + false, // TFunctionCos2 + false, // TFunctionCos3 + false, // TFunctionCos4 + false, // TFunctionDistance1_1 + false, // TFunctionDistance2_2 + false, // TFunctionDistance3_3 + false, // TFunctionDistance4_4 + false, // TFunctionDot1_1 + false, // TFunctionDot2_2 + false, // TFunctionDot3_3 + false, // TFunctionDot4_4 + false, // TFunctionLength1 + false, // TFunctionLength2 + false, // TFunctionLength3 + false, // TFunctionLength4 + false, // TFunctionNormalize1 + false, // TFunctionNormalize2 + false, // TFunctionNormalize3 + false, // TFunctionNormalize4 + false, // TFunctionReflect1_1 + false, // TFunctionReflect2_2 + false, // TFunctionReflect3_3 + false, // TFunctionReflect4_4 +#endif + false // TFunctionUnknown +}; + +class BuiltInFunctionEmulationMarker : public TIntermTraverser { +public: + BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator) + : mEmulator(emulator) + { + } + + virtual bool visitUnary(Visit visit, TIntermUnary* node) + { + if (visit == PreVisit) { + bool needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), node->getOperand()->getType()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + + virtual bool visitAggregate(Visit visit, TIntermAggregate* node) + { + if (visit == PreVisit) { + // Here we handle all the built-in functions instead of the ones we + // currently identified as problematic. + switch (node->getOp()) { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + case EOpVectorEqual: + case EOpVectorNotEqual: + case EOpMod: + case EOpPow: + case EOpAtan: + case EOpMin: + case EOpMax: + case EOpClamp: + case EOpMix: + case EOpStep: + case EOpSmoothStep: + case EOpDistance: + case EOpDot: + case EOpCross: + case EOpFaceForward: + case EOpReflect: + case EOpRefract: + case EOpMul: + break; + default: + return true; + }; + const TIntermSequence& sequence = node->getSequence(); + // Right now we only handle built-in functions with two parameters. + if (sequence.size() != 2) + return true; + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + if (!param1 || !param2) + return true; + bool needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType()); + if (needToEmulate) + node->setUseEmulatedFunction(); + } + return true; + } + +private: + BuiltInFunctionEmulator& mEmulator; +}; + +} // anonymous namepsace + +BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType) +{ + if (shaderType == SH_FRAGMENT_SHADER) { + mFunctionMask = kFunctionEmulationFragmentMask; + mFunctionSource = kFunctionEmulationFragmentSource; + } else { + mFunctionMask = kFunctionEmulationVertexMask; + mFunctionSource = kFunctionEmulationVertexSource; + } +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param) +{ + TBuiltInFunction function = IdentifyFunction(op, param); + return SetFunctionCalled(function); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2) +{ + TBuiltInFunction function = IdentifyFunction(op, param1, param2); + return SetFunctionCalled(function); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + BuiltInFunctionEmulator::TBuiltInFunction function) { + if (function == TFunctionUnknown || mFunctionMask[function] == false) + return false; + for (size_t i = 0; i < mFunctions.size(); ++i) { + if (mFunctions[i] == function) + return true; + } + mFunctions.push_back(function); + return true; +} + +void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( + TInfoSinkBase& out, bool withPrecision) const +{ + if (mFunctions.size() == 0) + return; + out << "// BEGIN: Generated code for built-in function emulation\n\n"; + if (withPrecision) { + out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n" + << "#define webgl_emu_precision highp\n" + << "#else\n" + << "#define webgl_emu_precision mediump\n" + << "#endif\n\n"; + } else { + out << "#define webgl_emu_precision\n\n"; + } + for (size_t i = 0; i < mFunctions.size(); ++i) { + out << mFunctionSource[mFunctions[i]] << "\n\n"; + } + out << "// END: Generated code for built-in function emulation\n\n"; +} + +BuiltInFunctionEmulator::TBuiltInFunction +BuiltInFunctionEmulator::IdentifyFunction( + TOperator op, const TType& param) +{ + if (param.getNominalSize() > 4 || param.getSecondarySize() > 4) + return TFunctionUnknown; + unsigned int function = TFunctionUnknown; + switch (op) { + case EOpCos: + function = TFunctionCos1; + break; + case EOpLength: + function = TFunctionLength1; + break; + case EOpNormalize: + function = TFunctionNormalize1; + break; + default: + break; + } + if (function == TFunctionUnknown) + return TFunctionUnknown; + if (param.isVector()) + function += param.getNominalSize() - 1; + return static_cast<TBuiltInFunction>(function); +} + +BuiltInFunctionEmulator::TBuiltInFunction +BuiltInFunctionEmulator::IdentifyFunction( + TOperator op, const TType& param1, const TType& param2) +{ + // Right now for all the emulated functions with two parameters, the two + // parameters have the same type. + if (param1.getNominalSize() != param2.getNominalSize() || + param1.getSecondarySize() != param2.getSecondarySize() || + param1.getNominalSize() > 4 || param1.getSecondarySize() > 4) + return TFunctionUnknown; + + unsigned int function = TFunctionUnknown; + switch (op) { + case EOpDistance: + function = TFunctionDistance1_1; + break; + case EOpDot: + function = TFunctionDot1_1; + break; + case EOpReflect: + function = TFunctionReflect1_1; + break; + default: + break; + } + if (function == TFunctionUnknown) + return TFunctionUnknown; + if (param1.isVector()) + function += param1.getNominalSize() - 1; + return static_cast<TBuiltInFunction>(function); +} + +void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( + TIntermNode* root) +{ + ASSERT(root); + + BuiltInFunctionEmulationMarker marker(*this); + root->traverse(&marker); +} + +void BuiltInFunctionEmulator::Cleanup() +{ + mFunctions.clear(); +} + +//static +TString BuiltInFunctionEmulator::GetEmulatedFunctionName( + const TString& name) +{ + ASSERT(name[name.length() - 1] == '('); + return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h new file mode 100644 index 00000000000..9367b558ac0 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulator.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/intermediate.h" + +// +// This class decides which built-in functions need to be replaced with the +// emulated ones. +// It's only a workaround for OpenGL driver bugs, and isn't needed in general. +// +class BuiltInFunctionEmulator { +public: + BuiltInFunctionEmulator(ShShaderType shaderType); + // Records that a function is called by the shader and might needs to be + // emulated. If the function's group is not in mFunctionGroupFilter, this + // becomes an no-op. + // Returns true if the function call needs to be replaced with an emulated + // one. + bool SetFunctionCalled(TOperator op, const TType& param); + bool SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2); + + // Output function emulation definition. This should be before any other + // shader source. + void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const; + + void MarkBuiltInFunctionsForEmulation(TIntermNode* root); + + void Cleanup(); + + // "name(" becomes "webgl_name_emu(". + static TString GetEmulatedFunctionName(const TString& name); + +private: + // + // Built-in functions. + // + enum TBuiltInFunction { + TFunctionCos1 = 0, // float cos(float); + TFunctionCos2, // vec2 cos(vec2); + TFunctionCos3, // vec3 cos(vec3); + TFunctionCos4, // vec4 cos(vec4); + + TFunctionDistance1_1, // float distance(float, float); + TFunctionDistance2_2, // vec2 distance(vec2, vec2); + TFunctionDistance3_3, // vec3 distance(vec3, vec3); + TFunctionDistance4_4, // vec4 distance(vec4, vec4); + + TFunctionDot1_1, // float dot(float, float); + TFunctionDot2_2, // vec2 dot(vec2, vec2); + TFunctionDot3_3, // vec3 dot(vec3, vec3); + TFunctionDot4_4, // vec4 dot(vec4, vec4); + + TFunctionLength1, // float length(float); + TFunctionLength2, // float length(vec2); + TFunctionLength3, // float length(vec3); + TFunctionLength4, // float length(vec4); + + TFunctionNormalize1, // float normalize(float); + TFunctionNormalize2, // vec2 normalize(vec2); + TFunctionNormalize3, // vec3 normalize(vec3); + TFunctionNormalize4, // vec4 normalize(vec4); + + TFunctionReflect1_1, // float reflect(float, float); + TFunctionReflect2_2, // vec2 reflect(vec2, vec2); + TFunctionReflect3_3, // vec3 reflect(vec3, vec3); + TFunctionReflect4_4, // vec4 reflect(vec4, vec4); + + TFunctionUnknown + }; + + TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); + TBuiltInFunction IdentifyFunction( + TOperator op, const TType& param1, const TType& param2); + + bool SetFunctionCalled(TBuiltInFunction function); + + std::vector<TBuiltInFunction> mFunctions; + + const bool* mFunctionMask; // a boolean flag for each function. + const char** mFunctionSource; +}; + +#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp b/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp new file mode 100644 index 00000000000..c35dbdc77ff --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/CodeGen.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/TranslatorESSL.h" +#include "compiler/translator/TranslatorGLSL.h" +#include "compiler/translator/TranslatorHLSL.h" + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler( + ShShaderType type, ShShaderSpec spec, ShShaderOutput output) +{ + switch (output) { + case SH_ESSL_OUTPUT: + return new TranslatorESSL(type, spec); + case SH_GLSL_OUTPUT: + return new TranslatorGLSL(type, spec); + case SH_HLSL9_OUTPUT: + case SH_HLSL11_OUTPUT: + return new TranslatorHLSL(type, spec, output); + default: + return NULL; + } +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} diff --git a/chromium/third_party/angle/src/compiler/translator/Common.h b/chromium/third_party/angle/src/compiler/translator/Common.h new file mode 100644 index 00000000000..1e4503e340c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Common.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _COMMON_INCLUDED_ +#define _COMMON_INCLUDED_ + +#include <map> +#include <sstream> +#include <string> +#include <vector> +#include <limits> +#include <stdio.h> + +#include "compiler/translator/PoolAlloc.h" +#include "compiler/translator/compilerdebug.h" +#include "common/angleutils.h" + +struct TSourceLoc { + int first_file; + int first_line; + int last_file; + int last_line; +}; + +// +// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. +// +#define POOL_ALLOCATOR_NEW_DELETE() \ + void* operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void* operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void*) { } \ + void operator delete(void *, void *) { } \ + void* operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \ + void* operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void*) { } \ + void operator delete[](void *, void *) { } + +// +// Pool version of string. +// +typedef pool_allocator<char> TStringAllocator; +typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString; +typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream; +inline TString* NewPoolTString(const char* s) +{ + void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TString)); + return new(memory) TString(s); +} + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles. +// +#define TPersistString std::string +#define TPersistStringStream std::ostringstream + +// +// Pool allocator versions of vectors, lists, and maps +// +template <class T> class TVector : public std::vector<T, pool_allocator<T> > { +public: + typedef typename std::vector<T, pool_allocator<T> >::size_type size_type; + TVector() : std::vector<T, pool_allocator<T> >() {} + TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {} + TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {} +}; + +template <class K, class D, class CMP = std::less<K> > +class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > { +public: + typedef pool_allocator<std::pair<const K, D> > tAllocator; + + TMap() : std::map<K, D, CMP, tAllocator>() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {} +}; + +// Integer to TString conversion +template <typename T> +inline TString str(T i) +{ + ASSERT(std::numeric_limits<T>::is_integer); + char buffer[((8 * sizeof(T)) / 3) + 3]; + const char *formatStr = std::numeric_limits<T>::is_signed ? "%d" : "%u"; + snprintf(buffer, sizeof(buffer), formatStr, i); + return buffer; +} + +#endif // _COMMON_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/Compiler.cpp b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp new file mode 100644 index 00000000000..402715b8af1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp @@ -0,0 +1,579 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/DetectCallDepth.h" +#include "compiler/translator/ForLoopUnroll.h" +#include "compiler/translator/Initialize.h" +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/RenameFunction.h" +#include "compiler/translator/ShHandle.h" +#include "compiler/translator/UnfoldShortCircuitAST.h" +#include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/ValidateOutputs.h" +#include "compiler/translator/VariablePacker.h" +#include "compiler/translator/depgraph/DependencyGraph.h" +#include "compiler/translator/depgraph/DependencyGraphOutput.h" +#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" +#include "compiler/translator/timing/RestrictVertexShaderTiming.h" +#include "third_party/compiler/ArrayBoundsClamper.h" + +bool IsWebGLBasedSpec(ShShaderSpec spec) +{ + return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; +} + +size_t GetGlobalMaxTokenSize(ShShaderSpec spec) +{ + // WebGL defines a max token legnth of 256, while ES2 leaves max token + // size undefined. ES3 defines a max size of 1024 characters. + if (IsWebGLBasedSpec(spec)) + { + return 256; + } + else + { + return 1024; + } +} + +namespace { +class TScopedPoolAllocator +{ + public: + TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) + { + mAllocator->push(); + SetGlobalPoolAllocator(mAllocator); + } + ~TScopedPoolAllocator() + { + SetGlobalPoolAllocator(NULL); + mAllocator->pop(); + } + + private: + TPoolAllocator* mAllocator; +}; + +class TScopedSymbolTableLevel +{ + public: + TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) + { + ASSERT(mTable->atBuiltInLevel()); + mTable->push(); + } + ~TScopedSymbolTableLevel() + { + while (!mTable->atBuiltInLevel()) + mTable->pop(); + } + + private: + TSymbolTable* mTable; +}; +} // namespace + +TShHandleBase::TShHandleBase() +{ + allocator.push(); + SetGlobalPoolAllocator(&allocator); +} + +TShHandleBase::~TShHandleBase() +{ + SetGlobalPoolAllocator(NULL); + allocator.popAll(); +} + +TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec, ShShaderOutput output) + : shaderType(type), + shaderSpec(spec), + outputType(output), + maxUniformVectors(0), + maxExpressionComplexity(0), + maxCallStackDepth(0), + fragmentPrecisionHigh(false), + clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), + builtInFunctionEmulator(type) +{ +} + +TCompiler::~TCompiler() +{ +} + +bool TCompiler::Init(const ShBuiltInResources& resources) +{ + shaderVersion = 100; + maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? + resources.MaxVertexUniformVectors : + resources.MaxFragmentUniformVectors; + maxExpressionComplexity = resources.MaxExpressionComplexity; + maxCallStackDepth = resources.MaxCallStackDepth; + + SetGlobalPoolAllocator(&allocator); + + // Generate built-in symbol table. + if (!InitBuiltInSymbolTable(resources)) + return false; + InitExtensionBehavior(resources, extensionBehavior); + fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1; + + arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy); + clampingStrategy = resources.ArrayIndexClampingStrategy; + + hashFunction = resources.HashFunction; + + return true; +} + +bool TCompiler::compile(const char* const shaderStrings[], + size_t numStrings, + int compileOptions) +{ + TScopedPoolAllocator scopedAlloc(&allocator); + clearResults(); + + if (numStrings == 0) + return true; + + // If compiling for WebGL, validate loop and indexing as well. + if (IsWebGLBasedSpec(shaderSpec)) + compileOptions |= SH_VALIDATE_LOOP_INDEXING; + + // First string is path of source file if flag is set. The actual source follows. + const char* sourcePath = NULL; + size_t firstSource = 0; + if (compileOptions & SH_SOURCE_PATH) + { + sourcePath = shaderStrings[0]; + ++firstSource; + } + + TIntermediate intermediate(infoSink); + TParseContext parseContext(symbolTable, extensionBehavior, intermediate, + shaderType, shaderSpec, compileOptions, true, + sourcePath, infoSink); + parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; + SetGlobalParseContext(&parseContext); + + // We preserve symbols at the built-in level from compile-to-compile. + // Start pushing the user-defined symbols at global level. + TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); + + // Parse shader. + bool success = + (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && + (parseContext.treeRoot != NULL); + + shaderVersion = parseContext.getShaderVersion(); + + if (success) + { + TIntermNode* root = parseContext.treeRoot; + success = intermediate.postProcess(root); + + // Disallow expressions deemed too complex. + if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) + success = limitExpressionComplexity(root); + + if (success) + success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); + + if (success && shaderVersion == 300 && shaderType == SH_FRAGMENT_SHADER) + success = validateOutputs(root); + + if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) + success = validateLimitations(root); + + if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) + success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); + + if (success && shaderSpec == SH_CSS_SHADERS_SPEC) + rewriteCSSShader(root); + + // Unroll for-loop markup needs to happen after validateLimitations pass. + if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) + { + ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex); + root->traverse(&marker); + } + if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) + { + ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex); + root->traverse(&marker); + if (marker.samplerArrayIndexIsFloatLoopIndex()) + { + infoSink.info.prefix(EPrefixError); + infoSink.info << "sampler array index is float loop index"; + success = false; + } + } + + // Built-in function emulation needs to happen after validateLimitations pass. + if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) + builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); + + // Clamping uniform array bounds needs to happen after validateLimitations pass. + if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) + arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); + + if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) + initializeGLPosition(root); + + if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) + { + UnfoldShortCircuitAST unfoldShortCircuit; + root->traverse(&unfoldShortCircuit); + unfoldShortCircuit.updateTree(); + } + + if (success && (compileOptions & SH_VARIABLES)) + { + collectVariables(root); + if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) + { + success = enforcePackingRestrictions(); + if (!success) + { + infoSink.info.prefix(EPrefixError); + infoSink.info << "too many uniforms"; + } + } + if (success && shaderType == SH_VERTEX_SHADER && + (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) + initializeVaryingsWithoutStaticUse(root); + } + + if (success && (compileOptions & SH_INTERMEDIATE_TREE)) + intermediate.outputTree(root); + + if (success && (compileOptions & SH_OBJECT_CODE)) + translate(root); + } + + // Cleanup memory. + intermediate.remove(parseContext.treeRoot); + SetGlobalParseContext(NULL); + return success; +} + +bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) +{ + compileResources = resources; + setResourceString(); + + assert(symbolTable.isEmpty()); + symbolTable.push(); // COMMON_BUILTINS + symbolTable.push(); // ESSL1_BUILTINS + symbolTable.push(); // ESSL3_BUILTINS + + TPublicType integer; + integer.type = EbtInt; + integer.primarySize = 1; + integer.secondarySize = 1; + integer.array = false; + + TPublicType floatingPoint; + floatingPoint.type = EbtFloat; + floatingPoint.primarySize = 1; + floatingPoint.secondarySize = 1; + floatingPoint.array = false; + + TPublicType sampler; + sampler.primarySize = 1; + sampler.secondarySize = 1; + sampler.array = false; + + switch(shaderType) + { + case SH_FRAGMENT_SHADER: + symbolTable.setDefaultPrecision(integer, EbpMedium); + break; + case SH_VERTEX_SHADER: + symbolTable.setDefaultPrecision(integer, EbpHigh); + symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); + break; + default: + assert(false && "Language not supported"); + } + // We set defaults for all the sampler types, even those that are + // only available if an extension exists. + for (int samplerType = EbtGuardSamplerBegin + 1; + samplerType < EbtGuardSamplerEnd; ++samplerType) + { + sampler.type = static_cast<TBasicType>(samplerType); + symbolTable.setDefaultPrecision(sampler, EbpLow); + } + + InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable); + + IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable); + + return true; +} + +void TCompiler::setResourceString() +{ + std::ostringstream strstream; + strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs + << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors + << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors + << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits + << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits + << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits + << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors + << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers + << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives + << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external + << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle + << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers + << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh + << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity + << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth + << ":EXT_frag_depth:" << compileResources.EXT_frag_depth + << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod + << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors + << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors + << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset; + + builtInResourcesString = strstream.str(); +} + +void TCompiler::clearResults() +{ + arrayBoundsClamper.Cleanup(); + infoSink.info.erase(); + infoSink.obj.erase(); + infoSink.debug.erase(); + + attribs.clear(); + uniforms.clear(); + varyings.clear(); + + builtInFunctionEmulator.Cleanup(); + + nameMap.clear(); +} + +bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth) +{ + DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth); + root->traverse(&detect); + switch (detect.detectCallDepth()) + { + case DetectCallDepth::kErrorNone: + return true; + case DetectCallDepth::kErrorMissingMain: + infoSink.info.prefix(EPrefixError); + infoSink.info << "Missing main()"; + return false; + case DetectCallDepth::kErrorRecursion: + infoSink.info.prefix(EPrefixError); + infoSink.info << "Function recursion detected"; + return false; + case DetectCallDepth::kErrorMaxDepthExceeded: + infoSink.info.prefix(EPrefixError); + infoSink.info << "Function call stack too deep"; + return false; + default: + UNREACHABLE(); + return false; + } +} + +bool TCompiler::validateOutputs(TIntermNode* root) +{ + ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers); + root->traverse(&validateOutputs); + return (validateOutputs.numErrors() == 0); +} + +void TCompiler::rewriteCSSShader(TIntermNode* root) +{ + RenameFunction renamer("main(", "css_main("); + root->traverse(&renamer); +} + +bool TCompiler::validateLimitations(TIntermNode* root) +{ + ValidateLimitations validate(shaderType, infoSink.info); + root->traverse(&validate); + return validate.numErrors() == 0; +} + +bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) +{ + if (shaderSpec != SH_WEBGL_SPEC) + { + infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; + return false; + } + + if (shaderType == SH_FRAGMENT_SHADER) + { + TDependencyGraph graph(root); + + // Output any errors first. + bool success = enforceFragmentShaderTimingRestrictions(graph); + + // Then, output the dependency graph. + if (outputGraph) + { + TDependencyGraphOutput output(infoSink.info); + output.outputAllSpanningTrees(graph); + } + + return success; + } + else + { + return enforceVertexShaderTimingRestrictions(root); + } +} + +bool TCompiler::limitExpressionComplexity(TIntermNode* root) +{ + TMaxDepthTraverser traverser(maxExpressionComplexity+1); + root->traverse(&traverser); + + if (traverser.getMaxDepth() > maxExpressionComplexity) + { + infoSink.info << "Expression too complex."; + return false; + } + + TDependencyGraph graph(root); + + for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); + iter != graph.endUserDefinedFunctionCalls(); + ++iter) + { + TGraphFunctionCall* samplerSymbol = *iter; + TDependencyGraphTraverser graphTraverser; + samplerSymbol->traverse(&graphTraverser); + } + + return true; +} + +bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) +{ + RestrictFragmentShaderTiming restrictor(infoSink.info); + restrictor.enforceRestrictions(graph); + return restrictor.numErrors() == 0; +} + +bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) +{ + RestrictVertexShaderTiming restrictor(infoSink.info); + restrictor.enforceRestrictions(root); + return restrictor.numErrors() == 0; +} + +void TCompiler::collectVariables(TIntermNode* root) +{ + CollectVariables collect(attribs, uniforms, varyings, hashFunction); + root->traverse(&collect); +} + +bool TCompiler::enforcePackingRestrictions() +{ + VariablePacker packer; + return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); +} + +void TCompiler::initializeGLPosition(TIntermNode* root) +{ + InitializeVariables::InitVariableInfoList variables; + InitializeVariables::InitVariableInfo var( + "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); + variables.push_back(var); + InitializeVariables initializer(variables); + root->traverse(&initializer); +} + +void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) +{ + InitializeVariables::InitVariableInfoList variables; + for (size_t ii = 0; ii < varyings.size(); ++ii) + { + const TVariableInfo& varying = varyings[ii]; + if (varying.staticUse) + continue; + unsigned char primarySize = 1, secondarySize = 1; + switch (varying.type) + { + case SH_FLOAT: + break; + case SH_FLOAT_VEC2: + primarySize = 2; + break; + case SH_FLOAT_VEC3: + primarySize = 3; + break; + case SH_FLOAT_VEC4: + primarySize = 4; + break; + case SH_FLOAT_MAT2: + primarySize = 2; + secondarySize = 2; + break; + case SH_FLOAT_MAT3: + primarySize = 3; + secondarySize = 3; + break; + case SH_FLOAT_MAT4: + primarySize = 4; + secondarySize = 4; + break; + default: + ASSERT(false); + } + TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray); + TString name = varying.name.c_str(); + if (varying.isArray) + { + type.setArraySize(varying.size); + name = name.substr(0, name.find_first_of('[')); + } + + InitializeVariables::InitVariableInfo var(name, type); + variables.push_back(var); + } + InitializeVariables initializer(variables); + root->traverse(&initializer); +} + +const TExtensionBehavior& TCompiler::getExtensionBehavior() const +{ + return extensionBehavior; +} + +const ShBuiltInResources& TCompiler::getResources() const +{ + return compileResources; +} + +const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const +{ + return arrayBoundsClamper; +} + +ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const +{ + return clampingStrategy; +} + +const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const +{ + return builtInFunctionEmulator; +} diff --git a/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h new file mode 100644 index 00000000000..5fdba61546c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h @@ -0,0 +1,282 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _CONSTANT_UNION_INCLUDED_ +#define _CONSTANT_UNION_INCLUDED_ + +#include <assert.h> + +class ConstantUnion { +public: + POOL_ALLOCATOR_NEW_DELETE(); + ConstantUnion() + { + iConst = 0; + type = EbtVoid; + } + + void setIConst(int i) {iConst = i; type = EbtInt; } + void setUConst(unsigned int u) { uConst = u; type = EbtUInt; } + void setFConst(float f) {fConst = f; type = EbtFloat; } + void setBConst(bool b) {bConst = b; type = EbtBool; } + + int getIConst() const { return iConst; } + unsigned int getUConst() const { return uConst; } + float getFConst() const { return fConst; } + bool getBConst() const { return bConst; } + + bool operator==(const int i) const + { + return i == iConst; + } + + bool operator==(const unsigned int u) const + { + return u == uConst; + } + + bool operator==(const float f) const + { + return f == fConst; + } + + bool operator==(const bool b) const + { + return b == bConst; + } + + bool operator==(const ConstantUnion& constant) const + { + if (constant.type != type) + return false; + + switch (type) { + case EbtInt: + return constant.iConst == iConst; + case EbtUInt: + return constant.uConst == uConst; + case EbtFloat: + return constant.fConst == fConst; + case EbtBool: + return constant.bConst == bConst; + default: + return false; + } + } + + bool operator!=(const int i) const + { + return !operator==(i); + } + + bool operator!=(const unsigned int u) const + { + return !operator==(u); + } + + bool operator!=(const float f) const + { + return !operator==(f); + } + + bool operator!=(const bool b) const + { + return !operator==(b); + } + + bool operator!=(const ConstantUnion& constant) const + { + return !operator==(constant); + } + + bool operator>(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst > constant.iConst; + case EbtUInt: + return uConst > constant.uConst; + case EbtFloat: + return fConst > constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + + bool operator<(const ConstantUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + return iConst < constant.iConst; + case EbtUInt: + return uConst < constant.uConst; + case EbtFloat: + return fConst < constant.fConst; + default: + return false; // Invalid operation, handled at semantic analysis + } + } + + ConstantUnion operator+(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break; + case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator-(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break; + case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator*(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break; + case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator%(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator>>(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator<<(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator|(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator^(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator&&(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + ConstantUnion operator||(const ConstantUnion& constant) const + { + ConstantUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + TBasicType getType() const { return type; } +private: + + union { + int iConst; // used for ivec, scalar ints + unsigned int uConst; // used for uvec, scalar uints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + } ; + + TBasicType type; +}; + +#endif // _CONSTANT_UNION_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp new file mode 100644 index 00000000000..bfc1d5852ff --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.cpp @@ -0,0 +1,185 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/DetectCallDepth.h" +#include "compiler/translator/InfoSink.h" + +DetectCallDepth::FunctionNode::FunctionNode(const TString& fname) + : name(fname), + visit(PreVisit) +{ +} + +const TString& DetectCallDepth::FunctionNode::getName() const +{ + return name; +} + +void DetectCallDepth::FunctionNode::addCallee( + DetectCallDepth::FunctionNode* callee) +{ + for (size_t i = 0; i < callees.size(); ++i) { + if (callees[i] == callee) + return; + } + callees.push_back(callee); +} + +int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth) +{ + ASSERT(visit == PreVisit); + ASSERT(detectCallDepth); + + int maxDepth = depth; + visit = InVisit; + for (size_t i = 0; i < callees.size(); ++i) { + switch (callees[i]->visit) { + case InVisit: + // cycle detected, i.e., recursion detected. + return kInfiniteCallDepth; + case PostVisit: + break; + case PreVisit: { + // Check before we recurse so we don't go too depth + if (detectCallDepth->checkExceedsMaxDepth(depth)) + return depth; + int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1); + // Check after we recurse so we can exit immediately and provide info. + if (detectCallDepth->checkExceedsMaxDepth(callDepth)) { + detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName(); + return callDepth; + } + maxDepth = std::max(callDepth, maxDepth); + break; + } + default: + UNREACHABLE(); + break; + } + } + visit = PostVisit; + return maxDepth; +} + +void DetectCallDepth::FunctionNode::reset() +{ + visit = PreVisit; +} + +DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth) + : TIntermTraverser(true, false, true, false), + currentFunction(NULL), + infoSink(infoSink), + maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth) +{ +} + +DetectCallDepth::~DetectCallDepth() +{ + for (size_t i = 0; i < functions.size(); ++i) + delete functions[i]; +} + +bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node) +{ + switch (node->getOp()) + { + case EOpPrototype: + // Function declaration. + // Don't add FunctionNode here because node->getName() is the + // unmangled function name. + break; + case EOpFunction: { + // Function definition. + if (visit == PreVisit) { + currentFunction = findFunctionByName(node->getName()); + if (currentFunction == NULL) { + currentFunction = new FunctionNode(node->getName()); + functions.push_back(currentFunction); + } + } else if (visit == PostVisit) { + currentFunction = NULL; + } + break; + } + case EOpFunctionCall: { + // Function call. + if (visit == PreVisit) { + FunctionNode* func = findFunctionByName(node->getName()); + if (func == NULL) { + func = new FunctionNode(node->getName()); + functions.push_back(func); + } + if (currentFunction) + currentFunction->addCallee(func); + } + break; + } + default: + break; + } + return true; +} + +bool DetectCallDepth::checkExceedsMaxDepth(int depth) +{ + return depth >= maxDepth; +} + +void DetectCallDepth::resetFunctionNodes() +{ + for (size_t i = 0; i < functions.size(); ++i) { + functions[i]->reset(); + } +} + +DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func) +{ + currentFunction = NULL; + resetFunctionNodes(); + + int maxCallDepth = func->detectCallDepth(this, 1); + + if (maxCallDepth == FunctionNode::kInfiniteCallDepth) + return kErrorRecursion; + + if (maxCallDepth >= maxDepth) + return kErrorMaxDepthExceeded; + + return kErrorNone; +} + +DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth() +{ + if (maxDepth != FunctionNode::kInfiniteCallDepth) { + // Check all functions because the driver may fail on them + // TODO: Before detectingRecursion, strip unused functions. + for (size_t i = 0; i < functions.size(); ++i) { + ErrorCode error = detectCallDepthForFunction(functions[i]); + if (error != kErrorNone) + return error; + } + } else { + FunctionNode* main = findFunctionByName("main("); + if (main == NULL) + return kErrorMissingMain; + + return detectCallDepthForFunction(main); + } + + return kErrorNone; +} + +DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName( + const TString& name) +{ + for (size_t i = 0; i < functions.size(); ++i) { + if (functions[i]->getName() == name) + return functions[i]; + } + return NULL; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h new file mode 100644 index 00000000000..cb76f1de02a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DetectCallDepth.h @@ -0,0 +1,78 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DETECT_RECURSION_H_ +#define COMPILER_DETECT_RECURSION_H_ + +#include <limits.h> +#include "compiler/translator/intermediate.h" +#include "compiler/translator/VariableInfo.h" + +class TInfoSink; + +// Traverses intermediate tree to detect function recursion. +class DetectCallDepth : public TIntermTraverser { +public: + enum ErrorCode { + kErrorMissingMain, + kErrorRecursion, + kErrorMaxDepthExceeded, + kErrorNone + }; + + DetectCallDepth(TInfoSink& infoSync, bool limitCallStackDepth, int maxCallStackDepth); + ~DetectCallDepth(); + + virtual bool visitAggregate(Visit, TIntermAggregate*); + + bool checkExceedsMaxDepth(int depth); + + ErrorCode detectCallDepth(); + +private: + class FunctionNode { + public: + static const int kInfiniteCallDepth = INT_MAX; + + FunctionNode(const TString& fname); + + const TString& getName() const; + + // If a function is already in the callee list, this becomes a no-op. + void addCallee(FunctionNode* callee); + + // Returns kInifinityCallDepth if recursive function calls are detected. + int detectCallDepth(DetectCallDepth* detectCallDepth, int depth); + + // Reset state. + void reset(); + + private: + // mangled function name is unique. + TString name; + + // functions that are directly called by this function. + TVector<FunctionNode*> callees; + + Visit visit; + }; + + ErrorCode detectCallDepthForFunction(FunctionNode* func); + FunctionNode* findFunctionByName(const TString& name); + void resetFunctionNodes(); + + TInfoSink& getInfoSink() { return infoSink; } + + TVector<FunctionNode*> functions; + FunctionNode* currentFunction; + TInfoSink& infoSink; + int maxDepth; + + DetectCallDepth(const DetectCallDepth&); + void operator=(const DetectCallDepth&); +}; + +#endif // COMPILER_DETECT_RECURSION_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp new file mode 100644 index 00000000000..334eb0bfa8b --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.cpp @@ -0,0 +1,139 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Contains analysis utilities for dealing with HLSL's lack of support for +// the use of intrinsic functions which (implicitly or explicitly) compute +// gradients of functions with discontinuities. +// + +#include "compiler/translator/DetectDiscontinuity.h" + +#include "compiler/translator/ParseContext.h" + +namespace sh +{ +bool DetectLoopDiscontinuity::traverse(TIntermNode *node) +{ + mLoopDepth = 0; + mLoopDiscontinuity = false; + node->traverse(this); + return mLoopDiscontinuity; +} + +bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop) +{ + if (visit == PreVisit) + { + ++mLoopDepth; + } + else if (visit == PostVisit) + { + --mLoopDepth; + } + + return true; +} + +bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node) +{ + if (mLoopDiscontinuity) + { + return false; + } + + if (!mLoopDepth) + { + return true; + } + + switch (node->getFlowOp()) + { + case EOpKill: + break; + case EOpBreak: + case EOpContinue: + case EOpReturn: + mLoopDiscontinuity = true; + break; + default: UNREACHABLE(); + } + + return !mLoopDiscontinuity; +} + +bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node) +{ + return !mLoopDiscontinuity; +} + +bool containsLoopDiscontinuity(TIntermNode *node) +{ + DetectLoopDiscontinuity detectLoopDiscontinuity; + return detectLoopDiscontinuity.traverse(node); +} + +bool DetectGradientOperation::traverse(TIntermNode *node) +{ + mGradientOperation = false; + node->traverse(this); + return mGradientOperation; +} + +bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mGradientOperation) + { + return false; + } + + switch (node->getOp()) + { + case EOpDFdx: + case EOpDFdy: + mGradientOperation = true; + default: + break; + } + + return !mGradientOperation; +} + +bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mGradientOperation) + { + return false; + } + + if (node->getOp() == EOpFunctionCall) + { + if (!node->isUserDefined()) + { + TString name = TFunction::unmangleName(node->getName()); + + if (name == "texture2D" || + name == "texture2DProj" || + name == "textureCube") + { + mGradientOperation = true; + } + } + else + { + // When a user defined function is called, we have to + // conservatively assume it to contain gradient operations + mGradientOperation = true; + } + } + + return !mGradientOperation; +} + +bool containsGradientOperation(TIntermNode *node) +{ + DetectGradientOperation detectGradientOperation; + return detectGradientOperation.traverse(node); +} +} diff --git a/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h new file mode 100644 index 00000000000..1dd8be92335 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DetectDiscontinuity.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Contains analysis utilities for dealing with HLSL's lack of support for +// the use of intrinsic functions which (implicitly or explicitly) compute +// gradients of functions with discontinuities. +// + +#ifndef COMPILER_DETECTDISCONTINUITY_H_ +#define COMPILER_DETECTDISCONTINUITY_H_ + +#include "compiler/translator/intermediate.h" + +namespace sh +{ +// Checks whether a loop can run for a variable number of iterations +class DetectLoopDiscontinuity : public TIntermTraverser +{ + public: + bool traverse(TIntermNode *node); + + protected: + bool visitBranch(Visit visit, TIntermBranch *node); + bool visitLoop(Visit visit, TIntermLoop *loop); + bool visitAggregate(Visit visit, TIntermAggregate *node); + + int mLoopDepth; + bool mLoopDiscontinuity; +}; + +bool containsLoopDiscontinuity(TIntermNode *node); + +// Checks for intrinsic functions which compute gradients +class DetectGradientOperation : public TIntermTraverser +{ + public: + bool traverse(TIntermNode *node); + + protected: + bool visitUnary(Visit visit, TIntermUnary *node); + bool visitAggregate(Visit visit, TIntermAggregate *node); + + bool mGradientOperation; +}; + +bool containsGradientOperation(TIntermNode *node); + +} + +#endif // COMPILER_DETECTDISCONTINUITY_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp new file mode 100644 index 00000000000..92db3e55cfb --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/Diagnostics.h" + +#include "compiler/translator/compilerdebug.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/preprocessor/SourceLocation.h" + +TDiagnostics::TDiagnostics(TInfoSink& infoSink) : + mInfoSink(infoSink), + mNumErrors(0), + mNumWarnings(0) +{ +} + +TDiagnostics::~TDiagnostics() +{ +} + +void TDiagnostics::writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra) +{ + TPrefixType prefix = EPrefixNone; + switch (severity) + { + case PP_ERROR: + ++mNumErrors; + prefix = EPrefixError; + break; + case PP_WARNING: + ++mNumWarnings; + prefix = EPrefixWarning; + break; + default: + UNREACHABLE(); + break; + } + + TInfoSinkBase& sink = mInfoSink.info; + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + sink.prefix(prefix); + sink.location(loc.file, loc.line); + sink << "'" << token << "' : " << reason << " " << extra << "\n"; +} + +void TDiagnostics::writeDebug(const std::string& str) +{ + mInfoSink.debug << str; +} + +void TDiagnostics::print(ID id, + const pp::SourceLocation& loc, + const std::string& text) +{ + writeInfo(severity(id), loc, message(id), text, ""); +} diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.h b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h new file mode 100644 index 00000000000..664da7803b8 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DIAGNOSTICS_H_ +#define COMPILER_DIAGNOSTICS_H_ + +#include "compiler/preprocessor/DiagnosticsBase.h" + +class TInfoSink; + +class TDiagnostics : public pp::Diagnostics +{ + public: + TDiagnostics(TInfoSink& infoSink); + virtual ~TDiagnostics(); + + TInfoSink& infoSink() { return mInfoSink; } + + int numErrors() const { return mNumErrors; } + int numWarnings() const { return mNumWarnings; } + + void writeInfo(Severity severity, + const pp::SourceLocation& loc, + const std::string& reason, + const std::string& token, + const std::string& extra); + + void writeDebug(const std::string& str); + + protected: + virtual void print(ID id, + const pp::SourceLocation& loc, + const std::string& text); + + private: + TInfoSink& mInfoSink; + int mNumErrors; + int mNumWarnings; +}; + +#endif // COMPILER_DIAGNOSTICS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp new file mode 100644 index 00000000000..59d2835f7b7 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp @@ -0,0 +1,166 @@ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/DirectiveHandler.h" + +#include <sstream> + +#include "compiler/translator/compilerdebug.h" +#include "compiler/translator/Diagnostics.h" + +static TBehavior getBehavior(const std::string& str) +{ + static const std::string kRequire("require"); + static const std::string kEnable("enable"); + static const std::string kDisable("disable"); + static const std::string kWarn("warn"); + + if (str == kRequire) return EBhRequire; + else if (str == kEnable) return EBhEnable; + else if (str == kDisable) return EBhDisable; + else if (str == kWarn) return EBhWarn; + return EBhUndefined; +} + +TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics, + int& shaderVersion) + : mExtensionBehavior(extBehavior), + mDiagnostics(diagnostics), + mShaderVersion(shaderVersion) +{ +} + +TDirectiveHandler::~TDirectiveHandler() +{ +} + +void TDirectiveHandler::handleError(const pp::SourceLocation& loc, + const std::string& msg) +{ + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", ""); +} + +void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value) +{ + static const std::string kSTDGL("STDGL"); + static const std::string kOptimize("optimize"); + static const std::string kDebug("debug"); + static const std::string kOn("on"); + static const std::string kOff("off"); + + bool invalidValue = false; + if (name == kSTDGL) + { + // The STDGL pragma is used to reserve pragmas for use by future + // revisions of GLSL. Ignore it. + return; + } + else if (name == kOptimize) + { + if (value == kOn) mPragma.optimize = true; + else if (value == kOff) mPragma.optimize = false; + else invalidValue = true; + } + else if (name == kDebug) + { + if (value == kOn) mPragma.debug = true; + else if (value == kOff) mPragma.debug = false; + else invalidValue = true; + } + else + { + mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); + return; + } + + if (invalidValue) + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "invalid pragma value", value, + "'on' or 'off' expected"); +} + +void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior) +{ + static const std::string kExtAll("all"); + + TBehavior behaviorVal = getBehavior(behavior); + if (behaviorVal == EBhUndefined) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "behavior", name, "invalid"); + return; + } + + if (name == kExtAll) + { + if (behaviorVal == EBhRequire) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "extension", name, + "cannot have 'require' behavior"); + } + else if (behaviorVal == EBhEnable) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "extension", name, + "cannot have 'enable' behavior"); + } + else + { + for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin(); + iter != mExtensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + return; + } + + TExtensionBehavior::iterator iter = mExtensionBehavior.find(name); + if (iter != mExtensionBehavior.end()) + { + iter->second = behaviorVal; + return; + } + + pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR; + switch (behaviorVal) { + case EBhRequire: + severity = pp::Diagnostics::PP_ERROR; + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + severity = pp::Diagnostics::PP_WARNING; + break; + default: + UNREACHABLE(); + break; + } + mDiagnostics.writeInfo(severity, loc, + "extension", name, "is not supported"); +} + +void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, + int version) +{ + if (version == 100 || + version == 300) + { + mShaderVersion = version; + } + else + { + std::stringstream stream; + stream << version; + std::string str = stream.str(); + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "version number", str, "not supported"); + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h new file mode 100644 index 00000000000..69418c277af --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DIRECTIVE_HANDLER_H_ +#define COMPILER_DIRECTIVE_HANDLER_H_ + +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/Pragma.h" +#include "compiler/preprocessor/DirectiveHandlerBase.h" + +class TDiagnostics; + +class TDirectiveHandler : public pp::DirectiveHandler +{ + public: + TDirectiveHandler(TExtensionBehavior& extBehavior, + TDiagnostics& diagnostics, + int& shaderVersion); + virtual ~TDirectiveHandler(); + + const TPragma& pragma() const { return mPragma; } + const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; } + + virtual void handleError(const pp::SourceLocation& loc, + const std::string& msg); + + virtual void handlePragma(const pp::SourceLocation& loc, + const std::string& name, + const std::string& value); + + virtual void handleExtension(const pp::SourceLocation& loc, + const std::string& name, + const std::string& behavior); + + virtual void handleVersion(const pp::SourceLocation& loc, + int version); + + private: + TPragma mPragma; + TExtensionBehavior& mExtensionBehavior; + TDiagnostics& mDiagnostics; + int& mShaderVersion; +}; + +#endif // COMPILER_DIRECTIVE_HANDLER_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h b/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h new file mode 100644 index 00000000000..5c1595fb212 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ExtensionBehavior.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _EXTENSION_BEHAVIOR_INCLUDED_ +#define _EXTENSION_BEHAVIOR_INCLUDED_ + +#include <map> +#include <string> + +typedef enum +{ + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable, + EBhUndefined +} TBehavior; + +inline const char* getBehaviorString(TBehavior b) +{ + switch(b) + { + case EBhRequire: return "require"; + case EBhEnable: return "enable"; + case EBhWarn: return "warn"; + case EBhDisable: return "disable"; + default: return NULL; + } +} + +// Mapping between extension name and behavior. +typedef std::map<std::string, TBehavior> TExtensionBehavior; + +#endif // _EXTENSION_TABLE_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp new file mode 100644 index 00000000000..a751b768b78 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.cpp @@ -0,0 +1,77 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/FlagStd140Structs.h" + +namespace sh +{ + +bool FlagStd140Structs::visitBinary(Visit visit, TIntermBinary *binaryNode) +{ + if (binaryNode->getRight()->getBasicType() == EbtStruct) + { + switch (binaryNode->getOp()) + { + case EOpIndexDirectInterfaceBlock: + case EOpIndexDirectStruct: + if (isInStd140InterfaceBlock(binaryNode->getLeft())) + { + mFlaggedNodes.push_back(binaryNode); + } + break; + + default: break; + } + return false; + } + + if (binaryNode->getOp() == EOpIndexDirectStruct) + { + return false; + } + + return visit == PreVisit; +} + +void FlagStd140Structs::visitSymbol(TIntermSymbol *symbol) +{ + if (isInStd140InterfaceBlock(symbol) && symbol->getBasicType() == EbtStruct) + { + mFlaggedNodes.push_back(symbol); + } +} + +bool FlagStd140Structs::isInStd140InterfaceBlock(TIntermTyped *node) const +{ + TIntermBinary *binaryNode = node->getAsBinaryNode(); + + if (binaryNode) + { + return isInStd140InterfaceBlock(binaryNode->getLeft()); + } + + const TType &type = node->getType(); + + // determine if we are in the standard layout + const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); + if (interfaceBlock) + { + return (interfaceBlock->blockStorage() == EbsStd140); + } + + return false; +} + +std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node) +{ + FlagStd140Structs flaggingTraversal; + + node->traverse(&flaggingTraversal); + + return flaggingTraversal.getFlaggedNodes(); +} + +} diff --git a/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h new file mode 100644 index 00000000000..610205eb92e --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/FlagStd140Structs.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_FLAGSTD140STRUCTS_H_ +#define COMPILER_FLAGSTD140STRUCTS_H_ + +#include "compiler/translator/intermediate.h" + +namespace sh +{ + +// This class finds references to nested structs of std140 blocks that access +// the nested struct "by value", where the padding added in the translator +// conflicts with the "natural" unpadded type. +class FlagStd140Structs : public TIntermTraverser +{ + public: + const std::vector<TIntermTyped *> getFlaggedNodes() const { return mFlaggedNodes; } + + protected: + virtual bool visitBinary(Visit visit, TIntermBinary *binaryNode); + virtual void visitSymbol(TIntermSymbol *symbol); + + private: + bool isInStd140InterfaceBlock(TIntermTyped *node) const; + + std::vector<TIntermTyped *> mFlaggedNodes; +}; + +std::vector<TIntermTyped *> FlagStd140ValueStructs(TIntermNode *node); + +} + +#endif // COMPILER_FLAGSTD140STRUCTS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp new file mode 100644 index 00000000000..5cb51645593 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.cpp @@ -0,0 +1,82 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/ForLoopUnroll.h" + +bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node) +{ + if (mUnrollCondition != kSamplerArrayIndex) + return true; + + // If a sampler array index is also the loop index, + // 1) if the index type is integer, mark the loop for unrolling; + // 2) if the index type if float, set a flag to later fail compile. + switch (node->getOp()) + { + case EOpIndexIndirect: + if (node->getLeft() != NULL && node->getRight() != NULL && node->getLeft()->getAsSymbolNode()) + { + TIntermSymbol *symbol = node->getLeft()->getAsSymbolNode(); + if (IsSampler(symbol->getBasicType()) && symbol->isArray() && !mLoopStack.empty()) + { + mVisitSamplerArrayIndexNodeInsideLoop = true; + node->getRight()->traverse(this); + mVisitSamplerArrayIndexNodeInsideLoop = false; + // We have already visited all the children. + return false; + } + } + break; + default: + break; + } + return true; +} + +bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node) +{ + if (mUnrollCondition == kIntegerIndex) + { + // Check if loop index type is integer. + // This is called after ValidateLimitations pass, so all the calls + // should be valid. See ValidateLimitations::validateForLoopInit(). + TIntermSequence& declSeq = node->getInit()->getAsAggregate()->getSequence(); + TIntermSymbol* symbol = declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + if (symbol->getBasicType() == EbtInt) + node->setUnrollFlag(true); + } + + TIntermNode *body = node->getBody(); + if (body != NULL) + { + mLoopStack.push(node); + body->traverse(this); + mLoopStack.pop(); + } + // The loop is fully processed - no need to visit children. + return false; +} + +void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol) +{ + if (!mVisitSamplerArrayIndexNodeInsideLoop) + return; + TIntermLoop *loop = mLoopStack.findLoop(symbol); + if (loop) + { + switch (symbol->getBasicType()) + { + case EbtFloat: + mSamplerArrayIndexIsFloatLoopIndex = true; + break; + case EbtInt: + loop->setUnrollFlag(true); + break; + default: + UNREACHABLE(); + } + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h new file mode 100644 index 00000000000..a820d2a20d6 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ForLoopUnroll.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_FORLOOPUNROLL_H_ +#define COMPILER_FORLOOPUNROLL_H_ + +#include "compiler/translator/LoopInfo.h" + +// This class detects for-loops that needs to be unrolled. +// Currently we support two unroll conditions: +// 1) kForLoopWithIntegerIndex: unroll if the index type is integer. +// 2) kForLoopWithSamplerArrayIndex: unroll where a sampler array index +// is also the loop integer index, and reject and fail a compile +// where a sampler array index is also the loop float index. +class ForLoopUnrollMarker : public TIntermTraverser +{ + public: + enum UnrollCondition + { + kIntegerIndex, + kSamplerArrayIndex + }; + + ForLoopUnrollMarker(UnrollCondition condition) + : mUnrollCondition(condition), + mSamplerArrayIndexIsFloatLoopIndex(false), + mVisitSamplerArrayIndexNodeInsideLoop(false) + { + } + + virtual bool visitBinary(Visit, TIntermBinary *node); + virtual bool visitLoop(Visit, TIntermLoop *node); + virtual void visitSymbol(TIntermSymbol *node); + + bool samplerArrayIndexIsFloatLoopIndex() const + { + return mSamplerArrayIndexIsFloatLoopIndex; + } + + private: + UnrollCondition mUnrollCondition; + TLoopStack mLoopStack; + bool mSamplerArrayIndexIsFloatLoopIndex; + bool mVisitSamplerArrayIndexNodeInsideLoop; +}; + +#endif diff --git a/chromium/third_party/angle/src/compiler/translator/HashNames.h b/chromium/third_party/angle/src/compiler/translator/HashNames.h new file mode 100644 index 00000000000..85161428b2a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/HashNames.h @@ -0,0 +1,18 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_HASH_NAMES_H_ +#define COMPILER_HASH_NAMES_H_ + +#include <map> + +#include "compiler/translator/intermediate.h" + +#define HASHED_NAME_PREFIX "webgl_" + +typedef std::map<TPersistString, TPersistString> NameMap; + +#endif // COMPILER_HASH_NAMES_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp b/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp new file mode 100644 index 00000000000..cd59658ff76 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InfoSink.cpp @@ -0,0 +1,54 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/InfoSink.h" + +void TInfoSinkBase::prefix(TPrefixType p) { + switch(p) { + case EPrefixNone: + break; + case EPrefixWarning: + sink.append("WARNING: "); + break; + case EPrefixError: + sink.append("ERROR: "); + break; + case EPrefixInternalError: + sink.append("INTERNAL ERROR: "); + break; + case EPrefixUnimplemented: + sink.append("UNIMPLEMENTED: "); + break; + case EPrefixNote: + sink.append("NOTE: "); + break; + default: + sink.append("UNKOWN ERROR: "); + break; + } +} + +void TInfoSinkBase::location(int file, int line) { + TPersistStringStream stream; + if (line) + stream << file << ":" << line; + else + stream << file << ":? "; + stream << ": "; + + sink.append(stream.str()); +} + +void TInfoSinkBase::location(const TSourceLoc& loc) { + location(loc.first_file, loc.first_line); +} + +void TInfoSinkBase::message(TPrefixType p, const TSourceLoc& loc, const char* m) { + prefix(p); + location(loc); + sink.append(m); + sink.append("\n"); +} diff --git a/chromium/third_party/angle/src/compiler/translator/InfoSink.h b/chromium/third_party/angle/src/compiler/translator/InfoSink.h new file mode 100644 index 00000000000..698a8b454b3 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InfoSink.h @@ -0,0 +1,116 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _INFOSINK_INCLUDED_ +#define _INFOSINK_INCLUDED_ + +#include <math.h> +#include <stdlib.h> +#include "compiler/translator/Common.h" + +// Returns the fractional part of the given floating-point number. +inline float fractionalPart(float f) { + float intPart = 0.0f; + return modff(f, &intPart); +} + +// +// TPrefixType is used to centralize how info log messages start. +// See below. +// +enum TPrefixType { + EPrefixNone, + EPrefixWarning, + EPrefixError, + EPrefixInternalError, + EPrefixUnimplemented, + EPrefixNote +}; + +// +// Encapsulate info logs for all objects that have them. +// +// The methods are a general set of tools for getting a variety of +// messages and types inserted into the log. +// +class TInfoSinkBase { +public: + TInfoSinkBase() {} + + template <typename T> + TInfoSinkBase& operator<<(const T& t) { + TPersistStringStream stream; + stream << t; + sink.append(stream.str()); + return *this; + } + // Override << operator for specific types. It is faster to append strings + // and characters directly to the sink. + TInfoSinkBase& operator<<(char c) { + sink.append(1, c); + return *this; + } + TInfoSinkBase& operator<<(const char* str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TPersistString& str) { + sink.append(str); + return *this; + } + TInfoSinkBase& operator<<(const TString& str) { + sink.append(str.c_str()); + return *this; + } + // Make sure floats are written with correct precision. + TInfoSinkBase& operator<<(float f) { + // Make sure that at least one decimal point is written. If a number + // does not have a fractional part, the default precision format does + // not write the decimal portion which gets interpreted as integer by + // the compiler. + TPersistStringStream stream; + if (fractionalPart(f) == 0.0f) { + stream.precision(1); + stream << std::showpoint << std::fixed << f; + } else { + stream.unsetf(std::ios::fixed); + stream.unsetf(std::ios::scientific); + stream.precision(8); + stream << f; + } + sink.append(stream.str()); + return *this; + } + // Write boolean values as their names instead of integral value. + TInfoSinkBase& operator<<(bool b) { + const char* str = b ? "true" : "false"; + sink.append(str); + return *this; + } + + void erase() { sink.clear(); } + int size() { return static_cast<int>(sink.size()); } + + const TPersistString& str() const { return sink; } + const char* c_str() const { return sink.c_str(); } + + void prefix(TPrefixType p); + void location(int file, int line); + void location(const TSourceLoc& loc); + void message(TPrefixType p, const TSourceLoc& loc, const char* m); + +private: + TPersistString sink; +}; + +class TInfoSink { +public: + TInfoSinkBase info; + TInfoSinkBase debug; + TInfoSinkBase obj; +}; + +#endif // _INFOSINK_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/Initialize.cpp b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp new file mode 100644 index 00000000000..27e96f4014a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp @@ -0,0 +1,760 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Create symbols that declare built-in definitions, add built-ins that +// cannot be expressed in the files, and establish mappings between +// built-in functions and operators. +// + +#include "compiler/translator/Initialize.h" + +#include "compiler/translator/intermediate.h" + +void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable) +{ + TType *float1 = new TType(EbtFloat); + TType *float2 = new TType(EbtFloat, 2); + TType *float3 = new TType(EbtFloat, 3); + TType *float4 = new TType(EbtFloat, 4); + + TType *int1 = new TType(EbtInt); + TType *int2 = new TType(EbtInt, 2); + TType *int3 = new TType(EbtInt, 3); + TType *int4 = new TType(EbtInt, 4); + + // + // Angle and Trigonometric Functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "radians", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "radians", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "radians", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "radians", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "degrees", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "degrees", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "degrees", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "degrees", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sin", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sin", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sin", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sin", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "cos", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "cos", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cos", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "cos", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "tan", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "tan", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "tan", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "tan", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "asin", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "asin", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "asin", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "asin", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "acos", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "acos", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "acos", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "acos", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4); + + // + // Exponential Functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "pow", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "pow", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "pow", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "pow", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp2", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp2", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp2", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp2", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log2", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log2", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log2", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log2", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sqrt", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sqrt", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sqrt", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sqrt", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "inversesqrt", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "inversesqrt", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "inversesqrt", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "inversesqrt", float4); + + // + // Common Functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "abs", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "abs", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "abs", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "abs", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sign", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sign", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sign", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sign", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "floor", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "floor", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "floor", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "floor", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "ceil", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "ceil", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "ceil", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "ceil", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "fract", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "fract", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "fract", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "fract", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mod", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "min", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "max", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "clamp", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mix", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "step", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float1, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float1, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float1, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "smoothstep", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float4, float4, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float1, float1, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float1, float1, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float1, float1, float4); + + // + // Geometric Functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cross", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "normalize", float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "normalize", float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "normalize", float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "normalize", float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "faceforward", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "faceforward", float2, float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "faceforward", float3, float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "faceforward", float4, float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "reflect", float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "reflect", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "reflect", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "reflect", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "refract", float1, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "refract", float2, float2, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "refract", float3, float3, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "refract", float4, float4, float1); + + TType *mat2 = new TType(EbtFloat, 2, 2); + TType *mat3 = new TType(EbtFloat, 3, 3); + TType *mat4 = new TType(EbtFloat, 4, 4); + + // + // Matrix Functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat2, "matrixCompMult", mat2, mat2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat3, "matrixCompMult", mat3, mat3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, mat4, "matrixCompMult", mat4, mat4); + + TType *bool1 = new TType(EbtBool); + TType *bool2 = new TType(EbtBool, 2); + TType *bool3 = new TType(EbtBool, 3); + TType *bool4 = new TType(EbtBool, 4); + + // + // Vector relational functions. + // + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", bool2, bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", bool3, bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", bool4, bool4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", float2, float2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", float4, float4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", int2, int2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", int3, int3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", int4, int4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", bool2, bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", bool3, bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", bool4, bool4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool4); + + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "not", bool2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "not", bool3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "not", bool4); + + TType *sampler2D = new TType(EbtSampler2D); + TType *samplerCube = new TType(EbtSamplerCube); + + // + // Texture Functions for GLSL ES 1.0 + // + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3); + + if (resources.OES_EGL_image_external) + { + TType *samplerExternalOES = new TType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES, float4); + } + + if (resources.ARB_texture_rectangle) + { + TType *sampler2DRect = new TType(EbtSampler2DRect); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect, float4); + } + + if (resources.EXT_shader_texture_lod) + { + /* The *Grad* variants are new to both vertex and fragment shaders; the fragment + * shader specific pieces are added separately below. + */ + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DGradEXT", sampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); + } + + if (type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCube", samplerCube, float3, float1); + + if (resources.OES_standard_derivatives) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdx", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdx", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdx", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdx", float4); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdy", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdy", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdy", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdy", float4); + + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "fwidth", float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "fwidth", float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "fwidth", float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "fwidth", float4); + } + + if (resources.EXT_shader_texture_lod) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLodEXT", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLodEXT", samplerCube, float3, float1); + } + } + + if(type == SH_VERTEX_SHADER) + { + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLod", samplerCube, float3, float1); + } + + TType *gvec4 = new TType(EbtGVec4); + + TType *gsampler2D = new TType(EbtGSampler2D); + TType *gsamplerCube = new TType(EbtGSamplerCube); + TType *gsampler3D = new TType(EbtGSampler3D); + TType *gsampler2DArray = new TType(EbtGSampler2DArray); + + // + // Texture Functions for GLSL ES 3.0 + // + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler3D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1); + + if (type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler3D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsamplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2DArray, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1); + } + + TType *sampler2DShadow = new TType(EbtSampler2DShadow); + TType *samplerCubeShadow = new TType(EbtSamplerCubeShadow); + TType *sampler2DArrayShadow = new TType(EbtSampler2DArrayShadow); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DArrayShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLod", sampler2DShadow, float3, float1); + + if (type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProj", sampler2DShadow, float4, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsampler2D, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler3D, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", gsamplerCube, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", gsampler2DArray, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2DShadow, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); + + if(type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdx", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdx", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdx", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdx", float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdy", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdy", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdy", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdy", float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "fwidth", float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "fwidth", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "fwidth", float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "fwidth", float4); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2); + + if(type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2); + + if(type == SH_FRAGMENT_SHADER) + { + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2, float1); + } + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2D, float2, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler3D, float3, float1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureLodOffset", sampler2DShadow, float3, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLodOffset", gsampler2DArray, float3, float1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLod", gsampler3D, float4, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLod", sampler2DShadow, float4, float1); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float3, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler2D, float4, float1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjLodOffset", gsampler3D, float4, float1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjLodOffset", sampler2DShadow, float4, float1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2D, int2, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler3D, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsamplerCube, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DShadow, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", samplerCubeShadow, float4, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGrad", gsampler2DArray, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGrad", sampler2DArrayShadow, float4, float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2D, float2, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler3D, float3, float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DShadow, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureGradOffset", gsampler2DArray, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureGradOffset", sampler2DArrayShadow, float4, float2, float2, int2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGrad", gsampler3D, float4, float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGrad", sampler2DShadow, float4, float2, float2); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float3, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler2D, float4, float2, float2, int2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2); + + // + // Depth range in window coordinates + // + TFieldList *fields = NewPoolTFieldList(); + TSourceLoc zeroSourceLoc = {0, 0, 0, 0}; + TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"), zeroSourceLoc); + TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"), zeroSourceLoc); + TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"), zeroSourceLoc); + fields->push_back(near); + fields->push_back(far); + fields->push_back(diff); + TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields); + TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true); + symbolTable.insert(COMMON_BUILTINS, *depthRangeParameters); + TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct)); + depthRange->setQualifier(EvqUniform); + symbolTable.insert(COMMON_BUILTINS, *depthRange); + + // + // Implementation dependent built-in constants. + // + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors); + + symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors); + + if (spec != SH_CSS_SHADERS_SPEC) + { + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers); + } + + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", resources.MaxProgramTexelOffset); +} + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources &resources, + TSymbolTable &symbolTable) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(type) { + case SH_FRAGMENT_SHADER: + symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); + symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); + symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); + + // + // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available. + // Instead, css_MixColor and css_ColorMatrix are available. + // + if (spec != SH_CSS_SHADERS_SPEC) { + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); + if (resources.EXT_frag_depth) { + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); + symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_FragDepthEXT", "GL_EXT_frag_depth"); + } + } else { + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); + } + + break; + + case SH_VERTEX_SHADER: + symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); + symbolTable.insert(COMMON_BUILTINS, *new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1))); + break; + + default: assert(false && "Language not supported"); + } + + // + // Next, identify which built-ins from the already loaded headers have + // a mapping to an operator. Those that are not identified as such are + // expected to be resolved through a library of functions, versus as + // operations. + // + symbolTable.relateToOperator(COMMON_BUILTINS, "matrixCompMult", EOpMul); + + symbolTable.relateToOperator(COMMON_BUILTINS, "equal", EOpVectorEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "notEqual", EOpVectorNotEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "lessThan", EOpLessThan); + symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThan", EOpGreaterThan); + symbolTable.relateToOperator(COMMON_BUILTINS, "lessThanEqual", EOpLessThanEqual); + symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThanEqual", EOpGreaterThanEqual); + + symbolTable.relateToOperator(COMMON_BUILTINS, "radians", EOpRadians); + symbolTable.relateToOperator(COMMON_BUILTINS, "degrees", EOpDegrees); + symbolTable.relateToOperator(COMMON_BUILTINS, "sin", EOpSin); + symbolTable.relateToOperator(COMMON_BUILTINS, "cos", EOpCos); + symbolTable.relateToOperator(COMMON_BUILTINS, "tan", EOpTan); + symbolTable.relateToOperator(COMMON_BUILTINS, "asin", EOpAsin); + symbolTable.relateToOperator(COMMON_BUILTINS, "acos", EOpAcos); + symbolTable.relateToOperator(COMMON_BUILTINS, "atan", EOpAtan); + + symbolTable.relateToOperator(COMMON_BUILTINS, "pow", EOpPow); + symbolTable.relateToOperator(COMMON_BUILTINS, "exp2", EOpExp2); + symbolTable.relateToOperator(COMMON_BUILTINS, "log", EOpLog); + symbolTable.relateToOperator(COMMON_BUILTINS, "exp", EOpExp); + symbolTable.relateToOperator(COMMON_BUILTINS, "log2", EOpLog2); + symbolTable.relateToOperator(COMMON_BUILTINS, "sqrt", EOpSqrt); + symbolTable.relateToOperator(COMMON_BUILTINS, "inversesqrt", EOpInverseSqrt); + + symbolTable.relateToOperator(COMMON_BUILTINS, "abs", EOpAbs); + symbolTable.relateToOperator(COMMON_BUILTINS, "sign", EOpSign); + symbolTable.relateToOperator(COMMON_BUILTINS, "floor", EOpFloor); + symbolTable.relateToOperator(COMMON_BUILTINS, "ceil", EOpCeil); + symbolTable.relateToOperator(COMMON_BUILTINS, "fract", EOpFract); + symbolTable.relateToOperator(COMMON_BUILTINS, "mod", EOpMod); + symbolTable.relateToOperator(COMMON_BUILTINS, "min", EOpMin); + symbolTable.relateToOperator(COMMON_BUILTINS, "max", EOpMax); + symbolTable.relateToOperator(COMMON_BUILTINS, "clamp", EOpClamp); + symbolTable.relateToOperator(COMMON_BUILTINS, "mix", EOpMix); + symbolTable.relateToOperator(COMMON_BUILTINS, "step", EOpStep); + symbolTable.relateToOperator(COMMON_BUILTINS, "smoothstep", EOpSmoothStep); + + symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength); + symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance); + symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot); + symbolTable.relateToOperator(COMMON_BUILTINS, "cross", EOpCross); + symbolTable.relateToOperator(COMMON_BUILTINS, "normalize", EOpNormalize); + symbolTable.relateToOperator(COMMON_BUILTINS, "faceforward", EOpFaceForward); + symbolTable.relateToOperator(COMMON_BUILTINS, "reflect", EOpReflect); + symbolTable.relateToOperator(COMMON_BUILTINS, "refract", EOpRefract); + + symbolTable.relateToOperator(COMMON_BUILTINS, "any", EOpAny); + symbolTable.relateToOperator(COMMON_BUILTINS, "all", EOpAll); + symbolTable.relateToOperator(COMMON_BUILTINS, "not", EOpVectorLogicalNot); + + // Map language-specific operators. + switch(type) { + case SH_VERTEX_SHADER: + break; + case SH_FRAGMENT_SHADER: + if (resources.OES_standard_derivatives) + { + symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdx", EOpDFdx); + symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdy", EOpDFdy); + symbolTable.relateToOperator(ESSL1_BUILTINS, "fwidth", EOpFwidth); + + symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdx", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdy", "GL_OES_standard_derivatives"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "fwidth", "GL_OES_standard_derivatives"); + } + if (resources.EXT_shader_texture_lod) + { + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DLodEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjLodEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeLodEXT", "GL_EXT_shader_texture_lod"); + } + break; + default: break; + } + + symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdx", EOpDFdx); + symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdy", EOpDFdy); + symbolTable.relateToOperator(ESSL3_BUILTINS, "fwidth", EOpFwidth); + + if (resources.EXT_shader_texture_lod) + { + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DGradEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjGradEXT", "GL_EXT_shader_texture_lod"); + symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeGradEXT", "GL_EXT_shader_texture_lod"); + } + + // Finally add resource-specific variables. + switch(type) { + case SH_FRAGMENT_SHADER: + if (spec != SH_CSS_SHADERS_SPEC) { + // Set up gl_FragData. The array size. + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); + fragData.setArraySize(resources.MaxDrawBuffers); + symbolTable.insert(ESSL1_BUILTINS, *new TVariable(NewPoolTString("gl_FragData"), fragData)); + } + break; + default: break; + } +} + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extBehavior) +{ + if (resources.OES_standard_derivatives) + extBehavior["GL_OES_standard_derivatives"] = EBhUndefined; + if (resources.OES_EGL_image_external) + extBehavior["GL_OES_EGL_image_external"] = EBhUndefined; + if (resources.ARB_texture_rectangle) + extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined; + if (resources.EXT_draw_buffers) + extBehavior["GL_EXT_draw_buffers"] = EBhUndefined; + if (resources.EXT_frag_depth) + extBehavior["GL_EXT_frag_depth"] = EBhUndefined; + if (resources.EXT_shader_texture_lod) + extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined; +} diff --git a/chromium/third_party/angle/src/compiler/translator/Initialize.h b/chromium/third_party/angle/src/compiler/translator/Initialize.h new file mode 100644 index 00000000000..b5642869aa1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Initialize.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _INITIALIZE_INCLUDED_ +#define _INITIALIZE_INCLUDED_ + +#include "compiler/translator/Common.h" +#include "compiler/translator/ShHandle.h" +#include "compiler/translator/SymbolTable.h" + +void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table); + +void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec, + const ShBuiltInResources& resources, + TSymbolTable& symbolTable); + +void InitExtensionBehavior(const ShBuiltInResources& resources, + TExtensionBehavior& extensionBehavior); + +#endif // _INITIALIZE_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp new file mode 100644 index 00000000000..43f81784d0a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeDll.cpp @@ -0,0 +1,32 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/InitializeDll.h" + +#include "compiler/translator/InitializeGlobals.h" +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/osinclude.h" + +bool InitProcess() +{ + if (!InitializePoolIndex()) { + assert(0 && "InitProcess(): Failed to initalize global pool"); + return false; + } + + if (!InitializeParseContextIndex()) { + assert(0 && "InitProcess(): Failed to initalize parse context"); + return false; + } + + return true; +} + +void DetachProcess() +{ + FreeParseContextIndex(); + FreePoolIndex(); +} diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeDll.h b/chromium/third_party/angle/src/compiler/translator/InitializeDll.h new file mode 100644 index 00000000000..43070cc3ff7 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeDll.h @@ -0,0 +1,13 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef __INITIALIZEDLL_H +#define __INITIALIZEDLL_H + +bool InitProcess(); +void DetachProcess(); + +#endif // __INITIALIZEDLL_H + diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h b/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h new file mode 100644 index 00000000000..07159414247 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeGlobals.h @@ -0,0 +1,13 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __INITIALIZE_GLOBALS_INCLUDED_ +#define __INITIALIZE_GLOBALS_INCLUDED_ + +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // __INITIALIZE_GLOBALS_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp new file mode 100644 index 00000000000..b4defae5695 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/InitializeParseContext.h" + +#include "compiler/translator/osinclude.h" + +OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + +bool InitializeParseContextIndex() +{ + assert(GlobalParseContextIndex == OS_INVALID_TLS_INDEX); + + GlobalParseContextIndex = OS_AllocTLSIndex(); + return GlobalParseContextIndex != OS_INVALID_TLS_INDEX; +} + +void FreeParseContextIndex() +{ + assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); + + OS_FreeTLSIndex(GlobalParseContextIndex); + GlobalParseContextIndex = OS_INVALID_TLS_INDEX; +} + +void SetGlobalParseContext(TParseContext* context) +{ + assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); + OS_SetTLSValue(GlobalParseContextIndex, context); +} + +TParseContext* GetGlobalParseContext() +{ + assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX); + return static_cast<TParseContext*>(OS_GetTLSValue(GlobalParseContextIndex)); +} + diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h new file mode 100644 index 00000000000..bffbab87d07 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeParseContext.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ + +bool InitializeParseContextIndex(); +void FreeParseContextIndex(); + +struct TParseContext; +extern void SetGlobalParseContext(TParseContext* context); +extern TParseContext* GetGlobalParseContext(); + +#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp new file mode 100644 index 00000000000..115c561c775 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/InitializeVariables.h" +#include "compiler/translator/compilerdebug.h" + +namespace +{ + +TIntermConstantUnion* constructFloatConstUnionNode(const TType& type) +{ + TType myType = type; + unsigned char size = myType.getNominalSize(); + if (myType.isMatrix()) + size *= size; + ConstantUnion *u = new ConstantUnion[size]; + for (int ii = 0; ii < size; ++ii) + u[ii].setFConst(0.0f); + + myType.clearArrayness(); + myType.setQualifier(EvqConst); + TIntermConstantUnion *node = new TIntermConstantUnion(u, myType); + return node; +} + +TIntermConstantUnion* constructIndexNode(int index) +{ + ConstantUnion *u = new ConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +} // namespace anonymous + +bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate* node) +{ + bool visitChildren = !mCodeInserted; + switch (node->getOp()) + { + case EOpSequence: + break; + case EOpFunction: + { + // Function definition. + ASSERT(visit == PreVisit); + if (node->getName() == "main(") + { + TIntermSequence &sequence = node->getSequence(); + ASSERT((sequence.size() == 1) || (sequence.size() == 2)); + TIntermAggregate *body = NULL; + if (sequence.size() == 1) + { + body = new TIntermAggregate(EOpSequence); + sequence.push_back(body); + } + else + { + body = sequence[1]->getAsAggregate(); + } + ASSERT(body); + insertInitCode(body->getSequence()); + mCodeInserted = true; + } + break; + } + default: + visitChildren = false; + break; + } + return visitChildren; +} + +void InitializeVariables::insertInitCode(TIntermSequence& sequence) +{ + for (size_t ii = 0; ii < mVariables.size(); ++ii) + { + const InitVariableInfo& varInfo = mVariables[ii]; + + if (varInfo.type.isArray()) + { + for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index) + { + TIntermBinary *assign = new TIntermBinary(EOpAssign); + sequence.insert(sequence.begin(), assign); + + TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); + TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); + indexDirect->setLeft(symbol); + TIntermConstantUnion *indexNode = constructIndexNode(index); + indexDirect->setRight(indexNode); + + assign->setLeft(indexDirect); + + TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); + assign->setRight(zeroConst); + } + } + else + { + TIntermBinary *assign = new TIntermBinary(EOpAssign); + sequence.insert(sequence.begin(), assign); + TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); + assign->setLeft(symbol); + TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); + assign->setRight(zeroConst); + } + + } +} + diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h new file mode 100644 index 00000000000..1cd6d7e1b51 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_INITIALIZE_VARIABLES_H_ +#define COMPILER_INITIALIZE_VARIABLES_H_ + +#include "compiler/translator/intermediate.h" + +class InitializeVariables : public TIntermTraverser +{ + public: + struct InitVariableInfo + { + TString name; + TType type; + + InitVariableInfo(const TString& _name, const TType& _type) + : name(_name), + type(_type) + { + } + }; + typedef TVector<InitVariableInfo> InitVariableInfoList; + + InitializeVariables(const InitVariableInfoList& vars) + : mCodeInserted(false), + mVariables(vars) + { + } + + protected: + virtual bool visitBinary(Visit visit, TIntermBinary* node) { return false; } + virtual bool visitUnary(Visit visit, TIntermUnary* node) { return false; } + virtual bool visitSelection(Visit visit, TIntermSelection* node) { return false; } + virtual bool visitLoop(Visit visit, TIntermLoop* node) { return false; } + virtual bool visitBranch(Visit visit, TIntermBranch* node) { return false; } + + virtual bool visitAggregate(Visit visit, TIntermAggregate* node); + + private: + void insertInitCode(TIntermSequence& sequence); + + InitVariableInfoList mVariables; + bool mCodeInserted; +}; + +#endif // COMPILER_INITIALIZE_VARIABLES_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp new file mode 100644 index 00000000000..69f87c32847 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp @@ -0,0 +1,263 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/intermediate.h" + +// +// Traverse the intermediate representation tree, and +// call a node type specific function for each node. +// Done recursively through the member function Traverse(). +// Node types can be skipped if their function to call is 0, +// but their subtree will still be traversed. +// Nodes with children can have their whole subtree skipped +// if preVisit is turned on and the type specific function +// returns false. +// +// preVisit, postVisit, and rightToLeft control what order +// nodes are visited in. +// + +// +// Traversal functions for terminals are straighforward.... +// +void TIntermSymbol::traverse(TIntermTraverser *it) +{ + it->visitSymbol(this); +} + +void TIntermConstantUnion::traverse(TIntermTraverser *it) +{ + it->visitConstantUnion(this); +} + +// +// Traverse a binary node. +// +void TIntermBinary::traverse(TIntermTraverser *it) +{ + bool visit = true; + + // + // visit the node before children if pre-visiting. + // + if (it->preVisit) + visit = it->visitBinary(PreVisit, this); + + // + // Visit the children, in the right order. + // + if (visit) + { + it->incrementDepth(this); + + if (it->rightToLeft) + { + if (right) + right->traverse(it); + + if (it->inVisit) + visit = it->visitBinary(InVisit, this); + + if (visit && left) + left->traverse(it); + } + else + { + if (left) + left->traverse(it); + + if (it->inVisit) + visit = it->visitBinary(InVisit, this); + + if (visit && right) + right->traverse(it); + } + + it->decrementDepth(); + } + + // + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + // + if (visit && it->postVisit) + it->visitBinary(PostVisit, this); +} + +// +// Traverse a unary node. Same comments in binary node apply here. +// +void TIntermUnary::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitUnary(PreVisit, this); + + if (visit) { + it->incrementDepth(this); + operand->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitUnary(PostVisit, this); +} + +// +// Traverse an aggregate node. Same comments in binary node apply here. +// +void TIntermAggregate::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitAggregate(PreVisit, this); + + if (visit) + { + it->incrementDepth(this); + + if (it->rightToLeft) + { + for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) + { + (*sit)->traverse(it); + + if (visit && it->inVisit) + { + if (*sit != sequence.front()) + visit = it->visitAggregate(InVisit, this); + } + } + } + else + { + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + (*sit)->traverse(it); + + if (visit && it->inVisit) + { + if (*sit != sequence.back()) + visit = it->visitAggregate(InVisit, this); + } + } + } + + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitAggregate(PostVisit, this); +} + +// +// Traverse a selection node. Same comments in binary node apply here. +// +void TIntermSelection::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSelection(PreVisit, this); + + if (visit) { + it->incrementDepth(this); + if (it->rightToLeft) { + if (falseBlock) + falseBlock->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + condition->traverse(it); + } else { + condition->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + if (falseBlock) + falseBlock->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSelection(PostVisit, this); +} + +// +// Traverse a loop node. Same comments in binary node apply here. +// +void TIntermLoop::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitLoop(PreVisit, this); + + if (visit) + { + it->incrementDepth(this); + + if (it->rightToLeft) + { + if (expr) + expr->traverse(it); + + if (body) + body->traverse(it); + + if (cond) + cond->traverse(it); + + if (init) + init->traverse(it); + } + else + { + if (init) + init->traverse(it); + + if (cond) + cond->traverse(it); + + if (body) + body->traverse(it); + + if (expr) + expr->traverse(it); + } + + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitLoop(PostVisit, this); +} + +// +// Traverse a branch node. Same comments in binary node apply here. +// +void TIntermBranch::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitBranch(PreVisit, this); + + if (visit && expression) { + it->incrementDepth(this); + expression->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitBranch(PostVisit, this); +} + +void TIntermRaw::traverse(TIntermTraverser *it) +{ + it->visitRaw(this); +} diff --git a/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp new file mode 100644 index 00000000000..9df2afc53c2 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp @@ -0,0 +1,1835 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Build the intermediate representation. +// + +#include <float.h> +#include <limits.h> +#include <algorithm> + +#include "compiler/translator/HashNames.h" +#include "compiler/translator/localintermediate.h" +#include "compiler/translator/QualifierAlive.h" +#include "compiler/translator/RemoveTree.h" +#include "compiler/translator/SymbolTable.h" + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray); + +static TPrecision GetHigherPrecision(TPrecision left, TPrecision right) +{ + return left > right ? left : right; +} + +const char* getOperatorString(TOperator op) +{ + switch (op) { + case EOpInitialize: return "="; + case EOpAssign: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + case EOpDivAssign: return "/="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return "."; + case EOpVectorSwizzle: return "."; + case EOpAdd: return "+"; + case EOpSub: return "-"; + case EOpMul: return "*"; + case EOpDiv: return "/"; + case EOpMod: UNIMPLEMENTED(); break; + case EOpEqual: return "=="; + case EOpNotEqual: return "!="; + case EOpLessThan: return "<"; + case EOpGreaterThan: return ">"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + case EOpNegative: return "-"; + case EOpVectorLogicalNot: return "not"; + case EOpLogicalNot: return "!"; + case EOpPostIncrement: return "++"; + case EOpPostDecrement: return "--"; + case EOpPreIncrement: return "++"; + case EOpPreDecrement: return "--"; + + // Fall-through. + case EOpConvIntToBool: + case EOpConvUIntToBool: + case EOpConvFloatToBool: return "bool"; + + // Fall-through. + case EOpConvBoolToFloat: + case EOpConvUIntToFloat: + case EOpConvIntToFloat: return "float"; + + // Fall-through. + case EOpConvFloatToInt: + case EOpConvUIntToInt: + case EOpConvBoolToInt: return "int"; + + // Fall-through. + case EOpConvIntToUInt: + case EOpConvFloatToUInt: + case EOpConvBoolToUInt: return "uint"; + + case EOpRadians: return "radians"; + case EOpDegrees: return "degrees"; + case EOpSin: return "sin"; + case EOpCos: return "cos"; + case EOpTan: return "tan"; + case EOpAsin: return "asin"; + case EOpAcos: return "acos"; + case EOpAtan: return "atan"; + case EOpExp: return "exp"; + case EOpLog: return "log"; + case EOpExp2: return "exp2"; + case EOpLog2: return "log2"; + case EOpSqrt: return "sqrt"; + case EOpInverseSqrt: return "inversesqrt"; + case EOpAbs: return "abs"; + case EOpSign: return "sign"; + case EOpFloor: return "floor"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpLength: return "length"; + case EOpNormalize: return "normalize"; + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + case EOpAny: return "any"; + case EOpAll: return "all"; + + default: break; + } + return ""; +} + +//////////////////////////////////////////////////////////////////////////// +// +// First set of functions are to help build the intermediate representation. +// These functions are not member functions of the nodes. +// They are called from parser productions. +// +///////////////////////////////////////////////////////////////////////////// + +// +// Add a terminal node for an identifier in an expression. +// +// Returns the added node. +// +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line) +{ + TIntermSymbol* node = new TIntermSymbol(id, name, type); + node->setLine(line); + + return node; +} + +// +// Connect two nodes with a new parent that does a binary operation on the nodes. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +{ + switch (op) { + case EOpEqual: + case EOpNotEqual: + if (left->isArray()) + return 0; + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + if (left->getType().getStruct() && right->getType().getStruct()) { + if (left->getType() != right->getType()) + return 0; + } else { + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child) + right = child; + else { + child = addConversion(op, right->getType(), left); + if (child) + left = child; + else + return 0; + } + } + + // + // Need a new node holding things together then. Make + // one and promote it to the right type. + // + TIntermBinary* node = new TIntermBinary(op); + node->setLine(line); + + node->setLeft(left); + node->setRight(right); + if (!node->promote(infoSink)) + return 0; + + // + // See if we can fold constants. + // + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + if (leftTempConstant && rightTempConstant) { + TIntermTyped *typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + + if (typedReturnNode) + return typedReturnNode; + } + + return node; +} + +// +// Connect two nodes through an assignment. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +{ + // + // Like adding binary math, except the conversion can only go + // from right to left. + // + TIntermBinary* node = new TIntermBinary(op); + node->setLine(line); + + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child == 0) + return 0; + + node->setLeft(left); + node->setRight(child); + if (! node->promote(infoSink)) + return 0; + + return node; +} + +// +// Connect two nodes through an index operator, where the left node is the base +// of an array or struct, and the right node is a direct or indirect offset. +// +// Returns the added node. +// The caller should set the type of the returned node. +// +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line) +{ + TIntermBinary* node = new TIntermBinary(op); + node->setLine(line); + node->setLeft(base); + node->setRight(index); + + // caller should set the type + + return node; +} + +// +// Add one node as the parent of another that it operates on. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line) +{ + TIntermUnary* node; + TIntermTyped* child = childNode->getAsTyped(); + + if (child == 0) { + infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath"); + return 0; + } + + switch (op) { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { + return 0; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) + return 0; + default: break; + } + + // + // Do we need to promote the operand? + // + // Note: Implicit promotions were removed from the language. + // + TBasicType newType = EbtVoid; + switch (op) { + case EOpConstructInt: newType = EbtInt; break; + case EOpConstructUInt: newType = EbtUInt; break; + case EOpConstructBool: newType = EbtBool; break; + case EOpConstructFloat: newType = EbtFloat; break; + default: break; + } + + if (newType != EbtVoid) { + child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary, + child->getNominalSize(), + child->getSecondarySize(), + child->isArray()), + child); + if (child == 0) + return 0; + } + + // + // For constructors, we are now done, it's all in the conversion. + // + switch (op) { + case EOpConstructInt: + case EOpConstructUInt: + case EOpConstructBool: + case EOpConstructFloat: + return child; + default: break; + } + + TIntermConstantUnion *childTempConstant = 0; + if (child->getAsConstantUnion()) + childTempConstant = child->getAsConstantUnion(); + + // + // Make a new node for the operator. + // + node = new TIntermUnary(op); + node->setLine(line); + node->setOperand(child); + + if (! node->promote(infoSink)) + return 0; + + if (childTempConstant) { + TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + + if (newChild) + return newChild; + } + + return node; +} + +// +// This is the safe way to change the operator on an aggregate, as it +// does lots of error checking and fixing. Especially for establishing +// a function call's operation on it's set of parameters. Sequences +// of instructions are also aggregates, but they just direnctly set +// their operator to EOpSequence. +// +// Returns an aggregate node, which could be the one passed in if +// it was already an aggregate but no operator was set. +// +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line) +{ + TIntermAggregate* aggNode; + + // + // Make sure we have an aggregate. If not turn it into one. + // + if (node) { + aggNode = node->getAsAggregate(); + if (aggNode == 0 || aggNode->getOp() != EOpNull) { + // + // Make an aggregate containing this node. + // + aggNode = new TIntermAggregate(); + aggNode->getSequence().push_back(node); + } + } else + aggNode = new TIntermAggregate(); + + // + // Set the operator. + // + aggNode->setOp(op); + aggNode->setLine(line); + + return aggNode; +} + +// +// Convert one type to another. +// +// Returns the node representing the conversion, which could be the same +// node passed in if no conversion was needed. +// +// Return 0 if a conversion can't be done. +// +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) +{ + // + // Does the base type allow operation? + // + if (node->getBasicType() == EbtVoid || + IsSampler(node->getBasicType())) + { + return 0; + } + + // + // Otherwise, if types are identical, no problem + // + if (type == node->getType()) + return node; + + // + // If one's a structure, then no conversions. + // + if (type.getStruct() || node->getType().getStruct()) + return 0; + + // + // If one's an array, then no conversions. + // + if (type.isArray() || node->getType().isArray()) + return 0; + + TBasicType promoteTo; + + switch (op) { + // + // Explicit conversions + // + case EOpConstructBool: + promoteTo = EbtBool; + break; + case EOpConstructFloat: + promoteTo = EbtFloat; + break; + case EOpConstructInt: + promoteTo = EbtInt; + break; + case EOpConstructUInt: + promoteTo = EbtUInt; + break; + default: + // + // implicit conversions were removed from the language. + // + if (type.getBasicType() != node->getType().getBasicType()) + return 0; + // + // Size and structure could still differ, but that's + // handled by operator promotion. + // + return node; + } + + if (node->getAsConstantUnion()) { + + return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); + } else { + + // + // Add a new newNode for the conversion. + // + TIntermUnary* newNode = 0; + + TOperator newOp = EOpNull; + switch (promoteTo) { + case EbtFloat: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToFloat; break; + case EbtUInt: newOp = EOpConvFloatToUInt; break; + case EbtBool: newOp = EOpConvBoolToFloat; break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); + return 0; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtUInt: newOp = EOpConvBoolToUInt; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); + return 0; + } + break; + case EbtInt: + switch (node->getBasicType()) { + case EbtUInt: newOp = EOpConvUIntToInt; break; + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); + return 0; + } + break; + case EbtUInt: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToUInt; break; + case EbtBool: newOp = EOpConvBoolToUInt; break; + case EbtFloat: newOp = EOpConvFloatToUInt; break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node"); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type"); + return 0; + } + + TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->getSecondarySize(), node->isArray()); + newNode = new TIntermUnary(newOp, type); + newNode->setLine(node->getLine()); + newNode->setOperand(node); + + return newNode; + } +} + +// +// Safe way to combine two nodes into an aggregate. Works with null pointers, +// a node that's not a aggregate yet, etc. +// +// Returns the resulting aggregate, unless 0 was passed in for +// both existing nodes. +// +TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line) +{ + if (left == 0 && right == 0) + return 0; + + TIntermAggregate* aggNode = 0; + if (left) + aggNode = left->getAsAggregate(); + if (!aggNode || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left) + aggNode->getSequence().push_back(left); + } + + if (right) + aggNode->getSequence().push_back(right); + + aggNode->setLine(line); + + return aggNode; +} + +// +// Turn an existing node into an aggregate. +// +// Returns an aggregate, unless 0 was passed in for the existing node. +// +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->getSequence().push_back(node); + + aggNode->setLine(line); + + return aggNode; +} + +// +// For "if" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are in the +// nodePair. +// +// Returns the selection node created. +// +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line) +{ + // + // For compile time constant selections, prune the code and + // test now. + // + + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getBConst(0) == true) + return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + else + return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + } + + TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + node->setLine(line); + + return node; +} + + +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line) +{ + if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + return right; + } else { + TIntermTyped *commaAggregate = growAggregate(left, right, line); + commaAggregate->getAsAggregate()->setOp(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->setQualifier(EvqTemporary); + return commaAggregate; + } +} + +// +// For "?:" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are specified +// as separate parameters. +// +// Returns the selection node created, or 0 if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line) +{ + // + // Get compatible types. + // + TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); + if (child) + falseBlock = child; + else { + child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); + if (child) + trueBlock = child; + else + return 0; + } + + // + // See if all the operands are constant, then fold it otherwise not. + // + + if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getBConst(0)) + return trueBlock; + else + return falseBlock; + } + + // + // Make a selection node. + // + TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + node->getTypePointer()->setQualifier(EvqTemporary); + node->setLine(line); + + return node; +} + +// +// Constant terminal nodes. Has a union that contains bool, float or int constants +// +// Returns the constant union node created. +// + +TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line) +{ + TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + node->setLine(line); + + return node; +} + +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line) +{ + + TIntermAggregate* node = new TIntermAggregate(EOpSequence); + + node->setLine(line); + TIntermConstantUnion* constIntNode; + TIntermSequence &sequenceVector = node->getSequence(); + ConstantUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.offsets[i]); + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line) +{ + TIntermNode* node = new TIntermLoop(type, init, cond, expr, body); + node->setLine(line); + + return node; +} + +// +// Add branches. +// +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line) +{ + return addBranch(branchOp, 0, line); +} + +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line) +{ + TIntermBranch* node = new TIntermBranch(branchOp, expression); + node->setLine(line); + + return node; +} + +// +// This is to be executed once the final root is put on top by the parsing +// process. +// +bool TIntermediate::postProcess(TIntermNode* root) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOp(EOpSequence); + + return true; +} + +// +// This deletes the tree. +// +void TIntermediate::remove(TIntermNode* root) +{ + if (root) + RemoveAllTreeNodes(root); +} + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +#define REPLACE_IF_IS(node, type, original, replacement) \ + if (node == original) { \ + node = static_cast<type *>(replacement); \ + return true; \ + } + +bool TIntermLoop::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(init, TIntermNode, original, replacement); + REPLACE_IF_IS(cond, TIntermTyped, original, replacement); + REPLACE_IF_IS(expr, TIntermTyped, original, replacement); + REPLACE_IF_IS(body, TIntermNode, original, replacement); + return false; +} + +void TIntermLoop::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + if (init) + { + nodeQueue->push(init); + } + if (cond) + { + nodeQueue->push(cond); + } + if (expr) + { + nodeQueue->push(expr); + } + if (body) + { + nodeQueue->push(body); + } +} + +bool TIntermBranch::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(expression, TIntermTyped, original, replacement); + return false; +} + +void TIntermBranch::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + if (expression) + { + nodeQueue->push(expression); + } +} + +bool TIntermBinary::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(left, TIntermTyped, original, replacement); + REPLACE_IF_IS(right, TIntermTyped, original, replacement); + return false; +} + +void TIntermBinary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + if (left) + { + nodeQueue->push(left); + } + if (right) + { + nodeQueue->push(right); + } +} + +bool TIntermUnary::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(operand, TIntermTyped, original, replacement); + return false; +} + +void TIntermUnary::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + if (operand) + { + nodeQueue->push(operand); + } +} + +bool TIntermAggregate::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + for (size_t ii = 0; ii < sequence.size(); ++ii) + { + REPLACE_IF_IS(sequence[ii], TIntermNode, original, replacement); + } + return false; +} + +void TIntermAggregate::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + for (size_t childIndex = 0; childIndex < sequence.size(); childIndex++) + { + nodeQueue->push(sequence[childIndex]); + } +} + +bool TIntermSelection::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(condition, TIntermTyped, original, replacement); + REPLACE_IF_IS(trueBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(falseBlock, TIntermNode, original, replacement); + return false; +} + +void TIntermSelection::enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const +{ + if (condition) + { + nodeQueue->push(condition); + } + if (trueBlock) + { + nodeQueue->push(trueBlock); + } + if (falseBlock) + { + nodeQueue->push(falseBlock); + } +} + +// +// Say whether or not an operation node changes the value of a variable. +// +bool TIntermOperator::isAssignment() const +{ + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + return true; + default: + return false; + } +} + +// +// returns true if the operator is for one of the constructors +// +bool TIntermOperator::isConstructor() const +{ + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructUVec2: + case EOpConstructUVec3: + case EOpConstructUVec4: + case EOpConstructUInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; + } +} + +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +// Returns false in nothing makes sense. +// +bool TIntermUnary::promote(TInfoSink&) +{ + switch (op) { + case EOpLogicalNot: + if (operand->getBasicType() != EbtBool) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (operand->getBasicType() == EbtBool) + return false; + break; + + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; + + default: + if (operand->getBasicType() != EbtFloat) + return false; + } + + setType(operand->getType()); + type.setQualifier(EvqTemporary); + + return true; +} + +bool validateMultiplication(TOperator op, const TType &left, const TType &right) +{ + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && left.getSecondarySize() == right.getSecondarySize(); + case EOpVectorTimesScalar: + case EOpVectorTimesScalarAssign: + return true; + case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + return left.getNominalSize() == right.getRows() && left.getNominalSize() == right.getCols(); + case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); + case EOpMatrixTimesScalar: + case EOpMatrixTimesScalarAssign: + return true; + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + return left.getCols() == right.getCols() && left.getRows() == right.getRows(); + + default: + UNREACHABLE(); + return false; + } +} + +// +// Establishes the type of the resultant operation, as well as +// makes the operator the correct one for the operands. +// +// Returns false if operator can't work on operands. +// +bool TIntermBinary::promote(TInfoSink& infoSink) +{ + // This function only handles scalars, vectors, and matrices. + if (left->isArray() || right->isArray()) + { + infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays"); + return false; + } + + // GLSL ES 2.0 does not support implicit type casting. + // So the basic type should always match. + if (left->getBasicType() != right->getBasicType()) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(left->getType()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + + // Binary operations results in temporary variables unless both + // operands are const. + if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) + { + getTypePointer()->setQualifier(EvqTemporary); + } + + const int nominalSize = std::max(left->getNominalSize(), right->getNominalSize()); + + // + // All scalars or structs. Code after this test assumes this case is removed! + // + if (nominalSize == 1) + { + switch (op) + { + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool, EbpUndefined)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + // Both operands must be of type bool. + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + { + return false; + } + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + break; + } + return true; + } + + // If we reach here, at least one of the operands is vector or matrix. + // The other operand could be a scalar, vector, or matrix. + // Can these two operands be combined? + // + TBasicType basicType = left->getBasicType(); + switch (op) + { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) + { + if (left->isVector()) + { + op = EOpVectorTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), 1)); + } + else + { + op = EOpMatrixTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), right->getRows())); + } + } + else if (left->isMatrix() && !right->isMatrix()) + { + if (right->isVector()) + { + op = EOpMatrixTimesVector; + setType(TType(basicType, higherPrecision, EvqTemporary, left->getRows(), 1)); + } + else + { + op = EOpMatrixTimesScalar; + } + } + else if (left->isMatrix() && right->isMatrix()) + { + op = EOpMatrixTimesMatrix; + setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), left->getRows())); + } + else if (!left->isMatrix() && !right->isMatrix()) + { + if (left->isVector() && right->isVector()) + { + // leave as component product + } + else if (left->isVector() || right->isVector()) + { + op = EOpVectorTimesScalar; + setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, 1)); + } + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); + return false; + } + + if (!validateMultiplication(op, left->getType(), right->getType())) + { + return false; + } + break; + + case EOpMulAssign: + if (!left->isMatrix() && right->isMatrix()) + { + if (left->isVector()) + { + op = EOpVectorTimesMatrixAssign; + } + else + { + return false; + } + } + else if (left->isMatrix() && !right->isMatrix()) + { + if (right->isVector()) + { + return false; + } + else + { + op = EOpMatrixTimesScalarAssign; + } + } + else if (left->isMatrix() && right->isMatrix()) + { + op = EOpMatrixTimesMatrixAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, right->getCols(), left->getRows())); + } + else if (!left->isMatrix() && !right->isMatrix()) + { + if (left->isVector() && right->isVector()) + { + // leave as component product + } + else if (left->isVector() || right->isVector()) + { + if (! left->isVector()) + return false; + op = EOpVectorTimesScalarAssign; + setType(TType(basicType, higherPrecision, EvqTemporary, left->getNominalSize(), 1)); + } + } + else + { + infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses"); + return false; + } + + if (!validateMultiplication(op, left->getType(), right->getType())) + { + return false; + } + break; + + case EOpAssign: + case EOpInitialize: + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + { + if ((left->isMatrix() && right->isVector()) || + (left->isVector() && right->isMatrix())) + return false; + + // Are the sizes compatible? + if (left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize()) + { + // If the nominal size of operands do not match: + // One of them must be scalar. + if (!left->isScalar() && !right->isScalar()) + return false; + + // Operator cannot be of type pure assignment. + if (op == EOpAssign || op == EOpInitialize) + return false; + } + + const int secondarySize = std::max(left->getSecondarySize(), right->getSecondarySize()); + + setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize)); + } + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((left->getNominalSize() != right->getNominalSize()) || + (left->getSecondarySize() != right->getSecondarySize())) + return false; + setType(TType(EbtBool, EbpUndefined)); + break; + + default: + return false; + } + + return true; +} + +bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + const TFieldList& fields = leftNodeType.getStruct()->fields(); + + size_t structSize = fields.size(); + size_t index = 0; + + for (size_t j = 0; j < structSize; j++) { + size_t size = fields[j]->type()->getObjectSize(); + for (size_t i = 0; i < size; i++) { + if (fields[j]->type()->getBasicType() == EbtStruct) { + if (!CompareStructure(*fields[j]->type(), &rightUnionArray[index], &leftUnionArray[index])) + return false; + } else { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + + } + } + return true; +} + +bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray) +{ + if (leftNodeType.isArray()) { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + size_t arraySize = leftNodeType.getArraySize(); + + for (size_t i = 0; i < arraySize; ++i) { + size_t offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + return false; + } + } else + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + + return true; +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// Returns the node to keep using, which may or may not be the node passed in. +// + +TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +{ + ConstantUnion *unionArray = getUnionArrayPointer(); + + if (!unionArray) + return 0; + + size_t objectSize = getType().getObjectSize(); + + if (constantNode) + { + // binary operations + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + TType returnType = getType(); + + if (!rightUnionArray) + return 0; + + // for a case like float f = 1.2 + vec4(2,3,4,5); + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) + { + rightUnionArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; ++i) + { + rightUnionArray[i] = *node->getUnionArrayPointer(); + } + returnType = getType(); + } + else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) + { + // for a case like float f = vec4(2,3,4,5) + 1.2; + unionArray = new ConstantUnion[constantNode->getType().getObjectSize()]; + for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i) + { + unionArray[i] = *getUnionArrayPointer(); + } + returnType = node->getType(); + objectSize = constantNode->getType().getObjectSize(); + } + + ConstantUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new ConstantUnion[objectSize]; + { + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + } + break; + case EOpSub: + tempConstArray = new ConstantUnion[objectSize]; + { + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + } + break; + + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new ConstantUnion[objectSize]; + { + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + } + break; + + case EOpMatrixTimesMatrix: + { + if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) + { + infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply"); + return 0; + } + + const int leftCols = getCols(); + const int leftRows = getRows(); + const int rightCols = constantNode->getType().getCols(); + const int rightRows = constantNode->getType().getRows(); + const int resultCols = rightCols; + const int resultRows = leftRows; + + tempConstArray = new ConstantUnion[resultCols*resultRows]; + for (int row = 0; row < resultRows; row++) + { + for (int column = 0; column < resultCols; column++) + { + tempConstArray[resultRows * column + row].setFConst(0.0f); + for (int i = 0; i < leftCols; i++) + { + tempConstArray[resultRows * column + row].setFConst(tempConstArray[resultRows * column + row].getFConst() + unionArray[i * leftRows + row].getFConst() * (rightUnionArray[column * rightRows + i].getFConst())); + } + } + } + + // update return type for matrix product + returnType.setPrimarySize(resultCols); + returnType.setSecondarySize(resultRows); + } + break; + + case EOpDiv: + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) + { + infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); + tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); + } + else + { + tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); + } + break; + + case EbtInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); + tempConstArray[i].setIConst(INT_MAX); + } + else + { + tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); + } + break; + + case EbtUInt: + if (rightUnionArray[i] == 0) + { + infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding"); + tempConstArray[i].setUConst(UINT_MAX); + } + else + { + tempConstArray[i].setUConst(unionArray[i].getUConst() / rightUnionArray[i].getUConst()); + } + break; + + default: + infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\""); + return 0; + } + } + } + break; + + case EOpMatrixTimesVector: + { + if (node->getBasicType() != EbtFloat) + { + infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector"); + return 0; + } + + const int matrixCols = getCols(); + const int matrixRows = getRows(); + + tempConstArray = new ConstantUnion[matrixRows]; + + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixRow].setFConst(0.0f); + for (int col = 0; col < matrixCols; col++) + { + tempConstArray[matrixRow].setFConst(tempConstArray[matrixRow].getFConst() + ((unionArray[col * matrixRows + matrixRow].getFConst()) * rightUnionArray[col].getFConst())); + } + } + + returnType = node->getType(); + returnType.setPrimarySize(matrixRows); + + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } + + case EOpVectorTimesMatrix: + { + if (getType().getBasicType() != EbtFloat) + { + infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix"); + return 0; + } + + const int matrixCols = constantNode->getType().getCols(); + const int matrixRows = constantNode->getType().getRows(); + + tempConstArray = new ConstantUnion[matrixCols]; + + for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++) + { + tempConstArray[matrixCol].setFConst(0.0f); + for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++) + { + tempConstArray[matrixCol].setFConst(tempConstArray[matrixCol].getFConst() + ((unionArray[matrixRow].getFConst()) * rightUnionArray[matrixCol * matrixRows + matrixRow].getFConst())); + } + } + + returnType.setPrimarySize(matrixCols); + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + } + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + } + break; + + case EOpLogicalXor: + { + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + switch (getType().getBasicType()) + { + case EbtBool: + tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); + break; + default: + UNREACHABLE(); + break; + } + } + } + break; + + case EOpLessThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + + case EOpGreaterThan: + assert(objectSize == 1); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + + case EOpLessThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + + case EOpGreaterThanEqual: + { + assert(objectSize == 1); + ConstantUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); + tempConstArray = new ConstantUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EbpUndefined, EvqConst); + break; + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) + { + if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } + else + { + for (size_t i = 0; i < objectSize; i++) + { + if (unionArray[i] != rightUnionArray[i]) + { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) + { + if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } + else + { + for (size_t i = 0; i < objectSize; i++) + { + if (unionArray[i] == rightUnionArray[i]) + { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new ConstantUnion[1]; + if (!boolNodeFlag) + { + tempConstArray->setBConst(true); + } + else + { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + default: + infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding"); + return 0; + } + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } + else + { + // + // Do unary operations + // + TIntermConstantUnion *newNode = 0; + ConstantUnion* tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + { + switch(op) + { + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; + case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; + case EbtUInt: tempConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break; + default: + infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); + return 0; + } + break; + + case EOpLogicalNot: // this code is written for possible future use, will not get executed currently + switch (getType().getBasicType()) + { + case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; + default: + infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); + return 0; + } + break; + + default: + return 0; + } + } + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; + } +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + size_t size = node->getType().getObjectSize(); + + ConstantUnion *leftUnionArray = new ConstantUnion[size]; + + for (size_t i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i))); + break; + case EbtUInt: + leftUnionArray[i].setFConst(static_cast<float>(node->getUConst(i))); + break; + case EbtBool: + leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i))); + break; + case EbtFloat: + leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i))); + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); + return 0; + } + break; + case EbtInt: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i))); + break; + case EbtUInt: + leftUnionArray[i].setIConst(static_cast<int>(node->getUConst(i))); + break; + case EbtBool: + leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i))); + break; + case EbtFloat: + leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i))); + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); + return 0; + } + break; + case EbtUInt: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getIConst(i))); + break; + case EbtUInt: + leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getUConst(i))); + break; + case EbtBool: + leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getBConst(i))); + break; + case EbtFloat: + leftUnionArray[i].setUConst(static_cast<unsigned int>(node->getFConst(i))); + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); + return 0; + } + break; + case EbtBool: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setBConst(node->getIConst(i) != 0); + break; + case EbtUInt: + leftUnionArray[i].setBConst(node->getUConst(i) != 0); + break; + case EbtBool: + leftUnionArray[i].setBConst(node->getBConst(i)); + break; + case EbtFloat: + leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f); + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote"); + return 0; + } + + break; + default: + infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found"); + return 0; + } + + } + + const TType& t = node->getType(); + + return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.getSecondarySize(), t.isArray()), node->getLine()); +} + +// static +TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction) +{ + if (hashFunction == NULL || name.empty()) + return name; + khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length()); + TStringStream stream; + stream << HASHED_NAME_PREFIX << std::hex << number; + TString hashedName = stream.str(); + return hashedName; +} diff --git a/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp b/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp new file mode 100644 index 00000000000..226f1b23807 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/LoopInfo.cpp @@ -0,0 +1,211 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/LoopInfo.h" + +namespace +{ + +int EvaluateIntConstant(TIntermConstantUnion *node) +{ + ASSERT(node && node->getUnionArrayPointer()); + return node->getIConst(0); +} + +int GetLoopIntIncrement(TIntermLoop *node) +{ + TIntermNode *expr = node->getExpression(); + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermConstantUnion *incrementNode = NULL; + if (unOp) + { + op = unOp->getOp(); + } + else if (binOp) + { + op = binOp->getOp(); + ASSERT(binOp->getRight()); + incrementNode = binOp->getRight()->getAsConstantUnion(); + ASSERT(incrementNode); + } + + int increment = 0; + // The operator is one of: ++ -- += -=. + switch (op) + { + case EOpPostIncrement: + case EOpPreIncrement: + ASSERT(unOp && !binOp); + increment = 1; + break; + case EOpPostDecrement: + case EOpPreDecrement: + ASSERT(unOp && !binOp); + increment = -1; + break; + case EOpAddAssign: + ASSERT(!unOp && binOp); + increment = EvaluateIntConstant(incrementNode); + break; + case EOpSubAssign: + ASSERT(!unOp && binOp); + increment = - EvaluateIntConstant(incrementNode); + break; + default: + UNREACHABLE(); + } + + return increment; +} + +} // namespace anonymous + +TLoopIndexInfo::TLoopIndexInfo() + : mId(-1), + mType(EbtVoid), + mInitValue(0), + mStopValue(0), + mIncrementValue(0), + mOp(EOpNull), + mCurrentValue(0) +{ +} + +void TLoopIndexInfo::fillInfo(TIntermLoop *node) +{ + if (node == NULL) + return; + + // Here we assume all the operations are valid, because the loop node is + // already validated in ValidateLimitations. + TIntermSequence &declSeq = + node->getInit()->getAsAggregate()->getSequence(); + TIntermBinary *declInit = declSeq[0]->getAsBinaryNode(); + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + + mId = symbol->getId(); + mType = symbol->getBasicType(); + + if (mType == EbtInt) + { + TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion(); + mInitValue = EvaluateIntConstant(initNode); + mCurrentValue = mInitValue; + mIncrementValue = GetLoopIntIncrement(node); + + TIntermBinary* binOp = node->getCondition()->getAsBinaryNode(); + mStopValue = EvaluateIntConstant( + binOp->getRight()->getAsConstantUnion()); + mOp = binOp->getOp(); + } +} + +bool TLoopIndexInfo::satisfiesLoopCondition() const +{ + // Relational operator is one of: > >= < <= == or !=. + switch (mOp) + { + case EOpEqual: + return (mCurrentValue == mStopValue); + case EOpNotEqual: + return (mCurrentValue != mStopValue); + case EOpLessThan: + return (mCurrentValue < mStopValue); + case EOpGreaterThan: + return (mCurrentValue > mStopValue); + case EOpLessThanEqual: + return (mCurrentValue <= mStopValue); + case EOpGreaterThanEqual: + return (mCurrentValue >= mStopValue); + default: + UNREACHABLE(); + return false; + } +} + +TLoopInfo::TLoopInfo() + : loop(NULL) +{ +} + +TLoopInfo::TLoopInfo(TIntermLoop *node) + : loop(node) +{ + index.fillInfo(node); +} + +TIntermLoop *TLoopStack::findLoop(TIntermSymbol *symbol) +{ + if (!symbol) + return NULL; + for (iterator iter = begin(); iter != end(); ++iter) + { + if (iter->index.getId() == symbol->getId()) + return iter->loop; + } + return NULL; +} + +TLoopIndexInfo *TLoopStack::getIndexInfo(TIntermSymbol *symbol) +{ + if (!symbol) + return NULL; + for (iterator iter = begin(); iter != end(); ++iter) + { + if (iter->index.getId() == symbol->getId()) + return &(iter->index); + } + return NULL; +} + +void TLoopStack::step() +{ + ASSERT(!empty()); + rbegin()->index.step(); +} + +bool TLoopStack::satisfiesLoopCondition() +{ + ASSERT(!empty()); + return rbegin()->index.satisfiesLoopCondition(); +} + +bool TLoopStack::needsToReplaceSymbolWithValue(TIntermSymbol *symbol) +{ + TIntermLoop *loop = findLoop(symbol); + return loop && loop->getUnrollFlag(); +} + +int TLoopStack::getLoopIndexValue(TIntermSymbol *symbol) +{ + TLoopIndexInfo *info = getIndexInfo(symbol); + ASSERT(info); + return info->getCurrentValue(); +} + +void TLoopStack::push(TIntermLoop *loop) +{ + TLoopInfo info(loop); + push_back(info); +} + +void TLoopStack::pop() +{ + pop_back(); +} + diff --git a/chromium/third_party/angle/src/compiler/translator/LoopInfo.h b/chromium/third_party/angle/src/compiler/translator/LoopInfo.h new file mode 100644 index 00000000000..5a140c339e9 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/LoopInfo.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATOR_LOOP_INFO_H_ +#define COMPILER_TRANSLATOR_LOOP_INFO_H_ + +#include "compiler/translator/intermediate.h" + +class TLoopIndexInfo +{ + public: + TLoopIndexInfo(); + + // If type is EbtInt, fill all fields of the structure with info + // extracted from a loop node. + // If type is not EbtInt, only fill id and type. + void fillInfo(TIntermLoop *node); + + int getId() const { return mId; } + void setId(int id) { mId = id; } + TBasicType getType() const { return mType; } + void setType(TBasicType type) { mType = type; } + int getCurrentValue() const { return mCurrentValue; } + + void step() { mCurrentValue += mIncrementValue; } + + // Check if the current value satisfies the loop condition. + bool satisfiesLoopCondition() const; + + private: + int mId; + TBasicType mType; // Either EbtInt or EbtFloat + + // Below fields are only valid if the index's type is int. + int mInitValue; + int mStopValue; + int mIncrementValue; + TOperator mOp; + int mCurrentValue; +}; + +struct TLoopInfo +{ + TLoopIndexInfo index; + TIntermLoop *loop; + + TLoopInfo(); + TLoopInfo(TIntermLoop *node); +}; + +class TLoopStack : public TVector<TLoopInfo> +{ + public: + // Search loop stack for a loop whose index matches the input symbol. + TIntermLoop *findLoop(TIntermSymbol *symbol); + + // Find the loop index info in the loop stack by the input symbol. + TLoopIndexInfo *getIndexInfo(TIntermSymbol *symbol); + + // Update the currentValue for the next loop iteration. + void step(); + + // Return false if loop condition is no longer satisfied. + bool satisfiesLoopCondition(); + + // Check if the symbol is the index of a loop that's unrolled. + bool needsToReplaceSymbolWithValue(TIntermSymbol *symbol); + + // Return the current value of a given loop index symbol. + int getLoopIndexValue(TIntermSymbol *symbol); + + void push(TIntermLoop *info); + void pop(); +}; + +#endif // COMPILER_TRANSLATOR_LOOP_INDEX_H_ + diff --git a/chromium/third_party/angle/src/compiler/translator/MMap.h b/chromium/third_party/angle/src/compiler/translator/MMap.h new file mode 100644 index 00000000000..a308671514c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/MMap.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _MMAP_INCLUDED_ +#define _MMAP_INCLUDED_ + +// +// Encapsulate memory mapped files +// + +class TMMap { +public: + TMMap(const char* fileName) : + fSize(-1), // -1 is the error value returned by GetFileSize() + fp(NULL), + fBuff(0) // 0 is the error value returned by MapViewOfFile() + { + if ((fp = fopen(fileName, "r")) == NULL) + return; + char c = getc(fp); + fSize = 0; + while (c != EOF) { + fSize++; + c = getc(fp); + } + if (c == EOF) + fSize++; + rewind(fp); + fBuff = (char*)malloc(sizeof(char) * fSize); + int count = 0; + c = getc(fp); + while (c != EOF) { + fBuff[count++] = c; + c = getc(fp); + } + fBuff[count++] = c; + } + + char* getData() { return fBuff; } + int getSize() { return fSize; } + + ~TMMap() { + if (fp != NULL) + fclose(fp); + } + +private: + int fSize; // size of file to map in + FILE *fp; + char* fBuff; // the actual data; +}; + +#endif // _MMAP_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/NodeSearch.h b/chromium/third_party/angle/src/compiler/translator/NodeSearch.h new file mode 100644 index 00000000000..b58c7ec6894 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/NodeSearch.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// NodeSearch.h: Utilities for searching translator node graphs +// + +#ifndef TRANSLATOR_NODESEARCH_H_ +#define TRANSLATOR_NODESEARCH_H_ + +#include "compiler/translator/intermediate.h" + +namespace sh +{ + +template <class Parent> +class NodeSearchTraverser : public TIntermTraverser +{ + public: + NodeSearchTraverser() + : mFound(false) + {} + + bool found() const { return mFound; } + + static bool search(TIntermNode *node) + { + Parent searchTraverser; + node->traverse(&searchTraverser); + return searchTraverser.found(); + } + + protected: + bool mFound; +}; + +class FindDiscard : public NodeSearchTraverser<FindDiscard> +{ + public: + virtual bool visitBranch(Visit visit, TIntermBranch *node) + { + switch (node->getFlowOp()) + { + case EOpKill: + mFound = true; + break; + + default: break; + } + + return !mFound; + } +}; + +class FindSideEffectRewriting : public NodeSearchTraverser<FindSideEffectRewriting> +{ + public: + virtual bool visitBinary(Visit visit, TIntermBinary *node) + { + switch (node->getOp()) + { + case EOpLogicalOr: + case EOpLogicalAnd: + if (node->getRight()->hasSideEffects()) + { + mFound = true; + } + break; + + default: break; + } + + return !mFound; + } +}; + +} + +#endif // TRANSLATOR_NODESEARCH_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp new file mode 100644 index 00000000000..65635af1fff --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputESSL.cpp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/OutputESSL.h" + +TOutputESSL::TOutputESSL(TInfoSinkBase& objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap& nameMap, + TSymbolTable& symbolTable, + int shaderVersion) + : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) +{ +} + +bool TOutputESSL::writeVariablePrecision(TPrecision precision) +{ + if (precision == EbpUndefined) + return false; + + TInfoSinkBase& out = objSink(); + out << getPrecisionString(precision); + return true; +} diff --git a/chromium/third_party/angle/src/compiler/translator/OutputESSL.h b/chromium/third_party/angle/src/compiler/translator/OutputESSL.h new file mode 100644 index 00000000000..8a567fb8aa2 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputESSL.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#define CROSSCOMPILERGLSL_OUTPUTESSL_H_ + +#include "compiler/translator/OutputGLSLBase.h" + +class TOutputESSL : public TOutputGLSLBase +{ +public: + TOutputESSL(TInfoSinkBase& objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap& nameMap, + TSymbolTable& symbolTable, + int shaderVersion); + +protected: + virtual bool writeVariablePrecision(TPrecision precision); +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp new file mode 100644 index 00000000000..eb7cbb4ae86 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/OutputGLSL.h" + +TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap& nameMap, + TSymbolTable& symbolTable, + int shaderVersion) + : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) +{ +} + +bool TOutputGLSL::writeVariablePrecision(TPrecision) +{ + return false; +} + +void TOutputGLSL::visitSymbol(TIntermSymbol* node) +{ + TInfoSinkBase& out = objSink(); + + if (node->getSymbol() == "gl_FragDepthEXT") + { + out << "gl_FragDepth"; + } + else + { + TOutputGLSLBase::visitSymbol(node); + } +} + +TString TOutputGLSL::translateTextureFunction(TString& name) +{ + static const char *simpleRename[] = { + "texture2DLodEXT", "texture2DLod", + "texture2DProjLodEXT", "texture2DProjLod", + "textureCubeLodEXT", "textureCubeLod", + "texture2DGradEXT", "texture2DGradARB", + "texture2DProjGradEXT", "texture2DProjGradARB", + "textureCubeGradEXT", "textureCubeGradARB", + NULL, NULL + }; + + for (int i = 0; simpleRename[i] != NULL; i += 2) { + if (name == simpleRename[i]) { + return simpleRename[i+1]; + } + } + + return name; +} diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h new file mode 100644 index 00000000000..bceebe397d7 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSL.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_ + +#include "compiler/translator/OutputGLSLBase.h" + +class TOutputGLSL : public TOutputGLSLBase +{ +public: + TOutputGLSL(TInfoSinkBase& objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap& nameMap, + TSymbolTable& symbolTable, + int shaderVersion); + +protected: + virtual bool writeVariablePrecision(TPrecision); + virtual void visitSymbol(TIntermSymbol* node); + virtual TString translateTextureFunction(TString& name); +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp new file mode 100644 index 00000000000..6995594e760 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -0,0 +1,1080 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/OutputGLSLBase.h" +#include "compiler/translator/compilerdebug.h" + +#include <cfloat> + +namespace +{ +TString arrayBrackets(const TType &type) +{ + ASSERT(type.isArray()); + TInfoSinkBase out; + out << "[" << type.getArraySize() << "]"; + return TString(out.c_str()); +} + +bool isSingleStatement(TIntermNode *node) +{ + if (const TIntermAggregate *aggregate = node->getAsAggregate()) + { + return (aggregate->getOp() != EOpFunction) && + (aggregate->getOp() != EOpSequence); + } + else if (const TIntermSelection *selection = node->getAsSelectionNode()) + { + // Ternary operators are usually part of an assignment operator. + // This handles those rare cases in which they are all by themselves. + return selection->usesTernaryOperator(); + } + else if (node->getAsLoopNode()) + { + return false; + } + return true; +} +} // namespace + +TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable &symbolTable, + int shaderVersion) + : TIntermTraverser(true, true, true), + mObjSink(objSink), + mDeclaringVariables(false), + mClampingStrategy(clampingStrategy), + mHashFunction(hashFunction), + mNameMap(nameMap), + mSymbolTable(symbolTable), + mShaderVersion(shaderVersion) +{ + // Set up global scope. + mDeclaredStructs.push_back(ScopedDeclaredStructs()); +} + +void TOutputGLSLBase::writeTriplet( + Visit visit, const char *preStr, const char *inStr, const char *postStr) +{ + TInfoSinkBase &out = objSink(); + if (visit == PreVisit && preStr) + out << preStr; + else if (visit == InVisit && inStr) + out << inStr; + else if (visit == PostVisit && postStr) + out << postStr; +} + +void TOutputGLSLBase::writeBuiltInFunctionTriplet( + Visit visit, const char *preStr, bool useEmulatedFunction) +{ + TString preString = useEmulatedFunction ? + BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr; + writeTriplet(visit, preString.c_str(), ", ", ")"); +} + +void TOutputGLSLBase::writeVariableType(const TType &type) +{ + TInfoSinkBase &out = objSink(); + TQualifier qualifier = type.getQualifier(); + // TODO(alokp): Validate qualifier for variable declarations. + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + out << type.getQualifierString() << " "; + // Declare the struct if we have not done so already. + if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) + { + declareStruct(type.getStruct()); + mDeclaredStructs[mDeclaredStructs.size() - 1].push_back(type.getStruct()); + } + else + { + if (writeVariablePrecision(type.getPrecision())) + out << " "; + out << getTypeName(type); + } +} + +void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args) +{ + TInfoSinkBase &out = objSink(); + for (TIntermSequence::const_iterator iter = args.begin(); + iter != args.end(); ++iter) + { + const TIntermSymbol *arg = (*iter)->getAsSymbolNode(); + ASSERT(arg != NULL); + + const TType &type = arg->getType(); + writeVariableType(type); + + const TString &name = arg->getSymbol(); + if (!name.empty()) + out << " " << hashName(name); + if (type.isArray()) + out << arrayBrackets(type); + + // Put a comma if this is not the last argument. + if (iter != args.end() - 1) + out << ", "; + } +} + +const ConstantUnion *TOutputGLSLBase::writeConstantUnion( + const TType &type, const ConstantUnion *pConstUnion) +{ + TInfoSinkBase &out = objSink(); + + if (type.getBasicType() == EbtStruct) + { + const TStructure *structure = type.getStruct(); + out << hashName(structure->name()) << "("; + + const TFieldList &fields = structure->fields(); + for (size_t i = 0; i < fields.size(); ++i) + { + const TType *fieldType = fields[i]->type(); + ASSERT(fieldType != NULL); + pConstUnion = writeConstantUnion(*fieldType, pConstUnion); + if (i != fields.size() - 1) + out << ", "; + } + out << ")"; + } + else + { + size_t size = type.getObjectSize(); + bool writeType = size > 1; + if (writeType) + out << getTypeName(type) << "("; + for (size_t i = 0; i < size; ++i, ++pConstUnion) + { + switch (pConstUnion->getType()) + { + case EbtFloat: + out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); + break; + case EbtInt: + out << pConstUnion->getIConst(); + break; + case EbtBool: + out << pConstUnion->getBConst(); + break; + default: UNREACHABLE(); + } + if (i != size - 1) + out << ", "; + } + if (writeType) + out << ")"; + } + return pConstUnion; +} + +void TOutputGLSLBase::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = objSink(); + if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node)) + out << mLoopUnrollStack.getLoopIndexValue(node); + else + out << hashVariableName(node->getSymbol()); + + if (mDeclaringVariables && node->getType().isArray()) + out << arrayBrackets(node->getType()); +} + +void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) +{ + writeConstantUnion(node->getType(), node->getUnionArrayPointer()); +} + +bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) +{ + bool visitChildren = true; + TInfoSinkBase &out = objSink(); + switch (node->getOp()) + { + case EOpInitialize: + if (visit == InVisit) + { + out << " = "; + // RHS of initialize is not being declared. + mDeclaringVariables = false; + } + break; + case EOpAssign: + writeTriplet(visit, "(", " = ", ")"); + break; + case EOpAddAssign: + writeTriplet(visit, "(", " += ", ")"); + break; + case EOpSubAssign: + writeTriplet(visit, "(", " -= ", ")"); + break; + case EOpDivAssign: + writeTriplet(visit, "(", " /= ", ")"); + break; + // Notice the fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + writeTriplet(visit, "(", " *= ", ")"); + break; + + case EOpIndexDirect: + writeTriplet(visit, NULL, "[", "]"); + break; + case EOpIndexIndirect: + if (node->getAddIndexClamp()) + { + if (visit == InVisit) + { + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "[int(clamp(float("; + else + out << "[webgl_int_clamp("; + } + else if (visit == PostVisit) + { + int maxSize; + TIntermTyped *left = node->getLeft(); + TType leftType = left->getType(); + + if (left->isArray()) + { + // The shader will fail validation if the array length is not > 0. + maxSize = leftType.getArraySize() - 1; + } + else + { + maxSize = leftType.getNominalSize() - 1; + } + + if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) + out << "), 0.0, float(" << maxSize << ")))]"; + else + out << ", 0, " << maxSize << ")]"; + } + } + else + { + writeTriplet(visit, NULL, "[", "]"); + } + break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + // Here we are writing out "foo.bar", where "foo" is struct + // and "bar" is field. In AST, it is represented as a binary + // node, where left child represents "foo" and right child "bar". + // The node itself represents ".". The struct field "bar" is + // actually stored as an index into TStructure::fields. + out << "."; + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion(); + const TField *field = structure->fields()[index->getIConst(0)]; + + TString fieldName = field->name(); + if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion)) + fieldName = hashName(fieldName); + + out << fieldName; + visitChildren = false; + } + break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); + TIntermSequence &sequence = rightChild->getSequence(); + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit) + { + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + ASSERT(element->getBasicType() == EbtInt); + ASSERT(element->getNominalSize() == 1); + const ConstantUnion& data = element->getUnionArrayPointer()[0]; + ASSERT(data.getType() == EbtInt); + switch (data.getIConst()) + { + case 0: + out << "x"; + break; + case 1: + out << "y"; + break; + case 2: + out << "z"; + break; + case 3: + out << "w"; + break; + default: + UNREACHABLE(); + } + } + visitChildren = false; + } + break; + + case EOpAdd: + writeTriplet(visit, "(", " + ", ")"); + break; + case EOpSub: + writeTriplet(visit, "(", " - ", ")"); + break; + case EOpMul: + writeTriplet(visit, "(", " * ", ")"); + break; + case EOpDiv: + writeTriplet(visit, "(", " / ", ")"); + break; + case EOpMod: + UNIMPLEMENTED(); + break; + case EOpEqual: + writeTriplet(visit, "(", " == ", ")"); + break; + case EOpNotEqual: + writeTriplet(visit, "(", " != ", ")"); + break; + case EOpLessThan: + writeTriplet(visit, "(", " < ", ")"); + break; + case EOpGreaterThan: + writeTriplet(visit, "(", " > ", ")"); + break; + case EOpLessThanEqual: + writeTriplet(visit, "(", " <= ", ")"); + break; + case EOpGreaterThanEqual: + writeTriplet(visit, "(", " >= ", ")"); + break; + + // Notice the fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + writeTriplet(visit, "(", " * ", ")"); + break; + + case EOpLogicalOr: + writeTriplet(visit, "(", " || ", ")"); + break; + case EOpLogicalXor: + writeTriplet(visit, "(", " ^^ ", ")"); + break; + case EOpLogicalAnd: + writeTriplet(visit, "(", " && ", ")"); + break; + default: + UNREACHABLE(); + } + + return visitChildren; +} + +bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) +{ + TString preString; + TString postString = ")"; + + switch (node->getOp()) + { + case EOpNegative: preString = "(-"; break; + case EOpVectorLogicalNot: preString = "not("; break; + case EOpLogicalNot: preString = "(!"; break; + + case EOpPostIncrement: preString = "("; postString = "++)"; break; + case EOpPostDecrement: preString = "("; postString = "--)"; break; + case EOpPreIncrement: preString = "(++"; break; + case EOpPreDecrement: preString = "(--"; break; + + case EOpConvIntToBool: + case EOpConvFloatToBool: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: + preString = "bool("; + break; + case 2: + preString = "bvec2("; + break; + case 3: + preString = "bvec3("; + break; + case 4: + preString = "bvec4("; + break; + default: + UNREACHABLE(); + } + break; + case EOpConvBoolToFloat: + case EOpConvIntToFloat: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: + preString = "float("; + break; + case 2: + preString = "vec2("; + break; + case 3: + preString = "vec3("; + break; + case 4: + preString = "vec4("; + break; + default: + UNREACHABLE(); + } + break; + case EOpConvFloatToInt: + case EOpConvBoolToInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: + preString = "int("; + break; + case 2: + preString = "ivec2("; + break; + case 3: + preString = "ivec3("; + break; + case 4: + preString = "ivec4("; + break; + default: + UNREACHABLE(); + } + break; + + case EOpRadians: + preString = "radians("; + break; + case EOpDegrees: + preString = "degrees("; + break; + case EOpSin: + preString = "sin("; + break; + case EOpCos: + preString = "cos("; + break; + case EOpTan: + preString = "tan("; + break; + case EOpAsin: + preString = "asin("; + break; + case EOpAcos: + preString = "acos("; + break; + case EOpAtan: + preString = "atan("; + break; + + case EOpExp: + preString = "exp("; + break; + case EOpLog: + preString = "log("; + break; + case EOpExp2: + preString = "exp2("; + break; + case EOpLog2: + preString = "log2("; + break; + case EOpSqrt: + preString = "sqrt("; + break; + case EOpInverseSqrt: + preString = "inversesqrt("; + break; + + case EOpAbs: + preString = "abs("; + break; + case EOpSign: + preString = "sign("; + break; + case EOpFloor: + preString = "floor("; + break; + case EOpCeil: + preString = "ceil("; + break; + case EOpFract: + preString = "fract("; + break; + + case EOpLength: + preString = "length("; + break; + case EOpNormalize: + preString = "normalize("; + break; + + case EOpDFdx: + preString = "dFdx("; + break; + case EOpDFdy: + preString = "dFdy("; + break; + case EOpFwidth: + preString = "fwidth("; + break; + + case EOpAny: + preString = "any("; + break; + case EOpAll: + preString = "all("; + break; + + default: + UNREACHABLE(); + } + + if (visit == PreVisit && node->getUseEmulatedFunction()) + preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString); + writeTriplet(visit, preString.c_str(), NULL, postString.c_str()); + + return true; +} + +bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = objSink(); + + if (node->usesTernaryOperator()) + { + // Notice two brackets at the beginning and end. The outer ones + // encapsulate the whole ternary expression. This preserves the + // order of precedence when ternary expressions are used in a + // compound expression, i.e., c = 2 * (a < b ? 1 : 2). + out << "(("; + node->getCondition()->traverse(this); + out << ") ? ("; + node->getTrueBlock()->traverse(this); + out << ") : ("; + node->getFalseBlock()->traverse(this); + out << "))"; + } + else + { + out << "if ("; + node->getCondition()->traverse(this); + out << ")\n"; + + incrementDepth(node); + visitCodeBlock(node->getTrueBlock()); + + if (node->getFalseBlock()) + { + out << "else\n"; + visitCodeBlock(node->getFalseBlock()); + } + decrementDepth(); + } + return false; +} + +bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) +{ + bool visitChildren = true; + TInfoSinkBase &out = objSink(); + TString preString; + bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction()); + switch (node->getOp()) + { + case EOpSequence: + // Scope the sequences except when at the global scope. + if (depth > 0) + { + out << "{\n"; + pushDeclaredStructsScope(); + } + + incrementDepth(node); + for (TIntermSequence::const_iterator iter = node->getSequence().begin(); + iter != node->getSequence().end(); ++iter) + { + TIntermNode *node = *iter; + ASSERT(node != NULL); + node->traverse(this); + + if (isSingleStatement(node)) + out << ";\n"; + } + decrementDepth(); + + // Scope the sequences except when at the global scope. + if (depth > 0) + { + popDeclaredStructsScope(); + out << "}\n"; + } + visitChildren = false; + break; + case EOpPrototype: + // Function declaration. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << hashName(node->getName()); + + out << "("; + writeFunctionParameters(node->getSequence()); + out << ")"; + + visitChildren = false; + break; + case EOpFunction: { + // Function definition. + ASSERT(visit == PreVisit); + writeVariableType(node->getType()); + out << " " << hashFunctionName(node->getName()); + + incrementDepth(node); + // Function definition node contains one or two children nodes + // representing function parameters and function body. The latter + // is not present in case of empty function bodies. + const TIntermSequence &sequence = node->getSequence(); + ASSERT((sequence.size() == 1) || (sequence.size() == 2)); + TIntermSequence::const_iterator seqIter = sequence.begin(); + + // Traverse function parameters. + TIntermAggregate *params = (*seqIter)->getAsAggregate(); + ASSERT(params != NULL); + ASSERT(params->getOp() == EOpParameters); + params->traverse(this); + + // Traverse function body. + TIntermAggregate *body = ++seqIter != sequence.end() ? + (*seqIter)->getAsAggregate() : NULL; + visitCodeBlock(body); + decrementDepth(); + + // Fully processed; no need to visit children. + visitChildren = false; + break; + } + case EOpFunctionCall: + // Function call. + if (visit == PreVisit) + out << hashFunctionName(node->getName()) << "("; + else if (visit == InVisit) + out << ", "; + else + out << ")"; + break; + case EOpParameters: + // Function parameters. + ASSERT(visit == PreVisit); + out << "("; + writeFunctionParameters(node->getSequence()); + out << ")"; + visitChildren = false; + break; + case EOpDeclaration: + // Variable declaration. + if (visit == PreVisit) + { + const TIntermSequence &sequence = node->getSequence(); + const TIntermTyped *variable = sequence.front()->getAsTyped(); + writeVariableType(variable->getType()); + out << " "; + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + out << ", "; + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + break; + case EOpConstructFloat: + writeTriplet(visit, "float(", NULL, ")"); + break; + case EOpConstructVec2: + writeBuiltInFunctionTriplet(visit, "vec2(", false); + break; + case EOpConstructVec3: + writeBuiltInFunctionTriplet(visit, "vec3(", false); + break; + case EOpConstructVec4: + writeBuiltInFunctionTriplet(visit, "vec4(", false); + break; + case EOpConstructBool: + writeTriplet(visit, "bool(", NULL, ")"); + break; + case EOpConstructBVec2: + writeBuiltInFunctionTriplet(visit, "bvec2(", false); + break; + case EOpConstructBVec3: + writeBuiltInFunctionTriplet(visit, "bvec3(", false); + break; + case EOpConstructBVec4: + writeBuiltInFunctionTriplet(visit, "bvec4(", false); + break; + case EOpConstructInt: + writeTriplet(visit, "int(", NULL, ")"); + break; + case EOpConstructIVec2: + writeBuiltInFunctionTriplet(visit, "ivec2(", false); + break; + case EOpConstructIVec3: + writeBuiltInFunctionTriplet(visit, "ivec3(", false); + break; + case EOpConstructIVec4: + writeBuiltInFunctionTriplet(visit, "ivec4(", false); + break; + case EOpConstructMat2: + writeBuiltInFunctionTriplet(visit, "mat2(", false); + break; + case EOpConstructMat3: + writeBuiltInFunctionTriplet(visit, "mat3(", false); + break; + case EOpConstructMat4: + writeBuiltInFunctionTriplet(visit, "mat4(", false); + break; + case EOpConstructStruct: + if (visit == PreVisit) + { + const TType &type = node->getType(); + ASSERT(type.getBasicType() == EbtStruct); + out << hashName(type.getStruct()->name()) << "("; + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + break; + + case EOpLessThan: + writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); + break; + case EOpGreaterThan: + writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction); + break; + case EOpLessThanEqual: + writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction); + break; + case EOpGreaterThanEqual: + writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction); + break; + case EOpVectorEqual: + writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction); + break; + case EOpVectorNotEqual: + writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction); + break; + case EOpComma: + writeTriplet(visit, NULL, ", ", NULL); + break; + + case EOpMod: + writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); + break; + case EOpPow: + writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); + break; + case EOpAtan: + writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction); + break; + case EOpMin: + writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction); + break; + case EOpMax: + writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction); + break; + case EOpClamp: + writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction); + break; + case EOpMix: + writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction); + break; + case EOpStep: + writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction); + break; + case EOpSmoothStep: + writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction); + break; + case EOpDistance: + writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction); + break; + case EOpDot: + writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction); + break; + case EOpCross: + writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction); + break; + case EOpFaceForward: + writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction); + break; + case EOpReflect: + writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction); + break; + case EOpRefract: + writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction); + break; + case EOpMul: + writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction); + break; + + default: + UNREACHABLE(); + } + return visitChildren; +} + +bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node) +{ + TInfoSinkBase &out = objSink(); + + incrementDepth(node); + // Loop header. + TLoopType loopType = node->getType(); + if (loopType == ELoopFor) // for loop + { + if (!node->getUnrollFlag()) + { + out << "for ("; + if (node->getInit()) + node->getInit()->traverse(this); + out << "; "; + + if (node->getCondition()) + node->getCondition()->traverse(this); + out << "; "; + + if (node->getExpression()) + node->getExpression()->traverse(this); + out << ")\n"; + } + else + { + // Need to put a one-iteration loop here to handle break. + TIntermSequence &declSeq = + node->getInit()->getAsAggregate()->getSequence(); + TIntermSymbol *indexSymbol = + declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode(); + TString name = hashVariableName(indexSymbol->getSymbol()); + out << "for (int " << name << " = 0; " + << name << " < 1; " + << "++" << name << ")\n"; + } + } + else if (loopType == ELoopWhile) // while loop + { + out << "while ("; + ASSERT(node->getCondition() != NULL); + node->getCondition()->traverse(this); + out << ")\n"; + } + else // do-while loop + { + ASSERT(loopType == ELoopDoWhile); + out << "do\n"; + } + + // Loop body. + if (node->getUnrollFlag()) + { + out << "{\n"; + mLoopUnrollStack.push(node); + while (mLoopUnrollStack.satisfiesLoopCondition()) + { + visitCodeBlock(node->getBody()); + mLoopUnrollStack.step(); + } + mLoopUnrollStack.pop(); + out << "}\n"; + } + else + { + visitCodeBlock(node->getBody()); + } + + // Loop footer. + if (loopType == ELoopDoWhile) // do-while loop + { + out << "while ("; + ASSERT(node->getCondition() != NULL); + node->getCondition()->traverse(this); + out << ");\n"; + } + decrementDepth(); + + // No need to visit children. They have been already processed in + // this function. + return false; +} + +bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node) +{ + switch (node->getFlowOp()) + { + case EOpKill: + writeTriplet(visit, "discard", NULL, NULL); + break; + case EOpBreak: + writeTriplet(visit, "break", NULL, NULL); + break; + case EOpContinue: + writeTriplet(visit, "continue", NULL, NULL); + break; + case EOpReturn: + writeTriplet(visit, "return ", NULL, NULL); + break; + default: + UNREACHABLE(); + } + + return true; +} + +void TOutputGLSLBase::visitCodeBlock(TIntermNode *node) +{ + TInfoSinkBase &out = objSink(); + if (node != NULL) + { + node->traverse(this); + // Single statements not part of a sequence need to be terminated + // with semi-colon. + if (isSingleStatement(node)) + out << ";\n"; + } + else + { + out << "{\n}\n"; // Empty code block. + } +} + +TString TOutputGLSLBase::getTypeName(const TType &type) +{ + TInfoSinkBase out; + if (type.isMatrix()) + { + out << "mat"; + out << type.getNominalSize(); + } + else if (type.isVector()) + { + switch (type.getBasicType()) + { + case EbtFloat: + out << "vec"; + break; + case EbtInt: + out << "ivec"; + break; + case EbtBool: + out << "bvec"; + break; + default: + UNREACHABLE(); + } + out << type.getNominalSize(); + } + else + { + if (type.getBasicType() == EbtStruct) + out << hashName(type.getStruct()->name()); + else + out << type.getBasicString(); + } + return TString(out.c_str()); +} + +TString TOutputGLSLBase::hashName(const TString &name) +{ + if (mHashFunction == NULL || name.empty()) + return name; + NameMap::const_iterator it = mNameMap.find(name.c_str()); + if (it != mNameMap.end()) + return it->second.c_str(); + TString hashedName = TIntermTraverser::hash(name, mHashFunction); + mNameMap[name.c_str()] = hashedName.c_str(); + return hashedName; +} + +TString TOutputGLSLBase::hashVariableName(const TString &name) +{ + if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL) + return name; + return hashName(name); +} + +TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name) +{ + TString name = TFunction::unmangleName(mangled_name); + if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main") + return translateTextureFunction(name); + return hashName(name); +} + +bool TOutputGLSLBase::structDeclared(const TStructure *structure) const +{ + ASSERT(structure); + ASSERT(mDeclaredStructs.size() > 0); + for (size_t ii = mDeclaredStructs.size(); ii > 0; --ii) + { + const ScopedDeclaredStructs &scope = mDeclaredStructs[ii - 1]; + for (size_t jj = 0; jj < scope.size(); ++jj) + { + if (scope[jj]->equals(*structure)) + return true; + } + } + return false; +} + +void TOutputGLSLBase::declareStruct(const TStructure *structure) +{ + TInfoSinkBase &out = objSink(); + + out << "struct " << hashName(structure->name()) << "{\n"; + const TFieldList &fields = structure->fields(); + for (size_t i = 0; i < fields.size(); ++i) + { + const TField *field = fields[i]; + if (writeVariablePrecision(field->type()->getPrecision())) + out << " "; + out << getTypeName(*field->type()) << " " << hashName(field->name()); + if (field->type()->isArray()) + out << arrayBrackets(*field->type()); + out << ";\n"; + } + out << "}"; +} + +void TOutputGLSLBase::pushDeclaredStructsScope() +{ + mDeclaredStructs.push_back(ScopedDeclaredStructs()); +} + +void TOutputGLSLBase::popDeclaredStructsScope() +{ + // We should never pop the global scope. + ASSERT(mDeclaredStructs.size() >= 2); + mDeclaredStructs.pop_back(); +} diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h new file mode 100644 index 00000000000..ae40f85e0d5 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ + +#include <vector> + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/LoopInfo.h" +#include "compiler/translator/ParseContext.h" + +class TOutputGLSLBase : public TIntermTraverser +{ + public: + TOutputGLSLBase(TInfoSinkBase &objSink, + ShArrayIndexClampingStrategy clampingStrategy, + ShHashFunction64 hashFunction, + NameMap &nameMap, + TSymbolTable& symbolTable, + int shaderVersion); + + protected: + TInfoSinkBase &objSink() { return mObjSink; } + void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr); + void writeVariableType(const TType &type); + virtual bool writeVariablePrecision(TPrecision precision) = 0; + void writeFunctionParameters(const TIntermSequence &args); + const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *pConstUnion); + TString getTypeName(const TType &type); + + virtual void visitSymbol(TIntermSymbol *node); + virtual void visitConstantUnion(TIntermConstantUnion *node); + virtual bool visitBinary(Visit visit, TIntermBinary *node); + virtual bool visitUnary(Visit visit, TIntermUnary *node); + virtual bool visitSelection(Visit visit, TIntermSelection *node); + virtual bool visitAggregate(Visit visit, TIntermAggregate *node); + virtual bool visitLoop(Visit visit, TIntermLoop *node); + virtual bool visitBranch(Visit visit, TIntermBranch *node); + + void visitCodeBlock(TIntermNode *node); + + // Return the original name if hash function pointer is NULL; + // otherwise return the hashed name. + TString hashName(const TString &name); + // Same as hashName(), but without hashing built-in variables. + TString hashVariableName(const TString &name); + // Same as hashName(), but without hashing built-in functions. + TString hashFunctionName(const TString &mangled_name); + // Used to translate function names for differences between ESSL and GLSL + virtual TString translateTextureFunction(TString &name) { return name; } + + private: + bool structDeclared(const TStructure *structure) const; + void declareStruct(const TStructure *structure); + void pushDeclaredStructsScope(); + void popDeclaredStructsScope(); + + void writeBuiltInFunctionTriplet(Visit visit, const char *preStr, bool useEmulatedFunction); + + TInfoSinkBase &mObjSink; + bool mDeclaringVariables; + + // Structs are declared as the tree is traversed. This list contains all + // the structs already declared within a scope. It is maintained so that + // a struct is declared only once within a scope. + typedef std::vector<TStructure *> ScopedDeclaredStructs; + // This vector contains all the structs from the global scope to the + // current scope. When the traverser exits a scope, the scope is discarded. + typedef std::vector<ScopedDeclaredStructs> DeclaredStructs; + DeclaredStructs mDeclaredStructs; + + // Stack of loops that need to be unrolled. + TLoopStack mLoopUnrollStack; + + ShArrayIndexClampingStrategy mClampingStrategy; + + // name hashing. + ShHashFunction64 mHashFunction; + + NameMap &mNameMap; + + TSymbolTable &mSymbolTable; + + const int mShaderVersion; +}; + +#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp new file mode 100644 index 00000000000..5520c861b4d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp @@ -0,0 +1,4184 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/OutputHLSL.h" + +#include "common/angleutils.h" +#include "common/utilities.h" +#include "common/blocklayout.h" +#include "compiler/translator/compilerdebug.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/DetectDiscontinuity.h" +#include "compiler/translator/SearchSymbol.h" +#include "compiler/translator/UnfoldShortCircuit.h" +#include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/NodeSearch.h" +#include "compiler/translator/RewriteElseBlocks.h" + +#include <algorithm> +#include <cfloat> +#include <stdio.h> + +namespace sh +{ + +TString OutputHLSL::TextureFunction::name() const +{ + TString name = "gl_texture"; + + if (IsSampler2D(sampler)) + { + name += "2D"; + } + else if (IsSampler3D(sampler)) + { + name += "3D"; + } + else if (IsSamplerCube(sampler)) + { + name += "Cube"; + } + else UNREACHABLE(); + + if (proj) + { + name += "Proj"; + } + + if (offset) + { + name += "Offset"; + } + + switch(method) + { + case IMPLICIT: break; + case BIAS: break; // Extra parameter makes the signature unique + case LOD: name += "Lod"; break; + case LOD0: name += "Lod0"; break; + case LOD0BIAS: name += "Lod0"; break; // Extra parameter makes the signature unique + case SIZE: name += "Size"; break; + case FETCH: name += "Fetch"; break; + case GRAD: name += "Grad"; break; + default: UNREACHABLE(); + } + + return name + "("; +} + +const char *RegisterPrefix(const TType &type) +{ + if (IsSampler(type.getBasicType())) + { + return "s"; + } + else + { + return "c"; + } +} + +bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const +{ + if (sampler < rhs.sampler) return true; + if (sampler > rhs.sampler) return false; + + if (coords < rhs.coords) return true; + if (coords > rhs.coords) return false; + + if (!proj && rhs.proj) return true; + if (proj && !rhs.proj) return false; + + if (!offset && rhs.offset) return true; + if (offset && !rhs.offset) return false; + + if (method < rhs.method) return true; + if (method > rhs.method) return false; + + return false; +} + +OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType) + : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType) +{ + mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); + mInsideFunction = false; + + mUsesFragColor = false; + mUsesFragData = false; + mUsesDepthRange = false; + mUsesFragCoord = false; + mUsesPointCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesFragDepth = false; + mUsesXor = false; + mUsesMod1 = false; + mUsesMod2v = false; + mUsesMod2f = false; + mUsesMod3v = false; + mUsesMod3f = false; + mUsesMod4v = false; + mUsesMod4f = false; + mUsesFaceforward1 = false; + mUsesFaceforward2 = false; + mUsesFaceforward3 = false; + mUsesFaceforward4 = false; + mUsesAtan2_1 = false; + mUsesAtan2_2 = false; + mUsesAtan2_3 = false; + mUsesAtan2_4 = false; + mUsesDiscardRewriting = false; + mUsesNestedBreak = false; + + mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + + mUniqueIndex = 0; + + mContainsLoopDiscontinuity = false; + mOutputLod0Function = false; + mInsideDiscontinuousLoop = false; + mNestedLoopDepth = 0; + + mExcessiveLoopIndex = NULL; + + if (mOutputType == SH_HLSL9_OUTPUT) + { + if (mContext.shaderType == SH_FRAGMENT_SHADER) + { + mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront + } + else + { + mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust + } + } + else + { + mUniformRegister = 0; + } + + mSamplerRegister = 0; + mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants + mPaddingCounter = 0; +} + +OutputHLSL::~OutputHLSL() +{ + delete mUnfoldShortCircuit; +} + +void OutputHLSL::output() +{ + mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); + const std::vector<TIntermTyped*> &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot); + makeFlaggedStructMaps(flaggedStructs); + + // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which + // use a vertex attribute as a condition, and some related computation in the else block. + if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == SH_VERTEX_SHADER) + { + RewriteElseBlocks(mContext.treeRoot); + } + + mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header + header(); + + mContext.infoSink().obj << mHeader.c_str(); + mContext.infoSink().obj << mBody.c_str(); +} + +void OutputHLSL::makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs) +{ + for (unsigned int structIndex = 0; structIndex < flaggedStructs.size(); structIndex++) + { + TIntermTyped *flaggedNode = flaggedStructs[structIndex]; + + // This will mark the necessary block elements as referenced + flaggedNode->traverse(this); + TString structName(mBody.c_str()); + mBody.erase(); + + mFlaggedStructOriginalNames[flaggedNode] = structName; + + for (size_t pos = structName.find('.'); pos != std::string::npos; pos = structName.find('.')) + { + structName.erase(pos, 1); + } + + mFlaggedStructMappedNames[flaggedNode] = "map" + structName; + } +} + +TInfoSinkBase &OutputHLSL::getBodyStream() +{ + return mBody; +} + +const std::vector<gl::Uniform> &OutputHLSL::getUniforms() +{ + return mActiveUniforms; +} + +const std::vector<gl::InterfaceBlock> &OutputHLSL::getInterfaceBlocks() const +{ + return mActiveInterfaceBlocks; +} + +const std::vector<gl::Attribute> &OutputHLSL::getOutputVariables() const +{ + return mActiveOutputVariables; +} + +const std::vector<gl::Attribute> &OutputHLSL::getAttributes() const +{ + return mActiveAttributes; +} + +const std::vector<gl::Varying> &OutputHLSL::getVaryings() const +{ + return mActiveVaryings; +} + +int OutputHLSL::vectorSize(const TType &type) const +{ + int elementSize = type.isMatrix() ? type.getCols() : 1; + int arraySize = type.isArray() ? type.getArraySize() : 1; + + return elementSize * arraySize; +} + +TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field) +{ + if (interfaceBlock.hasInstanceName()) + { + return interfaceBlock.name() + "." + field.name(); + } + else + { + return field.name(); + } +} + +TString OutputHLSL::decoratePrivate(const TString &privateText) +{ + return "dx_" + privateText; +} + +TString OutputHLSL::interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlock) +{ + return decoratePrivate(interfaceBlock.name()) + "_type"; +} + +TString OutputHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex) +{ + if (!interfaceBlock.hasInstanceName()) + { + return ""; + } + else if (interfaceBlock.isArray()) + { + return decoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex); + } + else + { + return decorate(interfaceBlock.instanceName()); + } +} + +TString OutputHLSL::interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage) +{ + const TType &fieldType = *field.type(); + const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; + ASSERT(matrixPacking != EmpUnspecified); + + if (fieldType.isMatrix()) + { + // Use HLSL row-major packing for GLSL column-major matrices + const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); + return matrixPackString + " " + typeString(fieldType); + } + else if (fieldType.getStruct()) + { + // Use HLSL row-major packing for GLSL column-major matrices + return structureTypeName(*fieldType.getStruct(), matrixPacking == EmpColumnMajor, blockStorage == EbsStd140); + } + else + { + return typeString(fieldType); + } +} + +TString OutputHLSL::interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage) +{ + TString hlsl; + + int elementIndex = 0; + + for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++) + { + const TField &field = *interfaceBlock.fields()[typeIndex]; + const TType &fieldType = *field.type(); + + if (blockStorage == EbsStd140) + { + // 2 and 3 component vector types in some cases need pre-padding + hlsl += std140PrePaddingString(fieldType, &elementIndex); + } + + hlsl += " " + interfaceBlockFieldTypeString(field, blockStorage) + + " " + decorate(field.name()) + arrayString(fieldType) + ";\n"; + + // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff + if (blockStorage == EbsStd140) + { + const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); + hlsl += std140PostPaddingString(fieldType, useHLSLRowMajorPacking); + } + } + + return hlsl; +} + +TString OutputHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock) +{ + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + + return "struct " + interfaceBlockStructNameString(interfaceBlock) + "\n" + "{\n" + + interfaceBlockFieldString(interfaceBlock, blockStorage) + + "};\n\n"; +} + +TString OutputHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex) +{ + const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? decorate(str(arrayIndex)) : ""); + const TString &blockName = interfaceBlock.name() + arrayIndexString; + TString hlsl; + + hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n" + "{\n"; + + if (interfaceBlock.hasInstanceName()) + { + hlsl += " " + interfaceBlockStructNameString(interfaceBlock) + " " + interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n"; + } + else + { + const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); + hlsl += interfaceBlockFieldString(interfaceBlock, blockStorage); + } + + hlsl += "};\n\n"; + + return hlsl; +} + +TString OutputHLSL::std140PrePaddingString(const TType &type, int *elementIndex) +{ + if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray()) + { + // no padding needed, HLSL will align the field to a new register + *elementIndex = 0; + return ""; + } + + const GLenum glType = glVariableType(type); + const int numComponents = gl::UniformComponentCount(glType); + + if (numComponents >= 4) + { + // no padding needed, HLSL will align the field to a new register + *elementIndex = 0; + return ""; + } + + if (*elementIndex + numComponents > 4) + { + // no padding needed, HLSL will align the field to a new register + *elementIndex = numComponents; + return ""; + } + + TString padding; + + const int alignment = numComponents == 3 ? 4 : numComponents; + const int paddingOffset = (*elementIndex % alignment); + + if (paddingOffset != 0) + { + // padding is neccessary + for (int paddingIndex = paddingOffset; paddingIndex < alignment; paddingIndex++) + { + padding += " float pad_" + str(mPaddingCounter++) + ";\n"; + } + + *elementIndex += (alignment - paddingOffset); + } + + *elementIndex += numComponents; + *elementIndex %= 4; + + return padding; +} + +TString OutputHLSL::std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking) +{ + if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct) + { + return ""; + } + + int numComponents = 0; + + if (type.isMatrix()) + { + // This method can also be called from structureString, which does not use layout qualifiers. + // Thus, use the method parameter for determining the matrix packing. + // + // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we + // wish to always transpose GL matrices to play well with HLSL's matrix array indexing. + // + const bool isRowMajorMatrix = !useHLSLRowMajorPacking; + const GLenum glType = glVariableType(type); + numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); + } + else if (type.getStruct()) + { + const TString &structName = structureTypeName(*type.getStruct(), useHLSLRowMajorPacking, true); + numComponents = mStd140StructElementIndexes[structName]; + + if (numComponents == 0) + { + return ""; + } + } + else + { + const GLenum glType = glVariableType(type); + numComponents = gl::UniformComponentCount(glType); + } + + TString padding; + for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++) + { + padding += " float pad_" + str(mPaddingCounter++) + ";\n"; + } + return padding; +} + +// Use the same layout for packed and shared +void setBlockLayout(gl::InterfaceBlock *interfaceBlock, gl::BlockLayoutType newLayout) +{ + interfaceBlock->layout = newLayout; + interfaceBlock->blockInfo.clear(); + + switch (newLayout) + { + case gl::BLOCKLAYOUT_SHARED: + case gl::BLOCKLAYOUT_PACKED: + { + gl::HLSLBlockEncoder hlslEncoder(&interfaceBlock->blockInfo, gl::HLSLBlockEncoder::ENCODE_PACKED); + hlslEncoder.encodeInterfaceBlockFields(interfaceBlock->fields); + interfaceBlock->dataSize = hlslEncoder.getBlockSize(); + } + break; + + case gl::BLOCKLAYOUT_STANDARD: + { + gl::Std140BlockEncoder stdEncoder(&interfaceBlock->blockInfo); + stdEncoder.encodeInterfaceBlockFields(interfaceBlock->fields); + interfaceBlock->dataSize = stdEncoder.getBlockSize(); + } + break; + + default: + UNREACHABLE(); + break; + } +} + +gl::BlockLayoutType convertBlockLayoutType(TLayoutBlockStorage blockStorage) +{ + switch (blockStorage) + { + case EbsPacked: return gl::BLOCKLAYOUT_PACKED; + case EbsShared: return gl::BLOCKLAYOUT_SHARED; + case EbsStd140: return gl::BLOCKLAYOUT_STANDARD; + default: UNREACHABLE(); return gl::BLOCKLAYOUT_SHARED; + } +} + +TString OutputHLSL::structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName) +{ + TString init; + + TString preIndentString; + TString fullIndentString; + + for (int spaces = 0; spaces < (indent * 4); spaces++) + { + preIndentString += ' '; + } + + for (int spaces = 0; spaces < ((indent+1) * 4); spaces++) + { + fullIndentString += ' '; + } + + init += preIndentString + "{\n"; + + const TFieldList &fields = structure.fields(); + for (unsigned int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const TField &field = *fields[fieldIndex]; + const TString &fieldName = rhsStructName + "." + decorate(field.name()); + const TType &fieldType = *field.type(); + + if (fieldType.getStruct()) + { + init += structInitializerString(indent + 1, *fieldType.getStruct(), fieldName); + } + else + { + init += fullIndentString + fieldName + ",\n"; + } + } + + init += preIndentString + "}" + (indent == 0 ? ";" : ",") + "\n"; + + return init; +} + +void OutputHLSL::header() +{ + TInfoSinkBase &out = mHeader; + + TString uniforms; + TString interfaceBlocks; + TString varyings; + TString attributes; + TString flaggedStructs; + + for (ReferencedSymbols::const_iterator uniformIt = mReferencedUniforms.begin(); uniformIt != mReferencedUniforms.end(); uniformIt++) + { + const TIntermSymbol &uniform = *uniformIt->second; + const TType &type = uniform.getType(); + const TString &name = uniform.getSymbol(); + + int registerIndex = declareUniformAndAssignRegister(type, name); + + if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture + { + uniforms += "uniform " + samplerString(type) + " sampler_" + decorateUniform(name, type) + arrayString(type) + + " : register(s" + str(registerIndex) + ");\n"; + + uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) + + " : register(t" + str(registerIndex) + ");\n"; + } + else + { + const TStructure *structure = type.getStruct(); + const TString &typeName = (structure ? structureTypeName(*structure, false, false) : typeString(type)); + + const TString ®isterString = TString("register(") + RegisterPrefix(type) + str(registerIndex) + ")"; + + uniforms += "uniform " + typeName + " " + decorateUniform(name, type) + arrayString(type) + " : " + registerString + ";\n"; + } + } + + for (ReferencedSymbols::const_iterator interfaceBlockIt = mReferencedInterfaceBlocks.begin(); interfaceBlockIt != mReferencedInterfaceBlocks.end(); interfaceBlockIt++) + { + const TType &nodeType = interfaceBlockIt->second->getType(); + const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock(); + const TFieldList &fieldList = interfaceBlock.fields(); + + unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize()); + gl::InterfaceBlock activeBlock(interfaceBlock.name().c_str(), arraySize, mInterfaceBlockRegister); + for (unsigned int typeIndex = 0; typeIndex < fieldList.size(); typeIndex++) + { + const TField &field = *fieldList[typeIndex]; + const TString &fullUniformName = interfaceBlockFieldString(interfaceBlock, field); + declareInterfaceBlockField(*field.type(), fullUniformName, activeBlock.fields); + } + + mInterfaceBlockRegister += std::max(1u, arraySize); + + gl::BlockLayoutType blockLayoutType = convertBlockLayoutType(interfaceBlock.blockStorage()); + setBlockLayout(&activeBlock, blockLayoutType); + + if (interfaceBlock.matrixPacking() == EmpRowMajor) + { + activeBlock.isRowMajorLayout = true; + } + + mActiveInterfaceBlocks.push_back(activeBlock); + + if (interfaceBlock.hasInstanceName()) + { + interfaceBlocks += interfaceBlockStructString(interfaceBlock); + } + + if (arraySize > 0) + { + for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + { + interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex + arrayIndex, arrayIndex); + } + } + else + { + interfaceBlocks += interfaceBlockString(interfaceBlock, activeBlock.registerIndex, GL_INVALID_INDEX); + } + } + + for (std::map<TIntermTyped*, TString>::const_iterator flaggedStructIt = mFlaggedStructMappedNames.begin(); flaggedStructIt != mFlaggedStructMappedNames.end(); flaggedStructIt++) + { + TIntermTyped *structNode = flaggedStructIt->first; + const TString &mappedName = flaggedStructIt->second; + const TStructure &structure = *structNode->getType().getStruct(); + const TString &originalName = mFlaggedStructOriginalNames[structNode]; + + flaggedStructs += "static " + decorate(structure.name()) + " " + mappedName + " =\n"; + flaggedStructs += structInitializerString(0, structure, originalName); + flaggedStructs += "\n"; + } + + for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++) + { + const TType &type = varying->second->getType(); + const TString &name = varying->second->getSymbol(); + + // Program linking depends on this exact format + varyings += "static " + interpolationString(type.getQualifier()) + " " + typeString(type) + " " + + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + + declareVaryingToList(type, type.getQualifier(), name, mActiveVaryings); + } + + for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++) + { + const TType &type = attribute->second->getType(); + const TString &name = attribute->second->getSymbol(); + + attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n"; + + gl::Attribute attributeVar(glVariableType(type), glVariablePrecision(type), name.c_str(), + (unsigned int)type.getArraySize(), type.getLayoutQualifier().location); + mActiveAttributes.push_back(attributeVar); + } + + for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++) + { + out << *structDeclaration; + } + + for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++) + { + out << *constructor; + } + + if (mUsesDiscardRewriting) + { + out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n"; + } + + if (mUsesNestedBreak) + { + out << "#define ANGLE_USES_NESTED_BREAK" << "\n"; + } + + if (mContext.shaderType == SH_FRAGMENT_SHADER) + { + TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); + const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire)); + + out << "// Varyings\n"; + out << varyings; + out << "\n"; + + if (mContext.getShaderVersion() >= 300) + { + for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) + { + const TString &variableName = outputVariableIt->first; + const TType &variableType = outputVariableIt->second->getType(); + const TLayoutQualifier &layoutQualifier = variableType.getLayoutQualifier(); + + out << "static " + typeString(variableType) + " out_" + variableName + arrayString(variableType) + + " = " + initializer(variableType) + ";\n"; + + gl::Attribute outputVar(glVariableType(variableType), glVariablePrecision(variableType), variableName.c_str(), + (unsigned int)variableType.getArraySize(), layoutQualifier.location); + mActiveOutputVariables.push_back(outputVar); + } + } + else + { + const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1; + + out << "static float4 gl_Color[" << numColorValues << "] =\n" + "{\n"; + for (unsigned int i = 0; i < numColorValues; i++) + { + out << " float4(0, 0, 0, 0)"; + if (i + 1 != numColorValues) + { + out << ","; + } + out << "\n"; + } + + out << "};\n"; + } + + if (mUsesFragDepth) + { + out << "static float gl_Depth = 0.0;\n"; + } + + if (mUsesFragCoord) + { + out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n"; + } + + if (mUsesPointCoord) + { + out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n"; + } + + if (mUsesFrontFacing) + { + out << "static bool gl_FrontFacing = false;\n"; + } + + out << "\n"; + + if (mUsesDepthRange) + { + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n"; + } + + if (mOutputType == SH_HLSL11_OUTPUT) + { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + + if (mUsesDepthRange) + { + out << " float3 dx_DepthRange : packoffset(c0);\n"; + } + + if (mUsesFragCoord) + { + out << " float4 dx_ViewCoords : packoffset(c1);\n"; + } + + if (mUsesFragCoord || mUsesFrontFacing) + { + out << " float3 dx_DepthFront : packoffset(c2);\n"; + } + + out << "};\n"; + } + else + { + if (mUsesDepthRange) + { + out << "uniform float3 dx_DepthRange : register(c0);"; + } + + if (mUsesFragCoord) + { + out << "uniform float4 dx_ViewCoords : register(c1);\n"; + } + + if (mUsesFragCoord || mUsesFrontFacing) + { + out << "uniform float3 dx_DepthFront : register(c2);\n"; + } + } + + out << "\n"; + + if (mUsesDepthRange) + { + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; + } + + out << uniforms; + out << "\n"; + + if (!interfaceBlocks.empty()) + { + out << interfaceBlocks; + out << "\n"; + + if (!flaggedStructs.empty()) + { + out << "// Std140 Structures accessed by value\n"; + out << "\n"; + out << flaggedStructs; + out << "\n"; + } + } + + if (usingMRTExtension && mNumRenderTargets > 1) + { + out << "#define GL_USES_MRT\n"; + } + + if (mUsesFragColor) + { + out << "#define GL_USES_FRAG_COLOR\n"; + } + + if (mUsesFragData) + { + out << "#define GL_USES_FRAG_DATA\n"; + } + } + else // Vertex shader + { + out << "// Attributes\n"; + out << attributes; + out << "\n" + "static float4 gl_Position = float4(0, 0, 0, 0);\n"; + + if (mUsesPointSize) + { + out << "static float gl_PointSize = float(1);\n"; + } + + out << "\n" + "// Varyings\n"; + out << varyings; + out << "\n"; + + if (mUsesDepthRange) + { + out << "struct gl_DepthRangeParameters\n" + "{\n" + " float near;\n" + " float far;\n" + " float diff;\n" + "};\n" + "\n"; + } + + if (mOutputType == SH_HLSL11_OUTPUT) + { + if (mUsesDepthRange) + { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n" + " float3 dx_DepthRange : packoffset(c0);\n" + "};\n" + "\n"; + } + } + else + { + if (mUsesDepthRange) + { + out << "uniform float3 dx_DepthRange : register(c0);\n"; + } + + out << "uniform float4 dx_ViewAdjust : register(c1);\n" + "\n"; + } + + if (mUsesDepthRange) + { + out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n" + "\n"; + } + + out << uniforms; + out << "\n"; + + if (!interfaceBlocks.empty()) + { + out << interfaceBlocks; + out << "\n"; + + if (!flaggedStructs.empty()) + { + out << "// Std140 Structures accessed by value\n"; + out << "\n"; + out << flaggedStructs; + out << "\n"; + } + } + } + + for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++) + { + // Return type + if (textureFunction->method == TextureFunction::SIZE) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "int2 "; break; + case EbtSampler3D: out << "int3 "; break; + case EbtSamplerCube: out << "int2 "; break; + case EbtSampler2DArray: out << "int3 "; break; + case EbtISampler2D: out << "int2 "; break; + case EbtISampler3D: out << "int3 "; break; + case EbtISamplerCube: out << "int2 "; break; + case EbtISampler2DArray: out << "int3 "; break; + case EbtUSampler2D: out << "int2 "; break; + case EbtUSampler3D: out << "int3 "; break; + case EbtUSamplerCube: out << "int2 "; break; + case EbtUSampler2DArray: out << "int3 "; break; + case EbtSampler2DShadow: out << "int2 "; break; + case EbtSamplerCubeShadow: out << "int2 "; break; + case EbtSampler2DArrayShadow: out << "int3 "; break; + default: UNREACHABLE(); + } + } + else // Sampling function + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "float4 "; break; + case EbtSampler3D: out << "float4 "; break; + case EbtSamplerCube: out << "float4 "; break; + case EbtSampler2DArray: out << "float4 "; break; + case EbtISampler2D: out << "int4 "; break; + case EbtISampler3D: out << "int4 "; break; + case EbtISamplerCube: out << "int4 "; break; + case EbtISampler2DArray: out << "int4 "; break; + case EbtUSampler2D: out << "uint4 "; break; + case EbtUSampler3D: out << "uint4 "; break; + case EbtUSamplerCube: out << "uint4 "; break; + case EbtUSampler2DArray: out << "uint4 "; break; + case EbtSampler2DShadow: out << "float "; break; + case EbtSamplerCubeShadow: out << "float "; break; + case EbtSampler2DArrayShadow: out << "float "; break; + default: UNREACHABLE(); + } + } + + // Function name + out << textureFunction->name(); + + // Argument list + int hlslCoords = 4; + + if (mOutputType == SH_HLSL9_OUTPUT) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "sampler2D s"; hlslCoords = 2; break; + case EbtSamplerCube: out << "samplerCUBE s"; hlslCoords = 3; break; + default: UNREACHABLE(); + } + + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: break; + case TextureFunction::BIAS: hlslCoords = 4; break; + case TextureFunction::LOD: hlslCoords = 4; break; + case TextureFunction::LOD0: hlslCoords = 4; break; + case TextureFunction::LOD0BIAS: hlslCoords = 4; break; + default: UNREACHABLE(); + } + } + else if (mOutputType == SH_HLSL11_OUTPUT) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "Texture2D x, SamplerState s"; hlslCoords = 2; break; + case EbtSampler3D: out << "Texture3D x, SamplerState s"; hlslCoords = 3; break; + case EbtSamplerCube: out << "TextureCube x, SamplerState s"; hlslCoords = 3; break; + case EbtSampler2DArray: out << "Texture2DArray x, SamplerState s"; hlslCoords = 3; break; + case EbtISampler2D: out << "Texture2D<int4> x, SamplerState s"; hlslCoords = 2; break; + case EbtISampler3D: out << "Texture3D<int4> x, SamplerState s"; hlslCoords = 3; break; + case EbtISamplerCube: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break; + case EbtISampler2DArray: out << "Texture2DArray<int4> x, SamplerState s"; hlslCoords = 3; break; + case EbtUSampler2D: out << "Texture2D<uint4> x, SamplerState s"; hlslCoords = 2; break; + case EbtUSampler3D: out << "Texture3D<uint4> x, SamplerState s"; hlslCoords = 3; break; + case EbtUSamplerCube: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break; + case EbtUSampler2DArray: out << "Texture2DArray<uint4> x, SamplerState s"; hlslCoords = 3; break; + case EbtSampler2DShadow: out << "Texture2D x, SamplerComparisonState s"; hlslCoords = 2; break; + case EbtSamplerCubeShadow: out << "TextureCube x, SamplerComparisonState s"; hlslCoords = 3; break; + case EbtSampler2DArrayShadow: out << "Texture2DArray x, SamplerComparisonState s"; hlslCoords = 3; break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + + if (textureFunction->method == TextureFunction::FETCH) // Integer coordinates + { + switch(textureFunction->coords) + { + case 2: out << ", int2 t"; break; + case 3: out << ", int3 t"; break; + default: UNREACHABLE(); + } + } + else // Floating-point coordinates (except textureSize) + { + switch(textureFunction->coords) + { + case 1: out << ", int lod"; break; // textureSize() + case 2: out << ", float2 t"; break; + case 3: out << ", float3 t"; break; + case 4: out << ", float4 t"; break; + default: UNREACHABLE(); + } + } + + if (textureFunction->method == TextureFunction::GRAD) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + case EbtSampler2DShadow: + case EbtSampler2DArrayShadow: + out << ", float2 ddx, float2 ddy"; + break; + case EbtSampler3D: + case EbtISampler3D: + case EbtUSampler3D: + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + case EbtSamplerCubeShadow: + out << ", float3 ddx, float3 ddy"; + break; + default: UNREACHABLE(); + } + } + + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: break; + case TextureFunction::BIAS: break; // Comes after the offset parameter + case TextureFunction::LOD: out << ", float lod"; break; + case TextureFunction::LOD0: break; + case TextureFunction::LOD0BIAS: break; // Comes after the offset parameter + case TextureFunction::SIZE: break; + case TextureFunction::FETCH: out << ", int mip"; break; + case TextureFunction::GRAD: break; + default: UNREACHABLE(); + } + + if (textureFunction->offset) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << ", int2 offset"; break; + case EbtSampler3D: out << ", int3 offset"; break; + case EbtSampler2DArray: out << ", int2 offset"; break; + case EbtISampler2D: out << ", int2 offset"; break; + case EbtISampler3D: out << ", int3 offset"; break; + case EbtISampler2DArray: out << ", int2 offset"; break; + case EbtUSampler2D: out << ", int2 offset"; break; + case EbtUSampler3D: out << ", int3 offset"; break; + case EbtUSampler2DArray: out << ", int2 offset"; break; + case EbtSampler2DShadow: out << ", int2 offset"; break; + case EbtSampler2DArrayShadow: out << ", int2 offset"; break; + default: UNREACHABLE(); + } + } + + if (textureFunction->method == TextureFunction::BIAS || + textureFunction->method == TextureFunction::LOD0BIAS) + { + out << ", float bias"; + } + + out << ")\n" + "{\n"; + + if (textureFunction->method == TextureFunction::SIZE) + { + if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler)) + { + if (IsSamplerArray(textureFunction->sampler)) + { + out << " uint width; uint height; uint layers; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, layers, numberOfLevels);\n"; + } + else + { + out << " uint width; uint height; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, numberOfLevels);\n"; + } + } + else if (IsSampler3D(textureFunction->sampler)) + { + out << " uint width; uint height; uint depth; uint numberOfLevels;\n" + " x.GetDimensions(lod, width, height, depth, numberOfLevels);\n"; + } + else UNREACHABLE(); + + switch(textureFunction->sampler) + { + case EbtSampler2D: out << " return int2(width, height);"; break; + case EbtSampler3D: out << " return int3(width, height, depth);"; break; + case EbtSamplerCube: out << " return int2(width, height);"; break; + case EbtSampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtISampler2D: out << " return int2(width, height);"; break; + case EbtISampler3D: out << " return int3(width, height, depth);"; break; + case EbtISamplerCube: out << " return int2(width, height);"; break; + case EbtISampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtUSampler2D: out << " return int2(width, height);"; break; + case EbtUSampler3D: out << " return int3(width, height, depth);"; break; + case EbtUSamplerCube: out << " return int2(width, height);"; break; + case EbtUSampler2DArray: out << " return int3(width, height, layers);"; break; + case EbtSampler2DShadow: out << " return int2(width, height);"; break; + case EbtSamplerCubeShadow: out << " return int2(width, height);"; break; + case EbtSampler2DArrayShadow: out << " return int3(width, height, layers);"; break; + default: UNREACHABLE(); + } + } + else + { + if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + + out << " uint mip = 0;\n"; + + out << " x.GetDimensions(mip, width, height, layers, levels);\n"; + + out << " bool xMajor = abs(t.x) > abs(t.y) && abs(t.x) > abs(t.z);\n"; + out << " bool yMajor = abs(t.y) > abs(t.z) && abs(t.y) > abs(t.x);\n"; + out << " bool zMajor = abs(t.z) > abs(t.x) && abs(t.z) > abs(t.y);\n"; + out << " bool negative = (xMajor && t.x < 0.0f) || (yMajor && t.y < 0.0f) || (zMajor && t.z < 0.0f);\n"; + + // FACE_POSITIVE_X = 000b + // FACE_NEGATIVE_X = 001b + // FACE_POSITIVE_Y = 010b + // FACE_NEGATIVE_Y = 011b + // FACE_POSITIVE_Z = 100b + // FACE_NEGATIVE_Z = 101b + out << " int face = (int)negative + (int)yMajor * 2 + (int)zMajor * 4;\n"; + + out << " float u = xMajor ? -t.z : (yMajor && t.y < 0.0f ? -t.x : t.x);\n"; + out << " float v = yMajor ? t.z : (negative ? t.y : -t.y);\n"; + out << " float m = xMajor ? t.x : (yMajor ? t.y : t.z);\n"; + + out << " t.x = (u * 0.5f / m) + 0.5f;\n"; + out << " t.y = (v * 0.5f / m) + 0.5f;\n"; + } + else if (IsIntegerSampler(textureFunction->sampler) && + textureFunction->method != TextureFunction::FETCH) + { + if (IsSampler2D(textureFunction->sampler)) + { + if (IsSamplerArray(textureFunction->sampler)) + { + out << " float width; float height; float layers; float levels;\n"; + + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, layers, levels);\n" + " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, layers, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " x.GetDimensions(mip, width, height, layers, levels);\n"; + } + else + { + out << " float width; float height; float levels;\n"; + + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, levels);\n" + " float2 tSized = float2(t.x * width, t.y * height);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::LOD) + { + out << " x.GetDimensions(0, width, height, levels);\n"; + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " x.GetDimensions(mip, width, height, levels);\n"; + } + } + else if (IsSampler3D(textureFunction->sampler)) + { + out << " float width; float height; float depth; float levels;\n"; + + if (textureFunction->method == TextureFunction::LOD0) + { + out << " uint mip = 0;\n"; + } + else if (textureFunction->method == TextureFunction::LOD0BIAS) + { + out << " uint mip = bias;\n"; + } + else + { + if (textureFunction->method == TextureFunction::IMPLICIT || + textureFunction->method == TextureFunction::BIAS) + { + out << " x.GetDimensions(0, width, height, depth, levels);\n" + " float3 tSized = float3(t.x * width, t.y * height, t.z * depth);\n" + " float dx = length(ddx(tSized));\n" + " float dy = length(ddy(tSized));\n" + " float lod = log2(max(dx, dy));\n"; + + if (textureFunction->method == TextureFunction::BIAS) + { + out << " lod += bias;\n"; + } + } + else if (textureFunction->method == TextureFunction::GRAD) + { + out << " x.GetDimensions(0, width, height, depth, levels);\n" + " float lod = log2(max(length(ddx), length(ddy)));\n"; + } + + out << " uint mip = uint(min(max(round(lod), 0), levels - 1));\n"; + } + + out << " x.GetDimensions(mip, width, height, depth, levels);\n"; + } + else UNREACHABLE(); + } + + out << " return "; + + // HLSL intrinsic + if (mOutputType == SH_HLSL9_OUTPUT) + { + switch(textureFunction->sampler) + { + case EbtSampler2D: out << "tex2D"; break; + case EbtSamplerCube: out << "texCUBE"; break; + default: UNREACHABLE(); + } + + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "(s, "; break; + case TextureFunction::BIAS: out << "bias(s, "; break; + case TextureFunction::LOD: out << "lod(s, "; break; + case TextureFunction::LOD0: out << "lod(s, "; break; + case TextureFunction::LOD0BIAS: out << "lod(s, "; break; + default: UNREACHABLE(); + } + } + else if (mOutputType == SH_HLSL11_OUTPUT) + { + if (textureFunction->method == TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction->sampler)) + { + out << "x.Load("; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + out << "x.SampleCmpLevelZero(s, "; + } + else + { + out << "x.SampleGrad(s, "; + } + } + else if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) + { + out << "x.Load("; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + out << "x.SampleCmp(s, "; + } + else + { + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "x.Sample(s, "; break; + case TextureFunction::BIAS: out << "x.SampleBias(s, "; break; + case TextureFunction::LOD: out << "x.SampleLevel(s, "; break; + case TextureFunction::LOD0: out << "x.SampleLevel(s, "; break; + case TextureFunction::LOD0BIAS: out << "x.SampleLevel(s, "; break; + default: UNREACHABLE(); + } + } + } + else UNREACHABLE(); + + // Integer sampling requires integer addresses + TString addressx = ""; + TString addressy = ""; + TString addressz = ""; + TString close = ""; + + if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) + { + switch(hlslCoords) + { + case 2: out << "int3("; break; + case 3: out << "int4("; break; + default: UNREACHABLE(); + } + + // Convert from normalized floating-point to integer + if (textureFunction->method != TextureFunction::FETCH) + { + addressx = "int(floor(width * frac(("; + addressy = "int(floor(height * frac(("; + + if (IsSamplerArray(textureFunction->sampler)) + { + addressz = "int(max(0, min(layers - 1, floor(0.5 + "; + } + else if (IsSamplerCube(textureFunction->sampler)) + { + addressz = "(((("; + } + else + { + addressz = "int(floor(depth * frac(("; + } + + close = "))))"; + } + } + else + { + switch(hlslCoords) + { + case 2: out << "float2("; break; + case 3: out << "float3("; break; + case 4: out << "float4("; break; + default: UNREACHABLE(); + } + } + + TString proj = ""; // Only used for projected textures + + if (textureFunction->proj) + { + switch(textureFunction->coords) + { + case 3: proj = " / t.z"; break; + case 4: proj = " / t.w"; break; + default: UNREACHABLE(); + } + } + + out << addressx + ("t.x" + proj) + close + ", " + addressy + ("t.y" + proj) + close; + + if (mOutputType == SH_HLSL9_OUTPUT) + { + if (hlslCoords >= 3) + { + if (textureFunction->coords < 3) + { + out << ", 0"; + } + else + { + out << ", t.z" + proj; + } + } + + if (hlslCoords == 4) + { + switch(textureFunction->method) + { + case TextureFunction::BIAS: out << ", bias"; break; + case TextureFunction::LOD: out << ", lod"; break; + case TextureFunction::LOD0: out << ", 0"; break; + case TextureFunction::LOD0BIAS: out << ", bias"; break; + default: UNREACHABLE(); + } + } + + out << "));\n"; + } + else if (mOutputType == SH_HLSL11_OUTPUT) + { + if (hlslCoords >= 3) + { + if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler)) + { + out << ", face"; + } + else + { + out << ", " + addressz + ("t.z" + proj) + close; + } + } + + if (textureFunction->method == TextureFunction::GRAD) + { + if (IsIntegerSampler(textureFunction->sampler)) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + // Compare value + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } + } + else + { + out << "), ddx, ddy"; + } + } + else if (IsIntegerSampler(textureFunction->sampler) || + textureFunction->method == TextureFunction::FETCH) + { + out << ", mip)"; + } + else if (IsShadowSampler(textureFunction->sampler)) + { + // Compare value + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } + } + else + { + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << ")"; break; + case TextureFunction::BIAS: out << "), bias"; break; + case TextureFunction::LOD: out << "), lod"; break; + case TextureFunction::LOD0: out << "), 0"; break; + case TextureFunction::LOD0BIAS: out << "), bias"; break; + default: UNREACHABLE(); + } + } + + if (textureFunction->offset) + { + out << ", offset"; + } + + out << ");"; + } + else UNREACHABLE(); + } + + out << "\n" + "}\n" + "\n"; + } + + if (mUsesFragCoord) + { + out << "#define GL_USES_FRAG_COORD\n"; + } + + if (mUsesPointCoord) + { + out << "#define GL_USES_POINT_COORD\n"; + } + + if (mUsesFrontFacing) + { + out << "#define GL_USES_FRONT_FACING\n"; + } + + if (mUsesPointSize) + { + out << "#define GL_USES_POINT_SIZE\n"; + } + + if (mUsesFragDepth) + { + out << "#define GL_USES_FRAG_DEPTH\n"; + } + + if (mUsesDepthRange) + { + out << "#define GL_USES_DEPTH_RANGE\n"; + } + + if (mUsesXor) + { + out << "bool xor(bool p, bool q)\n" + "{\n" + " return (p || q) && !(p && q);\n" + "}\n" + "\n"; + } + + if (mUsesMod1) + { + out << "float mod(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod2v) + { + out << "float2 mod(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod2f) + { + out << "float2 mod(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod3v) + { + out << "float3 mod(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod3f) + { + out << "float3 mod(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod4v) + { + out << "float4 mod(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesMod4f) + { + out << "float4 mod(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward1) + { + out << "float faceforward(float N, float I, float Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward2) + { + out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward3) + { + out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesFaceforward4) + { + out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n" + "{\n" + " if(dot(Nref, I) >= 0)\n" + " {\n" + " return -N;\n" + " }\n" + " else\n" + " {\n" + " return N;\n" + " }\n" + "}\n" + "\n"; + } + + if (mUsesAtan2_1) + { + out << "float atanyx(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN + " return atan2(y, x);\n" + "}\n"; + } + + if (mUsesAtan2_2) + { + out << "float2 atanyx(float2 y, float2 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n" + "}\n"; + } + + if (mUsesAtan2_3) + { + out << "float3 atanyx(float3 y, float3 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n" + "}\n"; + } + + if (mUsesAtan2_4) + { + out << "float4 atanyx(float4 y, float4 x)\n" + "{\n" + " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n" + " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n" + " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n" + " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n" + " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n" + "}\n"; + } +} + +void OutputHLSL::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = mBody; + + // Handle accessing std140 structs by value + if (mFlaggedStructMappedNames.count(node) > 0) + { + out << mFlaggedStructMappedNames[node]; + return; + } + + TString name = node->getSymbol(); + + if (name == "gl_DepthRange") + { + mUsesDepthRange = true; + out << name; + } + else + { + TQualifier qualifier = node->getQualifier(); + + if (qualifier == EvqUniform) + { + const TType& nodeType = node->getType(); + const TInterfaceBlock* interfaceBlock = nodeType.getInterfaceBlock(); + + if (interfaceBlock) + { + mReferencedInterfaceBlocks[interfaceBlock->name()] = node; + } + else + { + mReferencedUniforms[name] = node; + } + + out << decorateUniform(name, nodeType); + } + else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) + { + mReferencedAttributes[name] = node; + out << decorate(name); + } + else if (isVarying(qualifier)) + { + mReferencedVaryings[name] = node; + out << decorate(name); + } + else if (qualifier == EvqFragmentOut) + { + mReferencedOutputVariables[name] = node; + out << "out_" << name; + } + else if (qualifier == EvqFragColor) + { + out << "gl_Color[0]"; + mUsesFragColor = true; + } + else if (qualifier == EvqFragData) + { + out << "gl_Color"; + mUsesFragData = true; + } + else if (qualifier == EvqFragCoord) + { + mUsesFragCoord = true; + out << name; + } + else if (qualifier == EvqPointCoord) + { + mUsesPointCoord = true; + out << name; + } + else if (qualifier == EvqFrontFacing) + { + mUsesFrontFacing = true; + out << name; + } + else if (qualifier == EvqPointSize) + { + mUsesPointSize = true; + out << name; + } + else if (name == "gl_FragDepthEXT") + { + mUsesFragDepth = true; + out << "gl_Depth"; + } + else if (qualifier == EvqInternal) + { + out << name; + } + else + { + out << decorate(name); + } + } +} + +void OutputHLSL::visitRaw(TIntermRaw *node) +{ + mBody << node->getRawText(); +} + +bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = mBody; + + // Handle accessing std140 structs by value + if (mFlaggedStructMappedNames.count(node) > 0) + { + out << mFlaggedStructMappedNames[node]; + return false; + } + + switch (node->getOp()) + { + case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; + case EOpInitialize: + if (visit == PreVisit) + { + // GLSL allows to write things like "float x = x;" where a new variable x is defined + // and the value of an existing variable x is assigned. HLSL uses C semantics (the + // new variable is created before the assignment is evaluated), so we need to convert + // this to "float t = x, x = t;". + + TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + TIntermTyped *expression = node->getRight(); + + sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); + expression->traverse(&searchSymbol); + bool sameSymbol = searchSymbol.foundMatch(); + + if (sameSymbol) + { + // Type already printed + out << "t" + str(mUniqueIndex) + " = "; + expression->traverse(this); + out << ", "; + symbolNode->traverse(this); + out << " = t" + str(mUniqueIndex); + + mUniqueIndex++; + return false; + } + } + else if (visit == InVisit) + { + out << " = "; + } + break; + case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break; + case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break; + case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break; + case EOpVectorTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", transpose("; + } + else + { + out << ")))"; + } + break; + case EOpMatrixTimesMatrixAssign: + if (visit == PreVisit) + { + out << "("; + } + else if (visit == InVisit) + { + out << " = mul("; + node->getLeft()->traverse(this); + out << ", "; + } + else + { + out << "))"; + } + break; + case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; + case EOpIndexDirect: + { + const TType& leftType = node->getLeft()->getType(); + if (leftType.isInterfaceBlock()) + { + if (visit == PreVisit) + { + TInterfaceBlock* interfaceBlock = leftType.getInterfaceBlock(); + const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0); + + mReferencedInterfaceBlocks[interfaceBlock->instanceName()] = node->getLeft()->getAsSymbolNode(); + out << interfaceBlockInstanceString(*interfaceBlock, arrayIndex); + + return false; + } + } + else + { + outputTriplet(visit, "", "[", "]"); + } + } + break; + case EOpIndexIndirect: + // We do not currently support indirect references to interface blocks + ASSERT(node->getLeft()->getBasicType() != EbtInterfaceBlock); + outputTriplet(visit, "", "[", "]"); + break; + case EOpIndexDirectStruct: + if (visit == InVisit) + { + const TStructure* structure = node->getLeft()->getType().getStruct(); + const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); + const TField* field = structure->fields()[index->getIConst(0)]; + out << "." + decorateField(field->name(), *structure); + + return false; + } + break; + case EOpIndexDirectInterfaceBlock: + if (visit == InVisit) + { + const TInterfaceBlock* interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); + const TField* field = interfaceBlock->fields()[index->getIConst(0)]; + out << "." + decorate(field->name()); + + return false; + } + break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + + TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); + + if (swizzle) + { + TIntermSequence &sequence = swizzle->getSequence(); + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + + if (element) + { + int i = element->getIConst(0); + + switch (i) + { + case 0: out << "x"; break; + case 1: out << "y"; break; + case 2: out << "z"; break; + case 3: out << "w"; break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + } + else UNREACHABLE(); + + return false; // Fully processed + } + break; + case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break; + case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; + case EOpEqual: + case EOpNotEqual: + if (node->getLeft()->isScalar()) + { + if (node->getOp() == EOpEqual) + { + outputTriplet(visit, "(", " == ", ")"); + } + else + { + outputTriplet(visit, "(", " != ", ")"); + } + } + else if (node->getLeft()->getBasicType() == EbtStruct) + { + if (node->getOp() == EOpEqual) + { + out << "("; + } + else + { + out << "!("; + } + + const TStructure &structure = *node->getLeft()->getType().getStruct(); + const TFieldList &fields = structure.fields(); + + for (size_t i = 0; i < fields.size(); i++) + { + const TField *field = fields[i]; + + node->getLeft()->traverse(this); + out << "." + decorateField(field->name(), structure) + " == "; + node->getRight()->traverse(this); + out << "." + decorateField(field->name(), structure); + + if (i < fields.size() - 1) + { + out << " && "; + } + } + + out << ")"; + + return false; + } + else + { + ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector()); + + if (node->getOp() == EOpEqual) + { + outputTriplet(visit, "all(", " == ", ")"); + } + else + { + outputTriplet(visit, "!all(", " == ", ")"); + } + } + break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; + case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; + case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break; + case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break; + case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break; + case EOpLogicalOr: + if (node->getRight()->hasSideEffects()) + { + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + return false; + } + else + { + outputTriplet(visit, "(", " || ", ")"); + return true; + } + case EOpLogicalXor: + mUsesXor = true; + outputTriplet(visit, "xor(", ", ", ")"); + break; + case EOpLogicalAnd: + if (node->getRight()->hasSideEffects()) + { + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + return false; + } + else + { + outputTriplet(visit, "(", " && ", ")"); + return true; + } + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) +{ + switch (node->getOp()) + { + case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; + case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; + case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; + case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; + case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break; + case EOpConvIntToBool: + case EOpConvUIntToBool: + case EOpConvFloatToBool: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "bool(", "", ")"); break; + case 2: outputTriplet(visit, "bool2(", "", ")"); break; + case 3: outputTriplet(visit, "bool3(", "", ")"); break; + case 4: outputTriplet(visit, "bool4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvBoolToFloat: + case EOpConvIntToFloat: + case EOpConvUIntToFloat: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "float(", "", ")"); break; + case 2: outputTriplet(visit, "float2(", "", ")"); break; + case 3: outputTriplet(visit, "float3(", "", ")"); break; + case 4: outputTriplet(visit, "float4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvFloatToInt: + case EOpConvBoolToInt: + case EOpConvUIntToInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "int(", "", ")"); break; + case 2: outputTriplet(visit, "int2(", "", ")"); break; + case 3: outputTriplet(visit, "int3(", "", ")"); break; + case 4: outputTriplet(visit, "int4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvFloatToUInt: + case EOpConvBoolToUInt: + case EOpConvIntToUInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "uint(", "", ")"); break; + case 2: outputTriplet(visit, "uint2(", "", ")"); break; + case 3: outputTriplet(visit, "uint3(", "", ")"); break; + case 4: outputTriplet(visit, "uint4(", "", ")"); break; + default: UNREACHABLE(); + } + break; + case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break; + case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break; + case EOpSin: outputTriplet(visit, "sin(", "", ")"); break; + case EOpCos: outputTriplet(visit, "cos(", "", ")"); break; + case EOpTan: outputTriplet(visit, "tan(", "", ")"); break; + case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break; + case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break; + case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break; + case EOpExp: outputTriplet(visit, "exp(", "", ")"); break; + case EOpLog: outputTriplet(visit, "log(", "", ")"); break; + case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break; + case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break; + case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break; + case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break; + case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break; + case EOpSign: outputTriplet(visit, "sign(", "", ")"); break; + case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break; + case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break; + case EOpFract: outputTriplet(visit, "frac(", "", ")"); break; + case EOpLength: outputTriplet(visit, "length(", "", ")"); break; + case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; + case EOpDFdx: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "ddx(", "", ")"); + } + break; + case EOpDFdy: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "ddy(", "", ")"); + } + break; + case EOpFwidth: + if(mInsideDiscontinuousLoop || mOutputLod0Function) + { + outputTriplet(visit, "(", "", ", 0.0)"); + } + else + { + outputTriplet(visit, "fwidth(", "", ")"); + } + break; + case EOpAny: outputTriplet(visit, "any(", "", ")"); break; + case EOpAll: outputTriplet(visit, "all(", "", ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + TInfoSinkBase &out = mBody; + + switch (node->getOp()) + { + case EOpSequence: + { + if (mInsideFunction) + { + outputLineDirective(node->getLine().first_line); + out << "{\n"; + } + + for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++) + { + outputLineDirective((*sit)->getLine().first_line); + + traverseStatements(*sit); + + out << ";\n"; + } + + if (mInsideFunction) + { + outputLineDirective(node->getLine().last_line); + out << "}\n"; + } + + return false; + } + case EOpDeclaration: + if (visit == PreVisit) + { + TIntermSequence &sequence = node->getSequence(); + TIntermTyped *variable = sequence[0]->getAsTyped(); + + if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal)) + { + if (variable->getType().getStruct()) + { + addConstructor(variable->getType(), structNameString(*variable->getType().getStruct()), NULL); + } + + if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration + { + if (!mInsideFunction) + { + out << "static "; + } + + out << typeString(variable->getType()) + " "; + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + + if (symbol) + { + symbol->traverse(this); + out << arrayString(symbol->getType()); + out << " = " + initializer(symbol->getType()); + } + else + { + (*sit)->traverse(this); + } + + if (*sit != sequence.back()) + { + out << ", "; + } + } + } + else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration + { + // Already added to constructor map + } + else UNREACHABLE(); + } + else if (variable && isVaryingOut(variable->getQualifier())) + { + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + + if (symbol) + { + // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking + mReferencedVaryings[symbol->getSymbol()] = symbol; + } + else + { + (*sit)->traverse(this); + } + } + } + + return false; + } + else if (visit == InVisit) + { + out << ", "; + } + break; + case EOpPrototype: + if (visit == PreVisit) + { + out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); + + TIntermSequence &arguments = node->getSequence(); + + for (unsigned int i = 0; i < arguments.size(); i++) + { + TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + + if (symbol) + { + out << argumentString(symbol); + + if (i < arguments.size() - 1) + { + out << ", "; + } + } + else UNREACHABLE(); + } + + out << ");\n"; + + // Also prototype the Lod0 variant if needed + if (mContainsLoopDiscontinuity && !mOutputLod0Function) + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + + return false; + } + break; + case EOpComma: outputTriplet(visit, "(", ", ", ")"); break; + case EOpFunction: + { + TString name = TFunction::unmangleName(node->getName()); + + out << typeString(node->getType()) << " "; + + if (name == "main") + { + out << "gl_main("; + } + else + { + out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "("); + } + + TIntermSequence &sequence = node->getSequence(); + TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence(); + + for (unsigned int i = 0; i < arguments.size(); i++) + { + TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + + if (symbol) + { + if (symbol->getType().getStruct()) + { + addConstructor(symbol->getType(), structNameString(*symbol->getType().getStruct()), NULL); + } + + out << argumentString(symbol); + + if (i < arguments.size() - 1) + { + out << ", "; + } + } + else UNREACHABLE(); + } + + out << ")\n" + "{\n"; + + if (sequence.size() > 1) + { + mInsideFunction = true; + sequence[1]->traverse(this); + mInsideFunction = false; + } + + out << "}\n"; + + if (mContainsLoopDiscontinuity && !mOutputLod0Function) + { + if (name != "main") + { + mOutputLod0Function = true; + node->traverse(this); + mOutputLod0Function = false; + } + } + + return false; + } + break; + case EOpFunctionCall: + { + TString name = TFunction::unmangleName(node->getName()); + bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function; + TIntermSequence &arguments = node->getSequence(); + + if (node->isUserDefined()) + { + out << decorate(name) << (lod0 ? "Lod0(" : "("); + } + else + { + TBasicType samplerType = arguments[0]->getAsTyped()->getType().getBasicType(); + + TextureFunction textureFunction; + textureFunction.sampler = samplerType; + textureFunction.coords = arguments[1]->getAsTyped()->getNominalSize(); + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = false; + textureFunction.offset = false; + + if (name == "texture2D" || name == "textureCube" || name == "texture") + { + textureFunction.method = TextureFunction::IMPLICIT; + } + else if (name == "texture2DProj" || name == "textureProj") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.proj = true; + } + else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod" || + name == "texture2DLodEXT" || name == "textureCubeLodEXT") + { + textureFunction.method = TextureFunction::LOD; + } + else if (name == "texture2DProjLod" || name == "textureProjLod" || name == "texture2DProjLodEXT") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + } + else if (name == "textureSize") + { + textureFunction.method = TextureFunction::SIZE; + } + else if (name == "textureOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + } + else if (name == "textureProjOffset") + { + textureFunction.method = TextureFunction::IMPLICIT; + textureFunction.offset = true; + textureFunction.proj = true; + } + else if (name == "textureLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.offset = true; + } + else if (name == "textureProjLodOffset") + { + textureFunction.method = TextureFunction::LOD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else if (name == "texelFetch") + { + textureFunction.method = TextureFunction::FETCH; + } + else if (name == "texelFetchOffset") + { + textureFunction.method = TextureFunction::FETCH; + textureFunction.offset = true; + } + else if (name == "textureGrad" || name == "texture2DGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + } + else if (name == "textureGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.offset = true; + } + else if (name == "textureProjGrad" || name == "texture2DProjGradEXT" || name == "textureCubeGradEXT") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + } + else if (name == "textureProjGradOffset") + { + textureFunction.method = TextureFunction::GRAD; + textureFunction.proj = true; + textureFunction.offset = true; + } + else UNREACHABLE(); + + if (textureFunction.method == TextureFunction::IMPLICIT) // Could require lod 0 or have a bias argument + { + unsigned int mandatoryArgumentCount = 2; // All functions have sampler and coordinate arguments + + if (textureFunction.offset) + { + mandatoryArgumentCount++; + } + + bool bias = (arguments.size() > mandatoryArgumentCount); // Bias argument is optional + + if (lod0 || mContext.shaderType == SH_VERTEX_SHADER) + { + if (bias) + { + textureFunction.method = TextureFunction::LOD0BIAS; + } + else + { + textureFunction.method = TextureFunction::LOD0; + } + } + else if (bias) + { + textureFunction.method = TextureFunction::BIAS; + } + } + + mUsesTexture.insert(textureFunction); + + out << textureFunction.name(); + } + + for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++) + { + if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType())) + { + out << "texture_"; + (*arg)->traverse(this); + out << ", sampler_"; + } + + (*arg)->traverse(this); + + if (arg < arguments.end() - 1) + { + out << ", "; + } + } + + out << ")"; + + return false; + } + break; + case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; + case EOpConstructFloat: + addConstructor(node->getType(), "vec1", &node->getSequence()); + outputTriplet(visit, "vec1(", "", ")"); + break; + case EOpConstructVec2: + addConstructor(node->getType(), "vec2", &node->getSequence()); + outputTriplet(visit, "vec2(", ", ", ")"); + break; + case EOpConstructVec3: + addConstructor(node->getType(), "vec3", &node->getSequence()); + outputTriplet(visit, "vec3(", ", ", ")"); + break; + case EOpConstructVec4: + addConstructor(node->getType(), "vec4", &node->getSequence()); + outputTriplet(visit, "vec4(", ", ", ")"); + break; + case EOpConstructBool: + addConstructor(node->getType(), "bvec1", &node->getSequence()); + outputTriplet(visit, "bvec1(", "", ")"); + break; + case EOpConstructBVec2: + addConstructor(node->getType(), "bvec2", &node->getSequence()); + outputTriplet(visit, "bvec2(", ", ", ")"); + break; + case EOpConstructBVec3: + addConstructor(node->getType(), "bvec3", &node->getSequence()); + outputTriplet(visit, "bvec3(", ", ", ")"); + break; + case EOpConstructBVec4: + addConstructor(node->getType(), "bvec4", &node->getSequence()); + outputTriplet(visit, "bvec4(", ", ", ")"); + break; + case EOpConstructInt: + addConstructor(node->getType(), "ivec1", &node->getSequence()); + outputTriplet(visit, "ivec1(", "", ")"); + break; + case EOpConstructIVec2: + addConstructor(node->getType(), "ivec2", &node->getSequence()); + outputTriplet(visit, "ivec2(", ", ", ")"); + break; + case EOpConstructIVec3: + addConstructor(node->getType(), "ivec3", &node->getSequence()); + outputTriplet(visit, "ivec3(", ", ", ")"); + break; + case EOpConstructIVec4: + addConstructor(node->getType(), "ivec4", &node->getSequence()); + outputTriplet(visit, "ivec4(", ", ", ")"); + break; + case EOpConstructUInt: + addConstructor(node->getType(), "uvec1", &node->getSequence()); + outputTriplet(visit, "uvec1(", "", ")"); + break; + case EOpConstructUVec2: + addConstructor(node->getType(), "uvec2", &node->getSequence()); + outputTriplet(visit, "uvec2(", ", ", ")"); + break; + case EOpConstructUVec3: + addConstructor(node->getType(), "uvec3", &node->getSequence()); + outputTriplet(visit, "uvec3(", ", ", ")"); + break; + case EOpConstructUVec4: + addConstructor(node->getType(), "uvec4", &node->getSequence()); + outputTriplet(visit, "uvec4(", ", ", ")"); + break; + case EOpConstructMat2: + addConstructor(node->getType(), "mat2", &node->getSequence()); + outputTriplet(visit, "mat2(", ", ", ")"); + break; + case EOpConstructMat3: + addConstructor(node->getType(), "mat3", &node->getSequence()); + outputTriplet(visit, "mat3(", ", ", ")"); + break; + case EOpConstructMat4: + addConstructor(node->getType(), "mat4", &node->getSequence()); + outputTriplet(visit, "mat4(", ", ", ")"); + break; + case EOpConstructStruct: + { + const TString &structName = structNameString(*node->getType().getStruct()); + addConstructor(node->getType(), structName, &node->getSequence()); + outputTriplet(visit, structName + "_ctor(", ", ", ")"); + } + break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; + case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; + case EOpMod: + { + // We need to look at the number of components in both arguments + const int modValue = node->getSequence()[0]->getAsTyped()->getNominalSize() * 10 + + node->getSequence()[1]->getAsTyped()->getNominalSize(); + switch (modValue) + { + case 11: mUsesMod1 = true; break; + case 22: mUsesMod2v = true; break; + case 21: mUsesMod2f = true; break; + case 33: mUsesMod3v = true; break; + case 31: mUsesMod3f = true; break; + case 44: mUsesMod4v = true; break; + case 41: mUsesMod4f = true; break; + default: UNREACHABLE(); + } + + outputTriplet(visit, "mod(", ", ", ")"); + } + break; + case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; + case EOpAtan: + ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator + switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) + { + case 1: mUsesAtan2_1 = true; break; + case 2: mUsesAtan2_2 = true; break; + case 3: mUsesAtan2_3 = true; break; + case 4: mUsesAtan2_4 = true; break; + default: UNREACHABLE(); + } + outputTriplet(visit, "atanyx(", ", ", ")"); + break; + case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; + case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; + case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break; + case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break; + case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break; + case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break; + case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break; + case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; + case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; + case EOpFaceForward: + { + switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument + { + case 1: mUsesFaceforward1 = true; break; + case 2: mUsesFaceforward2 = true; break; + case 3: mUsesFaceforward3 = true; break; + case 4: mUsesFaceforward4 = true; break; + default: UNREACHABLE(); + } + + outputTriplet(visit, "faceforward(", ", ", ")"); + } + break; + case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; + case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = mBody; + + if (node->usesTernaryOperator()) + { + out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex(); + } + else // if/else statement + { + mUnfoldShortCircuit->traverse(node->getCondition()); + + out << "if ("; + + node->getCondition()->traverse(this); + + out << ")\n"; + + outputLineDirective(node->getLine().first_line); + out << "{\n"; + + bool discard = false; + + if (node->getTrueBlock()) + { + traverseStatements(node->getTrueBlock()); + + // Detect true discard + discard = (discard || FindDiscard::search(node->getTrueBlock())); + } + + outputLineDirective(node->getLine().first_line); + out << ";\n}\n"; + + if (node->getFalseBlock()) + { + out << "else\n"; + + outputLineDirective(node->getFalseBlock()->getLine().first_line); + out << "{\n"; + + outputLineDirective(node->getFalseBlock()->getLine().first_line); + traverseStatements(node->getFalseBlock()); + + outputLineDirective(node->getFalseBlock()->getLine().first_line); + out << ";\n}\n"; + + // Detect false discard + discard = (discard || FindDiscard::search(node->getFalseBlock())); + } + + // ANGLE issue 486: Detect problematic conditional discard + if (discard && FindSideEffectRewriting::search(node)) + { + mUsesDiscardRewriting = true; + } + } + + return false; +} + +void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) +{ + writeConstantUnion(node->getType(), node->getUnionArrayPointer()); +} + +bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) +{ + mNestedLoopDepth++; + + bool wasDiscontinuous = mInsideDiscontinuousLoop; + + if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop) + { + mInsideDiscontinuousLoop = containsLoopDiscontinuity(node); + } + + if (mOutputType == SH_HLSL9_OUTPUT) + { + if (handleExcessiveLoop(node)) + { + mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; + + return false; + } + } + + TInfoSinkBase &out = mBody; + + if (node->getType() == ELoopDoWhile) + { + out << "{do\n"; + + outputLineDirective(node->getLine().first_line); + out << "{\n"; + } + else + { + out << "{for("; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + out << "; "; + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + out << "; "; + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + out << ")\n"; + + outputLineDirective(node->getLine().first_line); + out << "{\n"; + } + + if (node->getBody()) + { + traverseStatements(node->getBody()); + } + + outputLineDirective(node->getLine().first_line); + out << ";}\n"; + + if (node->getType() == ELoopDoWhile) + { + outputLineDirective(node->getCondition()->getLine().first_line); + out << "while(\n"; + + node->getCondition()->traverse(this); + + out << ");"; + } + + out << "}\n"; + + mInsideDiscontinuousLoop = wasDiscontinuous; + mNestedLoopDepth--; + + return false; +} + +bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) +{ + TInfoSinkBase &out = mBody; + + switch (node->getFlowOp()) + { + case EOpKill: + outputTriplet(visit, "discard;\n", "", ""); + break; + case EOpBreak: + if (visit == PreVisit) + { + if (mNestedLoopDepth > 1) + { + mUsesNestedBreak = true; + } + + if (mExcessiveLoopIndex) + { + out << "{Break"; + mExcessiveLoopIndex->traverse(this); + out << " = true; break;}\n"; + } + else + { + out << "break;\n"; + } + } + break; + case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break; + case EOpReturn: + if (visit == PreVisit) + { + if (node->getExpression()) + { + out << "return "; + } + else + { + out << "return;\n"; + } + } + else if (visit == PostVisit) + { + if (node->getExpression()) + { + out << ";\n"; + } + } + break; + default: UNREACHABLE(); + } + + return true; +} + +void OutputHLSL::traverseStatements(TIntermNode *node) +{ + if (isSingleStatement(node)) + { + mUnfoldShortCircuit->traverse(node); + } + + node->traverse(this); +} + +bool OutputHLSL::isSingleStatement(TIntermNode *node) +{ + TIntermAggregate *aggregate = node->getAsAggregate(); + + if (aggregate) + { + if (aggregate->getOp() == EOpSequence) + { + return false; + } + else + { + for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++) + { + if (!isSingleStatement(*sit)) + { + return false; + } + } + + return true; + } + } + + return true; +} + +// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them +// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254). +bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) +{ + const int MAX_LOOP_ITERATIONS = 254; + TInfoSinkBase &out = mBody; + + // Parse loops of the form: + // for(int index = initial; index [comparator] limit; index += increment) + TIntermSymbol *index = NULL; + TOperator comparator = EOpNull; + int initial = 0; + int limit = 0; + int increment = 0; + + // Parse index name and intial value + if (node->getInit()) + { + TIntermAggregate *init = node->getInit()->getAsAggregate(); + + if (init) + { + TIntermSequence &sequence = init->getSequence(); + TIntermTyped *variable = sequence[0]->getAsTyped(); + + if (variable && variable->getQualifier() == EvqTemporary) + { + TIntermBinary *assign = variable->getAsBinaryNode(); + + if (assign->getOp() == EOpInitialize) + { + TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode(); + TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion(); + + if (symbol && constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + index = symbol; + initial = constant->getIConst(0); + } + } + } + } + } + } + + // Parse comparator and limit value + if (index != NULL && node->getCondition()) + { + TIntermBinary *test = node->getCondition()->getAsBinaryNode(); + + if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId()) + { + TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + comparator = test->getOp(); + limit = constant->getIConst(0); + } + } + } + } + + // Parse increment + if (index != NULL && comparator != EOpNull && node->getExpression()) + { + TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode(); + TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode(); + + if (binaryTerminal) + { + TOperator op = binaryTerminal->getOp(); + TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion(); + + if (constant) + { + if (constant->getBasicType() == EbtInt && constant->isScalar()) + { + int value = constant->getIConst(0); + + switch (op) + { + case EOpAddAssign: increment = value; break; + case EOpSubAssign: increment = -value; break; + default: UNIMPLEMENTED(); + } + } + } + } + else if (unaryTerminal) + { + TOperator op = unaryTerminal->getOp(); + + switch (op) + { + case EOpPostIncrement: increment = 1; break; + case EOpPostDecrement: increment = -1; break; + case EOpPreIncrement: increment = 1; break; + case EOpPreDecrement: increment = -1; break; + default: UNIMPLEMENTED(); + } + } + } + + if (index != NULL && comparator != EOpNull && increment != 0) + { + if (comparator == EOpLessThanEqual) + { + comparator = EOpLessThan; + limit += 1; + } + + if (comparator == EOpLessThan) + { + int iterations = (limit - initial) / increment; + + if (iterations <= MAX_LOOP_ITERATIONS) + { + return false; // Not an excessive loop + } + + TIntermSymbol *restoreIndex = mExcessiveLoopIndex; + mExcessiveLoopIndex = index; + + out << "{int "; + index->traverse(this); + out << ";\n" + "bool Break"; + index->traverse(this); + out << " = false;\n"; + + bool firstLoopFragment = true; + + while (iterations > 0) + { + int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations); + + if (!firstLoopFragment) + { + out << "if (!Break"; + index->traverse(this); + out << ") {\n"; + } + + if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment + { + mExcessiveLoopIndex = NULL; // Stops setting the Break flag + } + + // for(int index = initial; index < clampedLimit; index += increment) + + out << "for("; + index->traverse(this); + out << " = "; + out << initial; + + out << "; "; + index->traverse(this); + out << " < "; + out << clampedLimit; + + out << "; "; + index->traverse(this); + out << " += "; + out << increment; + out << ")\n"; + + outputLineDirective(node->getLine().first_line); + out << "{\n"; + + if (node->getBody()) + { + node->getBody()->traverse(this); + } + + outputLineDirective(node->getLine().first_line); + out << ";}\n"; + + if (!firstLoopFragment) + { + out << "}\n"; + } + + firstLoopFragment = false; + + initial += MAX_LOOP_ITERATIONS * increment; + iterations -= MAX_LOOP_ITERATIONS; + } + + out << "}"; + + mExcessiveLoopIndex = restoreIndex; + + return true; + } + else UNIMPLEMENTED(); + } + + return false; // Not handled as an excessive loop +} + +void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) +{ + TInfoSinkBase &out = mBody; + + if (visit == PreVisit) + { + out << preString; + } + else if (visit == InVisit) + { + out << inString; + } + else if (visit == PostVisit) + { + out << postString; + } +} + +void OutputHLSL::outputLineDirective(int line) +{ + if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) + { + mBody << "\n"; + mBody << "#line " << line; + + if (mContext.sourcePath) + { + mBody << " \"" << mContext.sourcePath << "\""; + } + + mBody << "\n"; + } +} + +TString OutputHLSL::argumentString(const TIntermSymbol *symbol) +{ + TQualifier qualifier = symbol->getQualifier(); + const TType &type = symbol->getType(); + TString name = symbol->getSymbol(); + + if (name.empty()) // HLSL demands named arguments, also for prototypes + { + name = "x" + str(mUniqueIndex++); + } + else + { + name = decorate(name); + } + + if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) + { + return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " + + qualifierString(qualifier) + " " + samplerString(type) + " sampler_" + name + arrayString(type); + } + + return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type); +} + +TString OutputHLSL::interpolationString(TQualifier qualifier) +{ + switch(qualifier) + { + case EvqVaryingIn: return ""; + case EvqFragmentIn: return ""; + case EvqInvariantVaryingIn: return ""; + case EvqSmoothIn: return "linear"; + case EvqFlatIn: return "nointerpolation"; + case EvqCentroidIn: return "centroid"; + case EvqVaryingOut: return ""; + case EvqVertexOut: return ""; + case EvqInvariantVaryingOut: return ""; + case EvqSmoothOut: return "linear"; + case EvqFlatOut: return "nointerpolation"; + case EvqCentroidOut: return "centroid"; + default: UNREACHABLE(); + } + + return ""; +} + +TString OutputHLSL::qualifierString(TQualifier qualifier) +{ + switch(qualifier) + { + case EvqIn: return "in"; + case EvqOut: return "inout"; // 'out' results in an HLSL error if not all fields are written, for GLSL it's undefined + case EvqInOut: return "inout"; + case EvqConstReadOnly: return "const"; + default: UNREACHABLE(); + } + + return ""; +} + +TString OutputHLSL::typeString(const TType &type) +{ + const TStructure* structure = type.getStruct(); + if (structure) + { + const TString& typeName = structure->name(); + if (typeName != "") + { + return structNameString(*type.getStruct()); + } + else // Nameless structure, define in place + { + return structureString(*structure, false, false); + } + } + else if (type.isMatrix()) + { + int cols = type.getCols(); + int rows = type.getRows(); + return "float" + str(cols) + "x" + str(rows); + } + else + { + switch (type.getBasicType()) + { + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: return "float"; + case 2: return "float2"; + case 3: return "float3"; + case 4: return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: return "int"; + case 2: return "int2"; + case 3: return "int3"; + case 4: return "int4"; + } + case EbtUInt: + switch (type.getNominalSize()) + { + case 1: return "uint"; + case 2: return "uint2"; + case 3: return "uint3"; + case 4: return "uint4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: return "bool"; + case 2: return "bool2"; + case 3: return "bool3"; + case 4: return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + case EbtISampler2D: + case EbtUSampler2D: + case EbtSampler2DArray: + case EbtISampler2DArray: + case EbtUSampler2DArray: + return "sampler2D"; + case EbtSamplerCube: + case EbtISamplerCube: + case EbtUSamplerCube: + return "samplerCUBE"; + case EbtSamplerExternalOES: + return "sampler2D"; + default: + break; + } + } + + UNREACHABLE(); + return "<unknown type>"; +} + +TString OutputHLSL::textureString(const TType &type) +{ + switch (type.getBasicType()) + { + case EbtSampler2D: return "Texture2D"; + case EbtSamplerCube: return "TextureCube"; + case EbtSamplerExternalOES: return "Texture2D"; + case EbtSampler2DArray: return "Texture2DArray"; + case EbtSampler3D: return "Texture3D"; + case EbtISampler2D: return "Texture2D<int4>"; + case EbtISampler3D: return "Texture3D<int4>"; + case EbtISamplerCube: return "Texture2DArray<int4>"; + case EbtISampler2DArray: return "Texture2DArray<int4>"; + case EbtUSampler2D: return "Texture2D<uint4>"; + case EbtUSampler3D: return "Texture3D<uint4>"; + case EbtUSamplerCube: return "Texture2DArray<uint4>"; + case EbtUSampler2DArray: return "Texture2DArray<uint4>"; + case EbtSampler2DShadow: return "Texture2D"; + case EbtSamplerCubeShadow: return "TextureCube"; + case EbtSampler2DArrayShadow: return "Texture2DArray"; + default: UNREACHABLE(); + } + + return "<unknown texture type>"; +} + +TString OutputHLSL::samplerString(const TType &type) +{ + if (IsShadowSampler(type.getBasicType())) + { + return "SamplerComparisonState"; + } + else + { + return "SamplerState"; + } +} + +TString OutputHLSL::arrayString(const TType &type) +{ + if (!type.isArray()) + { + return ""; + } + + return "[" + str(type.getArraySize()) + "]"; +} + +TString OutputHLSL::initializer(const TType &type) +{ + TString string; + + size_t size = type.getObjectSize(); + for (size_t component = 0; component < size; component++) + { + string += "0"; + + if (component + 1 < size) + { + string += ", "; + } + } + + return "{" + string + "}"; +} + +TString OutputHLSL::structureString(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing) +{ + const TFieldList &fields = structure.fields(); + const bool isNameless = (structure.name() == ""); + const TString &structName = structureTypeName(structure, useHLSLRowMajorPacking, useStd140Packing); + const TString declareString = (isNameless ? "struct" : "struct " + structName); + + TString string; + string += declareString + "\n" + "{\n"; + + int elementIndex = 0; + + for (unsigned int i = 0; i < fields.size(); i++) + { + const TField &field = *fields[i]; + const TType &fieldType = *field.type(); + const TStructure *fieldStruct = fieldType.getStruct(); + const TString &fieldTypeString = fieldStruct ? structureTypeName(*fieldStruct, useHLSLRowMajorPacking, useStd140Packing) : typeString(fieldType); + + if (useStd140Packing) + { + string += std140PrePaddingString(*field.type(), &elementIndex); + } + + string += " " + fieldTypeString + " " + decorateField(field.name(), structure) + arrayString(fieldType) + ";\n"; + + if (useStd140Packing) + { + string += std140PostPaddingString(*field.type(), useHLSLRowMajorPacking); + } + } + + // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable + string += (isNameless ? "} " : "};\n"); + + // Add remaining element index to the global map, for use with nested structs in standard layouts + if (useStd140Packing) + { + mStd140StructElementIndexes[structName] = elementIndex; + } + + return string; +} + +TString OutputHLSL::structureTypeName(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing) +{ + if (structure.name() == "") + { + return ""; + } + + TString prefix = ""; + + // Structs packed with row-major matrices in HLSL are prefixed with "rm" + // GLSL column-major maps to HLSL row-major, and the converse is true + + if (useStd140Packing) + { + prefix += "std"; + } + + if (useHLSLRowMajorPacking) + { + if (prefix != "") prefix += "_"; + prefix += "rm"; + } + + return prefix + structNameString(structure); +} + +void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) +{ + if (name == "") + { + return; // Nameless structures don't have constructors + } + + if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) + { + return; // Already added + } + + TType ctorType = type; + ctorType.clearArrayness(); + ctorType.setPrecision(EbpHigh); + ctorType.setQualifier(EvqTemporary); + + typedef std::vector<TType> ParameterArray; + ParameterArray ctorParameters; + + const TStructure* structure = type.getStruct(); + if (structure) + { + mStructNames.insert(name); + + const TString &structString = structureString(*structure, false, false); + + if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end()) + { + // Add row-major packed struct for interface blocks + TString rowMajorString = "#pragma pack_matrix(row_major)\n" + + structureString(*structure, true, false) + + "#pragma pack_matrix(column_major)\n"; + + TString std140String = structureString(*structure, false, true); + TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + + structureString(*structure, true, true) + + "#pragma pack_matrix(column_major)\n"; + + mStructDeclarations.push_back(structString); + mStructDeclarations.push_back(rowMajorString); + mStructDeclarations.push_back(std140String); + mStructDeclarations.push_back(std140RowMajorString); + } + + const TFieldList &fields = structure->fields(); + for (unsigned int i = 0; i < fields.size(); i++) + { + ctorParameters.push_back(*fields[i]->type()); + } + } + else if (parameters) + { + for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) + { + ctorParameters.push_back((*parameter)->getAsTyped()->getType()); + } + } + else UNREACHABLE(); + + TString constructor; + + if (ctorType.getStruct()) + { + constructor += name + " " + name + "_ctor("; + } + else // Built-in type + { + constructor += typeString(ctorType) + " " + name + "("; + } + + for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) + { + const TType &type = ctorParameters[parameter]; + + constructor += typeString(type) + " x" + str(parameter) + arrayString(type); + + if (parameter < ctorParameters.size() - 1) + { + constructor += ", "; + } + } + + constructor += ")\n" + "{\n"; + + if (ctorType.getStruct()) + { + constructor += " " + name + " structure = {"; + } + else + { + constructor += " return " + typeString(ctorType) + "("; + } + + if (ctorType.isMatrix() && ctorParameters.size() == 1) + { + int rows = ctorType.getRows(); + int cols = ctorType.getCols(); + const TType ¶meter = ctorParameters[0]; + + if (parameter.isScalar()) + { + for (int row = 0; row < rows; row++) + { + for (int col = 0; col < cols; col++) + { + constructor += TString((row == col) ? "x0" : "0.0"); + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else if (parameter.isMatrix()) + { + for (int row = 0; row < rows; row++) + { + for (int col = 0; col < cols; col++) + { + if (row < parameter.getRows() && col < parameter.getCols()) + { + constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]"; + } + else + { + constructor += TString((row == col) ? "1.0" : "0.0"); + } + + if (row < rows - 1 || col < cols - 1) + { + constructor += ", "; + } + } + } + } + else UNREACHABLE(); + } + else + { + size_t remainingComponents = ctorType.getObjectSize(); + size_t parameterIndex = 0; + + while (remainingComponents > 0) + { + const TType ¶meter = ctorParameters[parameterIndex]; + const size_t parameterSize = parameter.getObjectSize(); + bool moreParameters = parameterIndex + 1 < ctorParameters.size(); + + constructor += "x" + str(parameterIndex); + + if (parameter.isScalar()) + { + remainingComponents -= parameter.getObjectSize(); + } + else if (parameter.isVector()) + { + if (remainingComponents == parameterSize || moreParameters) + { + ASSERT(parameterSize <= remainingComponents); + remainingComponents -= parameterSize; + } + else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize())) + { + switch (remainingComponents) + { + case 1: constructor += ".x"; break; + case 2: constructor += ".xy"; break; + case 3: constructor += ".xyz"; break; + case 4: constructor += ".xyzw"; break; + default: UNREACHABLE(); + } + + remainingComponents = 0; + } + else UNREACHABLE(); + } + else if (parameter.isMatrix() || parameter.getStruct()) + { + ASSERT(remainingComponents == parameterSize || moreParameters); + ASSERT(parameterSize <= remainingComponents); + + remainingComponents -= parameterSize; + } + else UNREACHABLE(); + + if (moreParameters) + { + parameterIndex++; + } + + if (remainingComponents) + { + constructor += ", "; + } + } + } + + if (ctorType.getStruct()) + { + constructor += "};\n" + " return structure;\n" + "}\n"; + } + else + { + constructor += ");\n" + "}\n"; + } + + mConstructors.insert(constructor); +} + +const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) +{ + TInfoSinkBase &out = mBody; + + const TStructure* structure = type.getStruct(); + if (structure) + { + out << structNameString(*structure) + "_ctor("; + + const TFieldList& fields = structure->fields(); + + for (size_t i = 0; i < fields.size(); i++) + { + const TType *fieldType = fields[i]->type(); + + constUnion = writeConstantUnion(*fieldType, constUnion); + + if (i != fields.size() - 1) + { + out << ", "; + } + } + + out << ")"; + } + else + { + size_t size = type.getObjectSize(); + bool writeType = size > 1; + + if (writeType) + { + out << typeString(type) << "("; + } + + for (size_t i = 0; i < size; i++, constUnion++) + { + switch (constUnion->getType()) + { + case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break; + case EbtInt: out << constUnion->getIConst(); break; + case EbtUInt: out << constUnion->getUConst(); break; + case EbtBool: out << constUnion->getBConst(); break; + default: UNREACHABLE(); + } + + if (i != size - 1) + { + out << ", "; + } + } + + if (writeType) + { + out << ")"; + } + } + + return constUnion; +} + +TString OutputHLSL::structNameString(const TStructure &structure) +{ + if (structure.name().empty()) + { + return ""; + } + + return "ss_" + str(structure.uniqueId()) + structure.name(); +} + +TString OutputHLSL::decorate(const TString &string) +{ + if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0) + { + return "_" + string; + } + + return string; +} + +TString OutputHLSL::decorateUniform(const TString &string, const TType &type) +{ + if (type.getBasicType() == EbtSamplerExternalOES) + { + return "ex_" + string; + } + + return decorate(string); +} + +TString OutputHLSL::decorateField(const TString &string, const TStructure &structure) +{ + if (structure.name().compare(0, 3, "gl_") != 0) + { + return decorate(string); + } + + return string; +} + +void OutputHLSL::declareInterfaceBlockField(const TType &type, const TString &name, std::vector<gl::InterfaceBlockField>& output) +{ + const TStructure *structure = type.getStruct(); + + if (!structure) + { + const bool isRowMajorMatrix = (type.isMatrix() && type.getLayoutQualifier().matrixPacking == EmpRowMajor); + gl::InterfaceBlockField field(glVariableType(type), glVariablePrecision(type), name.c_str(), + (unsigned int)type.getArraySize(), isRowMajorMatrix); + output.push_back(field); + } + else + { + gl::InterfaceBlockField structField(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), false); + + const TFieldList &fields = structure->fields(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + TField *field = fields[fieldIndex]; + TType *fieldType = field->type(); + + // make sure to copy matrix packing information + fieldType->setLayoutQualifier(type.getLayoutQualifier()); + + declareInterfaceBlockField(*fieldType, field->name(), structField.fields); + } + + output.push_back(structField); + } +} + +gl::Uniform OutputHLSL::declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<gl::Uniform>& output) +{ + const TStructure *structure = type.getStruct(); + + if (!structure) + { + gl::Uniform uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), + (unsigned int)type.getArraySize(), (unsigned int)registerIndex, 0); + output.push_back(uniform); + + return uniform; + } + else + { + gl::Uniform structUniform(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), + (unsigned int)registerIndex, GL_INVALID_INDEX); + + const TFieldList &fields = structure->fields(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + TField *field = fields[fieldIndex]; + TType *fieldType = field->type(); + + declareUniformToList(*fieldType, field->name(), GL_INVALID_INDEX, structUniform.fields); + } + + // assign register offset information -- this will override the information in any sub-structures. + HLSLVariableGetRegisterInfo(registerIndex, &structUniform, mOutputType); + + output.push_back(structUniform); + + return structUniform; + } +} + +gl::InterpolationType getInterpolationType(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqFlatIn: + case EvqFlatOut: + return gl::INTERPOLATION_FLAT; + + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqVaryingIn: + case EvqVaryingOut: + return gl::INTERPOLATION_SMOOTH; + + case EvqCentroidIn: + case EvqCentroidOut: + return gl::INTERPOLATION_CENTROID; + + default: UNREACHABLE(); + return gl::INTERPOLATION_SMOOTH; + } +} + +void OutputHLSL::declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<gl::Varying>& fieldsOut) +{ + const TStructure *structure = type.getStruct(); + + gl::InterpolationType interpolation = getInterpolationType(baseTypeQualifier); + if (!structure) + { + gl::Varying varying(glVariableType(type), glVariablePrecision(type), name.c_str(), (unsigned int)type.getArraySize(), interpolation); + fieldsOut.push_back(varying); + } + else + { + gl::Varying structVarying(GL_STRUCT_ANGLEX, GL_NONE, name.c_str(), (unsigned int)type.getArraySize(), interpolation); + const TFieldList &fields = structure->fields(); + + structVarying.structName = structure->name().c_str(); + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) + { + const TField &field = *fields[fieldIndex]; + declareVaryingToList(*field.type(), baseTypeQualifier, field.name(), structVarying.fields); + } + + fieldsOut.push_back(structVarying); + } +} + +int OutputHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) +{ + int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); + + const gl::Uniform &uniform = declareUniformToList(type, name, registerIndex, mActiveUniforms); + + if (IsSampler(type.getBasicType())) + { + mSamplerRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType); + } + else + { + mUniformRegister += gl::HLSLVariableRegisterCount(uniform, mOutputType); + } + + return registerIndex; +} + +GLenum OutputHLSL::glVariableType(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + if (type.isScalar()) + { + return GL_FLOAT; + } + else if (type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_FLOAT_VEC2; + case 3: return GL_FLOAT_VEC3; + case 4: return GL_FLOAT_VEC4; + default: UNREACHABLE(); + } + } + else if (type.isMatrix()) + { + switch (type.getCols()) + { + case 2: + switch(type.getRows()) + { + case 2: return GL_FLOAT_MAT2; + case 3: return GL_FLOAT_MAT2x3; + case 4: return GL_FLOAT_MAT2x4; + default: UNREACHABLE(); + } + + case 3: + switch(type.getRows()) + { + case 2: return GL_FLOAT_MAT3x2; + case 3: return GL_FLOAT_MAT3; + case 4: return GL_FLOAT_MAT3x4; + default: UNREACHABLE(); + } + + case 4: + switch(type.getRows()) + { + case 2: return GL_FLOAT_MAT4x2; + case 3: return GL_FLOAT_MAT4x3; + case 4: return GL_FLOAT_MAT4; + default: UNREACHABLE(); + } + + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtInt) + { + if (type.isScalar()) + { + return GL_INT; + } + else if (type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_INT_VEC2; + case 3: return GL_INT_VEC3; + case 4: return GL_INT_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtUInt) + { + if (type.isScalar()) + { + return GL_UNSIGNED_INT; + } + else if (type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_UNSIGNED_INT_VEC2; + case 3: return GL_UNSIGNED_INT_VEC3; + case 4: return GL_UNSIGNED_INT_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + else if (type.getBasicType() == EbtBool) + { + if (type.isScalar()) + { + return GL_BOOL; + } + else if (type.isVector()) + { + switch(type.getNominalSize()) + { + case 2: return GL_BOOL_VEC2; + case 3: return GL_BOOL_VEC3; + case 4: return GL_BOOL_VEC4; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + + switch(type.getBasicType()) + { + case EbtSampler2D: return GL_SAMPLER_2D; + case EbtSampler3D: return GL_SAMPLER_3D; + case EbtSamplerCube: return GL_SAMPLER_CUBE; + case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY; + case EbtISampler2D: return GL_INT_SAMPLER_2D; + case EbtISampler3D: return GL_INT_SAMPLER_3D; + case EbtISamplerCube: return GL_INT_SAMPLER_CUBE; + case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY; + case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D; + case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D; + case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE; + case EbtUSampler2DArray: return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY; + case EbtSampler2DShadow: return GL_SAMPLER_2D_SHADOW; + case EbtSamplerCubeShadow: return GL_SAMPLER_CUBE_SHADOW; + case EbtSampler2DArrayShadow: return GL_SAMPLER_2D_ARRAY_SHADOW; + default: UNREACHABLE(); + } + + return GL_NONE; +} + +GLenum OutputHLSL::glVariablePrecision(const TType &type) +{ + if (type.getBasicType() == EbtFloat) + { + switch (type.getPrecision()) + { + case EbpHigh: return GL_HIGH_FLOAT; + case EbpMedium: return GL_MEDIUM_FLOAT; + case EbpLow: return GL_LOW_FLOAT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: UNREACHABLE(); + } + } + else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt) + { + switch (type.getPrecision()) + { + case EbpHigh: return GL_HIGH_INT; + case EbpMedium: return GL_MEDIUM_INT; + case EbpLow: return GL_LOW_INT; + case EbpUndefined: + // Should be defined as the default precision by the parser + default: UNREACHABLE(); + } + } + + // Other types (boolean, sampler) don't have a precision + return GL_NONE; +} + +bool OutputHLSL::isVaryingOut(TQualifier qualifier) +{ + switch(qualifier) + { + case EvqVaryingOut: + case EvqInvariantVaryingOut: + case EvqSmoothOut: + case EvqFlatOut: + case EvqCentroidOut: + case EvqVertexOut: + return true; + + default: break; + } + + return false; +} + +bool OutputHLSL::isVaryingIn(TQualifier qualifier) +{ + switch(qualifier) + { + case EvqVaryingIn: + case EvqInvariantVaryingIn: + case EvqSmoothIn: + case EvqFlatIn: + case EvqCentroidIn: + case EvqFragmentIn: + return true; + + default: break; + } + + return false; +} + +bool OutputHLSL::isVarying(TQualifier qualifier) +{ + return isVaryingIn(qualifier) || isVaryingOut(qualifier); +} + +} diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h new file mode 100644 index 00000000000..ab5a90be6e6 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h @@ -0,0 +1,220 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_OUTPUTHLSL_H_ +#define COMPILER_OUTPUTHLSL_H_ + +#include <list> +#include <set> +#include <map> + +#include <GLES3/gl3.h> +#include <GLES2/gl2.h> + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/ParseContext.h" +#include "common/shadervars.h" + +namespace sh +{ +class UnfoldShortCircuit; + +class OutputHLSL : public TIntermTraverser +{ + public: + OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType); + ~OutputHLSL(); + + void output(); + + TInfoSinkBase &getBodyStream(); + const std::vector<gl::Uniform> &getUniforms(); + const std::vector<gl::InterfaceBlock> &getInterfaceBlocks() const; + const std::vector<gl::Attribute> &getOutputVariables() const; + const std::vector<gl::Attribute> &getAttributes() const; + const std::vector<gl::Varying> &getVaryings() const; + + TString typeString(const TType &type); + TString textureString(const TType &type); + TString samplerString(const TType &type); + TString interpolationString(TQualifier qualifier); + TString structureString(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing); + TString structureTypeName(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing); + static TString qualifierString(TQualifier qualifier); + static TString arrayString(const TType &type); + static TString initializer(const TType &type); + static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes + static TString decorateUniform(const TString &string, const TType &type); + static TString decorateField(const TString &string, const TStructure &structure); + + protected: + void header(); + + // Visit AST nodes and output their code to the body stream + void visitSymbol(TIntermSymbol*); + void visitRaw(TIntermRaw*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + void traverseStatements(TIntermNode *node); + bool isSingleStatement(TIntermNode *node); + bool handleExcessiveLoop(TIntermLoop *node); + void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString); + void outputLineDirective(int line); + TString argumentString(const TIntermSymbol *symbol); + int vectorSize(const TType &type) const; + + void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters); + const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); + + TString structNameString(const TStructure &structure); + + TParseContext &mContext; + const ShShaderOutput mOutputType; + UnfoldShortCircuit *mUnfoldShortCircuit; + bool mInsideFunction; + + // Output streams + TInfoSinkBase mHeader; + TInfoSinkBase mBody; + TInfoSinkBase mFooter; + + typedef std::map<TString, TIntermSymbol*> ReferencedSymbols; + ReferencedSymbols mReferencedUniforms; + ReferencedSymbols mReferencedInterfaceBlocks; + ReferencedSymbols mReferencedAttributes; + ReferencedSymbols mReferencedVaryings; + ReferencedSymbols mReferencedOutputVariables; + + struct TextureFunction + { + enum Method + { + IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) + BIAS, + LOD, + LOD0, + LOD0BIAS, + SIZE, // textureSize() + FETCH, + GRAD + }; + + TBasicType sampler; + int coords; + bool proj; + bool offset; + Method method; + + TString name() const; + + bool operator<(const TextureFunction &rhs) const; + }; + + typedef std::set<TextureFunction> TextureFunctionSet; + + // Parameters determining what goes in the header output + TextureFunctionSet mUsesTexture; + bool mUsesFragColor; + bool mUsesFragData; + bool mUsesDepthRange; + bool mUsesFragCoord; + bool mUsesPointCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesFragDepth; + bool mUsesXor; + bool mUsesMod1; + bool mUsesMod2v; + bool mUsesMod2f; + bool mUsesMod3v; + bool mUsesMod3f; + bool mUsesMod4v; + bool mUsesMod4f; + bool mUsesFaceforward1; + bool mUsesFaceforward2; + bool mUsesFaceforward3; + bool mUsesFaceforward4; + bool mUsesAtan2_1; + bool mUsesAtan2_2; + bool mUsesAtan2_3; + bool mUsesAtan2_4; + bool mUsesDiscardRewriting; + bool mUsesNestedBreak; + + int mNumRenderTargets; + + typedef std::set<TString> Constructors; + Constructors mConstructors; + + typedef std::set<TString> StructNames; + StructNames mStructNames; + + typedef std::list<TString> StructDeclarations; + StructDeclarations mStructDeclarations; + + int mUniqueIndex; // For creating unique names + + bool mContainsLoopDiscontinuity; + bool mOutputLod0Function; + bool mInsideDiscontinuousLoop; + int mNestedLoopDepth; + + TIntermSymbol *mExcessiveLoopIndex; + + int mUniformRegister; + int mInterfaceBlockRegister; + int mSamplerRegister; + int mPaddingCounter; + + TString registerString(TIntermSymbol *operand); + int samplerRegister(TIntermSymbol *sampler); + int uniformRegister(TIntermSymbol *uniform); + void declareInterfaceBlockField(const TType &type, const TString &name, std::vector<gl::InterfaceBlockField>& output); + gl::Uniform declareUniformToList(const TType &type, const TString &name, int registerIndex, std::vector<gl::Uniform>& output); + void declareUniform(const TType &type, const TString &name, int index); + void declareVaryingToList(const TType &type, TQualifier baseTypeQualifier, const TString &name, std::vector<gl::Varying>& fieldsOut); + + // Returns the uniform's register index + int declareUniformAndAssignRegister(const TType &type, const TString &name); + + TString interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, const TField &field); + TString decoratePrivate(const TString &privateText); + TString interfaceBlockStructNameString(const TInterfaceBlock &interfaceBlockType); + TString interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex); + TString interfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage); + TString interfaceBlockFieldString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage); + TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock); + TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex); + TString std140PrePaddingString(const TType &type, int *elementIndex); + TString std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking); + TString structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName); + + static GLenum glVariableType(const TType &type); + static GLenum glVariablePrecision(const TType &type); + static bool isVaryingIn(TQualifier qualifier); + static bool isVaryingOut(TQualifier qualifier); + static bool isVarying(TQualifier qualifier); + + std::vector<gl::Uniform> mActiveUniforms; + std::vector<gl::InterfaceBlock> mActiveInterfaceBlocks; + std::vector<gl::Attribute> mActiveOutputVariables; + std::vector<gl::Attribute> mActiveAttributes; + std::vector<gl::Varying> mActiveVaryings; + std::map<TString, int> mStd140StructElementIndexes; + std::map<TIntermTyped*, TString> mFlaggedStructMappedNames; + std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames; + + void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs); +}; +} + +#endif // COMPILER_OUTPUTHLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp new file mode 100644 index 00000000000..f9009668b02 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp @@ -0,0 +1,2649 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/ParseContext.h" + +#include <stdarg.h> +#include <stdio.h> + +#include "compiler/translator/glslang.h" +#include "compiler/preprocessor/SourceLocation.h" + +/////////////////////////////////////////////////////////////////////// +// +// Sub- vector and matrix fields +// +//////////////////////////////////////////////////////////////////////// + +// +// Look at a '.' field selector string and change it into offsets +// for a vector. +// +bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line) +{ + fields.num = (int) compString.size(); + if (fields.num > 4) { + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + + enum { + exyzw, + ergba, + estpq + } fieldSet[4]; + + for (int i = 0; i < fields.num; ++i) { + switch (compString[i]) { + case 'x': + fields.offsets[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + fields.offsets[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + fields.offsets[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + fields.offsets[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + fields.offsets[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + fields.offsets[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + fields.offsets[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + fields.offsets[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + fields.offsets[i] = 2; + fieldSet[i] = estpq; + break; + + case 'w': + fields.offsets[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + fields.offsets[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + fields.offsets[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(line, "illegal vector field selection", compString.c_str()); + return false; + } + } + + for (int i = 0; i < fields.num; ++i) { + if (fields.offsets[i] >= vecSize) { + error(line, "vector field selection out of range", compString.c_str()); + return false; + } + + if (i > 0) { + if (fieldSet[i] != fieldSet[i-1]) { + error(line, "illegal - vector component fields not from the same set", compString.c_str()); + return false; + } + } + } + + return true; +} + + +// +// Look at a '.' field selector string and change it into offsets +// for a matrix. +// +bool TParseContext::parseMatrixFields(const TString& compString, int matCols, int matRows, TMatrixFields& fields, const TSourceLoc& line) +{ + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = -1; + fields.col = -1; + + if (compString.size() != 2) { + error(line, "illegal length of matrix field selection", compString.c_str()); + return false; + } + + if (compString[0] == '_') { + if (compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeCol = true; + fields.col = compString[1] - '0'; + } else if (compString[1] == '_') { + if (compString[0] < '0' || compString[0] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.wholeRow = true; + fields.row = compString[0] - '0'; + } else { + if (compString[0] < '0' || compString[0] > '3' || + compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str()); + return false; + } + fields.row = compString[0] - '0'; + fields.col = compString[1] - '0'; + } + + if (fields.row >= matRows || fields.col >= matCols) { + error(line, "matrix field selection out of range", compString.c_str()); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////// + +// +// Track whether errors have occurred. +// +void TParseContext::recover() +{ +} + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void TParseContext::error(const TSourceLoc& loc, + const char* reason, const char* token, + const char* extraInfo) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + diagnostics.writeInfo(pp::Diagnostics::PP_ERROR, + srcLoc, reason, token, extraInfo); + +} + +void TParseContext::warning(const TSourceLoc& loc, + const char* reason, const char* token, + const char* extraInfo) { + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + diagnostics.writeInfo(pp::Diagnostics::PP_WARNING, + srcLoc, reason, token, extraInfo); +} + +void TParseContext::trace(const char* str) +{ + diagnostics.writeDebug(str); +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", op, extraInfo.c_str()); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand + << " (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand type", op, extraInfo.c_str()); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right) +{ + std::stringstream extraInfoStream; + extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left + << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)"; + std::string extraInfo = extraInfoStream.str(); + error(line, " wrong operand types ", op, extraInfo.c_str()); +} + +bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){ + if (!checksPrecisionErrors) + return false; + switch( type ){ + case EbtFloat: + if( precision == EbpUndefined ){ + error( line, "No precision specified for (float)", "" ); + return true; + } + break; + case EbtInt: + if( precision == EbpUndefined ){ + error( line, "No precision specified (int)", "" ); + return true; + } + break; + default: + return false; + } + return false; +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if the was an error. +// +bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node) +{ + TIntermSymbol* symNode = node->getAsSymbolNode(); + TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode) { + bool errorReturn; + + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: + return lValueErrorCheck(line, op, binaryNode->getLeft()); + case EOpVectorSwizzle: + errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); + if (!errorReturn) { + int offset[4] = {0,0,0,0}; + + TIntermTyped* rightNode = binaryNode->getRight(); + TIntermAggregate *aggrNode = rightNode->getAsAggregate(); + + for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); + p != aggrNode->getSequence().end(); p++) { + int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0); + offset[value]++; + if (offset[value] > 1) { + error(line, " l-value of swizzle cannot have duplicate components", op); + + return true; + } + } + } + + return errorReturn; + default: + break; + } + error(line, " l-value required", op); + + return true; + } + + + const char* symbol = 0; + if (symNode != 0) + symbol = symNode->getSymbol().c_str(); + + const char* message = 0; + switch (node->getQualifier()) { + case EvqConst: message = "can't modify a const"; break; + case EvqConstReadOnly: message = "can't modify a const"; break; + case EvqAttribute: message = "can't modify an attribute"; break; + case EvqFragmentIn: message = "can't modify an input"; break; + case EvqVertexIn: message = "can't modify an input"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqVaryingIn: message = "can't modify a varying"; break; + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; + case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; + case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + default: + + // + // Type that can't be written to? + // + if (node->getBasicType() == EbtVoid) { + message = "can't modify void"; + } + if (IsSampler(node->getBasicType())) { + message = "can't modify a sampler"; + } + } + + if (message == 0 && binaryNode == 0 && symNode == 0) { + error(line, " l-value required", op); + + return true; + } + + + // + // Everything else is okay, no error. + // + if (message == 0) + return false; + + // + // If we get here, we have an error and a message. + // + if (symNode) { + std::stringstream extraInfoStream; + extraInfoStream << "\"" << symbol << "\" (" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + else { + std::stringstream extraInfoStream; + extraInfoStream << "(" << message << ")"; + std::string extraInfo = extraInfoStream.str(); + error(line, " l-value required", op, extraInfo.c_str()); + } + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// a constant. +// +// Returns true if the was an error. +// +bool TParseContext::constErrorCheck(TIntermTyped* node) +{ + if (node->getQualifier() == EvqConst) + return false; + + error(node->getLine(), "constant expression required", ""); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// an integer. +// +// Returns true if the was an error. +// +bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) +{ + if (node->isScalarInt()) + return false; + + error(node->getLine(), "integer expression required", token); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if we are currently +// globally scoped. +// +// Returns true if the was an error. +// +bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token) +{ + if (global) + return false; + + error(line, "only allowed at global scope", token); + + return true; +} + +// +// For now, keep it simple: if it starts "gl_", it's reserved, independent +// of scope. Except, if the symbol table is at the built-in push-level, +// which is when we are parsing built-ins. +// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a +// webgl shader. +// +// Returns true if there was an error. +// +bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier) +{ + static const char* reservedErrMsg = "reserved built-in name"; + if (!symbolTable.atBuiltInLevel()) { + if (identifier.compare(0, 3, "gl_") == 0) { + error(line, reservedErrMsg, "gl_"); + return true; + } + if (IsWebGLBasedSpec(shaderSpec)) { + if (identifier.compare(0, 6, "webgl_") == 0) { + error(line, reservedErrMsg, "webgl_"); + return true; + } + if (identifier.compare(0, 7, "_webgl_") == 0) { + error(line, reservedErrMsg, "_webgl_"); + return true; + } + if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) { + error(line, reservedErrMsg, "css_"); + return true; + } + } + if (identifier.find("__") != TString::npos) { + error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str()); + return true; + } + } + + return false; +} + +// +// Make sure there is enough data provided to the constructor to build +// something of the type of the constructor. Also returns the type of +// the constructor. +// +// Returns true if there was an error in construction. +// +bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type) +{ + *type = function.getReturnType(); + + bool constructingMatrix = false; + switch(op) { + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + constructingMatrix = true; + break; + default: + break; + } + + // + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop + // again, there is an extra argument, so 'overfull' will become true. + // + + size_t size = 0; + bool constType = true; + bool full = false; + bool overFull = false; + bool matrixInMatrix = false; + bool arrayArg = false; + for (size_t i = 0; i < function.getParamCount(); ++i) { + const TParameter& param = function.getParam(i); + size += param.type->getObjectSize(); + + if (constructingMatrix && param.type->isMatrix()) + matrixInMatrix = true; + if (full) + overFull = true; + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + full = true; + if (param.type->getQualifier() != EvqConst) + constType = false; + if (param.type->isArray()) + arrayArg = true; + } + + if (constType) + type->setQualifier(EvqConst); + + if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) { + error(line, "array constructor needs one argument per array element", "constructor"); + return true; + } + + if (arrayArg && op != EOpConstructStruct) { + error(line, "constructing from a non-dereferenced array", "constructor"); + return true; + } + + if (matrixInMatrix && !type->isArray()) { + if (function.getParamCount() != 1) { + error(line, "constructing matrix from matrix can only take one argument", "constructor"); + return true; + } + } + + if (overFull) { + error(line, "too many arguments", "constructor"); + return true; + } + + if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->fields().size() != function.getParamCount()) { + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor"); + return true; + } + + if (!type->isMatrix() || !matrixInMatrix) { + if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || + (op == EOpConstructStruct && size < type->getObjectSize())) { + error(line, "not enough data provided for construction", "constructor"); + return true; + } + } + + TIntermTyped *typed = node ? node->getAsTyped() : 0; + if (typed == 0) { + error(line, "constructor argument does not have a type", "constructor"); + return true; + } + if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { + error(line, "cannot convert a sampler", "constructor"); + return true; + } + if (typed->getBasicType() == EbtVoid) { + error(line, "cannot convert a void", "constructor"); + return true; + } + + return false; +} + +// This function checks to see if a void variable has been declared and raise an error message for such a case +// +// returns true in case of an error +// +bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType) +{ + if (pubType.type == EbtVoid) { + error(line, "illegal use of type 'void'", identifier.c_str()); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type) +{ + if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType) +{ + if (pType.type != EbtBool || pType.isAggregate()) { + error(line, "boolean expression expected", ""); + return true; + } + + return false; +} + +bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason) +{ + if (pType.type == EbtStruct) { + if (containsSampler(*pType.userDef)) { + error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); + + return true; + } + + return false; + } else if (IsSampler(pType.type)) { + error(line, reason, getBasicString(pType.type)); + + return true; + } + + return false; +} + +bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType) +{ + switch (pType.qualifier) + { + case EvqVaryingIn: + case EvqVaryingOut: + case EvqAttribute: + case EvqVertexIn: + case EvqFragmentOut: + if (pType.type == EbtStruct) + { + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier)); + return true; + } + + default: break; + } + + if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) + return true; + + return false; +} + +bool TParseContext::locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType) +{ + if (pType.layoutQualifier.location != -1) + { + error(line, "location must only be specified for a single input or output variable", "location"); + return true; + } + + return false; +} + +bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type) +{ + if ((qualifier == EvqOut || qualifier == EvqInOut) && + type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { + error(line, "samplers cannot be output parameters", type.getBasicString()); + return true; + } + + return false; +} + +bool TParseContext::containsSampler(TType& type) +{ + if (IsSampler(type.getBasicType())) + return true; + + if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { + const TFieldList& fields = type.getStruct()->fields(); + for (unsigned int i = 0; i < fields.size(); ++i) { + if (containsSampler(*fields[i]->type())) + return true; + } + } + + return false; +} + +// +// Do size checking for an array type's size. +// +// Returns true if there was an error. +// +bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size) +{ + TIntermConstantUnion* constant = expr->getAsConstantUnion(); + + if (constant == 0 || !constant->isScalarInt()) + { + error(line, "array size must be a constant integer expression", ""); + return true; + } + + unsigned int unsignedSize = 0; + + if (constant->getBasicType() == EbtUInt) + { + unsignedSize = constant->getUConst(0); + size = static_cast<int>(unsignedSize); + } + else + { + size = constant->getIConst(0); + + if (size < 0) + { + error(line, "array size must be non-negative", ""); + size = 1; + return true; + } + + unsignedSize = static_cast<unsigned int>(size); + } + + if (size == 0) + { + error(line, "array size must be greater than zero", ""); + size = 1; + return true; + } + + // The size of arrays is restricted here to prevent issues further down the + // compiler/translator/driver stack. Shader Model 5 generation hardware is limited to + // 4096 registers so this should be reasonable even for aggressively optimizable code. + const unsigned int sizeLimit = 65536; + + if (unsignedSize > sizeLimit) + { + error(line, "array size too large", ""); + size = 1; + return true; + } + + return false; +} + +// +// See if this qualifier can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type) +{ + if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConst)) { + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// See if this type can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type) +{ + // + // Can the type be an array? + // + if (type.array) { + error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); + return true; + } + + return false; +} + +// +// Do all the semantic checking for declaring an array, with and +// without a size, and make the right changes to the symbol table. +// +// size == 0 means no specified size. +// +// Returns true if there was an error. +// +bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable) +{ + // + // Don't check for reserved word use until after we know it's not in the symbol table, + // because reserved arrays can be redeclared. + // + + bool builtIn = false; + bool sameScope = false; + TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope); + if (symbol == 0 || !sameScope) { + if (reservedErrorCheck(line, identifier)) + return true; + + variable = new TVariable(&identifier, TType(type)); + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + + if (! symbolTable.declare(*variable)) { + delete variable; + error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str()); + return true; + } + } else { + if (! symbol->isVariable()) { + error(line, "variable expected", identifier.c_str()); + return true; + } + + variable = static_cast<TVariable*>(symbol); + if (! variable->getType().isArray()) { + error(line, "redeclaring non-array as array", identifier.c_str()); + return true; + } + if (variable->getType().getArraySize() > 0) { + error(line, "redeclaration of array with size", identifier.c_str()); + return true; + } + + if (! variable->getType().sameElementType(TType(type))) { + error(line, "redeclaration of array with a different type", identifier.c_str()); + return true; + } + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +// +// Enforce non-initializer type/qualifier rules. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array) +{ + if (type.qualifier == EvqConst) + { + // Make the qualifier make sense. + type.qualifier = EvqTemporary; + + if (array) + { + error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else if (type.isStructureContainingArrays()) + { + error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str()); + } + else + { + error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); + } + + return true; + } + + return false; +} + +// +// Do semantic checking for a variable declaration that has no initializer, +// and update the symbol table. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable) +{ + if (reservedErrorCheck(line, identifier)) + recover(); + + variable = new TVariable(&identifier, TType(type)); + + if (! symbolTable.declare(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + delete variable; + variable = 0; + return true; + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type) +{ + if (qualifier != EvqConst && qualifier != EvqTemporary) { + error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); + return true; + } + if (qualifier == EvqConst && paramQualifier != EvqIn) { + error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier)); + return true; + } + + if (qualifier == EvqConst) + type->setQualifier(EvqConstReadOnly); + else + type->setQualifier(paramQualifier); + + return false; +} + +bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension) +{ + const TExtensionBehavior& extBehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); + if (iter == extBehavior.end()) { + error(line, "extension", extension.c_str(), "is not supported"); + return true; + } + // In GLSL ES, an extension's default behavior is "disable". + if (iter->second == EBhDisable || iter->second == EBhUndefined) { + error(line, "extension", extension.c_str(), "is disabled"); + return true; + } + if (iter->second == EBhWarn) { + warning(line, "extension", extension.c_str(), "is being used"); + return false; + } + + return false; +} + +bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier) +{ + if (structQualifierErrorCheck(identifierLocation, publicType)) + return true; + + // check for layout qualifier issues + const TLayoutQualifier layoutQualifier = publicType.layoutQualifier; + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks"); + return true; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks"); + return true; + } + + if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier)) + { + return true; + } + + return false; +} + +bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier) +{ + if (layoutQualifier.location != -1) + { + error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs"); + return true; + } + + return false; +} + +bool TParseContext::supportsExtension(const char* extension) +{ + const TExtensionBehavior& extbehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); + return (iter != extbehavior.end()); +} + +bool TParseContext::isExtensionEnabled(const char* extension) const +{ + const TExtensionBehavior& extbehavior = extensionBehavior(); + TExtensionBehavior::const_iterator iter = extbehavior.find(extension); + + if (iter == extbehavior.end()) + { + return false; + } + + return (iter->second == EBhEnable || iter->second == EBhRequire); +} + +void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + directiveHandler.handleExtension(srcLoc, extName, behavior); +} + +void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + directiveHandler.handlePragma(srcLoc, name, value); +} + +///////////////////////////////////////////////////////////////////////////////// +// +// Non-Errors. +// +///////////////////////////////////////////////////////////////////////////////// + +// +// Look up a function name in the symbol table, and make sure it is a function. +// +// Return the function symbol if found, otherwise 0. +// +const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn) +{ + // First find by unmangled name to check whether the function name has been + // hidden by a variable name or struct typename. + // If a function is found, check for one with a matching argument list. + const TSymbol* symbol = symbolTable.find(call->getName(), shaderVersion, builtIn); + if (symbol == 0 || symbol->isFunction()) { + symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn); + } + + if (symbol == 0) { + error(line, "no matching overloaded function found", call->getName().c_str()); + return 0; + } + + if (!symbol->isFunction()) { + error(line, "function name expected", call->getName().c_str()); + return 0; + } + + return static_cast<const TFunction*>(symbol); +} + +// +// Initializers show up in several places in the grammar. Have one set of +// code to handle them here. +// +bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) +{ + TType type = TType(pType); + + if (variable == 0) { + if (reservedErrorCheck(line, identifier)) + return true; + + if (voidErrorCheck(line, identifier, pType)) + return true; + + // + // add variable to symbol table + // + variable = new TVariable(&identifier, type); + if (! symbolTable.declare(*variable)) { + error(line, "redefinition", variable->getName().c_str()); + return true; + // don't delete variable, it's used by error recovery, and the pool + // pop will take care of the memory + } + } + + // + // identifier must be of type constant, a global, or a temporary + // + TQualifier qualifier = variable->getType().getQualifier(); + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { + error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString()); + return true; + } + // + // test for and propagate constant + // + + if (qualifier == EvqConst) { + if (qualifier != initializer->getType().getQualifier()) { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " assigning non-constant to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (type != initializer->getType()) { + error(line, " non-matching types for const initializer ", + variable->getType().getQualifierString()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + if (initializer->getAsConstantUnion()) { + variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); + } else if (initializer->getAsSymbolNode()) { + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol(), 0); + const TVariable* tVar = static_cast<const TVariable*>(symbol); + + ConstantUnion* constArray = tVar->getConstPointer(); + variable->shareConstPointer(constArray); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "'" << variable->getType().getCompleteString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, " cannot assign to", "=", extraInfo.c_str()); + variable->getType().setQualifier(EvqTemporary); + return true; + } + } + + if (qualifier != EvqConst) { + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); + intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + if (intermNode == 0) { + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return true; + } + } else + intermNode = 0; + + return false; +} + +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) +{ + ASSERT(aggrNode != NULL); + if (!aggrNode->isConstructor()) + return false; + + bool allConstant = true; + + // check if all the child nodes are constants so that they can be inserted into + // the parent node + TIntermSequence &sequence = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) { + if (!(*p)->getAsTyped()->getAsConstantUnion()) + return false; + } + + return allConstant; +} + +TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier) +{ + TPublicType returnType = typeSpecifier; + returnType.qualifier = qualifier; + returnType.layoutQualifier = layoutQualifier; + + if (typeSpecifier.array) + { + error(typeSpecifier.line, "not supported", "first-class array"); + recover(); + returnType.setArray(false); + } + + if (shaderVersion < 300) + { + if (qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + { + error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); + recover(); + } + + if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) && + (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + { + error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); + recover(); + } + } + else + { + switch (qualifier) + { + case EvqSmoothIn: + case EvqSmoothOut: + case EvqVertexOut: + case EvqFragmentIn: + case EvqCentroidOut: + case EvqCentroidIn: + if (typeSpecifier.type == EbtBool) + { + error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); + recover(); + } + if (typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt) + { + error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier)); + recover(); + } + break; + + case EvqVertexIn: + case EvqFragmentOut: + case EvqFlatIn: + case EvqFlatOut: + if (typeSpecifier.type == EbtBool) + { + error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier)); + recover(); + } + break; + + default: break; + } + } + + return returnType; +} + +TIntermAggregate* TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier) +{ + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); + TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation); + + if (identifier != "") + { + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) + recover(); + + // this error check can mutate the type + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false)) + recover(); + + TVariable* variable = 0; + + if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable)) + recover(); + + if (variable && symbol) + { + symbol->setId(variable->getUniqueId()); + } + } + + return aggregate; +} + +TIntermAggregate* TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression) +{ + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) + recover(); + + // this error check can mutate the type + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true)) + recover(); + + if (arrayTypeErrorCheck(indexLocation, publicType) || arrayQualifierErrorCheck(indexLocation, publicType)) + { + recover(); + } + + TPublicType arrayType = publicType; + + int size; + if (arraySizeErrorCheck(identifierLocation, indexExpression, size)) + { + recover(); + } + else + { + arrayType.setArray(true, size); + } + + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(arrayType), identifierLocation); + TIntermAggregate* aggregate = intermediate.makeAggregate(symbol, identifierLocation); + TVariable* variable = 0; + + if (arrayErrorCheck(identifierLocation, identifier, arrayType, variable)) + recover(); + + if (variable && symbol) + { + symbol->setId(variable->getUniqueId()); + } + + return aggregate; +} + +TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer) +{ + if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier)) + recover(); + + TIntermNode* intermNode; + if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) + { + // + // Build intermediate representation + // + return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : NULL; + } + else + { + recover(); + return NULL; + } +} + +TIntermAggregate* TParseContext::parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier) +{ + if (publicType.type == EbtInvariant && !identifierSymbol) + { + error(identifierLocation, "undeclared identifier declared as invariant", identifier.c_str()); + recover(); + } + + TIntermSymbol* symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); + TIntermAggregate* intermAggregate = intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation); + + if (structQualifierErrorCheck(identifierLocation, publicType)) + recover(); + + if (locationDeclaratorListCheck(identifierLocation, publicType)) + recover(); + + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, false)) + recover(); + + TVariable* variable = 0; + if (nonInitErrorCheck(identifierLocation, identifier, publicType, variable)) + recover(); + if (symbol && variable) + symbol->setId(variable->getUniqueId()); + + return intermAggregate; +} + +TIntermAggregate* TParseContext::parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression) +{ + if (structQualifierErrorCheck(identifierLocation, publicType)) + recover(); + + if (locationDeclaratorListCheck(identifierLocation, publicType)) + recover(); + + if (nonInitConstErrorCheck(identifierLocation, identifier, publicType, true)) + recover(); + + if (arrayTypeErrorCheck(arrayLocation, publicType) || arrayQualifierErrorCheck(arrayLocation, publicType)) + { + recover(); + } + else if (indexExpression) + { + int size; + if (arraySizeErrorCheck(arrayLocation, indexExpression, size)) + recover(); + TPublicType arrayType(publicType); + arrayType.setArray(true, size); + TVariable* variable = NULL; + if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable)) + recover(); + TType type = TType(arrayType); + type.setArraySize(size); + + return intermediate.growAggregate(declaratorList, intermediate.addSymbol(variable ? variable->getUniqueId() : 0, identifier, type, identifierLocation), identifierLocation); + } + else + { + TPublicType arrayType(publicType); + arrayType.setArray(true); + TVariable* variable = NULL; + if (arrayErrorCheck(arrayLocation, identifier, arrayType, variable)) + recover(); + } + + return NULL; +} + +TIntermAggregate* TParseContext::parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer) +{ + if (structQualifierErrorCheck(identifierLocation, publicType)) + recover(); + + if (locationDeclaratorListCheck(identifierLocation, publicType)) + recover(); + + TIntermNode* intermNode; + if (!executeInitializer(identifierLocation, identifier, publicType, initializer, intermNode)) + { + // + // build the intermediate representation + // + if (intermNode) + { + return intermediate.growAggregate(declaratorList, intermNode, initLocation); + } + else + { + return declaratorList; + } + } + else + { + recover(); + return NULL; + } +} + +void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) +{ + if (typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "global layout must be uniform"); + recover(); + return; + } + + const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; + ASSERT(!layoutQualifier.isEmpty()); + + if (shaderVersion < 300) + { + error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout"); + recover(); + return; + } + + if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier)) + { + recover(); + return; + } + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + defaultMatrixPacking = layoutQualifier.matrixPacking; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + defaultBlockStorage = layoutQualifier.blockStorage; + } +} + +TFunction *TParseContext::addConstructorFunc(TPublicType publicType) +{ + TOperator op = EOpNull; + if (publicType.userDef) + { + op = EOpConstructStruct; + } + else + { + switch (publicType.type) + { + case EbtFloat: + if (publicType.isMatrix()) + { + // TODO: non-square matrices + switch(publicType.getCols()) + { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } + else + { + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + + case EbtInt: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructInt; break; + case 2: op = EOpConstructIVec2; break; + case 3: op = EOpConstructIVec3; break; + case 4: op = EOpConstructIVec4; break; + } + break; + + case EbtUInt: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructUInt; break; + case 2: op = EOpConstructUVec2; break; + case 3: op = EOpConstructUVec3; break; + case 4: op = EOpConstructUVec4; break; + } + break; + + case EbtBool: + switch(publicType.getNominalSize()) + { + case 1: op = EOpConstructBool; break; + case 2: op = EOpConstructBVec2; break; + case 3: op = EOpConstructBVec3; break; + case 4: op = EOpConstructBVec4; break; + } + break; + + default: break; + } + + if (op == EOpNull) + { + error(publicType.line, "cannot construct this type", getBasicString(publicType.type)); + recover(); + publicType.type = EbtFloat; + op = EOpConstructFloat; + } + } + + TString tempString; + TType type(publicType); + return new TFunction(&tempString, type, op); +} + +// This function is used to test for the correctness of the parameters passed to various constructor functions +// and also convert them to the right datatype if it is allowed and required. +// +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// +TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggrNode = node->getAsAggregate(); + + TFieldList::const_iterator memberTypes; + if (op == EOpConstructStruct) + memberTypes = type->getStruct()->fields().begin(); + + TType elementType = *type; + if (type->isArray()) + elementType.clearArrayness(); + + bool singleArg; + if (aggrNode) { + if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + singleArg = true; + else + singleArg = false; + } else + singleArg = true; + + TIntermTyped *newNode; + if (singleArg) { + // If structure constructor or array constructor is being called + // for only one parameter inside the structure, we need to call constructStruct function once. + if (type->isArray()) + newNode = constructStruct(node, &elementType, 1, node->getLine(), false); + else if (op == EOpConstructStruct) + newNode = constructStruct(node, (*memberTypes)->type(), 1, node->getLine(), false); + else + newNode = constructBuiltIn(type, op, node, node->getLine(), false); + + if (newNode && newNode->getAsAggregate()) { + TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + } + + return newNode; + } + + // + // Handle list of arguments. + // + TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor + // if the structure constructor contains more than one parameter, then construct + // each parameter + + int paramCount = 0; // keeps a track of the constructor parameter number being checked + + // for each parameter to the constructor call, check to see if the right type is passed or convert them + // to the right type if possible (and allowed). + // for structure constructors, just check if the right type is passed, no conversion is allowed. + + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++, paramCount++) { + if (type->isArray()) + newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); + else if (op == EOpConstructStruct) + newNode = constructStruct(*p, (memberTypes[paramCount])->type(), paramCount+1, node->getLine(), true); + else + newNode = constructBuiltIn(type, op, *p, node->getLine(), true); + + if (newNode) { + *p = newNode; + } + } + + TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); + TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + + return constructor; +} + +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +{ + bool canBeFolded = areAllChildConst(aggrNode); + aggrNode->setType(type); + if (canBeFolded) { + bool returnVal = false; + ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()]; + if (aggrNode->getSequence().size() == 1) { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type, true); + } + else { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), type); + } + if (returnVal) + return 0; + + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + } + + return 0; +} + +// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value +// for the parameter to the constructor (passed to this function). Essentially, it converts +// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a +// float, then float is converted to int. +// +// Returns 0 for an error or the constructed node. +// +TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset) +{ + TIntermTyped* newNode; + TOperator basicOp; + + // + // First, convert types as needed. + // + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + basicOp = EOpConstructFloat; + break; + + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + basicOp = EOpConstructInt; + break; + + case EOpConstructUVec2: + case EOpConstructUVec3: + case EOpConstructUVec4: + case EOpConstructUInt: + basicOp = EOpConstructUInt; + break; + + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + basicOp = EOpConstructBool; + break; + + default: + error(line, "unsupported construction", ""); + recover(); + + return 0; + } + newNode = intermediate.addUnaryMath(basicOp, node, node->getLine()); + if (newNode == 0) { + error(line, "can't convert", "constructor"); + return 0; + } + + // + // Now, if there still isn't an operation to do the construction, and we need one, add one. + // + + // Otherwise, skip out early. + if (subset || (newNode != node && newNode->getType() == *type)) + return newNode; + + // setAggregateOperator will insert a new node for the constructor, as needed. + return intermediate.setAggregateOperator(newNode, op, line); +} + +// This function tests for the type of the parameters to the structures constructors. Raises +// an error message if the expected type does not match the parameter passed to the constructor. +// +// Returns 0 for an error or the input node itself if the expected and the given parameter types match. +// +TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset) +{ + if (*type == node->getAsTyped()->getType()) { + if (subset) + return node->getAsTyped(); + else + return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); + } else { + std::stringstream extraInfoStream; + extraInfoStream << "cannot convert parameter " << paramCount + << " from '" << node->getAsTyped()->getType().getBasicString() + << "' to '" << type->getBasicString() << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "constructor", extraInfo.c_str()); + recover(); + } + + return 0; +} + +// +// This function returns the tree representation for the vector field(s) being accessed from contant vector. +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of +// a constant matrix. +// +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + ConstantUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + + if (!unionArray) { + return node; + } + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error + error(line, "Cannot offset into the vector", "Error"); + recover(); + + return 0; + } + + ConstantUnion* constArray = new ConstantUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getNominalSize()) { + std::stringstream extraInfoStream; + extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + fields.offsets[i] = 0; + } + + constArray[i] = unionArray[fields.offsets[i]]; + + } + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); + return typedNode; +} + +// +// This function returns the column being accessed from a constant matrix. The values are retrieved from +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + if (index >= node->getType().getCols()) { + std::stringstream extraInfoStream; + extraInfoStream << "matrix field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + if (tempConstantNode) { + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + int size = tempConstantNode->getType().getCols(); + typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the matrix", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns an element of an array accessed from a constant array. The values are retrieved from +// the symbol table and parse-tree is built for the type of the element. The input +// to the function could either be a symbol node (a[0] where a is a constant array)that represents a +// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + TType arrayElementType = node->getType(); + arrayElementType.clearArrayness(); + + if (index >= node->getType().getArraySize()) { + std::stringstream extraInfoStream; + extraInfoStream << "array field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(line, "", "[", extraInfo.c_str()); + recover(); + index = 0; + } + + if (tempConstantNode) { + size_t arrayElementSize = arrayElementType.getObjectSize(); + ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the array", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns the value of a particular field inside a constant structure from the symbol table. +// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr +// function and returns the parse-tree with the values of the embedded/nested struct. +// +TIntermTyped* TParseContext::addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line) +{ + const TFieldList& fields = node->getType().getStruct()->fields(); + size_t instanceSize = 0; + + for (size_t index = 0; index < fields.size(); ++index) { + if (fields[index]->name() == identifier) { + break; + } else { + instanceSize += fields[index]->type()->getObjectSize(); + } + } + + TIntermTyped *typedNode; + TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); + if (tempConstantNode) { + ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer(); + + typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function + } else { + error(line, "Cannot offset into the structure", "Error"); + recover(); + + return 0; + } + + return typedNode; +} + +// +// Interface/uniform blocks +// +TIntermAggregate* TParseContext::addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList, + const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine) +{ + if (reservedErrorCheck(nameLine, blockName)) + recover(); + + if (typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform"); + recover(); + } + + TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; + if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier)) + { + recover(); + } + + if (blockLayoutQualifier.matrixPacking == EmpUnspecified) + { + blockLayoutQualifier.matrixPacking = defaultMatrixPacking; + } + + if (blockLayoutQualifier.blockStorage == EbsUnspecified) + { + blockLayoutQualifier.blockStorage = defaultBlockStorage; + } + + TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName); + if (!symbolTable.declare(*blockNameSymbol)) { + error(nameLine, "redefinition", blockName.c_str(), "interface block name"); + recover(); + } + + // check for sampler types and apply layout qualifiers + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) { + TField* field = (*fieldList)[memberIndex]; + TType* fieldType = field->type(); + if (IsSampler(fieldType->getBasicType())) { + error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks"); + recover(); + } + + const TQualifier qualifier = fieldType->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + case EvqUniform: + break; + default: + error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier)); + recover(); + break; + } + + // check layout qualifiers + TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); + if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier)) + { + recover(); + } + + if (fieldLayoutQualifier.blockStorage != EbsUnspecified) + { + error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here"); + recover(); + } + + if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) + { + fieldLayoutQualifier.matrixPacking = blockLayoutQualifier.matrixPacking; + } + else if (!fieldType->isMatrix()) + { + error(field->line(), "invalid layout qualifier:", getMatrixPackingString(fieldLayoutQualifier.matrixPacking), "can only be used on matrix types"); + recover(); + } + + fieldType->setLayoutQualifier(fieldLayoutQualifier); + } + + // add array index + int arraySize = 0; + if (arrayIndex != NULL) + { + if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize)) + recover(); + } + + TInterfaceBlock* interfaceBlock = new TInterfaceBlock(&blockName, fieldList, instanceName, arraySize, blockLayoutQualifier); + TType interfaceBlockType(interfaceBlock, typeQualifier.qualifier, blockLayoutQualifier, arraySize); + + TString symbolName = ""; + int symbolId = 0; + + if (!instanceName) + { + // define symbols for the members of the interface block + for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex) + { + TField* field = (*fieldList)[memberIndex]; + TType* fieldType = field->type(); + + // set parent pointer of the field variable + fieldType->setInterfaceBlock(interfaceBlock); + + TVariable* fieldVariable = new TVariable(&field->name(), *fieldType); + fieldVariable->setQualifier(typeQualifier.qualifier); + + if (!symbolTable.declare(*fieldVariable)) { + error(field->line(), "redefinition", field->name().c_str(), "interface block member name"); + recover(); + } + } + } + else + { + // add a symbol for this interface block + TVariable* instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false); + instanceTypeDef->setQualifier(typeQualifier.qualifier); + + if (!symbolTable.declare(*instanceTypeDef)) { + error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name"); + recover(); + } + + symbolId = instanceTypeDef->getUniqueId(); + symbolName = instanceTypeDef->getName(); + } + + TIntermAggregate *aggregate = intermediate.makeAggregate(intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine); + aggregate->setOp(EOpDeclaration); + + exitStructDeclaration(); + return aggregate; +} + +bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier) +{ + ++structNestingLevel; + + // Embedded structure definitions are not supported per GLSL ES spec. + // They aren't allowed in GLSL either, but we need to detect this here + // so we don't rely on the GLSL compiler to catch it. + if (structNestingLevel > 1) { + error(line, "", "Embedded struct definitions are not allowed"); + return true; + } + + return false; +} + +void TParseContext::exitStructDeclaration() +{ + --structNestingLevel; +} + +namespace { + +const int kWebGLMaxStructNesting = 4; + +} // namespace + +bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field) +{ + if (!IsWebGLBasedSpec(shaderSpec)) { + return false; + } + + if (field.type()->getBasicType() != EbtStruct) { + return false; + } + + // We're already inside a structure definition at this point, so add + // one to the field's struct nesting. + if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) { + std::stringstream reasonStream; + reasonStream << "Reference of struct type " + << field.type()->getStruct()->name().c_str() + << " exceeds maximum allowed nesting level of " + << kWebGLMaxStructNesting; + std::string reason = reasonStream.str(); + error(line, reason.c_str(), field.name().c_str(), ""); + return true; + } + + return false; +} + +// +// Parse an array index expression +// +TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression) +{ + TIntermTyped *indexedExpression = NULL; + + if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) + { + if (baseExpression->getAsSymbolNode()) + { + error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str()); + } + else + { + error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); + } + recover(); + } + + if (indexExpression->getQualifier() == EvqConst) + { + int index = indexExpression->getAsConstantUnion()->getIConst(0); + if (index < 0) + { + std::stringstream infoStream; + infoStream << index; + std::string info = infoStream.str(); + error(location, "negative index", info.c_str()); + recover(); + index = 0; + } + if (baseExpression->getType().getQualifier() == EvqConst) + { + if (baseExpression->isArray()) + { + // constant folding for arrays + indexedExpression = addConstArrayNode(index, baseExpression, location); + } + else if (baseExpression->isVector()) + { + // constant folding for vectors + TVectorFields fields; + fields.num = 1; + fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array + indexedExpression = addConstVectorNode(fields, baseExpression, location); + } + else if (baseExpression->isMatrix()) + { + // constant folding for matrices + indexedExpression = addConstMatrixNode(index, baseExpression, location); + } + } + else + { + if (baseExpression->isArray()) + { + if (index >= baseExpression->getType().getArraySize()) + { + std::stringstream extraInfoStream; + extraInfoStream << "array index out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(location, "", "[", extraInfo.c_str()); + recover(); + index = baseExpression->getType().getArraySize() - 1; + } + else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers")) + { + error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled"); + recover(); + index = 0; + } + } + else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index) + { + std::stringstream extraInfoStream; + extraInfoStream << "field selection out of range '" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + error(location, "", "[", extraInfo.c_str()); + recover(); + index = baseExpression->getType().getNominalSize() - 1; + } + + indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index); + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); + } + } + else + { + if (baseExpression->isInterfaceBlock()) + { + error(location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions"); + recover(); + } + else if (baseExpression->getQualifier() == EvqFragmentOut) + { + error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions"); + recover(); + } + + indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); + } + + if (indexedExpression == 0) + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location); + } + else if (baseExpression->isArray()) + { + const TType &baseType = baseExpression->getType(); + if (baseType.getStruct()) + { + TType copyOfType(baseType.getStruct()); + indexedExpression->setType(copyOfType); + } + else if (baseType.isInterfaceBlock()) + { + TType copyOfType(baseType.getInterfaceBlock(), baseType.getQualifier(), baseType.getLayoutQualifier(), 0); + indexedExpression->setType(copyOfType); + } + else + { + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->getSecondarySize())); + } + + if (baseExpression->getType().getQualifier() == EvqConst) + { + indexedExpression->getTypePointer()->setQualifier(EvqConst); + } + } + else if (baseExpression->isMatrix()) + { + TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary; + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getRows())); + } + else if (baseExpression->isVector()) + { + TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary; + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier)); + } + else + { + indexedExpression->setType(baseExpression->getType()); + } + + return indexedExpression; +} + +TIntermTyped* TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation) +{ + TIntermTyped *indexedExpression = NULL; + + if (baseExpression->isArray()) + { + error(fieldLocation, "cannot apply dot operator to an array", "."); + recover(); + } + + if (baseExpression->isVector()) + { + TVectorFields fields; + if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields, fieldLocation)) + { + fields.num = 1; + fields.offsets[0] = 0; + recover(); + } + + if (baseExpression->getType().getQualifier() == EvqConst) + { + // constant folding for vector fields + indexedExpression = addConstVectorNode(fields, baseExpression, fieldLocation); + if (indexedExpression == 0) + { + recover(); + indexedExpression = baseExpression; + } + else + { + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqConst, (int) (fieldString).size())); + } + } + else + { + TString vectorString = fieldString; + TIntermTyped* index = intermediate.addSwizzle(fields, fieldLocation); + indexedExpression = intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, (int) vectorString.size())); + } + } + else if (baseExpression->isMatrix()) + { + TMatrixFields fields; + if (!parseMatrixFields(fieldString, baseExpression->getCols(), baseExpression->getRows(), fields, fieldLocation)) + { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + recover(); + } + + if (fields.wholeRow || fields.wholeCol) + { + error(dotLocation, " non-scalar fields not implemented yet", "."); + recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(),EvqTemporary, baseExpression->getCols(), baseExpression->getRows())); + } + else + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(fields.col * baseExpression->getRows() + fields.row); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, index, dotLocation); + indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision())); + } + } + else if (baseExpression->getBasicType() == EbtStruct) + { + bool fieldFound = false; + const TFieldList& fields = baseExpression->getType().getStruct()->fields(); + if (fields.empty()) + { + error(dotLocation, "structure has no fields", "Internal Error"); + recover(); + indexedExpression = baseExpression; + } + else + { + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + if (baseExpression->getType().getQualifier() == EvqConst) + { + indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation); + if (indexedExpression == 0) + { + recover(); + indexedExpression = baseExpression; + } + else + { + indexedExpression->setType(*fields[i]->type()); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + indexedExpression->getTypePointer()->setQualifier(EvqConst); + } + } + else + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation); + indexedExpression->setType(*fields[i]->type()); + } + } + else + { + error(dotLocation, " no such field in structure", fieldString.c_str()); + recover(); + indexedExpression = baseExpression; + } + } + } + else if (baseExpression->isInterfaceBlock()) + { + bool fieldFound = false; + const TFieldList& fields = baseExpression->getType().getInterfaceBlock()->fields(); + if (fields.empty()) + { + error(dotLocation, "interface block has no fields", "Internal Error"); + recover(); + indexedExpression = baseExpression; + } + else + { + unsigned int i; + for (i = 0; i < fields.size(); ++i) + { + if (fields[i]->name() == fieldString) + { + fieldFound = true; + break; + } + } + if (fieldFound) + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); + indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, dotLocation); + indexedExpression->setType(*fields[i]->type()); + } + else + { + error(dotLocation, " no such field in interface block", fieldString.c_str()); + recover(); + indexedExpression = baseExpression; + } + } + } + else + { + if (shaderVersion < 300) + { + error(dotLocation, " field selection requires structure, vector, or matrix on left hand side", fieldString.c_str()); + } + else + { + error(dotLocation, " field selection requires structure, vector, matrix, or interface block on left hand side", fieldString.c_str()); + } + recover(); + indexedExpression = baseExpression; + } + + return indexedExpression; +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine) +{ + TLayoutQualifier qualifier; + + qualifier.location = -1; + qualifier.matrixPacking = EmpUnspecified; + qualifier.blockStorage = EbsUnspecified; + + if (qualifierType == "shared") + { + qualifier.blockStorage = EbsShared; + } + else if (qualifierType == "packed") + { + qualifier.blockStorage = EbsPacked; + } + else if (qualifierType == "std140") + { + qualifier.blockStorage = EbsStd140; + } + else if (qualifierType == "row_major") + { + qualifier.matrixPacking = EmpRowMajor; + } + else if (qualifierType == "column_major") + { + qualifier.matrixPacking = EmpColumnMajor; + } + else if (qualifierType == "location") + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument"); + recover(); + } + else + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); + recover(); + } + + return qualifier; +} + +TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine) +{ + TLayoutQualifier qualifier; + + qualifier.location = -1; + qualifier.matrixPacking = EmpUnspecified; + qualifier.blockStorage = EbsUnspecified; + + if (qualifierType != "location") + { + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "only location may have arguments"); + recover(); + } + else + { + // must check that location is non-negative + if (intValue < 0) + { + error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative"); + recover(); + } + else + { + qualifier.location = intValue; + } + } + + return qualifier; +} + +TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier) +{ + TLayoutQualifier joinedQualifier = leftQualifier; + + if (rightQualifier.location != -1) + { + joinedQualifier.location = rightQualifier.location; + } + if (rightQualifier.matrixPacking != EmpUnspecified) + { + joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + } + if (rightQualifier.blockStorage != EbsUnspecified) + { + joinedQualifier.blockStorage = rightQualifier.blockStorage; + } + + return joinedQualifier; +} + +TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, + const TSourceLoc &storageLoc, TQualifier storageQualifier) +{ + TQualifier mergedQualifier = EvqSmoothIn; + + if (storageQualifier == EvqFragmentIn) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqSmoothIn; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatIn; + else UNREACHABLE(); + } + else if (storageQualifier == EvqCentroidIn) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqCentroidIn; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatIn; + else UNREACHABLE(); + } + else if (storageQualifier == EvqVertexOut) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqSmoothOut; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatOut; + else UNREACHABLE(); + } + else if (storageQualifier == EvqCentroidOut) { + if (interpolationQualifier == EvqSmooth) + mergedQualifier = EvqCentroidOut; + else if (interpolationQualifier == EvqFlat) + mergedQualifier = EvqFlatOut; + else UNREACHABLE(); + } + else { + error(interpolationLoc, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString(interpolationQualifier)); + recover(); + + mergedQualifier = storageQualifier; + } + + TPublicType type; + type.setBasic(EbtVoid, mergedQualifier, storageLoc); + return type; +} + +TFieldList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList) +{ + if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier)) { + recover(); + } + + for (unsigned int i = 0; i < fieldList->size(); ++i) { + // + // Careful not to replace already known aspects of type, like array-ness + // + TType* type = (*fieldList)[i]->type(); + type->setBasicType(typeSpecifier.type); + type->setPrimarySize(typeSpecifier.primarySize); + type->setSecondarySize(typeSpecifier.secondarySize); + type->setPrecision(typeSpecifier.precision); + type->setQualifier(typeSpecifier.qualifier); + type->setLayoutQualifier(typeSpecifier.layoutQualifier); + + // don't allow arrays of arrays + if (type->isArray()) { + if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier)) + recover(); + } + if (typeSpecifier.array) + type->setArraySize(typeSpecifier.arraySize); + if (typeSpecifier.userDef) { + type->setStruct(typeSpecifier.userDef->getStruct()); + } + + if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) { + recover(); + } + } + + return fieldList; +} + +TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList) +{ + TStructure* structure = new TStructure(structName, fieldList); + TType* structureType = new TType(structure); + + structure->setUniqueId(TSymbolTable::nextUniqueId()); + + if (!structName->empty()) + { + if (reservedErrorCheck(nameLine, *structName)) + { + recover(); + } + TVariable* userTypeDef = new TVariable(structName, *structureType, true); + if (!symbolTable.declare(*userTypeDef)) { + error(nameLine, "redefinition", structName->c_str(), "struct"); + recover(); + } + } + + // ensure we do not specify any storage qualifiers on the struct members + for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++) + { + const TField &field = *(*fieldList)[typeListIndex]; + const TQualifier qualifier = field.type()->getQualifier(); + switch (qualifier) + { + case EvqGlobal: + case EvqTemporary: + break; + default: + error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier)); + recover(); + break; + } + } + + TPublicType publicType; + publicType.setBasic(EbtStruct, EvqTemporary, structLine); + publicType.userDef = structureType; + exitStructDeclaration(); + + return publicType; +} + +// +// Parse an array of strings using yyparse. +// +// Returns 0 for success. +// +int PaParseStrings(size_t count, const char* const string[], const int length[], + TParseContext* context) { + if ((count == 0) || (string == NULL)) + return 1; + + if (glslang_initialize(context)) + return 1; + + int error = glslang_scan(count, string, length, context); + if (!error) + error = glslang_parse(context); + + glslang_finalize(context); + + return (error == 0) && (context->numErrors() == 0) ? 0 : 1; +} + + + diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.h b/chromium/third_party/angle/src/compiler/translator/ParseContext.h new file mode 100644 index 00000000000..3cd4b915e3c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.h @@ -0,0 +1,169 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef _PARSER_HELPER_INCLUDED_ +#define _PARSER_HELPER_INCLUDED_ + +#include "compiler/translator/Diagnostics.h" +#include "compiler/translator/DirectiveHandler.h" +#include "compiler/translator/localintermediate.h" +#include "compiler/translator/ShHandle.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/preprocessor/Preprocessor.h" + +struct TMatrixFields { + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +// +// The following are extra variables needed during parsing, grouped together so +// they can be passed to the parser without needing a global. +// +struct TParseContext { + TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : + intermediate(interm), + symbolTable(symt), + shaderType(type), + shaderSpec(spec), + compileOptions(options), + sourcePath(sourcePath), + treeRoot(0), + loopNestingLevel(0), + structNestingLevel(0), + currentFunctionType(NULL), + functionReturnsValue(false), + checksPrecisionErrors(checksPrecErrors), + defaultMatrixPacking(EmpColumnMajor), + defaultBlockStorage(EbsShared), + diagnostics(is), + shaderVersion(100), + directiveHandler(ext, diagnostics, shaderVersion), + preprocessor(&diagnostics, &directiveHandler), + scanner(NULL) { } + TIntermediate& intermediate; // to hold and build a parse tree + TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed + ShShaderType shaderType; // vertex or fragment language (future: pack or unpack) + ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + int shaderVersion; + int compileOptions; + const char* sourcePath; // Path of source file or NULL. + TIntermNode* treeRoot; // root of parse tree being created + int loopNestingLevel; // 0 if outside all loops + int structNestingLevel; // incremented while parsing a struct declaration + const TType* currentFunctionType; // the return type of the function that's currently being parsed + bool functionReturnsValue; // true if a non-void function has a return + bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit. + bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language. + TLayoutMatrixPacking defaultMatrixPacking; + TLayoutBlockStorage defaultBlockStorage; + TString HashErrMsg; + TDiagnostics diagnostics; + TDirectiveHandler directiveHandler; + pp::Preprocessor preprocessor; + void* scanner; + + int getShaderVersion() const { return shaderVersion; } + int numErrors() const { return diagnostics.numErrors(); } + TInfoSink& infoSink() { return diagnostics.infoSink(); } + void error(const TSourceLoc& loc, const char *reason, const char* token, + const char* extraInfo=""); + void warning(const TSourceLoc& loc, const char* reason, const char* token, + const char* extraInfo=""); + void trace(const char* str); + void recover(); + + bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line); + bool parseMatrixFields(const TString&, int matCols, int matRows, TMatrixFields&, const TSourceLoc& line); + + bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier); + void assignError(const TSourceLoc& line, const char* op, TString left, TString right); + void unaryOpError(const TSourceLoc& line, const char* op, TString operand); + void binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right); + bool precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type); + bool lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped*); + bool constErrorCheck(TIntermTyped* node); + bool integerErrorCheck(TIntermTyped* node, const char* token); + bool globalErrorCheck(const TSourceLoc& line, bool global, const char* token); + bool constructorErrorCheck(const TSourceLoc& line, TIntermNode*, TFunction&, TOperator, TType*); + bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size); + bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type); + bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type); + bool arrayErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType &type, TVariable*& variable); + bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&); + bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*); + bool boolErrorCheck(const TSourceLoc&, const TPublicType&); + bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason); + bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType); + bool locationDeclaratorListCheck(const TSourceLoc& line, const TPublicType &pType); + bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type); + bool nonInitConstErrorCheck(const TSourceLoc& line, const TString& identifier, TPublicType& type, bool array); + bool nonInitErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& type, TVariable*& variable); + bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type); + bool extensionErrorCheck(const TSourceLoc& line, const TString&); + bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier); + bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier); + + const TPragma& pragma() const { return directiveHandler.pragma(); } + const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } + bool supportsExtension(const char* extension); + bool isExtensionEnabled(const char* extension) const; + void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior); + void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value); + + bool containsSampler(TType& type); + bool areAllChildConst(TIntermAggregate* aggrNode); + const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int shaderVersion, bool *builtIn = 0); + bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); + + TPublicType addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier); + TPublicType addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier); + TIntermAggregate* parseSingleDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier); + TIntermAggregate* parseSingleArrayDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& indexLocation, TIntermTyped *indexExpression); + TIntermAggregate* parseSingleInitDeclaration(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer); + TIntermAggregate* parseDeclarator(TPublicType &publicType, TIntermAggregate *aggregateDeclaration, TSymbol *identifierSymbol, const TSourceLoc& identifierLocation, const TString &identifier); + TIntermAggregate* parseArrayDeclarator(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& arrayLocation, TIntermNode *declaratorList, TIntermTyped *indexExpression); + TIntermAggregate* parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer); + void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); + TFunction *addConstructorFunc(TPublicType publicType); + TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&); + TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); + TIntermTyped* constructStruct(TIntermNode*, TType*, int, const TSourceLoc&, bool subset); + TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, const TSourceLoc&, bool subset); + TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); + TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&); + TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line); + TIntermTyped* addConstStruct(const TString &identifier, TIntermTyped *node, const TSourceLoc& line); + TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression); + TIntermTyped* addFieldSelectionExpression(TIntermTyped *baseExpression, const TSourceLoc& dotLocation, const TString &fieldString, const TSourceLoc& fieldLocation); + + TFieldList *addStructDeclaratorList(const TPublicType& typeSpecifier, TFieldList *fieldList); + TPublicType addStructure(const TSourceLoc& structLine, const TSourceLoc& nameLine, const TString *structName, TFieldList* fieldList); + + TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, const TSourceLoc& nameLine, const TString& blockName, TFieldList* fieldList, + const TString* instanceName, const TSourceLoc& instanceLine, TIntermTyped* arrayIndex, const TSourceLoc& arrayIndexLine); + + TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine); + TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc& qualifierTypeLine, const TString &intValueString, int intValue, const TSourceLoc& intValueLine); + TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier); + TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, + const TSourceLoc &storageLoc, TQualifier storageQualifier); + + // Performs an error check for embedded struct declarations. + // Returns true if an error was raised due to the declaration of + // this struct. + bool enterStructDeclaration(const TSourceLoc& line, const TString& identifier); + void exitStructDeclaration(); + + bool structNestingErrorCheck(const TSourceLoc& line, const TField& field); +}; + +int PaParseStrings(size_t count, const char* const string[], const int length[], + TParseContext* context); + +#endif // _PARSER_HELPER_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp new file mode 100644 index 00000000000..abe70262f2d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp @@ -0,0 +1,294 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/PoolAlloc.h" + +#ifndef _MSC_VER +#include <stdint.h> +#endif +#include <stdio.h> + +#include "common/angleutils.h" +#include "compiler/translator/InitializeGlobals.h" +#include "compiler/translator/osinclude.h" + +OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX; + +bool InitializePoolIndex() +{ + assert(PoolIndex == OS_INVALID_TLS_INDEX); + + PoolIndex = OS_AllocTLSIndex(); + return PoolIndex != OS_INVALID_TLS_INDEX; +} + +void FreePoolIndex() +{ + assert(PoolIndex != OS_INVALID_TLS_INDEX); + + OS_FreeTLSIndex(PoolIndex); + PoolIndex = OS_INVALID_TLS_INDEX; +} + +TPoolAllocator* GetGlobalPoolAllocator() +{ + assert(PoolIndex != OS_INVALID_TLS_INDEX); + return static_cast<TPoolAllocator*>(OS_GetTLSValue(PoolIndex)); +} + +void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) +{ + assert(PoolIndex != OS_INVALID_TLS_INDEX); + OS_SetTLSValue(PoolIndex, poolAllocator); +} + +// +// Implement the functionality of the TPoolAllocator class, which +// is documented in PoolAlloc.h. +// +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : + pageSize(growthIncrement), + alignment(allocationAlignment), + freeList(0), + inUseList(0), + numCalls(0), + totalBytes(0) +{ + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4*1024) + pageSize = 4*1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + + // + // Adjust alignment to be at least pointer aligned and + // power of 2. + // + size_t minAlign = sizeof(void*); + alignment &= ~(minAlign - 1); + if (alignment < minAlign) + alignment = minAlign; + size_t a = 1; + while (a < alignment) + a <<= 1; + alignment = a; + alignmentMask = a - 1; + + // + // Align header skip + // + headerSkip = minAlign; + if (headerSkip < sizeof(tHeader)) { + headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; + } +} + +TPoolAllocator::~TPoolAllocator() +{ + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast<char*>(inUseList); + inUseList = next; + } + + // We should not check the guard blocks + // here, because we did it already when the block was + // placed into the free list. + // + while (freeList) { + tHeader* next = freeList->nextPage; + delete [] reinterpret_cast<char*>(freeList); + freeList = next; + } +} + +// Support MSVC++ 6.0 +const unsigned char TAllocation::guardBlockBeginVal = 0xfb; +const unsigned char TAllocation::guardBlockEndVal = 0xfe; +const unsigned char TAllocation::userDataFill = 0xcd; + +#ifdef GUARD_BLOCKS + const size_t TAllocation::guardBlockSize = 16; +#else + const size_t TAllocation::guardBlockSize = 0; +#endif + +// +// Check a single guard block for damage +// +void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const +{ +#ifdef GUARD_BLOCKS + for (size_t x = 0; x < guardBlockSize; x++) { + if (blockMem[x] != val) { + char assertMsg[80]; + + // We don't print the assert message. It's here just to be helpful. +#if defined(_MSC_VER) + snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n", + locText, size, data()); +#else + snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", + locText, size, data()); +#endif + assert(0 && "PoolAlloc: Damage in guard block"); + } + } +#endif +} + + +void TPoolAllocator::push() +{ + tAllocState state = { currentPageOffset, inUseList }; + + stack.push_back(state); + + // + // Indicate there is no current page to allocate from. + // + currentPageOffset = pageSize; +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred since the last push(), or since the +// last pop(), or since the object's creation. +// +// The deallocated pages are saved for future allocations. +// +void TPoolAllocator::pop() +{ + if (stack.size() < 1) + return; + + tHeader* page = stack.back().page; + currentPageOffset = stack.back().offset; + + while (inUseList != page) { + // invoke destructor to free allocation list + inUseList->~tHeader(); + + tHeader* nextInUse = inUseList->nextPage; + if (inUseList->pageCount > 1) + delete [] reinterpret_cast<char*>(inUseList); + else { + inUseList->nextPage = freeList; + freeList = inUseList; + } + inUseList = nextInUse; + } + + stack.pop_back(); +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred. +// +void TPoolAllocator::popAll() +{ + while (stack.size() > 0) + pop(); +} + +void* TPoolAllocator::allocate(size_t numBytes) +{ + // + // Just keep some interesting statistics. + // + ++numCalls; + totalBytes += numBytes; + + // If we are using guard blocks, all allocations are bracketed by + // them: [guardblock][allocation][guardblock]. numBytes is how + // much memory the caller asked for. allocationSize is the total + // size including guard blocks. In release build, + // guardBlockSize=0 and this all gets optimized away. + size_t allocationSize = TAllocation::allocationSize(numBytes); + // Detect integer overflow. + if (allocationSize < numBytes) + return 0; + + // + // Do the allocation, most likely case first, for efficiency. + // This step could be moved to be inline sometime. + // + if (allocationSize <= pageSize - currentPageOffset) { + // + // Safe to allocate from currentPageOffset. + // + unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset; + currentPageOffset += allocationSize; + currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, memory, numBytes); + } + + if (allocationSize > pageSize - headerSkip) { + // + // Do a multi-page allocation. Don't mix these with the others. + // The OS is efficient and allocating and free-ing multiple pages. + // + size_t numBytesToAlloc = allocationSize + headerSkip; + // Detect integer overflow. + if (numBytesToAlloc < allocationSize) + return 0; + + tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]); + if (memory == 0) + return 0; + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); + inUseList = memory; + + currentPageOffset = pageSize; // make next allocation come from a new page + + // No guard blocks for multi-page allocations (yet) + return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip); + } + + // + // Need a simple page to allocate from. + // + tHeader* memory; + if (freeList) { + memory = freeList; + freeList = freeList->nextPage; + } else { + memory = reinterpret_cast<tHeader*>(::new char[pageSize]); + if (memory == 0) + return 0; + } + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, 1); + inUseList = memory; + + unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip; + currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, ret, numBytes); +} + + +// +// Check all allocations in a list for damage by calling check on each. +// +void TAllocation::checkAllocList() const +{ + for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + alloc->check(); +} diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h new file mode 100644 index 00000000000..edd249c4d3a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h @@ -0,0 +1,300 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _POOLALLOC_INCLUDED_ +#define _POOLALLOC_INCLUDED_ + +#ifdef _DEBUG +#define GUARD_BLOCKS // define to enable guard block sanity checking +#endif + +// +// This header defines an allocator that can be used to efficiently +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather +// collectively deallocated at one time. +// +// This simultaneously +// +// * Makes each individual allocation much more efficient; the +// typical allocation is trivial. +// * Completely avoids the cost of doing individual deallocation. +// * Saves the trouble of tracking down and plugging a large class of leaks. +// +// Individual classes can use this allocator by supplying their own +// new and delete methods. +// +// STL containers can use this allocator by using the pool_allocator +// class as the allocator (second) template argument. +// + +#include <stddef.h> +#include <string.h> +#include <vector> + +// If we are using guard blocks, we must track each indivual +// allocation. If we aren't using guard blocks, these +// never get instantiated, so won't have any impact. +// + +class TAllocation { +public: + TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : + size(size), mem(mem), prevAlloc(prev) { + // Allocations are bracketed: + // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] + // This would be cleaner with if (guardBlockSize)..., but that + // makes the compiler print warnings about 0 length memsets, + // even with the if() protecting them. +#ifdef GUARD_BLOCKS + memset(preGuard(), guardBlockBeginVal, guardBlockSize); + memset(data(), userDataFill, size); + memset(postGuard(), guardBlockEndVal, guardBlockSize); +#endif + } + + void check() const { + checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); + checkGuardBlock(postGuard(), guardBlockEndVal, "after"); + } + + void checkAllocList() const; + + // Return total size needed to accomodate user buffer of 'size', + // plus our tracking data. + inline static size_t allocationSize(size_t size) { + return size + 2 * guardBlockSize + headerSize(); + } + + // Offset from surrounding buffer to get to user data buffer. + inline static unsigned char* offsetAllocation(unsigned char* m) { + return m + guardBlockSize + headerSize(); + } + +private: + void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const; + + // Find offsets to pre and post guard blocks, and user data buffer + unsigned char* preGuard() const { return mem + headerSize(); } + unsigned char* data() const { return preGuard() + guardBlockSize; } + unsigned char* postGuard() const { return data() + size; } + + size_t size; // size of the user data area + unsigned char* mem; // beginning of our allocation (pts to header) + TAllocation* prevAlloc; // prior allocation in the chain + + // Support MSVC++ 6.0 + const static unsigned char guardBlockBeginVal; + const static unsigned char guardBlockEndVal; + const static unsigned char userDataFill; + + const static size_t guardBlockSize; +#ifdef GUARD_BLOCKS + inline static size_t headerSize() { return sizeof(TAllocation); } +#else + inline static size_t headerSize() { return 0; } +#endif +}; + +// +// There are several stacks. One is to track the pushing and popping +// of the user, and not yet implemented. The others are simply a +// repositories of free pages or used pages. +// +// Page stacks are linked together with a simple header at the beginning +// of each allocation obtained from the underlying OS. Multi-page allocations +// are returned to the OS. Individual page allocations are kept for future +// re-use. +// +// The "page size" used is not, nor must it match, the underlying OS +// page size. But, having it be about that size or equal to a set of +// pages is likely most optimal. +// +class TPoolAllocator { +public: + TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16); + + // + // Don't call the destructor just to free up the memory, call pop() + // + ~TPoolAllocator(); + + // + // Call push() to establish a new place to pop memory too. Does not + // have to be called to get things started. + // + void push(); + + // + // Call pop() to free all memory allocated since the last call to push(), + // or if no last call to push, frees all memory since first allocation. + // + void pop(); + + // + // Call popAll() to free all memory allocated. + // + void popAll(); + + // + // Call allocate() to actually acquire memory. Returns 0 if no memory + // available, otherwise a properly aligned pointer to 'numBytes' of memory. + // + void* allocate(size_t numBytes); + + // + // There is no deallocate. The point of this class is that + // deallocation can be skipped by the user of it, as the model + // of use is to simultaneously deallocate everything at once + // by calling pop(), and to not have to solve memory leak problems. + // + +protected: + friend struct tHeader; + + struct tHeader { + tHeader(tHeader* nextPage, size_t pageCount) : + nextPage(nextPage), + pageCount(pageCount) +#ifdef GUARD_BLOCKS + , lastAllocation(0) +#endif + { } + + ~tHeader() { +#ifdef GUARD_BLOCKS + if (lastAllocation) + lastAllocation->checkAllocList(); +#endif + } + + tHeader* nextPage; + size_t pageCount; +#ifdef GUARD_BLOCKS + TAllocation* lastAllocation; +#endif + }; + + struct tAllocState { + size_t offset; + tHeader* page; + }; + typedef std::vector<tAllocState> tAllocStack; + + // Track allocations if and only if we're using guard blocks + void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) { +#ifdef GUARD_BLOCKS + new(memory) TAllocation(numBytes, memory, block->lastAllocation); + block->lastAllocation = reinterpret_cast<TAllocation*>(memory); +#endif + // This is optimized entirely away if GUARD_BLOCKS is not defined. + return TAllocation::offsetAllocation(memory); + } + + size_t pageSize; // granularity of allocation from the OS + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + size_t headerSkip; // amount of memory to skip to make room for the + // header (basically, size of header, rounded + // up to make it aligned + size_t currentPageOffset; // next offset in top of inUseList to allocate from + tHeader* freeList; // list of popped memory + tHeader* inUseList; // list of all memory currently being used + tAllocStack stack; // stack of where to allocate from, to partition pool + + int numCalls; // just an interesting statistic + size_t totalBytes; // just an interesting statistic +private: + TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator + TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor +}; + + +// +// There could potentially be many pools with pops happening at +// different times. But a simple use is to have a global pop +// with everyone using the same global allocator. +// +extern TPoolAllocator* GetGlobalPoolAllocator(); +extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator); + +// +// This STL compatible allocator is intended to be used as the allocator +// parameter to templatized STL containers, like vector and map. +// +// It will use the pools for allocation, and not +// do any deallocation, but will still do destruction. +// +template<class T> +class pool_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template<class Other> + struct rebind { + typedef pool_allocator<Other> other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pool_allocator() : allocator(GetGlobalPoolAllocator()) { } + pool_allocator(TPoolAllocator& a) : allocator(&a) { } + pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { } + + template <class Other> + pool_allocator<T>& operator=(const pool_allocator<Other>& p) { + allocator = p.allocator; + return *this; + } + + template<class Other> + pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { } + +#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR) + // libCStd on some platforms have a different allocate/deallocate interface. + // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be + // allocated, not the number of elements. + void* allocate(size_type n) { + return getAllocator().allocate(n); + } + void* allocate(size_type n, const void*) { + return getAllocator().allocate(n); + } + void deallocate(void*, size_type) {} +#else + pointer allocate(size_type n) { + return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + pointer allocate(size_type n, const void*) { + return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); + } + void deallocate(pointer, size_type) {} +#endif // _RWSTD_ALLOCATOR + + void construct(pointer p, const T& val) { new ((void *)p) T(val); } + void destroy(pointer p) { p->T::~T(); } + + bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); } + bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); } + + size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast<size_type>(-1) / size; } + + void setAllocator(TPoolAllocator* a) { allocator = a; } + TPoolAllocator& getAllocator() const { return *allocator; } + +protected: + TPoolAllocator* allocator; +}; + +#endif // _POOLALLOC_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/Pragma.h b/chromium/third_party/angle/src/compiler/translator/Pragma.h new file mode 100644 index 00000000000..2f744123b82 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Pragma.h @@ -0,0 +1,19 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_PRAGMA_H_ +#define COMPILER_PRAGMA_H_ + +struct TPragma { + // By default optimization is turned on and debug is turned off. + TPragma() : optimize(true), debug(false) { } + TPragma(bool o, bool d) : optimize(o), debug(d) { } + + bool optimize; + bool debug; +}; + +#endif // COMPILER_PRAGMA_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp new file mode 100644 index 00000000000..1ba087e1765 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/intermediate.h" + +class TAliveTraverser : public TIntermTraverser { +public: + TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q) + { + } + + bool wasFound() { return found; } + +protected: + bool found; + TQualifier qualifier; + + void visitSymbol(TIntermSymbol*); + bool visitSelection(Visit, TIntermSelection*); +}; + +// +// Report whether or not a variable of the given qualifier type +// is guaranteed written. Not always possible to determine if +// it is written conditionally. +// +// ?? It does not do this well yet, this is just a place holder +// that simply determines if it was reference at all, anywhere. +// +bool QualifierWritten(TIntermNode* node, TQualifier qualifier) +{ + TAliveTraverser it(qualifier); + + if (node) + node->traverse(&it); + + return it.wasFound(); +} + +void TAliveTraverser::visitSymbol(TIntermSymbol* node) +{ + // + // If it's what we're looking for, record it. + // + if (node->getQualifier() == qualifier) + found = true; +} + +bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +{ + if (wasFound()) + return false; + + return true; +} diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h new file mode 100644 index 00000000000..872a06f7219 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/QualifierAlive.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +bool QualifierWritten(TIntermNode* root, TQualifier); diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp b/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp new file mode 100644 index 00000000000..e381c326900 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RemoveTree.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/RemoveTree.h" + +// +// Code to delete the intermediate tree. +// +void RemoveAllTreeNodes(TIntermNode* root) +{ + std::queue<TIntermNode*> nodeQueue; + + nodeQueue.push(root); + + while (!nodeQueue.empty()) + { + TIntermNode *node = nodeQueue.front(); + nodeQueue.pop(); + + node->enqueueChildren(&nodeQueue); + + delete node; + } +} + diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveTree.h b/chromium/third_party/angle/src/compiler/translator/RemoveTree.h new file mode 100644 index 00000000000..97a821679c2 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RemoveTree.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +void RemoveAllTreeNodes(TIntermNode*); diff --git a/chromium/third_party/angle/src/compiler/translator/RenameFunction.h b/chromium/third_party/angle/src/compiler/translator/RenameFunction.h new file mode 100644 index 00000000000..1f7fb16c459 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RenameFunction.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_RENAME_FUNCTION +#define COMPILER_RENAME_FUNCTION + +#include "compiler/translator/intermediate.h" + +// +// Renames a function, including its declaration and any calls to it. +// +class RenameFunction : public TIntermTraverser +{ +public: + RenameFunction(const TString& oldFunctionName, const TString& newFunctionName) + : TIntermTraverser(true, false, false) + , mOldFunctionName(oldFunctionName) + , mNewFunctionName(newFunctionName) {} + + virtual bool visitAggregate(Visit visit, TIntermAggregate* node) + { + TOperator op = node->getOp(); + if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName) + node->setName(mNewFunctionName); + return true; + } + +private: + const TString mOldFunctionName; + const TString mNewFunctionName; +}; + +#endif // COMPILER_RENAME_FUNCTION diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp new file mode 100644 index 00000000000..46e510c31b9 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RewriteElseBlocks.cpp: Implementation for tree transform to change +// all if-else blocks to if-if blocks. +// + +#include "compiler/translator/RewriteElseBlocks.h" +#include "compiler/translator/NodeSearch.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +TIntermSymbol *MakeNewTemporary(const TString &name, TBasicType type) +{ + TType variableType(type, EbpHigh, EvqInternal); + return new TIntermSymbol(-1, name, variableType); +} + +TIntermBinary *MakeNewBinary(TOperator op, TIntermTyped *left, TIntermTyped *right, const TType &resultType) +{ + TIntermBinary *binary = new TIntermBinary(op); + binary->setLeft(left); + binary->setRight(right); + binary->setType(resultType); + return binary; +} + +TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) +{ + TIntermUnary *unary = new TIntermUnary(op, operand->getType()); + unary->setOperand(operand); + return unary; +} + +ElseBlockRewriter::ElseBlockRewriter() + : TIntermTraverser(true, false, true, false), + mTemporaryIndex(0), + mFunctionType(NULL) +{} + +bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) +{ + switch (node->getOp()) + { + case EOpSequence: + if (visit == PostVisit) + { + for (size_t statementIndex = 0; statementIndex != node->getSequence().size(); statementIndex++) + { + TIntermNode *statement = node->getSequence()[statementIndex]; + TIntermSelection *selection = statement->getAsSelectionNode(); + if (selection && selection->getFalseBlock() != NULL) + { + // Check for if / else if + TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); + if (elseIfBranch) + { + selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); + delete elseIfBranch; + } + + node->getSequence()[statementIndex] = rewriteSelection(selection); + delete selection; + } + } + } + break; + + case EOpFunction: + // Store the current function context (see comment below) + mFunctionType = ((visit == PreVisit) ? &node->getType() : NULL); + break; + + default: break; + } + + return true; +} + +TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) +{ + ASSERT(selection->getFalseBlock() != NULL); + + TString temporaryName = "cond_" + str(mTemporaryIndex++); + TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); + TType resultType(EbtBool, EbpUndefined); + TIntermSymbol *conditionSymbolA = MakeNewTemporary(temporaryName, EbtBool); + TIntermSymbol *conditionSymbolB = MakeNewTemporary(temporaryName, EbtBool); + TIntermSymbol *conditionSymbolC = MakeNewTemporary(temporaryName, EbtBool); + TIntermBinary *storeCondition = MakeNewBinary(EOpInitialize, conditionSymbolA, + typedCondition, resultType); + TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolB); + TIntermNode *negatedElse = NULL; + + // crbug.com/346463 + // D3D generates error messages claiming a function has no return value, when rewriting + // an if-else clause that returns something non-void in a function. By appending dummy + // returns (that are unreachable) we can silence this compile error. + if (mFunctionType && mFunctionType->getBasicType() != EbtVoid) + { + TString typeString = mFunctionType->getStruct() ? mFunctionType->getStruct()->name() : + mFunctionType->getBasicString(); + TString rawText = "return (" + typeString + ")0"; + negatedElse = new TIntermRaw(*mFunctionType, rawText); + } + + TIntermSelection *falseBlock = new TIntermSelection(negatedCondition, + selection->getFalseBlock(), negatedElse); + TIntermSelection *newIfElse = new TIntermSelection(conditionSymbolC, + selection->getTrueBlock(), falseBlock); + + TIntermAggregate *declaration = new TIntermAggregate(EOpDeclaration); + declaration->getSequence().push_back(storeCondition); + + TIntermAggregate *block = new TIntermAggregate(EOpSequence); + block->getSequence().push_back(declaration); + block->getSequence().push_back(newIfElse); + + return block; +} + +void RewriteElseBlocks(TIntermNode *node) +{ + ElseBlockRewriter rewriter; + node->traverse(&rewriter); +} + +} diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h new file mode 100644 index 00000000000..172928f7254 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// RewriteElseBlocks.h: Prototype for tree transform to change +// all if-else blocks to if-if blocks. +// + +#ifndef COMPILER_REWRITE_ELSE_BLOCKS_H_ +#define COMPILER_REWRITE_ELSE_BLOCKS_H_ + +#include "compiler/translator/intermediate.h" + +namespace sh +{ + +class ElseBlockRewriter : public TIntermTraverser +{ + public: + ElseBlockRewriter(); + + protected: + bool visitAggregate(Visit visit, TIntermAggregate *aggregate); + + private: + int mTemporaryIndex; + const TType *mFunctionType; + + TIntermNode *rewriteSelection(TIntermSelection *selection); +}; + +void RewriteElseBlocks(TIntermNode *node); + +} + +#endif // COMPILER_REWRITE_ELSE_BLOCKS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp new file mode 100644 index 00000000000..f78c84e370d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SearchSymbol is an AST traverser to detect the use of a given symbol name +// + +#include "compiler/translator/SearchSymbol.h" + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/OutputHLSL.h" + +namespace sh +{ +SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol) +{ + match = false; +} + +void SearchSymbol::traverse(TIntermNode *node) +{ + node->traverse(this); +} + +void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode) +{ + if (symbolNode->getSymbol() == mSymbol) + { + match = true; + } +} + +bool SearchSymbol::foundMatch() const +{ + return match; +} +} diff --git a/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h new file mode 100644 index 00000000000..8ddd3cb1ac3 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SearchSymbol.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SearchSymbol is an AST traverser to detect the use of a given symbol name +// + +#ifndef COMPILER_SEARCHSYMBOL_H_ +#define COMPILER_SEARCHSYMBOL_H_ + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/ParseContext.h" + +namespace sh +{ +class SearchSymbol : public TIntermTraverser +{ + public: + SearchSymbol(const TString &symbol); + + void traverse(TIntermNode *node); + void visitSymbol(TIntermSymbol *symbolNode); + + bool foundMatch() const; + + protected: + const TString &mSymbol; + bool match; +}; +} + +#endif // COMPILER_SEARCHSYMBOL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ShHandle.h b/chromium/third_party/angle/src/compiler/translator/ShHandle.h new file mode 100644 index 00000000000..bb6a60c519f --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ShHandle.h @@ -0,0 +1,180 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _SHHANDLE_INCLUDED_ +#define _SHHANDLE_INCLUDED_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/ExtensionBehavior.h" +#include "compiler/translator/HashNames.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/VariableInfo.h" +#include "third_party/compiler/ArrayBoundsClamper.h" + +class TCompiler; +class TDependencyGraph; +class TranslatorHLSL; + +// +// Helper function to identify specs that are based on the WebGL spec, +// like the CSS Shaders spec. +// +bool IsWebGLBasedSpec(ShShaderSpec spec); + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase(); + virtual ~TShHandleBase(); + virtual TCompiler* getAsCompiler() { return 0; } + virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } + +protected: + // Memory allocator. Allocates and tracks memory required by the compiler. + // Deallocates all memory when compiler is destructed. + TPoolAllocator allocator; +}; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase { +public: + TCompiler(ShShaderType type, ShShaderSpec spec, ShShaderOutput output); + virtual ~TCompiler(); + virtual TCompiler* getAsCompiler() { return this; } + + bool Init(const ShBuiltInResources& resources); + bool compile(const char* const shaderStrings[], + size_t numStrings, + int compileOptions); + + // Get results of the last compilation. + int getShaderVersion() const { return shaderVersion; } + TInfoSink& getInfoSink() { return infoSink; } + const TVariableInfoList& getAttribs() const { return attribs; } + const TVariableInfoList& getUniforms() const { return uniforms; } + const TVariableInfoList& getVaryings() const { return varyings; } + + ShHashFunction64 getHashFunction() const { return hashFunction; } + NameMap& getNameMap() { return nameMap; } + TSymbolTable& getSymbolTable() { return symbolTable; } + ShShaderSpec getShaderSpec() const { return shaderSpec; } + ShShaderOutput getOutputType() const { return outputType; } + std::string getBuiltInResourcesString() const { return builtInResourcesString; } + +protected: + ShShaderType getShaderType() const { return shaderType; } + // Initialize symbol-table with built-in symbols. + bool InitBuiltInSymbolTable(const ShBuiltInResources& resources); + // Compute the string representation of the built-in resources + void setResourceString(); + // Clears the results from the previous compilation. + void clearResults(); + // Return true if function recursion is detected or call depth exceeded. + bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth); + // Returns true if a program has no conflicting or missing fragment outputs + bool validateOutputs(TIntermNode* root); + // Rewrites a shader's intermediate tree according to the CSS Shaders spec. + void rewriteCSSShader(TIntermNode* root); + // Returns true if the given shader does not exceed the minimum + // functionality mandated in GLSL 1.0 spec Appendix A. + bool validateLimitations(TIntermNode* root); + // Collect info for all attribs, uniforms, varyings. + void collectVariables(TIntermNode* root); + // Translate to object code. + virtual void translate(TIntermNode* root) = 0; + // Returns true if, after applying the packing rules in the GLSL 1.017 spec + // Appendix A, section 7, the shader does not use too many uniforms. + bool enforcePackingRestrictions(); + // Insert statements to initialize varyings without static use in the beginning + // of main(). It is to work around a Mac driver where such varyings in a vertex + // shader may be optimized out incorrectly at compile time, causing a link failure. + // This function should only be applied to vertex shaders. + void initializeVaryingsWithoutStaticUse(TIntermNode* root); + // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). + // It is to work around a Linux driver bug where missing this causes compile failure + // while spec says it is allowed. + // This function should only be applied to vertex shaders. + void initializeGLPosition(TIntermNode* root); + // Returns true if the shader passes the restrictions that aim to prevent timing attacks. + bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); + // Returns true if the shader does not use samplers. + bool enforceVertexShaderTimingRestrictions(TIntermNode* root); + // Returns true if the shader does not use sampler dependent values to affect control + // flow or in operations whose time can depend on the input values. + bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); + // Return true if the maximum expression complexity is below the limit. + bool limitExpressionComplexity(TIntermNode* root); + // Get built-in extensions with default behavior. + const TExtensionBehavior& getExtensionBehavior() const; + // Get the resources set by InitBuiltInSymbolTable + const ShBuiltInResources& getResources() const; + + const ArrayBoundsClamper& getArrayBoundsClamper() const; + ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; + const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; + +private: + ShShaderType shaderType; + ShShaderSpec shaderSpec; + ShShaderOutput outputType; + + int maxUniformVectors; + int maxExpressionComplexity; + int maxCallStackDepth; + + ShBuiltInResources compileResources; + std::string builtInResourcesString; + + // Built-in symbol table for the given language, spec, and resources. + // It is preserved from compile-to-compile. + TSymbolTable symbolTable; + // Built-in extensions with default behavior. + TExtensionBehavior extensionBehavior; + bool fragmentPrecisionHigh; + + ArrayBoundsClamper arrayBoundsClamper; + ShArrayIndexClampingStrategy clampingStrategy; + BuiltInFunctionEmulator builtInFunctionEmulator; + + // Results of compilation. + int shaderVersion; + TInfoSink infoSink; // Output sink. + TVariableInfoList attribs; // Active attributes in the compiled shader. + TVariableInfoList uniforms; // Active uniforms in the compiled shader. + TVariableInfoList varyings; // Varyings in the compiled shader. + + // name hashing. + ShHashFunction64 hashFunction; + NameMap nameMap; +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler* ConstructCompiler( + ShShaderType type, ShShaderSpec spec, ShShaderOutput output); +void DeleteCompiler(TCompiler*); + +#endif // _SHHANDLE_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp new file mode 100644 index 00000000000..bf0587a34ce --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp @@ -0,0 +1,445 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Implement the top-level of interface to the compiler, +// as defined in ShaderLang.h +// + +#include "GLSLANG/ShaderLang.h" + +#include "compiler/translator/InitializeDll.h" +#include "compiler/translator/length_limits.h" +#include "compiler/translator/ShHandle.h" +#include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/VariablePacker.h" + +static bool isInitialized = false; + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler. +// + +static bool checkVariableMaxLengths(const ShHandle handle, + size_t expectedValue) +{ + size_t activeUniformLimit = 0; + ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); + size_t activeAttribLimit = 0; + ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); + size_t varyingLimit = 0; + ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit); + return (expectedValue == activeUniformLimit && + expectedValue == activeAttribLimit && + expectedValue == varyingLimit); +} + +static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue) +{ + size_t mappedNameMaxLength = 0; + ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength); + return (expectedValue == mappedNameMaxLength); +} + +// +// Driver must call this first, once, before doing any other compiler operations. +// Subsequent calls to this function are no-op. +// +int ShInitialize() +{ + if (!isInitialized) + { + isInitialized = InitProcess(); + } + return isInitialized ? 1 : 0; +} + +// +// Cleanup symbol tables +// +int ShFinalize() +{ + if (isInitialized) + { + DetachProcess(); + isInitialized = false; + } + return 1; +} + +// +// Initialize built-in resources with minimum expected values. +// +void ShInitBuiltInResources(ShBuiltInResources* resources) +{ + // Constants. + resources->MaxVertexAttribs = 8; + resources->MaxVertexUniformVectors = 128; + resources->MaxVaryingVectors = 8; + resources->MaxVertexTextureImageUnits = 0; + resources->MaxCombinedTextureImageUnits = 8; + resources->MaxTextureImageUnits = 8; + resources->MaxFragmentUniformVectors = 16; + resources->MaxDrawBuffers = 1; + + // Extensions. + resources->OES_standard_derivatives = 0; + resources->OES_EGL_image_external = 0; + resources->ARB_texture_rectangle = 0; + resources->EXT_draw_buffers = 0; + resources->EXT_frag_depth = 0; + resources->EXT_shader_texture_lod = 0; + + // Disable highp precision in fragment shader by default. + resources->FragmentPrecisionHigh = 0; + + // GLSL ES 3.0 constants. + resources->MaxVertexOutputVectors = 16; + resources->MaxFragmentInputVectors = 15; + resources->MinProgramTexelOffset = -8; + resources->MaxProgramTexelOffset = 7; + + // Disable name hashing by default. + resources->HashFunction = NULL; + + resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; + + resources->MaxExpressionComplexity = 256; + resources->MaxCallStackDepth = 256; +} + +// +// Driver calls these to create and destroy compiler objects. +// +ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec, + ShShaderOutput output, + const ShBuiltInResources* resources) +{ + TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output)); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + // Generate built-in symbol table. + if (!compiler->Init(*resources)) { + ShDestruct(base); + return 0; + } + + return reinterpret_cast<void*>(base); +} + +void ShDestruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); +} + +void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString) +{ + if (!handle || !outString) + { + return; + } + + TShHandleBase *base = static_cast<TShHandleBase*>(handle); + TCompiler *compiler = base->getAsCompiler(); + if (!compiler) + { + return; + } + + strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen); + outString[outStringLen - 1] = '\0'; +} +// +// Do an actual compile on the given strings. The result is left +// in the given compile object. +// +// Return: The return value of ShCompile is really boolean, indicating +// success or failure. +// +int ShCompile( + const ShHandle handle, + const char* const shaderStrings[], + size_t numStrings, + int compileOptions) +{ + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + bool success = compiler->compile(shaderStrings, numStrings, compileOptions); + return success ? 1 : 0; +} + +void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) +{ + if (!handle || !params) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + switch(pname) + { + case SH_INFO_LOG_LENGTH: + *params = compiler->getInfoSink().info.size() + 1; + break; + case SH_OBJECT_CODE_LENGTH: + *params = compiler->getInfoSink().obj.size() + 1; + break; + case SH_ACTIVE_UNIFORMS: + *params = compiler->getUniforms().size(); + break; + case SH_ACTIVE_UNIFORM_MAX_LENGTH: + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + break; + case SH_ACTIVE_ATTRIBUTES: + *params = compiler->getAttribs().size(); + break; + case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + break; + case SH_VARYINGS: + *params = compiler->getVaryings().size(); + break; + case SH_VARYING_MAX_LENGTH: + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + break; + case SH_MAPPED_NAME_MAX_LENGTH: + // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to + // handle array and struct dereferences. + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + break; + case SH_NAME_MAX_LENGTH: + *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + break; + case SH_HASHED_NAME_MAX_LENGTH: + if (compiler->getHashFunction() == NULL) { + *params = 0; + } else { + // 64 bits hashing output requires 16 bytes for hex + // representation. + const char HashedNamePrefix[] = HASHED_NAME_PREFIX; + (void)HashedNamePrefix; + *params = 16 + sizeof(HashedNamePrefix); + } + break; + case SH_HASHED_NAMES_COUNT: + *params = compiler->getNameMap().size(); + break; + case SH_SHADER_VERSION: + *params = compiler->getShaderVersion(); + break; + case SH_RESOURCES_STRING_LENGTH: + *params = compiler->getBuiltInResourcesString().length() + 1; + break; + case SH_OUTPUT_TYPE: + *params = compiler->getOutputType(); + break; + default: UNREACHABLE(); + } +} + +// +// Return any compiler log of messages for the application. +// +void ShGetInfoLog(const ShHandle handle, char* infoLog) +{ + if (!handle || !infoLog) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(infoLog, infoSink.info.c_str()); +} + +// +// Return any object code. +// +void ShGetObjectCode(const ShHandle handle, char* objCode) +{ + if (!handle || !objCode) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + TInfoSink& infoSink = compiler->getInfoSink(); + strcpy(objCode, infoSink.obj.c_str()); +} + +void ShGetVariableInfo(const ShHandle handle, + ShShaderInfo varType, + int index, + size_t* length, + int* size, + ShDataType* type, + ShPrecisionType* precision, + int* staticUse, + char* name, + char* mappedName) +{ + if (!handle || !size || !type || !precision || !staticUse || !name) + return; + ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || + (varType == SH_ACTIVE_UNIFORMS) || + (varType == SH_VARYINGS)); + + TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return; + + const TVariableInfoList& varList = + varType == SH_ACTIVE_ATTRIBUTES ? compiler->getAttribs() : + (varType == SH_ACTIVE_UNIFORMS ? compiler->getUniforms() : + compiler->getVaryings()); + if (index < 0 || index >= static_cast<int>(varList.size())) + return; + + const TVariableInfo& varInfo = varList[index]; + if (length) *length = varInfo.name.size(); + *size = varInfo.size; + *type = varInfo.type; + switch (varInfo.precision) { + case EbpLow: + *precision = SH_PRECISION_LOWP; + break; + case EbpMedium: + *precision = SH_PRECISION_MEDIUMP; + break; + case EbpHigh: + *precision = SH_PRECISION_HIGHP; + break; + default: + // Some types does not support precision, for example, boolean. + *precision = SH_PRECISION_UNDEFINED; + break; + } + *staticUse = varInfo.staticUse ? 1 : 0; + + // This size must match that queried by + // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH + // in ShGetInfo, below. + size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + ASSERT(checkVariableMaxLengths(handle, variableLength)); + strncpy(name, varInfo.name.c_str(), variableLength); + name[variableLength - 1] = 0; + if (mappedName) { + // This size must match that queried by + // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. + size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); + ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength)); + strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength); + mappedName[maxMappedNameLength - 1] = 0; + } +} + +void ShGetNameHashingEntry(const ShHandle handle, + int index, + char* name, + char* hashedName) +{ + if (!handle || !name || !hashedName || index < 0) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TCompiler* compiler = base->getAsCompiler(); + if (!compiler) return; + + const NameMap& nameMap = compiler->getNameMap(); + if (index >= static_cast<int>(nameMap.size())) + return; + + NameMap::const_iterator it = nameMap.begin(); + for (int i = 0; i < index; ++i) + ++it; + + size_t len = it->first.length() + 1; + size_t max_len = 0; + ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len); + if (len > max_len) { + ASSERT(false); + len = max_len; + } + strncpy(name, it->first.c_str(), len); + // To be on the safe side in case the source is longer than expected. + name[len - 1] = '\0'; + + len = it->second.length() + 1; + max_len = 0; + ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len); + if (len > max_len) { + ASSERT(false); + len = max_len; + } + strncpy(hashedName, it->second.c_str(), len); + // To be on the safe side in case the source is longer than expected. + hashedName[len - 1] = '\0'; +} + +void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params) +{ + if (!handle || !params) + return; + + TShHandleBase* base = static_cast<TShHandleBase*>(handle); + TranslatorHLSL* translator = base->getAsTranslatorHLSL(); + if (!translator) return; + + switch(pname) + { + case SH_ACTIVE_UNIFORMS_ARRAY: + *params = (void*)&translator->getUniforms(); + break; + case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY: + *params = (void*)&translator->getInterfaceBlocks(); + break; + case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY: + *params = (void*)&translator->getOutputVariables(); + break; + case SH_ACTIVE_ATTRIBUTES_ARRAY: + *params = (void*)&translator->getAttributes(); + break; + case SH_ACTIVE_VARYINGS_ARRAY: + *params = (void*)&translator->getVaryings(); + break; + default: UNREACHABLE(); + } +} + +int ShCheckVariablesWithinPackingLimits( + int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize) +{ + if (varInfoArraySize == 0) + return 1; + ASSERT(varInfoArray); + TVariableInfoList variables; + for (size_t ii = 0; ii < varInfoArraySize; ++ii) + { + TVariableInfo var(varInfoArray[ii].type, varInfoArray[ii].size); + variables.push_back(var); + } + VariablePacker packer; + return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0; +} diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp new file mode 100644 index 00000000000..aa5933d3e9a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp @@ -0,0 +1,241 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Symbol table for parsing. Most functionaliy and main ideas +// are documented in the header file. +// + +#if defined(_MSC_VER) +#pragma warning(disable: 4718) +#endif + +#include "compiler/translator/SymbolTable.h" + +#include <stdio.h> +#include <algorithm> + +int TSymbolTable::uniqueIdCounter = 0; + +// +// Functions have buried pointers to delete. +// +TFunction::~TFunction() +{ + for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) + delete (*i).type; +} + +// +// Symbol table levels are a map of pointers to symbols that have to be deleted. +// +TSymbolTableLevel::~TSymbolTableLevel() +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + delete (*it).second; +} + +bool TSymbolTableLevel::insert(const TString &name, TSymbol &symbol) +{ + symbol.setUniqueId(TSymbolTable::nextUniqueId()); + + // returning true means symbol was added to the table + tInsertResult result = level.insert(tLevelPair(name, &symbol)); + + return result.second; +} + +bool TSymbolTableLevel::insert(TSymbol &symbol) +{ + return insert(symbol.getMangledName(), symbol); +} + +TSymbol *TSymbolTableLevel::find(const TString &name) const +{ + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return 0; + else + return (*it).second; +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in operation. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToOperator(const char *name, TOperator op) +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + { + if ((*it).second->isFunction()) + { + TFunction *function = static_cast<TFunction*>((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } + } +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in extension. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToExtension(const char *name, const TString &ext) +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + { + TSymbol *symbol = it->second; + if (symbol->getName() == name) + symbol->relateToExtension(ext); + } +} + +TSymbol::TSymbol(const TSymbol ©Of) +{ + name = NewPoolTString(copyOf.name->c_str()); + uniqueId = copyOf.uniqueId; +} + +TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope) +{ + int level = currentLevel(); + TSymbol *symbol; + + do + { + if (level == ESSL3_BUILTINS && shaderVersion != 300) + level--; + if (level == ESSL1_BUILTINS && shaderVersion != 100) + level--; + + symbol = table[level]->find(name); + } + while (symbol == 0 && --level >= 0); + + if (builtIn) + *builtIn = (level <= LAST_BUILTIN_LEVEL); + if (sameScope) + *sameScope = (level == currentLevel()); + + return symbol; +} + +TSymbol *TSymbolTable::findBuiltIn(const TString &name, int shaderVersion) +{ + for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--) + { + if (level == ESSL3_BUILTINS && shaderVersion != 300) + level--; + if (level == ESSL1_BUILTINS && shaderVersion != 100) + level--; + + TSymbol *symbol = table[level]->find(name); + + if (symbol) + return symbol; + } + + return 0; +} + +TSymbolTable::~TSymbolTable() +{ + while (table.size() > 0) + pop(); +} + +void TSymbolTable::insertBuiltIn( + ESymbolLevel level, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) +{ + if (ptype1->getBasicType() == EbtGSampler2D) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSampler3D) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSamplerCube) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5); + return; + } + if (ptype1->getBasicType() == EbtGSampler2DArray) + { + bool gvec4 = (rvalue->getBasicType() == EbtGVec4); + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, + new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, + new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, + new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5); + return; + } + + TFunction *function = new TFunction(NewPoolTString(name), *rvalue); + + TType *types[] = {ptype1, ptype2, ptype3, ptype4, ptype5}; + for (size_t ii = 0; ii < sizeof(types) / sizeof(types[0]); ++ii) + { + if (types[ii]) + { + TParameter param = {NULL, types[ii]}; + function->addParameter(param); + } + } + + insert(level, *function); +} + +TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) +{ + if (!SupportsPrecision(type)) + return EbpUndefined; + + // unsigned integers use the same precision as signed + TBasicType baseType = (type == EbtUInt) ? EbtInt : type; + + int level = static_cast<int>(precisionStack.size()) - 1; + assert(level >= 0); // Just to be safe. Should not happen. + // If we dont find anything we return this. Should we error check this? + TPrecision prec = EbpUndefined; + while (level >= 0) + { + PrecisionStackLevel::iterator it = precisionStack[level]->find(baseType); + if (it != precisionStack[level]->end()) + { + prec = (*it).second; + break; + } + level--; + } + return prec; +} diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.h b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h new file mode 100644 index 00000000000..3f932a45432 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h @@ -0,0 +1,431 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _SYMBOL_TABLE_INCLUDED_ +#define _SYMBOL_TABLE_INCLUDED_ + +// +// Symbol table for parsing. Has these design characteristics: +// +// * Same symbol table can be used to compile many shaders, to preserve +// effort of creating and loading with the large numbers of built-in +// symbols. +// +// * Name mangling will be used to give each function a unique name +// so that symbol table lookups are never ambiguous. This allows +// a simpler symbol table structure. +// +// * Pushing and popping of scope, so symbol table will really be a stack +// of symbol tables. Searched from the top, with new inserts going into +// the top. +// +// * Constants: Compile time constant symbols will keep their values +// in the symbol table. The parser can substitute constants at parse +// time, including doing constant folding and constant propagation. +// +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) +// are tracked in the intermediate representation, not the symbol table. +// + +#include <assert.h> + +#include "common/angleutils.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/intermediate.h" + +// Symbol base class. (Can build functions or variables out of these...) +class TSymbol +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TSymbol(const TString *n) + : uniqueId(0), + name(n) + { + } + virtual ~TSymbol() + { + // don't delete name, it's from the pool + } + + const TString &getName() const + { + return *name; + } + virtual const TString &getMangledName() const + { + return getName(); + } + virtual bool isFunction() const + { + return false; + } + virtual bool isVariable() const + { + return false; + } + void setUniqueId(int id) + { + uniqueId = id; + } + int getUniqueId() const + { + return uniqueId; + } + void relateToExtension(const TString &ext) + { + extension = ext; + } + const TString &getExtension() const + { + return extension; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TSymbol); + + int uniqueId; // For real comparing during code generation + const TString *name; + TString extension; +}; + +// Variable class, meaning a symbol that's not a function. +// +// There could be a separate class heirarchy for Constant variables; +// Only one of int, bool, or float, (or none) is correct for +// any particular use, but it's easy to do this way, and doesn't +// seem worth having separate classes, and "getConst" can't simply return +// different values for different types polymorphically, so this is +// just simple and pragmatic. +class TVariable : public TSymbol +{ + public: + TVariable(const TString *name, const TType &t, bool uT = false) + : TSymbol(name), + type(t), + userType(uT), + unionArray(0) + { + } + virtual ~TVariable() + { + } + virtual bool isVariable() const + { + return true; + } + TType &getType() + { + return type; + } + const TType &getType() const + { + return type; + } + bool isUserType() const + { + return userType; + } + void setQualifier(TQualifier qualifier) + { + type.setQualifier(qualifier); + } + + ConstantUnion *getConstPointer() + { + if (!unionArray) + unionArray = new ConstantUnion[type.getObjectSize()]; + + return unionArray; + } + + ConstantUnion *getConstPointer() const + { + return unionArray; + } + + void shareConstPointer(ConstantUnion *constArray) + { + if (unionArray == constArray) + return; + + delete[] unionArray; + unionArray = constArray; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TVariable); + + TType type; + bool userType; + // we are assuming that Pool Allocator will free the memory + // allocated to unionArray when this object is destroyed. + ConstantUnion *unionArray; +}; + +// The function sub-class of symbols and the parser will need to +// share this definition of a function parameter. +struct TParameter +{ + TString *name; + TType *type; +}; + +// The function sub-class of a symbol. +class TFunction : public TSymbol +{ + public: + TFunction(TOperator o) + : TSymbol(0), + returnType(TType(EbtVoid, EbpUndefined)), + op(o), + defined(false) + { + } + TFunction(const TString *name, TType &retType, TOperator tOp = EOpNull) + : TSymbol(name), + returnType(retType), + mangledName(TFunction::mangleName(*name)), + op(tOp), + defined(false) + { + } + virtual ~TFunction(); + virtual bool isFunction() const + { + return true; + } + + static TString mangleName(const TString &name) + { + return name + '('; + } + static TString unmangleName(const TString &mangledName) + { + return TString(mangledName.c_str(), mangledName.find_first_of('(')); + } + + void addParameter(TParameter &p) + { + parameters.push_back(p); + mangledName = mangledName + p.type->getMangledName(); + } + + const TString &getMangledName() const + { + return mangledName; + } + const TType &getReturnType() const + { + return returnType; + } + + void relateToOperator(TOperator o) + { + op = o; + } + TOperator getBuiltInOp() const + { + return op; + } + + void setDefined() + { + defined = true; + } + bool isDefined() + { + return defined; + } + + size_t getParamCount() const + { + return parameters.size(); + } + const TParameter &getParam(size_t i) const + { + return parameters[i]; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TFunction); + + typedef TVector<TParameter> TParamList; + TParamList parameters; + TType returnType; + TString mangledName; + TOperator op; + bool defined; +}; + +// Interface block name sub-symbol +class TInterfaceBlockName : public TSymbol +{ + public: + TInterfaceBlockName(const TString *name) + : TSymbol(name) + { + } + + virtual ~TInterfaceBlockName() + { + } +}; + +class TSymbolTableLevel +{ + public: + typedef TMap<TString, TSymbol *> tLevel; + typedef tLevel::const_iterator const_iterator; + typedef const tLevel::value_type tLevelPair; + typedef std::pair<tLevel::iterator, bool> tInsertResult; + + TSymbolTableLevel() + { + } + ~TSymbolTableLevel(); + + bool insert(const TString &name, TSymbol &symbol); + bool insert(TSymbol &symbol); + + TSymbol *find(const TString &name) const; + + void relateToOperator(const char *name, TOperator op); + void relateToExtension(const char *name, const TString &ext); + + protected: + tLevel level; + static int uniqueId; // for unique identification in code generation +}; + +enum ESymbolLevel +{ + COMMON_BUILTINS = 0, + ESSL1_BUILTINS = 1, + ESSL3_BUILTINS = 2, + LAST_BUILTIN_LEVEL = ESSL3_BUILTINS, + GLOBAL_LEVEL = 3 +}; + +class TSymbolTable +{ + public: + TSymbolTable() + { + // The symbol table cannot be used until push() is called, but + // the lack of an initial call to push() can be used to detect + // that the symbol table has not been preloaded with built-ins. + } + + ~TSymbolTable(); + + // When the symbol table is initialized with the built-ins, there should + // 'push' calls, so that built-ins are at level 0 and the shader + // globals are at level 1. + bool isEmpty() + { + return table.empty(); + } + bool atBuiltInLevel() + { + return currentLevel() <= LAST_BUILTIN_LEVEL; + } + bool atGlobalLevel() + { + return currentLevel() <= GLOBAL_LEVEL; + } + void push() + { + table.push_back(new TSymbolTableLevel); + precisionStack.push_back(new PrecisionStackLevel); + } + + void pop() + { + delete table.back(); + table.pop_back(); + + delete precisionStack.back(); + precisionStack.pop_back(); + } + + bool declare(TSymbol &symbol) + { + return insert(currentLevel(), symbol); + } + + bool insert(ESymbolLevel level, TSymbol &symbol) + { + return table[level]->insert(symbol); + } + + bool insertConstInt(ESymbolLevel level, const char *name, int value) + { + TVariable *constant = new TVariable( + NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); + constant->getConstPointer()->setIConst(value); + return insert(level, *constant); + } + + void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, + TType *ptype4 = 0, TType *ptype5 = 0); + + TSymbol *find(const TString &name, int shaderVersion, + bool *builtIn = NULL, bool *sameScope = NULL); + TSymbol *findBuiltIn(const TString &name, int shaderVersion); + + TSymbolTableLevel *getOuterLevel() + { + assert(currentLevel() >= 1); + return table[currentLevel() - 1]; + } + + void relateToOperator(ESymbolLevel level, const char *name, TOperator op) + { + table[level]->relateToOperator(name, op); + } + void relateToExtension(ESymbolLevel level, const char *name, const TString &ext) + { + table[level]->relateToExtension(name, ext); + } + void dump(TInfoSink &infoSink) const; + + bool setDefaultPrecision(const TPublicType &type, TPrecision prec) + { + if (!SupportsPrecision(type.type)) + return false; + if (type.isAggregate()) + return false; // Not allowed to set for aggregate types + int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; + // Uses map operator [], overwrites the current value + (*precisionStack[indexOfLastElement])[type.type] = prec; + return true; + } + + // Searches down the precisionStack for a precision qualifier + // for the specified TBasicType + TPrecision getDefaultPrecision(TBasicType type); + + static int nextUniqueId() + { + return ++uniqueIdCounter; + } + + private: + ESymbolLevel currentLevel() const + { + return static_cast<ESymbolLevel>(table.size() - 1); + } + + std::vector<TSymbolTableLevel *> table; + typedef TMap<TBasicType, TPrecision> PrecisionStackLevel; + std::vector< PrecisionStackLevel *> precisionStack; + + static int uniqueIdCounter; +}; + +#endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp new file mode 100644 index 00000000000..c956e29c5be --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/TranslatorESSL.h" + +#include "compiler/translator/OutputESSL.h" + +TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec) + : TCompiler(type, spec, SH_ESSL_OUTPUT) { +} + +void TranslatorESSL::translate(TIntermNode* root) { + TInfoSinkBase& sink = getInfoSink().obj; + + // Write built-in extension behaviors. + writeExtensionBehavior(); + + // Write emulated built-in functions if needed. + getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( + sink, getShaderType() == SH_FRAGMENT_SHADER); + + // Write array bounds clamping emulation if needed. + getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + + // Write translated shader. + TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + root->traverse(&outputESSL); +} + +void TranslatorESSL::writeExtensionBehavior() { + TInfoSinkBase& sink = getInfoSink().obj; + const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); + iter != extensionBehavior.end(); ++iter) { + if (iter->second != EBhUndefined) { + sink << "#extension " << iter->first << " : " + << getBehaviorString(iter->second) << "\n"; + } + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h new file mode 100644 index 00000000000..e18f3c25ec8 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORESSL_H_ +#define COMPILER_TRANSLATORESSL_H_ + +#include "compiler/translator/ShHandle.h" + +class TranslatorESSL : public TCompiler { +public: + TranslatorESSL(ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); + +private: + void writeExtensionBehavior(); +}; + +#endif // COMPILER_TRANSLATORESSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp new file mode 100644 index 00000000000..749d8377f0c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/TranslatorGLSL.h" + +#include "compiler/translator/OutputGLSL.h" +#include "compiler/translator/VersionGLSL.h" + +static void writeVersion(ShShaderType type, TIntermNode* root, + TInfoSinkBase& sink) { + TVersionGLSL versionGLSL(type); + root->traverse(&versionGLSL); + int version = versionGLSL.getVersion(); + // We need to write version directive only if it is greater than 110. + // If there is no version directive in the shader, 110 is implied. + if (version > 110) { + sink << "#version " << version << "\n"; + } +} + +TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec) + : TCompiler(type, spec, SH_GLSL_OUTPUT) { +} + +void TranslatorGLSL::translate(TIntermNode* root) { + TInfoSinkBase& sink = getInfoSink().obj; + + // Write GLSL version. + writeVersion(getShaderType(), root, sink); + + // Write extension behaviour as needed + writeExtensionBehavior(); + + // Write emulated built-in functions if needed. + getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( + sink, false); + + // Write array bounds clamping emulation if needed. + getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + + // Write translated shader. + TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + root->traverse(&outputGLSL); +} + +void TranslatorGLSL::writeExtensionBehavior() { + TInfoSinkBase& sink = getInfoSink().obj; + const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); + iter != extensionBehavior.end(); ++iter) { + if (iter->second == EBhUndefined) + continue; + + // For GLSL output, we don't need to emit most extensions explicitly, + // but some we need to translate. + if (iter->first == "GL_EXT_shader_texture_lod") { + sink << "#extension GL_ARB_shader_texture_lod : " + << getBehaviorString(iter->second) << "\n"; + } + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h new file mode 100644 index 00000000000..1e16b2605e4 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORGLSL_H_ +#define COMPILER_TRANSLATORGLSL_H_ + +#include "compiler/translator/ShHandle.h" + +class TranslatorGLSL : public TCompiler { +public: + TranslatorGLSL(ShShaderType type, ShShaderSpec spec); + +protected: + virtual void translate(TIntermNode* root); + +private: + void writeExtensionBehavior(); +}; + +#endif // COMPILER_TRANSLATORGLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp new file mode 100644 index 00000000000..da6f9801ad0 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/TranslatorHLSL.h" + +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/OutputHLSL.h" + +TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output) + : TCompiler(type, spec, output) +{ +} + +void TranslatorHLSL::translate(TIntermNode *root) +{ + TParseContext& parseContext = *GetGlobalParseContext(); + sh::OutputHLSL outputHLSL(parseContext, getResources(), getOutputType()); + + outputHLSL.output(); + + mActiveUniforms = outputHLSL.getUniforms(); + mActiveInterfaceBlocks = outputHLSL.getInterfaceBlocks(); + mActiveOutputVariables = outputHLSL.getOutputVariables(); + mActiveAttributes = outputHLSL.getAttributes(); + mActiveVaryings = outputHLSL.getVaryings(); +} diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h new file mode 100644 index 00000000000..8b16587b6b1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TRANSLATORHLSL_H_ +#define COMPILER_TRANSLATORHLSL_H_ + +#include "compiler/translator/ShHandle.h" +#include "common/shadervars.h" + +class TranslatorHLSL : public TCompiler { +public: + TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output); + + virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; } + const std::vector<gl::Uniform> &getUniforms() { return mActiveUniforms; } + const std::vector<gl::InterfaceBlock> &getInterfaceBlocks() const { return mActiveInterfaceBlocks; } + const std::vector<gl::Attribute> &getOutputVariables() { return mActiveOutputVariables; } + const std::vector<gl::Attribute> &getAttributes() { return mActiveAttributes; } + const std::vector<gl::Varying> &getVaryings() { return mActiveVaryings; } + +protected: + virtual void translate(TIntermNode* root); + + std::vector<gl::Uniform> mActiveUniforms; + std::vector<gl::InterfaceBlock> mActiveInterfaceBlocks; + std::vector<gl::Attribute> mActiveOutputVariables; + std::vector<gl::Attribute> mActiveAttributes; + std::vector<gl::Varying> mActiveVaryings; +}; + +#endif // COMPILER_TRANSLATORHLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/Types.cpp b/chromium/third_party/angle/src/compiler/translator/Types.cpp new file mode 100644 index 00000000000..4763920f86e --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Types.cpp @@ -0,0 +1,250 @@ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#if defined(_MSC_VER) +#pragma warning(disable: 4718) +#endif + +#include "compiler/translator/Types.h" + +#include <algorithm> +#include <climits> + +TType::TType(const TPublicType &p) + : type(p.type), precision(p.precision), qualifier(p.qualifier), layoutQualifier(p.layoutQualifier), + primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize), + interfaceBlock(0), structure(0) +{ + if (p.userDef) + structure = p.userDef->getStruct(); +} + +bool TType::equals(const TType &other) const +{ + if (type != other.type || precision != other.precision || + primarySize != other.primarySize || secondarySize != other.secondarySize || + array != other.array || (array && arraySize != other.arraySize) || + interfaceBlock != other.interfaceBlock || structure != other.structure) + { + return false; + } + if (interfaceBlock && !interfaceBlock->equals(*(other.interfaceBlock))) + return false; + if (structure && !structure->equals(*(other.structure))) + return false; + return true; +} + +bool TField::equals(const TField &other) const +{ + ASSERT(mType && mName); + ASSERT(other.mType && other.mName); + return mType->equals(*(other.mType)) && *mName == *(other.mName); +} + +bool TFieldListCollection::equals(const TFieldListCollection &other) const +{ + ASSERT(mName && mFields); + ASSERT(other.mName && other.mFields); + if (*mName != *(other.mName)) + return false; + if (mFields->size() != other.mFields->size()) + return false; + for (size_t ii = 0; ii < mFields->size(); ++ii) + { + ASSERT((*mFields)[ii] && (*(other.mFields))[ii]); + if (!(*mFields)[ii]->equals(*((*(other.mFields))[ii]))) + return false; + } + return true; +} + +bool TStructure::equals(const TStructure &other) const +{ + return TFieldListCollection::equals(other); +} + +bool TInterfaceBlock::equals(const TInterfaceBlock &other) const +{ + if (!TFieldListCollection::equals(other)) + return false; + // TODO(zmo): do we need to consider mBlockStorage and mMatrixPacking? + return mArraySize == other.mArraySize; +} + +// +// Recursively generate mangled names. +// +TString TType::buildMangledName() const +{ + TString mangledName; + if (isMatrix()) + mangledName += 'm'; + else if (isVector()) + mangledName += 'v'; + + switch (type) + { + case EbtFloat: + mangledName += 'f'; + break; + case EbtInt: + mangledName += 'i'; + break; + case EbtUInt: + mangledName += 'u'; + break; + case EbtBool: + mangledName += 'b'; + break; + case EbtSampler2D: + mangledName += "s2"; + break; + case EbtSampler3D: + mangledName += "s3"; + break; + case EbtSamplerCube: + mangledName += "sC"; + break; + case EbtSampler2DArray: + mangledName += "s2a"; + break; + case EbtSamplerExternalOES: + mangledName += "sext"; + break; + case EbtSampler2DRect: + mangledName += "s2r"; + break; + case EbtISampler2D: + mangledName += "is2"; + break; + case EbtISampler3D: + mangledName += "is3"; + break; + case EbtISamplerCube: + mangledName += "isC"; + break; + case EbtISampler2DArray: + mangledName += "is2a"; + break; + case EbtUSampler2D: + mangledName += "us2"; + break; + case EbtUSampler3D: + mangledName += "us3"; + break; + case EbtUSamplerCube: + mangledName += "usC"; + break; + case EbtUSampler2DArray: + mangledName += "us2a"; + break; + case EbtSampler2DShadow: + mangledName += "s2s"; + break; + case EbtSamplerCubeShadow: + mangledName += "sCs"; + break; + case EbtSampler2DArrayShadow: + mangledName += "s2as"; + break; + case EbtStruct: + mangledName += structure->mangledName(); + break; + case EbtInterfaceBlock: + mangledName += interfaceBlock->mangledName(); + break; + default: + UNREACHABLE(); + } + + if (isMatrix()) + { + mangledName += static_cast<char>('0' + getCols()); + mangledName += static_cast<char>('x'); + mangledName += static_cast<char>('0' + getRows()); + } + else + { + mangledName += static_cast<char>('0' + getNominalSize()); + } + + if (isArray()) + { + char buf[20]; + snprintf(buf, sizeof(buf), "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } + return mangledName; +} + +size_t TType::getObjectSize() const +{ + size_t totalSize; + + if (getBasicType() == EbtStruct) + totalSize = structure->objectSize(); + else + totalSize = primarySize * secondarySize; + + if (isArray()) + { + size_t arraySize = getArraySize(); + if (arraySize > INT_MAX / totalSize) + totalSize = INT_MAX; + else + totalSize *= arraySize; + } + + return totalSize; +} + +bool TStructure::containsArrays() const +{ + for (size_t i = 0; i < mFields->size(); ++i) + { + const TType *fieldType = (*mFields)[i]->type(); + if (fieldType->isArray() || fieldType->isStructureContainingArrays()) + return true; + } + return false; +} + +TString TFieldListCollection::buildMangledName() const +{ + TString mangledName(mangledNamePrefix()); + mangledName += *mName; + for (size_t i = 0; i < mFields->size(); ++i) + { + mangledName += '-'; + mangledName += (*mFields)[i]->type()->getMangledName(); + } + return mangledName; +} + +size_t TFieldListCollection::calculateObjectSize() const +{ + size_t size = 0; + for (size_t i = 0; i < mFields->size(); ++i) + { + size_t fieldSize = (*mFields)[i]->type()->getObjectSize(); + if (fieldSize > INT_MAX - size) + size = INT_MAX; + else + size += fieldSize; + } + return size; +} + +int TStructure::calculateDeepestNesting() const +{ + int maxNesting = 0; + for (size_t i = 0; i < mFields->size(); ++i) + maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting()); + return 1 + maxNesting; +} diff --git a/chromium/third_party/angle/src/compiler/translator/Types.h b/chromium/third_party/angle/src/compiler/translator/Types.h new file mode 100644 index 00000000000..76297202a56 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/Types.h @@ -0,0 +1,586 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _TYPES_INCLUDED +#define _TYPES_INCLUDED + +#include "common/angleutils.h" + +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/compilerdebug.h" + +struct TPublicType; +class TType; +class TSymbol; + +class TField +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TField(TType *type, TString *name, const TSourceLoc &line) + : mType(type), + mName(name), + mLine(line) + { + } + + // TODO(alokp): We should only return const type. + // Fix it by tweaking grammar. + TType *type() + { + return mType; + } + const TType *type() const + { + return mType; + } + + const TString &name() const + { + return *mName; + } + const TSourceLoc &line() const + { + return mLine; + } + + bool equals(const TField &other) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TField); + TType *mType; + TString *mName; + TSourceLoc mLine; +}; + +typedef TVector<TField *> TFieldList; +inline TFieldList *NewPoolTFieldList() +{ + void *memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList)); + return new(memory) TFieldList; +} + +class TFieldListCollection +{ + public: + const TString &name() const + { + return *mName; + } + const TFieldList &fields() const + { + return *mFields; + } + + const TString &mangledName() const + { + if (mMangledName.empty()) + mMangledName = buildMangledName(); + return mMangledName; + } + size_t objectSize() const + { + if (mObjectSize == 0) + mObjectSize = calculateObjectSize(); + return mObjectSize; + }; + + protected: + TFieldListCollection(const TString *name, TFieldList *fields) + : mName(name), + mFields(fields), + mObjectSize(0) + { + } + TString buildMangledName() const; + size_t calculateObjectSize() const; + virtual TString mangledNamePrefix() const = 0; + + bool equals(const TFieldListCollection &other) const; + + const TString *mName; + TFieldList *mFields; + + mutable TString mMangledName; + mutable size_t mObjectSize; +}; + +// May also represent interface blocks +class TStructure : public TFieldListCollection +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TStructure(const TString *name, TFieldList *fields) + : TFieldListCollection(name, fields), + mDeepestNesting(0), + mUniqueId(0) + { + } + + int deepestNesting() const + { + if (mDeepestNesting == 0) + mDeepestNesting = calculateDeepestNesting(); + return mDeepestNesting; + } + bool containsArrays() const; + + bool equals(const TStructure &other) const; + + void setUniqueId(int uniqueId) + { + mUniqueId = uniqueId; + } + + int uniqueId() const + { + ASSERT(mUniqueId != 0); + return mUniqueId; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TStructure); + virtual TString mangledNamePrefix() const + { + return "struct-"; + } + int calculateDeepestNesting() const; + + mutable int mDeepestNesting; + int mUniqueId; +}; + +class TInterfaceBlock : public TFieldListCollection +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TInterfaceBlock(const TString *name, TFieldList *fields, const TString *instanceName, + int arraySize, const TLayoutQualifier &layoutQualifier) + : TFieldListCollection(name, fields), + mInstanceName(instanceName), + mArraySize(arraySize), + mBlockStorage(layoutQualifier.blockStorage), + mMatrixPacking(layoutQualifier.matrixPacking) + { + } + + const TString &instanceName() const + { + return *mInstanceName; + } + bool hasInstanceName() const + { + return mInstanceName != NULL; + } + bool isArray() const + { + return mArraySize > 0; + } + int arraySize() const + { + return mArraySize; + } + TLayoutBlockStorage blockStorage() const + { + return mBlockStorage; + } + TLayoutMatrixPacking matrixPacking() const + { + return mMatrixPacking; + } + + bool equals(const TInterfaceBlock &other) const; + + private: + DISALLOW_COPY_AND_ASSIGN(TInterfaceBlock); + virtual TString mangledNamePrefix() const + { + return "iblock-"; + } + + const TString *mInstanceName; // for interface block instance names + int mArraySize; // 0 if not an array + TLayoutBlockStorage mBlockStorage; + TLayoutMatrixPacking mMatrixPacking; +}; + +// +// Base class for things that have a type. +// +class TType +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TType() + { + } + TType(TBasicType t, unsigned char ps = 1, unsigned char ss = 1) + : type(t), precision(EbpUndefined), qualifier(EvqGlobal), + layoutQualifier(TLayoutQualifier::create()), + primarySize(ps), secondarySize(ss), array(false), arraySize(0), + interfaceBlock(0), structure(0) + { + } + TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, + unsigned char ps = 1, unsigned char ss = 1, bool a = false) + : type(t), precision(p), qualifier(q), + layoutQualifier(TLayoutQualifier::create()), + primarySize(ps), secondarySize(ss), array(a), arraySize(0), + interfaceBlock(0), structure(0) + { + } + explicit TType(const TPublicType &p); + TType(TStructure *userDef, TPrecision p = EbpUndefined) + : type(EbtStruct), precision(p), qualifier(EvqTemporary), + layoutQualifier(TLayoutQualifier::create()), + primarySize(1), secondarySize(1), array(false), arraySize(0), + interfaceBlock(0), structure(userDef) + { + } + TType(TInterfaceBlock *interfaceBlockIn, TQualifier qualifierIn, + TLayoutQualifier layoutQualifierIn, int arraySizeIn) + : type(EbtInterfaceBlock), precision(EbpUndefined), qualifier(qualifierIn), + layoutQualifier(layoutQualifierIn), + primarySize(1), secondarySize(1), array(arraySizeIn > 0), arraySize(arraySizeIn), + interfaceBlock(interfaceBlockIn), structure(0) + { + } + + TBasicType getBasicType() const + { + return type; + } + void setBasicType(TBasicType t) + { + type = t; + } + + TPrecision getPrecision() const + { + return precision; + } + void setPrecision(TPrecision p) + { + precision = p; + } + + TQualifier getQualifier() const + { + return qualifier; + } + void setQualifier(TQualifier q) + { + qualifier = q; + } + + TLayoutQualifier getLayoutQualifier() const + { + return layoutQualifier; + } + void setLayoutQualifier(TLayoutQualifier lq) + { + layoutQualifier = lq; + } + + int getNominalSize() const + { + return primarySize; + } + int getSecondarySize() const + { + return secondarySize; + } + int getCols() const + { + ASSERT(isMatrix()); + return primarySize; + } + int getRows() const + { + ASSERT(isMatrix()); + return secondarySize; + } + void setPrimarySize(unsigned char ps) + { + primarySize = ps; + } + void setSecondarySize(unsigned char ss) + { + secondarySize = ss; + } + + // Full size of single instance of type + size_t getObjectSize() const; + + bool isMatrix() const + { + return primarySize > 1 && secondarySize > 1; + } + bool isArray() const + { + return array ? true : false; + } + int getArraySize() const + { + return arraySize; + } + void setArraySize(int s) + { + array = true; + arraySize = s; + } + void clearArrayness() + { + array = false; + arraySize = 0; + } + + TInterfaceBlock *getInterfaceBlock() const + { + return interfaceBlock; + } + void setInterfaceBlock(TInterfaceBlock *interfaceBlockIn) + { + interfaceBlock = interfaceBlockIn; + } + bool isInterfaceBlock() const + { + return type == EbtInterfaceBlock; + } + + bool isVector() const + { + return primarySize > 1 && secondarySize == 1; + } + bool isScalar() const + { + return primarySize == 1 && secondarySize == 1 && !structure; + } + bool isScalarInt() const + { + return isScalar() && (type == EbtInt || type == EbtUInt); + } + + TStructure *getStruct() const + { + return structure; + } + void setStruct(TStructure *s) + { + structure = s; + } + + const TString &getMangledName() + { + if (mangled.empty()) + { + mangled = buildMangledName(); + mangled += ';'; + } + + return mangled; + } + + // This is different from operator== as we also compare + // precision here. + bool equals(const TType &other) const; + + bool sameElementType(const TType &right) const + { + return type == right.type && + primarySize == right.primarySize && + secondarySize == right.secondarySize && + structure == right.structure; + } + bool operator==(const TType &right) const + { + return type == right.type && + primarySize == right.primarySize && + secondarySize == right.secondarySize && + array == right.array && (!array || arraySize == right.arraySize) && + structure == right.structure; + // don't check the qualifier, it's not ever what's being sought after + } + bool operator!=(const TType &right) const + { + return !operator==(right); + } + bool operator<(const TType &right) const + { + if (type != right.type) + return type < right.type; + if (primarySize != right.primarySize) + return primarySize < right.primarySize; + if (secondarySize != right.secondarySize) + return secondarySize < right.secondarySize; + if (array != right.array) + return array < right.array; + if (arraySize != right.arraySize) + return arraySize < right.arraySize; + if (structure != right.structure) + return structure < right.structure; + + return false; + } + + const char *getBasicString() const + { + return ::getBasicString(type); + } + const char *getPrecisionString() const + { + return ::getPrecisionString(precision); + } + const char *getQualifierString() const + { + return ::getQualifierString(qualifier); + } + TString getCompleteString() const; + + // If this type is a struct, returns the deepest struct nesting of + // any field in the struct. For example: + // struct nesting1 { + // vec4 position; + // }; + // struct nesting2 { + // nesting1 field1; + // vec4 field2; + // }; + // For type "nesting2", this method would return 2 -- the number + // of structures through which indirection must occur to reach the + // deepest field (nesting2.field1.position). + int getDeepestStructNesting() const + { + return structure ? structure->deepestNesting() : 0; + } + + bool isStructureContainingArrays() const + { + return structure ? structure->containsArrays() : false; + } + + protected: + TString buildMangledName() const; + size_t getStructSize() const; + void computeDeepestStructNesting(); + + TBasicType type; + TPrecision precision; + TQualifier qualifier; + TLayoutQualifier layoutQualifier; + unsigned char primarySize; // size of vector or cols matrix + unsigned char secondarySize; // rows of a matrix + bool array; + int arraySize; + + // 0 unless this is an interface block, or interface block member variable + TInterfaceBlock *interfaceBlock; + + // 0 unless this is a struct + TStructure *structure; + + mutable TString mangled; +}; + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + TBasicType type; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TPrecision precision; + unsigned char primarySize; // size of vector or cols of matrix + unsigned char secondarySize; // rows of matrix + bool array; + int arraySize; + TType *userDef; + TSourceLoc line; + + void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln) + { + type = bt; + layoutQualifier = TLayoutQualifier::create(); + qualifier = q; + precision = EbpUndefined; + primarySize = 1; + secondarySize = 1; + array = false; + arraySize = 0; + userDef = 0; + line = ln; + } + + void setAggregate(unsigned char size) + { + primarySize = size; + } + + void setMatrix(unsigned char c, unsigned char r) + { + ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4); + primarySize = c; + secondarySize = r; + } + + void setArray(bool a, int s = 0) + { + array = a; + arraySize = s; + } + + bool isStructureContainingArrays() const + { + if (!userDef) + { + return false; + } + + return userDef->isStructureContainingArrays(); + } + + bool isMatrix() const + { + return primarySize > 1 && secondarySize > 1; + } + + bool isVector() const + { + return primarySize > 1 && secondarySize == 1; + } + + int getCols() const + { + ASSERT(isMatrix()); + return primarySize; + } + + int getRows() const + { + ASSERT(isMatrix()); + return secondarySize; + } + + int getNominalSize() const + { + return primarySize; + } + + bool isAggregate() const + { + return array || isMatrix() || isVector(); + } +}; + +#endif // _TYPES_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp new file mode 100644 index 00000000000..b7826119aea --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.cpp @@ -0,0 +1,184 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements. +// The results are assigned to s# temporaries, which are used by the main translator instead of +// the original expression. +// + +#include "compiler/translator/UnfoldShortCircuit.h" + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/OutputHLSL.h" + +namespace sh +{ +UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) +{ + mTemporaryIndex = 0; +} + +void UnfoldShortCircuit::traverse(TIntermNode *node) +{ + int rewindIndex = mTemporaryIndex; + node->traverse(this); + mTemporaryIndex = rewindIndex; +} + +bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + + // If our right node doesn't have side effects, we know we don't need to unfold this + // expression: there will be no short-circuiting side effects to avoid + // (note: unfolding doesn't depend on the left node -- it will always be evaluated) + if (!node->getRight()->hasSideEffects()) + { + return true; + } + + switch (node->getOp()) + { + case EOpLogicalOr: + // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;", + // and then further simplifies down to "bool s = x; if(!s) s = y;". + { + int i = mTemporaryIndex; + + out << "bool s" << i << ";\n"; + + out << "{\n"; + + mTemporaryIndex = i + 1; + node->getLeft()->traverse(this); + out << "s" << i << " = "; + mTemporaryIndex = i + 1; + node->getLeft()->traverse(mOutputHLSL); + out << ";\n"; + out << "if (!s" << i << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getRight()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getRight()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + out << "}\n"; + + mTemporaryIndex = i + 1; + } + return false; + case EOpLogicalAnd: + // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;", + // and then further simplifies down to "bool s = x; if(s) s = y;". + { + int i = mTemporaryIndex; + + out << "bool s" << i << ";\n"; + + out << "{\n"; + + mTemporaryIndex = i + 1; + node->getLeft()->traverse(this); + out << "s" << i << " = "; + mTemporaryIndex = i + 1; + node->getLeft()->traverse(mOutputHLSL); + out << ";\n"; + out << "if (s" << i << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getRight()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getRight()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + out << "}\n"; + + mTemporaryIndex = i + 1; + } + return false; + default: + return true; + } +} + +bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + + // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" + if (node->usesTernaryOperator()) + { + int i = mTemporaryIndex; + + out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n"; + + out << "{\n"; + + mTemporaryIndex = i + 1; + node->getCondition()->traverse(this); + out << "if ("; + mTemporaryIndex = i + 1; + node->getCondition()->traverse(mOutputHLSL); + out << ")\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getTrueBlock()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getTrueBlock()->traverse(mOutputHLSL); + out << ";\n" + "}\n" + "else\n" + "{\n"; + mTemporaryIndex = i + 1; + node->getFalseBlock()->traverse(this); + out << " s" << i << " = "; + mTemporaryIndex = i + 1; + node->getFalseBlock()->traverse(mOutputHLSL); + out << ";\n" + "}\n"; + + out << "}\n"; + + mTemporaryIndex = i + 1; + } + + return false; +} + +bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node) +{ + int rewindIndex = mTemporaryIndex; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + } + + if (node->getExpression()) + { + node->getExpression()->traverse(this); + } + + mTemporaryIndex = rewindIndex; + + return false; +} + +int UnfoldShortCircuit::getNextTemporaryIndex() +{ + return mTemporaryIndex++; +} +} diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h new file mode 100644 index 00000000000..1e416bc04c1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuit.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements +// + +#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_ +#define COMPILER_UNFOLDSHORTCIRCUIT_H_ + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/ParseContext.h" + +namespace sh +{ +class OutputHLSL; + +class UnfoldShortCircuit : public TIntermTraverser +{ + public: + UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL); + + void traverse(TIntermNode *node); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitSelection(Visit visit, TIntermSelection *node); + bool visitLoop(Visit visit, TIntermLoop *node); + + int getNextTemporaryIndex(); + + protected: + TParseContext &mContext; + OutputHLSL *const mOutputHLSL; + + int mTemporaryIndex; +}; +} + +#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp new file mode 100644 index 00000000000..29c4397d561 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/UnfoldShortCircuitAST.h" + +namespace +{ + +// "x || y" is equivalent to "x ? true : y". +TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y) +{ + const TType boolType(EbtBool, EbpUndefined); + ConstantUnion *u = new ConstantUnion; + u->setBConst(true); + TIntermConstantUnion *trueNode = new TIntermConstantUnion( + u, TType(EbtBool, EbpUndefined, EvqConst, 1)); + return new TIntermSelection(x, trueNode, y, boolType); +} + +// "x && y" is equivalent to "x ? y : false". +TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y) +{ + const TType boolType(EbtBool, EbpUndefined); + ConstantUnion *u = new ConstantUnion; + u->setBConst(false); + TIntermConstantUnion *falseNode = new TIntermConstantUnion( + u, TType(EbtBool, EbpUndefined, EvqConst, 1)); + return new TIntermSelection(x, y, falseNode, boolType); +} + +} // namespace anonymous + +bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) +{ + TIntermSelection *replacement = NULL; + + switch (node->getOp()) + { + case EOpLogicalOr: + replacement = UnfoldOR(node->getLeft(), node->getRight()); + break; + case EOpLogicalAnd: + replacement = UnfoldAND(node->getLeft(), node->getRight()); + break; + default: + break; + } + if (replacement) + { + replacements.push_back( + NodeUpdateEntry(getParentNode(), node, replacement)); + } + return true; +} + +void UnfoldShortCircuitAST::updateTree() +{ + for (size_t ii = 0; ii < replacements.size(); ++ii) + { + const NodeUpdateEntry& entry = replacements[ii]; + ASSERT(entry.parent); + bool replaced = entry.parent->replaceChildNode( + entry.original, entry.replacement); + ASSERT(replaced); + + // In AST traversing, a parent is visited before its children. + // After we replace a node, if an immediate child is to + // be replaced, we need to make sure we don't update the replaced + // node; instead, we update the replacement node. + for (size_t jj = ii + 1; jj < replacements.size(); ++jj) + { + NodeUpdateEntry& entry2 = replacements[jj]; + if (entry2.parent == entry.original) + entry2.parent = entry.replacement; + } + } +} + diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h new file mode 100644 index 00000000000..24c14a60e37 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// UnfoldShortCircuitAST is an AST traverser to replace short-circuiting +// operations with ternary operations. +// + +#ifndef COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ +#define COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ + +#include "common/angleutils.h" +#include "compiler/translator/intermediate.h" + +// This traverser identifies all the short circuit binary nodes that need to +// be replaced, and creates the corresponding replacement nodes. However, +// the actual replacements happen after the traverse through updateTree(). + +class UnfoldShortCircuitAST : public TIntermTraverser +{ + public: + UnfoldShortCircuitAST() { } + + virtual bool visitBinary(Visit visit, TIntermBinary *); + + void updateTree(); + + private: + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement) + : parent(_parent), + original(_original), + replacement(_replacement) {} + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + }; + + // During traversing, save all the replacements that need to happen; + // then replace them by calling updateNodes(). + std::vector<NodeUpdateEntry> replacements; + + DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST); +}; + +#endif // COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp new file mode 100644 index 00000000000..e96a777cee3 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.cpp @@ -0,0 +1,469 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/ValidateLimitations.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/ParseContext.h" + +namespace +{ + +// Traverses a node to check if it represents a constant index expression. +// Definition: +// constant-index-expressions are a superset of constant-expressions. +// Constant-index-expressions can include loop indices as defined in +// GLSL ES 1.0 spec, Appendix A, section 4. +// The following are constant-index-expressions: +// - Constant expressions +// - Loop indices as defined in section 4 +// - Expressions composed of both of the above +class ValidateConstIndexExpr : public TIntermTraverser +{ + public: + ValidateConstIndexExpr(TLoopStack& stack) + : mValid(true), mLoopStack(stack) {} + + // Returns true if the parsed node represents a constant index expression. + bool isValid() const { return mValid; } + + virtual void visitSymbol(TIntermSymbol *symbol) + { + // Only constants and loop indices are allowed in a + // constant index expression. + if (mValid) + { + mValid = (symbol->getQualifier() == EvqConst) || + (mLoopStack.findLoop(symbol)); + } + } + + private: + bool mValid; + TLoopStack& mLoopStack; +}; + +} // namespace anonymous + +ValidateLimitations::ValidateLimitations(ShShaderType shaderType, + TInfoSinkBase &sink) + : mShaderType(shaderType), + mSink(sink), + mNumErrors(0) +{ +} + +bool ValidateLimitations::visitBinary(Visit, TIntermBinary *node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getLeft()); + + // Check indexing. + switch (node->getOp()) + { + case EOpIndexDirect: + case EOpIndexIndirect: + validateIndexing(node); + break; + default: + break; + } + return true; +} + +bool ValidateLimitations::visitUnary(Visit, TIntermUnary *node) +{ + // Check if loop index is modified in the loop body. + validateOperation(node, node->getOperand()); + + return true; +} + +bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate *node) +{ + switch (node->getOp()) { + case EOpFunctionCall: + validateFunctionCall(node); + break; + default: + break; + } + return true; +} + +bool ValidateLimitations::visitLoop(Visit, TIntermLoop *node) +{ + if (!validateLoopType(node)) + return false; + + if (!validateForLoopHeader(node)) + return false; + + TIntermNode *body = node->getBody(); + if (body != NULL) + { + mLoopStack.push(node); + body->traverse(this); + mLoopStack.pop(); + } + + // The loop is fully processed - no need to visit children. + return false; +} + +void ValidateLimitations::error(TSourceLoc loc, + const char *reason, const char *token) +{ + mSink.prefix(EPrefixError); + mSink.location(loc); + mSink << "'" << token << "' : " << reason << "\n"; + ++mNumErrors; +} + +bool ValidateLimitations::withinLoopBody() const +{ + return !mLoopStack.empty(); +} + +bool ValidateLimitations::isLoopIndex(TIntermSymbol *symbol) +{ + return mLoopStack.findLoop(symbol) != NULL; +} + +bool ValidateLimitations::validateLoopType(TIntermLoop *node) +{ + TLoopType type = node->getType(); + if (type == ELoopFor) + return true; + + // Reject while and do-while loops. + error(node->getLine(), + "This type of loop is not allowed", + type == ELoopWhile ? "while" : "do"); + return false; +} + +bool ValidateLimitations::validateForLoopHeader(TIntermLoop *node) +{ + ASSERT(node->getType() == ELoopFor); + + // + // The for statement has the form: + // for ( init-declaration ; condition ; expression ) statement + // + int indexSymbolId = validateForLoopInit(node); + if (indexSymbolId < 0) + return false; + if (!validateForLoopCond(node, indexSymbolId)) + return false; + if (!validateForLoopExpr(node, indexSymbolId)) + return false; + + return true; +} + +int ValidateLimitations::validateForLoopInit(TIntermLoop *node) +{ + TIntermNode *init = node->getInit(); + if (init == NULL) + { + error(node->getLine(), "Missing init declaration", "for"); + return -1; + } + + // + // init-declaration has the form: + // type-specifier identifier = constant-expression + // + TIntermAggregate *decl = init->getAsAggregate(); + if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) + { + error(init->getLine(), "Invalid init declaration", "for"); + return -1; + } + // To keep things simple do not allow declaration list. + TIntermSequence &declSeq = decl->getSequence(); + if (declSeq.size() != 1) + { + error(decl->getLine(), "Invalid init declaration", "for"); + return -1; + } + TIntermBinary *declInit = declSeq[0]->getAsBinaryNode(); + if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) + { + error(decl->getLine(), "Invalid init declaration", "for"); + return -1; + } + TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode(); + if (symbol == NULL) + { + error(declInit->getLine(), "Invalid init declaration", "for"); + return -1; + } + // The loop index has type int or float. + TBasicType type = symbol->getBasicType(); + if ((type != EbtInt) && (type != EbtUInt) && (type != EbtFloat)) { + error(symbol->getLine(), + "Invalid type for loop index", getBasicString(type)); + return -1; + } + // The loop index is initialized with constant expression. + if (!isConstExpr(declInit->getRight())) + { + error(declInit->getLine(), + "Loop index cannot be initialized with non-constant expression", + symbol->getSymbol().c_str()); + return -1; + } + + return symbol->getId(); +} + +bool ValidateLimitations::validateForLoopCond(TIntermLoop *node, + int indexSymbolId) +{ + TIntermNode *cond = node->getCondition(); + if (cond == NULL) + { + error(node->getLine(), "Missing condition", "for"); + return false; + } + // + // condition has the form: + // loop_index relational_operator constant_expression + // + TIntermBinary *binOp = cond->getAsBinaryNode(); + if (binOp == NULL) + { + error(node->getLine(), "Invalid condition", "for"); + return false; + } + // Loop index should be to the left of relational operator. + TIntermSymbol *symbol = binOp->getLeft()->getAsSymbolNode(); + if (symbol == NULL) + { + error(binOp->getLine(), "Invalid condition", "for"); + return false; + } + if (symbol->getId() != indexSymbolId) + { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + // Relational operator is one of: > >= < <= == or !=. + switch (binOp->getOp()) + { + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + break; + default: + error(binOp->getLine(), + "Invalid relational operator", + getOperatorString(binOp->getOp())); + break; + } + // Loop index must be compared with a constant. + if (!isConstExpr(binOp->getRight())) + { + error(binOp->getLine(), + "Loop index cannot be compared with non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + + return true; +} + +bool ValidateLimitations::validateForLoopExpr(TIntermLoop *node, + int indexSymbolId) +{ + TIntermNode *expr = node->getExpression(); + if (expr == NULL) + { + error(node->getLine(), "Missing expression", "for"); + return false; + } + + // for expression has one of the following forms: + // loop_index++ + // loop_index-- + // loop_index += constant_expression + // loop_index -= constant_expression + // ++loop_index + // --loop_index + // The last two forms are not specified in the spec, but I am assuming + // its an oversight. + TIntermUnary *unOp = expr->getAsUnaryNode(); + TIntermBinary *binOp = unOp ? NULL : expr->getAsBinaryNode(); + + TOperator op = EOpNull; + TIntermSymbol *symbol = NULL; + if (unOp != NULL) + { + op = unOp->getOp(); + symbol = unOp->getOperand()->getAsSymbolNode(); + } + else if (binOp != NULL) + { + op = binOp->getOp(); + symbol = binOp->getLeft()->getAsSymbolNode(); + } + + // The operand must be loop index. + if (symbol == NULL) + { + error(expr->getLine(), "Invalid expression", "for"); + return false; + } + if (symbol->getId() != indexSymbolId) + { + error(symbol->getLine(), + "Expected loop index", symbol->getSymbol().c_str()); + return false; + } + + // The operator is one of: ++ -- += -=. + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + ASSERT((unOp != NULL) && (binOp == NULL)); + break; + case EOpAddAssign: + case EOpSubAssign: + ASSERT((unOp == NULL) && (binOp != NULL)); + break; + default: + error(expr->getLine(), "Invalid operator", getOperatorString(op)); + return false; + } + + // Loop index must be incremented/decremented with a constant. + if (binOp != NULL) + { + if (!isConstExpr(binOp->getRight())) + { + error(binOp->getLine(), + "Loop index cannot be modified by non-constant expression", + symbol->getSymbol().c_str()); + return false; + } + } + + return true; +} + +bool ValidateLimitations::validateFunctionCall(TIntermAggregate *node) +{ + ASSERT(node->getOp() == EOpFunctionCall); + + // If not within loop body, there is nothing to check. + if (!withinLoopBody()) + return true; + + // List of param indices for which loop indices are used as argument. + typedef std::vector<size_t> ParamIndex; + ParamIndex pIndex; + TIntermSequence& params = node->getSequence(); + for (TIntermSequence::size_type i = 0; i < params.size(); ++i) + { + TIntermSymbol *symbol = params[i]->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) + pIndex.push_back(i); + } + // If none of the loop indices are used as arguments, + // there is nothing to check. + if (pIndex.empty()) + return true; + + bool valid = true; + TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable; + TSymbol* symbol = symbolTable.find(node->getName(), GetGlobalParseContext()->shaderVersion); + ASSERT(symbol && symbol->isFunction()); + TFunction *function = static_cast<TFunction *>(symbol); + for (ParamIndex::const_iterator i = pIndex.begin(); + i != pIndex.end(); ++i) + { + const TParameter ¶m = function->getParam(*i); + TQualifier qual = param.type->getQualifier(); + if ((qual == EvqOut) || (qual == EvqInOut)) + { + error(params[*i]->getLine(), + "Loop index cannot be used as argument to a function out or inout parameter", + params[*i]->getAsSymbolNode()->getSymbol().c_str()); + valid = false; + } + } + + return valid; +} + +bool ValidateLimitations::validateOperation(TIntermOperator *node, + TIntermNode* operand) +{ + // Check if loop index is modified in the loop body. + if (!withinLoopBody() || !node->isAssignment()) + return true; + + TIntermSymbol *symbol = operand->getAsSymbolNode(); + if (symbol && isLoopIndex(symbol)) + { + error(node->getLine(), + "Loop index cannot be statically assigned to within the body of the loop", + symbol->getSymbol().c_str()); + } + return true; +} + +bool ValidateLimitations::isConstExpr(TIntermNode *node) +{ + ASSERT(node != NULL); + return node->getAsConstantUnion() != NULL; +} + +bool ValidateLimitations::isConstIndexExpr(TIntermNode *node) +{ + ASSERT(node != NULL); + + ValidateConstIndexExpr validate(mLoopStack); + node->traverse(&validate); + return validate.isValid(); +} + +bool ValidateLimitations::validateIndexing(TIntermBinary *node) +{ + ASSERT((node->getOp() == EOpIndexDirect) || + (node->getOp() == EOpIndexIndirect)); + + bool valid = true; + TIntermTyped *index = node->getRight(); + // The index expression must have integral type. + if (!index->isScalarInt()) { + error(index->getLine(), + "Index expression must have integral type", + index->getCompleteString().c_str()); + valid = false; + } + // The index expession must be a constant-index-expression unless + // the operand is a uniform in a vertex shader. + TIntermTyped *operand = node->getLeft(); + bool skip = (mShaderType == SH_VERTEX_SHADER) && + (operand->getQualifier() == EvqUniform); + if (!skip && !isConstIndexExpr(index)) + { + error(index->getLine(), "Index expression must be constant", "[]"); + valid = false; + } + return valid; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h new file mode 100644 index 00000000000..f28995c640b --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ValidateLimitations.h @@ -0,0 +1,55 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/LoopInfo.h" + +class TInfoSinkBase; + +// Traverses intermediate tree to ensure that the shader does not exceed the +// minimum functionality mandated in GLSL 1.0 spec, Appendix A. +class ValidateLimitations : public TIntermTraverser +{ + public: + ValidateLimitations(ShShaderType shaderType, TInfoSinkBase &sink); + + int numErrors() const { return mNumErrors; } + + virtual bool visitBinary(Visit, TIntermBinary *); + virtual bool visitUnary(Visit, TIntermUnary *); + virtual bool visitAggregate(Visit, TIntermAggregate *); + virtual bool visitLoop(Visit, TIntermLoop *); + + private: + void error(TSourceLoc loc, const char *reason, const char *token); + + bool withinLoopBody() const; + bool isLoopIndex(TIntermSymbol *symbol); + bool validateLoopType(TIntermLoop *node); + + bool validateForLoopHeader(TIntermLoop *node); + // If valid, return the index symbol id; Otherwise, return -1. + int validateForLoopInit(TIntermLoop *node); + bool validateForLoopCond(TIntermLoop *node, int indexSymbolId); + bool validateForLoopExpr(TIntermLoop *node, int indexSymbolId); + + // Returns true if none of the loop indices is used as the argument to + // the given function out or inout parameter. + bool validateFunctionCall(TIntermAggregate *node); + bool validateOperation(TIntermOperator *node, TIntermNode *operand); + + // Returns true if indexing does not exceed the minimum functionality + // mandated in GLSL 1.0 spec, Appendix A, Section 5. + bool isConstExpr(TIntermNode *node); + bool isConstIndexExpr(TIntermNode *node); + bool validateIndexing(TIntermBinary *node); + + ShShaderType mShaderType; + TInfoSinkBase &mSink; + int mNumErrors; + TLoopStack mLoopStack; +}; + diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp new file mode 100644 index 00000000000..ac1c10d6b03 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/ValidateOutputs.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/ParseContext.h" + +ValidateOutputs::ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers) + : mSink(sink), + mMaxDrawBuffers(maxDrawBuffers), + mNumErrors(0), + mHasUnspecifiedOutputLocation(false) +{ +} + +void ValidateOutputs::visitSymbol(TIntermSymbol *symbol) +{ + TString name = symbol->getSymbol(); + TQualifier qualifier = symbol->getQualifier(); + + if (mVisitedSymbols.count(name) == 1) + return; + + mVisitedSymbols.insert(name); + + if (qualifier == EvqFragmentOut) + { + const TType &type = symbol->getType(); + const int location = type.getLayoutQualifier().location; + + if (mHasUnspecifiedOutputLocation) + { + error(symbol->getLine(), "must explicitly specify all locations when using multiple fragment outputs", name.c_str()); + } + else if (location == -1) + { + mHasUnspecifiedOutputLocation = true; + } + else + { + OutputMap::iterator mapEntry = mOutputMap.find(location); + if (mapEntry == mOutputMap.end()) + { + const int elementCount = type.isArray() ? type.getArraySize() : 1; + if (location + elementCount > mMaxDrawBuffers) + { + error(symbol->getLine(), "output location must be < MAX_DRAW_BUFFERS", name.c_str()); + } + + for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) + { + const int offsetLocation = location + elementIndex; + mOutputMap[offsetLocation] = symbol; + } + } + else + { + std::stringstream strstr; + strstr << "conflicting output locations with previously defined output '" + << mapEntry->second->getSymbol() << "'"; + + error(symbol->getLine(), strstr.str().c_str(), name.c_str()); + } + } + } +} + +void ValidateOutputs::error(TSourceLoc loc, const char *reason, const char* token) +{ + mSink.prefix(EPrefixError); + mSink.location(loc); + mSink << "'" << token << "' : " << reason << "\n"; + mNumErrors++; +} diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h new file mode 100644 index 00000000000..e391ad94860 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/intermediate.h" + +#include <set> + +class TInfoSinkBase; + +class ValidateOutputs : public TIntermTraverser +{ + public: + ValidateOutputs(TInfoSinkBase& sink, int maxDrawBuffers); + + int numErrors() const { return mNumErrors; } + + virtual void visitSymbol(TIntermSymbol*); + + private: + TInfoSinkBase& mSink; + int mMaxDrawBuffers; + int mNumErrors; + bool mHasUnspecifiedOutputLocation; + + typedef std::map<int, TIntermSymbol*> OutputMap; + OutputMap mOutputMap; + std::set<TString> mVisitedSymbols; + + void error(TSourceLoc loc, const char *reason, const char* token); +}; diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp new file mode 100644 index 00000000000..d0b19907f4c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp @@ -0,0 +1,374 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/VariableInfo.h" + +namespace { + +TString arrayBrackets(int index) +{ + TStringStream stream; + stream << "[" << index << "]"; + return stream.str(); +} + +// Returns the data type for an attribute, uniform, or varying. +ShDataType getVariableDataType(const TType& type) +{ + switch (type.getBasicType()) { + case EbtFloat: + if (type.isMatrix()) { + switch (type.getCols()) + { + case 2: + switch (type.getRows()) + { + case 2: return SH_FLOAT_MAT2; + case 3: return SH_FLOAT_MAT2x3; + case 4: return SH_FLOAT_MAT2x4; + default: UNREACHABLE(); + } + case 3: + switch (type.getRows()) + { + case 2: return SH_FLOAT_MAT3x2; + case 3: return SH_FLOAT_MAT3; + case 4: return SH_FLOAT_MAT3x4; + default: UNREACHABLE(); + } + case 4: + switch (type.getRows()) + { + case 2: return SH_FLOAT_MAT4x2; + case 3: return SH_FLOAT_MAT4x3; + case 4: return SH_FLOAT_MAT4; + default: UNREACHABLE(); + } + } + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_FLOAT_VEC2; + case 3: return SH_FLOAT_VEC3; + case 4: return SH_FLOAT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_FLOAT; + } + case EbtInt: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_INT_VEC2; + case 3: return SH_INT_VEC3; + case 4: return SH_INT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_INT; + } + case EbtUInt: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_UNSIGNED_INT_VEC2; + case 3: return SH_UNSIGNED_INT_VEC3; + case 4: return SH_UNSIGNED_INT_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_UNSIGNED_INT; + } + case EbtBool: + if (type.isMatrix()) { + UNREACHABLE(); + } else if (type.isVector()) { + switch (type.getNominalSize()) { + case 2: return SH_BOOL_VEC2; + case 3: return SH_BOOL_VEC3; + case 4: return SH_BOOL_VEC4; + default: UNREACHABLE(); + } + } else { + return SH_BOOL; + } + case EbtSampler2D: return SH_SAMPLER_2D; + case EbtSampler3D: return SH_SAMPLER_3D; + case EbtSamplerCube: return SH_SAMPLER_CUBE; + case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES; + case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB; + case EbtSampler2DArray: return SH_SAMPLER_2D_ARRAY; + case EbtISampler2D: return SH_INT_SAMPLER_2D; + case EbtISampler3D: return SH_INT_SAMPLER_3D; + case EbtISamplerCube: return SH_INT_SAMPLER_CUBE; + case EbtISampler2DArray: return SH_INT_SAMPLER_2D_ARRAY; + case EbtUSampler2D: return SH_UNSIGNED_INT_SAMPLER_2D; + case EbtUSampler3D: return SH_UNSIGNED_INT_SAMPLER_3D; + case EbtUSamplerCube: return SH_UNSIGNED_INT_SAMPLER_CUBE; + case EbtUSampler2DArray: return SH_UNSIGNED_INT_SAMPLER_2D_ARRAY; + case EbtSampler2DShadow: return SH_SAMPLER_2D_SHADOW; + case EbtSamplerCubeShadow: return SH_SAMPLER_CUBE_SHADOW; + case EbtSampler2DArrayShadow: return SH_SAMPLER_2D_ARRAY_SHADOW; + default: UNREACHABLE(); + } + return SH_NONE; +} + +void getBuiltInVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList); +void getUserDefinedVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList, + ShHashFunction64 hashFunction); + +// Returns info for an attribute, uniform, or varying. +void getVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList, + ShHashFunction64 hashFunction) +{ + if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { + if (type.isArray()) { + for (int i = 0; i < type.getArraySize(); ++i) { + TString lname = name + arrayBrackets(i); + TString lmappedName = mappedName + arrayBrackets(i); + getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction); + } + } else { + getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction); + } + } else { + getBuiltInVariableInfo(type, name, mappedName, infoList); + } +} + +void getBuiltInVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList) +{ + ASSERT(type.getBasicType() != EbtStruct); + + TVariableInfo varInfo; + if (type.isArray()) { + varInfo.name = (name + "[0]").c_str(); + varInfo.mappedName = (mappedName + "[0]").c_str(); + varInfo.size = type.getArraySize(); + varInfo.isArray = true; + } else { + varInfo.name = name.c_str(); + varInfo.mappedName = mappedName.c_str(); + varInfo.size = 1; + varInfo.isArray = false; + } + varInfo.precision = type.getPrecision(); + varInfo.type = getVariableDataType(type); + infoList.push_back(varInfo); +} + +void getUserDefinedVariableInfo(const TType& type, + const TString& name, + const TString& mappedName, + TVariableInfoList& infoList, + ShHashFunction64 hashFunction) +{ + ASSERT(type.getBasicType() == EbtStruct || type.isInterfaceBlock()); + + const TFieldList& fields = type.isInterfaceBlock() ? + type.getInterfaceBlock()->fields() : + type.getStruct()->fields(); + for (size_t i = 0; i < fields.size(); ++i) { + const TType& fieldType = *(fields[i]->type()); + const TString& fieldName = fields[i]->name(); + getVariableInfo(fieldType, + name + "." + fieldName, + mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction), + infoList, + hashFunction); + } +} + +TVariableInfo* findVariable(const TType& type, + const TString& name, + TVariableInfoList& infoList) +{ + // TODO(zmo): optimize this function. + TString myName = name; + if (type.isArray()) + myName += "[0]"; + for (size_t ii = 0; ii < infoList.size(); ++ii) + { + if (infoList[ii].name.c_str() == myName) + return &(infoList[ii]); + } + return NULL; +} + +} // namespace anonymous + +TVariableInfo::TVariableInfo() + : type(SH_NONE), + size(0), + isArray(false), + precision(EbpUndefined), + staticUse(false) +{ +} + +TVariableInfo::TVariableInfo(ShDataType type, int size) + : type(type), + size(size), + isArray(false), + precision(EbpUndefined), + staticUse(false) +{ +} + +CollectVariables::CollectVariables(TVariableInfoList& attribs, + TVariableInfoList& uniforms, + TVariableInfoList& varyings, + ShHashFunction64 hashFunction) + : mAttribs(attribs), + mUniforms(uniforms), + mVaryings(varyings), + mPointCoordAdded(false), + mFrontFacingAdded(false), + mFragCoordAdded(false), + mHashFunction(hashFunction) +{ +} + +// We want to check whether a uniform/varying is statically used +// because we only count the used ones in packing computing. +// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count +// toward varying counting if they are statically used in a fragment +// shader. +void CollectVariables::visitSymbol(TIntermSymbol* symbol) +{ + ASSERT(symbol != NULL); + TVariableInfo* var = NULL; + switch (symbol->getQualifier()) + { + case EvqVaryingOut: + case EvqInvariantVaryingOut: + case EvqVaryingIn: + case EvqInvariantVaryingIn: + var = findVariable(symbol->getType(), symbol->getSymbol(), mVaryings); + break; + case EvqUniform: + var = findVariable(symbol->getType(), symbol->getSymbol(), mUniforms); + break; + case EvqFragCoord: + if (!mFragCoordAdded) { + TVariableInfo info; + info.name = "gl_FragCoord"; + info.mappedName = "gl_FragCoord"; + info.type = SH_FLOAT_VEC4; + info.size = 1; + info.precision = EbpMedium; // Use mediump as it doesn't really matter. + info.staticUse = true; + mVaryings.push_back(info); + mFragCoordAdded = true; + } + return; + case EvqFrontFacing: + if (!mFrontFacingAdded) { + TVariableInfo info; + info.name = "gl_FrontFacing"; + info.mappedName = "gl_FrontFacing"; + info.type = SH_BOOL; + info.size = 1; + info.precision = EbpUndefined; + info.staticUse = true; + mVaryings.push_back(info); + mFrontFacingAdded = true; + } + return; + case EvqPointCoord: + if (!mPointCoordAdded) { + TVariableInfo info; + info.name = "gl_PointCoord"; + info.mappedName = "gl_PointCoord"; + info.type = SH_FLOAT_VEC2; + info.size = 1; + info.precision = EbpMedium; // Use mediump as it doesn't really matter. + info.staticUse = true; + mVaryings.push_back(info); + mPointCoordAdded = true; + } + return; + default: + break; + } + if (var) + var->staticUse = true; +} + +bool CollectVariables::visitAggregate(Visit, TIntermAggregate* node) +{ + bool visitChildren = true; + + switch (node->getOp()) + { + case EOpDeclaration: { + const TIntermSequence& sequence = node->getSequence(); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if (qualifier == EvqAttribute || qualifier == EvqVertexIn || qualifier == EvqUniform || + qualifier == EvqVaryingIn || qualifier == EvqVaryingOut || + qualifier == EvqInvariantVaryingIn || qualifier == EvqInvariantVaryingOut) + { + TVariableInfoList *infoList = NULL; + + switch (qualifier) + { + case EvqAttribute: + case EvqVertexIn: + infoList = &mAttribs; + break; + case EvqUniform: + infoList = &mUniforms; + break; + default: + infoList = &mVaryings; + break; + } + + for (TIntermSequence::const_iterator i = sequence.begin(); + i != sequence.end(); ++i) + { + const TIntermSymbol* variable = (*i)->getAsSymbolNode(); + // The only case in which the sequence will not contain a + // TIntermSymbol node is initialization. It will contain a + // TInterBinary node in that case. Since attributes, uniforms, + // and varyings cannot be initialized in a shader, we must have + // only TIntermSymbol nodes in the sequence. + ASSERT(variable != NULL); + TString processedSymbol; + if (mHashFunction == NULL) + processedSymbol = variable->getSymbol(); + else + processedSymbol = TIntermTraverser::hash(variable->getSymbol(), mHashFunction); + getVariableInfo(variable->getType(), + variable->getSymbol(), + processedSymbol, + *infoList, + mHashFunction); + visitChildren = false; + } + } + break; + } + default: break; + } + + return visitChildren; +} diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.h b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h new file mode 100644 index 00000000000..fc9e15301bc --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_VARIABLE_INFO_H_ +#define COMPILER_VARIABLE_INFO_H_ + +#include "compiler/translator/intermediate.h" + +// Provides information about a variable. +// It is currently being used to store info about active attribs and uniforms. +struct TVariableInfo { + TVariableInfo(ShDataType type, int size); + TVariableInfo(); + + TPersistString name; + TPersistString mappedName; + ShDataType type; + int size; + bool isArray; + TPrecision precision; + bool staticUse; +}; +typedef std::vector<TVariableInfo> TVariableInfoList; + +// Traverses intermediate tree to collect all attributes, uniforms, varyings. +class CollectVariables : public TIntermTraverser { +public: + CollectVariables(TVariableInfoList& attribs, + TVariableInfoList& uniforms, + TVariableInfoList& varyings, + ShHashFunction64 hashFunction); + + virtual void visitSymbol(TIntermSymbol*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + +private: + TVariableInfoList& mAttribs; + TVariableInfoList& mUniforms; + TVariableInfoList& mVaryings; + + bool mPointCoordAdded; + bool mFrontFacingAdded; + bool mFragCoordAdded; + + ShHashFunction64 mHashFunction; +}; + +#endif // COMPILER_VARIABLE_INFO_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp new file mode 100644 index 00000000000..6390e303941 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp @@ -0,0 +1,323 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#include "compiler/translator/VariablePacker.h" + +#include <algorithm> +#include "compiler/translator/ShHandle.h" + +namespace { +int GetSortOrder(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + case SH_FLOAT_MAT2x4: + case SH_FLOAT_MAT3x4: + case SH_FLOAT_MAT4x2: + case SH_FLOAT_MAT4x3: + return 0; + case SH_FLOAT_MAT2: + return 1; + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + return 2; + case SH_FLOAT_MAT3: + case SH_FLOAT_MAT2x3: + case SH_FLOAT_MAT3x2: + return 3; + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + return 4; + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + return 5; + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 6; + default: + ASSERT(false); + return 7; + } +} +} // namespace + +int VariablePacker::GetNumComponentsPerRow(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + case SH_FLOAT_MAT2: + case SH_FLOAT_MAT2x4: + case SH_FLOAT_MAT3x4: + case SH_FLOAT_MAT4x2: + case SH_FLOAT_MAT4x3: + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + return 4; + case SH_FLOAT_MAT3: + case SH_FLOAT_MAT2x3: + case SH_FLOAT_MAT3x2: + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + return 3; + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + return 2; + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 1; + default: + ASSERT(false); + return 5; + } +} + +int VariablePacker::GetNumRows(ShDataType type) +{ + switch (type) { + case SH_FLOAT_MAT4: + case SH_FLOAT_MAT2x4: + case SH_FLOAT_MAT3x4: + case SH_FLOAT_MAT4x3: + case SH_FLOAT_MAT4x2: + return 4; + case SH_FLOAT_MAT3: + case SH_FLOAT_MAT2x3: + case SH_FLOAT_MAT3x2: + return 3; + case SH_FLOAT_MAT2: + return 2; + case SH_FLOAT_VEC4: + case SH_INT_VEC4: + case SH_BOOL_VEC4: + case SH_FLOAT_VEC3: + case SH_INT_VEC3: + case SH_BOOL_VEC3: + case SH_FLOAT_VEC2: + case SH_INT_VEC2: + case SH_BOOL_VEC2: + case SH_FLOAT: + case SH_INT: + case SH_BOOL: + case SH_SAMPLER_2D: + case SH_SAMPLER_CUBE: + case SH_SAMPLER_EXTERNAL_OES: + case SH_SAMPLER_2D_RECT_ARB: + return 1; + default: + ASSERT(false); + return 100000; + } +} + +struct TVariableInfoComparer { + bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const + { + int lhsSortOrder = GetSortOrder(lhs.type); + int rhsSortOrder = GetSortOrder(rhs.type); + if (lhsSortOrder != rhsSortOrder) { + return lhsSortOrder < rhsSortOrder; + } + // Sort by largest first. + return lhs.size > rhs.size; + } +}; + +unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow) +{ + return ((kColumnMask << (kNumColumns - numComponentsPerRow)) & + kColumnMask) >> column; +} + +void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow) +{ + unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow); + for (int r = 0; r < numRows; ++r) { + int row = topRow + r; + ASSERT((rows_[row] & columnFlags) == 0); + rows_[row] |= columnFlags; + } +} + +bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize) +{ + ASSERT(destRow); + + for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask; + ++topNonFullRow_) { + } + + for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask; + --bottomNonFullRow_) { + } + + if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) { + return false; + } + + unsigned columnFlags = makeColumnFlags(column, 1); + int topGoodRow = 0; + int smallestGoodTop = -1; + int smallestGoodSize = maxRows_ + 1; + int bottomRow = bottomNonFullRow_ + 1; + bool found = false; + for (int row = topNonFullRow_; row <= bottomRow; ++row) { + bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false; + if (rowEmpty) { + if (!found) { + topGoodRow = row; + found = true; + } + } else { + if (found) { + int size = row - topGoodRow; + if (size >= numRows && size < smallestGoodSize) { + smallestGoodSize = size; + smallestGoodTop = topGoodRow; + } + } + found = false; + } + } + if (smallestGoodTop < 0) { + return false; + } + + *destRow = smallestGoodTop; + if (destSize) { + *destSize = smallestGoodSize; + } + return true; +} + +bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables) +{ + ASSERT(maxVectors > 0); + maxRows_ = maxVectors; + topNonFullRow_ = 0; + bottomNonFullRow_ = maxRows_ - 1; + TVariableInfoList variables(in_variables); + + // Check whether each variable fits in the available vectors. + for (size_t i = 0; i < variables.size(); i++) { + const TVariableInfo& variable = variables[i]; + if (variable.size > maxVectors / GetNumRows(variable.type)) { + return false; + } + } + + // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific + // order by type, then by size of array, largest first. + std::sort(variables.begin(), variables.end(), TVariableInfoComparer()); + rows_.clear(); + rows_.resize(maxVectors, 0); + + // Packs the 4 column variables. + size_t ii = 0; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 4) { + break; + } + topNonFullRow_ += GetNumRows(variable.type) * variable.size; + } + + if (topNonFullRow_ > maxRows_) { + return false; + } + + // Packs the 3 column variables. + int num3ColumnRows = 0; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 3) { + break; + } + num3ColumnRows += GetNumRows(variable.type) * variable.size; + } + + if (topNonFullRow_ + num3ColumnRows > maxRows_) { + return false; + } + + fillColumns(topNonFullRow_, num3ColumnRows, 0, 3); + + // Packs the 2 column variables. + int top2ColumnRow = topNonFullRow_ + num3ColumnRows; + int twoColumnRowsAvailable = maxRows_ - top2ColumnRow; + int rowsAvailableInColumns01 = twoColumnRowsAvailable; + int rowsAvailableInColumns23 = twoColumnRowsAvailable; + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + if (GetNumComponentsPerRow(variable.type) != 2) { + break; + } + int numRows = GetNumRows(variable.type) * variable.size; + if (numRows <= rowsAvailableInColumns01) { + rowsAvailableInColumns01 -= numRows; + } else if (numRows <= rowsAvailableInColumns23) { + rowsAvailableInColumns23 -= numRows; + } else { + return false; + } + } + + int numRowsUsedInColumns01 = + twoColumnRowsAvailable - rowsAvailableInColumns01; + int numRowsUsedInColumns23 = + twoColumnRowsAvailable - rowsAvailableInColumns23; + fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2); + fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23, + 2, 2); + + // Packs the 1 column variables. + for (; ii < variables.size(); ++ii) { + const TVariableInfo& variable = variables[ii]; + ASSERT(1 == GetNumComponentsPerRow(variable.type)); + int numRows = GetNumRows(variable.type) * variable.size; + int smallestColumn = -1; + int smallestSize = maxRows_ + 1; + int topRow = -1; + for (int column = 0; column < kNumColumns; ++column) { + int row = 0; + int size = 0; + if (searchColumn(column, numRows, &row, &size)) { + if (size < smallestSize) { + smallestSize = size; + smallestColumn = column; + topRow = row; + } + } + } + + if (smallestColumn < 0) { + return false; + } + + fillColumns(topRow, numRows, smallestColumn, 1); + } + + ASSERT(variables.size() == ii); + + return true; +} + + + diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.h b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h new file mode 100644 index 00000000000..fd6090827cd --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _VARIABLEPACKER_INCLUDED_ +#define _VARIABLEPACKER_INCLUDED_ + +#include <vector> +#include "compiler/translator/ShHandle.h" + +class VariablePacker { + public: + // Returns true if the passed in variables pack in maxVectors following + // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. + bool CheckVariablesWithinPackingLimits( + int maxVectors, + const TVariableInfoList& in_variables); + + // Gets how many components in a row a data type takes. + static int GetNumComponentsPerRow(ShDataType type); + + // Gets how many rows a data type takes. + static int GetNumRows(ShDataType type); + + private: + static const int kNumColumns = 4; + static const unsigned kColumnMask = (1 << kNumColumns) - 1; + + unsigned makeColumnFlags(int column, int numComponentsPerRow); + void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); + bool searchColumn(int column, int numRows, int* destRow, int* destSize); + + int topNonFullRow_; + int bottomNonFullRow_; + int maxRows_; + std::vector<unsigned> rows_; +}; + +#endif // _VARIABLEPACKER_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp new file mode 100644 index 00000000000..dd11f99eb89 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.cpp @@ -0,0 +1,140 @@ +// +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/VersionGLSL.h" + +static const int GLSL_VERSION_110 = 110; +static const int GLSL_VERSION_120 = 120; + +// We need to scan for the following: +// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders +// but only at the global scope. +// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader +// but inside any scope. +// 3. Call to a matrix constructor with another matrix as argument. +// (These constructors were reserved in GLSL version 1.10.) +// 4. Arrays as "out" function parameters. +// GLSL spec section 6.1.1: "When calling a function, expressions that do +// not evaluate to l-values cannot be passed to parameters declared as +// out or inout." +// GLSL 1.1 section 5.8: "Other binary or unary expressions, +// non-dereferenced arrays, function names, swizzles with repeated fields, +// and constants cannot be l-values." +// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that +// are built-in types, entire structures or arrays... are all l-values." +// +// TODO(alokp): The following two cases of invariant decalaration get lost +// during parsing - they do not get carried over to the intermediate tree. +// Handle these cases: +// 1. When a pragma is used to force all output variables to be invariant: +// - #pragma STDGL invariant(all) +// 2. When a previously decalared or built-in variable is marked invariant: +// - invariant gl_Position; +// - varying vec3 color; invariant color; +// +TVersionGLSL::TVersionGLSL(ShShaderType type) + : mShaderType(type), + mVersion(GLSL_VERSION_110) +{ +} + +void TVersionGLSL::visitSymbol(TIntermSymbol* node) +{ + if (node->getSymbol() == "gl_PointCoord") + updateVersion(GLSL_VERSION_120); +} + +void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*) +{ +} + +bool TVersionGLSL::visitBinary(Visit, TIntermBinary*) +{ + return true; +} + +bool TVersionGLSL::visitUnary(Visit, TIntermUnary*) +{ + return true; +} + +bool TVersionGLSL::visitSelection(Visit, TIntermSelection*) +{ + return true; +} + +bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node) +{ + bool visitChildren = true; + + switch (node->getOp()) { + case EOpSequence: + // We need to visit sequence children to get to global or inner scope. + visitChildren = true; + break; + case EOpDeclaration: { + const TIntermSequence& sequence = node->getSequence(); + TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); + if ((qualifier == EvqInvariantVaryingIn) || + (qualifier == EvqInvariantVaryingOut)) { + updateVersion(GLSL_VERSION_120); + } + break; + } + case EOpParameters: { + const TIntermSequence& params = node->getSequence(); + for (TIntermSequence::const_iterator iter = params.begin(); + iter != params.end(); ++iter) + { + const TIntermTyped* param = (*iter)->getAsTyped(); + if (param->isArray()) + { + TQualifier qualifier = param->getQualifier(); + if ((qualifier == EvqOut) || (qualifier == EvqInOut)) + { + updateVersion(GLSL_VERSION_120); + break; + } + } + } + // Fully processed. No need to visit children. + visitChildren = false; + break; + } + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: { + const TIntermSequence& sequence = node->getSequence(); + if (sequence.size() == 1) { + TIntermTyped* typed = sequence.front()->getAsTyped(); + if (typed && typed->isMatrix()) { + updateVersion(GLSL_VERSION_120); + } + } + break; + } + + default: break; + } + + return visitChildren; +} + +bool TVersionGLSL::visitLoop(Visit, TIntermLoop*) +{ + return true; +} + +bool TVersionGLSL::visitBranch(Visit, TIntermBranch*) +{ + return true; +} + +void TVersionGLSL::updateVersion(int version) +{ + mVersion = std::max(version, mVersion); +} + diff --git a/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h new file mode 100644 index 00000000000..8a401c4e92b --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/VersionGLSL.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_VERSIONGLSL_H_ +#define COMPILER_VERSIONGLSL_H_ + +#include "compiler/translator/intermediate.h" + +// Traverses the intermediate tree to return the minimum GLSL version +// required to legally access all built-in features used in the shader. +// GLSL 1.1 which is mandated by OpenGL 2.0 provides: +// - #version and #extension to declare version and extensions. +// - built-in functions refract, exp, and log. +// - updated step() to compare x < edge instead of x <= edge. +// GLSL 1.2 which is mandated by OpenGL 2.1 provides: +// - many changes to reduce differences when compared to the ES specification. +// - invariant keyword and its support. +// - c++ style name hiding rules. +// - built-in variable gl_PointCoord for fragment shaders. +// - matrix constructors taking matrix as argument. +// - array as "out" function parameters +// +// TODO: ES3 equivalent versions of GLSL +class TVersionGLSL : public TIntermTraverser { +public: + TVersionGLSL(ShShaderType type); + + // Returns 120 if the following is used the shader: + // - "invariant", + // - "gl_PointCoord", + // - matrix/matrix constructors + // - array "out" parameters + // Else 110 is returned. + int getVersion() { return mVersion; } + + virtual void visitSymbol(TIntermSymbol*); + virtual void visitConstantUnion(TIntermConstantUnion*); + virtual bool visitBinary(Visit, TIntermBinary*); + virtual bool visitUnary(Visit, TIntermUnary*); + virtual bool visitSelection(Visit, TIntermSelection*); + virtual bool visitAggregate(Visit, TIntermAggregate*); + virtual bool visitLoop(Visit, TIntermLoop*); + virtual bool visitBranch(Visit, TIntermBranch*); + +protected: + void updateVersion(int version); + +private: + ShShaderType mShaderType; + int mVersion; +}; + +#endif // COMPILER_VERSIONGLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp b/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp new file mode 100644 index 00000000000..10cbe43b8d5 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/compilerdebug.cpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.cpp: Debugging utilities. + +#include "compiler/translator/compilerdebug.h" + +#include <stdarg.h> +#include <stdio.h> + +#include "compiler/translator/InitializeParseContext.h" +#include "compiler/translator/ParseContext.h" + +#ifdef TRACE_ENABLED +static const int kTraceBufferLen = 1024; + +extern "C" { +void Trace(const char *format, ...) { + if (!format) return; + + TParseContext* parseContext = GetGlobalParseContext(); + if (parseContext) { + char buf[kTraceBufferLen]; + va_list args; + va_start(args, format); + vsnprintf(buf, kTraceBufferLen, format, args); + va_end(args); + + parseContext->trace(buf); + } +} +} // extern "C" +#endif // TRACE_ENABLED + diff --git a/chromium/third_party/angle/src/compiler/translator/compilerdebug.h b/chromium/third_party/angle/src/compiler/translator/compilerdebug.h new file mode 100644 index 00000000000..7a371516af0 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/compilerdebug.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// debug.h: Debugging utilities. + +#ifndef COMPILER_DEBUG_H_ +#define COMPILER_DEBUG_H_ + +#include <assert.h> + +#ifdef _DEBUG +#define TRACE_ENABLED // define to enable debug message tracing +#endif // _DEBUG + +// Outputs text to the debug log +#ifdef TRACE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +void Trace(const char* format, ...); +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // TRACE_ENABLED + +#define Trace(...) ((void)0) + +#endif // TRACE_ENABLED + +// A macro asserting a condition and outputting failures to the debug log +#define ASSERT(expression) do { \ + if(!(expression)) \ + Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ + assert(expression); \ +} while(0) + +#define UNIMPLEMENTED() do { \ + Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#define UNREACHABLE() do { \ + Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ +} while(0) + +#endif // COMPILER_DEBUG_H_ + diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp new file mode 100644 index 00000000000..19ddf5c4392 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp @@ -0,0 +1,97 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#pragma warning(disable: 4718) + +#include "compiler/translator/depgraph/DependencyGraph.h" +#include "compiler/translator/depgraph/DependencyGraphBuilder.h" + +TDependencyGraph::TDependencyGraph(TIntermNode* intermNode) +{ + TDependencyGraphBuilder::build(intermNode, this); +} + +TDependencyGraph::~TDependencyGraph() +{ + for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter) + { + TGraphNode* node = *iter; + delete node; + } +} + +TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall, + int argumentNumber) +{ + TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber); + mAllNodes.push_back(argument); + return argument; +} + +TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall) +{ + TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall); + mAllNodes.push_back(functionCall); + if (functionCall->getIntermFunctionCall()->isUserDefined()) + mUserDefinedFunctionCalls.push_back(functionCall); + return functionCall; +} + +TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol) +{ + TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId()); + + TGraphSymbol* symbol = NULL; + + if (iter != mSymbolIdMap.end()) { + TSymbolIdPair pair = *iter; + symbol = pair.second; + } else { + symbol = new TGraphSymbol(intermSymbol); + mAllNodes.push_back(symbol); + + TSymbolIdPair pair(intermSymbol->getId(), symbol); + mSymbolIdMap.insert(pair); + + // We save all sampler symbols in a collection, so we can start graph traversals from them quickly. + if (IsSampler(intermSymbol->getBasicType())) + mSamplerSymbols.push_back(symbol); + } + + return symbol; +} + +TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection) +{ + TGraphSelection* selection = new TGraphSelection(intermSelection); + mAllNodes.push_back(selection); + return selection; +} + +TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop) +{ + TGraphLoop* loop = new TGraphLoop(intermLoop); + mAllNodes.push_back(loop); + return loop; +} + +TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp) +{ + TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp); + mAllNodes.push_back(logicalOp); + return logicalOp; +} + +const char* TGraphLogicalOp::getOpString() const +{ + const char* opString = NULL; + switch (getIntermLogicalOp()->getOp()) { + case EOpLogicalAnd: opString = "and"; break; + case EOpLogicalOr: opString = "or"; break; + default: opString = "unknown"; break; + } + return opString; +} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h new file mode 100644 index 00000000000..5ea1cbb837d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h @@ -0,0 +1,212 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H + +#include "compiler/translator/intermediate.h" + +#include <set> +#include <stack> + +class TGraphNode; +class TGraphParentNode; +class TGraphArgument; +class TGraphFunctionCall; +class TGraphSymbol; +class TGraphSelection; +class TGraphLoop; +class TGraphLogicalOp; +class TDependencyGraphTraverser; +class TDependencyGraphOutput; + +typedef std::set<TGraphNode*> TGraphNodeSet; +typedef std::vector<TGraphNode*> TGraphNodeVector; +typedef std::vector<TGraphSymbol*> TGraphSymbolVector; +typedef std::vector<TGraphFunctionCall*> TFunctionCallVector; + +// +// Base class for all dependency graph nodes. +// +class TGraphNode { +public: + TGraphNode(TIntermNode* node) : intermNode(node) {} + virtual ~TGraphNode() {} + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +protected: + TIntermNode* intermNode; +}; + +// +// Base class for dependency graph nodes that may have children. +// +class TGraphParentNode : public TGraphNode { +public: + TGraphParentNode(TIntermNode* node) : TGraphNode(node) {} + virtual ~TGraphParentNode() {} + void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +private: + TGraphNodeSet mDependentNodes; +}; + +// +// Handle function call arguments. +// +class TGraphArgument : public TGraphParentNode { +public: + TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber) + : TGraphParentNode(intermFunctionCall) + , mArgumentNumber(argumentNumber) {} + virtual ~TGraphArgument() {} + const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } + int getArgumentNumber() const { return mArgumentNumber; } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +private: + int mArgumentNumber; +}; + +// +// Handle function calls. +// +class TGraphFunctionCall : public TGraphParentNode { +public: + TGraphFunctionCall(TIntermAggregate* intermFunctionCall) + : TGraphParentNode(intermFunctionCall) {} + virtual ~TGraphFunctionCall() {} + const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle symbols. +// +class TGraphSymbol : public TGraphParentNode { +public: + TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {} + virtual ~TGraphSymbol() {} + const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle if statements and ternary operators. +// +class TGraphSelection : public TGraphNode { +public: + TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {} + virtual ~TGraphSelection() {} + const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle for, do-while, and while loops. +// +class TGraphLoop : public TGraphNode { +public: + TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {} + virtual ~TGraphLoop() {} + const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); } + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// Handle logical and, or. +// +class TGraphLogicalOp : public TGraphNode { +public: + TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {} + virtual ~TGraphLogicalOp() {} + const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); } + const char* getOpString() const; + virtual void traverse(TDependencyGraphTraverser* graphTraverser); +}; + +// +// A dependency graph of symbols, function calls, conditions etc. +// +// This class provides an interface to the entry points of the dependency graph. +// +// Dependency graph nodes should be created by using one of the provided "create..." methods. +// This class (and nobody else) manages the memory of the created nodes. +// Nodes may not be removed after being added, so all created nodes will exist while the +// TDependencyGraph instance exists. +// +class TDependencyGraph { +public: + TDependencyGraph(TIntermNode* intermNode); + ~TDependencyGraph(); + TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); } + TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); } + + TGraphSymbolVector::const_iterator beginSamplerSymbols() const + { + return mSamplerSymbols.begin(); + } + + TGraphSymbolVector::const_iterator endSamplerSymbols() const + { + return mSamplerSymbols.end(); + } + + TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const + { + return mUserDefinedFunctionCalls.begin(); + } + + TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const + { + return mUserDefinedFunctionCalls.end(); + } + + TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber); + TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall); + TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol); + TGraphSelection* createSelection(TIntermSelection* intermSelection); + TGraphLoop* createLoop(TIntermLoop* intermLoop); + TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp); +private: + typedef TMap<int, TGraphSymbol*> TSymbolIdMap; + typedef std::pair<int, TGraphSymbol*> TSymbolIdPair; + + TGraphNodeVector mAllNodes; + TGraphSymbolVector mSamplerSymbols; + TFunctionCallVector mUserDefinedFunctionCalls; + TSymbolIdMap mSymbolIdMap; +}; + +// +// For traversing the dependency graph. Users should derive from this, +// put their traversal specific data in it, and then pass it to a +// traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// +class TDependencyGraphTraverser { +public: + TDependencyGraphTraverser() : mDepth(0) {} + + virtual void visitSymbol(TGraphSymbol* symbol) {}; + virtual void visitArgument(TGraphArgument* selection) {}; + virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {}; + virtual void visitSelection(TGraphSelection* selection) {}; + virtual void visitLoop(TGraphLoop* loop) {}; + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {}; + + int getDepth() const { return mDepth; } + void incrementDepth() { ++mDepth; } + void decrementDepth() { --mDepth; } + + void clearVisited() { mVisited.clear(); } + void markVisited(TGraphNode* node) { mVisited.insert(node); } + bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); } +private: + int mDepth; + TGraphNodeSet mVisited; +}; + +#endif diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp new file mode 100644 index 00000000000..d5f2cba5fc0 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp @@ -0,0 +1,227 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/depgraph/DependencyGraphBuilder.h" + +void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph) +{ + TDependencyGraphBuilder builder(graph); + builder.build(node); +} + +bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate) +{ + switch (intermAggregate->getOp()) { + case EOpFunction: visitFunctionDefinition(intermAggregate); break; + case EOpFunctionCall: visitFunctionCall(intermAggregate); break; + default: visitAggregateChildren(intermAggregate); break; + } + + return false; +} + +void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate) +{ + // Currently, we do not support user defined functions. + if (intermAggregate->getName() != "main(") + return; + + visitAggregateChildren(intermAggregate); +} + +// Takes an expression like "f(x)" and creates a dependency graph like +// "x -> argument 0 -> function call". +void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall) +{ + TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall); + + // Run through the function call arguments. + int argumentNumber = 0; + TIntermSequence& intermArguments = intermFunctionCall->getSequence(); + for (TIntermSequence::const_iterator iter = intermArguments.begin(); + iter != intermArguments.end(); + ++iter, ++argumentNumber) + { + TNodeSetMaintainer nodeSetMaintainer(this); + + TIntermNode* intermArgument = *iter; + intermArgument->traverse(this); + + if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) { + TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber); + connectMultipleNodesToSingleNode(argumentNodes, argument); + argument->addDependentNode(functionCall); + } + } + + // Push the leftmost symbol of this function call into the current set of dependent symbols to + // represent the result of this function call. + // Thus, an expression like "y = f(x)" will yield a dependency graph like + // "x -> argument 0 -> function call -> y". + // This line essentially passes the function call node back up to an earlier visitAssignment + // call, which will create the connection "function call -> y". + mNodeSets.insertIntoTopSet(functionCall); +} + +void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate) +{ + TIntermSequence& sequence = intermAggregate->getSequence(); + for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter) + { + TIntermNode* intermChild = *iter; + intermChild->traverse(this); + } +} + +void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol) +{ + // Push this symbol into the set of dependent symbols for the current assignment or condition + // that we are traversing. + TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol); + mNodeSets.insertIntoTopSet(symbol); + + // If this symbol is the current leftmost symbol under an assignment, replace the previous + // leftmost symbol with this symbol. + if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) { + mLeftmostSymbols.pop(); + mLeftmostSymbols.push(symbol); + } +} + +bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary) +{ + TOperator op = intermBinary->getOp(); + if (op == EOpInitialize || intermBinary->isAssignment()) + visitAssignment(intermBinary); + else if (op == EOpLogicalAnd || op == EOpLogicalOr) + visitLogicalOp(intermBinary); + else + visitBinaryChildren(intermBinary); + + return false; +} + +void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment) +{ + TIntermTyped* intermLeft = intermAssignment->getLeft(); + if (!intermLeft) + return; + + TGraphSymbol* leftmostSymbol = NULL; + + { + TNodeSetMaintainer nodeSetMaintainer(this); + + { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree); + intermLeft->traverse(this); + leftmostSymbol = mLeftmostSymbols.top(); + + // After traversing the left subtree of this assignment, we should have found a real + // leftmost symbol, and the leftmost symbol should not be a placeholder. + ASSERT(leftmostSymbol != &mLeftSubtree); + ASSERT(leftmostSymbol != &mRightSubtree); + } + + if (TIntermTyped* intermRight = intermAssignment->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } + + if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet()) + connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol); + } + + // Push the leftmost symbol of this assignment into the current set of dependent symbols to + // represent the result of this assignment. + // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a". + // This line essentially passes the leftmost symbol of the nested assignment ("b" in this + // example) back up to the earlier visitAssignment call for the outer assignment, which will + // create the connection "b -> a". + mNodeSets.insertIntoTopSet(leftmostSymbol); +} + +void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp) +{ + if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) { + TNodeSetPropagatingMaintainer nodeSetMaintainer(this); + + intermLeft->traverse(this); + if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) { + TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp); + connectMultipleNodesToSingleNode(leftNodes, logicalOp); + } + } + + if (TIntermTyped* intermRight = intermLogicalOp->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } +} + +void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary) +{ + if (TIntermTyped* intermLeft = intermBinary->getLeft()) + intermLeft->traverse(this); + + if (TIntermTyped* intermRight = intermBinary->getRight()) { + TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); + intermRight->traverse(this); + } +} + +bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection) +{ + if (TIntermNode* intermCondition = intermSelection->getCondition()) { + TNodeSetMaintainer nodeSetMaintainer(this); + + intermCondition->traverse(this); + if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { + TGraphSelection* selection = mGraph->createSelection(intermSelection); + connectMultipleNodesToSingleNode(conditionNodes, selection); + } + } + + if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock()) + intermTrueBlock->traverse(this); + + if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock()) + intermFalseBlock->traverse(this); + + return false; +} + +bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop) +{ + if (TIntermTyped* intermCondition = intermLoop->getCondition()) { + TNodeSetMaintainer nodeSetMaintainer(this); + + intermCondition->traverse(this); + if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) { + TGraphLoop* loop = mGraph->createLoop(intermLoop); + connectMultipleNodesToSingleNode(conditionNodes, loop); + } + } + + if (TIntermNode* intermBody = intermLoop->getBody()) + intermBody->traverse(this); + + if (TIntermTyped* intermExpression = intermLoop->getExpression()) + intermExpression->traverse(this); + + return false; +} + + +void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes, + TGraphNode* node) const +{ + for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter) + { + TGraphParentNode* currentNode = *iter; + currentNode->addDependentNode(node); + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h new file mode 100644 index 00000000000..3e928fb77eb --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h @@ -0,0 +1,181 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H + +#include "compiler/translator/depgraph/DependencyGraph.h" + +// +// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a +// intermediate tree. +// +class TDependencyGraphBuilder : public TIntermTraverser { +public: + static void build(TIntermNode* node, TDependencyGraph* graph); + + virtual void visitSymbol(TIntermSymbol*); + virtual bool visitBinary(Visit visit, TIntermBinary*); + virtual bool visitSelection(Visit visit, TIntermSelection*); + virtual bool visitAggregate(Visit visit, TIntermAggregate*); + virtual bool visitLoop(Visit visit, TIntermLoop*); + +private: + typedef std::stack<TGraphSymbol*> TSymbolStack; + typedef std::set<TGraphParentNode*> TParentNodeSet; + + // + // For collecting the dependent nodes of assignments, conditions, etc. + // while traversing the intermediate tree. + // + // This data structure is stack of sets. Each set contains dependency graph parent nodes. + // + class TNodeSetStack { + public: + TNodeSetStack() {}; + ~TNodeSetStack() { clear(); } + + // This should only be called after a pushSet. + // Returns NULL if the top set is empty. + TParentNodeSet* getTopSet() const + { + ASSERT(!nodeSets.empty()); + TParentNodeSet* topSet = nodeSets.top(); + return !topSet->empty() ? topSet : NULL; + } + + void pushSet() { nodeSets.push(new TParentNodeSet()); } + void popSet() + { + ASSERT(!nodeSets.empty()); + delete nodeSets.top(); + nodeSets.pop(); + } + + // Pops the top set and adds its contents to the new top set. + // This should only be called after a pushSet. + // If there is no set below the top set, the top set is just deleted. + void popSetIntoNext() + { + ASSERT(!nodeSets.empty()); + TParentNodeSet* oldTopSet = nodeSets.top(); + nodeSets.pop(); + + if (!nodeSets.empty()) { + TParentNodeSet* newTopSet = nodeSets.top(); + newTopSet->insert(oldTopSet->begin(), oldTopSet->end()); + } + + delete oldTopSet; + } + + // Does nothing if there is no top set. + // This can be called when there is no top set if we are visiting + // symbols that are not under an assignment or condition. + // We don't need to track those symbols. + void insertIntoTopSet(TGraphParentNode* node) + { + if (nodeSets.empty()) + return; + + nodeSets.top()->insert(node); + } + + void clear() + { + while (!nodeSets.empty()) + popSet(); + } + + private: + typedef std::stack<TParentNodeSet*> TParentNodeSetStack; + + TParentNodeSetStack nodeSets; + }; + + // + // An instance of this class pushes a new node set when instantiated. + // When the instance goes out of scope, it and pops the node set. + // + class TNodeSetMaintainer { + public: + TNodeSetMaintainer(TDependencyGraphBuilder* factory) + : sets(factory->mNodeSets) { sets.pushSet(); } + ~TNodeSetMaintainer() { sets.popSet(); } + protected: + TNodeSetStack& sets; + }; + + // + // An instance of this class pushes a new node set when instantiated. + // When the instance goes out of scope, it and pops the top node set and adds its contents to + // the new top node set. + // + class TNodeSetPropagatingMaintainer { + public: + TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory) + : sets(factory->mNodeSets) { sets.pushSet(); } + ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); } + protected: + TNodeSetStack& sets; + }; + + // + // An instance of this class keeps track of the leftmost symbol while we're exploring an + // assignment. + // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree, + // and kRightSubtree under a right subtree. + // When it goes out of scope, it will pop the leftmost symbol at the top of the scope. + // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol. + // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost + // symbol. + // + class TLeftmostSymbolMaintainer { + public: + TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree) + : leftmostSymbols(factory->mLeftmostSymbols) + { + needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree; + if (needsPlaceholderSymbol) + leftmostSymbols.push(&subtree); + } + + ~TLeftmostSymbolMaintainer() + { + if (needsPlaceholderSymbol) + leftmostSymbols.pop(); + } + + protected: + TSymbolStack& leftmostSymbols; + bool needsPlaceholderSymbol; + }; + + TDependencyGraphBuilder(TDependencyGraph* graph) + : TIntermTraverser(true, false, false) + , mLeftSubtree(NULL) + , mRightSubtree(NULL) + , mGraph(graph) {} + void build(TIntermNode* intermNode) { intermNode->traverse(this); } + + void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const; + + void visitAssignment(TIntermBinary*); + void visitLogicalOp(TIntermBinary*); + void visitBinaryChildren(TIntermBinary*); + void visitFunctionDefinition(TIntermAggregate*); + void visitFunctionCall(TIntermAggregate* intermFunctionCall); + void visitAggregateChildren(TIntermAggregate*); + + TGraphSymbol mLeftSubtree; + TGraphSymbol mRightSubtree; + + TDependencyGraph* mGraph; + TNodeSetStack mNodeSets; + TSymbolStack mLeftmostSymbols; +}; + +#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp new file mode 100644 index 00000000000..e226333545f --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp @@ -0,0 +1,65 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/depgraph/DependencyGraphOutput.h" + +void TDependencyGraphOutput::outputIndentation() +{ + for (int i = 0; i < getDepth(); ++i) + mSink << " "; +} + +void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter) +{ + outputIndentation(); + mSink << "argument " << parameter->getArgumentNumber() << " of call to " + << parameter->getIntermFunctionCall()->getName() << "\n"; +} + +void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall) +{ + outputIndentation(); + mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n"; +} + +void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol) +{ + outputIndentation(); + mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: " + << symbol->getIntermSymbol()->getId() << ")\n"; +} + +void TDependencyGraphOutput::visitSelection(TGraphSelection* selection) +{ + outputIndentation(); + mSink << "selection\n"; +} + +void TDependencyGraphOutput::visitLoop(TGraphLoop* loop) +{ + outputIndentation(); + mSink << "loop condition\n"; +} + +void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp) +{ + outputIndentation(); + mSink << "logical " << logicalOp->getOpString() << "\n"; +} + +void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph) +{ + mSink << "\n"; + + for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter) + { + TGraphNode* symbol = *iter; + mSink << "--- Dependency graph spanning tree ---\n"; + clearVisited(); + symbol->traverse(this); + mSink << "\n"; + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h new file mode 100644 index 00000000000..c3a4112278f --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H + +#include "compiler/translator/depgraph/DependencyGraph.h" +#include "compiler/translator/InfoSink.h" + +class TDependencyGraphOutput : public TDependencyGraphTraverser { +public: + TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {} + virtual void visitSymbol(TGraphSymbol* symbol); + virtual void visitArgument(TGraphArgument* parameter); + virtual void visitFunctionCall(TGraphFunctionCall* functionCall); + virtual void visitSelection(TGraphSelection* selection); + virtual void visitLoop(TGraphLoop* loop); + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + + void outputAllSpanningTrees(TDependencyGraph& graph); +private: + void outputIndentation(); + + TInfoSinkBase& mSink; +}; + +#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp new file mode 100644 index 00000000000..197fde97e26 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp @@ -0,0 +1,69 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/depgraph/DependencyGraph.h" + +// These methods do a breadth-first traversal through the graph and mark visited nodes. + +void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->markVisited(this); +} + +void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser) +{ + TGraphNode::traverse(graphTraverser); + + graphTraverser->incrementDepth(); + + // Visit the parent node's children. + for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin(); + iter != mDependentNodes.end(); + ++iter) + { + TGraphNode* node = *iter; + if (!graphTraverser->isVisited(node)) + node->traverse(graphTraverser); + } + + graphTraverser->decrementDepth(); +} + +void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitArgument(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitFunctionCall(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitSymbol(this); + TGraphParentNode::traverse(graphTraverser); +} + +void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitSelection(this); + TGraphNode::traverse(graphTraverser); +} + +void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitLoop(this); + TGraphNode::traverse(graphTraverser); +} + +void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser) +{ + graphTraverser->visitLogicalOp(this); + TGraphNode::traverse(graphTraverser); +} diff --git a/chromium/third_party/angle/src/compiler/translator/generate_parser.sh b/chromium/third_party/angle/src/compiler/translator/generate_parser.sh new file mode 100644 index 00000000000..e4d88b2e84c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/generate_parser.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Generates GLSL ES parser - glslang_lex.cpp, glslang_tab.h, and glslang_tab.cpp + +run_flex() +{ +input_file=$script_dir/$1.l +output_source=$script_dir/$1_lex.cpp +flex --noline --nounistd --outfile=$output_source $input_file +} + +run_bison() +{ +input_file=$script_dir/$1.y +output_header=$script_dir/$1_tab.h +output_source=$script_dir/$1_tab.cpp +bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file +} + +script_dir=$(dirname $0) + +# Generate Parser +run_flex glslang +run_bison glslang +patch --silent --forward < 64bit-lexer-safety.patch diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.h b/chromium/third_party/angle/src/compiler/translator/glslang.h new file mode 100644 index 00000000000..f221199093c --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang.h @@ -0,0 +1,16 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +struct TParseContext; +extern int glslang_initialize(TParseContext* context); +extern int glslang_finalize(TParseContext* context); + +extern int glslang_scan(size_t count, + const char* const string[], + const int length[], + TParseContext* context); +extern int glslang_parse(TParseContext* context); + diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.l b/chromium/third_party/angle/src/compiler/translator/glslang.l new file mode 100644 index 00000000000..518b78df11e --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang.l @@ -0,0 +1,558 @@ +/* +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +%top{ +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif +} + +%{ +#include "compiler/translator/glslang.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/translator/util.h" +#include "compiler/translator/length_limits.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +#define YY_USER_ACTION \ + yylloc->first_file = yylloc->last_file = yycolumn; \ + yylloc->first_line = yylloc->last_line = yylineno; + +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); +static int ES2_reserved_ES3_keyword(TParseContext *context, int token); +static int ES2_keyword_ES3_reserved(TParseContext *context, int token); +static int ES2_ident_ES3_keyword(TParseContext *context, int token); +static int uint_constant(TParseContext *context); +static int int_constant(yyscan_t yyscanner); +static int float_constant(yyscan_t yyscanner); +static int floatsuffix_check(TParseContext* context); +%} + +%option noyywrap nounput never-interactive +%option yylineno reentrant bison-bridge bison-locations +%option extra-type="TParseContext*" + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +O [0-7] + +%% + +%{ + TParseContext* context = yyextra; +%} + +"invariant" { return INVARIANT; } +"highp" { return HIGH_PRECISION; } +"mediump" { return MEDIUM_PRECISION; } +"lowp" { return LOW_PRECISION; } +"precision" { return PRECISION; } + +"attribute" { return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } +"const" { return CONST_QUAL; } +"uniform" { return UNIFORM; } +"varying" { return ES2_keyword_ES3_reserved(context, VARYING); } + +"break" { return BREAK; } +"continue" { return CONTINUE; } +"do" { return DO; } +"for" { return FOR; } +"while" { return WHILE; } + +"if" { return IF; } +"else" { return ELSE; } +"switch" { return ES2_reserved_ES3_keyword(context, SWITCH); } +"case" { return ES2_ident_ES3_keyword(context, CASE); } +"default" { return ES2_reserved_ES3_keyword(context, DEFAULT); } + +"centroid" { return ES2_ident_ES3_keyword(context, CENTROID); } +"flat" { return ES2_reserved_ES3_keyword(context, FLAT); } +"smooth" { return ES2_ident_ES3_keyword(context, SMOOTH); } + +"in" { return IN_QUAL; } +"out" { return OUT_QUAL; } +"inout" { return INOUT_QUAL; } + +"float" { return FLOAT_TYPE; } +"int" { return INT_TYPE; } +"uint" { return ES2_ident_ES3_keyword(context, UINT_TYPE); } +"void" { return VOID_TYPE; } +"bool" { return BOOL_TYPE; } +"true" { yylval->lex.b = true; return BOOLCONSTANT; } +"false" { yylval->lex.b = false; return BOOLCONSTANT; } + +"discard" { return DISCARD; } +"return" { return RETURN; } + +"mat2" { return MATRIX2; } +"mat3" { return MATRIX3; } +"mat4" { return MATRIX4; } + +"mat2x2" { return ES2_ident_ES3_keyword(context, MATRIX2); } +"mat3x3" { return ES2_ident_ES3_keyword(context, MATRIX3); } +"mat4x4" { return ES2_ident_ES3_keyword(context, MATRIX4); } + +"mat2x3" { return ES2_ident_ES3_keyword(context, MATRIX2x3); } +"mat3x2" { return ES2_ident_ES3_keyword(context, MATRIX3x2); } +"mat2x4" { return ES2_ident_ES3_keyword(context, MATRIX2x4); } +"mat4x2" { return ES2_ident_ES3_keyword(context, MATRIX4x2); } +"mat3x4" { return ES2_ident_ES3_keyword(context, MATRIX3x4); } +"mat4x3" { return ES2_ident_ES3_keyword(context, MATRIX4x3); } + +"vec2" { return VEC2; } +"vec3" { return VEC3; } +"vec4" { return VEC4; } +"ivec2" { return IVEC2; } +"ivec3" { return IVEC3; } +"ivec4" { return IVEC4; } +"bvec2" { return BVEC2; } +"bvec3" { return BVEC3; } +"bvec4" { return BVEC4; } +"uvec2" { return ES2_ident_ES3_keyword(context, UVEC2); } +"uvec3" { return ES2_ident_ES3_keyword(context, UVEC3); } +"uvec4" { return ES2_ident_ES3_keyword(context, UVEC4); } + +"sampler2D" { return SAMPLER2D; } +"samplerCube" { return SAMPLERCUBE; } +"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; } +"sampler3D" { return ES2_reserved_ES3_keyword(context, SAMPLER3D); } +"sampler3DRect" { return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } +"sampler2DRect" { return SAMPLER2DRECT; } +"sampler2DArray" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); } +"isampler2D" { return ES2_ident_ES3_keyword(context, ISAMPLER2D); } +"isampler3D" { return ES2_ident_ES3_keyword(context, ISAMPLER3D); } +"isamplerCube" { return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); } +"isampler2DArray" { return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); } +"usampler2D" { return ES2_ident_ES3_keyword(context, USAMPLER2D); } +"usampler3D" { return ES2_ident_ES3_keyword(context, USAMPLER3D); } +"usamplerCube" { return ES2_ident_ES3_keyword(context, USAMPLERCUBE); } +"usampler2DArray" { return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); } +"sampler2DShadow" { return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } +"samplerCubeShadow" { return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); } +"sampler2DArrayShadow" { return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } + +"struct" { return STRUCT; } + +"layout" { return ES2_ident_ES3_keyword(context, LAYOUT); } + + /* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ +"coherent" | +"restrict" | +"readonly" | +"writeonly" | +"resource" | +"atomic_uint" | +"noperspective" | +"patch" | +"sample" | +"subroutine" | +"common" | +"partition" | +"active" | + +"filter" | +"image1D" | +"image2D" | +"image3D" | +"imageCube" | +"iimage1D" | +"iimage2D" | +"iimage3D" | +"iimageCube" | +"uimage1D" | +"uimage2D" | +"uimage3D" | +"uimageCube" | +"image1DArray" | +"image2DArray" | +"iimage1DArray" | +"iimage2DArray" | +"uimage1DArray" | +"uimage2DArray" | +"image1DShadow" | +"image2DShadow" | +"image1DArrayShadow" | +"image2DArrayShadow" | +"imageBuffer" | +"iimageBuffer" | +"uimageBuffer" | + +"sampler1DArray" | +"sampler1DArrayShadow" | +"isampler1D" | +"isampler1DArray" | +"usampler1D" | +"usampler1DArray" | +"isampler2DRect" | +"usampler2DRect" | +"samplerBuffer" | +"isamplerBuffer" | +"usamplerBuffer" | +"sampler2DMS" | +"isampler2DMS" | +"usampler2DMS" | +"sampler2DMSArray" | +"isampler2DMSArray" | +"usampler2DMSArray" { + if (context->shaderVersion < 300) { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + return reserved_word(yyscanner); +} + + /* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */ +"packed" { + if (context->shaderVersion >= 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return reserved_word(yyscanner); +} + + /* Reserved keywords */ +"asm" | + +"class" | +"union" | +"enum" | +"typedef" | +"template" | +"this" | + +"goto" | + +"inline" | +"noinline" | +"volatile" | +"public" | +"static" | +"extern" | +"external" | +"interface" | + +"long" | +"short" | +"double" | +"half" | +"fixed" | +"unsigned" | +"superp" | + +"input" | +"output" | + +"hvec2" | +"hvec3" | +"hvec4" | +"dvec2" | +"dvec3" | +"dvec4" | +"fvec2" | +"fvec3" | +"fvec4" | + +"sampler1D" | +"sampler1DShadow" | +"sampler2DRectShadow" | + +"sizeof" | +"cast" | + +"namespace" | +"using" { return reserved_word(yyscanner); } + +{L}({L}|{D})* { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + +0[xX]{H}+ { return int_constant(yyscanner); } +0{O}+ { return int_constant(yyscanner); } +{D}+ { return int_constant(yyscanner); } + +0[xX]{H}+[uU] { return uint_constant(context); } +0{O}+[uU] { return uint_constant(context); } +{D}+[uU] { return uint_constant(context); } + +{D}+{E} { return float_constant(yyscanner); } +{D}+"."{D}*({E})? { return float_constant(yyscanner); } +"."{D}+({E})? { return float_constant(yyscanner); } + +{D}+{E}[fF] { return floatsuffix_check(context); } +{D}+"."{D}*({E})?[fF] { return floatsuffix_check(context); } +"."{D}+({E})?[fF] { return floatsuffix_check(context); } + +"+=" { return ADD_ASSIGN; } +"-=" { return SUB_ASSIGN; } +"*=" { return MUL_ASSIGN; } +"/=" { return DIV_ASSIGN; } +"%=" { return MOD_ASSIGN; } +"<<=" { return LEFT_ASSIGN; } +">>=" { return RIGHT_ASSIGN; } +"&=" { return AND_ASSIGN; } +"^=" { return XOR_ASSIGN; } +"|=" { return OR_ASSIGN; } + +"++" { return INC_OP; } +"--" { return DEC_OP; } +"&&" { return AND_OP; } +"||" { return OR_OP; } +"^^" { return XOR_OP; } +"<=" { return LE_OP; } +">=" { return GE_OP; } +"==" { return EQ_OP; } +"!=" { return NE_OP; } +"<<" { return LEFT_OP; } +">>" { return RIGHT_OP; } +";" { return SEMICOLON; } +("{"|"<%") { return LEFT_BRACE; } +("}"|"%>") { return RIGHT_BRACE; } +"," { return COMMA; } +":" { return COLON; } +"=" { return EQUAL; } +"(" { return LEFT_PAREN; } +")" { return RIGHT_PAREN; } +("["|"<:") { return LEFT_BRACKET; } +("]"|":>") { return RIGHT_BRACKET; } +"." { return DOT; } +"!" { return BANG; } +"-" { return DASH; } +"~" { return TILDE; } +"+" { return PLUS; } +"*" { return STAR; } +"/" { return SLASH; } +"%" { return PERCENT; } +"<" { return LEFT_ANGLE; } +">" { return RIGHT_ANGLE; } +"|" { return VERTICAL_BAR; } +"^" { return CARET; } +"&" { return AMPERSAND; } +"?" { return QUESTION; } + +[ \t\v\n\f\r] { } +<<EOF>> { yyterminate(); } +. { assert(false); return 0; } + +%% + +yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) { + pp::Token token; + yyget_extra(yyscanner)->preprocessor.lex(&token); + yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size(); + if (len < max_size) + memcpy(buf, token.text.c_str(), len); + yyset_column(token.location.file, yyscanner); + yyset_lineno(token.location.line, yyscanner); + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion); + if (symbol && symbol->isVariable()) { + TVariable* variable = static_cast<TVariable*>(symbol); + if (variable->isUserType()) { + token = TYPE_NAME; + } + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); + yyextra->recover(); + return 0; +} + +int ES2_reserved_ES3_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_keyword_ES3_reserved(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion >= 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_ident_ES3_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name + if (context->shaderVersion < 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return token; +} + +int uint_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); + context->recover(); + return 0; + } + + if (!atoi_clamp(yytext, &(yylval->lex.i))) + yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + + return UINTCONSTANT; +} + +int floatsuffix_check(TParseContext* context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); + context->recover(); + return 0; + } + + if (!atof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext, ""); + + return(FLOATCONSTANT); +} + +void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) { + context->error(*lloc, reason, yyget_text(context->scanner)); + context->recover(); +} + +int int_constant(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + if (!atoi_clamp(yytext, &(yylval->lex.i))) + yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + return INTCONSTANT; +} + +int float_constant(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + if (!atof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext, ""); + return FLOATCONSTANT; +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context, &scanner)) + return 1; + + context->scanner = scanner; + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->scanner; + if (scanner == NULL) return 0; + + context->scanner = NULL; + yylex_destroy(scanner); + + return 0; +} + +int glslang_scan(size_t count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL, context->scanner); + yyset_column(0, context->scanner); + yyset_lineno(1, context->scanner); + + // Initialize preprocessor. + if (!context->preprocessor.init(count, string, length)) + return 1; + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { + context->preprocessor.predefineMacro(iter->first.c_str(), 1); + } + if (context->fragmentPrecisionHigh) + context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); + + context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec)); + + return 0; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.y b/chromium/third_party/angle/src/compiler/translator/glslang.y new file mode 100644 index 00000000000..8ebf2d1f641 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang.y @@ -0,0 +1,1951 @@ +/* +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Yacc grammar for GLSL ES. +Based on ANSI C Yacc grammar: +http://www.lysator.liu.se/c/ANSI-C-grammar-y.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). +*/ + +%{ +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/ParseContext.h" +#include "GLSLANG/ShaderLang.h" + +#define YYENABLE_NLS 0 + +#define YYLEX_PARAM context->scanner + +%} +%expect 1 /* One shift reduce conflict because of if | else */ +%pure-parser +%parse-param {TParseContext* context} +%locations + +%code requires { +#define YYLTYPE TSourceLoc +#define YYLTYPE_IS_DECLARED 1 +} + +%union { + struct { + union { + TString *string; + float f; + int i; + unsigned int u; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TFunction* function; + TParameter param; + TField* field; + TFieldList* fieldList; + }; + } interm; +} + +%{ +extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); +extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason); + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (YYID(N)) { \ + (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).last_file = YYRHSLOC(Rhs, N).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + } \ + else { \ + (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \ + } \ + } while (0) + +#define VERTEX_ONLY(S, L) { \ + if (context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only ", S); \ + context->recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER) { \ + context->error(L, " supported in fragment shaders only ", S); \ + context->recover(); \ + } \ +} + +#define ES2_ONLY(S, L) { \ + if (context->shaderVersion != 100) { \ + context->error(L, " supported in GLSL ES 1.00 only ", S); \ + context->recover(); \ + } \ +} + +#define ES3_ONLY(TOKEN, LINE, REASON) { \ + if (context->shaderVersion != 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ + context->recover(); \ + } \ +} +%} + +%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION +%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE UINT_TYPE +%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT +%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 UVEC2 UVEC3 UVEC4 +%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token <lex> MATRIX2x3 MATRIX3x2 MATRIX2x4 MATRIX4x2 MATRIX3x4 MATRIX4x3 +%token <lex> CENTROID FLAT SMOOTH +%token <lex> STRUCT VOID_TYPE WHILE +%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT SAMPLER2DARRAY +%token <lex> ISAMPLER2D ISAMPLER3D ISAMPLERCUBE ISAMPLER2DARRAY +%token <lex> USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER2DARRAY +%token <lex> SAMPLER3D SAMPLER3DRECT SAMPLER2DSHADOW SAMPLERCUBESHADOW SAMPLER2DARRAYSHADOW +%token <lex> LAYOUT + +%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT UINTCONSTANT BOOLCONSTANT +%token <lex> FIELD_SELECTION +%token <lex> LEFT_OP RIGHT_OP +%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token <lex> SUB_ASSIGN + +%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT +%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT +%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION + +%type <lex> identifier +%type <interm> assignment_operator unary_operator +%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression +%type <interm.intermTypedNode> expression integer_expression assignment_expression +%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression +%type <interm.intermTypedNode> relational_expression equality_expression +%type <interm.intermTypedNode> conditional_expression constant_expression +%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression +%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression +%type <interm.intermTypedNode> function_call initializer condition conditionopt + +%type <interm.intermNode> translation_unit function_definition +%type <interm.intermNode> statement simple_statement +%type <interm.intermAggregate> statement_list compound_statement +%type <interm.intermNode> declaration_statement selection_statement expression_statement +%type <interm.intermNode> declaration external_declaration +%type <interm.intermNode> for_init_statement compound_statement_no_new_scope +%type <interm.nodePair> selection_rest_statement for_rest_statement +%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope +%type <interm> single_declaration init_declarator_list + +%type <interm> parameter_declaration parameter_declarator parameter_type_specifier +%type <interm.qualifier> parameter_qualifier parameter_type_qualifier +%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id + +%type <interm.precision> precision_qualifier +%type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier +%type <interm.type> type_specifier_no_prec type_specifier_nonarray +%type <interm.type> struct_specifier +%type <interm.field> struct_declarator +%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list +%type <interm.function> function_header function_declarator function_identifier +%type <interm.function> function_header_with_parameters function_call_header +%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype +%type <interm> function_call_or_method + +%type <lex> enter_struct + +%start translation_unit +%% + +identifier + : IDENTIFIER + | TYPE_NAME + +variable_identifier + : IDENTIFIER { + // The symbol table search was done in the lexical phase + const TSymbol *symbol = $1.symbol; + const TVariable *variable = 0; + + if (!symbol) + { + context->error(@1, "undeclared identifier", $1.string->c_str()); + context->recover(); + } + else if (!symbol->isVariable()) + { + context->error(@1, "variable expected", $1.string->c_str()); + context->recover(); + } + else + { + variable = static_cast<const TVariable*>(symbol); + + if (context->symbolTable.findBuiltIn(variable->getName(), context->shaderVersion) && + !variable->getExtension().empty() && + context->extensionErrorCheck(@1, variable->getExtension())) + { + context->recover(); + } + } + + if (!variable) + { + TType type(EbtFloat, EbpUndefined); + TVariable *fakeVariable = new TVariable($1.string, type); + context->symbolTable.declare(*fakeVariable); + variable = fakeVariable; + } + + if (variable->getType().getQualifier() == EvqConst) + { + ConstantUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + $$ = context->intermediate.addConstantUnion(constArray, t, @1); + } + else + { + $$ = context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), + @1); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + } + ; + +primary_expression + : variable_identifier { + $$ = $1; + } + | INTCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst($1.i); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1); + } + | UINTCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setUConst($1.u); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), @1); + } + | FLOATCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst($1.f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1); + } + | BOOLCONSTANT { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst($1.b); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1); + } + | LEFT_PAREN expression RIGHT_PAREN { + $$ = $2; + } + ; + +postfix_expression + : primary_expression { + $$ = $1; + } + | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET { + $$ = context->addIndexExpression($1, @2, $3); + } + | function_call { + $$ = $1; + } + | postfix_expression DOT identifier { + $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3); + } + | postfix_expression INC_OP { + if (context->lValueErrorCheck(@2, "++", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2); + if ($$ == 0) { + context->unaryOpError(@2, "++", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | postfix_expression DEC_OP { + if (context->lValueErrorCheck(@2, "--", $1)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2); + if ($$ == 0) { + context->unaryOpError(@2, "--", $1->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +integer_expression + : expression { + if (context->integerErrorCheck($1, "[]")) + context->recover(); + $$ = $1; + } + ; + +function_call + : function_call_or_method { + TFunction* fnCall = $1.function; + TOperator op = fnCall->getBuiltInOp(); + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) { + $$ = 0; + } else { + // + // It's a constructor, of type 'type'. + // + $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1); + } + + if ($$ == 0) { + context->recover(); + $$ = context->intermediate.setAggregateOperator(0, op, @1); + } + $$->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn); + if (fnCandidate) { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + context->extensionErrorCheck(@1, fnCandidate->getExtension())) { + context->recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1); + if ($$ == 0) { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + YYERROR; + } + } else { + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1); + } + } else { + // This is a real function call + + $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1); + $$->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + $$->getAsAggregate()->setUserDefined(); + $$->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + context->recover(); + } + } + } + } + $$->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1); + context->recover(); + } + } + delete fnCall; + } + ; + +function_call_or_method + : function_call_generic { + $$ = $1; + } + | postfix_expression DOT function_call_generic { + context->error(@3, "methods are not supported", ""); + context->recover(); + $$ = $3; + } + ; + +function_call_generic + : function_call_header_with_parameters RIGHT_PAREN { + $$ = $1; + } + | function_call_header_no_parameters RIGHT_PAREN { + $$ = $1; + } + ; + +function_call_header_no_parameters + : function_call_header VOID_TYPE { + $$.function = $1; + $$.intermNode = 0; + } + | function_call_header { + $$.function = $1; + $$.intermNode = 0; + } + ; + +function_call_header_with_parameters + : function_call_header assignment_expression { + TParameter param = { 0, new TType($2->getType()) }; + $1->addParameter(param); + $$.function = $1; + $$.intermNode = $2; + } + | function_call_header_with_parameters COMMA assignment_expression { + TParameter param = { 0, new TType($3->getType()) }; + $1.function->addParameter(param); + $$.function = $1.function; + $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2); + } + ; + +function_call_header + : function_identifier LEFT_PAREN { + $$ = $1; + } + ; + +// Grammar Note: Constructors look like functions, but are recognized as types. + +function_identifier + : type_specifier_nonarray { + $$ = context->addConstructorFunc($1); + } + | IDENTIFIER { + if (context->reservedErrorCheck(@1, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + ; + +unary_expression + : postfix_expression { + $$ = $1; + } + | INC_OP unary_expression { + if (context->lValueErrorCheck(@1, "++", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1); + if ($$ == 0) { + context->unaryOpError(@1, "++", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | DEC_OP unary_expression { + if (context->lValueErrorCheck(@1, "--", $2)) + context->recover(); + $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1); + if ($$ == 0) { + context->unaryOpError(@1, "--", $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } + | unary_operator unary_expression { + if ($1.op != EOpNull) { + $$ = context->intermediate.addUnaryMath($1.op, $2, @1); + if ($$ == 0) { + const char* errorOp = ""; + switch($1.op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + default: break; + } + context->unaryOpError(@1, errorOp, $2->getCompleteString()); + context->recover(); + $$ = $2; + } + } else + $$ = $2; + } + ; +// Grammar Note: No traditional style type casts. + +unary_operator + : PLUS { $$.op = EOpNull; } + | DASH { $$.op = EOpNegative; } + | BANG { $$.op = EOpLogicalNot; } + ; +// Grammar Note: No '*' or '&' unary ops. Pointers are not supported. + +multiplicative_expression + : unary_expression { $$ = $1; } + | multiplicative_expression STAR unary_expression { + $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | multiplicative_expression SLASH unary_expression { + $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +additive_expression + : multiplicative_expression { $$ = $1; } + | additive_expression PLUS multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + | additive_expression DASH multiplicative_expression { + $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +shift_expression + : additive_expression { $$ = $1; } + ; + +relational_expression + : shift_expression { $$ = $1; } + | relational_expression LEFT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + | relational_expression RIGHT_ANGLE shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + | relational_expression LE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + | relational_expression GE_OP shift_expression { + $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + ; + +equality_expression + : relational_expression { $$ = $1; } + | equality_expression EQ_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + | equality_expression NE_OP relational_expression { + $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + ; + +and_expression + : equality_expression { $$ = $1; } + ; + +exclusive_or_expression + : and_expression { $$ = $1; } + ; + +inclusive_or_expression + : exclusive_or_expression { $$ = $1; } + ; + +logical_and_expression + : inclusive_or_expression { $$ = $1; } + | logical_and_expression AND_OP inclusive_or_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + ; + +logical_xor_expression + : logical_and_expression { $$ = $1; } + | logical_xor_expression XOR_OP logical_and_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + ; + +logical_or_expression + : logical_xor_expression { $$ = $1; } + | logical_or_expression OR_OP logical_xor_expression { + $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); + } + } + ; + +conditional_expression + : logical_or_expression { $$ = $1; } + | logical_or_expression QUESTION expression COLON assignment_expression { + if (context->boolErrorCheck(@2, $1)) + context->recover(); + + $$ = context->intermediate.addSelection($1, $3, $5, @2); + if ($3->getType() != $5->getType()) + $$ = 0; + + if ($$ == 0) { + context->binaryOpError(@2, ":", $3->getCompleteString(), $5->getCompleteString()); + context->recover(); + $$ = $5; + } + } + ; + +assignment_expression + : conditional_expression { $$ = $1; } + | unary_expression assignment_operator assignment_expression { + if (context->lValueErrorCheck(@2, "assign", $1)) + context->recover(); + $$ = context->intermediate.addAssign($2.op, $1, $3, @2); + if ($$ == 0) { + context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $1; + } + } + ; + +assignment_operator + : EQUAL { $$.op = EOpAssign; } + | MUL_ASSIGN { $$.op = EOpMulAssign; } + | DIV_ASSIGN { $$.op = EOpDivAssign; } + | ADD_ASSIGN { $$.op = EOpAddAssign; } + | SUB_ASSIGN { $$.op = EOpSubAssign; } + ; + +expression + : assignment_expression { + $$ = $1; + } + | expression COMMA assignment_expression { + $$ = context->intermediate.addComma($1, $3, @2); + if ($$ == 0) { + context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString()); + context->recover(); + $$ = $3; + } + } + ; + +constant_expression + : conditional_expression { + if (context->constErrorCheck($1)) + context->recover(); + $$ = $1; + } + ; + +enter_struct + : IDENTIFIER LEFT_BRACE { + if (context->enterStructDeclaration(@1, *$1.string)) + context->recover(); + $$ = $1; + } + ; + +declaration + : function_prototype SEMICOLON { + TFunction &function = *($1.function); + + TIntermAggregate *prototype = new TIntermAggregate; + prototype->setType(function.getReturnType()); + prototype->setName(function.getName()); + + for (size_t i = 0; i < function.getParamCount(); i++) + { + const TParameter ¶m = function.getParam(i); + if (param.name != 0) + { + TVariable variable(param.name, *param.type); + + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), @1), @1); + } + else + { + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, @1), @1); + } + } + + prototype->setOp(EOpPrototype); + $$ = prototype; + + context->symbolTable.pop(); + } + | init_declarator_list SEMICOLON { + if ($1.intermAggregate) + $1.intermAggregate->setOp(EOpDeclaration); + $$ = $1.intermAggregate; + } + | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { + if (($2 == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) { + context->error(@1, "precision is not supported in fragment shader", "highp"); + context->recover(); + } + if (!context->symbolTable.setDefaultPrecision( $3, $2 )) { + context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type)); + context->recover(); + } + $$ = 0; + } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$); + } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$); + } + | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { + ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); + $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6); + } + | type_qualifier SEMICOLON { + context->parseGlobalLayoutQualifier($1); + $$ = 0; + } + ; + +function_prototype + : function_declarator RIGHT_PAREN { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName(), context->shaderVersion)); + if (prevDec) { + if (prevDec->getReturnType() != $1->getReturnType()) { + context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString()); + context->recover(); + } + for (size_t i = 0; i < prevDec->getParamCount(); ++i) { + if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) { + context->error(@2, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString()); + context->recover(); + } + } + } + + // + // Check for previously declared variables using the same name. + // + TSymbol *prevSym = context->symbolTable.find($1->getName(), context->shaderVersion); + if (prevSym) + { + if (!prevSym->isFunction()) + { + context->error(@2, "redefinition", $1->getName().c_str(), "function"); + context->recover(); + } + } + else + { + // Insert the unmangled name to detect potential future redefinition as a variable. + context->symbolTable.getOuterLevel()->insert($1->getName(), *$1); + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + $$.function = $1; + + // We're at the inner scope level of the function's arguments and body statement. + // Add the function prototype to the surrounding scope instead. + context->symbolTable.getOuterLevel()->insert(*$$.function); + } + ; + +function_declarator + : function_header { + $$ = $1; + } + | function_header_with_parameters { + $$ = $1; + } + ; + + +function_header_with_parameters + : function_header parameter_declaration { + // Add the parameter + $$ = $1; + if ($2.param.type->getBasicType() != EbtVoid) + $1->addParameter($2.param); + else + delete $2.param.type; + } + | function_header_with_parameters COMMA parameter_declaration { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ($3.param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + context->error(@2, "cannot be an argument type except for '(void)'", "void"); + context->recover(); + delete $3.param.type; + } else { + // Add the parameter + $$ = $1; + $1->addParameter($3.param); + } + } + ; + +function_header + : fully_specified_type IDENTIFIER LEFT_PAREN { + if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) { + context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier)); + context->recover(); + } + // make sure a sampler is not involved as well... + if (context->structQualifierErrorCheck(@2, $1)) + context->recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type($1); + function = new TFunction($2.string, type); + $$ = function; + + context->symbolTable.push(); + } + ; + +parameter_declarator + // Type + name + : type_specifier identifier { + if ($1.type == EbtVoid) { + context->error(@2, "illegal use of type 'void'", $2.string->c_str()); + context->recover(); + } + if (context->reservedErrorCheck(@2, *$2.string)) + context->recover(); + TParameter param = {$2.string, new TType($1)}; + $$.param = param; + } + | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { + // Check that we can make an array out of this type + if (context->arrayTypeErrorCheck(@3, $1)) + context->recover(); + + if (context->reservedErrorCheck(@2, *$2.string)) + context->recover(); + + int size; + if (context->arraySizeErrorCheck(@3, $4, size)) + context->recover(); + $1.setArray(true, size); + + TType* type = new TType($1); + TParameter param = { $2.string, type }; + $$.param = param; + } + ; + +parameter_declaration + // + // The only parameter qualifier a parameter can have are + // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. + // + + // + // Type + name + // + : parameter_type_qualifier parameter_qualifier parameter_declarator { + $$ = $3; + if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_declarator { + $$ = $2; + if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + // + // Only type + // + | parameter_type_qualifier parameter_qualifier parameter_type_specifier { + $$ = $3; + if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) + context->recover(); + } + | parameter_qualifier parameter_type_specifier { + $$ = $2; + if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) + context->recover(); + if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) + context->recover(); + } + ; + +parameter_qualifier + : /* empty */ { + $$ = EvqIn; + } + | IN_QUAL { + $$ = EvqIn; + } + | OUT_QUAL { + $$ = EvqOut; + } + | INOUT_QUAL { + $$ = EvqInOut; + } + ; + +parameter_type_specifier + : type_specifier { + TParameter param = { 0, new TType($1) }; + $$.param = param; + } + ; + +init_declarator_list + : single_declaration { + $$ = $1; + } + | init_declarator_list COMMA identifier { + $$ = $1; + $$.intermAggregate = context->parseDeclarator($$.type, $1.intermAggregate, $3.symbol, @3, *$3.string); + } + | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET { + $$ = $1; + context->parseArrayDeclarator($$.type, @3, *$3.string, @4, NULL, NULL); + } + | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + $$.intermAggregate = context->parseArrayDeclarator($$.type, @3, *$3.string, @4, $1.intermNode, $5); + } + | init_declarator_list COMMA identifier EQUAL initializer { + $$ = $1; + $$.intermAggregate = context->parseInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); + } + ; + +single_declaration + : fully_specified_type { + $$.type = $1; + $$.intermAggregate = context->parseSingleDeclaration($$.type, @1, ""); + } + | fully_specified_type identifier { + $$.type = $1; + $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string); + } + | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET { + context->error(@2, "unsized array declarations not supported", $2.string->c_str()); + context->recover(); + + $$.type = $1; + $$.intermAggregate = context->parseSingleDeclaration($$.type, @2, *$2.string); + } + | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$.type = $1; + $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4); + } + | fully_specified_type identifier EQUAL initializer { + $$.type = $1; + $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); + } + | INVARIANT IDENTIFIER { + VERTEX_ONLY("invariant declaration", @1); + if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, @2); + if (!$2.symbol) + { + context->error(@2, "undeclared identifier declared as invariant", $2.string->c_str()); + context->recover(); + + $$.intermAggregate = 0; + } + else + { + TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), @2); + $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2); + } + } + ; + +fully_specified_type + : type_specifier { + $$ = $1; + + if ($1.array) { + context->error(@1, "not supported", "first-class array"); + context->recover(); + $1.setArray(false); + } + } + | type_qualifier type_specifier { + $$ = context->addFullySpecifiedType($1.qualifier, $1.layoutQualifier, $2); + } + ; + +interpolation_qualifier + : SMOOTH { + $$.qualifier = EvqSmooth; + } + | FLAT { + $$.qualifier = EvqFlat; + } + ; + +parameter_type_qualifier + : CONST_QUAL { + $$ = EvqConst; + } + ; + +type_qualifier + : ATTRIBUTE { + VERTEX_ONLY("attribute", @1); + ES2_ONLY("attribute", @1); + if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute")) + context->recover(); + $$.setBasic(EbtVoid, EvqAttribute, @1); + } + | VARYING { + ES2_ONLY("varying", @1); + if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqVaryingOut, @1); + else + $$.setBasic(EbtVoid, EvqVaryingIn, @1); + } + | INVARIANT VARYING { + ES2_ONLY("varying", @1); + if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1); + else + $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1); + } + | storage_qualifier { + if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) { + context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier)); + context->recover(); + } else { + $$.setBasic(EbtVoid, $1.qualifier, @1); + } + } + | interpolation_qualifier storage_qualifier { + $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier); + } + | interpolation_qualifier { + context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier)); + context->recover(); + + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, @1); + } + | layout_qualifier { + $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.layoutQualifier = $1; + } + | layout_qualifier storage_qualifier { + $$.setBasic(EbtVoid, $2.qualifier, @2); + $$.layoutQualifier = $1; + } + ; + +storage_qualifier + : CONST_QUAL { + $$.qualifier = EvqConst; + } + | IN_QUAL { + ES3_ONLY("in", @1, "storage qualifier"); + $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + } + | OUT_QUAL { + ES3_ONLY("out", @1, "storage qualifier"); + $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; + } + | CENTROID IN_QUAL { + ES3_ONLY("centroid in", @1, "storage qualifier"); + if (context->shaderType == SH_VERTEX_SHADER) + { + context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); + context->recover(); + } + $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; + } + | CENTROID OUT_QUAL { + ES3_ONLY("centroid out", @1, "storage qualifier"); + if (context->shaderType == SH_FRAGMENT_SHADER) + { + context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); + context->recover(); + } + $$.qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + } + | UNIFORM { + if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform")) + context->recover(); + $$.qualifier = EvqUniform; + } + ; + +type_specifier + : type_specifier_no_prec { + $$ = $1; + + if ($$.precision == EbpUndefined) { + $$.precision = context->symbolTable.getDefaultPrecision($1.type); + if (context->precisionErrorCheck(@1, $$.precision, $1.type)) { + context->recover(); + } + } + } + | precision_qualifier type_specifier_no_prec { + $$ = $2; + $$.precision = $1; + + if (!SupportsPrecision($2.type)) { + context->error(@1, "illegal type for precision qualifier", getBasicString($2.type)); + context->recover(); + } + } + ; + +precision_qualifier + : HIGH_PRECISION { + $$ = EbpHigh; + } + | MEDIUM_PRECISION { + $$ = EbpMedium; + } + | LOW_PRECISION { + $$ = EbpLow; + } + ; + +layout_qualifier + : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { + ES3_ONLY("layout", @1, "qualifier"); + $$ = $3; + } + ; + +layout_qualifier_id_list + : layout_qualifier_id { + $$ = $1; + } + | layout_qualifier_id_list COMMA layout_qualifier_id { + $$ = context->joinLayoutQualifiers($1, $3); + } + ; + +layout_qualifier_id + : IDENTIFIER { + $$ = context->parseLayoutQualifier(*$1.string, @1); + } + | IDENTIFIER EQUAL INTCONSTANT { + $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + } + | IDENTIFIER EQUAL UINTCONSTANT { + $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + } + ; + +type_specifier_no_prec + : type_specifier_nonarray { + $$ = $1; + } + | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + + if (context->arrayTypeErrorCheck(@2, $1)) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck(@2, $3, size)) + context->recover(); + $$.setArray(true, size); + } + } + ; + +type_specifier_nonarray + : VOID_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, @1); + } + | FLOAT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + } + | INT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, @1); + } + | UINT_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + } + | BOOL_TYPE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, @1); + } + | VEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setAggregate(2); + } + | VEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setAggregate(3); + } + | VEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setAggregate(4); + } + | BVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, @1); + $$.setAggregate(2); + } + | BVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, @1); + $$.setAggregate(3); + } + | BVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, @1); + $$.setAggregate(4); + } + | IVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, @1); + $$.setAggregate(2); + } + | IVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, @1); + $$.setAggregate(3); + } + | IVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, @1); + $$.setAggregate(4); + } + | UVEC2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(2); + } + | UVEC3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(3); + } + | UVEC4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUInt, qual, @1); + $$.setAggregate(4); + } + | MATRIX2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(2, 2); + } + | MATRIX3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(3, 3); + } + | MATRIX4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(4, 4); + } + | MATRIX2x3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(2, 3); + } + | MATRIX3x2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(3, 2); + } + | MATRIX2x4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(2, 4); + } + | MATRIX4x2 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(4, 2); + } + | MATRIX3x4 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(3, 4); + } + | MATRIX4x3 { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, @1); + $$.setMatrix(4, 3); + } + | SAMPLER2D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2D, qual, @1); + } + | SAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler3D, qual, @1); + } + | SAMPLERCUBE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCube, qual, @1); + } + | SAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DArray, qual, @1); + } + | ISAMPLER2D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler2D, qual, @1); + } + | ISAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler3D, qual, @1); + } + | ISAMPLERCUBE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISamplerCube, qual, @1); + } + | ISAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtISampler2DArray, qual, @1); + } + | USAMPLER2D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler2D, qual, @1); + } + | USAMPLER3D { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler3D, qual, @1); + } + | USAMPLERCUBE { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSamplerCube, qual, @1); + } + | USAMPLER2DARRAY { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtUSampler2DArray, qual, @1); + } + | SAMPLER2DSHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DShadow, qual, @1); + } + | SAMPLERCUBESHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCubeShadow, qual, @1); + } + | SAMPLER2DARRAYSHADOW { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DArrayShadow, qual, @1); + } + | SAMPLER_EXTERNAL_OES { + if (!context->supportsExtension("GL_OES_EGL_image_external")) { + context->error(@1, "unsupported type", "samplerExternalOES"); + context->recover(); + } + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerExternalOES, qual, @1); + } + | SAMPLER2DRECT { + if (!context->supportsExtension("GL_ARB_texture_rectangle")) { + context->error(@1, "unsupported type", "sampler2DRect"); + context->recover(); + } + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2DRect, qual, @1); + } + | struct_specifier { + $$ = $1; + $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | TYPE_NAME { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast<TVariable*>($1.symbol)->getType(); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtStruct, qual, @1); + $$.userDef = &structure; + } + ; + +struct_specifier + : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + $$ = context->addStructure(@1, @2, $2.string, $5); + } + | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + $$ = context->addStructure(@1, @$, NewPoolTString(""), $4); + } + ; + +struct_declaration_list + : struct_declaration { + $$ = $1; + } + | struct_declaration_list struct_declaration { + $$ = $1; + for (size_t i = 0; i < $2->size(); ++i) { + TField* field = (*$2)[i]; + for (size_t j = 0; j < $$->size(); ++j) { + if ((*$$)[j]->name() == field->name()) { + context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str()); + context->recover(); + } + } + $$->push_back(field); + } + } + ; + +struct_declaration + : type_specifier struct_declarator_list SEMICOLON { + $$ = context->addStructDeclaratorList($1, $2); + } + | type_qualifier type_specifier struct_declarator_list SEMICOLON { + // ES3 Only, but errors should be handled elsewhere + $2.qualifier = $1.qualifier; + $2.layoutQualifier = $1.layoutQualifier; + $$ = context->addStructDeclaratorList($2, $3); + } + ; + +struct_declarator_list + : struct_declarator { + $$ = NewPoolTFieldList(); + $$->push_back($1); + } + | struct_declarator_list COMMA struct_declarator { + $$->push_back($3); + } + ; + +struct_declarator + : identifier { + if (context->reservedErrorCheck(@1, *$1.string)) + context->recover(); + + TType* type = new TType(EbtVoid, EbpUndefined); + $$ = new TField(type, $1.string, @1); + } + | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (context->reservedErrorCheck(@1, *$1.string)) + context->recover(); + + TType* type = new TType(EbtVoid, EbpUndefined); + int size; + if (context->arraySizeErrorCheck(@3, $3, size)) + context->recover(); + type->setArraySize(size); + + $$ = new TField(type, $1.string, @1); + } + ; + +initializer + : assignment_expression { $$ = $1; } + ; + +declaration_statement + : declaration { $$ = $1; } + ; + +statement + : compound_statement { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +// Grammar Note: No labeled statements; 'goto' is not supported. + +simple_statement + : declaration_statement { $$ = $1; } + | expression_statement { $$ = $1; } + | selection_statement { $$ = $1; } + | iteration_statement { $$ = $1; } + | jump_statement { $$ = $1; } + ; + +compound_statement + : LEFT_BRACE RIGHT_BRACE { $$ = 0; } + | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE { + if ($3 != 0) { + $3->setOp(EOpSequence); + $3->setLine(@$); + } + $$ = $3; + } + ; + +statement_no_new_scope + : compound_statement_no_new_scope { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +statement_with_scope + : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; } + | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; } + ; + +compound_statement_no_new_scope + // Statement that doesn't create a new scope, for selection_statement, iteration_statement + : LEFT_BRACE RIGHT_BRACE { + $$ = 0; + } + | LEFT_BRACE statement_list RIGHT_BRACE { + if ($2) { + $2->setOp(EOpSequence); + $2->setLine(@$); + } + $$ = $2; + } + ; + +statement_list + : statement { + $$ = context->intermediate.makeAggregate($1, @$); + } + | statement_list statement { + $$ = context->intermediate.growAggregate($1, $2, @$); + } + ; + +expression_statement + : SEMICOLON { $$ = 0; } + | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); } + ; + +selection_statement + : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { + if (context->boolErrorCheck(@1, $3)) + context->recover(); + $$ = context->intermediate.addSelection($3, $5, @1); + } + ; + +selection_rest_statement + : statement_with_scope ELSE statement_with_scope { + $$.node1 = $1; + $$.node2 = $3; + } + | statement_with_scope { + $$.node1 = $1; + $$.node2 = 0; + } + ; + +// Grammar Note: No 'switch'. Switch statements not supported. + +condition + // In 1996 c++ draft, conditions can include single declarations + : expression { + $$ = $1; + if (context->boolErrorCheck($1->getLine(), $1)) + context->recover(); + } + | fully_specified_type identifier EQUAL initializer { + TIntermNode* intermNode; + if (context->structQualifierErrorCheck(@2, $1)) + context->recover(); + if (context->boolErrorCheck(@2, $1)) + context->recover(); + + if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode)) + $$ = $4; + else { + context->recover(); + $$ = 0; + } + } + ; + +iteration_statement + : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1); + --context->loopNestingLevel; + } + | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (context->boolErrorCheck(@8, $6)) + context->recover(); + + $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); + --context->loopNestingLevel; + } + | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + context->symbolTable.pop(); + $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1); + --context->loopNestingLevel; + } + ; + +for_init_statement + : expression_statement { + $$ = $1; + } + | declaration_statement { + $$ = $1; + } + ; + +conditionopt + : condition { + $$ = $1; + } + | /* May be null */ { + $$ = 0; + } + ; + +for_rest_statement + : conditionopt SEMICOLON { + $$.node1 = $1; + $$.node2 = 0; + } + | conditionopt SEMICOLON expression { + $$.node1 = $1; + $$.node2 = $3; + } + ; + +jump_statement + : CONTINUE SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error(@1, "continue statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpContinue, @1); + } + | BREAK SEMICOLON { + if (context->loopNestingLevel <= 0) { + context->error(@1, "break statement only allowed in loops", ""); + context->recover(); + } + $$ = context->intermediate.addBranch(EOpBreak, @1); + } + | RETURN SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, @1); + if (context->currentFunctionType->getBasicType() != EbtVoid) { + context->error(@1, "non-void function must return a value", "return"); + context->recover(); + } + } + | RETURN expression SEMICOLON { + $$ = context->intermediate.addBranch(EOpReturn, $2, @1); + context->functionReturnsValue = true; + if (context->currentFunctionType->getBasicType() == EbtVoid) { + context->error(@1, "void function cannot return a value", "return"); + context->recover(); + } else if (*(context->currentFunctionType) != $2->getType()) { + context->error(@1, "function return is not matching type:", "return"); + context->recover(); + } + } + | DISCARD SEMICOLON { + FRAG_ONLY("discard", @1); + $$ = context->intermediate.addBranch(EOpKill, @1); + } + ; + +// Grammar Note: No 'goto'. Gotos are not supported. + +translation_unit + : external_declaration { + $$ = $1; + context->treeRoot = $$; + } + | translation_unit external_declaration { + $$ = context->intermediate.growAggregate($1, $2, @$); + context->treeRoot = $$; + } + ; + +external_declaration + : function_definition { + $$ = $1; + } + | declaration { + $$ = $1; + } + ; + +function_definition + : function_prototype { + TFunction* function = $1.function; + + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion); + + if (builtIn) + { + context->error(@1, "built-in functions cannot be redefined", function->getName().c_str()); + context->recover(); + } + + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName(), context->shaderVersion)); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + context->error(@1, "function already has a body", function->getName().c_str()); + context->recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function->getName() == "main") { + if (function->getParamCount() > 0) { + context->error(@1, "function cannot take any parameter(s)", function->getName().c_str()); + context->recover(); + } + if (function->getReturnType().getBasicType() != EbtVoid) { + context->error(@1, "", function->getReturnType().getBasicString(), "main function cannot return a value"); + context->recover(); + } + } + + // + // Remember the return type for later checking for RETURN statements. + // + context->currentFunctionType = &(prevDec->getReturnType()); + context->functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (size_t i = 0; i < function->getParamCount(); i++) { + const TParameter& param = function->getParam(i); + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! context->symbolTable.declare(*variable)) { + context->error(@1, "redefinition", variable->getName().c_str()); + context->recover(); + delete variable; + } + + // + // Add the parameter to the HIL + // + paramNodes = context->intermediate.growAggregate( + paramNodes, + context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), @1), + @1); + } else { + paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1); + } + } + context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1); + $1.intermAggregate = paramNodes; + context->loopNestingLevel = 0; + } + compound_statement_no_new_scope { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + context->error(@1, "function does not return a value:", "", $1.function->getName().c_str()); + context->recover(); + } + + $$ = context->intermediate.growAggregate($1.intermAggregate, $3, @$); + context->intermediate.setAggregateOperator($$, EOpFunction, @1); + $$->getAsAggregate()->setName($1.function->getMangledName().c_str()); + $$->getAsAggregate()->setType($1.function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + $$->getAsAggregate()->setOptimize(context->pragma().optimize); + $$->getAsAggregate()->setDebug(context->pragma().debug); + + context->symbolTable.pop(); + } + ; + +%% + +int glslang_parse(TParseContext* context) { + return yyparse(context); +} diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp new file mode 100644 index 00000000000..5cfbba63eb3 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp @@ -0,0 +1,3360 @@ +#line 17 "./glslang.l" +// +// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + + + +#line 25 "./glslang_lex.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 37 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +typedef uint64_t flex_uint64_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + yy_size_t yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(yyscanner) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (yy_size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 237 +#define YY_END_OF_BUFFER 238 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[813] = + { 0, + 0, 0, 238, 236, 235, 235, 222, 228, 233, 217, + 218, 226, 225, 214, 223, 221, 227, 180, 180, 215, + 211, 229, 216, 230, 234, 177, 219, 220, 232, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 212, + 231, 213, 224, 208, 194, 213, 202, 197, 192, 200, + 190, 201, 191, 186, 193, 185, 179, 180, 0, 183, + 0, 220, 212, 219, 209, 205, 207, 206, 210, 177, + 198, 204, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 12, 177, 177, 177, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 15, 177, + 177, 23, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 199, 203, 0, 189, 185, + 0, 188, 182, 0, 184, 178, 195, 196, 177, 136, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 13, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 27, 177, 177, 177, 177, 177, + + 177, 177, 177, 177, 177, 177, 24, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 0, 186, 0, 185, 187, 181, 177, 177, 177, + 30, 177, 177, 18, 174, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 16, 139, 177, 177, 177, + 177, 21, 177, 177, 143, 155, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 152, 4, + 35, 36, 37, 177, 177, 177, 177, 177, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 142, 31, 177, + 177, 28, 177, 177, 177, 177, 177, 177, 177, 47, + 48, 49, 29, 177, 177, 177, 177, 177, 177, 10, + 53, 54, 55, 177, 137, 177, 177, 7, 177, 177, + 177, 177, 164, 165, 166, 177, 32, 177, 156, 26, + 167, 168, 169, 2, 161, 162, 163, 177, 177, 177, + 25, 159, 177, 177, 177, 50, 51, 52, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 86, + 177, 177, 177, 177, 177, 177, 177, 153, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 177, 138, + 177, 177, 176, 56, 57, 58, 177, 177, 14, 177, + 91, 177, 177, 177, 177, 89, 177, 177, 177, 154, + 149, 92, 177, 177, 177, 177, 177, 177, 144, 177, + 177, 177, 78, 38, 41, 43, 42, 39, 45, 44, + 46, 40, 177, 177, 177, 177, 160, 135, 177, 177, + 147, 177, 177, 177, 34, 87, 173, 22, 148, 77, + 177, 158, 17, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 19, 33, 177, + 177, 177, 177, 177, 177, 93, 94, 95, 177, 177, + + 177, 177, 177, 3, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 140, 177, 177, 177, 177, + 177, 8, 177, 177, 9, 177, 177, 177, 177, 20, + 79, 11, 150, 97, 98, 99, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 145, 177, + 177, 177, 81, 83, 80, 177, 177, 177, 177, 177, + 177, 177, 141, 101, 102, 103, 177, 177, 157, 177, + 146, 177, 177, 6, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 96, 151, 1, 177, 177, 177, 177, + 177, 175, 177, 90, 5, 170, 59, 62, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 82, 177, 177, 177, 177, 100, 177, 177, 177, + 177, 177, 120, 66, 67, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 88, 177, + 177, 177, 104, 122, 70, 71, 177, 177, 84, 177, + 177, 177, 177, 177, 177, 177, 115, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 129, 177, 177, + 177, 177, 60, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 116, 105, 177, 106, 177, + 177, 177, 130, 177, 177, 68, 177, 177, 177, 177, + + 177, 177, 177, 177, 177, 177, 177, 177, 177, 117, + 177, 177, 131, 177, 177, 72, 107, 108, 177, 111, + 177, 112, 177, 177, 177, 177, 177, 85, 177, 177, + 177, 177, 64, 177, 63, 126, 177, 177, 109, 110, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 124, 127, 118, 177, 65, 177, 177, 177, 177, 177, + 177, 177, 177, 125, 128, 177, 177, 121, 69, 177, + 177, 171, 177, 177, 177, 74, 177, 177, 123, 73, + 177, 177, 177, 177, 177, 177, 132, 177, 177, 177, + 177, 177, 177, 133, 177, 177, 177, 75, 177, 134, + + 113, 114, 177, 177, 177, 61, 177, 177, 172, 119, + 76, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 20, 20, 21, 21, 22, 23, 24, + 25, 26, 27, 1, 28, 29, 30, 31, 32, 33, + 34, 34, 34, 34, 34, 34, 35, 34, 36, 34, + 34, 37, 38, 34, 39, 34, 34, 40, 34, 34, + 41, 1, 42, 43, 44, 1, 45, 46, 47, 48, + + 49, 50, 51, 52, 53, 34, 54, 55, 56, 57, + 58, 59, 34, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[73] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 2, 2, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 4, 3, 3, 3, 3, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, + 1, 1 + } ; + +static yyconst flex_int16_t yy_base[817] = + { 0, + 0, 0, 941, 942, 942, 942, 915, 48, 69, 942, + 942, 914, 66, 942, 65, 63, 913, 82, 136, 911, + 942, 82, 911, 60, 942, 0, 942, 942, 67, 58, + 51, 68, 75, 61, 105, 877, 114, 79, 67, 44, + 89, 871, 101, 884, 121, 127, 136, 143, 36, 942, + 112, 942, 942, 942, 942, 942, 942, 942, 942, 942, + 942, 942, 942, 158, 942, 163, 163, 0, 199, 942, + 0, 942, 942, 942, 907, 942, 942, 942, 906, 0, + 942, 942, 868, 873, 80, 870, 878, 877, 864, 867, + 878, 171, 872, 860, 857, 870, 857, 854, 854, 860, + + 75, 176, 854, 864, 850, 856, 859, 860, 0, 852, + 862, 177, 861, 856, 837, 105, 841, 854, 845, 112, + 838, 178, 850, 852, 185, 841, 838, 827, 836, 177, + 185, 840, 836, 838, 827, 830, 124, 145, 197, 839, + 827, 839, 190, 832, 831, 942, 942, 239, 942, 220, + 256, 942, 942, 263, 270, 185, 942, 942, 830, 0, + 826, 821, 825, 834, 831, 243, 815, 815, 826, 818, + 143, 828, 825, 825, 823, 820, 812, 818, 805, 803, + 815, 801, 817, 0, 814, 802, 809, 806, 810, 811, + 804, 801, 790, 789, 802, 805, 793, 801, 789, 795, + + 786, 244, 791, 794, 785, 792, 781, 785, 776, 790, + 789, 780, 786, 235, 770, 773, 771, 781, 771, 766, + 764, 766, 776, 762, 764, 761, 772, 771, 774, 756, + 244, 764, 760, 758, 767, 746, 281, 764, 766, 755, + 747, 291, 298, 306, 317, 942, 942, 744, 754, 753, + 0, 751, 311, 0, 0, 744, 742, 742, 743, 738, + 746, 735, 752, 741, 322, 0, 0, 735, 745, 744, + 744, 0, 729, 325, 0, 0, 731, 328, 738, 739, + 730, 724, 723, 724, 723, 723, 334, 718, 0, 0, + 714, 713, 712, 714, 715, 720, 714, 710, 723, 718, + + 718, 716, 715, 709, 703, 705, 704, 708, 700, 703, + 698, 706, 711, 699, 696, 708, 699, 0, 0, 705, + 701, 0, 693, 693, 698, 689, 696, 337, 693, 0, + 0, 0, 0, 683, 695, 694, 693, 694, 694, 0, + 0, 0, 0, 681, 0, 689, 680, 0, 679, 680, + 674, 684, 0, 0, 0, 675, 0, 671, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 681, 341, 680, + 0, 0, 678, 674, 671, 0, 0, 0, 663, 343, + 346, 355, 668, 664, 669, 660, 658, 671, 656, 0, + 656, 669, 658, 654, 660, 655, 662, 0, 660, 657, + + 661, 645, 643, 646, 652, 658, 653, 652, 640, 0, + 642, 643, 0, 0, 0, 0, 640, 643, 0, 637, + 0, 650, 630, 639, 634, 0, 627, 627, 640, 0, + 642, 0, 359, 655, 654, 653, 620, 619, 0, 636, + 635, 630, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 619, 632, 619, 616, 0, 0, 621, 620, + 0, 617, 624, 623, 0, 609, 0, 0, 0, 0, + 606, 0, 0, 605, 616, 362, 609, 615, 614, 611, + 606, 603, 596, 596, 609, 594, 606, 0, 0, 599, + 622, 621, 620, 587, 586, 355, 356, 0, 598, 601, + + 599, 588, 584, 0, 596, 593, 592, 582, 581, 571, + 588, 574, 369, 582, 585, 0, 602, 601, 600, 567, + 566, 0, 580, 567, 0, 577, 570, 571, 574, 0, + 0, 0, 0, 594, 593, 0, 570, 573, 558, 565, + 556, 563, 564, 564, 563, 549, 379, 561, 0, 562, + 551, 550, 0, 0, 0, 575, 574, 573, 540, 539, + 535, 543, 0, 571, 570, 0, 547, 550, 0, 386, + 0, 528, 537, 0, 533, 532, 541, 541, 529, 543, + 527, 541, 536, 0, 0, 0, 553, 552, 551, 518, + 517, 0, 517, 0, 0, 362, 382, 541, 527, 530, + + 513, 525, 513, 512, 521, 521, 538, 537, 536, 503, + 502, 0, 502, 503, 502, 512, 0, 515, 511, 513, + 509, 496, 527, 377, 0, 504, 507, 499, 491, 498, + 489, 510, 498, 494, 496, 494, 494, 493, 0, 481, + 480, 490, 0, 510, 390, 0, 487, 490, 0, 490, + 489, 473, 465, 473, 463, 471, 0, 468, 467, 488, + 476, 474, 474, 458, 461, 475, 459, 490, 470, 471, + 468, 465, 475, 452, 466, 465, 449, 448, 447, 468, + 456, 454, 454, 435, 434, 0, 462, 434, 460, 432, + 436, 435, 466, 446, 443, 0, 442, 445, 441, 443, + + 427, 424, 437, 422, 423, 430, 424, 413, 412, 0, + 418, 417, 448, 428, 425, 0, 0, 0, 421, 0, + 420, 0, 426, 425, 409, 406, 407, 0, 399, 407, + 397, 403, 424, 403, 0, 0, 415, 414, 0, 0, + 413, 412, 396, 393, 394, 408, 407, 384, 383, 389, + 0, 0, 410, 382, 408, 400, 392, 378, 60, 89, + 105, 143, 173, 0, 0, 216, 217, 0, 0, 222, + 243, 0, 244, 234, 259, 0, 291, 330, 0, 0, + 323, 311, 323, 315, 361, 362, 0, 363, 348, 389, + 355, 358, 359, 0, 378, 380, 371, 0, 392, 0, + + 0, 0, 373, 374, 368, 0, 369, 370, 0, 0, + 0, 942, 434, 437, 438, 439 + } ; + +static yyconst flex_int16_t yy_def[817] = + { 0, + 812, 1, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 813, 812, 812, 812, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 814, 812, 815, 18, 19, 812, 812, + 816, 812, 812, 812, 812, 812, 812, 812, 812, 813, + 812, 812, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 812, 812, 812, 812, 815, + 812, 812, 812, 812, 812, 816, 812, 812, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 812, 812, 812, 812, 812, 812, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + + 813, 813, 813, 813, 813, 813, 813, 813, 813, 813, + 813, 0, 812, 812, 812, 812 + } ; + +static yyconst flex_int16_t yy_nxt[1015] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 19, 19, 19, + 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 27, 28, 29, 26, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 26, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 26, 26, 26, 50, 51, + 52, 53, 55, 56, 57, 60, 62, 64, 64, 64, + 64, 64, 64, 64, 78, 79, 73, 144, 117, 63, + 61, 81, 118, 58, 66, 145, 67, 67, 67, 67, + + 67, 67, 68, 74, 83, 75, 76, 777, 86, 82, + 87, 115, 89, 69, 88, 97, 90, 98, 84, 85, + 70, 71, 91, 93, 116, 92, 99, 94, 109, 180, + 69, 110, 95, 119, 111, 112, 146, 161, 96, 113, + 181, 162, 114, 778, 70, 122, 120, 71, 66, 100, + 68, 68, 68, 68, 68, 68, 68, 101, 106, 102, + 123, 200, 103, 124, 205, 126, 107, 69, 104, 201, + 206, 779, 127, 128, 70, 133, 129, 108, 134, 229, + 230, 147, 130, 131, 69, 132, 135, 141, 137, 148, + 149, 142, 138, 136, 151, 152, 139, 231, 70, 140, + + 143, 153, 812, 260, 261, 232, 148, 149, 154, 780, + 154, 151, 152, 155, 155, 155, 155, 155, 155, 155, + 182, 220, 169, 247, 208, 153, 170, 171, 812, 213, + 222, 192, 781, 183, 193, 194, 221, 209, 195, 210, + 196, 233, 238, 223, 239, 214, 215, 247, 242, 234, + 242, 151, 152, 243, 243, 243, 243, 243, 243, 243, + 291, 292, 293, 782, 783, 244, 784, 244, 151, 152, + 245, 245, 245, 245, 245, 245, 245, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 254, 305, 323, 785, 786, 306, 330, 331, 332, + + 787, 324, 246, 788, 255, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 246, + 245, 245, 245, 245, 245, 245, 245, 341, 342, 343, + 149, 245, 245, 245, 245, 245, 245, 245, 353, 354, + 355, 361, 362, 363, 365, 366, 367, 149, 789, 152, + 376, 377, 378, 414, 415, 416, 434, 435, 436, 444, + 445, 446, 447, 448, 449, 790, 152, 791, 792, 437, + 438, 450, 451, 452, 491, 492, 493, 517, 518, 519, + 793, 794, 539, 541, 556, 557, 558, 494, 495, 629, + 520, 521, 540, 542, 587, 588, 589, 559, 560, 630, + + 561, 607, 608, 609, 659, 795, 796, 590, 591, 631, + 797, 660, 798, 661, 610, 611, 632, 679, 633, 634, + 799, 800, 801, 802, 680, 803, 681, 804, 805, 806, + 807, 808, 809, 810, 811, 80, 80, 80, 64, 150, + 156, 156, 776, 775, 774, 773, 772, 771, 770, 769, + 768, 767, 766, 765, 764, 763, 762, 761, 760, 759, + 758, 757, 756, 755, 754, 753, 752, 751, 750, 749, + 748, 747, 746, 745, 744, 743, 742, 741, 740, 739, + 738, 737, 736, 735, 734, 733, 732, 731, 730, 729, + 728, 727, 726, 725, 724, 723, 722, 721, 720, 719, + + 718, 717, 716, 715, 714, 713, 712, 711, 710, 709, + 708, 707, 706, 705, 704, 703, 702, 701, 700, 699, + 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, + 688, 687, 686, 685, 684, 683, 682, 678, 677, 676, + 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, + 665, 664, 663, 662, 658, 657, 656, 655, 654, 653, + 652, 651, 650, 649, 648, 647, 646, 645, 644, 643, + 642, 641, 640, 639, 638, 637, 636, 635, 628, 627, + 626, 625, 624, 623, 622, 621, 620, 619, 618, 617, + 616, 615, 614, 613, 612, 606, 605, 604, 603, 602, + + 601, 600, 599, 598, 597, 596, 595, 594, 593, 592, + 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, + 576, 575, 574, 573, 572, 571, 570, 569, 568, 567, + 566, 565, 564, 563, 562, 555, 554, 553, 552, 551, + 550, 549, 548, 547, 546, 545, 544, 543, 538, 537, + 536, 535, 534, 533, 532, 531, 530, 529, 528, 527, + 526, 525, 524, 523, 522, 516, 515, 514, 513, 512, + 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, + 501, 500, 499, 498, 497, 496, 490, 489, 488, 487, + 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, + + 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, + 466, 465, 464, 463, 462, 461, 460, 459, 458, 457, + 456, 455, 454, 453, 443, 442, 441, 440, 439, 433, + 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, + 422, 421, 420, 419, 418, 417, 413, 412, 411, 410, + 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, + 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, + 389, 388, 387, 386, 385, 384, 383, 382, 381, 380, + 379, 375, 374, 373, 372, 371, 370, 369, 368, 364, + 360, 359, 358, 357, 356, 352, 351, 350, 349, 348, + + 347, 346, 345, 344, 340, 339, 338, 337, 336, 335, + 334, 333, 329, 328, 327, 326, 325, 322, 321, 320, + 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, + 309, 308, 307, 304, 303, 302, 301, 300, 299, 298, + 297, 296, 295, 294, 290, 289, 288, 287, 286, 285, + 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, + 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, + 264, 263, 262, 259, 258, 257, 256, 253, 252, 251, + 250, 249, 248, 241, 240, 237, 236, 235, 228, 227, + 226, 225, 224, 219, 218, 217, 216, 212, 211, 207, + + 204, 203, 202, 199, 198, 197, 191, 190, 189, 188, + 187, 186, 185, 184, 179, 178, 177, 176, 175, 174, + 173, 172, 168, 167, 166, 165, 164, 163, 160, 159, + 158, 157, 125, 121, 105, 77, 72, 65, 59, 54, + 812, 3, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812 + } ; + +static yyconst flex_int16_t yy_chk[1015] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 8, 8, 9, 13, 15, 16, 16, 16, + 16, 16, 16, 16, 24, 24, 22, 49, 40, 15, + 13, 29, 40, 9, 18, 49, 18, 18, 18, 18, + + 18, 18, 18, 22, 30, 22, 22, 759, 31, 29, + 31, 39, 32, 18, 31, 34, 32, 34, 30, 30, + 18, 18, 32, 33, 39, 32, 34, 33, 38, 101, + 18, 38, 33, 41, 38, 38, 51, 85, 33, 38, + 101, 85, 38, 760, 18, 43, 41, 18, 19, 35, + 19, 19, 19, 19, 19, 19, 19, 35, 37, 35, + 43, 116, 35, 43, 120, 45, 37, 19, 35, 116, + 120, 761, 45, 45, 19, 46, 45, 37, 46, 137, + 137, 51, 45, 45, 19, 45, 46, 48, 47, 64, + 64, 48, 47, 46, 66, 66, 47, 138, 19, 47, + + 48, 67, 67, 171, 171, 138, 64, 64, 69, 762, + 69, 66, 66, 69, 69, 69, 69, 69, 69, 69, + 102, 130, 92, 156, 122, 67, 92, 92, 67, 125, + 131, 112, 763, 102, 112, 112, 130, 122, 112, 122, + 112, 139, 143, 131, 143, 125, 125, 156, 148, 139, + 148, 150, 150, 148, 148, 148, 148, 148, 148, 148, + 202, 202, 202, 766, 767, 151, 770, 151, 150, 150, + 151, 151, 151, 151, 151, 151, 151, 154, 154, 154, + 154, 154, 154, 154, 155, 155, 155, 155, 155, 155, + 155, 166, 214, 231, 771, 773, 214, 237, 237, 237, + + 774, 231, 155, 775, 166, 242, 242, 242, 242, 242, + 242, 242, 243, 243, 243, 243, 243, 243, 243, 155, + 244, 244, 244, 244, 244, 244, 244, 253, 253, 253, + 243, 245, 245, 245, 245, 245, 245, 245, 265, 265, + 265, 274, 274, 274, 278, 278, 278, 243, 777, 245, + 287, 287, 287, 328, 328, 328, 369, 369, 369, 380, + 380, 380, 381, 381, 381, 778, 245, 781, 782, 369, + 369, 382, 382, 382, 433, 433, 433, 476, 476, 476, + 783, 784, 496, 497, 513, 513, 513, 433, 433, 596, + 476, 476, 496, 497, 547, 547, 547, 513, 513, 596, + + 513, 570, 570, 570, 624, 785, 786, 547, 547, 597, + 788, 624, 789, 624, 570, 570, 597, 645, 597, 597, + 790, 791, 792, 793, 645, 795, 645, 796, 797, 799, + 803, 804, 805, 807, 808, 813, 813, 813, 814, 815, + 816, 816, 758, 757, 756, 755, 754, 753, 750, 749, + 748, 747, 746, 745, 744, 743, 742, 741, 738, 737, + 734, 733, 732, 731, 730, 729, 727, 726, 725, 724, + 723, 721, 719, 715, 714, 713, 712, 711, 709, 708, + 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, + 697, 695, 694, 693, 692, 691, 690, 689, 688, 687, + + 685, 684, 683, 682, 681, 680, 679, 678, 677, 676, + 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, + 665, 664, 663, 662, 661, 660, 659, 658, 656, 655, + 654, 653, 652, 651, 650, 648, 647, 644, 642, 641, + 640, 638, 637, 636, 635, 634, 633, 632, 631, 630, + 629, 628, 627, 626, 623, 622, 621, 620, 619, 618, + 616, 615, 614, 613, 611, 610, 609, 608, 607, 606, + 605, 604, 603, 602, 601, 600, 599, 598, 593, 591, + 590, 589, 588, 587, 583, 582, 581, 580, 579, 578, + 577, 576, 575, 573, 572, 568, 567, 565, 564, 562, + + 561, 560, 559, 558, 557, 556, 552, 551, 550, 548, + 546, 545, 544, 543, 542, 541, 540, 539, 538, 537, + 535, 534, 529, 528, 527, 526, 524, 523, 521, 520, + 519, 518, 517, 515, 514, 512, 511, 510, 509, 508, + 507, 506, 505, 503, 502, 501, 500, 499, 495, 494, + 493, 492, 491, 490, 487, 486, 485, 484, 483, 482, + 481, 480, 479, 478, 477, 475, 474, 471, 466, 464, + 463, 462, 460, 459, 456, 455, 454, 453, 442, 441, + 440, 438, 437, 436, 435, 434, 431, 429, 428, 427, + 425, 424, 423, 422, 420, 418, 417, 412, 411, 409, + + 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, + 397, 396, 395, 394, 393, 392, 391, 389, 388, 387, + 386, 385, 384, 383, 379, 375, 374, 373, 370, 368, + 358, 356, 352, 351, 350, 349, 347, 346, 344, 339, + 338, 337, 336, 335, 334, 329, 327, 326, 325, 324, + 323, 321, 320, 317, 316, 315, 314, 313, 312, 311, + 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, + 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, + 288, 286, 285, 284, 283, 282, 281, 280, 279, 277, + 273, 271, 270, 269, 268, 264, 263, 262, 261, 260, + + 259, 258, 257, 256, 252, 250, 249, 248, 241, 240, + 239, 238, 236, 235, 234, 233, 232, 230, 229, 228, + 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, + 217, 216, 215, 213, 212, 211, 210, 209, 208, 207, + 206, 205, 204, 203, 201, 200, 199, 198, 197, 196, + 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, + 185, 183, 182, 181, 180, 179, 178, 177, 176, 175, + 174, 173, 172, 170, 169, 168, 167, 165, 164, 163, + 162, 161, 159, 145, 144, 142, 141, 140, 136, 135, + 134, 133, 132, 129, 128, 127, 126, 124, 123, 121, + + 119, 118, 117, 115, 114, 113, 111, 110, 108, 107, + 106, 105, 104, 103, 100, 99, 98, 97, 96, 95, + 94, 93, 91, 90, 89, 88, 87, 86, 84, 83, + 79, 75, 44, 42, 36, 23, 20, 17, 12, 7, + 3, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + + 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[238] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +/* +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +This file contains the Lex specification for GLSL ES. +Based on ANSI C grammar, Lex specification: +http://www.lysator.liu.se/c/ANSI-C-grammar-l.html + +IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh, +WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). +*/ + +#include "compiler/translator/glslang.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/preprocessor/Token.h" +#include "compiler/translator/util.h" +#include "compiler/translator/length_limits.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +#define YY_USER_ACTION \ + yylloc->first_file = yylloc->last_file = yycolumn; \ + yylloc->first_line = yylloc->last_line = yylineno; + +#define YY_INPUT(buf, result, max_size) \ + result = string_input(buf, max_size, yyscanner); + +static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); +static int check_type(yyscan_t yyscanner); +static int reserved_word(yyscan_t yyscanner); +static int ES2_reserved_ES3_keyword(TParseContext *context, int token); +static int ES2_keyword_ES3_reserved(TParseContext *context, int token); +static int ES2_ident_ES3_keyword(TParseContext *context, int token); +static int uint_constant(TParseContext *context); +static int int_constant(yyscan_t yyscanner); +static int float_constant(yyscan_t yyscanner); +static int floatsuffix_check(TParseContext* context); + +#define INITIAL 0 + +#define YY_EXTRA_TYPE TParseContext* + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + yy_size_t yy_n_chars; + yy_size_t yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +yy_size_t yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +int yyget_column (yyscan_t yyscanner ); + +void yyset_column (int column_no ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc (yyscan_t yyscanner ); + + void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + TParseContext* context = yyextra; + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 813 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 812 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + yy_size_t yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +{ return INVARIANT; } + YY_BREAK +case 2: +YY_RULE_SETUP +{ return HIGH_PRECISION; } + YY_BREAK +case 3: +YY_RULE_SETUP +{ return MEDIUM_PRECISION; } + YY_BREAK +case 4: +YY_RULE_SETUP +{ return LOW_PRECISION; } + YY_BREAK +case 5: +YY_RULE_SETUP +{ return PRECISION; } + YY_BREAK +case 6: +YY_RULE_SETUP +{ return ES2_keyword_ES3_reserved(context, ATTRIBUTE); } + YY_BREAK +case 7: +YY_RULE_SETUP +{ return CONST_QUAL; } + YY_BREAK +case 8: +YY_RULE_SETUP +{ return UNIFORM; } + YY_BREAK +case 9: +YY_RULE_SETUP +{ return ES2_keyword_ES3_reserved(context, VARYING); } + YY_BREAK +case 10: +YY_RULE_SETUP +{ return BREAK; } + YY_BREAK +case 11: +YY_RULE_SETUP +{ return CONTINUE; } + YY_BREAK +case 12: +YY_RULE_SETUP +{ return DO; } + YY_BREAK +case 13: +YY_RULE_SETUP +{ return FOR; } + YY_BREAK +case 14: +YY_RULE_SETUP +{ return WHILE; } + YY_BREAK +case 15: +YY_RULE_SETUP +{ return IF; } + YY_BREAK +case 16: +YY_RULE_SETUP +{ return ELSE; } + YY_BREAK +case 17: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SWITCH); } + YY_BREAK +case 18: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, CASE); } + YY_BREAK +case 19: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, DEFAULT); } + YY_BREAK +case 20: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, CENTROID); } + YY_BREAK +case 21: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, FLAT); } + YY_BREAK +case 22: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SMOOTH); } + YY_BREAK +case 23: +YY_RULE_SETUP +{ return IN_QUAL; } + YY_BREAK +case 24: +YY_RULE_SETUP +{ return OUT_QUAL; } + YY_BREAK +case 25: +YY_RULE_SETUP +{ return INOUT_QUAL; } + YY_BREAK +case 26: +YY_RULE_SETUP +{ return FLOAT_TYPE; } + YY_BREAK +case 27: +YY_RULE_SETUP +{ return INT_TYPE; } + YY_BREAK +case 28: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UINT_TYPE); } + YY_BREAK +case 29: +YY_RULE_SETUP +{ return VOID_TYPE; } + YY_BREAK +case 30: +YY_RULE_SETUP +{ return BOOL_TYPE; } + YY_BREAK +case 31: +YY_RULE_SETUP +{ yylval->lex.b = true; return BOOLCONSTANT; } + YY_BREAK +case 32: +YY_RULE_SETUP +{ yylval->lex.b = false; return BOOLCONSTANT; } + YY_BREAK +case 33: +YY_RULE_SETUP +{ return DISCARD; } + YY_BREAK +case 34: +YY_RULE_SETUP +{ return RETURN; } + YY_BREAK +case 35: +YY_RULE_SETUP +{ return MATRIX2; } + YY_BREAK +case 36: +YY_RULE_SETUP +{ return MATRIX3; } + YY_BREAK +case 37: +YY_RULE_SETUP +{ return MATRIX4; } + YY_BREAK +case 38: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2); } + YY_BREAK +case 39: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3); } + YY_BREAK +case 40: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4); } + YY_BREAK +case 41: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2x3); } + YY_BREAK +case 42: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3x2); } + YY_BREAK +case 43: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX2x4); } + YY_BREAK +case 44: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4x2); } + YY_BREAK +case 45: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX3x4); } + YY_BREAK +case 46: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, MATRIX4x3); } + YY_BREAK +case 47: +YY_RULE_SETUP +{ return VEC2; } + YY_BREAK +case 48: +YY_RULE_SETUP +{ return VEC3; } + YY_BREAK +case 49: +YY_RULE_SETUP +{ return VEC4; } + YY_BREAK +case 50: +YY_RULE_SETUP +{ return IVEC2; } + YY_BREAK +case 51: +YY_RULE_SETUP +{ return IVEC3; } + YY_BREAK +case 52: +YY_RULE_SETUP +{ return IVEC4; } + YY_BREAK +case 53: +YY_RULE_SETUP +{ return BVEC2; } + YY_BREAK +case 54: +YY_RULE_SETUP +{ return BVEC3; } + YY_BREAK +case 55: +YY_RULE_SETUP +{ return BVEC4; } + YY_BREAK +case 56: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC2); } + YY_BREAK +case 57: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC3); } + YY_BREAK +case 58: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, UVEC4); } + YY_BREAK +case 59: +YY_RULE_SETUP +{ return SAMPLER2D; } + YY_BREAK +case 60: +YY_RULE_SETUP +{ return SAMPLERCUBE; } + YY_BREAK +case 61: +YY_RULE_SETUP +{ return SAMPLER_EXTERNAL_OES; } + YY_BREAK +case 62: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SAMPLER3D); } + YY_BREAK +case 63: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SAMPLER3DRECT); } + YY_BREAK +case 64: +YY_RULE_SETUP +{ return SAMPLER2DRECT; } + YY_BREAK +case 65: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAY); } + YY_BREAK +case 66: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER2D); } + YY_BREAK +case 67: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER3D); } + YY_BREAK +case 68: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLERCUBE); } + YY_BREAK +case 69: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, ISAMPLER2DARRAY); } + YY_BREAK +case 70: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER2D); } + YY_BREAK +case 71: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER3D); } + YY_BREAK +case 72: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLERCUBE); } + YY_BREAK +case 73: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, USAMPLER2DARRAY); } + YY_BREAK +case 74: +YY_RULE_SETUP +{ return ES2_reserved_ES3_keyword(context, SAMPLER2DSHADOW); } + YY_BREAK +case 75: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLERCUBESHADOW); } + YY_BREAK +case 76: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, SAMPLER2DARRAYSHADOW); } + YY_BREAK +case 77: +YY_RULE_SETUP +{ return STRUCT; } + YY_BREAK +case 78: +YY_RULE_SETUP +{ return ES2_ident_ES3_keyword(context, LAYOUT); } + YY_BREAK +/* Reserved keywords for GLSL ES 3.00 that are not reserved for GLSL ES 1.00 */ +case 79: +case 80: +case 81: +case 82: +case 83: +case 84: +case 85: +case 86: +case 87: +case 88: +case 89: +case 90: +case 91: +case 92: +case 93: +case 94: +case 95: +case 96: +case 97: +case 98: +case 99: +case 100: +case 101: +case 102: +case 103: +case 104: +case 105: +case 106: +case 107: +case 108: +case 109: +case 110: +case 111: +case 112: +case 113: +case 114: +case 115: +case 116: +case 117: +case 118: +case 119: +case 120: +case 121: +case 122: +case 123: +case 124: +case 125: +case 126: +case 127: +case 128: +case 129: +case 130: +case 131: +case 132: +case 133: +case 134: +YY_RULE_SETUP +{ + if (context->shaderVersion < 300) { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + return reserved_word(yyscanner); +} + YY_BREAK +/* Reserved keywords in GLSL ES 1.00 that are not reserved in GLSL ES 3.00 */ +case 135: +YY_RULE_SETUP +{ + if (context->shaderVersion >= 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return reserved_word(yyscanner); +} + YY_BREAK +/* Reserved keywords */ +case 136: +case 137: +case 138: +case 139: +case 140: +case 141: +case 142: +case 143: +case 144: +case 145: +case 146: +case 147: +case 148: +case 149: +case 150: +case 151: +case 152: +case 153: +case 154: +case 155: +case 156: +case 157: +case 158: +case 159: +case 160: +case 161: +case 162: +case 163: +case 164: +case 165: +case 166: +case 167: +case 168: +case 169: +case 170: +case 171: +case 172: +case 173: +case 174: +case 175: +case 176: +YY_RULE_SETUP +{ return reserved_word(yyscanner); } + YY_BREAK +case 177: +YY_RULE_SETUP +{ + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); +} + YY_BREAK +case 178: +YY_RULE_SETUP +{ return int_constant(yyscanner); } + YY_BREAK +case 179: +YY_RULE_SETUP +{ return int_constant(yyscanner); } + YY_BREAK +case 180: +YY_RULE_SETUP +{ return int_constant(yyscanner); } + YY_BREAK +case 181: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 182: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 183: +YY_RULE_SETUP +{ return uint_constant(context); } + YY_BREAK +case 184: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 185: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 186: +YY_RULE_SETUP +{ return float_constant(yyscanner); } + YY_BREAK +case 187: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 188: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 189: +YY_RULE_SETUP +{ return floatsuffix_check(context); } + YY_BREAK +case 190: +YY_RULE_SETUP +{ return ADD_ASSIGN; } + YY_BREAK +case 191: +YY_RULE_SETUP +{ return SUB_ASSIGN; } + YY_BREAK +case 192: +YY_RULE_SETUP +{ return MUL_ASSIGN; } + YY_BREAK +case 193: +YY_RULE_SETUP +{ return DIV_ASSIGN; } + YY_BREAK +case 194: +YY_RULE_SETUP +{ return MOD_ASSIGN; } + YY_BREAK +case 195: +YY_RULE_SETUP +{ return LEFT_ASSIGN; } + YY_BREAK +case 196: +YY_RULE_SETUP +{ return RIGHT_ASSIGN; } + YY_BREAK +case 197: +YY_RULE_SETUP +{ return AND_ASSIGN; } + YY_BREAK +case 198: +YY_RULE_SETUP +{ return XOR_ASSIGN; } + YY_BREAK +case 199: +YY_RULE_SETUP +{ return OR_ASSIGN; } + YY_BREAK +case 200: +YY_RULE_SETUP +{ return INC_OP; } + YY_BREAK +case 201: +YY_RULE_SETUP +{ return DEC_OP; } + YY_BREAK +case 202: +YY_RULE_SETUP +{ return AND_OP; } + YY_BREAK +case 203: +YY_RULE_SETUP +{ return OR_OP; } + YY_BREAK +case 204: +YY_RULE_SETUP +{ return XOR_OP; } + YY_BREAK +case 205: +YY_RULE_SETUP +{ return LE_OP; } + YY_BREAK +case 206: +YY_RULE_SETUP +{ return GE_OP; } + YY_BREAK +case 207: +YY_RULE_SETUP +{ return EQ_OP; } + YY_BREAK +case 208: +YY_RULE_SETUP +{ return NE_OP; } + YY_BREAK +case 209: +YY_RULE_SETUP +{ return LEFT_OP; } + YY_BREAK +case 210: +YY_RULE_SETUP +{ return RIGHT_OP; } + YY_BREAK +case 211: +YY_RULE_SETUP +{ return SEMICOLON; } + YY_BREAK +case 212: +YY_RULE_SETUP +{ return LEFT_BRACE; } + YY_BREAK +case 213: +YY_RULE_SETUP +{ return RIGHT_BRACE; } + YY_BREAK +case 214: +YY_RULE_SETUP +{ return COMMA; } + YY_BREAK +case 215: +YY_RULE_SETUP +{ return COLON; } + YY_BREAK +case 216: +YY_RULE_SETUP +{ return EQUAL; } + YY_BREAK +case 217: +YY_RULE_SETUP +{ return LEFT_PAREN; } + YY_BREAK +case 218: +YY_RULE_SETUP +{ return RIGHT_PAREN; } + YY_BREAK +case 219: +YY_RULE_SETUP +{ return LEFT_BRACKET; } + YY_BREAK +case 220: +YY_RULE_SETUP +{ return RIGHT_BRACKET; } + YY_BREAK +case 221: +YY_RULE_SETUP +{ return DOT; } + YY_BREAK +case 222: +YY_RULE_SETUP +{ return BANG; } + YY_BREAK +case 223: +YY_RULE_SETUP +{ return DASH; } + YY_BREAK +case 224: +YY_RULE_SETUP +{ return TILDE; } + YY_BREAK +case 225: +YY_RULE_SETUP +{ return PLUS; } + YY_BREAK +case 226: +YY_RULE_SETUP +{ return STAR; } + YY_BREAK +case 227: +YY_RULE_SETUP +{ return SLASH; } + YY_BREAK +case 228: +YY_RULE_SETUP +{ return PERCENT; } + YY_BREAK +case 229: +YY_RULE_SETUP +{ return LEFT_ANGLE; } + YY_BREAK +case 230: +YY_RULE_SETUP +{ return RIGHT_ANGLE; } + YY_BREAK +case 231: +YY_RULE_SETUP +{ return VERTICAL_BAR; } + YY_BREAK +case 232: +YY_RULE_SETUP +{ return CARET; } + YY_BREAK +case 233: +YY_RULE_SETUP +{ return AMPERSAND; } + YY_BREAK +case 234: +YY_RULE_SETUP +{ return QUESTION; } + YY_BREAK +case 235: +/* rule 235 can match eol */ +YY_RULE_SETUP +{ } + YY_BREAK +case YY_STATE_EOF(INITIAL): +{ yyterminate(); } + YY_BREAK +case 236: +YY_RULE_SETUP +{ assert(false); return 0; } + YY_BREAK +case 237: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 813 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 813 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 812); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + yy_size_t i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +yy_size_t yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) { + pp::Token token; + yyget_extra(yyscanner)->preprocessor.lex(&token); + yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size(); + if (len < max_size) + memcpy(buf, token.text.c_str(), len); + yyset_column(token.location.file,yyscanner); + yyset_lineno(token.location.line,yyscanner); + + if (len >= max_size) + YY_FATAL_ERROR("Input buffer overflow"); + else if (len > 0) + buf[len++] = ' '; + return len; +} + +int check_type(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + int token = IDENTIFIER; + TSymbol* symbol = yyextra->symbolTable.find(yytext, yyextra->shaderVersion); + if (symbol && symbol->isVariable()) { + TVariable* variable = static_cast<TVariable*>(symbol); + if (variable->isUserType()) { + token = TYPE_NAME; + } + } + yylval->lex.symbol = symbol; + return token; +} + +int reserved_word(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); + yyextra->recover(); + return 0; +} + +int ES2_reserved_ES3_keyword(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_keyword_ES3_reserved(TParseContext *context, int token) +{ + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion >= 300) + { + return reserved_word(yyscanner); + } + + return token; +} + +int ES2_ident_ES3_keyword(TParseContext *context, int token) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + // not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name + if (context->shaderVersion < 300) + { + yylval->lex.string = NewPoolTString(yytext); + return check_type(yyscanner); + } + + return token; +} + +int uint_constant(TParseContext *context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + yyscan_t yyscanner = (yyscan_t) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); + context->recover(); + return 0; + } + + if (!atoi_clamp(yytext, &(yylval->lex.i))) + yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + + return UINTCONSTANT; +} + +int floatsuffix_check(TParseContext* context) +{ + struct yyguts_t* yyg = (struct yyguts_t*) context->scanner; + + if (context->shaderVersion < 300) + { + context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); + context->recover(); + return 0; + } + + if (!atof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext, ""); + + return(FLOATCONSTANT); +} + +void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) { + context->error(*lloc, reason, yyget_text(context->scanner)); + context->recover(); +} + +int int_constant(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + if (!atoi_clamp(yytext, &(yylval->lex.i))) + yyextra->warning(*yylloc, "Integer overflow", yytext, ""); + return INTCONSTANT; +} + +int float_constant(yyscan_t yyscanner) { + struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; + + if (!atof_clamp(yytext, &(yylval->lex.f))) + yyextra->warning(*yylloc, "Float overflow", yytext, ""); + return FLOATCONSTANT; +} + +int glslang_initialize(TParseContext* context) { + yyscan_t scanner = NULL; + if (yylex_init_extra(context,&scanner)) + return 1; + + context->scanner = scanner; + return 0; +} + +int glslang_finalize(TParseContext* context) { + yyscan_t scanner = context->scanner; + if (scanner == NULL) return 0; + + context->scanner = NULL; + yylex_destroy(scanner); + + return 0; +} + +int glslang_scan(size_t count, const char* const string[], const int length[], + TParseContext* context) { + yyrestart(NULL,context->scanner); + yyset_column(0,context->scanner); + yyset_lineno(1,context->scanner); + + // Initialize preprocessor. + if (!context->preprocessor.init(count, string, length)) + return 1; + + // Define extension macros. + const TExtensionBehavior& extBehavior = context->extensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { + context->preprocessor.predefineMacro(iter->first.c_str(), 1); + } + if (context->fragmentPrecisionHigh) + context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1); + + context->preprocessor.setMaxTokenSize(GetGlobalMaxTokenSize(context->shaderSpec)); + + return 0; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp new file mode 100644 index 00000000000..63ec8c7534f --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp @@ -0,0 +1,5263 @@ +/* A Bison parser, made by GNU Bison 2.7.1. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.7.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ + + +// +// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// This file is auto-generated by generate_parser.sh. DO NOT EDIT! + +// Ignore errors in auto-generated code. +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wswitch-enum" +#elif defined(_MSC_VER) +#pragma warning(disable: 4065) +#pragma warning(disable: 4189) +#pragma warning(disable: 4505) +#pragma warning(disable: 4701) +#endif + +#include "compiler/translator/SymbolTable.h" +#include "compiler/translator/ParseContext.h" +#include "GLSLANG/ShaderLang.h" + +#define YYENABLE_NLS 0 + +#define YYLEX_PARAM context->scanner + + + + +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "glslang_tab.h". */ +#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED +# define YY_YY_GLSLANG_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ + + +#define YYLTYPE TSourceLoc +#define YYLTYPE_IS_DECLARED 1 + + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + UINT_TYPE = 268, + BREAK = 269, + CONTINUE = 270, + DO = 271, + ELSE = 272, + FOR = 273, + IF = 274, + DISCARD = 275, + RETURN = 276, + SWITCH = 277, + CASE = 278, + DEFAULT = 279, + BVEC2 = 280, + BVEC3 = 281, + BVEC4 = 282, + IVEC2 = 283, + IVEC3 = 284, + IVEC4 = 285, + VEC2 = 286, + VEC3 = 287, + VEC4 = 288, + UVEC2 = 289, + UVEC3 = 290, + UVEC4 = 291, + MATRIX2 = 292, + MATRIX3 = 293, + MATRIX4 = 294, + IN_QUAL = 295, + OUT_QUAL = 296, + INOUT_QUAL = 297, + UNIFORM = 298, + VARYING = 299, + MATRIX2x3 = 300, + MATRIX3x2 = 301, + MATRIX2x4 = 302, + MATRIX4x2 = 303, + MATRIX3x4 = 304, + MATRIX4x3 = 305, + CENTROID = 306, + FLAT = 307, + SMOOTH = 308, + STRUCT = 309, + VOID_TYPE = 310, + WHILE = 311, + SAMPLER2D = 312, + SAMPLERCUBE = 313, + SAMPLER_EXTERNAL_OES = 314, + SAMPLER2DRECT = 315, + SAMPLER2DARRAY = 316, + ISAMPLER2D = 317, + ISAMPLER3D = 318, + ISAMPLERCUBE = 319, + ISAMPLER2DARRAY = 320, + USAMPLER2D = 321, + USAMPLER3D = 322, + USAMPLERCUBE = 323, + USAMPLER2DARRAY = 324, + SAMPLER3D = 325, + SAMPLER3DRECT = 326, + SAMPLER2DSHADOW = 327, + SAMPLERCUBESHADOW = 328, + SAMPLER2DARRAYSHADOW = 329, + LAYOUT = 330, + IDENTIFIER = 331, + TYPE_NAME = 332, + FLOATCONSTANT = 333, + INTCONSTANT = 334, + UINTCONSTANT = 335, + BOOLCONSTANT = 336, + FIELD_SELECTION = 337, + LEFT_OP = 338, + RIGHT_OP = 339, + INC_OP = 340, + DEC_OP = 341, + LE_OP = 342, + GE_OP = 343, + EQ_OP = 344, + NE_OP = 345, + AND_OP = 346, + OR_OP = 347, + XOR_OP = 348, + MUL_ASSIGN = 349, + DIV_ASSIGN = 350, + ADD_ASSIGN = 351, + MOD_ASSIGN = 352, + LEFT_ASSIGN = 353, + RIGHT_ASSIGN = 354, + AND_ASSIGN = 355, + XOR_ASSIGN = 356, + OR_ASSIGN = 357, + SUB_ASSIGN = 358, + LEFT_PAREN = 359, + RIGHT_PAREN = 360, + LEFT_BRACKET = 361, + RIGHT_BRACKET = 362, + LEFT_BRACE = 363, + RIGHT_BRACE = 364, + DOT = 365, + COMMA = 366, + COLON = 367, + EQUAL = 368, + SEMICOLON = 369, + BANG = 370, + DASH = 371, + TILDE = 372, + PLUS = 373, + STAR = 374, + SLASH = 375, + PERCENT = 376, + LEFT_ANGLE = 377, + RIGHT_ANGLE = 378, + VERTICAL_BAR = 379, + CARET = 380, + AMPERSAND = 381, + QUESTION = 382 + }; +#endif + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + struct { + union { + TString *string; + float f; + int i; + unsigned int u; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TFunction* function; + TParameter param; + TField* field; + TFieldList* fieldList; + }; + } interm; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (TParseContext* context); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + + +extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); +extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason); + +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (YYID(N)) { \ + (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).last_file = YYRHSLOC(Rhs, N).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + } \ + else { \ + (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \ + (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \ + (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \ + } \ + } while (0) + +#define VERTEX_ONLY(S, L) { \ + if (context->shaderType != SH_VERTEX_SHADER) { \ + context->error(L, " supported in vertex shaders only ", S); \ + context->recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (context->shaderType != SH_FRAGMENT_SHADER) { \ + context->error(L, " supported in fragment shaders only ", S); \ + context->recover(); \ + } \ +} + +#define ES2_ONLY(S, L) { \ + if (context->shaderVersion != 100) { \ + context->error(L, " supported in GLSL ES 1.00 only ", S); \ + context->recover(); \ + } \ +} + +#define ES3_ONLY(TOKEN, LINE, REASON) { \ + if (context->shaderVersion != 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ + context->recover(); \ + } \ +} + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if (! defined __GNUC__ || __GNUC__ < 2 \ + || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) +# define __attribute__(Spec) /* empty */ +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(N) (N) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 114 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 2375 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 128 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 91 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 250 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 373 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 382 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 7, 9, 11, 13, 15, 17, + 19, 23, 25, 30, 32, 36, 39, 42, 44, 46, + 48, 52, 55, 58, 61, 63, 66, 70, 73, 75, + 77, 79, 82, 85, 88, 90, 92, 94, 96, 100, + 104, 106, 110, 114, 116, 118, 122, 126, 130, 134, + 136, 140, 144, 146, 148, 150, 152, 156, 158, 162, + 164, 168, 170, 176, 178, 182, 184, 186, 188, 190, + 192, 194, 198, 200, 203, 206, 209, 214, 220, 227, + 237, 240, 243, 245, 247, 250, 254, 258, 261, 267, + 271, 274, 278, 281, 282, 284, 286, 288, 290, 292, + 296, 302, 309, 315, 317, 320, 325, 331, 336, 339, + 341, 344, 346, 348, 350, 352, 354, 357, 359, 362, + 364, 366, 369, 371, 373, 375, 378, 381, 383, 385, + 388, 390, 392, 394, 399, 401, 405, 407, 411, 415, + 417, 422, 424, 426, 428, 430, 432, 434, 436, 438, + 440, 442, 444, 446, 448, 450, 452, 454, 456, 458, + 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, + 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, + 500, 502, 504, 506, 508, 510, 512, 513, 520, 521, + 527, 529, 532, 536, 541, 543, 547, 549, 554, 556, + 558, 560, 562, 564, 566, 568, 570, 572, 575, 576, + 577, 583, 585, 587, 588, 591, 592, 595, 598, 602, + 604, 607, 609, 612, 618, 622, 624, 626, 631, 632, + 639, 640, 649, 650, 658, 660, 662, 664, 665, 668, + 672, 675, 678, 681, 685, 688, 690, 693, 695, 697, + 698 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 215, 0, -1, 76, -1, 77, -1, 76, -1, 130, + -1, 79, -1, 80, -1, 78, -1, 81, -1, 104, + 157, 105, -1, 131, -1, 132, 106, 133, 107, -1, + 134, -1, 132, 110, 129, -1, 132, 85, -1, 132, + 86, -1, 157, -1, 135, -1, 136, -1, 132, 110, + 136, -1, 138, 105, -1, 137, 105, -1, 139, 55, + -1, 139, -1, 139, 155, -1, 138, 111, 155, -1, + 140, 104, -1, 182, -1, 76, -1, 132, -1, 85, + 141, -1, 86, 141, -1, 142, 141, -1, 118, -1, + 116, -1, 115, -1, 141, -1, 143, 119, 141, -1, + 143, 120, 141, -1, 143, -1, 144, 118, 143, -1, + 144, 116, 143, -1, 144, -1, 145, -1, 146, 122, + 145, -1, 146, 123, 145, -1, 146, 87, 145, -1, + 146, 88, 145, -1, 146, -1, 147, 89, 146, -1, + 147, 90, 146, -1, 147, -1, 148, -1, 149, -1, + 150, -1, 151, 91, 150, -1, 151, -1, 152, 93, + 151, -1, 152, -1, 153, 92, 152, -1, 153, -1, + 153, 127, 157, 112, 155, -1, 154, -1, 141, 156, + 155, -1, 113, -1, 94, -1, 95, -1, 96, -1, + 103, -1, 155, -1, 157, 111, 155, -1, 154, -1, + 76, 108, -1, 161, 114, -1, 169, 114, -1, 7, + 177, 181, 114, -1, 174, 159, 186, 109, 114, -1, + 174, 159, 186, 109, 76, 114, -1, 174, 159, 186, + 109, 76, 106, 158, 107, 114, -1, 174, 114, -1, + 162, 105, -1, 164, -1, 163, -1, 164, 166, -1, + 163, 111, 166, -1, 171, 76, 104, -1, 176, 129, + -1, 176, 129, 106, 158, 107, -1, 173, 167, 165, + -1, 167, 165, -1, 173, 167, 168, -1, 167, 168, + -1, -1, 40, -1, 41, -1, 42, -1, 176, -1, + 170, -1, 169, 111, 129, -1, 169, 111, 129, 106, + 107, -1, 169, 111, 129, 106, 158, 107, -1, 169, + 111, 129, 113, 190, -1, 171, -1, 171, 129, -1, + 171, 129, 106, 107, -1, 171, 129, 106, 158, 107, + -1, 171, 129, 113, 190, -1, 3, 76, -1, 176, + -1, 174, 176, -1, 53, -1, 52, -1, 9, -1, + 8, -1, 44, -1, 3, 44, -1, 175, -1, 172, + 175, -1, 172, -1, 178, -1, 178, 175, -1, 9, + -1, 40, -1, 41, -1, 51, 40, -1, 51, 41, + -1, 43, -1, 181, -1, 177, 181, -1, 4, -1, + 5, -1, 6, -1, 75, 104, 179, 105, -1, 180, + -1, 179, 111, 180, -1, 76, -1, 76, 113, 79, + -1, 76, 113, 80, -1, 182, -1, 182, 106, 158, + 107, -1, 55, -1, 11, -1, 12, -1, 13, -1, + 10, -1, 31, -1, 32, -1, 33, -1, 25, -1, + 26, -1, 27, -1, 28, -1, 29, -1, 30, -1, + 34, -1, 35, -1, 36, -1, 37, -1, 38, -1, + 39, -1, 45, -1, 46, -1, 47, -1, 48, -1, + 49, -1, 50, -1, 57, -1, 70, -1, 58, -1, + 61, -1, 62, -1, 63, -1, 64, -1, 65, -1, + 66, -1, 67, -1, 68, -1, 69, -1, 72, -1, + 73, -1, 74, -1, 59, -1, 60, -1, 183, -1, + 77, -1, -1, 54, 129, 108, 184, 186, 109, -1, + -1, 54, 108, 185, 186, 109, -1, 187, -1, 186, + 187, -1, 176, 188, 114, -1, 174, 176, 188, 114, + -1, 189, -1, 188, 111, 189, -1, 129, -1, 129, + 106, 158, 107, -1, 155, -1, 160, -1, 194, -1, + 193, -1, 191, -1, 203, -1, 204, -1, 207, -1, + 214, -1, 108, 109, -1, -1, -1, 108, 195, 202, + 196, 109, -1, 201, -1, 193, -1, -1, 199, 201, + -1, -1, 200, 193, -1, 108, 109, -1, 108, 202, + 109, -1, 192, -1, 202, 192, -1, 114, -1, 157, + 114, -1, 19, 104, 157, 105, 205, -1, 198, 17, + 198, -1, 198, -1, 157, -1, 171, 129, 113, 190, + -1, -1, 56, 104, 208, 206, 105, 197, -1, -1, + 16, 209, 198, 56, 104, 157, 105, 114, -1, -1, + 18, 104, 210, 211, 213, 105, 197, -1, 203, -1, + 191, -1, 206, -1, -1, 212, 114, -1, 212, 114, + 157, -1, 15, 114, -1, 14, 114, -1, 21, 114, + -1, 21, 157, 114, -1, 20, 114, -1, 216, -1, + 215, 216, -1, 217, -1, 160, -1, -1, 161, 218, + 201, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 205, 205, 206, 209, 264, 267, 272, 277, 282, + 287, 293, 296, 299, 302, 305, 315, 328, 336, 436, + 439, 447, 450, 456, 460, 467, 473, 482, 490, 493, + 503, 506, 516, 526, 547, 548, 549, 554, 555, 563, + 574, 575, 583, 594, 598, 599, 609, 619, 629, 642, + 643, 653, 666, 670, 674, 678, 679, 692, 693, 706, + 707, 720, 721, 738, 739, 752, 753, 754, 755, 756, + 760, 763, 774, 782, 790, 817, 822, 833, 837, 841, + 845, 852, 907, 910, 917, 925, 946, 967, 977, 1005, + 1010, 1020, 1025, 1035, 1038, 1041, 1044, 1050, 1057, 1060, + 1064, 1068, 1072, 1079, 1083, 1087, 1094, 1098, 1102, 1123, + 1132, 1138, 1141, 1147, 1153, 1160, 1169, 1178, 1186, 1189, + 1196, 1200, 1207, 1210, 1214, 1218, 1227, 1236, 1244, 1254, + 1266, 1269, 1272, 1278, 1285, 1288, 1294, 1297, 1300, 1306, + 1309, 1324, 1328, 1332, 1336, 1340, 1344, 1349, 1354, 1359, + 1364, 1369, 1374, 1379, 1384, 1389, 1394, 1399, 1404, 1409, + 1414, 1419, 1424, 1429, 1434, 1439, 1444, 1449, 1453, 1457, + 1461, 1465, 1469, 1473, 1477, 1481, 1485, 1489, 1493, 1497, + 1501, 1505, 1509, 1517, 1525, 1529, 1542, 1542, 1545, 1545, + 1551, 1554, 1570, 1573, 1582, 1586, 1592, 1599, 1614, 1618, + 1622, 1623, 1629, 1630, 1631, 1632, 1633, 1637, 1638, 1638, + 1638, 1648, 1649, 1653, 1653, 1654, 1654, 1659, 1662, 1672, + 1675, 1681, 1682, 1686, 1694, 1698, 1708, 1713, 1730, 1730, + 1735, 1735, 1742, 1742, 1750, 1753, 1759, 1762, 1768, 1772, + 1779, 1786, 1793, 1800, 1811, 1820, 1824, 1831, 1834, 1840, + 1840 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION", + "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE", + "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "UINT_TYPE", + "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", + "SWITCH", "CASE", "DEFAULT", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", + "IVEC4", "VEC2", "VEC3", "VEC4", "UVEC2", "UVEC3", "UVEC4", "MATRIX2", + "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM", + "VARYING", "MATRIX2x3", "MATRIX3x2", "MATRIX2x4", "MATRIX4x2", + "MATRIX3x4", "MATRIX4x3", "CENTROID", "FLAT", "SMOOTH", "STRUCT", + "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE", "SAMPLER_EXTERNAL_OES", + "SAMPLER2DRECT", "SAMPLER2DARRAY", "ISAMPLER2D", "ISAMPLER3D", + "ISAMPLERCUBE", "ISAMPLER2DARRAY", "USAMPLER2D", "USAMPLER3D", + "USAMPLERCUBE", "USAMPLER2DARRAY", "SAMPLER3D", "SAMPLER3DRECT", + "SAMPLER2DSHADOW", "SAMPLERCUBESHADOW", "SAMPLER2DARRAYSHADOW", "LAYOUT", + "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", "INTCONSTANT", + "UINTCONSTANT", "BOOLCONSTANT", "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP", + "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", + "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", + "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", + "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET", + "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON", + "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH", + "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET", + "AMPERSAND", "QUESTION", "$accept", "identifier", "variable_identifier", + "primary_expression", "postfix_expression", "integer_expression", + "function_call", "function_call_or_method", "function_call_generic", + "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "enter_struct", "declaration", + "function_prototype", "function_declarator", + "function_header_with_parameters", "function_header", + "parameter_declarator", "parameter_declaration", "parameter_qualifier", + "parameter_type_specifier", "init_declarator_list", "single_declaration", + "fully_specified_type", "interpolation_qualifier", + "parameter_type_qualifier", "type_qualifier", "storage_qualifier", + "type_specifier", "precision_qualifier", "layout_qualifier", + "layout_qualifier_id_list", "layout_qualifier_id", + "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier", + "$@1", "$@2", "struct_declaration_list", "struct_declaration", + "struct_declarator_list", "struct_declarator", "initializer", + "declaration_statement", "statement", "simple_statement", + "compound_statement", "$@3", "$@4", "statement_no_new_scope", + "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope", + "statement_list", "expression_statement", "selection_statement", + "selection_rest_statement", "condition", "iteration_statement", "$@7", + "$@8", "$@9", "for_init_statement", "conditionopt", "for_rest_statement", + "jump_statement", "translation_unit", "external_declaration", + "function_definition", "$@10", YY_NULL +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 128, 129, 129, 130, 131, 131, 131, 131, 131, + 131, 132, 132, 132, 132, 132, 132, 133, 134, 135, + 135, 136, 136, 137, 137, 138, 138, 139, 140, 140, + 141, 141, 141, 141, 142, 142, 142, 143, 143, 143, + 144, 144, 144, 145, 146, 146, 146, 146, 146, 147, + 147, 147, 148, 149, 150, 151, 151, 152, 152, 153, + 153, 154, 154, 155, 155, 156, 156, 156, 156, 156, + 157, 157, 158, 159, 160, 160, 160, 160, 160, 160, + 160, 161, 162, 162, 163, 163, 164, 165, 165, 166, + 166, 166, 166, 167, 167, 167, 167, 168, 169, 169, + 169, 169, 169, 170, 170, 170, 170, 170, 170, 171, + 171, 172, 172, 173, 174, 174, 174, 174, 174, 174, + 174, 174, 175, 175, 175, 175, 175, 175, 176, 176, + 177, 177, 177, 178, 179, 179, 180, 180, 180, 181, + 181, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, + 182, 182, 182, 182, 182, 182, 184, 183, 185, 183, + 186, 186, 187, 187, 188, 188, 189, 189, 190, 191, + 192, 192, 193, 193, 193, 193, 193, 194, 195, 196, + 194, 197, 197, 199, 198, 200, 198, 201, 201, 202, + 202, 203, 203, 204, 205, 205, 206, 206, 208, 207, + 209, 207, 210, 207, 211, 211, 212, 212, 213, 213, + 214, 214, 214, 214, 214, 215, 215, 216, 216, 218, + 217 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 1, 4, 1, 3, 2, 2, 1, 1, 1, + 3, 2, 2, 2, 1, 2, 3, 2, 1, 1, + 1, 2, 2, 2, 1, 1, 1, 1, 3, 3, + 1, 3, 3, 1, 1, 3, 3, 3, 3, 1, + 3, 3, 1, 1, 1, 1, 3, 1, 3, 1, + 3, 1, 5, 1, 3, 1, 1, 1, 1, 1, + 1, 3, 1, 2, 2, 2, 4, 5, 6, 9, + 2, 2, 1, 1, 2, 3, 3, 2, 5, 3, + 2, 3, 2, 0, 1, 1, 1, 1, 1, 3, + 5, 6, 5, 1, 2, 4, 5, 4, 2, 1, + 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, + 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, + 1, 1, 1, 4, 1, 3, 1, 3, 3, 1, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 6, 0, 5, + 1, 2, 3, 4, 1, 3, 1, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, + 5, 1, 1, 0, 2, 0, 2, 2, 3, 1, + 2, 1, 2, 5, 3, 1, 1, 4, 0, 6, + 0, 8, 0, 7, 1, 1, 1, 0, 2, 3, + 2, 2, 2, 3, 2, 1, 2, 1, 1, 0, + 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 130, 131, 132, 0, 114, 122, 145, 142, + 143, 144, 149, 150, 151, 152, 153, 154, 146, 147, + 148, 155, 156, 157, 158, 159, 160, 123, 124, 127, + 115, 161, 162, 163, 164, 165, 166, 0, 112, 111, + 0, 141, 167, 169, 182, 183, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 168, 179, 180, 181, 0, + 185, 248, 249, 0, 83, 93, 0, 98, 103, 119, + 0, 117, 109, 0, 120, 128, 139, 184, 0, 245, + 247, 116, 108, 0, 125, 126, 2, 3, 188, 0, + 0, 74, 0, 81, 93, 113, 94, 95, 96, 84, + 0, 93, 0, 75, 2, 104, 118, 0, 80, 0, + 110, 129, 121, 0, 1, 246, 0, 0, 186, 136, + 0, 134, 0, 250, 85, 90, 92, 97, 0, 99, + 86, 0, 0, 73, 0, 0, 0, 0, 190, 4, + 8, 6, 7, 9, 0, 0, 0, 36, 35, 34, + 5, 11, 30, 13, 18, 19, 0, 0, 24, 0, + 37, 0, 40, 43, 44, 49, 52, 53, 54, 55, + 57, 59, 61, 72, 0, 28, 76, 0, 0, 0, + 133, 0, 0, 0, 230, 0, 0, 0, 0, 0, + 208, 217, 221, 37, 63, 70, 0, 199, 0, 139, + 202, 219, 201, 200, 0, 203, 204, 205, 206, 87, + 89, 91, 0, 0, 105, 0, 198, 107, 0, 196, + 0, 194, 0, 191, 31, 32, 0, 15, 16, 0, + 0, 22, 21, 0, 23, 25, 27, 33, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 140, 189, 0, 137, 138, 135, 241, 240, + 215, 232, 0, 244, 242, 0, 228, 207, 0, 66, + 67, 68, 69, 65, 0, 0, 222, 218, 220, 0, + 100, 0, 102, 106, 0, 0, 0, 192, 0, 77, + 10, 0, 17, 2, 3, 14, 20, 26, 38, 39, + 42, 41, 47, 48, 45, 46, 50, 51, 56, 58, + 60, 0, 187, 0, 0, 0, 0, 0, 243, 0, + 209, 64, 71, 0, 101, 193, 0, 195, 0, 78, + 12, 0, 0, 214, 216, 235, 234, 237, 215, 226, + 0, 0, 0, 0, 88, 197, 0, 62, 0, 236, + 0, 0, 225, 223, 0, 0, 210, 0, 0, 238, + 0, 215, 0, 212, 229, 211, 79, 0, 239, 233, + 224, 227, 231 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 219, 150, 151, 152, 291, 153, 154, 155, 156, + 157, 158, 159, 193, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 194, 195, 274, 196, + 174, 109, 197, 198, 63, 64, 65, 125, 99, 100, + 126, 66, 67, 68, 69, 101, 70, 71, 72, 73, + 74, 120, 121, 75, 175, 77, 178, 117, 137, 138, + 220, 221, 217, 200, 201, 202, 203, 268, 343, 364, + 313, 314, 315, 365, 204, 205, 206, 353, 342, 207, + 319, 260, 316, 337, 350, 351, 208, 78, 79, 80, + 92 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -309 +static const yytype_int16 yypact[] = +{ + 2013, -27, -309, -309, -309, 154, -309, -309, -309, -309, + -309, -309, -309, -309, -309, -309, -309, -309, -309, -309, + -309, -309, -309, -309, -309, -309, -309, -309, -309, -309, + -309, -309, -309, -309, -309, -309, -309, 98, -309, -309, + -40, -309, -309, -309, -309, -309, -309, -309, -309, -309, + -309, -309, -309, -309, -309, -309, -309, -309, -309, -46, + -309, -309, -42, -23, 8, 5, -87, -309, 91, 14, + 1130, -309, -309, 2298, 14, -309, -1, -309, 1938, -309, + -309, -309, -309, 2298, -309, -309, -309, -309, -309, 13, + 47, -309, 43, -309, 39, -309, -309, -309, -309, -309, + 2162, 124, 94, -309, 51, -14, -309, 66, -309, 2088, + -309, -309, -309, 1491, -309, -309, 62, 2088, -309, 48, + -83, -309, 358, -309, -309, -309, -309, 94, 2162, -9, + -309, 1200, 1491, -309, 148, 2162, 94, 1683, -309, 89, + -309, -309, -309, -309, 1491, 1491, 1491, -309, -309, -309, + -309, -309, 10, -309, -309, -309, 92, 20, 1586, 96, + -309, 1491, 53, -76, -309, -62, 90, -309, -309, -309, + 104, 101, -61, -309, 95, -309, -309, 1768, 2088, 103, + -309, 47, 82, 84, -309, 97, 99, 93, 1298, 105, + 102, -309, -309, -10, -309, -309, -13, -309, -42, 2, + -309, -309, -309, -309, 474, -309, -309, -309, -309, 106, + -309, -309, 1393, 1491, -309, 107, -309, -309, 94, 109, + 4, -309, -58, -309, -309, -309, 22, -309, -309, 1491, + 2230, -309, -309, 1491, 112, -309, -309, -309, 1491, 1491, + 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1491, + 1491, 1491, -309, -309, 1853, -309, -309, -309, -309, -309, + 100, -309, 1491, -309, -309, 36, -309, -309, 590, -309, + -309, -309, -309, -309, 1491, 1491, -309, -309, -309, 1491, + -309, 113, -309, -309, 42, 1491, 94, -309, -73, -309, + -309, 115, 108, 89, 119, -309, -309, -309, -309, -309, + 53, 53, -309, -309, -309, -309, -62, -62, -309, 104, + 101, 73, -309, 169, 43, 822, 938, 25, -309, 1035, + 590, -309, -309, 120, -309, -309, 121, -309, 1491, -309, + -309, 1491, 122, -309, -309, -309, -309, 1035, 100, 108, + 94, 2162, 125, 123, -309, -309, 126, -309, 1491, -309, + 117, 129, 212, -309, 139, 706, -309, 141, 29, 1491, + 706, 100, 1491, -309, -309, -309, -309, 142, 108, -309, + -309, -309, -309 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -309, -39, -309, -309, -309, -309, -309, -309, 7, -309, + -309, -309, -309, 1, -309, -54, -309, -101, -57, -309, + -309, -309, 9, -11, 3, -309, -110, -126, -309, -138, + -122, -309, 11, 16, -309, -309, -309, 130, 165, 159, + 133, -309, -309, -299, -309, -309, -102, -30, -66, 257, + -309, -309, 83, -6, 0, -309, -309, -309, -104, -125, + 45, -21, -208, -50, -194, -296, -309, -309, -309, -93, + -308, -309, -309, -90, 6, -47, -309, -309, -67, -309, + -309, -309, -309, -309, -309, -309, -309, -309, 193, -309, + -309 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -214 +static const yytype_int16 yytable[] = +{ + 76, 89, 123, 173, 110, 282, 216, 135, 226, 215, + 278, 61, 223, 177, 95, 135, 62, 81, 288, 334, + 340, 173, 180, 7, 102, 242, 243, 103, 181, 105, + 352, 250, 235, 328, 127, 135, 86, 87, 340, 106, + 240, 329, 241, 136, 112, 96, 97, 98, 95, 82, + 265, 136, 223, 370, 27, 28, 289, 29, 90, 363, + 244, 245, 127, 129, 363, 37, 251, 111, 88, 218, + 76, 136, 91, 76, 254, 135, 135, 116, 76, 96, + 97, 98, 93, 76, 269, 270, 271, 216, 209, 61, + 281, 292, 131, 272, 62, 227, 228, 212, 275, 132, + 76, 276, 173, 273, 213, 113, -28, 297, 113, 76, + -82, 136, 136, 311, 160, 286, 229, 76, 287, 94, + 230, 118, 199, 119, 317, 232, 278, 290, 76, 223, + 338, 233, 160, 275, 367, 76, 275, 76, 84, 85, + 275, 302, 303, 304, 305, 224, 225, 275, 321, 322, + 318, 122, 135, 286, 371, 130, 325, 323, 2, 3, + 4, 179, 237, 326, 96, 97, 98, 104, 87, 173, + 86, 87, 238, 239, 133, 173, 176, 76, 76, 246, + 247, 339, 255, 256, 275, 331, 300, 301, 136, 306, + 307, 295, 81, -29, 249, 248, 258, 231, 259, 339, + 236, 261, 252, 262, 199, 347, 346, 263, -213, 266, + 358, 267, 279, 160, 283, 285, -141, 341, 173, 275, + 324, 368, 330, -185, 333, 332, 348, 344, 345, 361, + 355, 359, 356, 357, 360, 341, 216, 296, 309, 298, + 299, 160, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 362, 310, 76, 366, 372, 308, 210, 124, + 128, 211, 83, 284, 257, 327, 335, 369, 199, 336, + 349, 115, 0, 0, 320, 110, 0, 0, 0, 0, + 160, 0, 0, 0, 0, 0, 160, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 354, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 199, 0, 0, 199, + 199, 0, 0, 0, 0, 0, 0, 0, 0, 160, + 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, + 0, 76, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, + 199, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 182, 183, 184, 0, 185, 186, 187, 188, + 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 189, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 59, 139, 60, 140, 141, 142, 143, + 0, 0, 0, 144, 145, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 146, 0, 0, 0, 190, 191, 0, 0, + 0, 0, 192, 147, 148, 0, 149, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 182, 183, + 184, 0, 185, 186, 187, 188, 0, 0, 0, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 0, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 189, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 0, 56, 57, 58, 59, + 139, 60, 140, 141, 142, 143, 0, 0, 0, 144, + 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 146, 0, + 0, 0, 190, 277, 0, 0, 0, 0, 192, 147, + 148, 0, 149, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 182, 183, 184, 0, 185, 186, + 187, 188, 0, 0, 0, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 0, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 189, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 0, 56, 57, 58, 59, 139, 60, 140, 141, + 142, 143, 0, 0, 0, 144, 145, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 146, 0, 0, 0, 190, 0, + 0, 0, 0, 0, 192, 147, 148, 0, 149, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 182, 183, 184, 0, 185, 186, 187, 188, 0, 0, + 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 0, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 189, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 0, 56, 57, + 58, 59, 139, 60, 140, 141, 142, 143, 0, 0, + 0, 144, 145, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 146, 0, 0, 0, 122, 0, 0, 0, 0, 0, + 192, 147, 148, 0, 149, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 182, 183, 184, 0, + 185, 186, 187, 188, 0, 0, 0, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 0, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 189, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 0, 56, 57, 58, 59, 139, 60, + 140, 141, 142, 143, 0, 0, 0, 144, 145, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 192, 147, 148, 0, + 149, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 59, 139, 60, 140, 141, 142, 143, + 0, 0, 0, 144, 145, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 134, 2, + 3, 4, 146, 6, 7, 8, 9, 10, 11, 0, + 0, 0, 192, 147, 148, 0, 149, 0, 0, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 0, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 0, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 0, 56, 57, 58, + 59, 139, 60, 140, 141, 142, 143, 0, 0, 0, + 144, 145, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 3, 4, 0, 0, 146, + 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, + 147, 148, 0, 149, 0, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 0, 0, 0, 0, 0, 31, 32, 33, 34, 35, + 36, 0, 0, 0, 40, 41, 0, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 0, 56, 57, 58, 0, 107, 60, 0, 0, + 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 0, 0, 0, 0, 108, 31, 32, 33, 34, 35, + 36, 0, 0, 0, 40, 41, 0, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 0, 56, 57, 58, 0, 139, 60, 140, 141, + 142, 143, 0, 0, 0, 144, 145, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 146, 0, 0, 214, 8, 9, + 10, 11, 0, 0, 0, 147, 148, 0, 149, 0, + 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, + 0, 0, 0, 31, 32, 33, 34, 35, 36, 0, + 0, 0, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 0, 139, 60, 140, 141, 142, 143, + 0, 0, 0, 144, 145, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 146, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 264, 147, 148, 0, 149, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 0, 0, 0, 0, 0, 31, 32, + 33, 34, 35, 36, 0, 0, 0, 40, 41, 0, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 0, 56, 57, 58, 0, 139, + 60, 140, 141, 142, 143, 0, 0, 0, 144, 145, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 146, 0, 0, + 280, 8, 9, 10, 11, 0, 0, 0, 147, 148, + 0, 149, 0, 0, 0, 0, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 0, 0, 0, 0, 0, 31, 32, 33, 34, + 35, 36, 0, 0, 0, 40, 41, 0, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 0, 56, 57, 58, 0, 139, 60, 140, + 141, 142, 143, 0, 0, 0, 144, 145, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 146, 8, 9, 10, 11, + 0, 0, 0, 0, 0, 0, 147, 148, 0, 149, + 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, + 0, 31, 32, 33, 34, 35, 36, 0, 0, 0, + 40, 234, 0, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 0, 56, 57, + 58, 0, 139, 60, 140, 141, 142, 143, 0, 0, + 0, 144, 145, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 2, 3, 4, + 146, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 147, 148, 0, 149, 0, 0, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 0, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 0, 56, 57, 58, 59, 0, + 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 134, 2, 3, 4, 0, 6, 7, 8, 9, + 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 222, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 59, 0, 60, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 2, 3, 4, + 0, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 253, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 0, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 0, 56, 57, 58, 59, 0, + 60, 0, 0, 0, 0, 0, 0, 0, 114, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 312, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 59, 0, 60, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 0, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 0, 56, 57, 58, 59, 0, + 60, 134, 2, 3, 4, 0, 6, 7, 8, 9, + 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 59, 0, 60, 2, 3, 4, 0, + 0, 0, 8, 9, 10, 11, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 0, 0, 0, 0, 0, 31, 32, 33, + 34, 35, 36, 0, 0, 0, 40, 41, 0, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 0, 56, 57, 58, 0, 0, 60, + 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 0, 0, 0, 0, 0, 31, 32, 33, 34, 35, + 36, 0, 0, 0, 40, 41, 0, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 0, 56, 57, 58, 0, 293, 294, 8, 9, + 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, + 0, 0, 0, 31, 32, 33, 34, 35, 36, 0, + 0, 0, 40, 41, 0, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, + 56, 57, 58, 0, 0, 60 +}; + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-309))) + +#define yytable_value_is_error(Yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 0, 40, 92, 113, 70, 213, 132, 109, 146, 131, + 204, 0, 137, 117, 9, 117, 0, 44, 76, 315, + 319, 131, 105, 9, 111, 87, 88, 114, 111, 68, + 338, 92, 158, 106, 100, 137, 76, 77, 337, 69, + 116, 114, 118, 109, 74, 40, 41, 42, 9, 76, + 188, 117, 177, 361, 40, 41, 114, 43, 104, 355, + 122, 123, 128, 102, 360, 51, 127, 73, 108, 135, + 70, 137, 114, 73, 178, 177, 178, 83, 78, 40, + 41, 42, 105, 83, 94, 95, 96, 213, 127, 78, + 212, 229, 106, 103, 78, 85, 86, 106, 111, 113, + 100, 114, 212, 113, 113, 106, 104, 233, 106, 109, + 105, 177, 178, 251, 113, 111, 106, 117, 114, 111, + 110, 108, 122, 76, 262, 105, 320, 105, 128, 254, + 105, 111, 131, 111, 105, 135, 111, 137, 40, 41, + 111, 242, 243, 244, 245, 144, 145, 111, 274, 275, + 114, 108, 254, 111, 362, 104, 114, 279, 4, 5, + 6, 113, 161, 285, 40, 41, 42, 76, 77, 279, + 76, 77, 119, 120, 108, 285, 114, 177, 178, 89, + 90, 319, 79, 80, 111, 112, 240, 241, 254, 246, + 247, 230, 44, 104, 93, 91, 114, 105, 114, 337, + 104, 104, 107, 104, 204, 331, 328, 114, 108, 104, + 348, 109, 106, 212, 107, 106, 104, 319, 328, 111, + 107, 359, 107, 104, 314, 56, 104, 107, 107, 17, + 105, 114, 109, 107, 105, 337, 362, 230, 249, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 113, 250, 254, 114, 114, 248, 128, 94, + 101, 128, 5, 218, 181, 286, 316, 360, 268, 316, + 337, 78, -1, -1, 268, 341, -1, -1, -1, -1, + 279, -1, -1, -1, -1, -1, 285, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 340, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 315, 316, -1, -1, 319, + 320, -1, -1, -1, -1, -1, -1, -1, -1, 328, + -1, -1, -1, -1, -1, -1, -1, 337, -1, -1, + -1, 341, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 355, -1, -1, -1, -1, + 360, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, + -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + -1, -1, -1, 85, 86, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 104, -1, -1, -1, 108, 109, -1, -1, + -1, -1, 114, 115, 116, -1, 118, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, -1, 18, 19, 20, 21, -1, -1, -1, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, -1, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, -1, -1, -1, 85, + 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, + -1, -1, 108, 109, -1, -1, -1, -1, 114, 115, + 116, -1, 118, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, + 20, 21, -1, -1, -1, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, -1, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, -1, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, -1, -1, -1, 85, 86, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 104, -1, -1, -1, 108, -1, + -1, -1, -1, -1, 114, 115, 116, -1, 118, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, -1, 18, 19, 20, 21, -1, -1, + -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, -1, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, -1, -1, + -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 104, -1, -1, -1, 108, -1, -1, -1, -1, -1, + 114, 115, 116, -1, 118, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, + 18, 19, 20, 21, -1, -1, -1, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, -1, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, -1, -1, -1, 85, 86, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 114, 115, 116, -1, + 118, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + -1, -1, -1, 85, 86, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, + 5, 6, 104, 8, 9, 10, 11, 12, 13, -1, + -1, -1, 114, 115, 116, -1, 118, -1, -1, -1, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, -1, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, -1, -1, -1, + 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, 5, 6, -1, -1, 104, + 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, + 115, 116, -1, 118, -1, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + -1, -1, -1, -1, -1, 45, 46, 47, 48, 49, + 50, -1, -1, -1, 54, 55, -1, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, -1, 72, 73, 74, -1, 76, 77, -1, -1, + 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + -1, -1, -1, -1, 114, 45, 46, 47, 48, 49, + 50, -1, -1, -1, 54, 55, -1, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, -1, 72, 73, 74, -1, 76, 77, 78, 79, + 80, 81, -1, -1, -1, 85, 86, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 104, -1, -1, 107, 10, 11, + 12, 13, -1, -1, -1, 115, 116, -1, 118, -1, + -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, + -1, -1, -1, 45, 46, 47, 48, 49, 50, -1, + -1, -1, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, -1, 76, 77, 78, 79, 80, 81, + -1, -1, -1, 85, 86, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 104, 10, 11, 12, 13, -1, -1, -1, + -1, -1, 114, 115, 116, -1, 118, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, -1, -1, -1, -1, -1, 45, 46, + 47, 48, 49, 50, -1, -1, -1, 54, 55, -1, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, -1, 72, 73, 74, -1, 76, + 77, 78, 79, 80, 81, -1, -1, -1, 85, 86, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, + 107, 10, 11, 12, 13, -1, -1, -1, 115, 116, + -1, 118, -1, -1, -1, -1, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, -1, -1, -1, -1, -1, 45, 46, 47, 48, + 49, 50, -1, -1, -1, 54, 55, -1, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, -1, 72, 73, 74, -1, 76, 77, 78, + 79, 80, 81, -1, -1, -1, 85, 86, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 104, 10, 11, 12, 13, + -1, -1, -1, -1, -1, -1, 115, 116, -1, 118, + -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, -1, -1, -1, -1, + -1, 45, 46, 47, 48, 49, 50, -1, -1, -1, + 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, + 74, -1, 76, 77, 78, 79, 80, 81, -1, -1, + -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + 104, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, 115, 116, -1, 118, -1, -1, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, -1, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, -1, 72, 73, 74, 75, -1, + 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3, 4, 5, 6, -1, 8, 9, 10, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 109, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, -1, 77, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + -1, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 109, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, -1, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, -1, 72, 73, 74, 75, -1, + 77, -1, -1, -1, -1, -1, -1, -1, 0, -1, + -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 109, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, -1, 77, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, -1, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, -1, 72, 73, 74, 75, -1, + 77, 3, 4, 5, 6, -1, 8, 9, 10, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, -1, 77, 4, 5, 6, -1, + -1, -1, 10, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, -1, -1, -1, -1, -1, 45, 46, 47, + 48, 49, 50, -1, -1, -1, 54, 55, -1, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, -1, 72, 73, 74, -1, -1, 77, + 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + -1, -1, -1, -1, -1, 45, 46, 47, 48, 49, + 50, -1, -1, -1, 54, 55, -1, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, -1, 72, 73, 74, -1, 76, 77, 10, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, + -1, -1, -1, 45, 46, 47, 48, 49, 50, -1, + -1, -1, 54, 55, -1, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, -1, -1, 77 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, + 77, 160, 161, 162, 163, 164, 169, 170, 171, 172, + 174, 175, 176, 177, 178, 181, 182, 183, 215, 216, + 217, 44, 76, 177, 40, 41, 76, 77, 108, 129, + 104, 114, 218, 105, 111, 9, 40, 41, 42, 166, + 167, 173, 111, 114, 76, 129, 175, 76, 114, 159, + 176, 181, 175, 106, 0, 216, 181, 185, 108, 76, + 179, 180, 108, 201, 166, 165, 168, 176, 167, 129, + 104, 106, 113, 108, 3, 174, 176, 186, 187, 76, + 78, 79, 80, 81, 85, 86, 104, 115, 116, 118, + 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 158, 182, 114, 186, 184, 113, + 105, 111, 14, 15, 16, 18, 19, 20, 21, 56, + 108, 109, 114, 141, 154, 155, 157, 160, 161, 182, + 191, 192, 193, 194, 202, 203, 204, 207, 214, 129, + 165, 168, 106, 113, 107, 158, 155, 190, 176, 129, + 188, 189, 109, 187, 141, 141, 157, 85, 86, 106, + 110, 105, 105, 111, 55, 155, 104, 141, 119, 120, + 116, 118, 87, 88, 122, 123, 89, 90, 91, 93, + 92, 127, 107, 109, 186, 79, 80, 180, 114, 114, + 209, 104, 104, 114, 114, 157, 104, 109, 195, 94, + 95, 96, 103, 113, 156, 111, 114, 109, 192, 106, + 107, 158, 190, 107, 188, 106, 111, 114, 76, 114, + 105, 133, 157, 76, 77, 129, 136, 155, 141, 141, + 143, 143, 145, 145, 145, 145, 146, 146, 150, 151, + 152, 157, 109, 198, 199, 200, 210, 157, 114, 208, + 202, 155, 155, 158, 107, 114, 158, 189, 106, 114, + 107, 112, 56, 201, 193, 191, 203, 211, 105, 157, + 171, 174, 206, 196, 107, 107, 158, 155, 104, 206, + 212, 213, 198, 205, 129, 105, 109, 107, 157, 114, + 105, 17, 113, 193, 197, 201, 114, 105, 157, 197, + 198, 190, 114 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +__attribute__((__unused__)) +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static unsigned +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +#else +static unsigned +yy_location_print_ (yyo, yylocp) + FILE *yyo; + YYLTYPE const * const yylocp; +#endif +{ + unsigned res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += fprintf (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += fprintf (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += fprintf (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += fprintf (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += fprintf (yyo, "-%d", end_col); + } + return res; + } + +# define YY_LOCATION_PRINT(File, Loc) \ + yy_location_print_ (File, &(Loc)) + +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + TParseContext* context; +#endif +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (context); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + TParseContext* context; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, TParseContext* context) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, context) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + TParseContext* context; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, context); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULL; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, TParseContext* context) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, context) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + TParseContext* context; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (context); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YYUSE (yytype); +} + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (TParseContext* context) +#else +int +yyparse (context) + TParseContext* context; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +static YYSTYPE yyval_default; +# define YY_INITIAL_VALUE(Value) = Value +#endif +static YYLTYPE yyloc_default +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc = yyloc_default; + + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yylsp = yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + yylsp[0] = yylloc; + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: + + { + // The symbol table search was done in the lexical phase + const TSymbol *symbol = (yyvsp[(1) - (1)].lex).symbol; + const TVariable *variable = 0; + + if (!symbol) + { + context->error((yylsp[(1) - (1)]), "undeclared identifier", (yyvsp[(1) - (1)].lex).string->c_str()); + context->recover(); + } + else if (!symbol->isVariable()) + { + context->error((yylsp[(1) - (1)]), "variable expected", (yyvsp[(1) - (1)].lex).string->c_str()); + context->recover(); + } + else + { + variable = static_cast<const TVariable*>(symbol); + + if (context->symbolTable.findBuiltIn(variable->getName(), context->shaderVersion) && + !variable->getExtension().empty() && + context->extensionErrorCheck((yylsp[(1) - (1)]), variable->getExtension())) + { + context->recover(); + } + } + + if (!variable) + { + TType type(EbtFloat, EbpUndefined); + TVariable *fakeVariable = new TVariable((yyvsp[(1) - (1)].lex).string, type); + context->symbolTable.declare(*fakeVariable); + variable = fakeVariable; + } + + if (variable->getType().getQualifier() == EvqConst) + { + ConstantUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[(1) - (1)])); + } + else + { + (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), + (yylsp[(1) - (1)])); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + } + break; + + case 5: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 6: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setIConst((yyvsp[(1) - (1)].lex).i); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[(1) - (1)])); + } + break; + + case 7: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setUConst((yyvsp[(1) - (1)].lex).u); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtUInt, EbpUndefined, EvqConst), (yylsp[(1) - (1)])); + } + break; + + case 8: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst((yyvsp[(1) - (1)].lex).f); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)])); + } + break; + + case 9: + + { + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst((yyvsp[(1) - (1)].lex).b); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(1) - (1)])); + } + break; + + case 10: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode); + } + break; + + case 11: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 12: + + { + (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[(1) - (4)].interm.intermTypedNode), (yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode)); + } + break; + + case 13: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 14: + + { + (yyval.interm.intermTypedNode) = context->addFieldSelectionExpression((yyvsp[(1) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yylsp[(3) - (3)])); + } + break; + + case 15: + + { + if (context->lValueErrorCheck((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode); + } + } + break; + + case 16: + + { + if (context->lValueErrorCheck((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode); + } + } + break; + + case 17: + + { + if (context->integerErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]")) + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 18: + + { + TFunction* fnCall = (yyvsp[(1) - (1)].interm).function; + TOperator op = fnCall->getBuiltInOp(); + + if (op != EOpNull) + { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid, EbpUndefined); // use this to get the type back + if (context->constructorErrorCheck((yylsp[(1) - (1)]), (yyvsp[(1) - (1)].interm).intermNode, *fnCall, op, &type)) { + (yyval.interm.intermTypedNode) = 0; + } else { + // + // It's a constructor, of type 'type'. + // + (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[(1) - (1)].interm).intermNode, &type, op, fnCall, (yylsp[(1) - (1)])); + } + + if ((yyval.interm.intermTypedNode) == 0) { + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yylsp[(1) - (1)])); + } + (yyval.interm.intermTypedNode)->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = context->findFunction((yylsp[(1) - (1)]), fnCall, context->shaderVersion, &builtIn); + if (fnCandidate) { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + context->extensionErrorCheck((yylsp[(1) - (1)]), fnCandidate->getExtension())) { + context->recover(); + } + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[(1) - (1)].interm).intermNode, (yylsp[(1) - (1)])); + if ((yyval.interm.intermTypedNode) == 0) { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>((yyvsp[(1) - (1)].interm).intermNode)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + YYERROR; + } + } else { + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, op, (yylsp[(1) - (1)])); + } + } else { + // This is a real function call + + (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, EOpFunctionCall, (yylsp[(1) - (1)])); + (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + (yyval.interm.intermTypedNode)->getAsAggregate()->setUserDefined(); + (yyval.interm.intermTypedNode)->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()[i]->getAsTyped())) { + context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + context->recover(); + } + } + } + } + (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)])); + context->recover(); + } + } + delete fnCall; + } + break; + + case 19: + + { + (yyval.interm) = (yyvsp[(1) - (1)].interm); + } + break; + + case 20: + + { + context->error((yylsp[(3) - (3)]), "methods are not supported", ""); + context->recover(); + (yyval.interm) = (yyvsp[(3) - (3)].interm); + } + break; + + case 21: + + { + (yyval.interm) = (yyvsp[(1) - (2)].interm); + } + break; + + case 22: + + { + (yyval.interm) = (yyvsp[(1) - (2)].interm); + } + break; + + case 23: + + { + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + (yyval.interm).intermNode = 0; + } + break; + + case 24: + + { + (yyval.interm).function = (yyvsp[(1) - (1)].interm.function); + (yyval.interm).intermNode = 0; + } + break; + + case 25: + + { + TParameter param = { 0, new TType((yyvsp[(2) - (2)].interm.intermTypedNode)->getType()) }; + (yyvsp[(1) - (2)].interm.function)->addParameter(param); + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + break; + + case 26: + + { + TParameter param = { 0, new TType((yyvsp[(3) - (3)].interm.intermTypedNode)->getType()) }; + (yyvsp[(1) - (3)].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[(1) - (3)].interm).function; + (yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + } + break; + + case 27: + + { + (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function); + } + break; + + case 28: + + { + (yyval.interm.function) = context->addConstructorFunc((yyvsp[(1) - (1)].interm.type)); + } + break; + + case 29: + + { + if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type); + (yyval.interm.function) = function; + } + break; + + case 30: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 31: + + { + if (context->lValueErrorCheck((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } + break; + + case 32: + + { + if (context->lValueErrorCheck((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->unaryOpError((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } + break; + + case 33: + + { + if ((yyvsp[(1) - (2)].interm).op != EOpNull) { + (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath((yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)])); + if ((yyval.interm.intermTypedNode) == 0) { + const char* errorOp = ""; + switch((yyvsp[(1) - (2)].interm).op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + default: break; + } + context->unaryOpError((yylsp[(1) - (2)]), errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + } else + (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode); + } + break; + + case 34: + + { (yyval.interm).op = EOpNull; } + break; + + case 35: + + { (yyval.interm).op = EOpNegative; } + break; + + case 36: + + { (yyval.interm).op = EOpLogicalNot; } + break; + + case 37: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 38: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 39: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 40: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 41: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "+", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 42: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "-", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 43: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 44: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 45: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "<", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 46: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), ">", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 47: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "<=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 48: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), ">=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 49: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 50: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "==", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 51: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "!=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 52: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 53: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 54: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 55: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 56: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "&&", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 57: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 58: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "^^", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 59: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 60: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), "||", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)])); + } + } + break; + + case 61: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 62: + + { + if (context->boolErrorCheck((yylsp[(2) - (5)]), (yyvsp[(1) - (5)].interm.intermTypedNode))) + context->recover(); + + (yyval.interm.intermTypedNode) = context->intermediate.addSelection((yyvsp[(1) - (5)].interm.intermTypedNode), (yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.intermTypedNode), (yylsp[(2) - (5)])); + if ((yyvsp[(3) - (5)].interm.intermTypedNode)->getType() != (yyvsp[(5) - (5)].interm.intermTypedNode)->getType()) + (yyval.interm.intermTypedNode) = 0; + + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (5)]), ":", (yyvsp[(3) - (5)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(5) - (5)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(5) - (5)].interm.intermTypedNode); + } + } + break; + + case 63: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 64: + + { + if (context->lValueErrorCheck((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = context->intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->assignError((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode); + } + } + break; + + case 65: + + { (yyval.interm).op = EOpAssign; } + break; + + case 66: + + { (yyval.interm).op = EOpMulAssign; } + break; + + case 67: + + { (yyval.interm).op = EOpDivAssign; } + break; + + case 68: + + { (yyval.interm).op = EOpAddAssign; } + break; + + case 69: + + { (yyval.interm).op = EOpSubAssign; } + break; + + case 70: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 71: + + { + (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)])); + if ((yyval.interm.intermTypedNode) == 0) { + context->binaryOpError((yylsp[(2) - (3)]), ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString()); + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode); + } + } + break; + + case 72: + + { + if (context->constErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 73: + + { + if (context->enterStructDeclaration((yylsp[(1) - (2)]), *(yyvsp[(1) - (2)].lex).string)) + context->recover(); + (yyval.lex) = (yyvsp[(1) - (2)].lex); + } + break; + + case 74: + + { + TFunction &function = *((yyvsp[(1) - (2)].interm).function); + + TIntermAggregate *prototype = new TIntermAggregate; + prototype->setType(function.getReturnType()); + prototype->setName(function.getName()); + + for (size_t i = 0; i < function.getParamCount(); i++) + { + const TParameter ¶m = function.getParam(i); + if (param.name != 0) + { + TVariable variable(param.name, *param.type); + + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), (yylsp[(1) - (2)])), (yylsp[(1) - (2)])); + } + else + { + prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (2)])), (yylsp[(1) - (2)])); + } + } + + prototype->setOp(EOpPrototype); + (yyval.interm.intermNode) = prototype; + + context->symbolTable.pop(); + } + break; + + case 75: + + { + if ((yyvsp[(1) - (2)].interm).intermAggregate) + (yyvsp[(1) - (2)].interm).intermAggregate->setOp(EOpDeclaration); + (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermAggregate; + } + break; + + case 76: + + { + if (((yyvsp[(2) - (4)].interm.precision) == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) { + context->error((yylsp[(1) - (4)]), "precision is not supported in fragment shader", "highp"); + context->recover(); + } + if (!context->symbolTable.setDefaultPrecision( (yyvsp[(3) - (4)].interm.type), (yyvsp[(2) - (4)].interm.precision) )) { + context->error((yylsp[(1) - (4)]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[(3) - (4)].interm.type).type)); + context->recover(); + } + (yyval.interm.intermNode) = 0; + } + break; + + case 77: + + { + ES3_ONLY(getQualifierString((yyvsp[(1) - (5)].interm.type).qualifier), (yylsp[(1) - (5)]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (5)].interm.type), (yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yyvsp[(3) - (5)].interm.fieldList), NULL, (yyloc), NULL, (yyloc)); + } + break; + + case 78: + + { + ES3_ONLY(getQualifierString((yyvsp[(1) - (6)].interm.type).qualifier), (yylsp[(1) - (6)]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (6)].interm.type), (yylsp[(2) - (6)]), *(yyvsp[(2) - (6)].lex).string, (yyvsp[(3) - (6)].interm.fieldList), (yyvsp[(5) - (6)].lex).string, (yylsp[(5) - (6)]), NULL, (yyloc)); + } + break; + + case 79: + + { + ES3_ONLY(getQualifierString((yyvsp[(1) - (9)].interm.type).qualifier), (yylsp[(1) - (9)]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[(1) - (9)].interm.type), (yylsp[(2) - (9)]), *(yyvsp[(2) - (9)].lex).string, (yyvsp[(3) - (9)].interm.fieldList), (yyvsp[(5) - (9)].lex).string, (yylsp[(5) - (9)]), (yyvsp[(7) - (9)].interm.intermTypedNode), (yylsp[(6) - (9)])); + } + break; + + case 80: + + { + context->parseGlobalLayoutQualifier((yyvsp[(1) - (2)].interm.type)); + (yyval.interm.intermNode) = 0; + } + break; + + case 81: + + { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getMangledName(), context->shaderVersion)); + if (prevDec) { + if (prevDec->getReturnType() != (yyvsp[(1) - (2)].interm.function)->getReturnType()) { + context->error((yylsp[(2) - (2)]), "overloaded functions must have the same return type", (yyvsp[(1) - (2)].interm.function)->getReturnType().getBasicString()); + context->recover(); + } + for (size_t i = 0; i < prevDec->getParamCount(); ++i) { + if (prevDec->getParam(i).type->getQualifier() != (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifier()) { + context->error((yylsp[(2) - (2)]), "overloaded functions must have the same parameter qualifiers", (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifierString()); + context->recover(); + } + } + } + + // + // Check for previously declared variables using the same name. + // + TSymbol *prevSym = context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getName(), context->shaderVersion); + if (prevSym) + { + if (!prevSym->isFunction()) + { + context->error((yylsp[(2) - (2)]), "redefinition", (yyvsp[(1) - (2)].interm.function)->getName().c_str(), "function"); + context->recover(); + } + } + else + { + // Insert the unmangled name to detect potential future redefinition as a variable. + context->symbolTable.getOuterLevel()->insert((yyvsp[(1) - (2)].interm.function)->getName(), *(yyvsp[(1) - (2)].interm.function)); + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + (yyval.interm).function = (yyvsp[(1) - (2)].interm.function); + + // We're at the inner scope level of the function's arguments and body statement. + // Add the function prototype to the surrounding scope instead. + context->symbolTable.getOuterLevel()->insert(*(yyval.interm).function); + } + break; + + case 82: + + { + (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function); + } + break; + + case 83: + + { + (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function); + } + break; + + case 84: + + { + // Add the parameter + (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function); + if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid) + (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param); + else + delete (yyvsp[(2) - (2)].interm).param.type; + } + break; + + case 85: + + { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ((yyvsp[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + context->error((yylsp[(2) - (3)]), "cannot be an argument type except for '(void)'", "void"); + context->recover(); + delete (yyvsp[(3) - (3)].interm).param.type; + } else { + // Add the parameter + (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function); + (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param); + } + } + break; + + case 86: + + { + if ((yyvsp[(1) - (3)].interm.type).qualifier != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier != EvqTemporary) { + context->error((yylsp[(2) - (3)]), "no qualifiers allowed for function return", getQualifierString((yyvsp[(1) - (3)].interm.type).qualifier)); + context->recover(); + } + // make sure a sampler is not involved as well... + if (context->structQualifierErrorCheck((yylsp[(2) - (3)]), (yyvsp[(1) - (3)].interm.type))) + context->recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type((yyvsp[(1) - (3)].interm.type)); + function = new TFunction((yyvsp[(2) - (3)].lex).string, type); + (yyval.interm.function) = function; + + context->symbolTable.push(); + } + break; + + case 87: + + { + if ((yyvsp[(1) - (2)].interm.type).type == EbtVoid) { + context->error((yylsp[(2) - (2)]), "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str()); + context->recover(); + } + if (context->reservedErrorCheck((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string)) + context->recover(); + TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))}; + (yyval.interm).param = param; + } + break; + + case 88: + + { + // Check that we can make an array out of this type + if (context->arrayTypeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm.type))) + context->recover(); + + if (context->reservedErrorCheck((yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string)) + context->recover(); + + int size; + if (context->arraySizeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode), size)) + context->recover(); + (yyvsp[(1) - (5)].interm.type).setArray(true, size); + + TType* type = new TType((yyvsp[(1) - (5)].interm.type)); + TParameter param = { (yyvsp[(2) - (5)].lex).string, type }; + (yyval.interm).param = param; + } + break; + + case 89: + + { + (yyval.interm) = (yyvsp[(3) - (3)].interm); + if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.qualifier), (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 90: + + { + (yyval.interm) = (yyvsp[(2) - (2)].interm); + if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type)) + context->recover(); + if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 91: + + { + (yyval.interm) = (yyvsp[(3) - (3)].interm); + if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.qualifier), (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 92: + + { + (yyval.interm) = (yyvsp[(2) - (2)].interm); + if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type)) + context->recover(); + if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type)) + context->recover(); + } + break; + + case 93: + + { + (yyval.interm.qualifier) = EvqIn; + } + break; + + case 94: + + { + (yyval.interm.qualifier) = EvqIn; + } + break; + + case 95: + + { + (yyval.interm.qualifier) = EvqOut; + } + break; + + case 96: + + { + (yyval.interm.qualifier) = EvqInOut; + } + break; + + case 97: + + { + TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) }; + (yyval.interm).param = param; + } + break; + + case 98: + + { + (yyval.interm) = (yyvsp[(1) - (1)].interm); + } + break; + + case 99: + + { + (yyval.interm) = (yyvsp[(1) - (3)].interm); + (yyval.interm).intermAggregate = context->parseDeclarator((yyval.interm).type, (yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].lex).symbol, (yylsp[(3) - (3)]), *(yyvsp[(3) - (3)].lex).string); + } + break; + + case 100: + + { + (yyval.interm) = (yyvsp[(1) - (5)].interm); + context->parseArrayDeclarator((yyval.interm).type, (yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yylsp[(4) - (5)]), NULL, NULL); + } + break; + + case 101: + + { + (yyval.interm) = (yyvsp[(1) - (6)].interm); + (yyval.interm).intermAggregate = context->parseArrayDeclarator((yyval.interm).type, (yylsp[(3) - (6)]), *(yyvsp[(3) - (6)].lex).string, (yylsp[(4) - (6)]), (yyvsp[(1) - (6)].interm).intermNode, (yyvsp[(5) - (6)].interm.intermTypedNode)); + } + break; + + case 102: + + { + (yyval.interm) = (yyvsp[(1) - (5)].interm); + (yyval.interm).intermAggregate = context->parseInitDeclarator((yyval.interm).type, (yyvsp[(1) - (5)].interm).intermAggregate, (yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yylsp[(4) - (5)]), (yyvsp[(5) - (5)].interm.intermTypedNode)); + } + break; + + case 103: + + { + (yyval.interm).type = (yyvsp[(1) - (1)].interm.type); + (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(1) - (1)]), ""); + } + break; + + case 104: + + { + (yyval.interm).type = (yyvsp[(1) - (2)].interm.type); + (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string); + } + break; + + case 105: + + { + context->error((yylsp[(2) - (4)]), "unsized array declarations not supported", (yyvsp[(2) - (4)].lex).string->c_str()); + context->recover(); + + (yyval.interm).type = (yyvsp[(1) - (4)].interm.type); + (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string); + } + break; + + case 106: + + { + (yyval.interm).type = (yyvsp[(1) - (5)].interm.type); + (yyval.interm).intermAggregate = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode)); + } + break; + + case 107: + + { + (yyval.interm).type = (yyvsp[(1) - (4)].interm.type); + (yyval.interm).intermAggregate = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yylsp[(3) - (4)]), (yyvsp[(4) - (4)].interm.intermTypedNode)); + } + break; + + case 108: + + { + VERTEX_ONLY("invariant declaration", (yylsp[(1) - (2)])); + if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + (yyval.interm).type.setBasic(EbtInvariant, EvqInvariantVaryingOut, (yylsp[(2) - (2)])); + if (!(yyvsp[(2) - (2)].lex).symbol) + { + context->error((yylsp[(2) - (2)]), "undeclared identifier declared as invariant", (yyvsp[(2) - (2)].lex).string->c_str()); + context->recover(); + + (yyval.interm).intermAggregate = 0; + } + else + { + TIntermSymbol *symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyval.interm).type), (yylsp[(2) - (2)])); + (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (2)])); + } + } + break; + + case 109: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + + if ((yyvsp[(1) - (1)].interm.type).array) { + context->error((yylsp[(1) - (1)]), "not supported", "first-class array"); + context->recover(); + (yyvsp[(1) - (1)].interm.type).setArray(false); + } + } + break; + + case 110: + + { + (yyval.interm.type) = context->addFullySpecifiedType((yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(1) - (2)].interm.type).layoutQualifier, (yyvsp[(2) - (2)].interm.type)); + } + break; + + case 111: + + { + (yyval.interm.type).qualifier = EvqSmooth; + } + break; + + case 112: + + { + (yyval.interm.type).qualifier = EvqFlat; + } + break; + + case 113: + + { + (yyval.interm.qualifier) = EvqConst; + } + break; + + case 114: + + { + VERTEX_ONLY("attribute", (yylsp[(1) - (1)])); + ES2_ONLY("attribute", (yylsp[(1) - (1)])); + if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "attribute")) + context->recover(); + (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yylsp[(1) - (1)])); + } + break; + + case 115: + + { + ES2_ONLY("varying", (yylsp[(1) - (1)])); + if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yylsp[(1) - (1)])); + else + (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yylsp[(1) - (1)])); + } + break; + + case 116: + + { + ES2_ONLY("varying", (yylsp[(1) - (2)])); + if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying")) + context->recover(); + if (context->shaderType == SH_VERTEX_SHADER) + (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingOut, (yylsp[(1) - (2)])); + else + (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingIn, (yylsp[(1) - (2)])); + } + break; + + case 117: + + { + if ((yyvsp[(1) - (1)].interm.type).qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) { + context->error((yylsp[(1) - (1)]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[(1) - (1)].interm.type).qualifier)); + context->recover(); + } else { + (yyval.interm.type).setBasic(EbtVoid, (yyvsp[(1) - (1)].interm.type).qualifier, (yylsp[(1) - (1)])); + } + } + break; + + case 118: + + { + (yyval.interm.type) = context->joinInterpolationQualifiers((yylsp[(1) - (2)]), (yyvsp[(1) - (2)].interm.type).qualifier, (yylsp[(2) - (2)]), (yyvsp[(2) - (2)].interm.type).qualifier); + } + break; + + case 119: + + { + context->error((yylsp[(1) - (1)]), "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString((yyvsp[(1) - (1)].interm.type).qualifier)); + context->recover(); + + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[(1) - (1)])); + } + break; + + case 120: + + { + (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).layoutQualifier = (yyvsp[(1) - (1)].interm.layoutQualifier); + } + break; + + case 121: + + { + (yyval.interm.type).setBasic(EbtVoid, (yyvsp[(2) - (2)].interm.type).qualifier, (yylsp[(2) - (2)])); + (yyval.interm.type).layoutQualifier = (yyvsp[(1) - (2)].interm.layoutQualifier); + } + break; + + case 122: + + { + (yyval.interm.type).qualifier = EvqConst; + } + break; + + case 123: + + { + ES3_ONLY("in", (yylsp[(1) - (1)]), "storage qualifier"); + (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + } + break; + + case 124: + + { + ES3_ONLY("out", (yylsp[(1) - (1)]), "storage qualifier"); + (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; + } + break; + + case 125: + + { + ES3_ONLY("centroid in", (yylsp[(1) - (2)]), "storage qualifier"); + if (context->shaderType == SH_VERTEX_SHADER) + { + context->error((yylsp[(1) - (2)]), "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); + context->recover(); + } + (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; + } + break; + + case 126: + + { + ES3_ONLY("centroid out", (yylsp[(1) - (2)]), "storage qualifier"); + if (context->shaderType == SH_FRAGMENT_SHADER) + { + context->error((yylsp[(1) - (2)]), "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); + context->recover(); + } + (yyval.interm.type).qualifier = (context->shaderType == SH_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + } + break; + + case 127: + + { + if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "uniform")) + context->recover(); + (yyval.interm.type).qualifier = EvqUniform; + } + break; + + case 128: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + + if ((yyval.interm.type).precision == EbpUndefined) { + (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[(1) - (1)].interm.type).type); + if (context->precisionErrorCheck((yylsp[(1) - (1)]), (yyval.interm.type).precision, (yyvsp[(1) - (1)].interm.type).type)) { + context->recover(); + } + } + } + break; + + case 129: + + { + (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type); + (yyval.interm.type).precision = (yyvsp[(1) - (2)].interm.precision); + + if (!SupportsPrecision((yyvsp[(2) - (2)].interm.type).type)) { + context->error((yylsp[(1) - (2)]), "illegal type for precision qualifier", getBasicString((yyvsp[(2) - (2)].interm.type).type)); + context->recover(); + } + } + break; + + case 130: + + { + (yyval.interm.precision) = EbpHigh; + } + break; + + case 131: + + { + (yyval.interm.precision) = EbpMedium; + } + break; + + case 132: + + { + (yyval.interm.precision) = EbpLow; + } + break; + + case 133: + + { + ES3_ONLY("layout", (yylsp[(1) - (4)]), "qualifier"); + (yyval.interm.layoutQualifier) = (yyvsp[(3) - (4)].interm.layoutQualifier); + } + break; + + case 134: + + { + (yyval.interm.layoutQualifier) = (yyvsp[(1) - (1)].interm.layoutQualifier); + } + break; + + case 135: + + { + (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[(1) - (3)].interm.layoutQualifier), (yyvsp[(3) - (3)].interm.layoutQualifier)); + } + break; + + case 136: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (1)].lex).string, (yylsp[(1) - (1)])); + } + break; + + case 137: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yylsp[(1) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yylsp[(3) - (3)])); + } + break; + + case 138: + + { + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yylsp[(1) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yylsp[(3) - (3)])); + } + break; + + case 139: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + } + break; + + case 140: + + { + (yyval.interm.type) = (yyvsp[(1) - (4)].interm.type); + + if (context->arrayTypeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type))) + context->recover(); + else { + int size; + if (context->arraySizeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size)) + context->recover(); + (yyval.interm.type).setArray(true, size); + } + } + break; + + case 141: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[(1) - (1)])); + } + break; + + case 142: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + } + break; + + case 143: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)])); + } + break; + + case 144: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)])); + } + break; + + case 145: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)])); + } + break; + + case 146: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(2); + } + break; + + case 147: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(3); + } + break; + + case 148: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(4); + } + break; + + case 149: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(2); + } + break; + + case 150: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(3); + } + break; + + case 151: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(4); + } + break; + + case 152: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(2); + } + break; + + case 153: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(3); + } + break; + + case 154: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(4); + } + break; + + case 155: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(2); + } + break; + + case 156: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(3); + } + break; + + case 157: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setAggregate(4); + } + break; + + case 158: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(2, 2); + } + break; + + case 159: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(3, 3); + } + break; + + case 160: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(4, 4); + } + break; + + case 161: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(2, 3); + } + break; + + case 162: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(3, 2); + } + break; + + case 163: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(2, 4); + } + break; + + case 164: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(4, 2); + } + break; + + case 165: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(3, 4); + } + break; + + case 166: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).setMatrix(4, 3); + } + break; + + case 167: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2D, qual, (yylsp[(1) - (1)])); + } + break; + + case 168: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler3D, qual, (yylsp[(1) - (1)])); + } + break; + + case 169: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yylsp[(1) - (1)])); + } + break; + + case 170: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2DArray, qual, (yylsp[(1) - (1)])); + } + break; + + case 171: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtISampler2D, qual, (yylsp[(1) - (1)])); + } + break; + + case 172: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtISampler3D, qual, (yylsp[(1) - (1)])); + } + break; + + case 173: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtISamplerCube, qual, (yylsp[(1) - (1)])); + } + break; + + case 174: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtISampler2DArray, qual, (yylsp[(1) - (1)])); + } + break; + + case 175: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUSampler2D, qual, (yylsp[(1) - (1)])); + } + break; + + case 176: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUSampler3D, qual, (yylsp[(1) - (1)])); + } + break; + + case 177: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUSamplerCube, qual, (yylsp[(1) - (1)])); + } + break; + + case 178: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtUSampler2DArray, qual, (yylsp[(1) - (1)])); + } + break; + + case 179: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2DShadow, qual, (yylsp[(1) - (1)])); + } + break; + + case 180: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSamplerCubeShadow, qual, (yylsp[(1) - (1)])); + } + break; + + case 181: + + { + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2DArrayShadow, qual, (yylsp[(1) - (1)])); + } + break; + + case 182: + + { + if (!context->supportsExtension("GL_OES_EGL_image_external")) { + context->error((yylsp[(1) - (1)]), "unsupported type", "samplerExternalOES"); + context->recover(); + } + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSamplerExternalOES, qual, (yylsp[(1) - (1)])); + } + break; + + case 183: + + { + if (!context->supportsExtension("GL_ARB_texture_rectangle")) { + context->error((yylsp[(1) - (1)]), "unsupported type", "sampler2DRect"); + context->recover(); + } + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[(1) - (1)])); + } + break; + + case 184: + + { + (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type); + (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + break; + + case 185: + + { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast<TVariable*>((yyvsp[(1) - (1)].lex).symbol)->getType(); + TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.type).setBasic(EbtStruct, qual, (yylsp[(1) - (1)])); + (yyval.interm.type).userDef = &structure; + } + break; + + case 186: + + { if (context->enterStructDeclaration((yylsp[(2) - (3)]), *(yyvsp[(2) - (3)].lex).string)) context->recover(); } + break; + + case 187: + + { + (yyval.interm.type) = context->addStructure((yylsp[(1) - (6)]), (yylsp[(2) - (6)]), (yyvsp[(2) - (6)].lex).string, (yyvsp[(5) - (6)].interm.fieldList)); + } + break; + + case 188: + + { if (context->enterStructDeclaration((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string)) context->recover(); } + break; + + case 189: + + { + (yyval.interm.type) = context->addStructure((yylsp[(1) - (5)]), (yyloc), NewPoolTString(""), (yyvsp[(4) - (5)].interm.fieldList)); + } + break; + + case 190: + + { + (yyval.interm.fieldList) = (yyvsp[(1) - (1)].interm.fieldList); + } + break; + + case 191: + + { + (yyval.interm.fieldList) = (yyvsp[(1) - (2)].interm.fieldList); + for (size_t i = 0; i < (yyvsp[(2) - (2)].interm.fieldList)->size(); ++i) { + TField* field = (*(yyvsp[(2) - (2)].interm.fieldList))[i]; + for (size_t j = 0; j < (yyval.interm.fieldList)->size(); ++j) { + if ((*(yyval.interm.fieldList))[j]->name() == field->name()) { + context->error((yylsp[(2) - (2)]), "duplicate field name in structure:", "struct", field->name().c_str()); + context->recover(); + } + } + (yyval.interm.fieldList)->push_back(field); + } + } + break; + + case 192: + + { + (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[(1) - (3)].interm.type), (yyvsp[(2) - (3)].interm.fieldList)); + } + break; + + case 193: + + { + // ES3 Only, but errors should be handled elsewhere + (yyvsp[(2) - (4)].interm.type).qualifier = (yyvsp[(1) - (4)].interm.type).qualifier; + (yyvsp[(2) - (4)].interm.type).layoutQualifier = (yyvsp[(1) - (4)].interm.type).layoutQualifier; + (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[(2) - (4)].interm.type), (yyvsp[(3) - (4)].interm.fieldList)); + } + break; + + case 194: + + { + (yyval.interm.fieldList) = NewPoolTFieldList(); + (yyval.interm.fieldList)->push_back((yyvsp[(1) - (1)].interm.field)); + } + break; + + case 195: + + { + (yyval.interm.fieldList)->push_back((yyvsp[(3) - (3)].interm.field)); + } + break; + + case 196: + + { + if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string)) + context->recover(); + + TType* type = new TType(EbtVoid, EbpUndefined); + (yyval.interm.field) = new TField(type, (yyvsp[(1) - (1)].lex).string, (yylsp[(1) - (1)])); + } + break; + + case 197: + + { + if (context->reservedErrorCheck((yylsp[(1) - (4)]), *(yyvsp[(1) - (4)].lex).string)) + context->recover(); + + TType* type = new TType(EbtVoid, EbpUndefined); + int size; + if (context->arraySizeErrorCheck((yylsp[(3) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size)) + context->recover(); + type->setArraySize(size); + + (yyval.interm.field) = new TField(type, (yyvsp[(1) - (4)].lex).string, (yylsp[(1) - (4)])); + } + break; + + case 198: + + { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); } + break; + + case 199: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 200: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); } + break; + + case 201: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 202: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 203: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 204: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 205: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 206: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 207: + + { (yyval.interm.intermAggregate) = 0; } + break; + + case 208: + + { context->symbolTable.push(); } + break; + + case 209: + + { context->symbolTable.pop(); } + break; + + case 210: + + { + if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) { + (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence); + (yyvsp[(3) - (5)].interm.intermAggregate)->setLine((yyloc)); + } + (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate); + } + break; + + case 211: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 212: + + { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); } + break; + + case 213: + + { context->symbolTable.push(); } + break; + + case 214: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); } + break; + + case 215: + + { context->symbolTable.push(); } + break; + + case 216: + + { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); } + break; + + case 217: + + { + (yyval.interm.intermNode) = 0; + } + break; + + case 218: + + { + if ((yyvsp[(2) - (3)].interm.intermAggregate)) { + (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence); + (yyvsp[(2) - (3)].interm.intermAggregate)->setLine((yyloc)); + } + (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate); + } + break; + + case 219: + + { + (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), (yyloc)); + } + break; + + case 220: + + { + (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), (yyloc)); + } + break; + + case 221: + + { (yyval.interm.intermNode) = 0; } + break; + + case 222: + + { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); } + break; + + case 223: + + { + if (context->boolErrorCheck((yylsp[(1) - (5)]), (yyvsp[(3) - (5)].interm.intermTypedNode))) + context->recover(); + (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yylsp[(1) - (5)])); + } + break; + + case 224: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode); + } + break; + + case 225: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode); + (yyval.interm.nodePair).node2 = 0; + } + break; + + case 226: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode))) + context->recover(); + } + break; + + case 227: + + { + TIntermNode* intermNode; + if (context->structQualifierErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type))) + context->recover(); + if (context->boolErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type))) + context->recover(); + + if (!context->executeInitializer((yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode)) + (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode); + else { + context->recover(); + (yyval.interm.intermTypedNode) = 0; + } + } + break; + + case 228: + + { context->symbolTable.push(); ++context->loopNestingLevel; } + break; + + case 229: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yylsp[(1) - (6)])); + --context->loopNestingLevel; + } + break; + + case 230: + + { ++context->loopNestingLevel; } + break; + + case 231: + + { + if (context->boolErrorCheck((yylsp[(8) - (8)]), (yyvsp[(6) - (8)].interm.intermTypedNode))) + context->recover(); + + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yylsp[(4) - (8)])); + --context->loopNestingLevel; + } + break; + + case 232: + + { context->symbolTable.push(); ++context->loopNestingLevel; } + break; + + case 233: + + { + context->symbolTable.pop(); + (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yylsp[(1) - (7)])); + --context->loopNestingLevel; + } + break; + + case 234: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 235: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 236: + + { + (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); + } + break; + + case 237: + + { + (yyval.interm.intermTypedNode) = 0; + } + break; + + case 238: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = 0; + } + break; + + case 239: + + { + (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode); + } + break; + + case 240: + + { + if (context->loopNestingLevel <= 0) { + context->error((yylsp[(1) - (2)]), "continue statement only allowed in loops", ""); + context->recover(); + } + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[(1) - (2)])); + } + break; + + case 241: + + { + if (context->loopNestingLevel <= 0) { + context->error((yylsp[(1) - (2)]), "break statement only allowed in loops", ""); + context->recover(); + } + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[(1) - (2)])); + } + break; + + case 242: + + { + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[(1) - (2)])); + if (context->currentFunctionType->getBasicType() != EbtVoid) { + context->error((yylsp[(1) - (2)]), "non-void function must return a value", "return"); + context->recover(); + } + } + break; + + case 243: + + { + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yylsp[(1) - (3)])); + context->functionReturnsValue = true; + if (context->currentFunctionType->getBasicType() == EbtVoid) { + context->error((yylsp[(1) - (3)]), "void function cannot return a value", "return"); + context->recover(); + } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) { + context->error((yylsp[(1) - (3)]), "function return is not matching type:", "return"); + context->recover(); + } + } + break; + + case 244: + + { + FRAG_ONLY("discard", (yylsp[(1) - (2)])); + (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[(1) - (2)])); + } + break; + + case 245: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + context->treeRoot = (yyval.interm.intermNode); + } + break; + + case 246: + + { + (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), (yyloc)); + context->treeRoot = (yyval.interm.intermNode); + } + break; + + case 247: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 248: + + { + (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); + } + break; + + case 249: + + { + TFunction* function = (yyvsp[(1) - (1)].interm).function; + + const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName(), context->shaderVersion); + + if (builtIn) + { + context->error((yylsp[(1) - (1)]), "built-in functions cannot be redefined", function->getName().c_str()); + context->recover(); + } + + TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName(), context->shaderVersion)); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + context->error((yylsp[(1) - (1)]), "function already has a body", function->getName().c_str()); + context->recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function->getName() == "main") { + if (function->getParamCount() > 0) { + context->error((yylsp[(1) - (1)]), "function cannot take any parameter(s)", function->getName().c_str()); + context->recover(); + } + if (function->getReturnType().getBasicType() != EbtVoid) { + context->error((yylsp[(1) - (1)]), "", function->getReturnType().getBasicString(), "main function cannot return a value"); + context->recover(); + } + } + + // + // Remember the return type for later checking for RETURN statements. + // + context->currentFunctionType = &(prevDec->getReturnType()); + context->functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (size_t i = 0; i < function->getParamCount(); i++) { + const TParameter& param = function->getParam(i); + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! context->symbolTable.declare(*variable)) { + context->error((yylsp[(1) - (1)]), "redefinition", variable->getName().c_str()); + context->recover(); + delete variable; + } + + // + // Add the parameter to the HIL + // + paramNodes = context->intermediate.growAggregate( + paramNodes, + context->intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), (yylsp[(1) - (1)])), + (yylsp[(1) - (1)])); + } else { + paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (1)])), (yylsp[(1) - (1)])); + } + } + context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[(1) - (1)])); + (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes; + context->loopNestingLevel = 0; + } + break; + + case 250: + + { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) { + context->error((yylsp[(1) - (3)]), "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str()); + context->recover(); + } + + (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].interm.intermNode), (yyloc)); + context->intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yylsp[(1) - (3)])); + (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str()); + (yyval.interm.intermNode)->getAsAggregate()->setType((yyvsp[(1) - (3)].interm).function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + (yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->pragma().optimize); + (yyval.interm.intermNode)->getAsAggregate()->setDebug(context->pragma().debug); + + context->symbolTable.pop(); + } + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, context, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (&yylloc, context, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + yyerror_range[1] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[1] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, yyerror_range, 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, context); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +int glslang_parse(TParseContext* context) { + return yyparse(context); +} diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.h b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h new file mode 100644 index 00000000000..c6a61dcd85f --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h @@ -0,0 +1,257 @@ +/* A Bison parser, made by GNU Bison 2.7.1. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED +# define YY_YY_GLSLANG_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif +/* "%code requires" blocks. */ + + +#define YYLTYPE TSourceLoc +#define YYLTYPE_IS_DECLARED 1 + + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INVARIANT = 258, + HIGH_PRECISION = 259, + MEDIUM_PRECISION = 260, + LOW_PRECISION = 261, + PRECISION = 262, + ATTRIBUTE = 263, + CONST_QUAL = 264, + BOOL_TYPE = 265, + FLOAT_TYPE = 266, + INT_TYPE = 267, + UINT_TYPE = 268, + BREAK = 269, + CONTINUE = 270, + DO = 271, + ELSE = 272, + FOR = 273, + IF = 274, + DISCARD = 275, + RETURN = 276, + SWITCH = 277, + CASE = 278, + DEFAULT = 279, + BVEC2 = 280, + BVEC3 = 281, + BVEC4 = 282, + IVEC2 = 283, + IVEC3 = 284, + IVEC4 = 285, + VEC2 = 286, + VEC3 = 287, + VEC4 = 288, + UVEC2 = 289, + UVEC3 = 290, + UVEC4 = 291, + MATRIX2 = 292, + MATRIX3 = 293, + MATRIX4 = 294, + IN_QUAL = 295, + OUT_QUAL = 296, + INOUT_QUAL = 297, + UNIFORM = 298, + VARYING = 299, + MATRIX2x3 = 300, + MATRIX3x2 = 301, + MATRIX2x4 = 302, + MATRIX4x2 = 303, + MATRIX3x4 = 304, + MATRIX4x3 = 305, + CENTROID = 306, + FLAT = 307, + SMOOTH = 308, + STRUCT = 309, + VOID_TYPE = 310, + WHILE = 311, + SAMPLER2D = 312, + SAMPLERCUBE = 313, + SAMPLER_EXTERNAL_OES = 314, + SAMPLER2DRECT = 315, + SAMPLER2DARRAY = 316, + ISAMPLER2D = 317, + ISAMPLER3D = 318, + ISAMPLERCUBE = 319, + ISAMPLER2DARRAY = 320, + USAMPLER2D = 321, + USAMPLER3D = 322, + USAMPLERCUBE = 323, + USAMPLER2DARRAY = 324, + SAMPLER3D = 325, + SAMPLER3DRECT = 326, + SAMPLER2DSHADOW = 327, + SAMPLERCUBESHADOW = 328, + SAMPLER2DARRAYSHADOW = 329, + LAYOUT = 330, + IDENTIFIER = 331, + TYPE_NAME = 332, + FLOATCONSTANT = 333, + INTCONSTANT = 334, + UINTCONSTANT = 335, + BOOLCONSTANT = 336, + FIELD_SELECTION = 337, + LEFT_OP = 338, + RIGHT_OP = 339, + INC_OP = 340, + DEC_OP = 341, + LE_OP = 342, + GE_OP = 343, + EQ_OP = 344, + NE_OP = 345, + AND_OP = 346, + OR_OP = 347, + XOR_OP = 348, + MUL_ASSIGN = 349, + DIV_ASSIGN = 350, + ADD_ASSIGN = 351, + MOD_ASSIGN = 352, + LEFT_ASSIGN = 353, + RIGHT_ASSIGN = 354, + AND_ASSIGN = 355, + XOR_ASSIGN = 356, + OR_ASSIGN = 357, + SUB_ASSIGN = 358, + LEFT_PAREN = 359, + RIGHT_PAREN = 360, + LEFT_BRACKET = 361, + RIGHT_BRACKET = 362, + LEFT_BRACE = 363, + RIGHT_BRACE = 364, + DOT = 365, + COMMA = 366, + COLON = 367, + EQUAL = 368, + SEMICOLON = 369, + BANG = 370, + DASH = 371, + TILDE = 372, + PLUS = 373, + STAR = 374, + SLASH = 375, + PERCENT = 376, + LEFT_ANGLE = 377, + RIGHT_ANGLE = 378, + VERTICAL_BAR = 379, + CARET = 380, + AMPERSAND = 381, + QUESTION = 382 + }; +#endif + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + struct { + union { + TString *string; + float f; + int i; + unsigned int u; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + TFunction* function; + TParameter param; + TField* field; + TFieldList* fieldList; + }; + } interm; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (TParseContext* context); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */ diff --git a/chromium/third_party/angle/src/compiler/translator/intermOut.cpp b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp new file mode 100644 index 00000000000..7f94ac31416 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp @@ -0,0 +1,439 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/localintermediate.h" +#include "compiler/translator/SymbolTable.h" + +// +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can +// also directly call Traverse() on children themselves to +// have finer grained control over the process than shown here. +// See the last function for how to get started. +// 2. Print out a text based description of the tree. +// + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TOutputTraverser : public TIntermTraverser { +public: + TOutputTraverser(TInfoSinkBase& i) : sink(i) { } + TInfoSinkBase& sink; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); +}; + +TString TType::getCompleteString() const +{ + TStringStream stream; + + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + stream << getQualifierString() << " " << getPrecisionString() << " "; + if (array) + stream << "array[" << getArraySize() << "] of "; + if (isMatrix()) + stream << getCols() << "X" << getRows() << " matrix of "; + else if (isVector()) + stream << getNominalSize() << "-component vector of "; + + stream << getBasicString(); + return stream.str(); +} + +// +// Helper functions for printing, not part of traversing. +// + +void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth) +{ + int i; + + sink.location(node->getLine()); + + for (i = 0; i < depth; ++i) + sink << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol* node) +{ + OutputTreeText(sink, node, depth); + + sink << "'" << node->getSymbol() << "' "; + sink << "(" << node->getCompleteString() << ")\n"; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpAssign: out << "move second child to first child"; break; + case EOpInitialize: out << "initialize first child with second child"; break; + case EOpAddAssign: out << "add second child into first child"; break; + case EOpSubAssign: out << "subtract second child into first child"; break; + case EOpMulAssign: out << "multiply second child into first child"; break; + case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break; + case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break; + case EOpDivAssign: out << "divide second child into first child"; break; + case EOpIndexDirect: out << "direct index"; break; + case EOpIndexIndirect: out << "indirect index"; break; + case EOpIndexDirectStruct: out << "direct index for structure"; break; + case EOpIndexDirectInterfaceBlock: out << "direct index for interface block"; break; + case EOpVectorSwizzle: out << "vector swizzle"; break; + + case EOpAdd: out << "add"; break; + case EOpSub: out << "subtract"; break; + case EOpMul: out << "component-wise multiply"; break; + case EOpDiv: out << "divide"; break; + case EOpEqual: out << "Compare Equal"; break; + case EOpNotEqual: out << "Compare Not Equal"; break; + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + + case EOpVectorTimesScalar: out << "vector-scale"; break; + case EOpVectorTimesMatrix: out << "vector-times-matrix"; break; + case EOpMatrixTimesVector: out << "matrix-times-vector"; break; + case EOpMatrixTimesScalar: out << "matrix-scale"; break; + case EOpMatrixTimesMatrix: out << "matrix-multiply"; break; + + case EOpLogicalOr: out << "logical-or"; break; + case EOpLogicalXor: out << "logical-xor"; break; + case EOpLogicalAnd: out << "logical-and"; break; + default: out << "<unknown op>"; + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpNegative: out << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out << "Negate conditional"; break; + + case EOpPostIncrement: out << "Post-Increment"; break; + case EOpPostDecrement: out << "Post-Decrement"; break; + case EOpPreIncrement: out << "Pre-Increment"; break; + case EOpPreDecrement: out << "Pre-Decrement"; break; + + case EOpConvIntToBool: out << "Convert int to bool"; break; + case EOpConvUIntToBool: out << "Convert uint to bool"; break; + case EOpConvFloatToBool:out << "Convert float to bool";break; + case EOpConvBoolToFloat:out << "Convert bool to float";break; + case EOpConvIntToFloat: out << "Convert int to float"; break; + case EOpConvUIntToFloat:out << "Convert uint to float";break; + case EOpConvFloatToInt: out << "Convert float to int"; break; + case EOpConvBoolToInt: out << "Convert bool to int"; break; + case EOpConvIntToUInt: out << "Convert int to uint"; break; + case EOpConvFloatToUInt:out << "Convert float to uint";break; + case EOpConvBoolToUInt: out << "Convert bool to uint"; break; + + case EOpRadians: out << "radians"; break; + case EOpDegrees: out << "degrees"; break; + case EOpSin: out << "sine"; break; + case EOpCos: out << "cosine"; break; + case EOpTan: out << "tangent"; break; + case EOpAsin: out << "arc sine"; break; + case EOpAcos: out << "arc cosine"; break; + case EOpAtan: out << "arc tangent"; break; + + case EOpExp: out << "exp"; break; + case EOpLog: out << "log"; break; + case EOpExp2: out << "exp2"; break; + case EOpLog2: out << "log2"; break; + case EOpSqrt: out << "sqrt"; break; + case EOpInverseSqrt: out << "inverse sqrt"; break; + + case EOpAbs: out << "Absolute value"; break; + case EOpSign: out << "Sign"; break; + case EOpFloor: out << "Floor"; break; + case EOpCeil: out << "Ceiling"; break; + case EOpFract: out << "Fraction"; break; + + case EOpLength: out << "length"; break; + case EOpNormalize: out << "normalize"; break; + // case EOpDPdx: out << "dPdx"; break; + // case EOpDPdy: out << "dPdy"; break; + // case EOpFwidth: out << "fwidth"; break; + + case EOpAny: out << "any"; break; + case EOpAll: out << "all"; break; + + default: + out.prefix(EPrefixError); + out << "Bad unary op"; + } + + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + TInfoSinkBase& out = sink; + + if (node->getOp() == EOpNull) { + out.prefix(EPrefixError); + out << "node is still EOpNull!"; + return true; + } + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpSequence: out << "Sequence\n"; return true; + case EOpComma: out << "Comma\n"; return true; + case EOpFunction: out << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out << "Function Call: " << node->getName(); break; + case EOpParameters: out << "Function Parameters: "; break; + + case EOpConstructFloat: out << "Construct float"; break; + case EOpConstructVec2: out << "Construct vec2"; break; + case EOpConstructVec3: out << "Construct vec3"; break; + case EOpConstructVec4: out << "Construct vec4"; break; + case EOpConstructBool: out << "Construct bool"; break; + case EOpConstructBVec2: out << "Construct bvec2"; break; + case EOpConstructBVec3: out << "Construct bvec3"; break; + case EOpConstructBVec4: out << "Construct bvec4"; break; + case EOpConstructInt: out << "Construct int"; break; + case EOpConstructIVec2: out << "Construct ivec2"; break; + case EOpConstructIVec3: out << "Construct ivec3"; break; + case EOpConstructIVec4: out << "Construct ivec4"; break; + case EOpConstructUInt: out << "Construct uint"; break; + case EOpConstructUVec2: out << "Construct uvec2"; break; + case EOpConstructUVec3: out << "Construct uvec3"; break; + case EOpConstructUVec4: out << "Construct uvec4"; break; + case EOpConstructMat2: out << "Construct mat2"; break; + case EOpConstructMat3: out << "Construct mat3"; break; + case EOpConstructMat4: out << "Construct mat4"; break; + case EOpConstructStruct: out << "Construct structure"; break; + + case EOpLessThan: out << "Compare Less Than"; break; + case EOpGreaterThan: out << "Compare Greater Than"; break; + case EOpLessThanEqual: out << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out << "Equal"; break; + case EOpVectorNotEqual: out << "NotEqual"; break; + + case EOpMod: out << "mod"; break; + case EOpPow: out << "pow"; break; + + case EOpAtan: out << "arc tangent"; break; + + case EOpMin: out << "min"; break; + case EOpMax: out << "max"; break; + case EOpClamp: out << "clamp"; break; + case EOpMix: out << "mix"; break; + case EOpStep: out << "step"; break; + case EOpSmoothStep: out << "smoothstep"; break; + + case EOpDistance: out << "distance"; break; + case EOpDot: out << "dot-product"; break; + case EOpCross: out << "cross-product"; break; + case EOpFaceForward: out << "face-forward"; break; + case EOpReflect: out << "reflect"; break; + case EOpRefract: out << "refract"; break; + case EOpMul: out << "component-wise multiply"; break; + + case EOpDeclaration: out << "Declaration: "; break; + + default: + out.prefix(EPrefixError); + out << "Bad aggregation op"; + } + + if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + out << " (" << node->getCompleteString() << ")"; + + out << "\n"; + + return true; +} + +bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Test condition and select"; + out << " (" << node->getCompleteString() << ")\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + out << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(sink, node, depth); + if (node->getTrueBlock()) { + out << "true case\n"; + node->getTrueBlock()->traverse(this); + } else + out << "true case is null\n"; + + if (node->getFalseBlock()) { + OutputTreeText(sink, node, depth); + out << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --depth; + + return false; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + TInfoSinkBase& out = sink; + + size_t size = node->getType().getObjectSize(); + + for (size_t i = 0; i < size; i++) { + OutputTreeText(out, node, depth); + switch (node->getUnionArrayPointer()[i].getType()) { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out << "true"; + else + out << "false"; + + out << " (" << "const bool" << ")"; + out << "\n"; + break; + case EbtFloat: + out << node->getUnionArrayPointer()[i].getFConst(); + out << " (const float)\n"; + break; + case EbtInt: + out << node->getUnionArrayPointer()[i].getIConst(); + out << " (const int)\n"; + break; + case EbtUInt: + out << node->getUnionArrayPointer()[i].getUConst(); + out << " (const uint)\n"; + break; + default: + out.message(EPrefixInternalError, node->getLine(), "Unknown constant"); + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + out << "Loop with condition "; + if (node->getType() == ELoopDoWhile) + out << "not "; + out << "tested first\n"; + + ++depth; + + OutputTreeText(sink, node, depth); + if (node->getCondition()) { + out << "Loop Condition\n"; + node->getCondition()->traverse(this); + } else + out << "No loop condition\n"; + + OutputTreeText(sink, node, depth); + if (node->getBody()) { + out << "Loop Body\n"; + node->getBody()->traverse(this); + } else + out << "No loop body\n"; + + if (node->getExpression()) { + OutputTreeText(sink, node, depth); + out << "Loop Terminal Expression\n"; + node->getExpression()->traverse(this); + } + + --depth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + TInfoSinkBase& out = sink; + + OutputTreeText(out, node, depth); + + switch (node->getFlowOp()) { + case EOpKill: out << "Branch: Kill"; break; + case EOpBreak: out << "Branch: Break"; break; + case EOpContinue: out << "Branch: Continue"; break; + case EOpReturn: out << "Branch: Return"; break; + default: out << "Branch: Unknown Branch"; break; + } + + if (node->getExpression()) { + out << " with expression\n"; + ++depth; + node->getExpression()->traverse(this); + --depth; + } else + out << "\n"; + + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +void TIntermediate::outputTree(TIntermNode* root) +{ + if (root == 0) + return; + + TOutputTraverser it(infoSink.info); + + root->traverse(&it); +} diff --git a/chromium/third_party/angle/src/compiler/translator/intermediate.h b/chromium/third_party/angle/src/compiler/translator/intermediate.h new file mode 100644 index 00000000000..2fdde02e0f6 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/intermediate.h @@ -0,0 +1,719 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// Definition of the in-memory high-level intermediate representation +// of shaders. This is a tree that parser creates. +// +// Nodes in the tree are defined as a hierarchy of classes derived from +// TIntermNode. Each is a node in a tree. There is no preset branching factor; +// each node can have it's own type of list of children. +// + +#ifndef __INTERMEDIATE_H +#define __INTERMEDIATE_H + +#include "GLSLANG/ShaderLang.h" + +#include <algorithm> +#include <queue> +#include "compiler/translator/Common.h" +#include "compiler/translator/Types.h" +#include "compiler/translator/ConstantUnion.h" + +// +// Operators used by the high-level (parse tree) representation. +// +enum TOperator { + EOpNull, // if in a node, should only mean a node is still being built + EOpSequence, // denotes a list of statements, or parameters, etc. + EOpFunctionCall, + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + + EOpDeclaration, + EOpPrototype, + + // + // Unary operators + // + + EOpNegative, + EOpLogicalNot, + EOpVectorLogicalNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpConvIntToBool, + EOpConvUIntToBool, + EOpConvFloatToBool, + EOpConvBoolToFloat, + EOpConvIntToFloat, + EOpConvUIntToFloat, + EOpConvFloatToInt, + EOpConvBoolToInt, + EOpConvUIntToInt, + EOpConvIntToUInt, + EOpConvFloatToUInt, + EOpConvBoolToUInt, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + EOpIndexDirectInterfaceBlock, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpCeil, + EOpFract, + EOpMod, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + + EOpDFdx, // Fragment only, OES_standard_derivatives extension + EOpDFdy, // Fragment only, OES_standard_derivatives extension + EOpFwidth, // Fragment only, OES_standard_derivatives extension + + EOpMatrixTimesMatrix, + + EOpAny, + EOpAll, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructUInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructUVec2, + EOpConstructUVec3, + EOpConstructUVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + EOpDivAssign +}; + +extern const char* getOperatorString(TOperator op); + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBinary; +class TIntermUnary; +class TIntermConstantUnion; +class TIntermSelection; +class TIntermTyped; +class TIntermSymbol; +class TIntermLoop; +class TInfoSink; +class TIntermRaw; + +// +// Base class for the tree nodes +// +class TIntermNode { +public: + POOL_ALLOCATOR_NEW_DELETE(); + TIntermNode() { + // TODO: Move this to TSourceLoc constructor + // after getting rid of TPublicType. + line.first_file = line.last_file = 0; + line.first_line = line.last_line = 0; + } + virtual ~TIntermNode() { } + + const TSourceLoc& getLine() const { return line; } + void setLine(const TSourceLoc& l) { line = l; } + + virtual void traverse(TIntermTraverser*) = 0; + virtual TIntermTyped* getAsTyped() { return 0; } + virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } + virtual TIntermAggregate* getAsAggregate() { return 0; } + virtual TIntermBinary* getAsBinaryNode() { return 0; } + virtual TIntermUnary* getAsUnaryNode() { return 0; } + virtual TIntermSelection* getAsSelectionNode() { return 0; } + virtual TIntermSymbol* getAsSymbolNode() { return 0; } + virtual TIntermLoop* getAsLoopNode() { return 0; } + virtual TIntermRaw* getAsRawNode() { return 0; } + + // Replace a child node. Return true if |original| is a child + // node and it is replaced; otherwise, return false. + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement) = 0; + + // For traversing a tree in no particular order, but using + // heap memory. + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const = 0; + +protected: + TSourceLoc line; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair { + TIntermNode* node1; + TIntermNode* node2; +}; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode { +public: + TIntermTyped(const TType& t) : type(t) { } + virtual TIntermTyped* getAsTyped() { return this; } + + virtual bool hasSideEffects() const = 0; + + void setType(const TType& t) { type = t; } + const TType& getType() const { return type; } + TType* getTypePointer() { return &type; } + + TBasicType getBasicType() const { return type.getBasicType(); } + TQualifier getQualifier() const { return type.getQualifier(); } + TPrecision getPrecision() const { return type.getPrecision(); } + int getCols() const { return type.getCols(); } + int getRows() const { return type.getRows(); } + int getNominalSize() const { return type.getNominalSize(); } + int getSecondarySize() const { return type.getSecondarySize(); } + + bool isInterfaceBlock() const { return type.isInterfaceBlock(); } + bool isMatrix() const { return type.isMatrix(); } + bool isArray() const { return type.isArray(); } + bool isVector() const { return type.isVector(); } + bool isScalar() const { return type.isScalar(); } + bool isScalarInt() const { return type.isScalarInt(); } + const char* getBasicString() const { return type.getBasicString(); } + const char* getQualifierString() const { return type.getQualifierString(); } + TString getCompleteString() const { return type.getCompleteString(); } + + int getArraySize() const { return type.getArraySize(); } + +protected: + TType type; +}; + +// +// Handle for, do-while, and while loops. +// +enum TLoopType { + ELoopFor, + ELoopWhile, + ELoopDoWhile +}; + +class TIntermLoop : public TIntermNode { +public: + TIntermLoop(TLoopType aType, + TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr, + TIntermNode* aBody) : + type(aType), + init(aInit), + cond(aCond), + expr(aExpr), + body(aBody), + unrollFlag(false) { } + + virtual TIntermLoop* getAsLoopNode() { return this; } + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + TLoopType getType() const { return type; } + TIntermNode* getInit() { return init; } + TIntermTyped* getCondition() { return cond; } + TIntermTyped* getExpression() { return expr; } + TIntermNode* getBody() { return body; } + + void setUnrollFlag(bool flag) { unrollFlag = flag; } + bool getUnrollFlag() { return unrollFlag; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TLoopType type; + TIntermNode* init; // for-loop initialization + TIntermTyped* cond; // loop exit condition + TIntermTyped* expr; // for-loop expression + TIntermNode* body; // loop body + + bool unrollFlag; // Whether the loop should be unrolled or not. +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode { +public: + TIntermBranch(TOperator op, TIntermTyped* e) : + flowOp(op), + expression(e) { } + + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + TOperator getFlowOp() { return flowOp; } + TIntermTyped* getExpression() { return expression; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TOperator flowOp; + TIntermTyped* expression; // non-zero except for "return exp;" statements +}; + +// +// Nodes that correspond to symbols or constants in the source code. +// +class TIntermSymbol : public TIntermTyped { +public: + // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from + // per process globalpoolallocator, then it causes increased memory usage per compile + // it is essential to use "symbol = sym" to assign to symbol + TIntermSymbol(int i, const TString& sym, const TType& t) : + TIntermTyped(t), id(i) { symbol = sym; } + + virtual bool hasSideEffects() const { return false; } + + int getId() const { return id; } + const TString& getSymbol() const { return symbol; } + + void setId(int newId) { id = newId; } + + virtual void traverse(TIntermTraverser*); + virtual TIntermSymbol* getAsSymbolNode() { return this; } + virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {} + +protected: + int id; + TString symbol; +}; + +// A Raw node stores raw code, that the translator will insert verbatim +// into the output stream. Useful for transformation operations that make +// complex code that might not fit naturally into the GLSL model. +class TIntermRaw : public TIntermTyped { +public: + TIntermRaw(const TType &t, const TString &rawTextIn) + : TIntermTyped(t), rawText(rawTextIn) + {} + + virtual bool hasSideEffects() const { return false; } + + TString getRawText() const { return rawText; } + + virtual void traverse(TIntermTraverser*); + + virtual TIntermRaw* getAsRawNode() { return this; } + virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {} + +protected: + TString rawText; +}; + +class TIntermConstantUnion : public TIntermTyped { +public: + TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } + + virtual bool hasSideEffects() const { return false; } + + ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; } + + int getIConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; } + unsigned int getUConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getUConst() : 0; } + float getFConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; } + bool getBConst(size_t index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; } + + virtual TIntermConstantUnion* getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } + + TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {} + +protected: + ConstantUnion *unionArrayPointer; +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermTyped { +public: + TOperator getOp() const { return op; } + void setOp(TOperator o) { op = o; } + + bool isAssignment() const; + bool isConstructor() const; + + virtual bool hasSideEffects() const { return isAssignment(); } + +protected: + TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {} + TIntermOperator(TOperator o, const TType& t) : TIntermTyped(t), op(o) {} + TOperator op; +}; + +// +// Nodes for all the basic binary math operators. +// +class TIntermBinary : public TIntermOperator { +public: + TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {} + + virtual TIntermBinary* getAsBinaryNode() { return this; } + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + virtual bool hasSideEffects() const { return (isAssignment() || left->hasSideEffects() || right->hasSideEffects()); } + + void setLeft(TIntermTyped* n) { left = n; } + void setRight(TIntermTyped* n) { right = n; } + TIntermTyped* getLeft() const { return left; } + TIntermTyped* getRight() const { return right; } + bool promote(TInfoSink&); + + void setAddIndexClamp() { addIndexClamp = true; } + bool getAddIndexClamp() { return addIndexClamp; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TIntermTyped* left; + TIntermTyped* right; + + // If set to true, wrap any EOpIndexIndirect with a clamp to bounds. + bool addIndexClamp; +}; + +// +// Nodes for unary math operators. +// +class TIntermUnary : public TIntermOperator { +public: + TIntermUnary(TOperator o, const TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {} + TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {} + + virtual void traverse(TIntermTraverser*); + virtual TIntermUnary* getAsUnaryNode() { return this; } + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + virtual bool hasSideEffects() const { return (isAssignment() || operand->hasSideEffects()); } + + void setOperand(TIntermTyped* o) { operand = o; } + TIntermTyped* getOperand() { return operand; } + bool promote(TInfoSink&); + + void setUseEmulatedFunction() { useEmulatedFunction = true; } + bool getUseEmulatedFunction() { return useEmulatedFunction; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TIntermTyped* operand; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. + bool useEmulatedFunction; +}; + +typedef TVector<TIntermNode*> TIntermSequence; +typedef TVector<int> TQualifierList; + +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator { +public: + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { } + TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { } + ~TIntermAggregate() { } + + virtual TIntermAggregate* getAsAggregate() { return this; } + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + // Conservatively assume function calls and other aggregate operators have side-effects + virtual bool hasSideEffects() const { return true; } + + TIntermSequence& getSequence() { return sequence; } + + void setName(const TString& n) { name = n; } + const TString& getName() const { return name; } + + void setUserDefined() { userDefined = true; } + bool isUserDefined() const { return userDefined; } + + void setOptimize(bool o) { optimize = o; } + bool getOptimize() { return optimize; } + void setDebug(bool d) { debug = d; } + bool getDebug() { return debug; } + + void setUseEmulatedFunction() { useEmulatedFunction = true; } + bool getUseEmulatedFunction() { return useEmulatedFunction; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TIntermAggregate(const TIntermAggregate&); // disallow copy constructor + TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator + TIntermSequence sequence; + TString name; + bool userDefined; // used for user defined function names + + bool optimize; + bool debug; + + // If set to true, replace the built-in function call with an emulated one + // to work around driver bugs. + bool useEmulatedFunction; +}; + +// +// For if tests. Simplified since there is no switch statement. +// +class TIntermSelection : public TIntermTyped { +public: + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : + TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + + virtual void traverse(TIntermTraverser*); + virtual bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement); + + // Conservatively assume selections have side-effects + virtual bool hasSideEffects() const { return true; } + + bool usesTernaryOperator() const { return getBasicType() != EbtVoid; } + TIntermNode* getCondition() const { return condition; } + TIntermNode* getTrueBlock() const { return trueBlock; } + TIntermNode* getFalseBlock() const { return falseBlock; } + TIntermSelection* getAsSelectionNode() { return this; } + + virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const; + +protected: + TIntermTyped* condition; + TIntermNode* trueBlock; + TIntermNode* falseBlock; +}; + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +// +// For traversing the tree. User should derive from this, +// put their traversal specific data in it, and then pass +// it to a Traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +// +class TIntermTraverser +{ +public: + POOL_ALLOCATOR_NEW_DELETE(); + TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : + preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + rightToLeft(rightToLeft), + depth(0), + maxDepth(0) {} + virtual ~TIntermTraverser() {} + + virtual void visitSymbol(TIntermSymbol*) {} + virtual void visitRaw(TIntermRaw*) {} + virtual void visitConstantUnion(TIntermConstantUnion*) {} + virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} + virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} + virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} + virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} + virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} + virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} + + int getMaxDepth() const {return maxDepth;} + + void incrementDepth(TIntermNode *current) + { + depth++; + maxDepth = std::max(maxDepth, depth); + path.push_back(current); + } + + void decrementDepth() + { + depth--; + path.pop_back(); + } + + TIntermNode *getParentNode() + { + return path.size() == 0 ? NULL : path.back(); + } + + // Return the original name if hash function pointer is NULL; + // otherwise return the hashed name. + static TString hash(const TString& name, ShHashFunction64 hashFunction); + + const bool preVisit; + const bool inVisit; + const bool postVisit; + const bool rightToLeft; + +protected: + int depth; + int maxDepth; + + // All the nodes from root to the current node's parent during traversing. + TVector<TIntermNode *> path; +}; + +// +// For traversing the tree, and computing max depth. +// Takes a maximum depth limit to prevent stack overflow. +// +class TMaxDepthTraverser : public TIntermTraverser +{ +public: + POOL_ALLOCATOR_NEW_DELETE(); + TMaxDepthTraverser(int depthLimit) + : TIntermTraverser(true, true, false, false), + depthLimit(depthLimit) + {} + + virtual bool visitBinary(Visit visit, TIntermBinary*) { return depthCheck(); } + virtual bool visitUnary(Visit visit, TIntermUnary*) { return depthCheck(); } + virtual bool visitSelection(Visit visit, TIntermSelection*) { return depthCheck(); } + virtual bool visitAggregate(Visit visit, TIntermAggregate*) { return depthCheck(); } + virtual bool visitLoop(Visit visit, TIntermLoop*) { return depthCheck(); } + virtual bool visitBranch(Visit visit, TIntermBranch*) { return depthCheck(); } + +protected: + int depthLimit; + + bool depthCheck() const { return maxDepth < depthLimit; } +}; + +#endif // __INTERMEDIATE_H diff --git a/chromium/third_party/angle/src/compiler/translator/length_limits.h b/chromium/third_party/angle/src/compiler/translator/length_limits.h new file mode 100644 index 00000000000..df70ee5d84a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/length_limits.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2011-2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// length_limits.h +// + +#if !defined(__LENGTH_LIMITS_H) +#define __LENGTH_LIMITS_H 1 + +#include "GLSLANG/ShaderLang.h" + +// These constants are factored out from the rest of the headers to +// make it easier to reference them from the compiler sources. + +size_t GetGlobalMaxTokenSize(ShShaderSpec spec); + +#endif // !(defined(__LENGTH_LIMITS_H) diff --git a/chromium/third_party/angle/src/compiler/translator/localintermediate.h b/chromium/third_party/angle/src/compiler/translator/localintermediate.h new file mode 100644 index 00000000000..125dcd989a2 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/localintermediate.h @@ -0,0 +1,55 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef _LOCAL_INTERMEDIATE_INCLUDED_ +#define _LOCAL_INTERMEDIATE_INCLUDED_ + +#include "compiler/translator/intermediate.h" + +struct TVectorFields { + int offsets[4]; + int num; +}; + +// +// Set of helper functions to help parse and build the tree. +// +class TInfoSink; +class TIntermediate { +public: + POOL_ALLOCATOR_NEW_DELETE(); + TIntermediate(TInfoSink& i) : infoSink(i) { } + + TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&); + TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); + TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); + TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); + TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&); + TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, const TSourceLoc&); + TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); + TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); + TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, const TSourceLoc&); + TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&); + TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&); + TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&); + TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, const TSourceLoc&); + TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; + bool parseConstTree(const TSourceLoc&, TIntermNode*, ConstantUnion*, TOperator, TType, bool singleConstantParam = false); + TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, const TSourceLoc&); + TIntermBranch* addBranch(TOperator, const TSourceLoc&); + TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&); + TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&); + bool postProcess(TIntermNode*); + void remove(TIntermNode*); + void outputTree(TIntermNode*); + +private: + void operator=(TIntermediate&); // prevent assignments + + TInfoSink& infoSink; +}; + +#endif // _LOCAL_INTERMEDIATE_INCLUDED_ diff --git a/chromium/third_party/angle/src/compiler/translator/osinclude.h b/chromium/third_party/angle/src/compiler/translator/osinclude.h new file mode 100644 index 00000000000..c3063d624a8 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/osinclude.h @@ -0,0 +1,66 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains contains os-specific datatypes and +// declares any os-specific functions. +// + +#if defined(_WIN32) || defined(_WIN64) +#define ANGLE_OS_WIN +#elif defined(__APPLE__) || defined(__linux__) || \ + defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__sun) || defined(ANDROID) || \ + defined(__GLIBC__) || defined(__GNU__) || \ + defined(__QNX__) +#define ANGLE_OS_POSIX +#else +#error Unsupported platform. +#endif + +#if defined(ANGLE_OS_WIN) +#define STRICT +#define VC_EXTRALEAN 1 +#include <windows.h> +#elif defined(ANGLE_OS_POSIX) +#include <pthread.h> +#include <semaphore.h> +#include <errno.h> +#endif // ANGLE_OS_WIN + + +#include "compiler/translator/compilerdebug.h" + +// +// Thread Local Storage Operations +// +#if defined(ANGLE_OS_WIN) +typedef DWORD OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) +#elif defined(ANGLE_OS_POSIX) +typedef pthread_key_t OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (static_cast<OS_TLSIndex>(-1)) +#endif // ANGLE_OS_WIN + +OS_TLSIndex OS_AllocTLSIndex(); +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); +bool OS_FreeTLSIndex(OS_TLSIndex nIndex); + +inline void* OS_GetTLSValue(OS_TLSIndex nIndex) +{ + ASSERT(nIndex != OS_INVALID_TLS_INDEX); +#if defined(ANGLE_OS_WIN) + return TlsGetValue(nIndex); +#elif defined(ANGLE_OS_POSIX) + return pthread_getspecific(nIndex); +#endif // ANGLE_OS_WIN +} + +#endif // __OSINCLUDE_H diff --git a/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp b/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp new file mode 100644 index 00000000000..90a37574441 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ossource_posix.cpp @@ -0,0 +1,64 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// +// This file contains the posix specific functions +// +#include "compiler/translator/osinclude.h" + +#if !defined(ANGLE_OS_POSIX) +#error Trying to build a posix specific file in a non-posix build. +#endif + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + pthread_key_t pPoolIndex; + + // + // Create global pool key. + // + if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return false; + } + else { + return pPoolIndex; + } +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (pthread_setspecific(nIndex, lpvValue) == 0) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + // + // Delete the global pool key. + // + if (pthread_key_delete(nIndex) == 0) + return true; + else + return false; +} diff --git a/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp b/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp new file mode 100644 index 00000000000..2cc5871b71d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ossource_win.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/osinclude.h" +// +// This file contains contains the window's specific functions +// + +#if !defined(ANGLE_OS_WIN) +#error Trying to build a windows specific file in a non windows build. +#endif + + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + DWORD dwIndex = TlsAlloc(); + if (dwIndex == TLS_OUT_OF_INDEXES) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + + return dwIndex; +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsSetValue(nIndex, lpvValue)) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsFree(nIndex)) + return true; + else + return false; +} diff --git a/chromium/third_party/angle/src/compiler/translator/parseConst.cpp b/chromium/third_party/angle/src/compiler/translator/parseConst.cpp new file mode 100644 index 00000000000..33617e53d9a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/parseConst.cpp @@ -0,0 +1,251 @@ +// +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/ParseContext.h" + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TConstTraverser : public TIntermTraverser { +public: + TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TType& t) + : error(false), + index(0), + unionArray(cUnion), + type(t), + constructorType(constructType), + singleConstantParam(singleConstParam), + infoSink(sink), + size(0), + isDiagonalMatrixInit(false), + matrixCols(0), + matrixRows(0) { + } + + bool error; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + size_t index; + ConstantUnion *unionArray; + TType type; + TOperator constructorType; + bool singleConstantParam; + TInfoSink& infoSink; + size_t size; // size of the constructor ( 4 for vec4) + bool isDiagonalMatrixInit; + int matrixCols; // columns of the matrix + int matrixRows; // rows of the matrix +}; + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TConstTraverser::visitSymbol(TIntermSymbol* node) +{ + infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor"); + return; + +} + +bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TQualifier qualifier = node->getType().getQualifier(); + + if (qualifier != EvqConst) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + error = true; + return false; + } + + infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor"); + + return false; +} + +bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + error = true; + return false; +} + +bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + if (!node->isConstructor() && node->getOp() != EOpComma) { + TString buf; + buf.append("'constructor' : assigning non-constant to "); + buf.append(type.getCompleteString()); + infoSink.info.message(EPrefixError, node->getLine(), buf.c_str()); + error = true; + return false; + } + + if (node->getSequence().size() == 0) { + error = true; + return false; + } + + bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); + if (flag) + { + singleConstantParam = true; + constructorType = node->getOp(); + size = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) { + isDiagonalMatrixInit = true; + matrixCols = node->getType().getCols(); + matrixRows = node->getType().getRows(); + } + } + + for (TIntermSequence::iterator p = node->getSequence().begin(); + p != node->getSequence().end(); p++) { + + if (node->getOp() == EOpComma) + index = 0; + + (*p)->traverse(this); + } + if (flag) + { + singleConstantParam = false; + constructorType = EOpNull; + size = 0; + isDiagonalMatrixInit = false; + matrixCols = 0; + matrixRows = 0; + } + return false; +} + +bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor"); + error = true; + return false; +} + +void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + if (!node->getUnionArrayPointer()) + { + // The constant was not initialized, this should already have been logged + assert(infoSink.info.size() != 0); + return; + } + + ConstantUnion* leftUnionArray = unionArray; + size_t instanceSize = type.getObjectSize(); + + if (index >= instanceSize) + return; + + if (!singleConstantParam) { + size_t objectSize = node->getType().getObjectSize(); + + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + for (size_t i=0; i < objectSize; i++) { + if (index >= instanceSize) + return; + leftUnionArray[index] = rightUnionArray[i]; + + (index)++; + } + } else { + size_t totalSize = index + size; + ConstantUnion *rightUnionArray = node->getUnionArrayPointer(); + if (!isDiagonalMatrixInit) { + int count = 0; + for (size_t i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + + leftUnionArray[i] = rightUnionArray[count]; + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } + else + { + // for matrix diagonal constructors from a single scalar + for (int i = 0, col = 0; col < matrixCols; col++) + { + for (int row = 0; row < matrixRows; row++, i++) + { + if (col == row) + { + leftUnionArray[i] = rightUnionArray[0]; + } + else + { + leftUnionArray[i].setFConst(0.0f); + } + + (index)++; + } + } + } + } +} + +bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor"); + error = true; + return false; +} + +bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor"); + error = true; + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TType t, bool singleConstantParam) +{ + if (root == 0) + return false; + + TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, t); + + root->traverse(&it); + if (it.error) + return true; + else + return false; +} diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp new file mode 100644 index 00000000000..48d44c72d17 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp @@ -0,0 +1,136 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/ParseContext.h" +#include "compiler/translator/depgraph/DependencyGraphOutput.h" +#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" + +RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) + : mSink(sink) + , mNumErrors(0) +{ + // Sampling ops found only in fragment shaders. + mSamplingOps.insert("texture2D(s21;vf2;f1;"); + mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); + mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); + mSamplingOps.insert("textureCube(sC1;vf3;f1;"); + // Sampling ops found in both vertex and fragment shaders. + mSamplingOps.insert("texture2D(s21;vf2;"); + mSamplingOps.insert("texture2DProj(s21;vf3;"); + mSamplingOps.insert("texture2DProj(s21;vf4;"); + mSamplingOps.insert("textureCube(sC1;vf3;"); + // Sampling ops provided by OES_EGL_image_external. + mSamplingOps.insert("texture2D(1;vf2;"); + mSamplingOps.insert("texture2DProj(1;vf3;"); + mSamplingOps.insert("texture2DProj(1;vf4;"); + // Sampling ops provided by ARB_texture_rectangle. + mSamplingOps.insert("texture2DRect(1;vf2;"); + mSamplingOps.insert("texture2DRectProj(1;vf3;"); + mSamplingOps.insert("texture2DRectProj(1;vf4;"); + // Sampling ops provided by EXT_shader_texture_lod. + mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;"); + mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;"); + mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;"); + mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;"); + mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;"); + mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;"); + mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;"); + mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;"); +} + +// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. +// can vary based on the value of the input arguments. If so, we should restrict those as well. +void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) +{ + mNumErrors = 0; + + // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, + // so we generate errors for them. + validateUserDefinedFunctionCallUsage(graph); + + // Starting from each sampler, traverse the dependency graph and generate an error each time we + // hit a node where sampler dependent values are not allowed. + for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols(); + iter != graph.endSamplerSymbols(); + ++iter) + { + TGraphSymbol* samplerSymbol = *iter; + clearVisited(); + samplerSymbol->traverse(this); + } +} + +void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) +{ + for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); + iter != graph.endUserDefinedFunctionCalls(); + ++iter) + { + TGraphFunctionCall* functionCall = *iter; + beginError(functionCall->getIntermFunctionCall()); + mSink << "A call to a user defined function is not permitted.\n"; + } +} + +void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) +{ + ++mNumErrors; + mSink.prefix(EPrefixError); + mSink.location(node->getLine()); +} + +bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const +{ + return !intermFunctionCall->isUserDefined() && + mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); +} + +void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) +{ + // Texture cache access time might leak sensitive information. + // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a + // sampling operation. + if (isSamplingOp(parameter->getIntermFunctionCall())) { + switch (parameter->getArgumentNumber()) { + case 1: + // Second argument (coord) + beginError(parameter->getIntermFunctionCall()); + mSink << "An expression dependent on a sampler is not permitted to be the" + << " coordinate argument of a sampling operation.\n"; + break; + case 2: + // Third argument (bias) + beginError(parameter->getIntermFunctionCall()); + mSink << "An expression dependent on a sampler is not permitted to be the" + << " bias argument of a sampling operation.\n"; + break; + default: + // First argument (sampler) + break; + } + } +} + +void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) +{ + beginError(selection->getIntermSelection()); + mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; +} + +void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) +{ + beginError(loop->getIntermLoop()); + mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; +} + +void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) +{ + beginError(logicalOp->getIntermLogicalOp()); + mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " + << logicalOp->getOpString() + << " operator.\n"; +} diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h new file mode 100644 index 00000000000..e77d8c21cbc --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/depgraph/DependencyGraph.h" + +class TInfoSinkBase; + +class RestrictFragmentShaderTiming : TDependencyGraphTraverser { +public: + RestrictFragmentShaderTiming(TInfoSinkBase& sink); + void enforceRestrictions(const TDependencyGraph& graph); + int numErrors() const { return mNumErrors; } + + virtual void visitArgument(TGraphArgument* parameter); + virtual void visitSelection(TGraphSelection* selection); + virtual void visitLoop(TGraphLoop* loop); + virtual void visitLogicalOp(TGraphLogicalOp* logicalOp); + +private: + void beginError(const TIntermNode* node); + void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph); + bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const; + + TInfoSinkBase& mSink; + int mNumErrors; + + typedef std::set<TString> StringSet; + StringSet mSamplingOps; +}; + +#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp new file mode 100644 index 00000000000..7c1208a2986 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp @@ -0,0 +1,17 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/timing/RestrictVertexShaderTiming.h" + +void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node) +{ + if (IsSampler(node->getBasicType())) { + ++mNumErrors; + mSink.message(EPrefixError, + node->getLine(), + "Samplers are not permitted in vertex shaders.\n"); + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h new file mode 100644 index 00000000000..d461fbdbfea --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ + +#include "compiler/translator/intermediate.h" +#include "compiler/translator/InfoSink.h" + +class TInfoSinkBase; + +class RestrictVertexShaderTiming : public TIntermTraverser { +public: + RestrictVertexShaderTiming(TInfoSinkBase& sink) + : TIntermTraverser(true, false, false) + , mSink(sink) + , mNumErrors(0) {} + + void enforceRestrictions(TIntermNode* root) { root->traverse(this); } + int numErrors() { return mNumErrors; } + + virtual void visitSymbol(TIntermSymbol*); +private: + TInfoSinkBase& mSink; + int mNumErrors; +}; + +#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/util.cpp b/chromium/third_party/angle/src/compiler/translator/util.cpp new file mode 100644 index 00000000000..077bdcc48b8 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/util.cpp @@ -0,0 +1,28 @@ +// +// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/util.h" + +#include <limits> + +#include "compiler/preprocessor/numeric_lex.h" + +bool atof_clamp(const char *str, float *value) +{ + bool success = pp::numeric_lex_float(str, value); + if (!success) + *value = std::numeric_limits<float>::max(); + return success; +} + +bool atoi_clamp(const char *str, int *value) +{ + bool success = pp::numeric_lex_int(str, value); + if (!success) + *value = std::numeric_limits<int>::max(); + return success; +} + diff --git a/chromium/third_party/angle/src/compiler/translator/util.h b/chromium/third_party/angle/src/compiler/translator/util.h new file mode 100644 index 00000000000..dc69f39060d --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/util.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef COMPILER_UTIL_H +#define COMPILER_UTIL_H + +// atof_clamp is like atof but +// 1. it forces C locale, i.e. forcing '.' as decimal point. +// 2. it clamps the value to -FLT_MAX or FLT_MAX if overflow happens. +// Return false if overflow happens. +extern bool atof_clamp(const char *str, float *value); + +// If overflow happens, clamp the value to INT_MIN or INT_MAX. +// Return false if overflow happens. +extern bool atoi_clamp(const char *str, int *value); + +#endif // COMPILER_UTIL_H |