--- a/gfx/angle/BUILD.gn
+++ b/gfx/angle/BUILD.gn
@@ -492,33 +492,37 @@ util_gypi = exec_script("//build/gypi_to
config("angle_util_config") {
include_dirs = [ "util" ]
if (is_linux && use_x11) {
libs = [ "X11" ]
}
}
-static_library("angle_util") {
+shared_library("angle_util") {
sources = rebase_path(util_gypi.util_sources, ".", "util")
if (is_win) {
sources += rebase_path(util_gypi.util_win32_sources, ".", "util")
}
if (is_linux) {
sources += rebase_path(util_gypi.util_linux_sources, ".", "util")
libs = [
"rt",
"dl",
]
}
if (is_mac) {
sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
+ libs = [
+ "AppKit.framework",
+ "QuartzCore.framework",
+ ]
}
if (use_x11) {
sources += rebase_path(util_gypi.util_x11_sources, ".", "util")
}
if (is_android) {
# To prevent linux sources filtering on android
@@ -533,26 +537,34 @@ static_library("angle_util") {
if (use_ozone) {
sources += rebase_path(util_gypi.util_ozone_sources, ".", "util")
}
defines = [
"GL_GLEXT_PROTOTYPES",
"EGL_EGLEXT_PROTOTYPES",
+ "LIBANGLE_UTIL_IMPLEMENTATION",
]
configs += [
":debug_annotations_config",
":extra_warnings",
]
public_configs = [
":angle_util_config",
":internal_config",
]
+ if (is_mac && !is_component_build) {
+ ldflags = [
+ "-install_name",
+ "@rpath/lib${target_name}.dylib",
+ ]
+ public_configs += [ ":shared_library_public_config" ]
+ }
deps = [
":angle_common",
":libEGL",
":libGLESv2",
]
}
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -44,49 +44,28 @@ typedef unsigned int GLenum;
}
// Must be included after GLenum proxy typedef
// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
#include "ShaderVars.h"
// Version number for shader translation API.
// It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 155
+#define ANGLE_SH_VERSION 161
typedef enum {
SH_GLES2_SPEC,
SH_WEBGL_SPEC,
SH_GLES3_SPEC,
SH_WEBGL2_SPEC,
SH_GLES3_1_SPEC,
SH_WEBGL3_SPEC,
- // The CSS Shaders spec is a subset of the WebGL spec.
- //
- // In both CSS vertex and fragment shaders, ANGLE:
- // (1) Reserves the "css_" prefix.
- // (2) Renames the main function to css_main.
- // (3) Disables the gl_MaxDrawBuffers built-in.
- //
- // In CSS fragment shaders, ANGLE:
- // (1) Disables the gl_FragColor built-in.
- // (2) Disables the gl_FragData built-in.
- // (3) Enables the css_MixColor built-in.
- // (4) Enables the css_ColorMatrix built-in.
- //
- // After passing a CSS shader through ANGLE, the browser is expected to append
- // a new main function to it.
- // This new main function will call the css_main function.
- // It may also perform additional operations like varying assignment, texture
- // access, and gl_FragColor assignment in order to implement the CSS Shaders
- // blend modes.
- //
- SH_CSS_SHADERS_SPEC
} ShShaderSpec;
typedef enum
{
// ESSL output only supported in some configurations.
SH_ESSL_OUTPUT = 0x8B45,
// GLSL output only supported in some configurations.
@@ -111,132 +90,119 @@ typedef enum
// Prefer using these to specify HLSL output type:
SH_HLSL_3_0_OUTPUT = 0x8B48, // D3D 9
SH_HLSL_4_1_OUTPUT = 0x8B49, // D3D 11
SH_HLSL_4_0_FL9_3_OUTPUT = 0x8B4A // D3D 11 feature level 9_3
} ShShaderOutput;
// Compile options.
-typedef enum {
- SH_VALIDATE = 0,
- SH_VALIDATE_LOOP_INDEXING = 0x0001,
- SH_INTERMEDIATE_TREE = 0x0002,
- SH_OBJECT_CODE = 0x0004,
- SH_VARIABLES = 0x0008,
- SH_LINE_DIRECTIVES = 0x0010,
- SH_SOURCE_PATH = 0x0020,
- SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
- // If a sampler array index happens to be a loop index,
- // 1) if its type is integer, unroll the loop.
- // 2) if its type is float, fail the shader compile.
- // This is to work around a mac driver bug.
- SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
+typedef uint64_t ShCompileOptions;
- // This is needed only as a workaround for certain OpenGL driver bugs.
- SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
+const ShCompileOptions SH_VALIDATE = 0;
+const ShCompileOptions SH_VALIDATE_LOOP_INDEXING = UINT64_C(1) << 0;
+const ShCompileOptions SH_INTERMEDIATE_TREE = UINT64_C(1) << 1;
+const ShCompileOptions SH_OBJECT_CODE = UINT64_C(1) << 2;
+const ShCompileOptions SH_VARIABLES = UINT64_C(1) << 3;
+const ShCompileOptions SH_LINE_DIRECTIVES = UINT64_C(1) << 4;
+const ShCompileOptions SH_SOURCE_PATH = UINT64_C(1) << 5;
+const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = UINT64_C(1) << 6;
+// If a sampler array index happens to be a loop index,
+// 1) if its type is integer, unroll the loop.
+// 2) if its type is float, fail the shader compile.
+// This is to work around a mac driver bug.
+const ShCompileOptions SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = UINT64_C(1) << 7;
- // This is an experimental flag to enforce restrictions that aim to prevent
- // timing attacks.
- // It generates compilation errors for shaders that could expose sensitive
- // texture information via the timing channel.
- // To use this flag, you must compile the shader under the WebGL spec
- // (using the SH_WEBGL_SPEC flag).
- SH_TIMING_RESTRICTIONS = 0x0200,
+// This flag works around bug in Intel Mac drivers related to abs(i) where
+// i is an integer.
+const ShCompileOptions SH_EMULATE_ABS_INT_FUNCTION = UINT64_C(1) << 8;
- // This flag prints the dependency graph that is used to enforce timing
- // restrictions on fragment shaders.
- // This flag only has an effect if all of the following are true:
- // - The shader spec is SH_WEBGL_SPEC.
- // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
- // - The shader type is GL_FRAGMENT_SHADER.
- SH_DEPENDENCY_GRAPH = 0x0400,
+// Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
+// This flag only enforces (and can only enforce) the packing
+// restrictions for uniform variables in both vertex and fragment
+// shaders. ShCheckVariablesWithinPackingLimits() lets embedders
+// enforce the packing restrictions for varying variables during
+// program link time.
+const ShCompileOptions SH_ENFORCE_PACKING_RESTRICTIONS = UINT64_C(1) << 9;
- // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
- // This flag only enforces (and can only enforce) the packing
- // restrictions for uniform variables in both vertex and fragment
- // shaders. ShCheckVariablesWithinPackingLimits() lets embedders
- // enforce the packing restrictions for varying variables during
- // program link time.
- SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
+// This flag ensures all indirect (expression-based) array indexing
+// is clamped to the bounds of the array. This ensures, for example,
+// that you cannot read off the end of a uniform, whether an array
+// vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
+// specified in the ShBuiltInResources when constructing the
+// compiler, selects the strategy for the clamping implementation.
+const ShCompileOptions SH_CLAMP_INDIRECT_ARRAY_BOUNDS = UINT64_C(1) << 10;
- // This flag ensures all indirect (expression-based) array indexing
- // is clamped to the bounds of the array. This ensures, for example,
- // that you cannot read off the end of a uniform, whether an array
- // vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
- // specified in the ShBuiltInResources when constructing the
- // compiler, selects the strategy for the clamping implementation.
- SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
+// This flag limits the complexity of an expression.
+const ShCompileOptions SH_LIMIT_EXPRESSION_COMPLEXITY = UINT64_C(1) << 11;
+
+// This flag limits the depth of the call stack.
+const ShCompileOptions SH_LIMIT_CALL_STACK_DEPTH = UINT64_C(1) << 12;
- // This flag limits the complexity of an expression.
- SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
-
- // This flag limits the depth of the call stack.
- SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
+// This flag initializes gl_Position to vec4(0,0,0,0) at the
+// beginning of the vertex shader's main(), and has no effect in the
+// fragment shader. It is intended as a workaround for drivers which
+// incorrectly fail to link programs if gl_Position is not written.
+const ShCompileOptions SH_INIT_GL_POSITION = UINT64_C(1) << 13;
- // This flag initializes gl_Position to vec4(0,0,0,0) at the
- // beginning of the vertex shader's main(), and has no effect in the
- // fragment shader. It is intended as a workaround for drivers which
- // incorrectly fail to link programs if gl_Position is not written.
- SH_INIT_GL_POSITION = 0x8000,
+// This flag replaces
+// "a && b" with "a ? b : false",
+// "a || b" with "a ? true : b".
+// This is to work around a MacOSX driver bug that |b| is executed
+// independent of |a|'s value.
+const ShCompileOptions SH_UNFOLD_SHORT_CIRCUIT = UINT64_C(1) << 14;
- // This flag replaces
- // "a && b" with "a ? b : false",
- // "a || b" with "a ? true : b".
- // This is to work around a MacOSX driver bug that |b| is executed
- // independent of |a|'s value.
- SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
+// This flag initializes output variables to 0 at the beginning of main().
+// It is to avoid undefined behaviors.
+const ShCompileOptions SH_INIT_OUTPUT_VARIABLES = UINT64_C(1) << 15;
- // This flag initializes output variables to 0 at the beginning of main().
- // It is to avoid undefined behaviors.
- SH_INIT_OUTPUT_VARIABLES = 0x20000,
- // TODO(zmo): obsolete, remove after ANGLE roll into Chromium.
- SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
+// This flag scalarizes vec/ivec/bvec/mat constructor args.
+// It is intended as a workaround for Linux/Mac driver bugs.
+const ShCompileOptions SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = UINT64_C(1) << 16;
- // This flag scalarizes vec/ivec/bvec/mat constructor args.
- // It is intended as a workaround for Linux/Mac driver bugs.
- SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
+// This flag overwrites a struct name with a unique prefix.
+// It is intended as a workaround for drivers that do not handle
+// struct scopes correctly, including all Mac drivers and Linux AMD.
+const ShCompileOptions SH_REGENERATE_STRUCT_NAMES = UINT64_C(1) << 17;
- // This flag overwrites a struct name with a unique prefix.
- // It is intended as a workaround for drivers that do not handle
- // struct scopes correctly, including all Mac drivers and Linux AMD.
- SH_REGENERATE_STRUCT_NAMES = 0x80000,
+// This flag makes the compiler not prune unused function early in the
+// compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
+// helps avoid bad shaders causing stack overflows.
+const ShCompileOptions SH_DONT_PRUNE_UNUSED_FUNCTIONS = UINT64_C(1) << 18;
- // This flag makes the compiler not prune unused function early in the
- // compilation process. Pruning coupled with SH_LIMIT_CALL_STACK_DEPTH
- // helps avoid bad shaders causing stack overflows.
- SH_DONT_PRUNE_UNUSED_FUNCTIONS = 0x100000,
+// This flag works around a bug in NVIDIA 331 series drivers related
+// to pow(x, y) where y is a constant vector.
+const ShCompileOptions SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = UINT64_C(1) << 19;
- // This flag works around a bug in NVIDIA 331 series drivers related
- // to pow(x, y) where y is a constant vector.
- SH_REMOVE_POW_WITH_CONSTANT_EXPONENT = 0x200000,
+// This flag works around bugs in Mac drivers related to do-while by
+// transforming them into an other construct.
+const ShCompileOptions SH_REWRITE_DO_WHILE_LOOPS = UINT64_C(1) << 20;
- // This flag works around bugs in Mac drivers related to do-while by
- // transforming them into an other construct.
- SH_REWRITE_DO_WHILE_LOOPS = 0x400000,
+// This flag works around a bug in the HLSL compiler optimizer that folds certain
+// constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
+// by expanding the integer pow expressions into a series of multiplies.
+const ShCompileOptions SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = UINT64_C(1) << 21;
- // This flag works around a bug in the HLSL compiler optimizer that folds certain
- // constant pow expressions incorrectly. Only applies to the HLSL back-end. It works
- // by expanding the integer pow expressions into a series of multiplies.
- SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS = 0x800000,
-
- // Flatten "#pragma STDGL invariant(all)" into the declarations of
- // varying variables and built-in GLSL variables. This compiler
- // option is enabled automatically when needed.
- SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = 0x1000000,
+// Flatten "#pragma STDGL invariant(all)" into the declarations of
+// varying variables and built-in GLSL variables. This compiler
+// option is enabled automatically when needed.
+const ShCompileOptions SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL = UINT64_C(1) << 22;
- // Some drivers do not take into account the base level of the texture in the results of the
- // HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
- // offsetting.
- SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = 0x2000000,
+// Some drivers do not take into account the base level of the texture in the results of the
+// HLSL GetDimensions builtin. This flag instructs the compiler to manually add the base level
+// offsetting.
+const ShCompileOptions SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL = UINT64_C(1) << 23;
- // This flag works around an issue in translating GLSL function texelFetchOffset on
- // INTEL drivers. It works by translating texelFetchOffset into texelFetch.
- SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = 0x4000000,
-} ShCompileOptions;
+// This flag works around an issue in translating GLSL function texelFetchOffset on
+// INTEL drivers. It works by translating texelFetchOffset into texelFetch.
+const ShCompileOptions SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH = UINT64_C(1) << 24;
+
+// This flag works around condition bug of for and while loops in Intel Mac OSX drivers.
+// Condition calculation is not correct. Rewrite it from "CONDITION" to "CONDITION && true".
+const ShCompileOptions SH_ADD_AND_TRUE_TO_LOOP_CONDITION = UINT64_C(1) << 25;
// Defines alternate strategies for implementing array index clamping.
typedef enum {
// Use the clamp intrinsic for array index clamping.
SH_CLAMP_WITH_CLAMP_INTRINSIC = 1,
// Use a user-defined function for array index clamping.
SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION
@@ -460,21 +426,20 @@ COMPILER_EXPORT void ShDestruct(ShHandle
// compiling for WebGL - it is implied.
// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
// Can be queried by calling ShGetInfoLog().
// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
// Can be queried by calling ShGetObjectCode().
// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
// Can be queried by calling ShGetVariableInfo().
//
-COMPILER_EXPORT bool ShCompile(
- const ShHandle handle,
- const char * const shaderStrings[],
- size_t numStrings,
- int compileOptions);
+COMPILER_EXPORT bool ShCompile(const ShHandle handle,
+ const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions);
// Clears the results from the previous compilation.
COMPILER_EXPORT void ShClearResults(const ShHandle handle);
// Return the version of the shader language.
COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle);
// Return the currently set language output type.
--- a/gfx/angle/include/export.h
+++ b/gfx/angle/include/export.h
@@ -5,23 +5,25 @@
//
// export.h : Defines ANGLE_EXPORT, a macro for exporting functions from the DLL
#ifndef LIBGLESV2_EXPORT_H_
#define LIBGLESV2_EXPORT_H_
#if defined(_WIN32)
-# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION)
+#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \
+ defined(LIBANGLE_UTIL_IMPLEMENTATION)
# define ANGLE_EXPORT __declspec(dllexport)
# else
# define ANGLE_EXPORT __declspec(dllimport)
# endif
#elif defined(__GNUC__)
-# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION)
+#if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) || \
+ defined(LIBANGLE_UTIL_IMPLEMENTATION)
# define ANGLE_EXPORT __attribute__((visibility ("default")))
# else
# define ANGLE_EXPORT
# endif
#else
# define ANGLE_EXPORT
#endif
--- a/gfx/angle/moz.build
+++ b/gfx/angle/moz.build
@@ -23,33 +23,32 @@ UNIFIED_SOURCES += [
'src/compiler/preprocessor/ExpressionParser.cpp',
'src/compiler/preprocessor/Input.cpp',
'src/compiler/preprocessor/Lexer.cpp',
'src/compiler/preprocessor/Macro.cpp',
'src/compiler/preprocessor/MacroExpander.cpp',
'src/compiler/preprocessor/Preprocessor.cpp',
'src/compiler/preprocessor/Token.cpp',
'src/compiler/preprocessor/Tokenizer.cpp',
+ 'src/compiler/translator/AddAndTrueToLoopCondition.cpp',
'src/compiler/translator/AddDefaultReturnStatements.cpp',
'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
'src/compiler/translator/ASTMetadataHLSL.cpp',
'src/compiler/translator/blocklayout.cpp',
'src/compiler/translator/blocklayoutHLSL.cpp',
+ 'src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
'src/compiler/translator/BuiltInFunctionEmulator.cpp',
'src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
'src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
'src/compiler/translator/Cache.cpp',
'src/compiler/translator/CallDAG.cpp',
'src/compiler/translator/CodeGen.cpp',
'src/compiler/translator/Compiler.cpp',
+ 'src/compiler/translator/ConstantUnion.cpp',
'src/compiler/translator/DeferGlobalInitializers.cpp',
- 'src/compiler/translator/depgraph/DependencyGraph.cpp',
- 'src/compiler/translator/depgraph/DependencyGraphBuilder.cpp',
- 'src/compiler/translator/depgraph/DependencyGraphOutput.cpp',
- 'src/compiler/translator/depgraph/DependencyGraphTraverse.cpp',
'src/compiler/translator/Diagnostics.cpp',
'src/compiler/translator/DirectiveHandler.cpp',
'src/compiler/translator/EmulatePrecision.cpp',
'src/compiler/translator/ExpandIntegerPowExpressions.cpp',
'src/compiler/translator/ExtensionGLSL.cpp',
'src/compiler/translator/FlagStd140Structs.cpp',
'src/compiler/translator/ForLoopUnroll.cpp',
'src/compiler/translator/InfoSink.cpp',
@@ -66,16 +65,17 @@ UNIFIED_SOURCES += [
'src/compiler/translator/Operator.cpp',
'src/compiler/translator/OutputESSL.cpp',
'src/compiler/translator/OutputGLSL.cpp',
'src/compiler/translator/OutputGLSLBase.cpp',
'src/compiler/translator/OutputHLSL.cpp',
'src/compiler/translator/ParseContext.cpp',
'src/compiler/translator/PoolAlloc.cpp',
'src/compiler/translator/PruneEmptyDeclarations.cpp',
+ 'src/compiler/translator/QualifierTypes.cpp',
'src/compiler/translator/RecordConstantPrecision.cpp',
'src/compiler/translator/RegenerateStructNames.cpp',
'src/compiler/translator/RemoveDynamicIndexing.cpp',
'src/compiler/translator/RemovePow.cpp',
'src/compiler/translator/RemoveSwitchFallThrough.cpp',
'src/compiler/translator/RewriteDoWhile.cpp',
'src/compiler/translator/RewriteElseBlocks.cpp',
'src/compiler/translator/RewriteTexelFetchOffset.cpp',
@@ -86,18 +86,16 @@ UNIFIED_SOURCES += [
'src/compiler/translator/SeparateExpressionsReturningArrays.cpp',
'src/compiler/translator/ShaderLang.cpp',
'src/compiler/translator/ShaderVars.cpp',
'src/compiler/translator/SimplifyLoopConditions.cpp',
'src/compiler/translator/SplitSequenceOperator.cpp',
'src/compiler/translator/StructureHLSL.cpp',
'src/compiler/translator/SymbolTable.cpp',
'src/compiler/translator/TextureFunctionHLSL.cpp',
- 'src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
- 'src/compiler/translator/timing/RestrictVertexShaderTiming.cpp',
'src/compiler/translator/TranslatorESSL.cpp',
'src/compiler/translator/TranslatorGLSL.cpp',
'src/compiler/translator/TranslatorHLSL.cpp',
'src/compiler/translator/Types.cpp',
'src/compiler/translator/UnfoldShortCircuitAST.cpp',
'src/compiler/translator/UnfoldShortCircuitToIf.cpp',
'src/compiler/translator/UniformHLSL.cpp',
'src/compiler/translator/util.cpp',
--- a/gfx/angle/src/commit.h
+++ b/gfx/angle/src/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH ""
-#define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE ""
+#define ANGLE_COMMIT_HASH "8b3e8b4d1b09"
+#define ANGLE_COMMIT_HASH_SIZE 12
+#define ANGLE_COMMIT_DATE "2016-10-24 15:38:47 +0800"
--- a/gfx/angle/src/compiler.gypi
+++ b/gfx/angle/src/compiler.gypi
@@ -17,27 +17,32 @@
'../include/GLES3/gl3.h',
'../include/GLES3/gl3platform.h',
'../include/GLES3/gl31.h',
'../include/GLES3/gl32.h',
'../include/GLSLANG/ShaderLang.h',
'../include/GLSLANG/ShaderVars.h',
'../include/KHR/khrplatform.h',
'../include/angle_gl.h',
+ 'compiler/translator/AddAndTrueToLoopCondition.cpp',
+ 'compiler/translator/AddAndTrueToLoopCondition.h',
'compiler/translator/BaseTypes.h',
'compiler/translator/BuiltInFunctionEmulator.cpp',
'compiler/translator/BuiltInFunctionEmulator.h',
+ 'compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
+ 'compiler/translator/BreakVariableAliasingInInnerLoops.h',
'compiler/translator/Cache.cpp',
'compiler/translator/Cache.h',
'compiler/translator/CallDAG.cpp',
'compiler/translator/CallDAG.h',
'compiler/translator/CodeGen.cpp',
'compiler/translator/Common.h',
'compiler/translator/Compiler.cpp',
'compiler/translator/Compiler.h',
+ 'compiler/translator/ConstantUnion.cpp',
'compiler/translator/ConstantUnion.h',
'compiler/translator/DeferGlobalInitializers.cpp',
'compiler/translator/DeferGlobalInitializers.h',
'compiler/translator/Diagnostics.cpp',
'compiler/translator/Diagnostics.h',
'compiler/translator/DirectiveHandler.cpp',
'compiler/translator/DirectiveHandler.h',
'compiler/translator/EmulateGLFragColorBroadcast.cpp',
@@ -76,27 +81,28 @@
'compiler/translator/Operator.h',
'compiler/translator/ParseContext.cpp',
'compiler/translator/ParseContext.h',
'compiler/translator/PoolAlloc.cpp',
'compiler/translator/PoolAlloc.h',
'compiler/translator/Pragma.h',
'compiler/translator/PruneEmptyDeclarations.cpp',
'compiler/translator/PruneEmptyDeclarations.h',
+ 'compiler/translator/QualifierTypes.h',
+ 'compiler/translator/QualifierTypes.cpp',
'compiler/translator/RecordConstantPrecision.cpp',
'compiler/translator/RecordConstantPrecision.h',
'compiler/translator/RegenerateStructNames.cpp',
'compiler/translator/RegenerateStructNames.h',
'compiler/translator/RemovePow.cpp',
'compiler/translator/RemovePow.h',
'compiler/translator/RewriteDoWhile.cpp',
'compiler/translator/RewriteDoWhile.h',
'compiler/translator/RewriteTexelFetchOffset.cpp',
'compiler/translator/RewriteTexelFetchOffset.h',
- 'compiler/translator/RenameFunction.h',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
'compiler/translator/SearchSymbol.cpp',
'compiler/translator/SearchSymbol.h',
'compiler/translator/SymbolTable.cpp',
'compiler/translator/SymbolTable.h',
'compiler/translator/Types.cpp',
'compiler/translator/Types.h',
@@ -113,35 +119,24 @@
'compiler/translator/ValidateSwitch.cpp',
'compiler/translator/ValidateSwitch.h',
'compiler/translator/VariableInfo.cpp',
'compiler/translator/VariableInfo.h',
'compiler/translator/VariablePacker.cpp',
'compiler/translator/VariablePacker.h',
'compiler/translator/blocklayout.cpp',
'compiler/translator/blocklayout.h',
- 'compiler/translator/depgraph/DependencyGraph.cpp',
- 'compiler/translator/depgraph/DependencyGraph.h',
- 'compiler/translator/depgraph/DependencyGraphBuilder.cpp',
- 'compiler/translator/depgraph/DependencyGraphBuilder.h',
- 'compiler/translator/depgraph/DependencyGraphOutput.cpp',
- 'compiler/translator/depgraph/DependencyGraphOutput.h',
- 'compiler/translator/depgraph/DependencyGraphTraverse.cpp',
'compiler/translator/glslang.h',
'compiler/translator/glslang.l',
'compiler/translator/glslang.y',
'compiler/translator/glslang_lex.cpp',
'compiler/translator/glslang_tab.cpp',
'compiler/translator/glslang_tab.h',
'compiler/translator/intermOut.cpp',
'compiler/translator/length_limits.h',
- 'compiler/translator/timing/RestrictFragmentShaderTiming.cpp',
- 'compiler/translator/timing/RestrictFragmentShaderTiming.h',
- 'compiler/translator/timing/RestrictVertexShaderTiming.cpp',
- 'compiler/translator/timing/RestrictVertexShaderTiming.h',
'compiler/translator/util.cpp',
'compiler/translator/util.h',
'third_party/compiler/ArrayBoundsClamper.cpp',
'third_party/compiler/ArrayBoundsClamper.h',
],
'angle_translator_lib_essl_sources':
[
'compiler/translator/OutputESSL.cpp',
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2016 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/AddAndTrueToLoopCondition.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that rewrites for and while loops by replacing "condition" with
+// "condition && true" to work around condition bug on Intel Mac.
+class AddAndTrueToLoopConditionTraverser : public TIntermTraverser
+{
+ public:
+ AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {}
+
+ bool visitLoop(Visit, TIntermLoop *loop) override
+ {
+ // do-while loop doesn't have this bug.
+ if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile)
+ {
+ return true;
+ }
+
+ // For loop may not have a condition.
+ if (loop->getCondition() == nullptr)
+ {
+ return true;
+ }
+
+ // Constant true.
+ TConstantUnion *trueConstant = new TConstantUnion();
+ trueConstant->setBConst(true);
+ TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, TType(EbtBool));
+
+ // CONDITION && true.
+ TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue);
+ loop->setCondition(andOp);
+
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void AddAndTrueToLoopCondition(TIntermNode *root)
+{
+ AddAndTrueToLoopConditionTraverser traverser;
+ root->traverse(&traverser);
+}
+
+} // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/AddAndTrueToLoopCondition.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// Rewrite condition in for and while loops to work around driver bug on Intel Mac.
+
+#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
+#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void AddAndTrueToLoopCondition(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
--- a/gfx/angle/src/compiler/translator/AddDefaultReturnStatements.cpp
+++ b/gfx/angle/src/compiler/translator/AddDefaultReturnStatements.cpp
@@ -49,58 +49,23 @@ class AddDefaultReturnStatementsTraverse
if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
{
return false;
}
return true;
}
- static TIntermTyped *GenerateTypeConstructor(const TType &returnType)
- {
- // Base case, constructing a single element
- if (!returnType.isArray())
- {
- size_t objectSize = returnType.getObjectSize();
- TConstantUnion *constantUnion = new TConstantUnion[objectSize];
- for (size_t constantIdx = 0; constantIdx < objectSize; constantIdx++)
- {
- constantUnion[constantIdx].setFConst(0.0f);
- }
-
- TIntermConstantUnion *intermConstantUnion =
- new TIntermConstantUnion(constantUnion, returnType);
- return intermConstantUnion;
- }
-
- // Recursive case, construct an array of single elements
- TIntermAggregate *constructorAggrigate =
- new TIntermAggregate(TypeToConstructorOperator(returnType));
- constructorAggrigate->setType(returnType);
-
- size_t arraySize = returnType.getArraySize();
- for (size_t arrayIdx = 0; arrayIdx < arraySize; arrayIdx++)
- {
- TType arrayElementType(returnType);
- arrayElementType.clearArrayness();
-
- constructorAggrigate->getSequence()->push_back(
- GenerateTypeConstructor(arrayElementType));
- }
-
- return constructorAggrigate;
- }
-
bool visitAggregate(Visit, TIntermAggregate *node) override
{
TType returnType;
if (IsFunctionWithoutReturnStatement(node, &returnType))
{
TIntermBranch *branch =
- new TIntermBranch(EOpReturn, GenerateTypeConstructor(returnType));
+ new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType));
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
lastNode->getSequence()->push_back(branch);
return false;
}
return true;
--- a/gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/gfx/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -162,22 +162,21 @@ bool ArrayReturnValueToOutParameterTrave
bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
{
if (mInFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn)
{
// Instead of returning a value, assign to the out parameter and then return.
TIntermSequence replacements;
- TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign);
TIntermTyped *expression = node->getExpression();
ASSERT(expression != nullptr);
- replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType()));
- replacementAssignment->setRight(node->getExpression());
- replacementAssignment->setType(expression->getType());
+ TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
+ TIntermBinary *replacementAssignment =
+ new TIntermBinary(EOpAssign, returnValueSymbol, expression);
replacementAssignment->setLine(expression->getLine());
replacements.push_back(replacementAssignment);
TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr);
replacementBranch->setLine(node->getLine());
replacements.push_back(replacementBranch);
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsAggregate(), node, replacements));
--- a/gfx/angle/src/compiler/translator/BaseTypes.h
+++ b/gfx/angle/src/compiler/translator/BaseTypes.h
@@ -336,20 +336,21 @@ enum TQualifier
EvqSecondaryFragColorEXT, // EXT_blend_func_extended
EvqSecondaryFragDataEXT, // EXT_blend_func_extended
// built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor,
EvqLastFragData,
// GLSL ES 3.0 vertex output and fragment input
- EvqSmooth, // Incomplete qualifier, smooth is the default
- EvqFlat, // Incomplete qualifier
- EvqSmoothOut = EvqSmooth,
- EvqFlatOut = EvqFlat,
+ EvqSmooth, // Incomplete qualifier, smooth is the default
+ EvqFlat, // Incomplete qualifier
+ EvqCentroid, // Incomplete qualifier
+ EvqSmoothOut,
+ EvqFlatOut,
EvqCentroidOut, // Implies smooth
EvqSmoothIn,
EvqFlatIn,
EvqCentroidIn, // Implies smooth
// GLSL ES 3.1 compute shader special variables
EvqComputeIn,
EvqNumWorkGroups,
@@ -358,16 +359,21 @@ enum TQualifier
EvqLocalInvocationID,
EvqGlobalInvocationID,
EvqLocalInvocationIndex,
// end of list
EvqLast
};
+inline bool IsQualifierUnspecified(TQualifier qualifier)
+{
+ return (qualifier == EvqTemporary || qualifier == EvqGlobal);
+}
+
enum TLayoutMatrixPacking
{
EmpUnspecified,
EmpRowMajor,
EmpColumnMajor
};
enum TLayoutBlockStorage
@@ -376,27 +382,29 @@ enum TLayoutBlockStorage
EbsShared,
EbsPacked,
EbsStd140
};
struct TLayoutQualifier
{
int location;
+ unsigned int locationsSpecified;
TLayoutMatrixPacking matrixPacking;
TLayoutBlockStorage blockStorage;
// Compute shader layout qualifiers.
sh::WorkGroupSize localSize;
static TLayoutQualifier create()
{
TLayoutQualifier layoutQualifier;
layoutQualifier.location = -1;
+ layoutQualifier.locationsSpecified = 0;
layoutQualifier.matrixPacking = EmpUnspecified;
layoutQualifier.blockStorage = EbsUnspecified;
layoutQualifier.localSize.fill(-1);
return layoutQualifier;
}
@@ -477,16 +485,19 @@ inline const char* getQualifierString(TQ
case EvqLastFragColor: return "LastFragColor";
case EvqLastFragData: return "LastFragData";
case EvqSmoothOut: return "smooth out";
case EvqCentroidOut: return "smooth centroid out";
case EvqFlatOut: return "flat out";
case EvqSmoothIn: return "smooth in";
case EvqFlatIn: return "flat in";
case EvqCentroidIn: return "smooth centroid in";
+ case EvqCentroid: return "centroid";
+ case EvqFlat: return "flat";
+ case EvqSmooth: return "smooth";
case EvqComputeIn: return "in";
case EvqNumWorkGroups: return "NumWorkGroups";
case EvqWorkGroupSize: return "WorkGroupSize";
case EvqWorkGroupID: return "WorkGroupID";
case EvqLocalInvocationID: return "LocalInvocationID";
case EvqGlobalInvocationID: return "GlobalInvocationID";
case EvqLocalInvocationIndex: return "LocalInvocationIndex";
default: UNREACHABLE(); return "unknown qualifier";
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+// may record a variable as aliasing another. Sometimes the alias information gets garbled
+// so we work around this issue by breaking the aliasing chain in inner loops.
+
+#include "BreakVariableAliasingInInnerLoops.h"
+
+#include "compiler/translator/IntermNode.h"
+
+// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
+// The root problem is that if the HLSL compiler is applying aliasing information even on
+// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
+// that comes from a series of assignments, possibly with swizzled or ternary operators with
+// known conditionals, where the source is before the loop.
+// So, a workaround is to add a +0 term to variables the first time they are assigned to in
+// an inner loop (if they are declared in an outside scope, otherwise there is no need).
+// This will break the aliasing chain.
+
+// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
+// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
+// assignment don't need a workaround.
+
+namespace
+{
+
+class AliasingBreaker : public TIntermTraverser
+{
+ public:
+ AliasingBreaker() : TIntermTraverser(true, false, true) {}
+
+ protected:
+ bool visitBinary(Visit visit, TIntermBinary *binary)
+ {
+ if (visit != PreVisit)
+ {
+ return false;
+ }
+
+ if (mLoopLevel < 2 || !binary->isAssignment())
+ {
+ return true;
+ }
+
+ TIntermTyped *B = binary->getRight();
+ TType type = B->getType();
+
+ if (!type.isScalar() && !type.isVector() && !type.isMatrix())
+ {
+ return true;
+ }
+
+ if (type.isArray() || IsSampler(type.getBasicType()))
+ {
+ return true;
+ }
+
+ // We have a scalar / vector / matrix assignment with loop depth 2.
+ // Transform it from
+ // A = B
+ // to
+ // A = (B + typeof<B>(0));
+
+ TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, TIntermTyped::CreateZero(type));
+ bPlusZero->setLine(B->getLine());
+
+ binary->replaceChildNode(B, bPlusZero);
+
+ return true;
+ }
+
+ bool visitLoop(Visit visit, TIntermLoop *loop)
+ {
+ if (visit == PreVisit)
+ {
+ mLoopLevel++;
+ }
+ else
+ {
+ ASSERT(mLoopLevel > 0);
+ mLoopLevel--;
+ }
+
+ return true;
+ }
+
+ private:
+ int mLoopLevel = 0;
+};
+
+} // anonymous namespace
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root)
+{
+ AliasingBreaker breaker;
+ root->traverse(&breaker);
+}
+
+} // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+// may record a variable as aliasing another. Sometimes the alias information gets garbled
+// so we work around this issue by breaking the aliasing chain in inner loops.
+
+#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
+#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
--- a/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -6,42 +6,24 @@
#include "angle_gl.h"
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
#include "compiler/translator/Cache.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
-void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType)
{
- // 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 TType *float1 = TCache::getType(EbtFloat);
- const TType *float2 = TCache::getType(EbtFloat, 2);
- const TType *float3 = TCache::getType(EbtFloat, 3);
- const TType *float4 = TCache::getType(EbtFloat, 4);
-
- if (shaderType == GL_FRAGMENT_SHADER)
+ if (shaderType == GL_VERTEX_SHADER)
{
- emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }");
- emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }");
+ const TType *int1 = TCache::getType(EbtInt);
+ emu->addEmulatedFunction(EOpAbs, int1, "int webgl_abs_emu(int x) { return x * sign(x); }");
}
- emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))");
- emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))");
- emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))");
- emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))");
- emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))");
- emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1, "#define webgl_faceforward_emu(N, I, Nref) (((Nref) * (I) < 0.0) ? (N) : -(N))");
}
// Emulate built-in functions missing from GLSL 1.30 and higher
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
int targetGLSLVersion)
{
// Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
if (targetGLSLVersion < GLSL_VERSION_410)
@@ -176,17 +158,19 @@ void InitBuiltInFunctionEmulatorForGLSLM
" return uintBitsToFloat(sign | 0x7F800000u | mantissa);\n"
" }\n"
" else\n"
" {\n"
" exponent -= 15;\n"
" float scale;\n"
" if(exponent < 0)\n"
" {\n"
- " scale = 1.0 / (1 << -exponent);\n"
+ " // The negative unary operator is buggy on OSX.\n"
+ " // Work around this by using abs instead.\n"
+ " scale = 1.0 / (1 << abs(exponent));\n"
" }\n"
" else\n"
" {\n"
" scale = 1 << exponent;\n"
" }\n"
" float decimal = 1.0 + float(mantissa) / float(1 << 10);\n"
" f32 = scale * decimal;\n"
" }\n"
--- a/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
+++ b/gfx/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h
@@ -7,19 +7,20 @@
#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
#include "GLSLANG/ShaderLang.h"
class BuiltInFunctionEmulator;
//
-// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
+// This works around bug in Intel Mac drivers.
//
-void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType);
+void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
+ sh::GLenum shaderType);
//
// This function is emulating built-in functions missing from GLSL 1.30 and higher.
//
void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType,
int targetGLSLVersion);
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_
--- a/gfx/angle/src/compiler/translator/Compiler.cpp
+++ b/gfx/angle/src/compiler/translator/Compiler.cpp
@@ -1,47 +1,42 @@
//
// 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/AddAndTrueToLoopCondition.h"
#include "compiler/translator/Cache.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/DeferGlobalInitializers.h"
#include "compiler/translator/EmulateGLFragColorBroadcast.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/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
#include "compiler/translator/RemovePow.h"
-#include "compiler/translator/RenameFunction.h"
#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
#include "compiler/translator/UnfoldShortCircuitAST.h"
#include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.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"
#include "angle_gl.h"
#include "common/utilities.h"
bool IsWebGLBasedSpec(ShShaderSpec spec)
{
- return (spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC || spec == SH_WEBGL2_SPEC ||
- spec == SH_WEBGL3_SPEC);
+ return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
}
bool IsGLSL130OrNewer(ShShaderOutput output)
{
return (output == SH_GLSL_130_OUTPUT ||
output == SH_GLSL_140_OUTPUT ||
output == SH_GLSL_150_CORE_OUTPUT ||
output == SH_GLSL_330_CORE_OUTPUT ||
@@ -55,17 +50,16 @@ bool IsGLSL130OrNewer(ShShaderOutput out
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.
switch (spec)
{
case SH_WEBGL_SPEC:
- case SH_CSS_SHADERS_SPEC:
return 256;
default:
return 1024;
}
}
namespace {
@@ -106,17 +100,16 @@ class TScopedSymbolTableLevel
};
int MapSpecToShaderVersion(ShShaderSpec spec)
{
switch (spec)
{
case SH_GLES2_SPEC:
case SH_WEBGL_SPEC:
- case SH_CSS_SHADERS_SPEC:
return 100;
case SH_GLES3_SPEC:
case SH_WEBGL2_SPEC:
return 300;
case SH_GLES3_1_SPEC:
case SH_WEBGL3_SPEC:
return 310;
default:
@@ -157,17 +150,17 @@ TCompiler::TCompiler(sh::GLenum type, Sh
{
mComputeShaderLocalSize.fill(1);
}
TCompiler::~TCompiler()
{
}
-bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const
+bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
{
// If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
// validate loop and indexing as well (to verify that the shader only uses minimal functionality
// of ESSL 1.00 as in Appendix A of the spec).
return (IsWebGLBasedSpec(shaderSpec) && shaderVersion == 100) ||
(compileOptions & SH_VALIDATE_LOOP_INDEXING);
}
@@ -192,25 +185,26 @@ bool TCompiler::Init(const ShBuiltInReso
arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
clampingStrategy = resources.ArrayIndexClampingStrategy;
hashFunction = resources.HashFunction;
return true;
}
-TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
- size_t numStrings, int compileOptions)
+TIntermNode *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions)
{
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
- const int compileOptions)
+ const ShCompileOptions compileOptions)
{
clearResults();
ASSERT(numStrings > 0);
ASSERT(GetGlobalPoolAllocator());
// Reset the extension behavior for each compilation unit.
ResetExtensionBehavior(extensionBehavior);
@@ -218,18 +212,17 @@ TIntermNode *TCompiler::compileTreeImpl(
// First string is path of source file if flag is set. The actual source follows.
size_t firstSource = 0;
if (compileOptions & SH_SOURCE_PATH)
{
mSourcePath = shaderStrings[0];
++firstSource;
}
- TIntermediate intermediate(infoSink);
- TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
+ TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(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);
@@ -253,17 +246,17 @@ TIntermNode *TCompiler::compileTreeImpl(
{
mPragma = parseContext.pragma();
symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot();
- root = intermediate.postProcess(root);
+ root = TIntermediate::PostProcess(root);
// Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
// Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
@@ -290,22 +283,16 @@ TIntermNode *TCompiler::compileTreeImpl(
PruneEmptyDeclarations(root);
if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
success = validateOutputs(root);
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
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,
shouldRunLoopAndIndexingValidation(compileOptions));
root->traverse(&marker);
}
if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
@@ -340,16 +327,19 @@ TIntermNode *TCompiler::compileTreeImpl(
((compileOptions & SH_INIT_GL_POSITION) ||
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
initializeGLPosition(root);
// This pass might emit short circuits so keep it before the short circuit unfolding
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
RewriteDoWhile(root, getTemporaryIndex());
+ if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION))
+ sh::AddAndTrueToLoopCondition(root);
+
if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
{
UnfoldShortCircuitAST unfoldShortCircuit;
root->traverse(&unfoldShortCircuit);
unfoldShortCircuit.updateTree();
}
if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT))
@@ -403,22 +393,24 @@ TIntermNode *TCompiler::compileTreeImpl(
SetGlobalParseContext(NULL);
if (success)
return root;
return NULL;
}
-bool TCompiler::compile(const char *const shaderStrings[], size_t numStrings, int compileOptionsIn)
+bool TCompiler::compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptionsIn)
{
if (numStrings == 0)
return true;
- int compileOptions = compileOptionsIn;
+ ShCompileOptions compileOptions = compileOptionsIn;
// Apply key workarounds.
if (shouldFlattenPragmaStdglInvariantAll())
{
// This should be harmless to do in all cases, but for the moment, do it only conditionally.
compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
}
@@ -447,25 +439,23 @@ bool TCompiler::InitBuiltInSymbolTable(c
assert(symbolTable.isEmpty());
symbolTable.push(); // COMMON_BUILTINS
symbolTable.push(); // ESSL1_BUILTINS
symbolTable.push(); // ESSL3_BUILTINS
symbolTable.push(); // ESSL3_1_BUILTINS
TPublicType integer;
- integer.type = EbtInt;
- integer.primarySize = 1;
- integer.secondarySize = 1;
+ integer.setBasicType(EbtInt);
+ integer.initializeSizeForScalarTypes();
integer.array = false;
TPublicType floatingPoint;
- floatingPoint.type = EbtFloat;
- floatingPoint.primarySize = 1;
- floatingPoint.secondarySize = 1;
+ floatingPoint.setBasicType(EbtFloat);
+ floatingPoint.initializeSizeForScalarTypes();
floatingPoint.array = false;
switch(shaderType)
{
case GL_FRAGMENT_SHADER:
symbolTable.setDefaultPrecision(integer, EbpMedium);
break;
case GL_VERTEX_SHADER:
@@ -495,20 +485,19 @@ bool TCompiler::InitBuiltInSymbolTable(c
return true;
}
void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
{
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
TPublicType sampler;
- sampler.primarySize = 1;
- sampler.secondarySize = 1;
+ sampler.initializeSizeForScalarTypes();
+ sampler.setBasicType(samplerType);
sampler.array = false;
- sampler.type = samplerType;
symbolTable.setDefaultPrecision(sampler, EbpLow);
}
void TCompiler::setResourceString()
{
std::ostringstream strstream;
// clang-format off
@@ -758,59 +747,23 @@ bool TCompiler::pruneUnusedFunctions(TIn
bool TCompiler::validateOutputs(TIntermNode* root)
{
ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
root->traverse(&validateOutputs);
return (validateOutputs.validateAndCountErrors(infoSink.info) == 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 == GL_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.";
@@ -821,30 +774,16 @@ bool TCompiler::limitExpressionComplexit
{
infoSink.info << "Function has too many parameters.";
return false;
}
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)
{
if (!variablesCollected)
{
sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings,
&interfaceBlocks, hashFunction, symbolTable, extensionBehavior);
root->traverse(&collect);
@@ -915,17 +854,17 @@ ShArrayIndexClampingStrategy TCompiler::
return clampingStrategy;
}
const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
-void TCompiler::writePragma(int compileOptions)
+void TCompiler::writePragma(ShCompileOptions compileOptions)
{
if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
{
TInfoSinkBase &sink = infoSink.obj;
if (mPragma.stdgl.invariantAll)
sink << "#pragma STDGL invariant(all)\n";
}
}
--- a/gfx/angle/src/compiler/translator/Compiler.h
+++ b/gfx/angle/src/compiler/translator/Compiler.h
@@ -20,24 +20,22 @@
#include "compiler/translator/HashNames.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/Pragma.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VariableInfo.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
class TCompiler;
-class TDependencyGraph;
#ifdef ANGLE_ENABLE_HLSL
class TranslatorHLSL;
#endif // ANGLE_ENABLE_HLSL
//
-// Helper function to identify specs that are based on the WebGL spec,
-// like the CSS Shaders spec.
+// Helper function to identify specs that are based on the WebGL spec.
//
bool IsWebGLBasedSpec(ShShaderSpec spec);
//
// Helper function to check if the shader type is GLSL.
//
bool IsGLSL130OrNewer(ShShaderOutput output);
@@ -70,21 +68,23 @@ class TCompiler : public TShHandleBase
~TCompiler() override;
TCompiler *getAsCompiler() override { return this; }
bool Init(const ShBuiltInResources& resources);
// compileTreeForTesting should be used only when tests require access to
// the AST. Users of this function need to manually manage the global pool
// allocator. Returns NULL whenever there are compilation errors.
- TIntermNode *compileTreeForTesting(const char* const shaderStrings[],
- size_t numStrings, int compileOptions);
+ TIntermNode *compileTreeForTesting(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions);
- bool compile(const char* const shaderStrings[],
- size_t numStrings, int compileOptions);
+ bool compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions);
// Get results of the last compilation.
int getShaderVersion() const { return shaderVersion; }
TInfoSink& getInfoSink() { return infoSink; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
const sh::WorkGroupSize &getComputeShaderLocalSize() { return mComputeShaderLocalSize; }
@@ -99,76 +99,68 @@ class TCompiler : public TShHandleBase
ShHashFunction64 getHashFunction() const { return hashFunction; }
NameMap& getNameMap() { return nameMap; }
TSymbolTable& getSymbolTable() { return symbolTable; }
ShShaderSpec getShaderSpec() const { return shaderSpec; }
ShShaderOutput getOutputType() const { return outputType; }
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
- bool shouldRunLoopAndIndexingValidation(int compileOptions) const;
+ bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
// Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources& getResources() const;
protected:
sh::GLenum 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();
// Return false if the call depth is exceeded.
bool checkCallDepth();
// 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);
// Add emulated functions to the built-in function emulator.
- virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {};
+ virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu,
+ ShCompileOptions compileOptions){};
// Translate to object code.
- virtual void translate(TIntermNode *root, int compileOptions) = 0;
+ virtual void translate(TIntermNode *root, ShCompileOptions compileOptions) = 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 output variables in the beginning of main().
// This is to avoid undefined behaviors.
void initializeOutputVariables(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;
const char *getSourcePath() const;
const TPragma& getPragma() const { return mPragma; }
- void writePragma(int compileOptions);
+ void writePragma(ShCompileOptions compileOptions);
unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
// Relies on collectVariables having been called.
bool isVaryingDefined(const char *varyingName);
const ArrayBoundsClamper& getArrayBoundsClamper() const;
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
- virtual bool shouldCollectVariables(int compileOptions)
+ virtual bool shouldCollectVariables(ShCompileOptions compileOptions)
{
return (compileOptions & SH_VARIABLES) != 0;
}
virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
std::vector<sh::Attribute> attributes;
std::vector<sh::OutputVariable> outputVariables;
@@ -188,17 +180,17 @@ class TCompiler : public TShHandleBase
void initSamplerDefaultPrecision(TBasicType samplerType);
// Removes unused function declarations and prototypes from the AST
class UnusedPredicate;
bool pruneUnusedFunctions(TIntermNode *root);
TIntermNode *compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
- const int compileOptions);
+ const ShCompileOptions compileOptions);
sh::GLenum shaderType;
ShShaderSpec shaderSpec;
ShShaderOutput outputType;
struct FunctionMetadata
{
FunctionMetadata()
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/translator/ConstantUnion.cpp
@@ -0,0 +1,443 @@
+//
+// Copyright 2016 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.
+//
+// ConstantUnion: Constant folding helper class.
+
+#include "compiler/translator/ConstantUnion.h"
+
+#include "compiler/translator/Diagnostics.h"
+
+TConstantUnion::TConstantUnion()
+{
+ iConst = 0;
+ type = EbtVoid;
+}
+
+bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
+{
+ switch (newType)
+ {
+ case EbtFloat:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setFConst(static_cast<float>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setFConst(static_cast<float>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setFConst(static_cast<float>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ setFConst(static_cast<float>(constant.getFConst()));
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtInt:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setIConst(static_cast<int>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setIConst(static_cast<int>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setIConst(static_cast<int>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ setIConst(static_cast<int>(constant.getFConst()));
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtUInt:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setUConst(static_cast<unsigned int>(constant.getIConst()));
+ break;
+ case EbtUInt:
+ setUConst(static_cast<unsigned int>(constant.getUConst()));
+ break;
+ case EbtBool:
+ setUConst(static_cast<unsigned int>(constant.getBConst()));
+ break;
+ case EbtFloat:
+ setUConst(static_cast<unsigned int>(constant.getFConst()));
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtBool:
+ switch (constant.type)
+ {
+ case EbtInt:
+ setBConst(constant.getIConst() != 0);
+ break;
+ case EbtUInt:
+ setBConst(constant.getUConst() != 0);
+ break;
+ case EbtBool:
+ setBConst(constant.getBConst());
+ break;
+ case EbtFloat:
+ setBConst(constant.getFConst() != 0.0f);
+ break;
+ default:
+ return false;
+ }
+ break;
+ case EbtStruct: // Struct fields don't get cast
+ switch (constant.type)
+ {
+ case EbtInt:
+ setIConst(constant.getIConst());
+ break;
+ case EbtUInt:
+ setUConst(constant.getUConst());
+ break;
+ case EbtBool:
+ setBConst(constant.getBConst());
+ break;
+ case EbtFloat:
+ setFConst(constant.getFConst());
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool TConstantUnion::operator==(const int i) const
+{
+ return i == iConst;
+}
+
+bool TConstantUnion::operator==(const unsigned int u) const
+{
+ return u == uConst;
+}
+
+bool TConstantUnion::operator==(const float f) const
+{
+ return f == fConst;
+}
+
+bool TConstantUnion::operator==(const bool b) const
+{
+ return b == bConst;
+}
+
+bool TConstantUnion::operator==(const TConstantUnion &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 TConstantUnion::operator!=(const int i) const
+{
+ return !operator==(i);
+}
+
+bool TConstantUnion::operator!=(const unsigned int u) const
+{
+ return !operator==(u);
+}
+
+bool TConstantUnion::operator!=(const float f) const
+{
+ return !operator==(f);
+}
+
+bool TConstantUnion::operator!=(const bool b) const
+{
+ return !operator==(b);
+}
+
+bool TConstantUnion::operator!=(const TConstantUnion &constant) const
+{
+ return !operator==(constant);
+}
+
+bool TConstantUnion::operator>(const TConstantUnion &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 TConstantUnion::operator<(const TConstantUnion &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
+ }
+}
+
+// static
+TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(lhs.iConst + rhs.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(lhs.uConst + rhs.uConst);
+ break;
+ case EbtFloat:
+ returnValue.setFConst(lhs.fConst + rhs.fConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(lhs.iConst - rhs.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(lhs.uConst - rhs.uConst);
+ break;
+ case EbtFloat:
+ returnValue.setFConst(lhs.fConst - rhs.fConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+// static
+TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag)
+{
+ TConstantUnion returnValue;
+ ASSERT(lhs.type == rhs.type);
+ switch (lhs.type)
+ {
+ case EbtInt:
+ returnValue.setIConst(lhs.iConst * rhs.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(lhs.uConst * rhs.uConst);
+ break;
+ case EbtFloat:
+ returnValue.setFConst(lhs.fConst * rhs.fConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst % constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst % constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator>>(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst >> constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst >> constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator<<(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ // The signedness of the second parameter might be different, but we
+ // don't care, since the result is undefined if the second parameter is
+ // negative, and aliasing should not be a problem with unions.
+ ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst << constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst << constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst & constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst & constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst | constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst | constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtInt:
+ returnValue.setIConst(iConst ^ constant.iConst);
+ break;
+ case EbtUInt:
+ returnValue.setUConst(uConst ^ constant.uConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtBool:
+ returnValue.setBConst(bConst && constant.bConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
+
+TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
+{
+ TConstantUnion returnValue;
+ ASSERT(type == constant.type);
+ switch (type)
+ {
+ case EbtBool:
+ returnValue.setBConst(bConst || constant.bConst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return returnValue;
+}
--- a/gfx/angle/src/compiler/translator/ConstantUnion.h
+++ b/gfx/angle/src/compiler/translator/ConstantUnion.h
@@ -4,345 +4,74 @@
// found in the LICENSE file.
//
#ifndef COMPILER_TRANSLATOR_CONSTANTUNION_H_
#define COMPILER_TRANSLATOR_CONSTANTUNION_H_
#include <assert.h>
+#include "compiler/translator/Common.h"
#include "compiler/translator/BaseTypes.h"
-class TConstantUnion {
-public:
- POOL_ALLOCATOR_NEW_DELETE();
- TConstantUnion()
- {
- iConst = 0;
- type = EbtVoid;
- }
+class TDiagnostics;
- bool cast(TBasicType newType, const TConstantUnion &constant)
- {
- switch (newType)
- {
- case EbtFloat:
- switch (constant.type)
- {
- case EbtInt: setFConst(static_cast<float>(constant.getIConst())); break;
- case EbtUInt: setFConst(static_cast<float>(constant.getUConst())); break;
- case EbtBool: setFConst(static_cast<float>(constant.getBConst())); break;
- case EbtFloat: setFConst(static_cast<float>(constant.getFConst())); break;
- default: return false;
- }
- break;
- case EbtInt:
- switch (constant.type)
- {
- case EbtInt: setIConst(static_cast<int>(constant.getIConst())); break;
- case EbtUInt: setIConst(static_cast<int>(constant.getUConst())); break;
- case EbtBool: setIConst(static_cast<int>(constant.getBConst())); break;
- case EbtFloat: setIConst(static_cast<int>(constant.getFConst())); break;
- default: return false;
- }
- break;
- case EbtUInt:
- switch (constant.type)
- {
- case EbtInt: setUConst(static_cast<unsigned int>(constant.getIConst())); break;
- case EbtUInt: setUConst(static_cast<unsigned int>(constant.getUConst())); break;
- case EbtBool: setUConst(static_cast<unsigned int>(constant.getBConst())); break;
- case EbtFloat: setUConst(static_cast<unsigned int>(constant.getFConst())); break;
- default: return false;
- }
- break;
- case EbtBool:
- switch (constant.type)
- {
- case EbtInt: setBConst(constant.getIConst() != 0); break;
- case EbtUInt: setBConst(constant.getUConst() != 0); break;
- case EbtBool: setBConst(constant.getBConst()); break;
- case EbtFloat: setBConst(constant.getFConst() != 0.0f); break;
- default: return false;
- }
- break;
- case EbtStruct: // Struct fields don't get cast
- switch (constant.type)
- {
- case EbtInt: setIConst(constant.getIConst()); break;
- case EbtUInt: setUConst(constant.getUConst()); break;
- case EbtBool: setBConst(constant.getBConst()); break;
- case EbtFloat: setFConst(constant.getFConst()); break;
- default: return false;
- }
- break;
- default:
- return false;
- }
+class TConstantUnion
+{
+ public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TConstantUnion();
- return true;
- }
+ bool cast(TBasicType newType, const TConstantUnion &constant);
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 TConstantUnion& 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 TConstantUnion& constant) const
- {
- return !operator==(constant);
- }
-
- bool operator>(const TConstantUnion& 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 TConstantUnion& 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
- }
- }
-
- TConstantUnion operator+(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator-(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator*(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator%(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator>>(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator<<(const TConstantUnion& constant) const
- {
- TConstantUnion returnValue;
- // The signedness of the second parameter might be different, but we
- // don't care, since the result is undefined if the second parameter is
- // negative, and aliasing should not be a problem with unions.
- assert(constant.type == EbtInt || constant.type == EbtUInt);
- 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;
- }
-
- TConstantUnion operator&(const TConstantUnion& constant) const
- {
- TConstantUnion returnValue;
- assert(constant.type == EbtInt || constant.type == EbtUInt);
- 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;
- }
-
- TConstantUnion operator|(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator^(const TConstantUnion& constant) const
- {
- TConstantUnion 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;
- }
-
- TConstantUnion operator&&(const TConstantUnion& constant) const
- {
- TConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
-
- TConstantUnion operator||(const TConstantUnion& constant) const
- {
- TConstantUnion returnValue;
- assert(type == constant.type);
- switch (type) {
- case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
- default: assert(false && "Default missing");
- }
-
- return returnValue;
- }
+ bool operator==(const int i) const;
+ bool operator==(const unsigned int u) const;
+ bool operator==(const float f) const;
+ bool operator==(const bool b) const;
+ bool operator==(const TConstantUnion &constant) const;
+ bool operator!=(const int i) const;
+ bool operator!=(const unsigned int u) const;
+ bool operator!=(const float f) const;
+ bool operator!=(const bool b) const;
+ bool operator!=(const TConstantUnion &constant) const;
+ bool operator>(const TConstantUnion &constant) const;
+ bool operator<(const TConstantUnion &constant) const;
+ static TConstantUnion add(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag);
+ static TConstantUnion sub(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag);
+ static TConstantUnion mul(const TConstantUnion &lhs,
+ const TConstantUnion &rhs,
+ TDiagnostics *diag);
+ TConstantUnion operator%(const TConstantUnion &constant) const;
+ TConstantUnion operator>>(const TConstantUnion &constant) const;
+ TConstantUnion operator<<(const TConstantUnion &constant) const;
+ TConstantUnion operator&(const TConstantUnion &constant) const;
+ TConstantUnion operator|(const TConstantUnion &constant) const;
+ TConstantUnion operator^(const TConstantUnion &constant) const;
+ TConstantUnion operator&&(const TConstantUnion &constant) const;
+ TConstantUnion operator||(const TConstantUnion &constant) const;
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
- } ;
+ 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 // COMPILER_TRANSLATOR_CONSTANTUNION_H_
--- a/gfx/angle/src/compiler/translator/DeferGlobalInitializers.cpp
+++ b/gfx/angle/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -96,20 +96,18 @@ bool DeferGlobalInitializersTraverser::v
(expression->getAsConstantUnion() == nullptr &&
!expression->isConstructorWithOnlyConstantUnionParameters())))
{
// For variables which are not constant, defer their real initialization until
// after we initialize uniforms.
// Deferral is done also in any cases where the variable has not been constant folded,
// since otherwise there's a chance that HLSL output will generate extra statements
// from the initializer expression.
- TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
- deferredInit->setLeft(symbolNode->deepCopy());
- deferredInit->setRight(node->getRight());
- deferredInit->setType(node->getType());
+ TIntermBinary *deferredInit =
+ new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight());
mDeferredInitializers.push_back(deferredInit);
// Change const global to a regular global if its initialization is deferred.
// This can happen if ANGLE has not been able to fold the constant expression used
// as an initializer.
ASSERT(symbolNode->getQualifier() == EvqConst ||
symbolNode->getQualifier() == EvqGlobal);
if (symbolNode->getQualifier() == EvqConst)
--- a/gfx/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
+++ b/gfx/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -12,66 +12,64 @@
//
#include "compiler/translator/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/IntermNode.h"
namespace
{
-TIntermConstantUnion *constructIndexNode(int index)
-{
- TConstantUnion *u = new TConstantUnion[1];
- u[0].setIConst(index);
-
- TType type(EbtInt, EbpUndefined, EvqConst, 1);
- TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
- return node;
-}
-
-TIntermBinary *constructGLFragDataNode(int index)
-{
- TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
- TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", TType(EbtFloat, 4));
- indexDirect->setLeft(symbol);
- TIntermConstantUnion *indexNode = constructIndexNode(index);
- indexDirect->setRight(indexNode);
- return indexDirect;
-}
-
-TIntermBinary *constructGLFragDataAssignNode(int index)
-{
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
- assign->setLeft(constructGLFragDataNode(index));
- assign->setRight(constructGLFragDataNode(0));
- assign->setType(TType(EbtFloat, 4));
- return assign;
-}
-
class GLFragColorBroadcastTraverser : public TIntermTraverser
{
public:
- GLFragColorBroadcastTraverser()
- : TIntermTraverser(true, false, false), mMainSequence(nullptr), mGLFragColorUsed(false)
+ GLFragColorBroadcastTraverser(int maxDrawBuffers)
+ : TIntermTraverser(true, false, false),
+ mMainSequence(nullptr),
+ mGLFragColorUsed(false),
+ mMaxDrawBuffers(maxDrawBuffers)
{
}
- void broadcastGLFragColor(int maxDrawBuffers);
+ void broadcastGLFragColor();
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
protected:
void visitSymbol(TIntermSymbol *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+ TIntermBinary *constructGLFragDataNode(int index) const;
+ TIntermBinary *constructGLFragDataAssignNode(int index) const;
+
private:
TIntermSequence *mMainSequence;
bool mGLFragColorUsed;
+ int mMaxDrawBuffers;
};
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
+{
+ TType gl_FragDataType = TType(EbtFloat, EbpMedium, EvqFragData, 4);
+ gl_FragDataType.setArraySize(mMaxDrawBuffers);
+
+ TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", gl_FragDataType);
+ TIntermTyped *indexNode = TIntermTyped::CreateIndexNode(index);
+
+ TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode);
+ return binary;
+}
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const
+{
+ TIntermTyped *fragDataIndex = constructGLFragDataNode(index);
+ TIntermTyped *fragDataZero = constructGLFragDataNode(0);
+
+ return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero);
+}
+
void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
{
if (node->getSymbol() == "gl_FragColor")
{
queueReplacement(node, constructGLFragDataNode(0), OriginalNode::IS_DROPPED);
mGLFragColorUsed = true;
}
}
@@ -96,47 +94,47 @@ bool GLFragColorBroadcastTraverser::visi
}
break;
default:
break;
}
return true;
}
-void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
+void GLFragColorBroadcastTraverser::broadcastGLFragColor()
{
- ASSERT(maxDrawBuffers > 1);
+ ASSERT(mMaxDrawBuffers > 1);
if (!mGLFragColorUsed)
{
return;
}
ASSERT(mMainSequence);
// Now insert statements
// gl_FragData[1] = gl_FragData[0];
// ...
// gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
- for (int colorIndex = 1; colorIndex < maxDrawBuffers; ++colorIndex)
+ for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
{
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
}
}
} // namespace anonymous
void EmulateGLFragColorBroadcast(TIntermNode *root,
int maxDrawBuffers,
std::vector<sh::OutputVariable> *outputVariables)
{
ASSERT(maxDrawBuffers > 1);
- GLFragColorBroadcastTraverser traverser;
+ GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
root->traverse(&traverser);
if (traverser.isGLFragColorUsed())
{
traverser.updateTree();
- traverser.broadcastGLFragColor(maxDrawBuffers);
+ traverser.broadcastGLFragColor();
for (auto &var : *outputVariables)
{
if (var.name == "gl_FragColor")
{
// TODO(zmo): Find a way to keep the original variable information.
var.name = "gl_FragData";
var.mappedName = "gl_FragData";
var.arraySize = maxDrawBuffers;
--- a/gfx/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp
+++ b/gfx/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp
@@ -119,33 +119,28 @@ bool Traverser::visitAggregate(Visit vis
TIntermAggregate *init = createTempInitDeclaration(lhs);
TIntermTyped *current = createTempSymbol(lhs->getType());
insertStatementInParentBlock(init);
// Create a chain of n-1 multiples.
for (int i = 1; i < n; ++i)
{
- TIntermBinary *mul = new TIntermBinary(EOpMul);
- mul->setLeft(current);
- mul->setRight(createTempSymbol(lhs->getType()));
- mul->setType(node->getType());
+ TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType()));
mul->setLine(node->getLine());
current = mul;
}
// For negative pow, compute the reciprocal of the positive pow.
if (exponent < 0)
{
TConstantUnion *oneVal = new TConstantUnion();
oneVal->setFConst(1.0f);
TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
- TIntermBinary *div = new TIntermBinary(EOpDiv);
- div->setLeft(oneNode);
- div->setRight(current);
+ TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current);
current = div;
}
queueReplacement(node, current, OriginalNode::IS_DROPPED);
mFound = true;
return false;
}
--- a/gfx/angle/src/compiler/translator/Initialize.cpp
+++ b/gfx/angle/src/compiler/translator/Initialize.cpp
@@ -506,26 +506,23 @@ void InsertBuiltInFunctions(sh::GLenum t
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits",
resources.MaxTextureImageUnits, EbpMedium);
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors",
resources.MaxFragmentUniformVectors, EbpMedium);
symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
EbpMedium);
- if (spec != SH_CSS_SHADERS_SPEC)
+ symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
+ EbpMedium);
+ if (resources.EXT_blend_func_extended)
{
- symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
- EbpMedium);
- if (resources.EXT_blend_func_extended)
- {
- symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
- "gl_MaxDualSourceDrawBuffersEXT",
- resources.MaxDualSourceDrawBuffers);
- }
+ symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
+ "gl_MaxDualSourceDrawBuffersEXT",
+ resources.MaxDualSourceDrawBuffers);
}
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
resources.MaxVertexOutputVectors, EbpMedium);
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors",
resources.MaxFragmentInputVectors, EbpMedium);
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset",
resources.MinProgramTexelOffset, EbpMedium);
@@ -585,95 +582,83 @@ void IdentifyBuiltIns(sh::GLenum type, S
{
//
// Insert some special built-in variables that are not in
// the built-in header files.
//
switch (type)
{
case GL_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)));
+ {
+ 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)));
- TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
- fragData.setArraySize(resources.MaxDrawBuffers);
- symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
+ symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"),
+ TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData));
- if (resources.EXT_blend_func_extended)
- {
- symbolTable.insert(
- ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
- new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
- TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
- TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
- secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
- symbolTable.insert(
- ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
- new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
- }
+ if (resources.EXT_blend_func_extended)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragColorEXT"),
+ TType(EbtFloat, EbpMedium, EvqSecondaryFragColorEXT, 4)));
+ TType secondaryFragData(EbtFloat, EbpMedium, EvqSecondaryFragDataEXT, 4, 1, true);
+ secondaryFragData.setArraySize(resources.MaxDualSourceDrawBuffers);
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_blend_func_extended",
+ new TVariable(NewPoolTString("gl_SecondaryFragDataEXT"), secondaryFragData));
+ }
- if (resources.EXT_frag_depth)
- {
- symbolTable.insert(
- ESSL1_BUILTINS, "GL_EXT_frag_depth",
- new TVariable(
- NewPoolTString("gl_FragDepthEXT"),
- TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
- EvqFragDepthEXT, 1)));
- }
+ if (resources.EXT_frag_depth)
+ {
+ symbolTable.insert(
+ ESSL1_BUILTINS, "GL_EXT_frag_depth",
+ new TVariable(
+ NewPoolTString("gl_FragDepthEXT"),
+ TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
+ EvqFragDepthEXT, 1)));
+ }
- symbolTable.insert(ESSL3_BUILTINS,
- new TVariable(NewPoolTString("gl_FragDepth"),
- TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
+ symbolTable.insert(ESSL3_BUILTINS,
+ new TVariable(NewPoolTString("gl_FragDepth"),
+ TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
- if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
- {
- TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
- lastFragData.setArraySize(resources.MaxDrawBuffers);
+ if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
+ {
+ TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
+ lastFragData.setArraySize(resources.MaxDrawBuffers);
- if (resources.EXT_shader_framebuffer_fetch)
- {
- symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
- new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
- }
- else if (resources.NV_shader_framebuffer_fetch)
- {
- symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
- new TVariable(NewPoolTString("gl_LastFragColor"),
- TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
- symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
- new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
- }
- }
- else if (resources.ARM_shader_framebuffer_fetch)
- {
- symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
- new TVariable(NewPoolTString("gl_LastFragColorARM"),
- TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
- }
- }
- 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)));
- }
+ if (resources.EXT_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
+ }
+ else if (resources.NV_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragColor"),
+ TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
+ symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragData"), lastFragData));
+ }
+ }
+ else if (resources.ARM_shader_framebuffer_fetch)
+ {
+ symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch",
+ new TVariable(NewPoolTString("gl_LastFragColorARM"),
+ TType(EbtFloat, EbpMedium, EvqLastFragColor, 4)));
+ }
+ }
break;
case GL_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)));
--- a/gfx/angle/src/compiler/translator/InitializeVariables.cpp
+++ b/gfx/angle/src/compiler/translator/InitializeVariables.cpp
@@ -9,56 +9,16 @@
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/util.h"
namespace
{
-TIntermConstantUnion *constructConstUnionNode(const TType &type)
-{
- TType myType = type;
- myType.clearArrayness();
- myType.setQualifier(EvqConst);
- size_t size = myType.getObjectSize();
- TConstantUnion *u = new TConstantUnion[size];
- for (size_t ii = 0; ii < size; ++ii)
- {
- switch (type.getBasicType())
- {
- case EbtFloat:
- u[ii].setFConst(0.0f);
- break;
- case EbtInt:
- u[ii].setIConst(0);
- break;
- case EbtUInt:
- u[ii].setUConst(0u);
- break;
- default:
- UNREACHABLE();
- return nullptr;
- }
- }
-
- TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
- return node;
-}
-
-TIntermConstantUnion *constructIndexNode(int index)
-{
- TConstantUnion *u = new TConstantUnion[1];
- u[0].setIConst(index);
-
- TType type(EbtInt, EbpUndefined, EvqConst, 1);
- TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
- return node;
-}
-
class VariableInitializer : public TIntermTraverser
{
public:
VariableInitializer(const InitVariableList &vars)
: TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
{
}
@@ -115,83 +75,53 @@ bool VariableInitializer::visitAggregate
visitChildren = false;
break;
}
return visitChildren;
}
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
- for (size_t ii = 0; ii < mVariables.size(); ++ii)
+ for (const auto &var : mVariables)
{
- const sh::ShaderVariable &var = mVariables[ii];
TString name = TString(var.name.c_str());
+ TType type = sh::GetShaderVariableType(var);
+
+ // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
+ // doesn't have array assignment.
if (var.isArray())
{
- TType type = sh::ConvertShaderVariableTypeToTType(var.type);
size_t pos = name.find_last_of('[');
if (pos != TString::npos)
+ {
name = name.substr(0, pos);
- for (int index = static_cast<int>(var.arraySize) - 1; index >= 0; --index)
- {
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
- sequence->insert(sequence->begin(), assign);
-
- TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
- TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
- indexDirect->setLeft(symbol);
- TIntermConstantUnion *indexNode = constructIndexNode(index);
- indexDirect->setRight(indexNode);
-
- assign->setLeft(indexDirect);
-
- TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
- assign->setRight(zeroConst);
}
- }
- else if (var.isStruct())
- {
- TFieldList *fields = new TFieldList;
- TSourceLoc loc;
- for (auto field : var.fields)
- {
- fields->push_back(new TField(nullptr, new TString(field.name.c_str()), loc));
- }
- TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
- TType type;
- type.setStruct(structure);
- for (int fieldIndex = 0; fieldIndex < static_cast<int>(var.fields.size()); ++fieldIndex)
+ TType elementType = type;
+ elementType.clearArrayness();
+
+ for (unsigned int i = 0; i < var.arraySize; ++i)
{
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
- sequence->insert(sequence->begin(), assign);
+ TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type);
+ TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
+ TIntermTyped::CreateIndexNode(i));
- TIntermBinary *indexDirectStruct = new TIntermBinary(EOpIndexDirectStruct);
- TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
- indexDirectStruct->setLeft(symbol);
- TIntermConstantUnion *indexNode = constructIndexNode(fieldIndex);
- indexDirectStruct->setRight(indexNode);
- assign->setLeft(indexDirectStruct);
+ TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
+ TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
- const sh::ShaderVariable &field = var.fields[fieldIndex];
- TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type);
- TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType);
- assign->setRight(zeroConst);
+ sequence->insert(sequence->begin(), assignment);
}
}
else
{
- TType type = sh::ConvertShaderVariableTypeToTType(var.type);
- TIntermBinary *assign = new TIntermBinary(EOpAssign);
+ TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
+ TIntermTyped *zero = TIntermTyped::CreateZero(type);
+
+ TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
sequence->insert(sequence->begin(), assign);
- TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
- assign->setLeft(symbol);
- TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
- assign->setRight(zeroConst);
}
-
}
}
} // namespace anonymous
void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
{
VariableInitializer initializer(vars);
--- a/gfx/angle/src/compiler/translator/InitializeVariables.h
+++ b/gfx/angle/src/compiler/translator/InitializeVariables.h
@@ -8,11 +8,12 @@
#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
#include <GLSLANG/ShaderLang.h>
class TIntermNode;
typedef std::vector<sh::ShaderVariable> InitVariableList;
+// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend.
void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
--- a/gfx/angle/src/compiler/translator/IntermNode.cpp
+++ b/gfx/angle/src/compiler/translator/IntermNode.cpp
@@ -16,16 +16,17 @@
#include <vector>
#include "common/mathutil.h"
#include "common/matrix_utils.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/HashNames.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
namespace
{
const float kPi = 3.14159265358979323846f;
const float kDegreesToRadiansMultiplier = kPi / 180.0f;
const float kRadiansToDegreesMultiplier = 180.0f / kPi;
@@ -38,23 +39,24 @@ TConstantUnion *Vectorize(const TConstan
{
TConstantUnion *constUnion = new TConstantUnion[size];
for (unsigned int i = 0; i < size; ++i)
constUnion[i] = constant;
return constUnion;
}
-void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
- TInfoSink &infoSink, TConstantUnion *result)
+void UndefinedConstantFoldingError(const TSourceLoc &loc,
+ TOperator op,
+ TBasicType basicType,
+ TDiagnostics *diagnostics,
+ TConstantUnion *result)
{
- std::stringstream constantFoldingErrorStream;
- constantFoldingErrorStream << "'" << GetOperatorString(op)
- << "' operation result is undefined for the values passed in";
- infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
+ diagnostics->warning(loc, "operation result is undefined for the values passed in",
+ GetOperatorString(op), "");
switch (basicType)
{
case EbtFloat :
result->setFConst(0.0f);
break;
case EbtInt:
result->setIConst(0);
@@ -86,17 +88,17 @@ float VectorDotProduct(const TConstantUn
size_t paramArraySize)
{
float result = 0.0f;
for (size_t i = 0; i < paramArraySize; i++)
result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
return result;
}
-TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
+TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
const TIntermTyped *originalNode,
TQualifier qualifier)
{
if (constArray == nullptr)
{
return nullptr;
}
TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
@@ -185,16 +187,17 @@ bool TIntermBinary::replaceChildNode(
REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
return false;
}
bool TIntermUnary::replaceChildNode(
TIntermNode *original, TIntermNode *replacement)
{
+ ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
return false;
}
bool TIntermAggregate::replaceChildNode(
TIntermNode *original, TIntermNode *replacement)
{
for (size_t ii = 0; ii < mSequence.size(); ++ii)
@@ -284,16 +287,24 @@ void TIntermAggregate::setBuiltInFunctio
// ESSL 3.0 spec section 8: textureSize always gets highp precision.
// All other functions that take a sampler are assumed to be texture functions.
if (mName.getString().find("textureSize") == 0)
mType.setPrecision(EbpHigh);
else
mType.setPrecision(precision);
}
+bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
+{
+ REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
+ REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
+ return false;
+}
+
bool TIntermSelection::replaceChildNode(
TIntermNode *original, TIntermNode *replacement)
{
REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
return false;
}
@@ -331,16 +342,93 @@ bool TIntermTyped::isConstructorWithOnly
for (TIntermNode *&node : *constructor->getSequence())
{
if (!node->getAsConstantUnion())
return false;
}
return true;
}
+// static
+TIntermTyped *TIntermTyped::CreateIndexNode(int index)
+{
+ TConstantUnion *u = new TConstantUnion[1];
+ u[0].setIConst(index);
+
+ TType type(EbtInt, EbpUndefined, EvqConst, 1);
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+ return node;
+}
+
+// static
+TIntermTyped *TIntermTyped::CreateZero(const TType &type)
+{
+ TType constType(type);
+ constType.setQualifier(EvqConst);
+
+ if (!type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
+
+ size_t size = constType.getObjectSize();
+ TConstantUnion *u = new TConstantUnion[size];
+ for (size_t i = 0; i < size; ++i)
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ u[i].setFConst(0.0f);
+ break;
+ case EbtInt:
+ u[i].setIConst(0);
+ break;
+ case EbtUInt:
+ u[i].setUConst(0u);
+ break;
+ case EbtBool:
+ u[i].setBConst(false);
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+
+ TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
+ return node;
+ }
+
+ TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
+ constructor->setType(constType);
+
+ if (type.isArray())
+ {
+ TType elementType(type);
+ elementType.clearArrayness();
+
+ size_t arraySize = type.getArraySize();
+ for (size_t i = 0; i < arraySize; ++i)
+ {
+ constructor->getSequence()->push_back(CreateZero(elementType));
+ }
+ }
+ else
+ {
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ TStructure *structure = type.getStruct();
+ for (const auto &field : structure->fields())
+ {
+ constructor->getSequence()->push_back(CreateZero(*field->type()));
+ }
+ }
+
+ return constructor;
+}
+
TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
{
mUnionArrayPointer = node.mUnionArrayPointer;
}
TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
: TIntermOperator(node),
mName(node.mName),
@@ -371,30 +459,25 @@ TIntermBinary::TIntermBinary(const TInte
TIntermUnary::TIntermUnary(const TIntermUnary &node)
: TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
{
TIntermTyped *operandCopy = node.mOperand->deepCopy();
ASSERT(operandCopy != nullptr);
mOperand = operandCopy;
}
-TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
+TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
{
- // Only supported for ternary nodes, not if statements.
- TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
- TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
- ASSERT(trueTyped != nullptr);
- ASSERT(falseTyped != nullptr);
TIntermTyped *conditionCopy = node.mCondition->deepCopy();
- TIntermTyped *trueCopy = trueTyped->deepCopy();
- TIntermTyped *falseCopy = falseTyped->deepCopy();
+ TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
+ TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
- mCondition = conditionCopy;
- mTrueBlock = trueCopy;
- mFalseBlock = falseCopy;
+ mCondition = conditionCopy;
+ mTrueExpression = trueCopy;
+ mFalseExpression = falseCopy;
}
bool TIntermOperator::isAssignment() const
{
return IsAssignment(mOp);
}
bool TIntermOperator::isMultiplication() const
@@ -539,96 +622,190 @@ TOperator TIntermBinary::GetMulAssignOpB
}
}
}
//
// Make sure the type of a unary operator is appropriate for its
// combination of operation and operand type.
//
-void TIntermUnary::promote(const TType *funcReturnType)
+void TIntermUnary::promote()
{
+ TQualifier resultQualifier = EvqTemporary;
+ if (mOperand->getQualifier() == EvqConst)
+ resultQualifier = EvqConst;
+
+ unsigned char operandPrimarySize =
+ static_cast<unsigned char>(mOperand->getType().getNominalSize());
switch (mOp)
{
- case EOpFloatBitsToInt:
- case EOpFloatBitsToUint:
- case EOpIntBitsToFloat:
- case EOpUintBitsToFloat:
- case EOpPackSnorm2x16:
- case EOpPackUnorm2x16:
- case EOpPackHalf2x16:
- case EOpUnpackSnorm2x16:
- case EOpUnpackUnorm2x16:
- mType.setPrecision(EbpHigh);
- break;
- case EOpUnpackHalf2x16:
- mType.setPrecision(EbpMedium);
- break;
- default:
- setType(mOperand->getType());
+ case EOpFloatBitsToInt:
+ setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpFloatBitsToUint:
+ setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpIntBitsToFloat:
+ case EOpUintBitsToFloat:
+ setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
+ break;
+ case EOpPackSnorm2x16:
+ case EOpPackUnorm2x16:
+ case EOpPackHalf2x16:
+ setType(TType(EbtUInt, EbpHigh, resultQualifier));
+ break;
+ case EOpUnpackSnorm2x16:
+ case EOpUnpackUnorm2x16:
+ setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
+ break;
+ case EOpUnpackHalf2x16:
+ setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
+ break;
+ case EOpAny:
+ case EOpAll:
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
+ case EOpLength:
+ case EOpDeterminant:
+ setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
+ break;
+ case EOpTranspose:
+ setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
+ static_cast<unsigned char>(mOperand->getType().getRows()),
+ static_cast<unsigned char>(mOperand->getType().getCols())));
+ break;
+ case EOpIsInf:
+ case EOpIsNan:
+ setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
+ break;
+ default:
+ setType(mOperand->getType());
+ mType.setQualifier(resultQualifier);
+ break;
}
+}
- if (funcReturnType != nullptr)
- {
- if (funcReturnType->getBasicType() == EbtBool)
- {
- // Bool types should not have precision.
- setType(*funcReturnType);
- }
- else
- {
- // Precision of the node has been set based on the operand.
- setTypePreservePrecision(*funcReturnType);
- }
- }
-
- if (mOperand->getQualifier() == EvqConst)
- mType.setQualifier(EvqConst);
- else
- mType.setQualifier(EvqTemporary);
+TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
+ : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
+{
+ promote();
}
TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
: TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
{
promote();
}
+TIntermTernary::TIntermTernary(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+ : TIntermTyped(trueExpression->getType()),
+ mCondition(cond),
+ mTrueExpression(trueExpression),
+ mFalseExpression(falseExpression)
+{
+ getTypePointer()->setQualifier(
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
+}
+
+// static
+TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression)
+{
+ if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
+ falseExpression->getQualifier() == EvqConst)
+ {
+ return EvqConst;
+ }
+ return EvqTemporary;
+}
+
//
// Establishes the type of the resultant operation, as well as
// makes the operator the correct one for the operands.
//
// For lots of operations it should already be established that the operand
// combination is valid, but returns false if operator can't work on operands.
//
void TIntermBinary::promote()
{
- ASSERT(mLeft->isArray() == mRight->isArray());
-
ASSERT(!isMultiplication() ||
mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
// Base assumption: just make the type the same as the left
// operand. Then only deviations from this need be coded.
setType(mLeft->getType());
- // The result gets promoted to the highest precision.
- TPrecision higherPrecision = GetHigherPrecision(
- mLeft->getPrecision(), mRight->getPrecision());
- getTypePointer()->setPrecision(higherPrecision);
-
TQualifier resultQualifier = EvqConst;
// Binary operations results in temporary variables unless both
// operands are const.
if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
{
resultQualifier = EvqTemporary;
getTypePointer()->setQualifier(EvqTemporary);
}
+ // Handle indexing ops.
+ switch (mOp)
+ {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ if (mLeft->isArray())
+ {
+ mType.clearArrayness();
+ }
+ else if (mLeft->isMatrix())
+ {
+ setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
+ static_cast<unsigned char>(mLeft->getRows())));
+ }
+ else if (mLeft->isVector())
+ {
+ setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ return;
+ case EOpIndexDirectStruct:
+ {
+ const TFieldList &fields = mLeft->getType().getStruct()->fields();
+ const int i = mRight->getAsConstantUnion()->getIConst(0);
+ setType(*fields[i]->type());
+ getTypePointer()->setQualifier(resultQualifier);
+ return;
+ }
+ case EOpIndexDirectInterfaceBlock:
+ {
+ const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
+ const int i = mRight->getAsConstantUnion()->getIConst(0);
+ setType(*fields[i]->type());
+ getTypePointer()->setQualifier(resultQualifier);
+ return;
+ }
+ case EOpVectorSwizzle:
+ {
+ auto numFields = mRight->getAsAggregate()->getSequence()->size();
+ setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
+ static_cast<unsigned char>(numFields)));
+ return;
+ }
+ default:
+ break;
+ }
+
+ ASSERT(mLeft->isArray() == mRight->isArray());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
const int nominalSize =
std::max(mLeft->getNominalSize(), mRight->getNominalSize());
//
// All scalars or structs. Code after this test assumes this case is removed!
//
if (nominalSize == 1)
{
@@ -638,27 +815,27 @@ void TIntermBinary::promote()
// Promote to conditional
//
case EOpEqual:
case EOpNotEqual:
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
case EOpGreaterThanEqual:
- setType(TType(EbtBool, EbpUndefined));
- break;
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
+ break;
//
// And and Or operate on conditionals
//
case EOpLogicalAnd:
case EOpLogicalXor:
case EOpLogicalOr:
ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
- setType(TType(EbtBool, EbpUndefined));
+ setType(TType(EbtBool, EbpUndefined, resultQualifier));
break;
default:
break;
}
return;
}
@@ -744,46 +921,126 @@ void TIntermBinary::promote()
(mLeft->getSecondarySize() == mRight->getSecondarySize()));
setType(TType(EbtBool, EbpUndefined, resultQualifier));
break;
case EOpIndexDirect:
case EOpIndexIndirect:
case EOpIndexDirectInterfaceBlock:
case EOpIndexDirectStruct:
- // TODO (oetuaho): These ops could be handled here as well (should be done closer to the
- // top of the function).
+ case EOpVectorSwizzle:
+ // These ops should be already fully handled.
UNREACHABLE();
break;
default:
UNREACHABLE();
break;
}
}
-TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
+const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
{
- TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
- TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
- if (leftConstant == nullptr || rightConstant == nullptr)
+ if (isArray())
+ {
+ ASSERT(index < static_cast<int>(getType().getArraySize()));
+ TType arrayElementType = getType();
+ arrayElementType.clearArrayness();
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ return &mUnionArrayPointer[arrayElementSize * index];
+ }
+ else if (isMatrix())
{
+ ASSERT(index < getType().getCols());
+ int size = getType().getRows();
+ return &mUnionArrayPointer[size * index];
+ }
+ else if (isVector())
+ {
+ ASSERT(index < getType().getNominalSize());
+ return &mUnionArrayPointer[index];
+ }
+ else
+ {
+ UNREACHABLE();
return nullptr;
}
- TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
-
- // Nodes may be constant folded without being qualified as constant.
- TQualifier resultQualifier = EvqConst;
- if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
- {
- resultQualifier = EvqTemporary;
- }
- return CreateFoldedNode(constArray, this, resultQualifier);
}
-TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
+TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
+{
+ TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
+ TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
+ switch (mOp)
+ {
+ case EOpIndexDirect:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ int index = rightConstant->getIConst(0);
+
+ const TConstantUnion *constArray = leftConstant->foldIndexing(index);
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+ }
+ case EOpIndexDirectStruct:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ const TFieldList &fields = mLeft->getType().getStruct()->fields();
+ size_t index = static_cast<size_t>(rightConstant->getIConst(0));
+
+ size_t previousFieldsSize = 0;
+ for (size_t i = 0; i < index; ++i)
+ {
+ previousFieldsSize += fields[i]->type()->getObjectSize();
+ }
+
+ const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
+ return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
+ }
+ case EOpIndexIndirect:
+ case EOpIndexDirectInterfaceBlock:
+ // Can never be constant folded.
+ return nullptr;
+ case EOpVectorSwizzle:
+ {
+ if (leftConstant == nullptr)
+ {
+ return nullptr;
+ }
+ TIntermAggregate *fieldsAgg = mRight->getAsAggregate();
+ TIntermSequence *fieldsSequence = fieldsAgg->getSequence();
+ size_t numFields = fieldsSequence->size();
+
+ TConstantUnion *constArray = new TConstantUnion[numFields];
+ for (size_t i = 0; i < numFields; i++)
+ {
+ int fieldOffset = fieldsSequence->at(i)->getAsConstantUnion()->getIConst(0);
+ constArray[i] = *leftConstant->foldIndexing(fieldOffset);
+ }
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+ }
+ default:
+ {
+ if (leftConstant == nullptr || rightConstant == nullptr)
+ {
+ return nullptr;
+ }
+ TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
+
+ // Nodes may be constant folded without being qualified as constant.
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
+ }
+ }
+}
+
+TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
{
TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
if (operandConstant == nullptr)
{
return nullptr;
}
TConstantUnion *constArray = nullptr;
@@ -796,43 +1053,42 @@ TIntermTyped *TIntermUnary::fold(TInfoSi
case EOpDeterminant:
case EOpInverse:
case EOpPackSnorm2x16:
case EOpUnpackSnorm2x16:
case EOpPackUnorm2x16:
case EOpUnpackUnorm2x16:
case EOpPackHalf2x16:
case EOpUnpackHalf2x16:
- constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
- break;
+ constArray = operandConstant->foldUnaryNonComponentWise(mOp);
+ break;
default:
- constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
- break;
+ constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
+ break;
}
// Nodes may be constant folded without being qualified as constant.
- TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
- return CreateFoldedNode(constArray, this, resultQualifier);
+ return CreateFoldedNode(constArray, this, mType.getQualifier());
}
-TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
+TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
{
// Make sure that all params are constant before actual constant folding.
for (auto *param : *getSequence())
{
if (param->getAsConstantUnion() == nullptr)
{
return nullptr;
}
}
TConstantUnion *constArray = nullptr;
if (isConstructor())
- constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
+ constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
else
- constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
+ constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
// Nodes may be constant folded without being qualified as constant.
TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
return CreateFoldedNode(constArray, this, resultQualifier);
}
//
// The fold functions see if an operation on a constant can be done in place,
@@ -842,20 +1098,17 @@ TIntermTyped *TIntermAggregate::fold(TIn
//
TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics)
{
const TConstantUnion *leftArray = getUnionArrayPointer();
const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
- if (!leftArray)
- return nullptr;
- if (!rightArray)
- return nullptr;
+ ASSERT(leftArray && rightArray);
size_t objectSize = getType().getObjectSize();
// for a case like float f = vec4(2, 3, 4, 5) + 1.2;
if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
{
rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
}
@@ -868,30 +1121,30 @@ TConstantUnion *TIntermConstantUnion::fo
TConstantUnion *resultArray = nullptr;
switch(op)
{
case EOpAdd:
resultArray = new TConstantUnion[objectSize];
for (size_t i = 0; i < objectSize; i++)
- resultArray[i] = leftArray[i] + rightArray[i];
+ resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics);
break;
case EOpSub:
resultArray = new TConstantUnion[objectSize];
for (size_t i = 0; i < objectSize; i++)
- resultArray[i] = leftArray[i] - rightArray[i];
+ resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics);
break;
case EOpMul:
case EOpVectorTimesScalar:
case EOpMatrixTimesScalar:
resultArray = new TConstantUnion[objectSize];
for (size_t i = 0; i < objectSize; i++)
- resultArray[i] = leftArray[i] * rightArray[i];
+ resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics);
break;
case EOpMatrixTimesMatrix:
{
ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
const int leftCols = getCols();
const int leftRows = getRows();
@@ -1142,690 +1395,539 @@ TConstantUnion *TIntermConstantUnion::fo
default:
UNREACHABLE();
return nullptr;
}
return resultArray;
}
-//
-// The fold functions see if an operation on a constant can be done in place,
-// without generating run-time code.
-//
-// Returns the constant value to keep using or nullptr.
-//
-TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
+// The fold functions do operations on a constant at GLSL compile time, without generating run-time
+// code. Returns the constant value to keep using. Nullptr should not be returned.
+TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
{
- //
- // Do operations where the return type has a different number of components compared to the operand type.
- //
+ // Do operations where the return type may have a different number of components compared to the
+ // operand type.
const TConstantUnion *operandArray = getUnionArrayPointer();
- if (!operandArray)
- return nullptr;
+ ASSERT(operandArray);
size_t objectSize = getType().getObjectSize();
TConstantUnion *resultArray = nullptr;
switch (op)
{
- case EOpAny:
- if (getType().getBasicType() == EbtBool)
- {
+ case EOpAny:
+ ASSERT(getType().getBasicType() == EbtBool);
resultArray = new TConstantUnion();
resultArray->setBConst(false);
for (size_t i = 0; i < objectSize; i++)
{
if (operandArray[i].getBConst())
{
resultArray->setBConst(true);
break;
}
}
break;
- }
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- case EOpAll:
- if (getType().getBasicType() == EbtBool)
- {
+ case EOpAll:
+ ASSERT(getType().getBasicType() == EbtBool);
resultArray = new TConstantUnion();
resultArray->setBConst(true);
for (size_t i = 0; i < objectSize; i++)
{
if (!operandArray[i].getBConst())
{
resultArray->setBConst(false);
break;
}
}
break;
- }
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- case EOpLength:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpLength:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray = new TConstantUnion();
resultArray->setFConst(VectorLength(operandArray, objectSize));
break;
- }
- else
+
+ case EOpTranspose:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpTranspose:
- if (getType().getBasicType() == EbtFloat)
- {
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray = new TConstantUnion[objectSize];
angle::Matrix<float> result =
GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
SetUnionArrayFromMatrix(result, resultArray);
break;
}
- else
+
+ case EOpDeterminant:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpDeterminant:
- if (getType().getBasicType() == EbtFloat)
- {
+ ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4);
resultArray = new TConstantUnion();
resultArray->setFConst(GetMatrix(operandArray, size).determinant());
break;
}
- else
+
+ case EOpInverse:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpInverse:
- if (getType().getBasicType() == EbtFloat)
- {
+ ASSERT(getType().getBasicType() == EbtFloat);
unsigned int size = getType().getNominalSize();
ASSERT(size >= 2 && size <= 4);
- resultArray = new TConstantUnion[objectSize];
+ resultArray = new TConstantUnion[objectSize];
angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
SetUnionArrayFromMatrix(result, resultArray);
break;
}
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- case EOpPackSnorm2x16:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpPackSnorm2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
- resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ resultArray->setUConst(
+ gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
- }
- else
+
+ case EOpUnpackSnorm2x16:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpUnpackSnorm2x16:
- if (getType().getBasicType() == EbtUInt)
- {
+ ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
resultArray[0].setFConst(f1);
resultArray[1].setFConst(f2);
break;
}
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- case EOpPackUnorm2x16:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpPackUnorm2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
- resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ resultArray->setUConst(
+ gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
- }
- else
+
+ case EOpUnpackUnorm2x16:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpUnpackUnorm2x16:
- if (getType().getBasicType() == EbtUInt)
- {
+ ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
resultArray[0].setFConst(f1);
resultArray[1].setFConst(f2);
break;
}
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- case EOpPackHalf2x16:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpPackHalf2x16:
+ ASSERT(getType().getBasicType() == EbtFloat);
ASSERT(getType().getNominalSize() == 2);
resultArray = new TConstantUnion();
- resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
+ resultArray->setUConst(
+ gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
break;
- }
- else
+
+ case EOpUnpackHalf2x16:
{
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
-
- case EOpUnpackHalf2x16:
- if (getType().getBasicType() == EbtUInt)
- {
+ ASSERT(getType().getBasicType() == EbtUInt);
resultArray = new TConstantUnion[2];
float f1, f2;
gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
resultArray[0].setFConst(f1);
resultArray[1].setFConst(f2);
break;
}
- else
- {
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- default:
- break;
+ default:
+ UNREACHABLE();
+ break;
}
return resultArray;
}
-TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
+TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
+ TDiagnostics *diagnostics)
{
- //
- // Do unary operations where the return type is the same as operand type.
- //
+ // Do unary operations where each component of the result is computed based on the corresponding
+ // component of the operand. Also folds normalize, though the divisor in that case takes all
+ // components into account.
const TConstantUnion *operandArray = getUnionArrayPointer();
- if (!operandArray)
- return nullptr;
+ ASSERT(operandArray);
size_t objectSize = getType().getObjectSize();
TConstantUnion *resultArray = new TConstantUnion[objectSize];
for (size_t i = 0; i < objectSize; i++)
{
switch(op)
{
- case EOpNegative:
- switch (getType().getBasicType())
- {
- case EbtFloat:
- resultArray[i].setFConst(-operandArray[i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setIConst(-operandArray[i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setUConst(static_cast<unsigned int>(
- -static_cast<int>(operandArray[i].getUConst())));
- break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
-
- case EOpPositive:
- switch (getType().getBasicType())
- {
- case EbtFloat:
- resultArray[i].setFConst(operandArray[i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setIConst(operandArray[i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setUConst(static_cast<unsigned int>(
- static_cast<int>(operandArray[i].getUConst())));
+ case EOpNegative:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(-operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(-operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ -static_cast<int>(operandArray[i].getUConst())));
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- case EOpLogicalNot:
- // this code is written for possible future use,
- // will not get executed currently
- switch (getType().getBasicType())
- {
- case EbtBool:
- resultArray[i].setBConst(!operandArray[i].getBConst());
+ case EOpPositive:
+ switch (getType().getBasicType())
+ {
+ case EbtFloat:
+ resultArray[i].setFConst(operandArray[i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(static_cast<unsigned int>(
+ static_cast<int>(operandArray[i].getUConst())));
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- case EOpBitwiseNot:
- switch (getType().getBasicType())
- {
- case EbtInt:
- resultArray[i].setIConst(~operandArray[i].getIConst());
+ case EOpLogicalNot:
+ switch (getType().getBasicType())
+ {
+ case EbtBool:
+ resultArray[i].setBConst(!operandArray[i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
break;
- case EbtUInt:
- resultArray[i].setUConst(~operandArray[i].getUConst());
+
+ case EOpBitwiseNot:
+ switch (getType().getBasicType())
+ {
+ case EbtInt:
+ resultArray[i].setIConst(~operandArray[i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(~operandArray[i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- case EOpRadians:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpRadians:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
break;
- }
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- case EOpDegrees:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpDegrees:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
break;
- }
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
+
+ case EOpSin:
+ foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
+ break;
- case EOpSin:
- if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpCos:
+ foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
+ break;
- case EOpCos:
- if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
- return nullptr;
- break;
-
- case EOpTan:
- if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpTan:
+ foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
+ break;
- case EOpAsin:
- // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpAsin:
+ // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
+ break;
- case EOpAcos:
- // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpAcos:
+ // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) > 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
+ break;
- case EOpAtan:
- if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpAtan:
+ foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
+ break;
- case EOpSinh:
- if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
- return nullptr;
- break;
-
- case EOpCosh:
- if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpSinh:
+ foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
+ break;
- case EOpTanh:
- if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpCosh:
+ foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
+ break;
- case EOpAsinh:
- if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpTanh:
+ foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
+ break;
- case EOpAcosh:
- // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpAsinh:
+ foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
+ break;
- case EOpAtanh:
- // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpAcosh:
+ // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() < 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
+ break;
- case EOpAbs:
- switch (getType().getBasicType())
- {
- case EbtFloat:
- resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
- break;
- case EbtInt:
- resultArray[i].setIConst(abs(operandArray[i].getIConst()));
+ case EOpAtanh:
+ // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
+ // 0.
+ if (fabsf(operandArray[i].getFConst()) >= 1.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- case EOpSign:
- switch (getType().getBasicType())
- {
- case EbtFloat:
+ case EOpAbs:
+ switch (getType().getBasicType())
{
- float fConst = operandArray[i].getFConst();
- float fResult = 0.0f;
- if (fConst > 0.0f)
- fResult = 1.0f;
- else if (fConst < 0.0f)
- fResult = -1.0f;
- resultArray[i].setFConst(fResult);
+ case EbtFloat:
+ resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(abs(operandArray[i].getIConst()));
+ break;
+ default:
+ UNREACHABLE();
+ return nullptr;
}
break;
- case EbtInt:
+
+ case EOpSign:
+ switch (getType().getBasicType())
{
- int iConst = operandArray[i].getIConst();
- int iResult = 0;
- if (iConst > 0)
- iResult = 1;
- else if (iConst < 0)
- iResult = -1;
- resultArray[i].setIConst(iResult);
+ case EbtFloat:
+ {
+ float fConst = operandArray[i].getFConst();
+ float fResult = 0.0f;
+ if (fConst > 0.0f)
+ fResult = 1.0f;
+ else if (fConst < 0.0f)
+ fResult = -1.0f;
+ resultArray[i].setFConst(fResult);
+ break;
+ }
+ case EbtInt:
+ {
+ int iConst = operandArray[i].getIConst();
+ int iResult = 0;
+ if (iConst > 0)
+ iResult = 1;
+ else if (iConst < 0)
+ iResult = -1;
+ resultArray[i].setIConst(iResult);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ return nullptr;
}
break;
- default:
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- }
- break;
- case EOpFloor:
- if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpFloor:
+ foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
+ break;
- case EOpTrunc:
- if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpTrunc:
+ foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
+ break;
- case EOpRound:
- if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpRound:
+ foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
+ break;
- case EOpRoundEven:
- if (getType().getBasicType() == EbtFloat)
+ case EOpRoundEven:
{
+ ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
float result;
float fractPart = modff(x, &result);
if (fabsf(fractPart) == 0.5f)
result = 2.0f * roundf(x / 2.0f);
else
result = roundf(x);
resultArray[i].setFConst(result);
break;
}
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- case EOpCeil:
- if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpCeil:
+ foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
+ break;
- case EOpFract:
- if (getType().getBasicType() == EbtFloat)
+ case EOpFract:
{
+ ASSERT(getType().getBasicType() == EbtFloat);
float x = operandArray[i].getFConst();
resultArray[i].setFConst(x - floorf(x));
break;
}
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- case EOpIsNan:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpIsNan:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpIsInf:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpIsInf:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpFloatBitsToInt:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpFloatBitsToInt:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpFloatBitsToUint:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpFloatBitsToUint:
+ ASSERT(getType().getBasicType() == EbtFloat);
resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpIntBitsToFloat:
- if (getType().getBasicType() == EbtInt)
- {
+ case EOpIntBitsToFloat:
+ ASSERT(getType().getBasicType() == EbtInt);
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpUintBitsToFloat:
- if (getType().getBasicType() == EbtUInt)
- {
+ case EOpUintBitsToFloat:
+ ASSERT(getType().getBasicType() == EbtUInt);
resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpExp:
- if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpExp:
+ foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
+ break;
- case EOpLog:
- // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpLog:
+ // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
+ break;
- case EOpExp2:
- if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpExp2:
+ foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
+ break;
- case EOpLog2:
- // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
- // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
- if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
- return nullptr;
- else
- resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
- break;
+ case EOpLog2:
+ // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
+ // And log2f is not available on some plarforms like old android, so just using
+ // log(x)/log(2) here.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ {
+ foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
+ resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
+ }
+ break;
- case EOpSqrt:
- // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
- return nullptr;
- break;
+ case EOpSqrt:
+ // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
+ if (operandArray[i].getFConst() < 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
+ break;
- case EOpInverseSqrt:
- // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
- // so getting the square root first using builtin function sqrt() and then taking its inverse.
- // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
- if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
- else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
- return nullptr;
- else
- resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
- break;
+ case EOpInverseSqrt:
+ // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
+ // so getting the square root first using builtin function sqrt() and then taking
+ // its inverse.
+ // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
+ // result to 0.
+ if (operandArray[i].getFConst() <= 0.0f)
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
+ else
+ {
+ foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
+ resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
+ }
+ break;
- case EOpVectorLogicalNot:
- if (getType().getBasicType() == EbtBool)
- {
+ case EOpVectorLogicalNot:
+ ASSERT(getType().getBasicType() == EbtBool);
resultArray[i].setBConst(!operandArray[i].getBConst());
break;
- }
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return nullptr;
- case EOpNormalize:
- if (getType().getBasicType() == EbtFloat)
+ case EOpNormalize:
{
- float x = operandArray[i].getFConst();
+ ASSERT(getType().getBasicType() == EbtFloat);
+ float x = operandArray[i].getFConst();
float length = VectorLength(operandArray, objectSize);
if (length)
resultArray[i].setFConst(x / length);
else
- UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
- &resultArray[i]);
+ UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
+ diagnostics, &resultArray[i]);
break;
}
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- case EOpDFdx:
- case EOpDFdy:
- case EOpFwidth:
- if (getType().getBasicType() == EbtFloat)
- {
+ case EOpDFdx:
+ case EOpDFdy:
+ case EOpFwidth:
+ ASSERT(getType().getBasicType() == EbtFloat);
// Derivatives of constant arguments should be 0.
resultArray[i].setFConst(0.0f);
break;
- }
- infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
- return nullptr;
- default:
- return nullptr;
+ default:
+ return nullptr;
}
}
return resultArray;
}
-bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc,
- TInfoSink &infoSink, TConstantUnion *result) const
+void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter,
+ FloatTypeUnaryFunc builtinFunc,
+ TConstantUnion *result) const
{
ASSERT(builtinFunc);
- if (getType().getBasicType() == EbtFloat)
- {
- result->setFConst(builtinFunc(parameter.getFConst()));
- return true;
- }
-
- infoSink.info.message(
- EPrefixInternalError, getLine(),
- "Unary operation not folded into constant");
- return false;
+ ASSERT(getType().getBasicType() == EbtFloat);
+ result->setFConst(builtinFunc(parameter.getFConst()));
}
// static
-TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
- TInfoSink &infoSink)
+TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
{
ASSERT(aggregate->getSequence()->size() > 0u);
size_t resultSize = aggregate->getType().getObjectSize();
TConstantUnion *resultArray = new TConstantUnion[resultSize];
TBasicType basicType = aggregate->getBasicType();
size_t resultIndex = 0u;
@@ -1914,17 +2016,18 @@ TConstantUnion *TIntermConstantUnion::Fo
++resultIndex;
}
}
ASSERT(resultIndex == resultSize);
return resultArray;
}
// static
-TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
+TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
{
TOperator op = aggregate->getOp();
TIntermSequence *sequence = aggregate->getSequence();
unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
std::vector<const TConstantUnion *> unionArrays(paramsCount);
std::vector<size_t> objectSizes(paramsCount);
size_t maxObjectSize = 0;
TBasicType basicType = EbtVoid;
@@ -1955,560 +2058,560 @@ TConstantUnion *TIntermConstantUnion::Fo
TConstantUnion *resultArray = nullptr;
if (paramsCount == 2)
{
//
// Binary built-in
//
switch (op)
{
- case EOpAtan:
+ case EOpAtan:
{
- if (basicType == EbtFloat)
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
- {
- float y = unionArrays[0][i].getFConst();
- float x = unionArrays[1][i].getFConst();
- // Results are undefined if x and y are both 0.
- if (x == 0.0f && y == 0.0f)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
- else
- resultArray[i].setFConst(atan2f(y, x));
- }
+ float y = unionArrays[0][i].getFConst();
+ float x = unionArrays[1][i].getFConst();
+ // Results are undefined if x and y are both 0.
+ if (x == 0.0f && y == 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else
+ resultArray[i].setFConst(atan2f(y, x));
}
- else
- UNREACHABLE();
+ break;
}
- break;
- case EOpPow:
+ case EOpPow:
{
- if (basicType == EbtFloat)
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
- {
- float x = unionArrays[0][i].getFConst();
- float y = unionArrays[1][i].getFConst();
- // Results are undefined if x < 0.
- // Results are undefined if x = 0 and y <= 0.
- if (x < 0.0f)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
- else if (x == 0.0f && y <= 0.0f)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
- else
- resultArray[i].setFConst(powf(x, y));
- }
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ // Results are undefined if x < 0.
+ // Results are undefined if x = 0 and y <= 0.
+ if (x < 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else if (x == 0.0f && y <= 0.0f)
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ else
+ resultArray[i].setFConst(powf(x, y));
}
- else
- UNREACHABLE();
+ break;
}
- break;
- case EOpMod:
+ case EOpMod:
{
- if (basicType == EbtFloat)
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
- {
- float x = unionArrays[0][i].getFConst();
- float y = unionArrays[1][i].getFConst();
- resultArray[i].setFConst(x - y * floorf(x / y));
- }
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ resultArray[i].setFConst(x - y * floorf(x / y));
}
- else
- UNREACHABLE();
+ break;
}
- break;
- case EOpMin:
+ case EOpMin:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
- break;
- case EbtInt:
- resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
- break;
- case EbtUInt:
- resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
+ unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
+ unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
+ unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpMax:
+ case EOpMax:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
- break;
- case EbtInt:
- resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
- break;
- case EbtUInt:
- resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
+ unionArrays[1][i].getFConst()));
+ break;
+ case EbtInt:
+ resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
+ unionArrays[1][i].getIConst()));
+ break;
+ case EbtUInt:
+ resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
+ unionArrays[1][i].getUConst()));
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpStep:
+ case EOpStep:
{
- if (basicType == EbtFloat)
- {
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
- resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
- }
- else
- UNREACHABLE();
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ resultArray[i].setFConst(
+ unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
+ : 1.0f);
+ break;
}
- break;
- case EOpLessThan:
+ case EOpLessThan:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() <
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() <
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() <
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpLessThanEqual:
+ case EOpLessThanEqual:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpGreaterThan:
+ case EOpGreaterThan:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() >
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() >
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() >
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
-
- case EOpGreaterThanEqual:
+ case EOpGreaterThanEqual:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
+ unionArrays[1][i].getUConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
}
break;
- case EOpVectorEqual:
+ case EOpVectorEqual:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
- break;
- case EbtBool:
- resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
+ unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
+ unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpVectorNotEqual:
+ case EOpVectorNotEqual:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
- resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
- break;
- case EbtInt:
- resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
- break;
- case EbtUInt:
- resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
- break;
- case EbtBool:
- resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
- break;
- default:
- UNREACHABLE();
- break;
+ case EbtFloat:
+ resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
+ unionArrays[1][i].getFConst());
+ break;
+ case EbtInt:
+ resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
+ unionArrays[1][i].getIConst());
+ break;
+ case EbtUInt:
+ resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
+ unionArrays[1][i].getUConst());
+ break;
+ case EbtBool:
+ resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
+ unionArrays[1][i].getBConst());
+ break;
+ default:
+ UNREACHABLE();
+ break;
}
}
+ break;
}
- break;
- case EOpDistance:
- if (basicType == EbtFloat)
+ case EOpDistance:
{
+ ASSERT(basicType == EbtFloat);
TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
- resultArray = new TConstantUnion();
+ resultArray = new TConstantUnion();
for (size_t i = 0; i < maxObjectSize; i++)
{
float x = unionArrays[0][i].getFConst();
float y = unionArrays[1][i].getFConst();
distanceArray[i].setFConst(x - y);
}
resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
- }
- else
- UNREACHABLE();
- break;
-
- case EOpDot:
-
- if (basicType == EbtFloat)
- {
- resultArray = new TConstantUnion();
- resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
+ break;
}
- else
- UNREACHABLE();
- break;
- case EOpCross:
- if (basicType == EbtFloat && maxObjectSize == 3)
+ case EOpDot:
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion();
+ resultArray->setFConst(
+ VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
+ break;
+
+ case EOpCross:
{
+ ASSERT(basicType == EbtFloat && maxObjectSize == 3);
resultArray = new TConstantUnion[maxObjectSize];
- float x0 = unionArrays[0][0].getFConst();
- float x1 = unionArrays[0][1].getFConst();
- float x2 = unionArrays[0][2].getFConst();
- float y0 = unionArrays[1][0].getFConst();
- float y1 = unionArrays[1][1].getFConst();
- float y2 = unionArrays[1][2].getFConst();
+ float x0 = unionArrays[0][0].getFConst();
+ float x1 = unionArrays[0][1].getFConst();
+ float x2 = unionArrays[0][2].getFConst();
+ float y0 = unionArrays[1][0].getFConst();
+ float y1 = unionArrays[1][1].getFConst();
+ float y2 = unionArrays[1][2].getFConst();
resultArray[0].setFConst(x1 * y2 - y1 * x2);
resultArray[1].setFConst(x2 * y0 - y2 * x0);
resultArray[2].setFConst(x0 * y1 - y0 * x1);
+ break;
}
- else
- UNREACHABLE();
- break;
- case EOpReflect:
- if (basicType == EbtFloat)
+ case EOpReflect:
{
+ ASSERT(basicType == EbtFloat);
// genType reflect (genType I, genType N) :
- // For the incident vector I and surface orientation N, returns the reflection direction:
+ // For the incident vector I and surface orientation N, returns the reflection
+ // direction:
// I - 2 * dot(N, I) * N.
- resultArray = new TConstantUnion[maxObjectSize];
+ resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++)
{
float result = unionArrays[0][i].getFConst() -
2.0f * dotProduct * unionArrays[1][i].getFConst();
resultArray[i].setFConst(result);
}
+ break;
}
- else
- UNREACHABLE();
- break;
- case EOpMul:
- if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
- (*sequence)[1]->getAsTyped()->isMatrix())
+ case EOpMul:
{
+ ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
+ (*sequence)[1]->getAsTyped()->isMatrix());
// Perform component-wise matrix multiplication.
resultArray = new TConstantUnion[maxObjectSize];
- int size = (*sequence)[0]->getAsTyped()->getNominalSize();
+ int size = (*sequence)[0]->getAsTyped()->getNominalSize();
angle::Matrix<float> result =
GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
SetUnionArrayFromMatrix(result, resultArray);
+ break;
}
- else
- UNREACHABLE();
- break;
- case EOpOuterProduct:
- if (basicType == EbtFloat)
+ case EOpOuterProduct:
{
+ ASSERT(basicType == EbtFloat);
size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
- resultArray = new TConstantUnion[numRows * numCols];
+ resultArray = new TConstantUnion[numRows * numCols];
angle::Matrix<float> result =
GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
.outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
SetUnionArrayFromMatrix(result, resultArray);
+ break;
}
- else
- UNREACHABLE();
- break;
- default:
- UNREACHABLE();
- // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
- return nullptr;
+ default:
+ UNREACHABLE();
+ // TODO: Add constant folding support for other built-in operations that take 2
+ // parameters and not handled above.
+ return nullptr;
}
}
else if (paramsCount == 3)
{
//
// Ternary built-in
//
switch (op)
{
- case EOpClamp:
+ case EOpClamp:
{
resultArray = new TConstantUnion[maxObjectSize];
for (size_t i = 0; i < maxObjectSize; i++)
{
switch (basicType)
{
- case EbtFloat:
+ case EbtFloat:
{
- float x = unionArrays[0][i].getFConst();
+ float x = unionArrays[0][i].getFConst();
float min = unionArrays[1][i].getFConst();
float max = unionArrays[2][i].getFConst();
// Results are undefined if min > max.
if (min > max)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
else
resultArray[i].setFConst(gl::clamp(x, min, max));
+ break;
}
- break;
- case EbtInt:
+
+ case EbtInt:
{
- int x = unionArrays[0][i].getIConst();
+ int x = unionArrays[0][i].getIConst();
int min = unionArrays[1][i].getIConst();
int max = unionArrays[2][i].getIConst();
// Results are undefined if min > max.
if (min > max)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
else
resultArray[i].setIConst(gl::clamp(x, min, max));
+ break;
}
- break;
- case EbtUInt:
+ case EbtUInt:
{
- unsigned int x = unionArrays[0][i].getUConst();
+ unsigned int x = unionArrays[0][i].getUConst();
unsigned int min = unionArrays[1][i].getUConst();
unsigned int max = unionArrays[2][i].getUConst();
// Results are undefined if min > max.
if (min > max)
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
else
resultArray[i].setUConst(gl::clamp(x, min, max));
+ break;
}
- break;
- default:
- UNREACHABLE();
- break;
- }
- }
- }
- break;
-
- case EOpMix:
- {
- if (basicType == EbtFloat)
- {
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
- {
- float x = unionArrays[0][i].getFConst();
- float y = unionArrays[1][i].getFConst();
- TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
- if (type == EbtFloat)
- {
- // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
- float a = unionArrays[2][i].getFConst();
- resultArray[i].setFConst(x * (1.0f - a) + y * a);
- }
- else // 3rd parameter is EbtBool
- {
- ASSERT(type == EbtBool);
- // Selects which vector each returned component comes from.
- // For a component of a that is false, the corresponding component of x is returned.
- // For a component of a that is true, the corresponding component of y is returned.
- bool a = unionArrays[2][i].getBConst();
- resultArray[i].setFConst(a ? y : x);
- }
+ default:
+ UNREACHABLE();
+ break;
}
}
- else
- UNREACHABLE();
+ break;
}
- break;
- case EOpSmoothStep:
+ case EOpMix:
{
- if (basicType == EbtFloat)
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
{
- resultArray = new TConstantUnion[maxObjectSize];
- for (size_t i = 0; i < maxObjectSize; i++)
+ float x = unionArrays[0][i].getFConst();
+ float y = unionArrays[1][i].getFConst();
+ TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
+ if (type == EbtFloat)
{
- float edge0 = unionArrays[0][i].getFConst();
- float edge1 = unionArrays[1][i].getFConst();
- float x = unionArrays[2][i].getFConst();
- // Results are undefined if edge0 >= edge1.
- if (edge0 >= edge1)
- {
- UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
- }
- else
- {
- // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
- // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
- float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
- resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
- }
+ // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
+ float a = unionArrays[2][i].getFConst();
+ resultArray[i].setFConst(x * (1.0f - a) + y * a);
+ }
+ else // 3rd parameter is EbtBool
+ {
+ ASSERT(type == EbtBool);
+ // Selects which vector each returned component comes from.
+ // For a component of a that is false, the corresponding component of x is
+ // returned.
+ // For a component of a that is true, the corresponding component of y is
+ // returned.
+ bool a = unionArrays[2][i].getBConst();
+ resultArray[i].setFConst(a ? y : x);
}
}
- else
- UNREACHABLE();
+ break;
}
- break;
- case EOpFaceForward:
- if (basicType == EbtFloat)
+ case EOpSmoothStep:
{
+ ASSERT(basicType == EbtFloat);
+ resultArray = new TConstantUnion[maxObjectSize];
+ for (size_t i = 0; i < maxObjectSize; i++)
+ {
+ float edge0 = unionArrays[0][i].getFConst();
+ float edge1 = unionArrays[1][i].getFConst();
+ float x = unionArrays[2][i].getFConst();
+ // Results are undefined if edge0 >= edge1.
+ if (edge0 >= edge1)
+ {
+ UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
+ &resultArray[i]);
+ }
+ else
+ {
+ // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
+ // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
+ float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
+ resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
+ }
+ }
+ break;
+ }
+
+ case EOpFaceForward:
+ {
+ ASSERT(basicType == EbtFloat);
// genType faceforward(genType N, genType I, genType Nref) :
// If dot(Nref, I) < 0 return N, otherwise return -N.
- resultArray = new TConstantUnion[maxObjectSize];
+ resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++)
{
if (dotProduct < 0)
resultArray[i].setFConst(unionArrays[0][i].getFConst());
else
resultArray[i].setFConst(-unionArrays[0][i].getFConst());
}
+ break;
}
- else
- UNREACHABLE();
- break;
- case EOpRefract:
- if (basicType == EbtFloat)
+ case EOpRefract:
{
+ ASSERT(basicType == EbtFloat);
// genType refract(genType I, genType N, float eta) :
- // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
+ // For the incident vector I and surface normal N, and the ratio of indices of
+ // refraction eta,
// return the refraction vector. The result is computed by
// k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
// if (k < 0.0)
// return genType(0.0)
// else
// return eta * I - (eta * dot(N, I) + sqrt(k)) * N
- resultArray = new TConstantUnion[maxObjectSize];
+ resultArray = new TConstantUnion[maxObjectSize];
float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
for (size_t i = 0; i < maxObjectSize; i++)
{
float eta = unionArrays[2][i].getFConst();
- float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
+ float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
if (k < 0.0f)
resultArray[i].setFConst(0.0f);
else
resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
- (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
+ (eta * dotProduct + sqrtf(k)) *
+ unionArrays[1][i].getFConst());
}
+ break;
}
- else
+
+ default:
UNREACHABLE();
- break;
-
- default:
- UNREACHABLE();
- // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
- return nullptr;
+ // TODO: Add constant folding support for other built-in operations that take 3
+ // parameters and not handled above.
+ return nullptr;
}
}
return resultArray;
}
// static
TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
{
--- a/gfx/angle/src/compiler/translator/IntermNode.h
+++ b/gfx/angle/src/compiler/translator/IntermNode.h
@@ -29,16 +29,17 @@
class TDiagnostics;
class TIntermTraverser;
class TIntermAggregate;
class TIntermBinary;
class TIntermUnary;
class TIntermConstantUnion;
+class TIntermTernary;
class TIntermSelection;
class TIntermSwitch;
class TIntermCase;
class TIntermTyped;
class TIntermSymbol;
class TIntermLoop;
class TInfoSink;
class TInfoSinkBase;
@@ -88,16 +89,17 @@ class TIntermNode : angle::NonCopyable
void setLine(const TSourceLoc &l) { mLine = 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 TIntermTernary *getAsTernaryNode() { return nullptr; }
virtual TIntermSelection *getAsSelectionNode() { return 0; }
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
virtual TIntermCase *getAsCaseNode() { return 0; }
virtual TIntermSymbol *getAsSymbolNode() { return 0; }
virtual TIntermLoop *getAsLoopNode() { return 0; }
virtual TIntermRaw *getAsRawNode() { return 0; }
virtual TIntermBranch *getAsBranchNode() { return 0; }
@@ -154,16 +156,19 @@ class TIntermTyped : public TIntermNode
bool isScalarInt() const { return mType.isScalarInt(); }
const char *getBasicString() const { return mType.getBasicString(); }
TString getCompleteString() const { return mType.getCompleteString(); }
unsigned int getArraySize() const { return mType.getArraySize(); }
bool isConstructorWithOnlyConstantUnionParameters();
+ static TIntermTyped *CreateIndexNode(int index);
+ static TIntermTyped *CreateZero(const TType &type);
+
protected:
TType mType;
TIntermTyped(const TIntermTyped &node);
};
//
// Handle for, do-while, and while loops.
@@ -311,16 +316,17 @@ class TIntermRaw : public TIntermTyped
// Other nodes than TIntermConstantUnion may also be constant expressions.
//
class TIntermConstantUnion : public TIntermTyped
{
public:
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
{
+ ASSERT(unionPointer);
}
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
bool hasSideEffects() const override { return false; }
const TConstantUnion *getUnionArrayPointer() const { return mUnionArrayPointer; }
@@ -338,53 +344,56 @@ class TIntermConstantUnion : public TInt
}
bool getBConst(size_t index) const
{
return mUnionArrayPointer ? mUnionArrayPointer[index].getBConst() : false;
}
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
{
+ ASSERT(safeConstantUnion);
// Previous union pointer freed on pool deallocation.
mUnionArrayPointer = safeConstantUnion;
}
TIntermConstantUnion *getAsConstantUnion() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; }
TConstantUnion *foldBinary(TOperator op,
TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics);
- TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
- TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
+ const TConstantUnion *foldIndexing(int index);
+ TConstantUnion *foldUnaryNonComponentWise(TOperator op);
+ TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
- static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
- TInfoSink &infoSink);
- static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
+ static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
+ static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics);
protected:
// Same data may be shared between multiple constant unions, so it can't be modified.
const TConstantUnion *mUnionArrayPointer;
private:
typedef float(*FloatTypeUnaryFunc) (float);
- bool foldFloatTypeUnary(const TConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
+ void foldFloatTypeUnary(const TConstantUnion ¶meter,
+ FloatTypeUnaryFunc builtinFunc,
+ TConstantUnion *result) const;
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
};
//
// Intermediate class for node types that hold operators.
//
class TIntermOperator : public TIntermTyped
{
public:
TOperator getOp() const { return mOp; }
- void setOp(TOperator op) { mOp = op; }
bool isAssignment() const;
bool isMultiplication() const;
bool isConstructor() const;
bool hasSideEffects() const override { return isAssignment(); }
protected:
@@ -401,40 +410,33 @@ class TIntermOperator : public TIntermTy
};
//
// Nodes for all the basic binary math operators.
//
class TIntermBinary : public TIntermOperator
{
public:
- TIntermBinary(TOperator op)
- : TIntermOperator(op),
- mAddIndexClamp(false) {}
-
// This constructor determines the type of the binary node based on the operands and op.
- // This is only supported for math/logical ops, not indexing.
TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right);
TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); }
static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right);
static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right);
TIntermBinary *getAsBinaryNode() override { return this; };
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override
{
return isAssignment() || mLeft->hasSideEffects() || mRight->hasSideEffects();
}
- void setLeft(TIntermTyped *node) { mLeft = node; }
- void setRight(TIntermTyped *node) { mRight = node; }
TIntermTyped *getLeft() const { return mLeft; }
TIntermTyped *getRight() const { return mRight; }
TIntermTyped *fold(TDiagnostics *diagnostics);
void setAddIndexClamp() { mAddIndexClamp = true; }
bool getAddIndexClamp() { return mAddIndexClamp; }
protected:
@@ -451,49 +453,42 @@ class TIntermBinary : public TIntermOper
};
//
// Nodes for unary math operators.
//
class TIntermUnary : public TIntermOperator
{
public:
- TIntermUnary(TOperator op, const TType &type)
- : TIntermOperator(op, type),
- mOperand(NULL),
- mUseEmulatedFunction(false) {}
- TIntermUnary(TOperator op)
- : TIntermOperator(op),
- mOperand(NULL),
- mUseEmulatedFunction(false) {}
+ TIntermUnary(TOperator op, TIntermTyped *operand);
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
void traverse(TIntermTraverser *it) override;
TIntermUnary *getAsUnaryNode() override { return this; }
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
- void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
- void promote(const TType *funcReturnType);
- TIntermTyped *fold(TInfoSink &infoSink);
+ TIntermTyped *fold(TDiagnostics *diagnostics);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
protected:
TIntermTyped *mOperand;
// If set to true, replace the built-in function call with an emulated one
// to work around driver bugs.
bool mUseEmulatedFunction;
private:
+ void promote();
+
TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
};
typedef TVector<TIntermNode *> TIntermSequence;
typedef TVector<int> TQualifierList;
//
// Nodes that operate on an arbitrary sized set of children.
@@ -517,26 +512,29 @@ class TIntermAggregate : public TIntermO
mGotPrecisionFromChildren(false)
{
}
~TIntermAggregate() { }
// Note: only supported for nodes that can be a part of an expression.
TIntermTyped *deepCopy() const override { return new TIntermAggregate(*this); }
+ void setOp(TOperator op) { mOp = op; }
+
TIntermAggregate *getAsAggregate() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects
bool hasSideEffects() const override { return true; }
- TIntermTyped *fold(TInfoSink &infoSink);
+ TIntermTyped *fold(TDiagnostics *diagnostics);
TIntermSequence *getSequence() { return &mSequence; }
+ const TIntermSequence *getSequence() const { return &mSequence; }
void setNameObj(const TName &name) { mName = name; }
const TName &getNameObj() const { return mName; }
void setName(const TString &name) { mName.setString(name); }
const TString &getName() const { return mName.getString(); }
void setUserDefined() { mUserDefined = true; }
@@ -566,56 +564,71 @@ class TIntermAggregate : public TIntermO
bool mUseEmulatedFunction;
bool mGotPrecisionFromChildren;
private:
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
};
-//
-// For if tests.
-//
-class TIntermSelection : public TIntermTyped
+// For ternary operators like a ? b : c.
+class TIntermTernary : public TIntermTyped
{
public:
- TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
- : TIntermTyped(TType(EbtVoid, EbpUndefined)),
- mCondition(cond),
- mTrueBlock(trueB),
- mFalseBlock(falseB) {}
- TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB,
- const TType &type)
- : TIntermTyped(type),
- mCondition(cond),
- mTrueBlock(trueB),
- mFalseBlock(falseB) {}
-
- // Note: only supported for ternary operator nodes.
- TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); }
+ TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
- // Conservatively assume selections have side-effects
- bool hasSideEffects() const override { return true; }
+ TIntermTyped *getCondition() const { return mCondition; }
+ TIntermTyped *getTrueExpression() const { return mTrueExpression; }
+ TIntermTyped *getFalseExpression() const { return mFalseExpression; }
+ TIntermTernary *getAsTernaryNode() override { return this; }
+
+ TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); }
+
+ bool hasSideEffects() const override
+ {
+ return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() ||
+ mFalseExpression->hasSideEffects();
+ }
+
+ static TQualifier DetermineQualifier(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression);
- bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
- TIntermNode *getCondition() const { return mCondition; }
+ private:
+ TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
+
+ TIntermTyped *mCondition;
+ TIntermTyped *mTrueExpression;
+ TIntermTyped *mFalseExpression;
+};
+
+// For if tests.
+class TIntermSelection : public TIntermNode
+{
+ public:
+ TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB)
+ : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
+ {
+ }
+
+ void traverse(TIntermTraverser *it) override;
+ bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
+
+ TIntermTyped *getCondition() const { return mCondition; }
TIntermNode *getTrueBlock() const { return mTrueBlock; }
TIntermNode *getFalseBlock() const { return mFalseBlock; }
TIntermSelection *getAsSelectionNode() override { return this; }
protected:
TIntermTyped *mCondition;
TIntermNode *mTrueBlock;
TIntermNode *mFalseBlock;
-
- private:
- TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private!
};
//
// Switch statement.
//
class TIntermSwitch : public TIntermNode
{
public:
@@ -691,31 +704,33 @@ class TIntermTraverser : angle::NonCopya
TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
virtual ~TIntermTraverser();
virtual void visitSymbol(TIntermSymbol *node) {}
virtual void visitRaw(TIntermRaw *node) {}
virtual void visitConstantUnion(TIntermConstantUnion *node) {}
virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
+ virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
virtual bool visitSelection(Visit visit, TIntermSelection *node) { return true; }
virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
// The traverse functions contain logic for iterating over the children of the node
// and calling the visit functions in the appropriate places. They also track some
// context that may be used by the visit functions.
virtual void traverseSymbol(TIntermSymbol *node);
virtual void traverseRaw(TIntermRaw *node);
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseBinary(TIntermBinary *node);
virtual void traverseUnary(TIntermUnary *node);
+ virtual void traverseTernary(TIntermTernary *node);
virtual void traverseSelection(TIntermSelection *node);
virtual void traverseSwitch(TIntermSwitch *node);
virtual void traverseCase(TIntermCase *node);
virtual void traverseAggregate(TIntermAggregate *node);
virtual void traverseLoop(TIntermLoop *node);
virtual void traverseBranch(TIntermBranch *node);
int getMaxDepth() const { return mMaxDepth; }
@@ -993,16 +1008,17 @@ class TMaxDepthTraverser : public TInter
public:
POOL_ALLOCATOR_NEW_DELETE();
TMaxDepthTraverser(int depthLimit)
: TIntermTraverser(true, true, false),
mDepthLimit(depthLimit) { }
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
+ bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
bool visitSelection(Visit, TIntermSelection *) override { return depthCheck(); }
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
protected:
bool depthCheck() const { return mMaxDepth < mDepthLimit; }
--- a/gfx/angle/src/compiler/translator/IntermNodePatternMatcher.cpp
+++ b/gfx/angle/src/compiler/translator/IntermNodePatternMatcher.cpp
@@ -100,19 +100,16 @@ bool IntermNodePatternMatcher::match(TIn
{
return true;
}
}
}
return false;
}
-bool IntermNodePatternMatcher::match(TIntermSelection *node)
+bool IntermNodePatternMatcher::match(TIntermTernary *node)
{
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
{
- if (node->usesTernaryOperator())
- {
- return true;
- }
+ return true;
}
return false;
}
--- a/gfx/angle/src/compiler/translator/IntermNodePatternMatcher.h
+++ b/gfx/angle/src/compiler/translator/IntermNodePatternMatcher.h
@@ -9,17 +9,17 @@
//
#ifndef COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
class TIntermAggregate;
class TIntermBinary;
class TIntermNode;
-class TIntermSelection;
+class TIntermTernary;
class IntermNodePatternMatcher
{
public:
static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
enum PatternType
{
@@ -37,17 +37,17 @@ class IntermNodePatternMatcher
bool match(TIntermBinary *node, TIntermNode *parentNode);
// Use this version for checking binary node matches in case you're using flag
// kDynamicIndexingOfVectorOrMatrixInLValue.
bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
bool match(TIntermAggregate *node, TIntermNode *parentNode);
- bool match(TIntermSelection *node);
+ bool match(TIntermTernary *node);
private:
const unsigned int mMask;
bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
};
#endif
--- a/gfx/angle/src/compiler/translator/IntermTraverse.cpp
+++ b/gfx/angle/src/compiler/translator/IntermTraverse.cpp
@@ -28,16 +28,21 @@ void TIntermBinary::traverse(TIntermTrav
it->traverseBinary(this);
}
void TIntermUnary::traverse(TIntermTraverser *it)
{
it->traverseUnary(this);
}
+void TIntermTernary::traverse(TIntermTraverser *it)
+{
+ it->traverseTernary(this);
+}
+
void TIntermSelection::traverse(TIntermTraverser *it)
{
it->traverseSelection(this);
}
void TIntermSwitch::traverse(TIntermTraverser *it)
{
it->traverseSwitch(this);
@@ -142,37 +147,31 @@ TIntermAggregate *TIntermTraverser::crea
return tempDeclaration;
}
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
{
ASSERT(initializer != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
- TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
- tempInit->setLeft(tempSymbol);
- tempInit->setRight(initializer);
- tempInit->setType(tempSymbol->getType());
+ TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
tempDeclaration->getSequence()->push_back(tempInit);
return tempDeclaration;
}
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
{
return createTempInitDeclaration(initializer, EvqTemporary);
}
TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
{
ASSERT(rightNode != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
- TIntermBinary *assignment = new TIntermBinary(EOpAssign);
- assignment->setLeft(tempSymbol);
- assignment->setRight(rightNode);
- assignment->setType(tempSymbol->getType());
+ TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
return assignment;
}
void TIntermTraverser::useTemporaryIndex(unsigned int *temporaryIndex)
{
mTemporaryIndex = temporaryIndex;
}
@@ -568,16 +567,41 @@ void TLValueTrackingTraverser::traverseA
decrementDepth();
}
if (visit && postVisit)
visitAggregate(PostVisit, node);
}
//
+// Traverse a ternary node. Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseTernary(TIntermTernary *node)
+{
+ bool visit = true;
+
+ if (preVisit)
+ visit = visitTernary(PreVisit, node);
+
+ if (visit)
+ {
+ incrementDepth(node);
+ node->getCondition()->traverse(this);
+ if (node->getTrueExpression())
+ node->getTrueExpression()->traverse(this);
+ if (node->getFalseExpression())
+ node->getFalseExpression()->traverse(this);
+ decrementDepth();
+ }
+
+ if (visit && postVisit)
+ visitTernary(PostVisit, node);
+}
+
+//
// Traverse a selection node. Same comments in binary node apply here.
//
void TIntermTraverser::traverseSelection(TIntermSelection *node)
{
bool visit = true;
if (preVisit)
visit = visitSelection(PreVisit, node);
--- a/gfx/angle/src/compiler/translator/Intermediate.cpp
+++ b/gfx/angle/src/compiler/translator/Intermediate.cpp
@@ -39,48 +39,30 @@ TIntermSymbol *TIntermediate::addSymbol(
//
// 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)
+TIntermTyped *TIntermediate::addIndex(TOperator op,
+ TIntermTyped *base,
+ TIntermTyped *index,
+ const TSourceLoc &line,
+ TDiagnostics *diagnostics)
{
- TIntermBinary *node = new TIntermBinary(op);
+ TIntermBinary *node = new TIntermBinary(op, base, index);
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, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType)
-{
- //
- // Make a new node for the operator.
- //
- TIntermUnary *node = new TIntermUnary(op);
- node->setLine(line);
- node->setOperand(child);
- node->promote(funcReturnType);
-
- TIntermTyped *foldedNode = node->fold(mInfoSink);
- if (foldedNode)
- return foldedNode;
+ TIntermTyped *folded = node->fold(diagnostics);
+ if (folded)
+ {
+ return folded;
+ }
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
@@ -249,53 +231,47 @@ TIntermTyped *TIntermediate::addComma(TI
commaNode = growAggregate(left, right, line);
commaNode->getAsAggregate()->setOp(EOpComma);
commaNode->setType(right->getType());
}
commaNode->getTypePointer()->setQualifier(resultQualifier);
return commaNode;
}
-//
// 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 one of trueBlock and falseBlock if the expression could be folded.
-//
-TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
- const TSourceLoc &line)
+// Returns the ternary node created, or one of trueExpression and falseExpression if the expression
+// could be folded.
+TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line)
{
- TQualifier resultQualifier = EvqTemporary;
- if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst &&
- falseBlock->getQualifier() == EvqConst)
- {
- resultQualifier = EvqConst;
- }
// Note that the node resulting from here can be a constant union without being qualified as
// constant.
if (cond->getAsConstantUnion())
{
+ TQualifier resultQualifier =
+ TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression);
if (cond->getAsConstantUnion()->getBConst(0))
{
- trueBlock->getTypePointer()->setQualifier(resultQualifier);
- return trueBlock;
+ trueExpression->getTypePointer()->setQualifier(resultQualifier);
+ return trueExpression;
}
else
{
- falseBlock->getTypePointer()->setQualifier(resultQualifier);
- return falseBlock;
+ falseExpression->getTypePointer()->setQualifier(resultQualifier);
+ return falseExpression;
}
}
- //
- // Make a selection node.
- //
- TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
- node->getTypePointer()->setQualifier(resultQualifier);
+ // Make a ternary node.
+ TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
node->setLine(line);
return node;
}
TIntermSwitch *TIntermediate::addSwitch(
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
{
@@ -330,16 +306,17 @@ TIntermConstantUnion *TIntermediate::add
return node;
}
TIntermTyped *TIntermediate::addSwizzle(
TVectorFields &fields, const TSourceLoc &line)
{
TIntermAggregate *node = new TIntermAggregate(EOpSequence);
+ node->getTypePointer()->setQualifier(EvqConst);
node->setLine(line);
TIntermConstantUnion *constIntNode;
TIntermSequence *sequenceVector = node->getSequence();
TConstantUnion *unionArray;
for (int i = 0; i < fields.num; i++)
{
@@ -383,17 +360,17 @@ TIntermBranch* TIntermediate::addBranch(
return node;
}
//
// This is to be executed once the final root is put on top by the parsing
// process.
//
-TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
+TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root)
{
if (root == nullptr)
return nullptr;
//
// Finish off the top level sequence, if any
//
TIntermAggregate *aggRoot = root->getAsAggregate();
@@ -406,17 +383,18 @@ TIntermAggregate *TIntermediate::postPro
aggRoot = new TIntermAggregate(EOpSequence);
aggRoot->setLine(root->getLine());
aggRoot->getSequence()->push_back(root);
}
return aggRoot;
}
-TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
+TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
+ TDiagnostics *diagnostics)
{
switch (aggregate->getOp())
{
case EOpAtan:
case EOpPow:
case EOpMod:
case EOpMin:
case EOpMax:
@@ -433,19 +411,19 @@ TIntermTyped *TIntermediate::foldAggrega
case EOpVectorEqual:
case EOpVectorNotEqual:
case EOpDistance:
case EOpDot:
case EOpCross:
case EOpFaceForward:
case EOpReflect:
case EOpRefract:
- return aggregate->fold(mInfoSink);
+ return aggregate->fold(diagnostics);
default:
// TODO: Add support for folding array constructors
if (aggregate->isConstructor() && !aggregate->isArray())
{
- return aggregate->fold(mInfoSink);
+ return aggregate->fold(diagnostics);
}
// Constant folding not supported for the built-in.
return nullptr;
}
}
--- a/gfx/angle/src/compiler/translator/Intermediate.h
+++ b/gfx/angle/src/compiler/translator/Intermediate.h
@@ -11,61 +11,62 @@
struct TVectorFields
{
int offsets[4];
int num;
};
//
-// Set of helper functions to help parse and build the tree.
+// Set of helper functions to help build the tree.
//
-class TInfoSink;
class TIntermediate
{
public:
POOL_ALLOCATOR_NEW_DELETE();
- TIntermediate(TInfoSink &i)
- : mInfoSink(i) { }
+ TIntermediate() {}
TIntermSymbol *addSymbol(
int id, const TString &, const TType &, const TSourceLoc &);
- TIntermTyped *addIndex(
- TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &);
+ TIntermTyped *addIndex(TOperator op,
+ TIntermTyped *base,
+ TIntermTyped *index,
+ const TSourceLoc &line,
+ TDiagnostics *diagnostics);
TIntermTyped *addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
TIntermAggregate *growAggregate(
TIntermNode *left, TIntermNode *right, const TSourceLoc &);
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
TIntermAggregate *ensureSequence(TIntermNode *node);
TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
- TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &);
- TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
- const TSourceLoc &line);
+ TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
+ static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
+ const TSourceLoc &line);
TIntermSwitch *addSwitch(
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
TIntermCase *addCase(
TIntermTyped *condition, const TSourceLoc &line);
TIntermTyped *addComma(TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &line,
int shaderVersion);
TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
const TType &type,
const TSourceLoc &line);
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 &);
- TIntermAggregate *postProcess(TIntermNode *root);
+ static TIntermAggregate *PostProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &);
- TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
+ TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
private:
void operator=(TIntermediate &); // prevent assignments
-
- TInfoSink & mInfoSink;
};
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_
--- a/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
+++ b/gfx/angle/src/compiler/translator/OutputGLSLBase.cpp
@@ -22,21 +22,19 @@ TString arrayBrackets(const TType &type)
bool isSingleStatement(TIntermNode *node)
{
if (const TIntermAggregate *aggregate = node->getAsAggregate())
{
return (aggregate->getOp() != EOpFunction) &&
(aggregate->getOp() != EOpSequence);
}
- else if (const TIntermSelection *selection = node->getAsSelectionNode())
+ else if (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();
+ return false;
}
else if (node->getAsLoopNode())
{
return false;
}
else if (node->getAsSwitchNode())
{
return false;
@@ -706,50 +704,50 @@ bool TOutputGLSLBase::visitUnary(Visit v
if (visit == PreVisit && node->getUseEmulatedFunction())
preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
return true;
}
+bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
+{
+ TInfoSinkBase &out = objSink();
+ // 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->getTrueExpression()->traverse(this);
+ out << ") : (";
+ node->getFalseExpression()->traverse(this);
+ out << "))";
+ return false;
+}
+
bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = objSink();
- if (node->usesTernaryOperator())
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ incrementDepth(node);
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
{
- // 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 << "))";
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
}
- else
- {
- out << "if (";
- node->getCondition()->traverse(this);
- out << ")\n";
-
- incrementDepth(node);
- visitCodeBlock(node->getTrueBlock());
-
- if (node->getFalseBlock())
- {
- out << "else\n";
- visitCodeBlock(node->getFalseBlock());
- }
- decrementDepth();
- }
+ decrementDepth();
return false;
}
bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
{
if (node->getStatementList())
{
writeTriplet(visit, "switch (", ") ", nullptr);
--- a/gfx/angle/src/compiler/translator/OutputGLSLBase.h
+++ b/gfx/angle/src/compiler/translator/OutputGLSLBase.h
@@ -39,16 +39,17 @@ class TOutputGLSLBase : public TIntermTr
const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion);
void writeConstructorTriplet(Visit visit, const TType &type);
TString getTypeName(const TType &type);
void visitSymbol(TIntermSymbol *node) override;
void visitConstantUnion(TIntermConstantUnion *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitUnary(Visit visit, TIntermUnary *node) override;
+ bool visitTernary(Visit visit, TIntermTernary *node) override;
bool visitSelection(Visit visit, TIntermSelection *node) override;
bool visitSwitch(Visit visit, TIntermSwitch *node) override;
bool visitCase(Visit visit, TIntermCase *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitLoop(Visit visit, TIntermLoop *node) override;
bool visitBranch(Visit visit, TIntermBranch *node) override;
void visitCodeBlock(TIntermNode *node);
--- a/gfx/angle/src/compiler/translator/OutputHLSL.cpp
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.cpp
@@ -75,21 +75,24 @@ const TConstantUnion *WriteConstantUnion
return constUnionIterated;
}
} // namespace
namespace sh
{
-OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion,
- const TExtensionBehavior &extensionBehavior,
- const char *sourcePath, ShShaderOutput outputType,
- int numRenderTargets, const std::vector<Uniform> &uniforms,
- int compileOptions)
+OutputHLSL::OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions)
: TIntermTraverser(true, true, true),
mShaderType(shaderType),
mShaderVersion(shaderVersion),
mExtensionBehavior(extensionBehavior),
mSourcePath(sourcePath),
mOutputType(outputType),
mCompileOptions(compileOptions),
mNumRenderTargets(numRenderTargets),
@@ -1451,19 +1454,18 @@ bool OutputHLSL::visitAggregate(Visit vi
(*sit)->traverse(this);
// Don't output ; after case labels, they're terminated by :
// This is needed especially since outputting a ; after a case statement would turn empty
// case statements into non-empty case statements, disallowing fall-through from them.
// Also no need to output ; after selection (if) statements or sequences. This is done just
// for code clarity.
- TIntermSelection *asSelection = (*sit)->getAsSelectionNode();
- ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator());
- if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit))
+ if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsSelectionNode() == nullptr &&
+ !IsSequence(*sit))
out << ";\n";
}
if (mInsideFunction)
{
outputLineDirective(out, node->getLine().last_line);
out << "}\n";
}
@@ -1977,21 +1979,28 @@ void OutputHLSL::writeSelection(TInfoSin
// ANGLE issue 486: Detect problematic conditional discard
if (discard)
{
mUsesDiscardRewriting = true;
}
}
+bool OutputHLSL::visitTernary(Visit, TIntermTernary *)
+{
+ // Ternary ops should have been already converted to something else in the AST. HLSL ternary
+ // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator.
+ UNREACHABLE();
+ return false;
+}
+
bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
{
TInfoSinkBase &out = getInfoSink();
- ASSERT(!node->usesTernaryOperator());
ASSERT(mInsideFunction);
// D3D errors when there is a gradient operation in a loop in an unflattened if.
if (mShaderType == GL_FRAGMENT_SHADER && mCurrentFunctionMetadata->hasGradientLoop(node))
{
out << "FLATTEN ";
}
--- a/gfx/angle/src/compiler/translator/OutputHLSL.h
+++ b/gfx/angle/src/compiler/translator/OutputHLSL.h
@@ -25,21 +25,24 @@ class TextureFunctionHLSL;
class UnfoldShortCircuit;
class UniformHLSL;
typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
class OutputHLSL : public TIntermTraverser
{
public:
- OutputHLSL(sh::GLenum shaderType, int shaderVersion,
- const TExtensionBehavior &extensionBehavior,
- const char *sourcePath, ShShaderOutput outputType,
- int numRenderTargets, const std::vector<Uniform> &uniforms,
- int compileOptions);
+ OutputHLSL(sh::GLenum shaderType,
+ int shaderVersion,
+ const TExtensionBehavior &extensionBehavior,
+ const char *sourcePath,
+ ShShaderOutput outputType,
+ int numRenderTargets,
+ const std::vector<Uniform> &uniforms,
+ ShCompileOptions compileOptions);
~OutputHLSL();
void output(TIntermNode *treeRoot, TInfoSinkBase &objSink);
const std::map<std::string, unsigned int> &getInterfaceBlockRegisterMap() const;
const std::map<std::string, unsigned int> &getUniformRegisterMap() const;
@@ -53,16 +56,17 @@ class OutputHLSL : public TIntermTravers
void header(TInfoSinkBase &out, const BuiltInFunctionEmulator *builtInFunctionEmulator);
// 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 visitTernary(Visit visit, TIntermTernary *);
bool visitSelection(Visit visit, TIntermSelection*);
bool visitSwitch(Visit visit, TIntermSwitch *);
bool visitCase(Visit visit, TIntermCase *);
bool visitAggregate(Visit visit, TIntermAggregate*);
bool visitLoop(Visit visit, TIntermLoop*);
bool visitBranch(Visit visit, TIntermBranch*);
bool isSingleStatement(TIntermNode *node);
@@ -112,17 +116,17 @@ class OutputHLSL : public TIntermTravers
// Ensures if the type is a struct, the struct is defined
void ensureStructDefined(const TType &type);
sh::GLenum mShaderType;
int mShaderVersion;
const TExtensionBehavior &mExtensionBehavior;
const char *mSourcePath;
const ShShaderOutput mOutputType;
- int mCompileOptions;
+ ShCompileOptions mCompileOptions;
bool mInsideFunction;
// Output streams
TInfoSinkBase mHeader;
TInfoSinkBase mBody;
TInfoSinkBase mFooter;
--- a/gfx/angle/src/compiler/translator/ParseContext.cpp
+++ b/gfx/angle/src/compiler/translator/ParseContext.cpp
@@ -208,16 +208,22 @@ void TParseContext::binaryOpError(const
}
void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
TPrecision precision,
TBasicType type)
{
if (!mChecksPrecisionErrors)
return;
+
+ if (precision != EbpUndefined && !SupportsPrecision(type))
+ {
+ error(line, "illegal type for precision qualifier", getBasicString(type));
+ }
+
if (precision == EbpUndefined)
{
switch (type)
{
case EbtFloat:
error(line, "No precision specified for (float)", "");
return;
case EbtInt:
@@ -442,21 +448,16 @@ bool TParseContext::checkIsNotReserved(c
error(line, reservedErrMsg, "webgl_");
return false;
}
if (identifier.compare(0, 7, "_webgl_") == 0)
{
error(line, reservedErrMsg, "_webgl_");
return false;
}
- if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0)
- {
- error(line, reservedErrMsg, "css_");
- return false;
- }
}
if (identifier.find("__") != TString::npos)
{
error(line,
"identifiers containing two consecutive underscores (__) are reserved as "
"possible future keywords",
identifier.c_str());
return false;
@@ -656,24 +657,24 @@ void TParseContext::checkIsScalarBool(co
error(line, "boolean expression expected", "");
}
}
// This function checks to see if the node (for the expression) contains a scalar boolean expression
// or not.
void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType)
{
- if (pType.type != EbtBool || pType.isAggregate())
+ if (pType.getBasicType() != EbtBool || pType.isAggregate())
{
error(line, "boolean expression expected", "");
}
}
bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
- const TPublicType &pType,
+ const TTypeSpecifierNonArray &pType,
const char *reason)
{
if (pType.type == EbtStruct)
{
if (containsSampler(*pType.userDef))
{
error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
return false;
@@ -818,17 +819,17 @@ bool TParseContext::checkIsValidTypeForA
{
error(line, "cannot declare arrays of arrays",
TType(elementType).getCompleteString().c_str());
return false;
}
// In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
// In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
// 4.3.4).
- if (mShaderVersion >= 300 && elementType.type == EbtStruct &&
+ if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
sh::IsVarying(elementType.qualifier))
{
error(line, "cannot declare arrays of structs of this qualifier",
TType(elementType).getCompleteString().c_str());
return false;
}
return true;
@@ -923,37 +924,34 @@ bool TParseContext::declareVariable(cons
}
if (!checkIsNonVoid(line, identifier, type.getBasicType()))
return false;
return true;
}
-void TParseContext::checkIsParameterQualifierValid(const TSourceLoc &line,
- TQualifier qualifier,
- TQualifier paramQualifier,
- TType *type)
+void TParseContext::checkIsParameterQualifierValid(
+ const TSourceLoc &line,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TType *type)
{
- if (qualifier != EvqConst && qualifier != EvqTemporary)
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics);
+
+ if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
{
- error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
- return;
+ checkOutParameterIsNotSampler(line, typeQualifier.qualifier, *type);
}
- if (qualifier == EvqConst && paramQualifier != EvqIn)
+
+ type->setQualifier(typeQualifier.qualifier);
+
+ if (typeQualifier.precision != EbpUndefined)
{
- error(line, "qualifier not allowed with ", getQualifierString(qualifier),
- getQualifierString(paramQualifier));
- return;
+ type->setPrecision(typeQualifier.precision);
}
-
- if (qualifier == EvqConst)
- type->setQualifier(EvqConstReadOnly);
- else
- type->setQualifier(paramQualifier);
}
bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension)
{
const TExtensionBehavior &extBehavior = extensionBehavior();
TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
if (iter == extBehavior.end())
{
@@ -983,29 +981,30 @@ void TParseContext::singleDeclarationErr
switch (publicType.qualifier)
{
case EvqVaryingIn:
case EvqVaryingOut:
case EvqAttribute:
case EvqVertexIn:
case EvqFragmentOut:
case EvqComputeIn:
- if (publicType.type == EbtStruct)
+ if (publicType.getBasicType() == EbtStruct)
{
error(identifierLocation, "cannot be used with a structure",
getQualifierString(publicType.qualifier));
return;
}
default:
break;
}
if (publicType.qualifier != EvqUniform &&
- !checkIsNotSampler(identifierLocation, publicType, "samplers must be uniform"))
+ !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
+ "samplers must be uniform"))
{
return;
}
// check for layout qualifier issues
const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
if (layoutQualifier.matrixPacking != EmpUnspecified)
@@ -1072,22 +1071,37 @@ void TParseContext::functionCallLValueEr
error(argument->getLine(),
"Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
return;
}
}
}
}
-void TParseContext::checkInvariantIsOutVariableES3(const TQualifier qualifier,
- const TSourceLoc &invariantLocation)
+void TParseContext::checkInvariantVariableQualifier(bool invariant,
+ const TQualifier qualifier,
+ const TSourceLoc &invariantLocation)
{
- if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut)
+ if (!invariant)
+ return;
+
+ if (mShaderVersion < 300)
{
- error(invariantLocation, "Only out variables can be invariant.", "invariant");
+ // input variables in the fragment shader can be also qualified as invariant
+ if (!sh::CanBeInvariantESSL1(qualifier))
+ {
+ error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
+ }
+ }
+ else
+ {
+ if (!sh::CanBeInvariantESSL3OrGreater(qualifier))
+ {
+ error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
+ }
}
}
bool TParseContext::supportsExtension(const char *extension)
{
const TExtensionBehavior &extbehavior = extensionBehavior();
TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
return (iter != extbehavior.end());
@@ -1380,74 +1394,90 @@ bool TParseContext::executeInitializer(c
{
assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
return true;
}
return false;
}
-TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
- bool invariant,
- TLayoutQualifier layoutQualifier,
+TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
const TPublicType &typeSpecifier)
{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
TPublicType returnType = typeSpecifier;
- returnType.qualifier = qualifier;
- returnType.invariant = invariant;
- returnType.layoutQualifier = layoutQualifier;
-
- checkWorkGroupSizeIsNotSpecified(typeSpecifier.line, layoutQualifier);
+ returnType.qualifier = typeQualifier.qualifier;
+ returnType.invariant = typeQualifier.invariant;
+ returnType.layoutQualifier = typeQualifier.layoutQualifier;
+ returnType.precision = typeSpecifier.precision;
+
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ returnType.precision = typeQualifier.precision;
+ }
+
+ checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision,
+ typeSpecifier.getBasicType());
+
+ checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier,
+ typeSpecifier.getLine());
+
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier);
if (mShaderVersion < 300)
{
if (typeSpecifier.array)
{
- error(typeSpecifier.line, "not supported", "first-class array");
+ error(typeSpecifier.getLine(), "not supported", "first-class array");
returnType.clearArrayness();
}
- if (qualifier == EvqAttribute &&
- (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
+ if (returnType.qualifier == EvqAttribute &&
+ (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
{
- error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
+ error(typeSpecifier.getLine(), "cannot be bool or int",
+ getQualifierString(returnType.qualifier));
}
- if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
- (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
+ if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) &&
+ (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
{
- error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
+ error(typeSpecifier.getLine(), "cannot be bool or int",
+ getQualifierString(returnType.qualifier));
}
}
else
{
- if (!layoutQualifier.isEmpty())
+ if (!returnType.layoutQualifier.isEmpty())
{
- checkIsAtGlobalLevel(typeSpecifier.line, "layout");
+ checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout");
}
- if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut)
+ if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn ||
+ returnType.qualifier == EvqFragmentOut)
{
- checkInputOutputTypeIsValidES3(qualifier, typeSpecifier, typeSpecifier.line);
+ checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier,
+ typeSpecifier.getLine());
}
- if (qualifier == EvqComputeIn)
+ if (returnType.qualifier == EvqComputeIn)
{
- error(typeSpecifier.line, "'in' can be only used to specify the local group size",
+ error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size",
"in");
}
}
return returnType;
}
void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TPublicType &type,
const TSourceLoc &qualifierLocation)
{
// An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
- if (type.type == EbtBool)
+ if (type.getBasicType() == EbtBool)
{
error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
}
// Specific restrictions apply for vertex shader inputs and fragment shader outputs.
switch (qualifier)
{
case EvqVertexIn:
@@ -1455,38 +1485,38 @@ void TParseContext::checkInputOutputType
if (type.array)
{
error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
}
// Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
return;
case EvqFragmentOut:
// ESSL 3.00 section 4.3.6
- if (type.isMatrix())
+ if (type.typeSpecifierNonArray.isMatrix())
{
error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
}
// Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
return;
default:
break;
}
// Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
// restrictions.
bool typeContainsIntegers =
- (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) ||
- type.isStructureContainingType(EbtUInt));
+ (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
+ type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
{
error(qualifierLocation, "must use 'flat' interpolation here",
getQualifierString(qualifier));
}
- if (type.type == EbtStruct)
+ if (type.getBasicType() == EbtStruct)
{
// ESSL 3.00 sections 4.3.4 and 4.3.6.
// These restrictions are only implied by the ESSL 3.00 spec, but
// the ESSL 3.10 spec lists these restrictions explicitly.
if (type.array)
{
error(qualifierLocation, "cannot be an array of structures",
getQualifierString(qualifier));
@@ -1663,50 +1693,68 @@ TIntermAggregate *TParseContext::parseSi
return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
}
else
{
return nullptr;
}
}
-TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
- const TSourceLoc &identifierLoc,
- const TString *identifier,
- const TSymbol *symbol)
+TIntermAggregate *TParseContext::parseInvariantDeclaration(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &identifierLoc,
+ const TString *identifier,
+ const TSymbol *symbol)
{
- // invariant declaration
- if (!checkIsAtGlobalLevel(invariantLoc, "invariant varying"))
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
+ if (!typeQualifier.invariant)
+ {
+ error(identifierLoc, "Expected invariant", identifier->c_str());
return nullptr;
-
+ }
+ if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
+ {
+ return nullptr;
+ }
if (!symbol)
{
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
return nullptr;
}
- else
+ if (!IsQualifierUnspecified(typeQualifier.qualifier))
+ {
+ error(identifierLoc, "invariant declaration specifies qualifier",
+ getQualifierString(typeQualifier.qualifier));
+ }
+ if (typeQualifier.precision != EbpUndefined)
+ {
+ error(identifierLoc, "invariant declaration specifies precision",
+ getPrecisionString(typeQualifier.precision));
+ }
+ if (!typeQualifier.layoutQualifier.isEmpty())
{
- const TString kGlFrontFacing("gl_FrontFacing");
- if (*identifier == kGlFrontFacing)
- {
- error(identifierLoc, "identifier should not be declared as invariant",
- identifier->c_str());
- return nullptr;
- }
- symbolTable.addInvariantVarying(std::string(identifier->c_str()));
- const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
- ASSERT(variable);
- const TType &type = variable->getType();
- TIntermSymbol *intermSymbol =
- intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
-
- TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
- aggregate->setOp(EOpInvariantDeclaration);
- return aggregate;
+ error(identifierLoc, "invariant declaration specifies layout", "'layout'");
}
+
+ const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
+ ASSERT(variable);
+ const TType &type = variable->getType();
+
+ checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(),
+ typeQualifier.line);
+
+ symbolTable.addInvariantVarying(std::string(identifier->c_str()));
+
+ TIntermSymbol *intermSymbol =
+ intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
+
+ TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
+ aggregate->setOp(EOpInvariantDeclaration);
+ return aggregate;
}
TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
TIntermAggregate *aggregateDeclaration,
const TSourceLoc &identifierLocation,
const TString &identifier)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
@@ -1857,20 +1905,24 @@ TIntermAggregate *TParseContext::parseAr
}
}
else
{
return nullptr;
}
}
-void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
+void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
{
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
+ checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
+ typeQualifier.line);
+
// It should never be the case, but some strange parser errors can send us here.
if (layoutQualifier.isEmpty())
{
error(typeQualifier.line, "Error during layout qualifier parsing.", "?");
return;
}
if (!layoutQualifier.isCombinationValid())
@@ -2216,17 +2268,18 @@ TFunction *TParseContext::parseFunctionH
error(location, "no qualifiers allowed for function return",
getQualifierString(type.qualifier));
}
if (!type.layoutQualifier.isEmpty())
{
error(location, "no qualifiers allowed for function return", "layout");
}
// make sure a sampler is not involved as well...
- checkIsNotSampler(location, type, "samplers can't be function return values");
+ checkIsNotSampler(location, type.typeSpecifierNonArray,
+ "samplers can't be function return values");
if (mShaderVersion < 300)
{
// Array return values are forbidden, but there's also no valid syntax for declaring array
// return values in ESSL 1.00.
ASSERT(type.arraySize == 0 || mDiagnostics.numErrors() > 0);
if (type.isStructureContainingArrays())
{
@@ -2238,34 +2291,35 @@ TFunction *TParseContext::parseFunctionH
// Add the function as a prototype after parsing it (we do not support recursion)
return new TFunction(name, new TType(type));
}
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
TPublicType publicType = publicTypeIn;
- if (publicType.isStructSpecifier)
+ if (publicType.isStructSpecifier())
{
- error(publicType.line, "constructor can't be a structure definition",
- getBasicString(publicType.type));
+ error(publicType.getLine(), "constructor can't be a structure definition",
+ getBasicString(publicType.getBasicType()));
}
TOperator op = EOpNull;
- if (publicType.userDef)
+ if (publicType.getUserDef())
{
op = EOpConstructStruct;
}
else
{
op = sh::TypeToConstructorOperator(TType(publicType));
if (op == EOpNull)
{
- error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
- publicType.type = EbtFloat;
+ error(publicType.getLine(), "cannot construct this type",
+ getBasicString(publicType.getBasicType()));
+ publicType.setBasicType(EbtFloat);
op = EOpConstructFloat;
}
}
TString tempString;
const TType *type = new TType(publicType);
return new TFunction(&tempString, type, op);
}
@@ -2317,137 +2371,53 @@ TIntermTyped *TParseContext::addConstruc
if (op != EOpConstructStruct)
{
constructor->setPrecisionFromChildren();
type.setPrecision(constructor->getPrecision());
}
constructor->setType(type);
- TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor);
+ TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
if (constConstructor)
{
return constConstructor;
}
return constructor;
}
-// This function returns vector field(s) being accessed from a constant vector.
-TIntermConstantUnion *TParseContext::foldVectorSwizzle(TVectorFields &fields,
- TIntermConstantUnion *baseNode,
- const TSourceLoc &location)
-{
- const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
- ASSERT(unionArray);
-
- TConstantUnion *constArray = new TConstantUnion[fields.num];
- const auto &type = baseNode->getType();
-
- for (int i = 0; i < fields.num; i++)
- {
- // Out-of-range indices should already be checked.
- ASSERT(fields.offsets[i] < type.getNominalSize());
- constArray[i] = unionArray[fields.offsets[i]];
- }
- return intermediate.addConstantUnion(constArray, type, location);
-}
-
-// This function returns the column vector being accessed from a constant matrix.
-TIntermConstantUnion *TParseContext::foldMatrixSubscript(int index,
- TIntermConstantUnion *baseNode,
- const TSourceLoc &location)
-{
- ASSERT(index < baseNode->getType().getCols());
-
- const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
- int size = baseNode->getType().getRows();
- return intermediate.addConstantUnion(&unionArray[size * index], baseNode->getType(), location);
-}
-
-// This function returns an element of an array accessed from a constant array.
-TIntermConstantUnion *TParseContext::foldArraySubscript(int index,
- TIntermConstantUnion *baseNode,
- const TSourceLoc &location)
-{
- ASSERT(index < static_cast<int>(baseNode->getArraySize()));
-
- TType arrayElementType = baseNode->getType();
- arrayElementType.clearArrayness();
- size_t arrayElementSize = arrayElementType.getObjectSize();
- const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
- return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], baseNode->getType(),
- location);
-}
-
-//
-// 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)
- {
- const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
-
- // type will be changed in the calling function
- typedNode = intermediate.addConstantUnion(constArray + instanceSize,
- tempConstantNode->getType(), line);
- }
- else
- {
- error(line, "Cannot offset into the structure", "Error");
- return nullptr;
- }
-
- 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)
+TIntermAggregate *TParseContext::addInterfaceBlock(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ const TSourceLoc &nameLine,
+ const TString &blockName,
+ TFieldList *fieldList,
+ const TString *instanceName,
+ const TSourceLoc &instanceLine,
+ TIntermTyped *arrayIndex,
+ const TSourceLoc &arrayIndexLine)
{
checkIsNotReserved(nameLine, blockName);
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
if (typeQualifier.qualifier != EvqUniform)
{
error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
"interface blocks must be uniform");
}
+ if (typeQualifier.invariant)
+ {
+ error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
+ }
+
TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
if (blockLayoutQualifier.matrixPacking == EmpUnspecified)
{
blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking;
}
@@ -2482,16 +2452,21 @@ TIntermAggregate *TParseContext::addInte
case EvqUniform:
break;
default:
error(field->line(), "invalid qualifier on interface block member",
getQualifierString(qualifier));
break;
}
+ if (fieldType->isInvariant())
+ {
+ error(field->line(), "invalid qualifier on interface block member", "invariant");
+ }
+
// check layout qualifiers
TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
{
error(field->line(), "invalid layout qualifier:",
getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here");
@@ -2625,29 +2600,32 @@ void TParseContext::checkIsBelowStructNe
//
// 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");
}
+
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst),
+ location);
}
TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
// TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
// to constant fold all constant expressions. Right now we don't allow indexing interface blocks
// or fragment outputs with expressions that ANGLE is not able to constant fold, even if the
// index is a constant expression.
@@ -2667,161 +2645,88 @@ TIntermTyped *TParseContext::addIndexExp
else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
{
error(location, "", "[", "array index for gl_FragData must be constant zero");
}
}
if (indexConstantUnion)
{
- // If the index is not qualified as constant, the behavior in the spec is undefined. This
- // applies even if ANGLE has been able to constant fold it (ANGLE may constant fold
- // expressions that are not constant expressions). The most compatible way to handle this
- // case is to report a warning instead of an error and force the index to be in the
- // correct range.
+ // If an out-of-range index is not qualified as constant, the behavior in the spec is
+ // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may
+ // constant fold expressions that are not constant expressions). The most compatible way to
+ // handle this case is to report a warning instead of an error and force the index to be in
+ // the correct range.
bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
int index = indexConstantUnion->getIConst(0);
- if (!baseExpression->isArray())
+
+ int safeIndex = -1;
+
+ if (baseExpression->isArray())
{
- // Array checks are done later because a different error message might be generated
- // based on the index in some cases.
- if (baseExpression->isVector())
+ if (baseExpression->getQualifier() == EvqFragData && index > 0)
{
- index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
- baseExpression->getType().getNominalSize(),
- "vector field selection out of range", "[]");
+ if (mShaderSpec == SH_WEBGL2_SPEC)
+ {
+ // Error has been already generated if index is not const.
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ error(location, "", "[",
+ "array index for gl_FragData must be constant zero");
+ }
+ safeIndex = 0;
+ }
+ else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
+ {
+ outOfRangeError(outOfRangeIndexIsError, location, "", "[",
+ "array index for gl_FragData must be zero when "
+ "GL_EXT_draw_buffers is disabled");
+ safeIndex = 0;
+ }
}
- else if (baseExpression->isMatrix())
+ // Only do generic out-of-range check if similar error hasn't already been reported.
+ if (safeIndex < 0)
{
- index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
- baseExpression->getType().getCols(),
- "matrix field selection out of range", "[]");
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getArraySize(),
+ "array index out of range", "[]");
}
}
-
- TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion();
- if (baseConstantUnion)
+ else if (baseExpression->isMatrix())
{
- if (baseExpression->isArray())
- {
- index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
- baseExpression->getArraySize(),
- "array index out of range", "[]");
- // Constant folding for array indexing.
- indexedExpression = foldArraySubscript(index, baseConstantUnion, location);
- }
- else if (baseExpression->isVector())
- {
- // Constant folding for vector indexing - reusing vector swizzle folding.
- TVectorFields fields;
- fields.num = 1;
- fields.offsets[0] = index;
- indexedExpression = foldVectorSwizzle(fields, baseConstantUnion, location);
- }
- else if (baseExpression->isMatrix())
- {
- // Constant folding for matrix indexing.
- indexedExpression = foldMatrixSubscript(index, baseConstantUnion, location);
- }
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getCols(),
+ "matrix field selection out of range", "[]");
}
- else
+ else if (baseExpression->isVector())
{
- int safeIndex = -1;
-
- if (baseExpression->isArray())
- {
- if (baseExpression->getQualifier() == EvqFragData && index > 0)
- {
- if (mShaderSpec == SH_WEBGL2_SPEC)
- {
- // Error has been already generated if index is not const.
- if (indexExpression->getQualifier() == EvqConst)
- {
- error(location, "", "[",
- "array index for gl_FragData must be constant zero");
- }
- safeIndex = 0;
- }
- else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
- {
- outOfRangeError(outOfRangeIndexIsError, location, "", "[",
- "array index for gl_FragData must be zero when "
- "GL_EXT_draw_buffers is disabled");
- safeIndex = 0;
- }
- }
- // Only do generic out-of-range check if similar error hasn't already been reported.
- if (safeIndex < 0)
- {
- safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
- baseExpression->getArraySize(),
- "array index out of range", "[]");
- }
- }
-
- // Data of constant unions can't be changed, because it may be shared with other
- // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
- // sanitized object.
- if (safeIndex != -1)
- {
- TConstantUnion *safeConstantUnion = new TConstantUnion();
- safeConstantUnion->setIConst(safeIndex);
- indexConstantUnion->replaceConstantUnion(safeConstantUnion);
- }
-
- indexedExpression =
- intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getNominalSize(),
+ "vector field selection out of range", "[]");
}
+
+ ASSERT(safeIndex >= 0);
+ // Data of constant unions can't be changed, because it may be shared with other
+ // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new
+ // sanitized object.
+ if (safeIndex != index)
+ {
+ TConstantUnion *safeConstantUnion = new TConstantUnion();
+ safeConstantUnion->setIConst(safeIndex);
+ indexConstantUnion->replaceConstantUnion(safeConstantUnion);
+ }
+
+ return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
+ &mDiagnostics);
}
else
{
- indexedExpression =
- intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
- }
-
- if (indexedExpression == 0)
- {
- TConstantUnion *unionArray = new TConstantUnion[1];
- unionArray->setFConst(0.0f);
- indexedExpression =
- intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
- }
- else if (baseExpression->isArray())
- {
- TType indexedType = baseExpression->getType();
- indexedType.clearArrayness();
- indexedExpression->setType(indexedType);
+ return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
+ &mDiagnostics);
}
- else if (baseExpression->isMatrix())
- {
- indexedExpression->setType(TType(baseExpression->getBasicType(),
- baseExpression->getPrecision(), EvqTemporary,
- static_cast<unsigned char>(baseExpression->getRows())));
- }
- else if (baseExpression->isVector())
- {
- indexedExpression->setType(
- TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary));
- }
- else
- {
- indexedExpression->setType(baseExpression->getType());
- }
-
- if (baseExpression->getType().getQualifier() == EvqConst &&
- indexExpression->getType().getQualifier() == EvqConst)
- {
- indexedExpression->getTypePointer()->setQualifier(EvqConst);
- }
- else
- {
- indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
- }
-
- return indexedExpression;
}
int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError,
const TSourceLoc &location,
int index,
int arraySize,
const char *reason,
const char *token)
@@ -2844,143 +2749,101 @@ int TParseContext::checkIndexOutOfRange(
return index;
}
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", ".");
+ return baseExpression;
}
if (baseExpression->isVector())
{
TVectorFields fields;
if (!parseVectorFields(fieldString, baseExpression->getNominalSize(), fields,
fieldLocation))
{
fields.num = 1;
fields.offsets[0] = 0;
}
- if (baseExpression->getAsConstantUnion())
- {
- // constant folding for vector fields
- indexedExpression =
- foldVectorSwizzle(fields, baseExpression->getAsConstantUnion(), fieldLocation);
- }
- else
- {
- TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
- indexedExpression =
- intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
- }
- if (indexedExpression == nullptr)
- {
- indexedExpression = baseExpression;
- }
- else
- {
- // Note that the qualifier set here will be corrected later.
- indexedExpression->setType(TType(baseExpression->getBasicType(),
- baseExpression->getPrecision(), EvqTemporary,
- static_cast<unsigned char>(fields.num)));
- }
+ TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
+ return intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation,
+ &mDiagnostics);
}
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");
- indexedExpression = baseExpression;
+ return baseExpression;
}
else
{
+ bool fieldFound = false;
unsigned int i;
for (i = 0; i < fields.size(); ++i)
{
if (fields[i]->name() == fieldString)
{
fieldFound = true;
break;
}
}
if (fieldFound)
{
- if (baseExpression->getAsConstantUnion())
- {
- indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
- if (indexedExpression == 0)
- {
- indexedExpression = baseExpression;
- }
- else
- {
- indexedExpression->setType(*fields[i]->type());
- }
- }
- else
- {
- TConstantUnion *unionArray = new TConstantUnion[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());
- }
+ TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
+ dotLocation, &mDiagnostics);
}
else
{
error(dotLocation, " no such field in structure", fieldString.c_str());
- indexedExpression = baseExpression;
+ return 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");
- indexedExpression = baseExpression;
+ return baseExpression;
}
else
{
+ bool fieldFound = false;
unsigned int i;
for (i = 0; i < fields.size(); ++i)
{
if (fields[i]->name() == fieldString)
{
fieldFound = true;
break;
}
}
if (fieldFound)
{
- TConstantUnion *unionArray = new TConstantUnion[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());
+ TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
+ index->setLine(fieldLocation);
+ return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
+ dotLocation, &mDiagnostics);
}
else
{
error(dotLocation, " no such field in interface block", fieldString.c_str());
- indexedExpression = baseExpression;
+ return baseExpression;
}
}
}
else
{
if (mShaderVersion < 300)
{
error(dotLocation, " field selection requires structure or vector on left hand side",
@@ -2988,29 +2851,18 @@ TIntermTyped *TParseContext::addFieldSel
}
else
{
error(dotLocation,
" field selection requires structure, vector, or interface block on left hand "
"side",
fieldString.c_str());
}
- indexedExpression = baseExpression;
- }
-
- if (baseExpression->getQualifier() == EvqConst)
- {
- indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ return baseExpression;
}
- else
- {
- indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
- }
-
- return indexedExpression;
}
TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine)
{
TLayoutQualifier qualifier = TLayoutQualifier::create();
if (qualifierType == "shared")
@@ -3078,16 +2930,17 @@ TLayoutQualifier TParseContext::parseLay
if (intValue < 0)
{
error(intValueLine, "out of range:", intValueString.c_str(),
"location must be non-negative");
}
else
{
qualifier.location = intValue;
+ qualifier.locationsSpecified = 1;
}
}
else if (qualifierType == "local_size_x")
{
parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u,
&qualifier.localSize);
}
else if (qualifierType == "local_size_y")
@@ -3103,159 +2956,100 @@ TLayoutQualifier TParseContext::parseLay
else
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
}
return qualifier;
}
+TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
+{
+ return new TTypeQualifierBuilder(
+ new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
+ mShaderVersion);
+}
+
TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation)
{
- 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;
- }
-
- for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
- {
- if (rightQualifier.localSize[i] != -1)
- {
- if (joinedQualifier.localSize[i] != -1 &&
- joinedQualifier.localSize[i] != rightQualifier.localSize[i])
- {
- error(rightQualifierLocation,
- "Cannot have multiple different work group size specifiers",
- getWorkGroupSizeString(i));
- }
- joinedQualifier.localSize[i] = rightQualifier.localSize[i];
- }
- }
-
- return joinedQualifier;
+ return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
+ &mDiagnostics);
}
-TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
- TQualifier interpolationQualifier,
- const TSourceLoc &storageLoc,
- TQualifier storageQualifier)
+TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
+ const TTypeQualifierBuilder &typeQualifierBuilder,
+ TPublicType *typeSpecifier,
+ TFieldList *fieldList)
{
- TQualifier mergedQualifier = EvqSmoothIn;
-
- if (storageQualifier == EvqFragmentIn)
+ TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+
+ typeSpecifier->qualifier = typeQualifier.qualifier;
+ typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
+ typeSpecifier->invariant = typeQualifier.invariant;
+ if (typeQualifier.precision != EbpUndefined)
{
- 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();
+ typeSpecifier->precision = typeQualifier.precision;
}
- 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));
-
- mergedQualifier = storageQualifier;
- }
-
- TPublicType type;
- type.setBasic(EbtVoid, mergedQualifier, storageLoc);
- return type;
+ return addStructDeclaratorList(*typeSpecifier, fieldList);
}
TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
TFieldList *fieldList)
{
- checkIsNonVoid(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type);
-
- checkWorkGroupSizeIsNotSpecified(typeSpecifier.line, typeSpecifier.layoutQualifier);
+ checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
+ typeSpecifier.getBasicType());
+
+ checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType());
+
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
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->setBasicType(typeSpecifier.getBasicType());
+ type->setPrimarySize(typeSpecifier.getPrimarySize());
+ type->setSecondarySize(typeSpecifier.getSecondarySize());
type->setPrecision(typeSpecifier.precision);
type->setQualifier(typeSpecifier.qualifier);
type->setLayoutQualifier(typeSpecifier.layoutQualifier);
+ type->setInvariant(typeSpecifier.invariant);
// don't allow arrays of arrays
if (type->isArray())
{
- checkIsValidTypeForArray(typeSpecifier.line, typeSpecifier);
+ checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
}
if (typeSpecifier.array)
type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize));
- if (typeSpecifier.userDef)
+ if (typeSpecifier.getUserDef())
{
- type->setStruct(typeSpecifier.userDef->getStruct());
+ type->setStruct(typeSpecifier.getUserDef()->getStruct());
}
- checkIsBelowStructNestingLimit(typeSpecifier.line, *(*fieldList)[i]);
+ checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]);
}
return fieldList;
}
-TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
- const TSourceLoc &nameLine,
- const TString *structName,
- TFieldList *fieldList)
+TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList)
{
TStructure *structure = new TStructure(structName, fieldList);
TType *structureType = new TType(structure);
// Store a bool in the struct if we're at global scope, to allow us to
// skip the local struct scoping workaround in HLSL.
- structure->setUniqueId(TSymbolTable::nextUniqueId());
structure->setAtGlobalScope(symbolTable.atGlobalLevel());
if (!structName->empty())
{
checkIsNotReserved(nameLine, *structName);
TVariable *userTypeDef = new TVariable(structName, *structureType, true);
if (!symbolTable.declare(userTypeDef))
{
@@ -3273,25 +3067,31 @@ TPublicType TParseContext::addStructure(
case EvqGlobal:
case EvqTemporary:
break;
default:
error(field.line(), "invalid qualifier on struct member",
getQualifierString(qualifier));
break;
}
+ if (field.type()->isInvariant())
+ {
+ error(field.line(), "invalid qualifier on struct member", "invariant");
+ }
+
+ checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
}
- TPublicType publicType;
- publicType.setBasic(EbtStruct, EvqTemporary, structLine);
- publicType.userDef = structureType;
- publicType.isStructSpecifier = true;
+ TTypeSpecifierNonArray typeSpecifierNonArray;
+ typeSpecifierNonArray.initialize(EbtStruct, structLine);
+ typeSpecifierNonArray.userDef = structureType;
+ typeSpecifierNonArray.isStructSpecifier = true;
exitStructDeclaration();
- return publicType;
+ return typeSpecifierNonArray;
}
TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
TIntermAggregate *statementList,
const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
if ((switchType != EbtInt && switchType != EbtUInt) || init->isMatrix() || init->isArray() ||
@@ -3406,17 +3206,24 @@ TIntermTyped *TParseContext::createUnary
{
return nullptr;
}
// Operators for built-ins are already type checked against their prototype.
default:
break;
}
- return intermediate.addUnaryMath(op, child, loc, funcReturnType);
+ TIntermUnary *node = new TIntermUnary(op, child);
+ node->setLine(loc);
+
+ TIntermTyped *foldedNode = node->fold(&mDiagnostics);
+ if (foldedNode)
+ return foldedNode;
+
+ return node;
}
TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
{
TIntermTyped *node = createUnaryMath(op, child, loc, nullptr);
if (node == nullptr)
{
unaryOpError(loc, GetOperatorString(op), child->getCompleteString());
@@ -4035,17 +3842,18 @@ TIntermTyped *TParseContext::addFunction
aggregate->getTypePointer()->setQualifier(EvqConst);
}
// Some built-in functions have out parameters too.
functionCallLValueErrorCheck(fnCandidate, aggregate);
// See if we can constant fold a built-in. Note that this may be possible even
// if it is not const-qualified.
- TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
+ TIntermTyped *foldedNode =
+ intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics);
if (foldedNode)
{
callNode = foldedNode;
}
else
{
callNode = aggregate;
}
@@ -4090,44 +3898,45 @@ TIntermTyped *TParseContext::addFunction
callNode = intermediate.addConstantUnion(unionArray,
TType(EbtFloat, EbpUndefined, EvqConst), loc);
}
}
return callNode;
}
TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
- TIntermTyped *trueBlock,
- TIntermTyped *falseBlock,
+ TIntermTyped *trueExpression,
+ TIntermTyped *falseExpression,
const TSourceLoc &loc)
{
checkIsScalarBool(loc, cond);
- if (trueBlock->getType() != falseBlock->getType())
+ if (trueExpression->getType() != falseExpression->getType())
{
- binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
- return falseBlock;
+ binaryOpError(loc, ":", trueExpression->getCompleteString(),
+ falseExpression->getCompleteString());
+ return falseExpression;
}
// ESSL1 sections 5.2 and 5.7:
// ESSL3 section 5.7:
// Ternary operator is not among the operators allowed for structures/arrays.
- if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
+ if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
{
error(loc, "ternary operator is not allowed for structures or arrays", ":");
- return falseBlock;
+ return falseExpression;
}
// WebGL2 section 5.26, the following results in an error:
// "Ternary operator applied to void, arrays, or structs containing arrays"
- if (mShaderSpec == SH_WEBGL2_SPEC && trueBlock->getBasicType() == EbtVoid)
+ if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid)
{
error(loc, "ternary operator is not allowed for void", ":");
- return falseBlock;
+ return falseExpression;
}
- return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
+ return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
}
//
// Parse an array of strings using yyparse.
//
// Returns 0 for success.
//
int PaParseStrings(size_t count,
--- a/gfx/angle/src/compiler/translator/ParseContext.h
+++ b/gfx/angle/src/compiler/translator/ParseContext.h
@@ -6,16 +6,17 @@
#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_
#define COMPILER_TRANSLATOR_PARSECONTEXT_H_
#include "compiler/translator/Compiler.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/DirectiveHandler.h"
#include "compiler/translator/Intermediate.h"
#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/QualifierTypes.h"
#include "compiler/preprocessor/Preprocessor.h"
struct TMatrixFields
{
bool wholeRow;
bool wholeCol;
int row;
int col;
@@ -25,24 +26,23 @@ struct TMatrixFields
// The following are extra variables needed during parsing, grouped together so
// they can be passed to the parser without needing a global.
//
class TParseContext : angle::NonCopyable
{
public:
TParseContext(TSymbolTable &symt,
TExtensionBehavior &ext,
- TIntermediate &interm,
sh::GLenum type,
ShShaderSpec spec,
- int options,
+ ShCompileOptions options,
bool checksPrecErrors,
TInfoSink &is,
const ShBuiltInResources &resources)
- : intermediate(interm),
+ : intermediate(),
symbolTable(symt),
mDeferredSingleDeclarationErrorCheck(false),
mShaderType(type),
mShaderSpec(spec),
mCompileOptions(options),
mShaderVersion(100),
mTreeRoot(nullptr),
mLoopNestingLevel(0),
@@ -62,17 +62,18 @@ class TParseContext : angle::NonCopyable
resources.WEBGL_debug_shader_precision == 1),
mPreprocessor(&mDiagnostics, &mDirectiveHandler),
mScanner(nullptr),
mUsesFragData(false),
mUsesFragColor(false),
mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
- mComputeShaderLocalSizeDeclared(false)
+ mComputeShaderLocalSizeDeclared(false),
+ mDeclaringFunction(false)
{
mComputeShaderLocalSize.fill(-1);
}
const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; }
pp::Preprocessor &getPreprocessor() { return mPreprocessor; }
void *getScanner() const { return mScanner; }
void setScanner(void *scanner) { mScanner = scanner; }
@@ -114,16 +115,22 @@ class TParseContext : angle::NonCopyable
void decrLoopNestingLevel() { --mLoopNestingLevel; }
void incrSwitchNestingLevel() { ++mSwitchNestingLevel; }
void decrSwitchNestingLevel() { --mSwitchNestingLevel; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
sh::WorkGroupSize getComputeShaderLocalSize() const;
+ void enterFunctionDeclaration() { mDeclaringFunction = true; }
+
+ void exitFunctionDeclaration() { mDeclaringFunction = false; }
+
+ bool declaringFunction() const { return mDeclaringFunction; }
+
// This method is guaranteed to succeed, even if no variable with 'name' exists.
const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol);
TIntermTyped *parseVariableIdentifier(const TSourceLoc &location,
const TString *name,
const TSymbol *symbol);
bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line);
@@ -147,39 +154,41 @@ class TParseContext : angle::NonCopyable
// Returns a sanitized array size to use (the size is at least 1).
unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr);
bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier);
bool checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType);
bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
- bool checkIsNotSampler(const TSourceLoc &line, const TPublicType &pType, const char *reason);
+ bool checkIsNotSampler(const TSourceLoc &line,
+ const TTypeSpecifierNonArray &pType,
+ const char *reason);
void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
void checkLocationIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
void checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkIsParameterQualifierValid(const TSourceLoc &line,
- TQualifier qualifier,
- TQualifier paramQualifier,
+ const TTypeQualifierBuilder &typeQualifierBuilder,
TType *type);
bool checkCanUseExtension(const TSourceLoc &line, const TString &extension);
void singleDeclarationErrorCheck(const TPublicType &publicType,
const TSourceLoc &identifierLocation);
void checkLayoutQualifierSupported(const TSourceLoc &location,
const TString &layoutQualifierName,
int versionRequired);
bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier);
void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall);
- void checkInvariantIsOutVariableES3(const TQualifier qualifier,
- const TSourceLoc &invariantLocation);
+ void checkInvariantVariableQualifier(bool invariant,
+ const TQualifier qualifier,
+ const TSourceLoc &invariantLocation);
void checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TPublicType &type,
const TSourceLoc &qualifierLocation);
const TPragma &pragma() const { return mDirectiveHandler.pragma(); }
const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
bool supportsExtension(const char *extension);
bool isExtensionEnabled(const char *extension) const;
@@ -190,19 +199,17 @@ class TParseContext : angle::NonCopyable
const TFunction* findFunction(
const TSourceLoc &line, TFunction *pfnCall, int inputShaderVersion, bool *builtIn = 0);
bool executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
TIntermTyped *initializer,
TIntermNode **intermNode);
- TPublicType addFullySpecifiedType(TQualifier qualifier,
- bool invariant,
- TLayoutQualifier layoutQualifier,
+ TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
const TPublicType &typeSpecifier);
TIntermAggregate *parseSingleDeclaration(TPublicType &publicType,
const TSourceLoc &identifierOrTypeLocation,
const TString &identifier);
TIntermAggregate *parseSingleArrayDeclaration(TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
@@ -219,17 +226,17 @@ class TParseContext : angle::NonCopyable
TIntermAggregate *parseSingleArrayInitDeclaration(TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
const TSourceLoc &indexLocation,
TIntermTyped *indexExpression,
const TSourceLoc &initLocation,
TIntermTyped *initializer);