Roll back to ANGLE/2845

This commit is contained in:
wolfbeast 2018-07-11 18:11:13 +02:00 committed by Roy Tam
commit 581db453db
582 changed files with 22757 additions and 56816 deletions

View file

@ -45,7 +45,6 @@
'angle_enable_gl%': 1,
}],
],
'angle_enable_null%': 1, # Available on all platforms
},
'includes':
[
@ -59,7 +58,7 @@
{
'target_name': 'angle_common',
'type': 'static_library',
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'sources':
[
'<@(libangle_common_sources)',
@ -146,7 +145,7 @@
{
'target_name': 'angle_image_util',
'type': 'static_library',
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'sources':
[
'<@(libangle_image_util_sources)',
@ -173,7 +172,7 @@
{
'target_name': 'copy_scripts',
'type': 'none',
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'hard_dependency': 1,
'copies':
[
@ -200,7 +199,7 @@
{
'target_name': 'commit_id',
'type': 'none',
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'dependencies': [ 'copy_scripts', ],
'hard_dependency': 1,
'actions':
@ -242,7 +241,7 @@
'target_name': 'commit_id',
'type': 'none',
'hard_dependency': 1,
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'copies':
[
{
@ -275,7 +274,7 @@
'target_name': 'copy_compiler_dll',
'type': 'none',
'dependencies': [ 'copy_scripts', ],
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'conditions':
[
['angle_build_winrt==0',

View file

@ -1,3 +1,3 @@
#define ANGLE_COMMIT_HASH "2a250c8a0e15"
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE "2016-11-23 17:58:16 +0800"
#define ANGLE_COMMIT_HASH ""
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE ""

View file

@ -104,6 +104,7 @@ inline unsigned long ScanForward(unsigned long bits)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
ASSERT(ret != 0);
UNUSED_ASSERTION_VARIABLE(ret);
return firstBitIndex;
#elif defined(ANGLE_PLATFORM_POSIX)
return static_cast<unsigned long>(__builtin_ctzl(bits));

View file

@ -156,14 +156,6 @@ size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>
std::string FormatString(const char *fmt, va_list vararg);
std::string FormatString(const char *fmt, ...);
template <typename T>
std::string ToString(const T &value)
{
std::ostringstream o;
o << value;
return o.str();
}
// snprintf is not defined with MSVC prior to to msvc14
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf

View file

@ -171,9 +171,4 @@ ScopedPerfEventHelper::~ScopedPerfEventHelper()
}
}
std::ostream &DummyStream()
{
return std::cout;
}
} // namespace gl

View file

@ -57,20 +57,7 @@ void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
void UninitializeDebugAnnotations();
bool DebugAnnotationsActive();
// This class is used to explicitly ignore values in the conditional logging macros. This avoids
// compiler warnings like "value computed is not used" and "statement has no effect".
class LogMessageVoidify
{
public:
LogMessageVoidify() {}
// This has to be an operator with a precedence lower than << but higher than ?:
void operator&(std::ostream &) {}
};
// This can be any ostream, it is unused, but needs to be a valid reference.
std::ostream &DummyStream();
} // namespace gl
}
#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
#define ANGLE_TRACE_ENABLED
@ -117,58 +104,61 @@ std::ostream &DummyStream();
#undef ANGLE_TRACE_ENABLED
#endif
#if defined(COMPILER_GCC) || defined(__clang__)
#define ANGLE_CRASH() __builtin_trap()
#else
#define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0))
#endif
#if !defined(NDEBUG)
#define ANGLE_ASSERT_IMPL(expression) assert(expression)
#else
// TODO(jmadill): Detect if debugger is attached and break.
#define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
#define ANGLE_ASSERT_IMPL(expression) abort()
#endif // !defined(NDEBUG)
// Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold.
// Condition is evaluated once and only once.
#define ANGLE_LAZY_STREAM(stream, condition) \
!(condition) ? static_cast<void>(0) : ::gl::LogMessageVoidify() & (stream)
#if defined(NDEBUG) && !defined(ANGLE_ENABLE_ASSERTS)
#define ANGLE_ASSERTS_ON 0
#else
#define ANGLE_ASSERTS_ON 1
#endif
// A macro asserting a condition and outputting failures to the debug log
#if ANGLE_ASSERTS_ON
#define ASSERT(expression) \
(expression ? static_cast<void>(0) \
: (ERR("\t! Assert failed in %s(%d): %s\n", __FUNCTION__, __LINE__, #expression), \
ANGLE_ASSERT_IMPL(expression)))
#if defined(ANGLE_ENABLE_ASSERTS)
#define ASSERT(expression) \
{ \
if (!(expression)) \
{ \
ERR("\t! Assert failed in %s(%d): %s\n", __FUNCTION__, __LINE__, #expression); \
ANGLE_ASSERT_IMPL(expression); \
} \
} \
ANGLE_EMPTY_STATEMENT
#define UNUSED_ASSERTION_VARIABLE(variable)
#else
#define ASSERT(condition) \
ANGLE_LAZY_STREAM(::gl::DummyStream(), ANGLE_ASSERTS_ON ? !(condition) : false) \
<< "Check failed: " #condition ". "
#endif // ANGLE_ASSERTS_ON
#define ASSERT(expression) (void(0))
#define UNUSED_ASSERTION_VARIABLE(variable) ((void)variable)
#endif
#define UNUSED_VARIABLE(variable) ((void)variable)
// A macro to indicate unimplemented functionality
#ifndef NOASSERT_UNIMPLEMENTED
#if defined (ANGLE_TEST_CONFIG)
#define NOASSERT_UNIMPLEMENTED 1
#endif
#define UNIMPLEMENTED() \
{ \
ERR("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
ASSERT(NOASSERT_UNIMPLEMENTED); \
} \
ANGLE_EMPTY_STATEMENT
// Define NOASSERT_UNIMPLEMENTED to non zero to skip the assert fail in the unimplemented checks
// This will allow us to test with some automated test suites (eg dEQP) without crashing
#ifndef NOASSERT_UNIMPLEMENTED
#define NOASSERT_UNIMPLEMENTED 0
#endif
#if !defined(NDEBUG)
#define UNIMPLEMENTED() { \
FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
assert(NOASSERT_UNIMPLEMENTED); \
} ANGLE_EMPTY_STATEMENT
#else
#define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__)
#endif
// A macro for code which is not expected to be reached under valid assumptions
#define UNREACHABLE() \
(ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__), ASSERT(false))
#if !defined(NDEBUG)
#define UNREACHABLE() { \
ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
assert(false); \
} ANGLE_EMPTY_STATEMENT
#else
#define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__)
#endif
#endif // COMMON_DEBUG_H_

View file

@ -14,9 +14,6 @@
namespace gl
{
namespace
{
struct RGB9E5Data
{
unsigned int R : 9;
@ -26,20 +23,17 @@ struct RGB9E5Data
};
// B is the exponent bias (15)
constexpr int g_sharedexp_bias = 15;
static const int g_sharedexp_bias = 15;
// N is the number of mantissa bits per component (9)
constexpr int g_sharedexp_mantissabits = 9;
static const int g_sharedexp_mantissabits = 9;
// Emax is the maximum allowed biased exponent value (31)
constexpr int g_sharedexp_maxexponent = 31;
static const int g_sharedexp_maxexponent = 31;
constexpr float g_sharedexp_max =
((static_cast<float>(1 << g_sharedexp_mantissabits) - 1) /
static_cast<float>(1 << g_sharedexp_mantissabits)) *
static_cast<float>(1 << (g_sharedexp_maxexponent - g_sharedexp_bias));
} // anonymous namespace
static const float g_sharedexp_max = ((pow(2.0f, g_sharedexp_mantissabits) - 1) /
pow(2.0f, g_sharedexp_mantissabits)) *
pow(2.0f, g_sharedexp_maxexponent - g_sharedexp_bias);
unsigned int convertRGBFloatsTo999E5(float red, float green, float blue)
{

View file

@ -44,15 +44,6 @@ struct Vector4
float w;
};
struct Vector2
{
Vector2() {}
Vector2(float x, float y) : x(x), y(y) {}
float x;
float y;
};
inline bool isPow2(int x)
{
return (x & (x - 1)) == 0 && (x != 0);
@ -765,40 +756,6 @@ constexpr unsigned int iSquareRoot()
return priv::iSquareRoot<N, 1>::value;
}
// Sum, difference and multiplication operations for signed ints that wrap on 32-bit overflow.
//
// Unsigned types are defined to do arithmetic modulo 2^n in C++. For signed types, overflow
// behavior is undefined.
template <typename T>
inline T WrappingSum(T lhs, T rhs)
{
uint32_t lhsUnsigned = static_cast<uint32_t>(lhs);
uint32_t rhsUnsigned = static_cast<uint32_t>(rhs);
return static_cast<T>(lhsUnsigned + rhsUnsigned);
}
template <typename T>
inline T WrappingDiff(T lhs, T rhs)
{
uint32_t lhsUnsigned = static_cast<uint32_t>(lhs);
uint32_t rhsUnsigned = static_cast<uint32_t>(rhs);
return static_cast<T>(lhsUnsigned - rhsUnsigned);
}
inline int32_t WrappingMul(int32_t lhs, int32_t rhs)
{
int64_t lhsWide = static_cast<int64_t>(lhs);
int64_t rhsWide = static_cast<int64_t>(rhs);
// The multiplication is guaranteed not to overflow.
int64_t resultWide = lhsWide * rhsWide;
// Implement the desired wrapping behavior by masking out the high-order 32 bits.
resultWide = resultWide & 0xffffffffll;
// Casting to a narrower signed type is fine since the casted value is representable in the
// narrower type.
return static_cast<int32_t>(resultWide);
}
} // namespace gl
namespace rx

View file

@ -16,7 +16,7 @@
// Unfortunately ANGLE relies on ASSERT being an empty statement, which these libs don't respect.
#ifndef NOTREACHED
#define NOTREACHED() UNREACHABLE()
#define NOTREACHED() 0
#endif
#endif // BASE_LOGGING_H_
#endif // BASE_LOGGING_H_

View file

@ -92,7 +92,7 @@ struct StaticDstRangeRelationToSrcRange<Dst,
static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
};
enum RangeConstraint : unsigned char
enum RangeConstraint
{
RANGE_VALID = 0x0, // Value can be represented by the destination type.
RANGE_UNDERFLOW = 0x1, // Value would overflow.

View file

@ -247,19 +247,7 @@ int VariableRowCount(GLenum type)
case GL_SAMPLER_2D_SHADOW:
case GL_SAMPLER_CUBE_SHADOW:
case GL_SAMPLER_2D_ARRAY_SHADOW:
case GL_IMAGE_2D:
case GL_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_2D:
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
case GL_IMAGE_3D:
case GL_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_3D:
case GL_IMAGE_CUBE:
case GL_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_CUBE:
return 1;
return 1;
case GL_FLOAT_MAT2:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT4x2:
@ -656,29 +644,6 @@ std::string ParseUniformName(const std::string &name, size_t *outSubscript)
return name.substr(0, open);
}
template <>
GLuint ConvertToGLuint(GLfloat param)
{
return uiround<GLuint>(param);
}
template <>
GLint ConvertToGLint(GLfloat param)
{
return iround<GLint>(param);
}
template <>
GLint ConvertFromGLfloat(GLfloat param)
{
return iround<GLint>(param);
}
template <>
GLuint ConvertFromGLfloat(GLfloat param)
{
return uiround<GLuint>(param);
}
unsigned int ParseAndStripArrayIndex(std::string *name)
{
unsigned int subscript = GL_INVALID_INDEX;

View file

@ -68,76 +68,6 @@ bool IsTriangleMode(GLenum drawMode);
template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(value > 0.0f ? floor(value + 0.5f) : ceil(value - 0.5f)); }
template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); }
// Helper for converting arbitrary GL types to other GL types used in queries and state setting
template <typename ParamType>
GLuint ConvertToGLuint(ParamType param)
{
return static_cast<GLuint>(param);
}
template <>
GLuint ConvertToGLuint(GLfloat param);
template <typename ParamType>
GLint ConvertToGLint(ParamType param)
{
return static_cast<GLint>(param);
}
template <>
GLint ConvertToGLint(GLfloat param);
// Same conversion as uint
template <typename ParamType>
GLenum ConvertToGLenum(ParamType param)
{
return static_cast<GLenum>(ConvertToGLuint(param));
}
template <typename ParamType>
GLfloat ConvertToGLfloat(ParamType param)
{
return static_cast<GLfloat>(param);
}
template <typename ParamType>
ParamType ConvertFromGLfloat(GLfloat param)
{
return static_cast<ParamType>(param);
}
template <>
GLint ConvertFromGLfloat(GLfloat param);
template <>
GLuint ConvertFromGLfloat(GLfloat param);
template <typename ParamType>
ParamType ConvertFromGLenum(GLenum param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLuint(GLuint param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLint(GLint param)
{
return static_cast<ParamType>(param);
}
template <typename ParamType>
ParamType ConvertFromGLboolean(GLboolean param)
{
return static_cast<ParamType>(param ? GL_TRUE : GL_FALSE);
}
template <typename ParamType>
ParamType ConvertFromGLint64(GLint64 param)
{
return clampCast<ParamType>(param);
}
unsigned int ParseAndStripArrayIndex(std::string *name);
} // namespace gl

View file

@ -6,7 +6,7 @@
'variables':
{
# These file lists are shared with the GN build.
'angle_translator_sources':
'angle_translator_lib_sources':
[
'../include/EGL/egl.h',
'../include/EGL/eglext.h',
@ -22,13 +22,9 @@
'../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',
@ -37,7 +33,6 @@
'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',
@ -86,36 +81,27 @@
'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/RemoveInvariantDeclaration.cpp',
'compiler/translator/RemoveInvariantDeclaration.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/RewriteUnaryMinusOperatorInt.cpp',
'compiler/translator/RewriteUnaryMinusOperatorInt.h',
'compiler/translator/RenameFunction.h',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
'compiler/translator/ScalarizeVecAndMatConstructorArgs.h',
'compiler/translator/SearchSymbol.cpp',
'compiler/translator/SearchSymbol.h',
'compiler/translator/ShaderLang.cpp',
'compiler/translator/ShaderVars.cpp',
'compiler/translator/SymbolTable.cpp',
'compiler/translator/SymbolTable.h',
'compiler/translator/Types.cpp',
'compiler/translator/Types.h',
'compiler/translator/UnfoldShortCircuitAST.cpp',
'compiler/translator/UnfoldShortCircuitAST.h',
'compiler/translator/UseInterfaceBlockFields.cpp',
'compiler/translator/UseInterfaceBlockFields.h',
'compiler/translator/ValidateGlobalInitializer.cpp',
'compiler/translator/ValidateGlobalInitializer.h',
'compiler/translator/ValidateLimitations.cpp',
@ -132,6 +118,13 @@
'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',
@ -140,19 +133,23 @@
'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_essl_sources':
'angle_translator_lib_essl_sources':
[
'compiler/translator/OutputESSL.cpp',
'compiler/translator/OutputESSL.h',
'compiler/translator/TranslatorESSL.cpp',
'compiler/translator/TranslatorESSL.h',
],
'angle_translator_glsl_sources':
'angle_translator_lib_glsl_sources':
[
'compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
'compiler/translator/BuiltInFunctionEmulatorGLSL.h',
@ -167,7 +164,7 @@
'compiler/translator/VersionGLSL.cpp',
'compiler/translator/VersionGLSL.h',
],
'angle_translator_hlsl_sources':
'angle_translator_lib_hlsl_sources':
[
'compiler/translator/AddDefaultReturnStatements.cpp',
'compiler/translator/AddDefaultReturnStatements.h',
@ -240,6 +237,7 @@
'compiler/preprocessor/Tokenizer.h',
'compiler/preprocessor/Tokenizer.l',
'compiler/preprocessor/numeric_lex.h',
'compiler/preprocessor/pp_utils.h',
],
},
# Everything below this is duplicated in the GN build. If you change
@ -249,23 +247,28 @@
{
'target_name': 'preprocessor',
'type': 'static_library',
'dependencies': [ 'angle_common' ],
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'sources': [ '<@(angle_preprocessor_sources)', ],
},
{
'target_name': 'translator',
'target_name': 'translator_lib',
'type': 'static_library',
'dependencies': [ 'preprocessor', 'angle_common' ],
'includes': [ '../gyp/common_defines.gypi', ],
'includes': [ '../build/common_defines.gypi', ],
'include_dirs':
[
'.',
'../include',
],
'defines':
[
# define the static translator to indicate exported
# classes are (in fact) locally defined
'ANGLE_TRANSLATOR_STATIC',
],
'sources':
[
'<@(angle_translator_sources)',
'<@(angle_translator_lib_sources)',
],
'msvs_settings':
{
@ -291,7 +294,7 @@
},
'sources':
[
'<@(angle_translator_essl_sources)',
'<@(angle_translator_lib_essl_sources)',
],
}],
['angle_enable_glsl==1',
@ -309,7 +312,7 @@
},
'sources':
[
'<@(angle_translator_glsl_sources)',
'<@(angle_translator_lib_glsl_sources)',
],
}],
['angle_enable_hlsl==1',
@ -327,10 +330,59 @@
},
'sources':
[
'<@(angle_translator_hlsl_sources)',
'<@(angle_translator_lib_hlsl_sources)',
],
}],
],
},
{
'target_name': 'translator',
'type': '<(component)',
'dependencies': [ 'translator_lib', 'angle_common' ],
'includes': [ '../build/common_defines.gypi', ],
'include_dirs':
[
'.',
'../include',
],
'defines':
[
'ANGLE_TRANSLATOR_IMPLEMENTATION',
],
'sources':
[
'compiler/translator/ShaderLang.cpp',
'compiler/translator/ShaderVars.cpp'
],
},
{
'target_name': 'translator_static',
'type': 'static_library',
'dependencies': [ 'translator_lib' ],
'includes': [ '../build/common_defines.gypi', ],
'include_dirs':
[
'.',
'../include',
],
'defines':
[
'ANGLE_TRANSLATOR_STATIC',
],
'direct_dependent_settings':
{
'defines':
[
'ANGLE_TRANSLATOR_STATIC',
],
},
'sources':
[
'compiler/translator/ShaderLang.cpp',
'compiler/translator/ShaderVars.cpp'
],
},
],
}

View file

@ -1,161 +0,0 @@
//
// 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.
//
// translator_fuzzer.cpp: A libfuzzer fuzzer for the shader translator.
#include <stddef.h>
#include <stdint.h>
#include <unordered_map>
#include <iostream>
#include "compiler/translator/Compiler.h"
#include "angle_gl.h"
using namespace sh;
struct TranslatorCacheKey
{
bool operator==(const TranslatorCacheKey &other) const
{
return type == other.type && spec == other.spec && output == other.output;
}
uint32_t type = 0;
uint32_t spec = 0;
uint32_t output = 0;
};
namespace std
{
template <>
struct hash<TranslatorCacheKey>
{
std::size_t operator()(const TranslatorCacheKey &k) const
{
return (hash<uint32_t>()(k.type) << 1) ^ (hash<uint32_t>()(k.spec) >> 1) ^
hash<uint32_t>()(k.output);
}
};
} // namespace std
static std::unordered_map<TranslatorCacheKey, TCompiler *> translators;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
// Reserve some size for future compile options
const size_t kHeaderSize = 128;
if (size <= kHeaderSize)
{
return 0;
}
// Make sure the rest of data will be a valid C string so that we don't have to copy it.
if (data[size - 1] != 0)
{
return 0;
}
uint32_t type = *reinterpret_cast<const uint32_t *>(data);
uint32_t spec = *reinterpret_cast<const uint32_t *>(data + 4);
uint32_t output = *reinterpret_cast<const uint32_t *>(data + 8);
uint64_t options = *reinterpret_cast<const uint64_t *>(data + 12);
if (type != GL_FRAGMENT_SHADER && type != GL_VERTEX_SHADER)
{
return 0;
}
if (spec != SH_GLES2_SPEC && type != SH_WEBGL_SPEC && spec != SH_GLES3_SPEC &&
spec != SH_WEBGL2_SPEC)
{
return 0;
}
std::vector<uint32_t> validOutputs;
validOutputs.push_back(SH_ESSL_OUTPUT);
validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
validOutputs.push_back(SH_GLSL_130_OUTPUT);
validOutputs.push_back(SH_GLSL_140_OUTPUT);
validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_400_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_410_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_420_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_430_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_440_CORE_OUTPUT);
validOutputs.push_back(SH_GLSL_450_CORE_OUTPUT);
validOutputs.push_back(SH_HLSL_3_0_OUTPUT);
validOutputs.push_back(SH_HLSL_4_1_OUTPUT);
validOutputs.push_back(SH_HLSL_4_0_FL9_3_OUTPUT);
bool found = false;
for (auto valid : validOutputs)
{
found = found || (valid == output);
}
if (!found)
{
return 0;
}
size -= kHeaderSize;
data += kHeaderSize;
if (!ShInitialize())
{
return 0;
}
TranslatorCacheKey key;
key.type = type;
key.spec = spec;
key.output = output;
if (translators.find(key) == translators.end())
{
TCompiler *translator = ConstructCompiler(type, static_cast<ShShaderSpec>(spec),
static_cast<ShShaderOutput>(output));
if (!translator)
{
return 0;
}
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
// Enable all the extensions to have more coverage
resources.OES_standard_derivatives = 1;
resources.OES_EGL_image_external = 1;
resources.OES_EGL_image_external_essl3 = 1;
resources.NV_EGL_stream_consumer_external = 1;
resources.ARB_texture_rectangle = 1;
resources.EXT_blend_func_extended = 1;
resources.EXT_draw_buffers = 1;
resources.EXT_frag_depth = 1;
resources.EXT_shader_texture_lod = 1;
resources.WEBGL_debug_shader_precision = 1;
resources.EXT_shader_framebuffer_fetch = 1;
resources.NV_shader_framebuffer_fetch = 1;
resources.ARM_shader_framebuffer_fetch = 1;
if (!translator->Init(resources))
{
DeleteCompiler(translator);
return 0;
}
translators[key] = translator;
}
TCompiler *translator = translators[key];
const char *shaderStrings[] = {reinterpret_cast<const char *>(data)};
translator->compile(shaderStrings, 1, options);
return 0;
}

View file

@ -1,79 +1,31 @@
diff --git a/src/compiler/preprocessor/Tokenizer.cpp b/src/compiler/preprocessor/Tokenizer.cpp
index 0d7ad58..5ef0e5e 100644
--- a/src/compiler/preprocessor/Tokenizer.cpp
+++ b/src/compiler/preprocessor/Tokenizer.cpp
@@ -1703,7 +1703,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{
int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ static_cast<int>(YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
@@ -1737,8 +1737,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
+ num_to_read = static_cast<int>(YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1);
}
@@ -1746,8 +1746,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
+ yy_size_t ret = 0;
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, num_to_read );
+ ret, num_to_read );
+ yyg->yy_n_chars = static_cast<int>(ret);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
}
@@ -1773,13 +1775,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
- int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
}
- yyg->yy_n_chars += number_to_move;
+ yyg->yy_n_chars += static_cast<int>(number_to_move);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
@@ -2171,7 +2173,7 @@ void pppop_buffer_state (yyscan_t yyscanner)
@@ -56,6 +56,7 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
@@ -179,6 +180,11 @@ typedef void* yyscan_t;
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
@@ -353,7 +354,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
*/
static void ppensure_buffer_stack (yyscan_t yyscanner)
{
- int num_to_alloc;
+ yy_size_t num_to_alloc;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (!yyg->yy_buffer_stack) {
@@ -2238,7 +2240,7 @@ YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" );
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_size = static_cast<int>(size - 2); /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = NULL;
@@ -2293,7 +2295,7 @@ YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, int _yybytes_len , yysc
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" );
- for ( i = 0; i < _yybytes_len; ++i )
+ for ( i = 0; i < static_cast<yy_size_t>(_yybytes_len); ++i )
buf[i] = yybytes[i];
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
#define YY_DO_BEFORE_ACTION \
yyg->yytext_ptr = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;

View file

@ -4,9 +4,9 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "DiagnosticsBase.h"
#include "common/debug.h"
#include <cassert>
namespace pp
{
@ -31,7 +31,7 @@ Diagnostics::Severity Diagnostics::severity(ID id)
if ((id > PP_WARNING_BEGIN) && (id < PP_WARNING_END))
return PP_WARNING;
UNREACHABLE();
assert(false);
return PP_ERROR;
}
@ -74,8 +74,6 @@ std::string Diagnostics::message(ID id)
return "predefined macro undefined";
case PP_MACRO_UNTERMINATED_INVOCATION:
return "unterminated macro invocation";
case PP_MACRO_UNDEFINED_WHILE_INVOKED:
return "macro undefined while being invoked";
case PP_MACRO_TOO_FEW_ARGS:
return "Not enough arguments for macro";
case PP_MACRO_TOO_MANY_ARGS:
@ -133,8 +131,8 @@ std::string Diagnostics::message(ID id)
return "macro name with a double underscore is reserved - unintented behavior is possible";
// Warnings end.
default:
UNREACHABLE();
return "";
assert(false);
return "";
}
}

View file

@ -44,7 +44,6 @@ class Diagnostics
PP_MACRO_PREDEFINED_REDEFINED,
PP_MACRO_PREDEFINED_UNDEFINED,
PP_MACRO_UNTERMINATED_INVOCATION,
PP_MACRO_UNDEFINED_WHILE_INVOKED,
PP_MACRO_TOO_FEW_ARGS,
PP_MACRO_TOO_MANY_ARGS,
PP_MACRO_DUPLICATE_PARAMETER_NAMES,

View file

@ -4,7 +4,7 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/DirectiveHandlerBase.h"
#include "DirectiveHandlerBase.h"
namespace pp
{

View file

@ -4,19 +4,19 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/DirectiveParser.h"
#include "DirectiveParser.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <sstream>
#include "common/debug.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "compiler/preprocessor/DirectiveHandlerBase.h"
#include "compiler/preprocessor/ExpressionParser.h"
#include "compiler/preprocessor/MacroExpander.h"
#include "compiler/preprocessor/Token.h"
#include "compiler/preprocessor/Tokenizer.h"
#include "DiagnosticsBase.h"
#include "DirectiveHandlerBase.h"
#include "ExpressionParser.h"
#include "MacroExpander.h"
#include "Token.h"
#include "Tokenizer.h"
namespace {
enum DirectiveType
@ -248,7 +248,7 @@ void DirectiveParser::lex(Token *token)
void DirectiveParser::parseDirective(Token *token)
{
ASSERT(token->type == Token::PP_HASH);
assert(token->type == Token::PP_HASH);
mTokenizer->lex(token);
if (isEOD(token))
@ -314,8 +314,8 @@ void DirectiveParser::parseDirective(Token *token)
parseLine(token);
break;
default:
UNREACHABLE();
break;
assert(false);
break;
}
skipUntilEOD(mTokenizer, token);
@ -328,7 +328,7 @@ void DirectiveParser::parseDirective(Token *token)
void DirectiveParser::parseDefine(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_DEFINE);
assert(getDirective(token) == DIRECTIVE_DEFINE);
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
@ -428,7 +428,7 @@ void DirectiveParser::parseDefine(Token *token)
void DirectiveParser::parseUndef(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_UNDEF);
assert(getDirective(token) == DIRECTIVE_UNDEF);
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)
@ -445,13 +445,6 @@ void DirectiveParser::parseUndef(Token *token)
{
mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
token->location, token->text);
return;
}
else if (iter->second.expansionCount > 0)
{
mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,
token->text);
return;
}
else
{
@ -470,25 +463,25 @@ void DirectiveParser::parseUndef(Token *token)
void DirectiveParser::parseIf(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_IF);
assert(getDirective(token) == DIRECTIVE_IF);
parseConditionalIf(token);
}
void DirectiveParser::parseIfdef(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_IFDEF);
assert(getDirective(token) == DIRECTIVE_IFDEF);
parseConditionalIf(token);
}
void DirectiveParser::parseIfndef(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);
assert(getDirective(token) == DIRECTIVE_IFNDEF);
parseConditionalIf(token);
}
void DirectiveParser::parseElse(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_ELSE);
assert(getDirective(token) == DIRECTIVE_ELSE);
if (mConditionalStack.empty())
{
@ -529,7 +522,7 @@ void DirectiveParser::parseElse(Token *token)
void DirectiveParser::parseElif(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_ELIF);
assert(getDirective(token) == DIRECTIVE_ELIF);
if (mConditionalStack.empty())
{
@ -569,7 +562,7 @@ void DirectiveParser::parseElif(Token *token)
void DirectiveParser::parseEndif(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_ENDIF);
assert(getDirective(token) == DIRECTIVE_ENDIF);
if (mConditionalStack.empty())
{
@ -593,7 +586,7 @@ void DirectiveParser::parseEndif(Token *token)
void DirectiveParser::parseError(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_ERROR);
assert(getDirective(token) == DIRECTIVE_ERROR);
std::ostringstream stream;
mTokenizer->lex(token);
@ -608,7 +601,7 @@ void DirectiveParser::parseError(Token *token)
// Parses pragma of form: #pragma name[(value)].
void DirectiveParser::parsePragma(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);
assert(getDirective(token) == DIRECTIVE_PRAGMA);
enum State
{
@ -669,7 +662,7 @@ void DirectiveParser::parsePragma(Token *token)
void DirectiveParser::parseExtension(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);
assert(getDirective(token) == DIRECTIVE_EXTENSION);
enum State
{
@ -750,7 +743,7 @@ void DirectiveParser::parseExtension(Token *token)
void DirectiveParser::parseVersion(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_VERSION);
assert(getDirective(token) == DIRECTIVE_VERSION);
if (mPastFirstStatement)
{
@ -837,7 +830,7 @@ void DirectiveParser::parseVersion(Token *token)
void DirectiveParser::parseLine(Token *token)
{
ASSERT(getDirective(token) == DIRECTIVE_LINE);
assert(getDirective(token) == DIRECTIVE_LINE);
bool valid = true;
bool parsedFileNumber = false;
@ -938,8 +931,8 @@ void DirectiveParser::parseConditionalIf(Token *token)
expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
break;
default:
UNREACHABLE();
break;
assert(false);
break;
}
block.skipGroup = expression == 0;
block.foundValidGroup = expression != 0;
@ -949,7 +942,8 @@ void DirectiveParser::parseConditionalIf(Token *token)
int DirectiveParser::parseExpressionIf(Token *token)
{
ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));
assert((getDirective(token) == DIRECTIVE_IF) ||
(getDirective(token) == DIRECTIVE_ELIF));
DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
@ -976,7 +970,8 @@ int DirectiveParser::parseExpressionIf(Token *token)
int DirectiveParser::parseExpressionIfdef(Token *token)
{
ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));
assert((getDirective(token) == DIRECTIVE_IFDEF) ||
(getDirective(token) == DIRECTIVE_IFNDEF));
mTokenizer->lex(token);
if (token->type != Token::IDENTIFIER)

View file

@ -7,9 +7,10 @@
#ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_
#define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_
#include "compiler/preprocessor/Lexer.h"
#include "compiler/preprocessor/Macro.h"
#include "compiler/preprocessor/SourceLocation.h"
#include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h"
#include "SourceLocation.h"
namespace pp
{
@ -29,6 +30,7 @@ class DirectiveParser : public Lexer
void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
void parseDirective(Token *token);
void parseDefine(Token *token);

View file

@ -99,15 +99,17 @@
#include <cassert>
#include <sstream>
#include <stdint.h>
#include "DiagnosticsBase.h"
#include "Lexer.h"
#include "Token.h"
#include "common/mathutil.h"
typedef int32_t YYSTYPE;
typedef uint32_t UNSIGNED_TYPE;
#if defined(_MSC_VER)
typedef __int64 YYSTYPE;
#else
#include <stdint.h>
typedef intmax_t YYSTYPE;
#endif // _MSC_VER
#define YYENABLE_NLS 0
#define YYLTYPE_IS_TRIVIAL 1
@ -496,12 +498,9 @@ static const yytype_uint8 yytranslate[] =
#if YYDEBUG
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
0, 108, 108, 115, 116, 127, 127, 148, 148, 169,
172, 175, 178, 181, 184, 187, 190, 193, 196, 221,
246, 249, 252, 278, 305, 308, 311, 314, 326, 329
};
static const yytype_uint16 yyrline[] = {0, 110, 110, 117, 118, 129, 129, 150, 150, 171,
174, 177, 180, 183, 186, 189, 192, 195, 198, 218,
238, 241, 244, 264, 284, 287, 290, 293, 296, 299};
#endif
#if YYDEBUG || YYERROR_VERBOSE || 0
@ -1493,7 +1492,7 @@ yyreduce:
case 18:
{
if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
if ((yyvsp[0]) < 0)
{
if (!context->isIgnoringErrors())
{
@ -1501,17 +1500,11 @@ yyreduce:
stream << (yyvsp[-2]) << " >> " << (yyvsp[0]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
context->token->location,
text.c_str());
context->token->location, text.c_str());
*(context->valid) = false;
}
(yyval) = static_cast<YYSTYPE>(0);
}
else if ((yyvsp[-2]) < 0)
{
// Logical shift right.
(yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) >> (yyvsp[0]));
}
else
{
(yyval) = (yyvsp[-2]) >> (yyvsp[0]);
@ -1523,7 +1516,7 @@ yyreduce:
case 19:
{
if ((yyvsp[0]) < 0 || (yyvsp[0]) > 31)
if ((yyvsp[0]) < 0)
{
if (!context->isIgnoringErrors())
{
@ -1531,17 +1524,11 @@ yyreduce:
stream << (yyvsp[-2]) << " << " << (yyvsp[0]);
std::string text = stream.str();
context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
context->token->location,
text.c_str());
context->token->location, text.c_str());
*(context->valid) = false;
}
(yyval) = static_cast<YYSTYPE>(0);
}
else if ((yyvsp[-2]) < 0)
{
// Logical shift left.
(yyval) = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>((yyvsp[-2])) << (yyvsp[0]));
}
else
{
(yyval) = (yyvsp[-2]) << (yyvsp[0]);
@ -1553,7 +1540,7 @@ yyreduce:
case 20:
{
(yyval) = gl::WrappingDiff<YYSTYPE>((yyvsp[-2]), (yyvsp[0]));
(yyval) = (yyvsp[-2]) - (yyvsp[0]);
}
break;
@ -1561,7 +1548,7 @@ yyreduce:
case 21:
{
(yyval) = gl::WrappingSum<YYSTYPE>((yyvsp[-2]), (yyvsp[0]));
(yyval) = (yyvsp[-2]) + (yyvsp[0]);
}
break;
@ -1583,12 +1570,6 @@ yyreduce:
}
(yyval) = static_cast<YYSTYPE>(0);
}
else if (((yyvsp[-2]) == std::numeric_limits<YYSTYPE>::min()) && ((yyvsp[0]) == -1))
{
// Check for the special case where the minimum representable number is
// divided by -1. If left alone this has undefined results.
(yyval) = 0;
}
else
{
(yyval) = (yyvsp[-2]) % (yyvsp[0]);
@ -1614,13 +1595,6 @@ yyreduce:
}
(yyval) = static_cast<YYSTYPE>(0);
}
else if (((yyvsp[-2]) == std::numeric_limits<YYSTYPE>::min()) && ((yyvsp[0]) == -1))
{
// Check for the special case where the minimum representable number is
// divided by -1. If left alone this leads to integer overflow in C++, which
// has undefined results.
(yyval) = std::numeric_limits<YYSTYPE>::max();
}
else
{
(yyval) = (yyvsp[-2]) / (yyvsp[0]);
@ -1632,7 +1606,7 @@ yyreduce:
case 24:
{
(yyval) = gl::WrappingMul((yyvsp[-2]), (yyvsp[0]));
(yyval) = (yyvsp[-2]) * (yyvsp[0]);
}
break;
@ -1656,16 +1630,7 @@ yyreduce:
case 27:
{
// Check for negation of minimum representable integer to prevent undefined signed int
// overflow.
if ((yyvsp[0]) == std::numeric_limits<YYSTYPE>::min())
{
(yyval) = std::numeric_limits<YYSTYPE>::min();
}
else
{
(yyval) = -(yyvsp[0]);
}
(yyval) = - (yyvsp[0]);
}
break;

View file

@ -7,8 +7,8 @@
#ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_
#include "common/angleutils.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "DiagnosticsBase.h"
#include "pp_utils.h"
namespace pp
{
@ -16,7 +16,7 @@ namespace pp
class Lexer;
struct Token;
class ExpressionParser : angle::NonCopyable
class ExpressionParser
{
public:
struct ErrorSettings
@ -34,6 +34,8 @@ class ExpressionParser : angle::NonCopyable
bool *valid);
private:
PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
Lexer *mLexer;
Diagnostics *mDiagnostics;
};

View file

@ -41,15 +41,17 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser.
#include <cassert>
#include <sstream>
#include <stdint.h>
#include "DiagnosticsBase.h"
#include "Lexer.h"
#include "Token.h"
#include "common/mathutil.h"
typedef int32_t YYSTYPE;
typedef uint32_t UNSIGNED_TYPE;
#if defined(_MSC_VER)
typedef __int64 YYSTYPE;
#else
#include <stdint.h>
typedef intmax_t YYSTYPE;
#endif // _MSC_VER
#define YYENABLE_NLS 0
#define YYLTYPE_IS_TRIVIAL 1
@ -194,7 +196,7 @@ expression
$$ = $1 < $3;
}
| expression TOK_OP_RIGHT expression {
if ($3 < 0 || $3 > 31)
if ($3 < 0)
{
if (!context->isIgnoringErrors())
{
@ -208,18 +210,13 @@ expression
}
$$ = static_cast<YYSTYPE>(0);
}
else if ($1 < 0)
{
// Logical shift right.
$$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
}
else
{
$$ = $1 >> $3;
}
}
| expression TOK_OP_LEFT expression {
if ($3 < 0 || $3 > 31)
if ($3 < 0)
{
if (!context->isIgnoringErrors())
{
@ -233,21 +230,16 @@ expression
}
$$ = static_cast<YYSTYPE>(0);
}
else if ($1 < 0)
{
// Logical shift left.
$$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
}
else
{
$$ = $1 << $3;
}
}
| expression '-' expression {
$$ = gl::WrappingDiff<YYSTYPE>($1, $3);
$$ = $1 - $3;
}
| expression '+' expression {
$$ = gl::WrappingSum<YYSTYPE>($1, $3);
$$ = $1 + $3;
}
| expression '%' expression {
if ($3 == 0)
@ -264,12 +256,6 @@ expression
}
$$ = static_cast<YYSTYPE>(0);
}
else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
{
// Check for the special case where the minimum representable number is
// divided by -1. If left alone this has undefined results.
$$ = 0;
}
else
{
$$ = $1 % $3;
@ -290,20 +276,13 @@ expression
}
$$ = static_cast<YYSTYPE>(0);
}
else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
{
// Check for the special case where the minimum representable number is
// divided by -1. If left alone this leads to integer overflow in C++, which
// has undefined results.
$$ = std::numeric_limits<YYSTYPE>::max();
}
else
{
$$ = $1 / $3;
}
}
| expression '*' expression {
$$ = gl::WrappingMul($1, $3);
$$ = $1 * $3;
}
| '!' expression %prec TOK_UNARY {
$$ = ! $2;
@ -312,16 +291,7 @@ expression
$$ = ~ $2;
}
| '-' expression %prec TOK_UNARY {
// Check for negation of minimum representable integer to prevent undefined signed int
// overflow.
if ($2 == std::numeric_limits<YYSTYPE>::min())
{
$$ = std::numeric_limits<YYSTYPE>::min();
}
else
{
$$ = -$2;
}
$$ = - $2;
}
| '+' expression %prec TOK_UNARY {
$$ = + $2;

View file

@ -4,13 +4,12 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/Input.h"
#include "Input.h"
#include <algorithm>
#include <cassert>
#include <cstring>
#include "common/debug.h"
namespace pp
{
@ -33,7 +32,7 @@ Input::Input(size_t count, const char *const string[], const int length[]) :
const char *Input::skipChar()
{
// This function should only be called when there is a character to skip.
ASSERT(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
assert(mReadLoc.cIndex < mLength[mReadLoc.sIndex]);
++mReadLoc.cIndex;
if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
{

View file

@ -7,7 +7,7 @@
#ifndef COMPILER_PREPROCESSOR_INPUT_H_
#define COMPILER_PREPROCESSOR_INPUT_H_
#include <cstddef>
#include <stddef.h>
#include <vector>
namespace pp

View file

@ -4,7 +4,7 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/Lexer.h"
#include "Lexer.h"
namespace pp
{

View file

@ -7,14 +7,12 @@
#ifndef COMPILER_PREPROCESSOR_LEXER_H_
#define COMPILER_PREPROCESSOR_LEXER_H_
#include "common/angleutils.h"
namespace pp
{
struct Token;
class Lexer : angle::NonCopyable
class Lexer
{
public:
virtual ~Lexer();

View file

@ -4,10 +4,11 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/Macro.h"
#include "Macro.h"
#include "common/angleutils.h"
#include "compiler/preprocessor/Token.h"
#include <sstream>
#include "Token.h"
namespace pp
{
@ -22,9 +23,12 @@ bool Macro::equals(const Macro &other) const
void PredefineMacro(MacroSet *macroSet, const char *name, int value)
{
std::ostringstream stream;
stream << value;
Token token;
token.type = Token::CONST_INT;
token.text = ToString(value);
token.text = stream.str();
Macro macro;
macro.predefined = true;

View file

@ -26,12 +26,16 @@ struct Macro
typedef std::vector<std::string> Parameters;
typedef std::vector<Token> Replacements;
Macro() : predefined(false), disabled(false), expansionCount(0), type(kTypeObj) {}
Macro()
: predefined(false),
disabled(false),
type(kTypeObj)
{
}
bool equals(const Macro &other) const;
bool predefined;
mutable bool disabled;
mutable int expansionCount;
Type type;
std::string name;

View file

@ -4,22 +4,17 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/MacroExpander.h"
#include "MacroExpander.h"
#include <algorithm>
#include <sstream>
#include "common/debug.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "compiler/preprocessor/Token.h"
#include "DiagnosticsBase.h"
#include "Token.h"
namespace pp
{
namespace
{
const size_t kMaxContextTokens = 10000;
class TokenLexer : public Lexer
{
public:
@ -45,52 +40,22 @@ class TokenLexer : public Lexer
}
private:
PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
TokenVector mTokens;
TokenVector::const_iterator mIter;
};
} // anonymous namespace
class MacroExpander::ScopedMacroReenabler final : angle::NonCopyable
{
public:
ScopedMacroReenabler(MacroExpander *expander);
~ScopedMacroReenabler();
private:
MacroExpander *mExpander;
};
MacroExpander::ScopedMacroReenabler::ScopedMacroReenabler(MacroExpander *expander)
: mExpander(expander)
{
mExpander->mDeferReenablingMacros = true;
}
MacroExpander::ScopedMacroReenabler::~ScopedMacroReenabler()
{
mExpander->mDeferReenablingMacros = false;
for (auto *macro : mExpander->mMacrosToReenable)
{
macro->disabled = false;
}
mExpander->mMacrosToReenable.clear();
}
MacroExpander::MacroExpander(Lexer *lexer, MacroSet *macroSet, Diagnostics *diagnostics)
: mLexer(lexer),
mMacroSet(macroSet),
mDiagnostics(diagnostics),
mTotalTokensInContexts(0),
mDeferReenablingMacros(false)
: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
{
}
MacroExpander::~MacroExpander()
{
for (MacroContext *context : mContextStack)
for (std::size_t i = 0; i < mContextStack.size(); ++i)
{
delete context;
delete mContextStack[i];
}
}
@ -117,15 +82,10 @@ void MacroExpander::lex(Token *token)
token->setExpansionDisabled(true);
break;
}
// Bump the expansion count before peeking if the next token is a '('
// otherwise there could be a #undef of the macro before the next token.
macro.expansionCount++;
if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
{
// If the token immediately after the macro name is not a '(',
// this macro should not be expanded.
macro.expansionCount--;
break;
}
@ -154,7 +114,6 @@ void MacroExpander::getToken(Token *token)
}
else
{
ASSERT(mTotalTokensInContexts == 0);
mLexer->lex(token);
}
}
@ -165,11 +124,11 @@ void MacroExpander::ungetToken(const Token &token)
{
MacroContext *context = mContextStack.back();
context->unget();
ASSERT(context->replacements[context->index] == token);
assert(context->replacements[context->index] == token);
}
else
{
ASSERT(!mReserveToken.get());
assert(!mReserveToken.get());
mReserveToken.reset(new Token(token));
}
}
@ -187,10 +146,10 @@ bool MacroExpander::isNextTokenLeftParen()
bool MacroExpander::pushMacro(const Macro &macro, const Token &identifier)
{
ASSERT(!macro.disabled);
ASSERT(!identifier.expansionDisabled());
ASSERT(identifier.type == Token::IDENTIFIER);
ASSERT(identifier.text == macro.name);
assert(!macro.disabled);
assert(!identifier.expansionDisabled());
assert(identifier.type == Token::IDENTIFIER);
assert(identifier.text == macro.name);
std::vector<Token> replacements;
if (!expandMacro(macro, identifier, &replacements))
@ -203,30 +162,19 @@ bool MacroExpander::pushMacro(const Macro &macro, const Token &identifier)
context->macro = &macro;
context->replacements.swap(replacements);
mContextStack.push_back(context);
mTotalTokensInContexts += context->replacements.size();
return true;
}
void MacroExpander::popMacro()
{
ASSERT(!mContextStack.empty());
assert(!mContextStack.empty());
MacroContext *context = mContextStack.back();
mContextStack.pop_back();
ASSERT(context->empty());
ASSERT(context->macro->disabled);
ASSERT(context->macro->expansionCount > 0);
if (mDeferReenablingMacros)
{
mMacrosToReenable.push_back(context->macro);
}
else
{
context->macro->disabled = false;
}
context->macro->expansionCount--;
mTotalTokensInContexts -= context->replacements.size();
assert(context->empty());
assert(context->macro->disabled);
context->macro->disabled = false;
delete context;
}
@ -251,21 +199,25 @@ bool MacroExpander::expandMacro(const Macro &macro,
const char kLine[] = "__LINE__";
const char kFile[] = "__FILE__";
ASSERT(replacements->size() == 1);
assert(replacements->size() == 1);
Token& repl = replacements->front();
if (macro.name == kLine)
{
repl.text = ToString(identifier.location.line);
std::ostringstream stream;
stream << identifier.location.line;
repl.text = stream.str();
}
else if (macro.name == kFile)
{
repl.text = ToString(identifier.location.file);
std::ostringstream stream;
stream << identifier.location.file;
repl.text = stream.str();
}
}
}
else
{
ASSERT(macro.type == Macro::kTypeFunc);
assert(macro.type == Macro::kTypeFunc);
std::vector<MacroArg> args;
args.reserve(macro.parameters.size());
if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
@ -296,17 +248,10 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
{
Token token;
getToken(&token);
ASSERT(token.type == '(');
assert(token.type == '(');
args->push_back(MacroArg());
// Defer reenabling macros until args collection is finished to avoid the possibility of
// infinite recursion. Otherwise infinite recursion might happen when expanding the args after
// macros have been popped from the context stack when parsing the args.
ScopedMacroReenabler deferReenablingMacros(this);
int openParens = 1;
while (openParens != 0)
for (int openParens = 1; openParens != 0; )
{
getToken(&token);
@ -372,9 +317,9 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
// Pre-expand each argument before substitution.
// This step expands each argument individually before they are
// inserted into the macro body.
size_t numTokens = 0;
for (auto &arg : *args)
for (std::size_t i = 0; i < args->size(); ++i)
{
MacroArg &arg = args->at(i);
TokenLexer lexer(&arg);
MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
@ -384,12 +329,6 @@ bool MacroExpander::collectMacroArgs(const Macro &macro,
{
arg.push_back(token);
expander.lex(&token);
numTokens++;
if (numTokens + mTotalTokensInContexts > kMaxContextTokens)
{
mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
return false;
}
}
}
return true;
@ -401,14 +340,6 @@ void MacroExpander::replaceMacroParams(const Macro &macro,
{
for (std::size_t i = 0; i < macro.replacements.size(); ++i)
{
if (!replacements->empty() &&
replacements->size() + mTotalTokensInContexts > kMaxContextTokens)
{
const Token &token = replacements->back();
mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token.location, token.text);
return;
}
const Token &repl = macro.replacements[i];
if (repl.type != Token::IDENTIFIER)
{
@ -441,25 +372,5 @@ void MacroExpander::replaceMacroParams(const Macro &macro,
}
}
MacroExpander::MacroContext::MacroContext() : macro(0), index(0)
{
}
bool MacroExpander::MacroContext::empty() const
{
return index == replacements.size();
}
const Token &MacroExpander::MacroContext::get()
{
return replacements[index++];
}
void MacroExpander::MacroContext::unget()
{
ASSERT(index > 0);
--index;
}
} // namespace pp

View file

@ -7,11 +7,13 @@
#ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_
#define COMPILER_PREPROCESSOR_MACROEXPANDER_H_
#include <cassert>
#include <memory>
#include <vector>
#include "compiler/preprocessor/Lexer.h"
#include "compiler/preprocessor/Macro.h"
#include "Lexer.h"
#include "Macro.h"
#include "pp_utils.h"
namespace pp
{
@ -28,6 +30,8 @@ class MacroExpander : public Lexer
void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
void getToken(Token *token);
void ungetToken(const Token &token);
bool isNextTokenLeftParen();
@ -50,14 +54,28 @@ class MacroExpander : public Lexer
struct MacroContext
{
MacroContext();
bool empty() const;
const Token &get();
void unget();
const Macro *macro;
std::size_t index;
std::vector<Token> replacements;
MacroContext()
: macro(0),
index(0)
{
}
bool empty() const
{
return index == replacements.size();
}
const Token &get()
{
return replacements[index++];
}
void unget()
{
assert(index > 0);
--index;
}
};
Lexer *mLexer;
@ -66,12 +84,6 @@ class MacroExpander : public Lexer
std::unique_ptr<Token> mReserveToken;
std::vector<MacroContext *> mContextStack;
size_t mTotalTokensInContexts;
bool mDeferReenablingMacros;
std::vector<const Macro *> mMacrosToReenable;
class ScopedMacroReenabler;
};
} // namespace pp

View file

@ -4,15 +4,16 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/Preprocessor.h"
#include "Preprocessor.h"
#include "common/debug.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "compiler/preprocessor/DirectiveParser.h"
#include "compiler/preprocessor/Macro.h"
#include "compiler/preprocessor/MacroExpander.h"
#include "compiler/preprocessor/Token.h"
#include "compiler/preprocessor/Tokenizer.h"
#include <cassert>
#include "DiagnosticsBase.h"
#include "DirectiveParser.h"
#include "Macro.h"
#include "MacroExpander.h"
#include "Token.h"
#include "Tokenizer.h"
namespace pp
{
@ -77,8 +78,8 @@ void Preprocessor::lex(Token *token)
// Convert preprocessing tokens to compiler tokens or report
// diagnostics.
case Token::PP_HASH:
UNREACHABLE();
break;
assert(false);
break;
case Token::PP_NUMBER:
mImpl->diagnostics->report(Diagnostics::PP_INVALID_NUMBER,
token->location, token->text);

View file

@ -7,9 +7,9 @@
#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_
#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
#include <cstddef>
#include <stddef.h>
#include "common/angleutils.h"
#include "pp_utils.h"
namespace pp
{
@ -19,7 +19,7 @@ class DirectiveHandler;
struct PreprocessorImpl;
struct Token;
class Preprocessor : angle::NonCopyable
class Preprocessor
{
public:
Preprocessor(Diagnostics *diagnostics, DirectiveHandler *directiveHandler);
@ -44,6 +44,8 @@ class Preprocessor : angle::NonCopyable
void setMaxTokenSize(size_t maxTokenSize);
private:
PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
PreprocessorImpl *mImpl;
};

View file

@ -4,10 +4,11 @@
// found in the LICENSE file.
//
#include "compiler/preprocessor/Token.h"
#include "Token.h"
#include "common/debug.h"
#include "compiler/preprocessor/numeric_lex.h"
#include <cassert>
#include "numeric_lex.h"
namespace pp
{
@ -54,19 +55,19 @@ void Token::setExpansionDisabled(bool disable)
bool Token::iValue(int *value) const
{
ASSERT(type == CONST_INT);
assert(type == CONST_INT);
return numeric_lex_int(text, value);
}
bool Token::uValue(unsigned int *value) const
{
ASSERT(type == CONST_INT);
assert(type == CONST_INT);
return numeric_lex_int(text, value);
}
bool Token::fValue(float *value) const
{
ASSERT(type == CONST_FLOAT);
assert(type == CONST_FLOAT);
return numeric_lex_float(text, value);
}

View file

@ -10,7 +10,7 @@
#include <ostream>
#include <string>
#include "compiler/preprocessor/SourceLocation.h"
#include "SourceLocation.h"
namespace pp
{
@ -113,7 +113,7 @@ inline bool operator!=(const Token &lhs, const Token &rhs)
return !lhs.equals(rhs);
}
std::ostream &operator<<(std::ostream &out, const Token &token);
extern std::ostream &operator<<(std::ostream &out, const Token &token);
} // namepsace pp

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,9 @@
#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_
#define COMPILER_PREPROCESSOR_TOKENIZER_H_
#include "common/angleutils.h"
#include "compiler/preprocessor/Input.h"
#include "compiler/preprocessor/Lexer.h"
#include "Input.h"
#include "Lexer.h"
#include "pp_utils.h"
namespace pp
{
@ -45,6 +45,7 @@ class Tokenizer : public Lexer
void lex(Token *token) override;
private:
PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
bool initScanner();
void destroyScanner();

View file

@ -27,10 +27,10 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
#pragma warning(disable: 4005)
#endif
#include "compiler/preprocessor/Tokenizer.h"
#include "Tokenizer.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
#include "compiler/preprocessor/Token.h"
#include "DiagnosticsBase.h"
#include "Token.h"
#if defined(__GNUC__)
// Triggered by the auto-generated yy_fatal_error function.
@ -280,7 +280,9 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
namespace pp {
Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(nullptr), mMaxTokenSize(256)
Tokenizer::Tokenizer(Diagnostics *diagnostics)
: mHandle(0),
mMaxTokenSize(256)
{
mContext.diagnostics = diagnostics;
}
@ -337,7 +339,7 @@ void Tokenizer::lex(Token *token)
bool Tokenizer::initScanner()
{
if ((mHandle == nullptr) && yylex_init_extra(&mContext, &mHandle))
if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle))
return false;
yyrestart(0, mHandle);
@ -346,11 +348,11 @@ bool Tokenizer::initScanner()
void Tokenizer::destroyScanner()
{
if (mHandle == nullptr)
if (mHandle == NULL)
return;
yylex_destroy(mHandle);
mHandle = nullptr;
mHandle = NULL;
}
} // namespace pp

View file

@ -9,7 +9,6 @@
#ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_
#define COMPILER_PREPROCESSOR_NUMERICLEX_H_
#include <cmath>
#include <sstream>
namespace pp {
@ -64,7 +63,7 @@ bool numeric_lex_float(const std::string &str, FloatType *value)
stream.imbue(std::locale::classic());
stream >> (*value);
return !stream.fail() && std::isfinite(*value);
return !stream.fail();
#endif
}

View file

@ -0,0 +1,18 @@
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// pp_utils.h: Common preprocessor utilities
#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_
#define COMPILER_PREPROCESSOR_PPUTILS_H_
// A macro to disallow the copy constructor and operator= functions
// This must be used in the private: declarations for a class.
#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName &); \
void operator=(const TypeName &)
#endif // COMPILER_PREPROCESSOR_PPUTILS_H_

View file

@ -1,13 +1,6 @@
diff --git a/src/compiler/translator/glslang_lex.cpp b/src/compiler/translator/glslang_lex.cpp
index 1ba63df..2a206ab 100644
--- a/src/compiler/translator/glslang_lex.cpp
+++ b/src/compiler/translator/glslang_lex.cpp
@@ -1,4 +1,3 @@
-#line 17 "./glslang.l"
//
// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
@@ -149,6 +148,7 @@ typedef int16_t flex_int16_t;
--- a/src/compiler/glslang_lex.cpp
+++ b/src/compiler/glslang_lex.cpp
@@ -68,6 +68,7 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
@ -15,10 +8,10 @@ index 1ba63df..2a206ab 100644
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
@@ -335,6 +335,11 @@ typedef size_t yy_size_t;
@@ -191,6 +192,11 @@ typedef void* yyscan_t;
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
@ -27,96 +20,21 @@ index 1ba63df..2a206ab 100644
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
@@ -351,8 +356,8 @@ typedef size_t yy_size_t;
@@ -204,7 +210,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
*/
#define YY_LESS_LINENO(n) \
do { \
- int yyl;\
- for ( yyl = n; yyl < yyleng; ++yyl )\
+ yy_size_t yyl;\
+ for ( yyl = n; yyl < static_cast<yy_site_t>(yyleng); ++yyl )\
for ( yyl = n; yyl < yyleng; ++yyl )\
if ( yytext[yyl] == '\n' )\
--yylineno;\
}while(0)
@@ -1692,7 +1697,7 @@ yy_find_action:
if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
{
yy_size_t yyl;
- for ( yyl = 0; yyl < yyleng; ++yyl )
+ for ( yyl = 0; yyl < static_cast<yy_size_t>(yyleng); ++yyl )
if ( yytext[yyl] == '\n' )
do{ yylineno++;
@@ -2655,7 +2660,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{
int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - static_cast<int>(number_to_move) - 1;
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
@@ -2690,7 +2695,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
+ static_cast<int>(number_to_move) - 1;
}
@@ -2698,8 +2703,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
+ size_t result = 0;
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, num_to_read );
+ result, num_to_read );
+ yyg->yy_n_chars = static_cast<int>(result);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
}
@@ -2725,13 +2732,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
- int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ int new_size = yyg->yy_n_chars + static_cast<int>(number_to_move) + (yyg->yy_n_chars >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
}
- yyg->yy_n_chars += number_to_move;
+ yyg->yy_n_chars += static_cast<int>(number_to_move);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
@@ -3158,7 +3165,7 @@ static void yyensure_buffer_stack (yyscan_t yyscanner)
/* Increase the buffer to prepare for a possible push. */
yy_size_t grow_size = 8 /* arbitrary grow size */;
- num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ num_to_alloc = static_cast<int>(yyg->yy_buffer_stack_max + grow_size);
yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
(yyg->yy_buffer_stack,
num_to_alloc * sizeof(struct yy_buffer_state*)
@@ -3196,7 +3203,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscann
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_size = static_cast<int>(size) - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = NULL;
@@ -3251,7 +3258,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yysc
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
- for ( i = 0; i < _yybytes_len; ++i )
+ for ( i = 0; i < static_cast<yy_size_t>(_yybytes_len); ++i )
buf[i] = yybytes[i];
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
@@ -378,7 +379,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
*/
#define YY_DO_BEFORE_ACTION \
yyg->yytext_ptr = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;

View file

@ -11,9 +11,6 @@
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
namespace
{
@ -34,7 +31,7 @@ class PullGradient : public TIntermTraverser
ASSERT(index < metadataList->size());
}
void traverse(TIntermFunctionDefinition *node)
void traverse(TIntermAggregate *node)
{
node->traverse(this);
ASSERT(mParents.empty());
@ -75,9 +72,9 @@ class PullGradient : public TIntermTraverser
return true;
}
bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override
bool visitSelection(Visit visit, TIntermSelection *selection) override
{
visitControlFlow(visit, ifElse);
visitControlFlow(visit, selection);
return true;
}
@ -106,8 +103,9 @@ class PullGradient : public TIntermTraverser
{
if (node->isUserDefined())
{
size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
size_t calleeIndex = mDag.findIndex(node);
ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
UNUSED_ASSERTION_VARIABLE(mIndex);
if ((*mMetadataList)[calleeIndex].mUsesGradient) {
onGradient();
@ -115,8 +113,7 @@ class PullGradient : public TIntermTraverser
}
else
{
TString name =
TFunction::unmangleName(node->getFunctionSymbolInfo()->getName());
TString name = TFunction::unmangleName(node->getName());
if (name == "texture2D" ||
name == "texture2DProj" ||
@ -160,7 +157,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
{
}
void traverse(TIntermFunctionDefinition *node)
void traverse(TIntermAggregate *node)
{
node->traverse(this);
ASSERT(mLoopsAndSwitches.empty());
@ -199,7 +196,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
return true;
}
bool visitIfElse(Visit visit, TIntermIfElse *node) override
bool visitSelection(Visit visit, TIntermSelection *node) override
{
if (visit == PreVisit)
{
@ -278,8 +275,9 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
{
if (node->isUserDefined())
{
size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
size_t calleeIndex = mDag.findIndex(node);
ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
UNUSED_ASSERTION_VARIABLE(mIndex);
if ((*mMetadataList)[calleeIndex].mHasGradientLoopInCallGraph)
{
@ -312,7 +310,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser
const CallDAG &mDag;
std::vector<TIntermNode*> mLoopsAndSwitches;
std::vector<TIntermIfElse *> mIfs;
std::vector<TIntermSelection*> mIfs;
};
// Tags all the functions called in a discontinuous loop
@ -329,7 +327,7 @@ class PushDiscontinuousLoops : public TIntermTraverser
{
}
void traverse(TIntermFunctionDefinition *node)
void traverse(TIntermAggregate *node)
{
node->traverse(this);
ASSERT(mNestedDiscont == (mMetadata->mCalledInDiscontinuousLoop ? 1 : 0));
@ -358,8 +356,9 @@ class PushDiscontinuousLoops : public TIntermTraverser
case EOpFunctionCall:
if (visit == PreVisit && node->isUserDefined() && mNestedDiscont > 0)
{
size_t calleeIndex = mDag.findIndex(node->getFunctionSymbolInfo());
size_t calleeIndex = mDag.findIndex(node);
ASSERT(calleeIndex != CallDAG::InvalidIndex && calleeIndex < mIndex);
UNUSED_ASSERTION_VARIABLE(mIndex);
(*mMetadataList)[calleeIndex].mCalledInDiscontinuousLoop = true;
}
@ -386,7 +385,7 @@ bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node)
return mControlFlowsContainingGradient.count(node) > 0;
}
bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node)
bool ASTMetadataHLSL::hasGradientLoop(TIntermSelection *node)
{
return mIfsContainingGradientLoop.count(node) > 0;
}
@ -450,5 +449,3 @@ MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag)
return metadataList;
}
} // namespace sh

View file

@ -12,12 +12,9 @@
#include <set>
#include <vector>
namespace sh
{
class CallDAG;
class TIntermNode;
class TIntermIfElse;
class TIntermSelection;
class TIntermLoop;
struct ASTMetadataHLSL
@ -33,7 +30,7 @@ struct ASTMetadataHLSL
// Here "something uses a gradient" means here that it either contains a
// gradient operation, or a call to a function that uses a gradient.
bool hasGradientInCallGraph(TIntermLoop *node);
bool hasGradientLoop(TIntermIfElse *node);
bool hasGradientLoop(TIntermSelection *node);
// Does the function use a gradient.
bool mUsesGradient;
@ -47,7 +44,7 @@ struct ASTMetadataHLSL
bool mCalledInDiscontinuousLoop;
bool mHasGradientLoopInCallGraph;
std::set<TIntermLoop*> mDiscontinuousLoops;
std::set<TIntermIfElse *> mIfsContainingGradientLoop;
std::set<TIntermSelection *> mIfsContainingGradientLoop;
// Will we need to generate a Lod0 version of the function.
bool mNeedsLod0;
@ -58,6 +55,4 @@ typedef std::vector<ASTMetadataHLSL> MetadataList;
// Return the AST analysis result, in the order defined by the call DAG
MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag);
} // namespace sh
#endif // COMPILER_TRANSLATOR_ASTMETADATAHLSL_H_

View file

@ -1,59 +0,0 @@
//
// 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

View file

@ -1,20 +0,0 @@
//
// 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_

View file

@ -31,16 +31,21 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser
private:
AddDefaultReturnStatementsTraverser() : TIntermTraverser(true, false, false) {}
static bool IsFunctionWithoutReturnStatement(TIntermFunctionDefinition *node, TType *returnType)
static bool IsFunctionWithoutReturnStatement(TIntermAggregate *node, TType *returnType)
{
*returnType = node->getType();
if (node->getType().getBasicType() == EbtVoid)
if (node->getOp() != EOpFunction || node->getType().getBasicType() == EbtVoid)
{
return false;
}
TIntermBlock *bodyNode = node->getBody();
TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode();
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
if (lastNode == nullptr)
{
return true;
}
TIntermBranch *returnNode = lastNode->getSequence()->front()->getAsBranchNode();
if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
{
return false;
@ -49,16 +54,51 @@ class AddDefaultReturnStatementsTraverser : private TIntermTraverser
return true;
}
bool visitFunctionDefinition(Visit, TIntermFunctionDefinition *node) override
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, TIntermTyped::CreateZero(returnType));
new TIntermBranch(EOpReturn, GenerateTypeConstructor(returnType));
TIntermBlock *bodyNode = node->getBody();
bodyNode->getSequence()->push_back(branch);
TIntermAggregate *lastNode = node->getSequence()->back()->getAsAggregate();
lastNode->getSequence()->push_back(branch);
return false;
}

View file

@ -10,9 +10,6 @@
#include "compiler/translator/IntermNode.h"
namespace sh
{
namespace
{
@ -44,7 +41,8 @@ TIntermAggregate *CreateReplacementCall(TIntermAggregate *originalCall, TIntermT
TIntermAggregate *replacementCall = new TIntermAggregate(EOpFunctionCall);
replacementCall->setType(TType(EbtVoid));
replacementCall->setUserDefined();
*replacementCall->getFunctionSymbolInfo() = *originalCall->getFunctionSymbolInfo();
replacementCall->setNameObj(originalCall->getNameObj());
replacementCall->setFunctionId(originalCall->getFunctionId());
replacementCall->setLine(originalCall->getLine());
TIntermSequence *replacementParameters = replacementCall->getSequence();
TIntermSequence *originalParameters = originalCall->getSequence();
@ -63,7 +61,6 @@ class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
private:
ArrayReturnValueToOutParameterTraverser();
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitBranch(Visit visit, TIntermBranch *node) override;
bool visitBinary(Visit visit, TIntermBinary *node) override;
@ -85,47 +82,35 @@ ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser
{
}
bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition(
Visit visit,
TIntermFunctionDefinition *node)
{
if (node->isArray() && visit == PreVisit)
{
// Replace the parameters child node of the function definition with another node
// that has the out parameter added.
// Also set the function to return void.
TIntermAggregate *params = node->getFunctionParameters();
ASSERT(params != nullptr && params->getOp() == EOpParameters);
TIntermAggregate *replacementParams = new TIntermAggregate;
replacementParams->setOp(EOpParameters);
CopyAggregateChildren(params, replacementParams);
replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
replacementParams->setLine(params->getLine());
queueReplacementWithParent(node, params, replacementParams, OriginalNode::IS_DROPPED);
node->setType(TType(EbtVoid));
mInFunctionWithArrayReturnValue = true;
}
if (visit == PostVisit)
{
// This isn't conditional on node->isArray() since the type has already been changed on
// PreVisit.
mInFunctionWithArrayReturnValue = false;
}
return true;
}
bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (visit == PreVisit)
{
if (node->isArray())
{
if (node->getOp() == EOpPrototype)
if (node->getOp() == EOpFunction)
{
// Replace the parameters child node of the function definition with another node
// that has the out parameter added.
// Also set the function to return void.
TIntermAggregate *params = node->getSequence()->front()->getAsAggregate();
ASSERT(params != nullptr && params->getOp() == EOpParameters);
TIntermAggregate *replacementParams = new TIntermAggregate;
replacementParams->setOp(EOpParameters);
CopyAggregateChildren(params, replacementParams);
replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
replacementParams->setLine(params->getLine());
queueReplacementWithParent(node, params, replacementParams,
OriginalNode::IS_DROPPED);
node->setType(TType(EbtVoid));
mInFunctionWithArrayReturnValue = true;
}
else if (node->getOp() == EOpPrototype)
{
// Replace the whole prototype node with another node that has the out parameter added.
TIntermAggregate *replacement = new TIntermAggregate;
@ -133,7 +118,8 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter
CopyAggregateChildren(node, replacement);
replacement->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType()));
replacement->setUserDefined();
*replacement->getFunctionSymbolInfo() = *node->getFunctionSymbolInfo();
replacement->setNameObj(node->getNameObj());
replacement->setFunctionId(node->getFunctionId());
replacement->setLine(node->getLine());
replacement->setType(TType(EbtVoid));
@ -150,21 +136,27 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter
// Cases 2 to 4 are already converted to simpler cases by SeparateExpressionsReturningArrays, so we
// only need to worry about the case where a function call returning an array forms an expression by
// itself.
TIntermBlock *parentBlock = getParentNode()->getAsBlock();
if (parentBlock)
TIntermAggregate *parentAgg = getParentNode()->getAsAggregate();
if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence)
{
nextTemporaryIndex();
TIntermSequence replacements;
replacements.push_back(createTempDeclaration(node->getType()));
TIntermSymbol *returnSymbol = createTempSymbol(node->getType());
replacements.push_back(CreateReplacementCall(node, returnSymbol));
mMultiReplacements.push_back(
NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, replacements));
}
return false;
}
}
}
else if (visit == PostVisit)
{
if (node->getOp() == EOpFunction)
{
mInFunctionWithArrayReturnValue = false;
}
}
return true;
}
@ -175,11 +167,12 @@ bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBr
// 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);
TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType());
TIntermBinary *replacementAssignment =
new TIntermBinary(EOpAssign, returnValueSymbol, expression);
replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType()));
replacementAssignment->setRight(node->getExpression());
replacementAssignment->setType(expression->getType());
replacementAssignment->setLine(expression->getLine());
replacements.push_back(replacementAssignment);
@ -187,8 +180,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBr
replacementBranch->setLine(node->getLine());
replacements.push_back(replacementBranch);
mMultiReplacements.push_back(
NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements));
mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(getParentNode()->getAsAggregate(), node, replacements));
}
return false;
}
@ -213,5 +205,3 @@ void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIn
{
ArrayReturnValueToOutParameterTraverser::apply(root, temporaryIndex);
}
} // namespace sh

View file

@ -9,11 +9,8 @@
#ifndef COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
#define COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
namespace sh
{
class TIntermNode;
void ArrayReturnValueToOutParameter(TIntermNode *root, unsigned int *temporaryIndex);
} // namespace sh
#endif // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_

View file

@ -13,9 +13,6 @@
#include "common/debug.h"
#include "GLSLANG/ShaderLang.h"
namespace sh
{
//
// Precision qualifiers
//
@ -35,10 +32,10 @@ inline const char* getPrecisionString(TPrecision p)
{
switch(p)
{
case EbpHigh: return "highp";
case EbpMedium: return "mediump";
case EbpLow: return "lowp";
default: return "mediump"; // Safest fallback
case EbpHigh: return "highp"; break;
case EbpMedium: return "mediump"; break;
case EbpLow: return "lowp"; break;
default: return "mediump"; break; // Safest fallback
}
}
@ -79,98 +76,19 @@ enum TBasicType
EbtSampler2DShadow,
EbtSamplerCubeShadow,
EbtSampler2DArrayShadow,
EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D
EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D
EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube
EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and
// usampler2DArray
// images
EbtGuardImageBegin,
EbtImage2D,
EbtIImage2D,
EbtUImage2D,
EbtImage3D,
EbtIImage3D,
EbtUImage3D,
EbtImage2DArray,
EbtIImage2DArray,
EbtUImage2DArray,
EbtImageCube,
EbtIImageCube,
EbtUImageCube,
EbtGuardImageEnd,
EbtGuardGImageBegin,
EbtGImage2D, // non type: represents image2D, uimage2D, iimage2D
EbtGImage3D, // non type: represents image3D, uimage3D, iimage3D
EbtGImage2DArray, // non type: represents image2DArray, uimage2DArray, iimage2DArray
EbtGImageCube, // non type: represents imageCube, uimageCube, iimageCube
EbtGuardGImageEnd,
EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D
EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D
EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube
EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and usampler2DArray
EbtStruct,
EbtInterfaceBlock,
EbtAddress, // should be deprecated??
EbtAddress, // should be deprecated??
// end of list
EbtLast
};
inline TBasicType convertGImageToFloatImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtImage2D;
case EbtGImage3D:
return EbtImage3D;
case EbtGImage2DArray:
return EbtImage2DArray;
case EbtGImageCube:
return EbtImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
inline TBasicType convertGImageToIntImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtIImage2D;
case EbtGImage3D:
return EbtIImage3D;
case EbtGImage2DArray:
return EbtIImage2DArray;
case EbtGImageCube:
return EbtIImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
inline TBasicType convertGImageToUnsignedImage(TBasicType type)
{
switch (type)
{
case EbtGImage2D:
return EbtUImage2D;
case EbtGImage3D:
return EbtUImage3D;
case EbtGImage2DArray:
return EbtUImage2DArray;
case EbtGImageCube:
return EbtUImageCube;
default:
UNREACHABLE();
}
return EbtLast;
}
const char* getBasicString(TBasicType t);
inline bool IsSampler(TBasicType type)
@ -178,22 +96,6 @@ inline bool IsSampler(TBasicType type)
return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
}
inline bool IsImage(TBasicType type)
{
return type > EbtGuardImageBegin && type < EbtGuardImageEnd;
}
inline bool IsGImage(TBasicType type)
{
return type > EbtGuardGImageBegin && type < EbtGuardGImageEnd;
}
inline bool IsOpaqueType(TBasicType type)
{
// TODO (mradev): add atomic types as opaque.
return IsSampler(type) || IsImage(type);
}
inline bool IsIntegerSampler(TBasicType type)
{
switch (type)
@ -224,56 +126,6 @@ inline bool IsIntegerSampler(TBasicType type)
return false;
}
inline bool IsFloatImage(TBasicType type)
{
switch (type)
{
case EbtImage2D:
case EbtImage3D:
case EbtImage2DArray:
case EbtImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsIntegerImage(TBasicType type)
{
switch (type)
{
case EbtIImage2D:
case EbtIImage3D:
case EbtIImage2DArray:
case EbtIImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsUnsignedImage(TBasicType type)
{
switch (type)
{
case EbtUImage2D:
case EbtUImage3D:
case EbtUImage2DArray:
case EbtUImageCube:
return true;
default:
break;
}
return false;
}
inline bool IsSampler2D(TBasicType type)
{
switch (type)
@ -431,7 +283,7 @@ inline bool IsInteger(TBasicType type)
inline bool SupportsPrecision(TBasicType type)
{
return type == EbtFloat || type == EbtInt || type == EbtUInt || IsOpaqueType(type);
return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type);
}
//
@ -489,11 +341,10 @@ enum TQualifier
EvqLastFragData,
// GLSL ES 3.0 vertex output and fragment input
EvqSmooth, // Incomplete qualifier, smooth is the default
EvqFlat, // Incomplete qualifier
EvqCentroid, // Incomplete qualifier
EvqSmoothOut,
EvqFlatOut,
EvqSmooth, // Incomplete qualifier, smooth is the default
EvqFlat, // Incomplete qualifier
EvqSmoothOut = EvqSmooth,
EvqFlatOut = EvqFlat,
EvqCentroidOut, // Implies smooth
EvqSmoothIn,
EvqFlatIn,
@ -508,40 +359,10 @@ enum TQualifier
EvqGlobalInvocationID,
EvqLocalInvocationIndex,
// GLSL ES 3.1 memory qualifiers
EvqReadOnly,
EvqWriteOnly,
EvqCoherent,
EvqRestrict,
EvqVolatile,
// end of list
EvqLast
};
inline bool IsQualifierUnspecified(TQualifier qualifier)
{
return (qualifier == EvqTemporary || qualifier == EvqGlobal);
}
enum TLayoutImageInternalFormat
{
EiifUnspecified,
EiifRGBA32F,
EiifRGBA16F,
EiifR32F,
EiifRGBA32UI,
EiifRGBA16UI,
EiifRGBA8UI,
EiifR32UI,
EiifRGBA32I,
EiifRGBA16I,
EiifRGBA8I,
EiifR32I,
EiifRGBA8,
EiifRGBA8_SNORM
};
enum TLayoutMatrixPacking
{
EmpUnspecified,
@ -560,44 +381,36 @@ enum TLayoutBlockStorage
struct TLayoutQualifier
{
int location;
unsigned int locationsSpecified;
TLayoutMatrixPacking matrixPacking;
TLayoutBlockStorage blockStorage;
// Compute shader layout qualifiers.
sh::WorkGroupSize localSize;
// Image format layout qualifier
TLayoutImageInternalFormat imageInternalFormat;
static TLayoutQualifier create()
{
TLayoutQualifier layoutQualifier;
layoutQualifier.location = -1;
layoutQualifier.locationsSpecified = 0;
layoutQualifier.matrixPacking = EmpUnspecified;
layoutQualifier.blockStorage = EbsUnspecified;
layoutQualifier.localSize.fill(-1);
layoutQualifier.imageInternalFormat = EiifUnspecified;
return layoutQualifier;
}
bool isEmpty() const
{
return location == -1 && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && !localSize.isAnyValueSet() &&
imageInternalFormat == EiifUnspecified;
blockStorage == EbsUnspecified && !localSize.isAnyValueSet();
}
bool isCombinationValid() const
{
bool workSizeSpecified = localSize.isAnyValueSet();
bool otherLayoutQualifiersSpecified =
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified ||
imageInternalFormat != EiifUnspecified);
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified);
// we can have either the work group size specified, or the other layout qualifiers
return !(workSizeSpecified && otherLayoutQualifiersSpecified);
@ -609,37 +422,6 @@ struct TLayoutQualifier
}
};
struct TMemoryQualifier
{
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
// An image can be qualified as both readonly and writeonly. It still can be can be used with
// imageSize().
bool readonly;
bool writeonly;
bool coherent;
// restrict and volatile are reserved keywords in C/C++
bool restrictQualifier;
bool volatileQualifier;
static TMemoryQualifier create()
{
TMemoryQualifier memoryQualifier;
memoryQualifier.readonly = false;
memoryQualifier.writeonly = false;
memoryQualifier.coherent = false;
memoryQualifier.restrictQualifier = false;
memoryQualifier.volatileQualifier = false;
return memoryQualifier;
}
bool isEmpty()
{
return !readonly && !writeonly && !coherent && !restrictQualifier && !volatileQualifier;
}
};
inline const char *getWorkGroupSizeString(size_t dimension)
{
switch (dimension)
@ -700,9 +482,6 @@ inline const char* getQualifierString(TQualifier q)
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";
@ -710,8 +489,6 @@ inline const char* getQualifierString(TQualifier q)
case EvqLocalInvocationID: return "LocalInvocationID";
case EvqGlobalInvocationID: return "GlobalInvocationID";
case EvqLocalInvocationIndex: return "LocalInvocationIndex";
case EvqReadOnly: return "readonly";
case EvqWriteOnly: return "writeonly";
default: UNREACHABLE(); return "unknown qualifier";
}
// clang-format on
@ -740,42 +517,18 @@ inline const char* getBlockStorageString(TLayoutBlockStorage bsq)
}
}
inline const char *getImageInternalFormatString(TLayoutImageInternalFormat iifq)
inline const char* getInterpolationString(TQualifier q)
{
switch (iifq)
switch(q)
{
case EiifRGBA32F:
return "rgba32f";
case EiifRGBA16F:
return "rgba16f";
case EiifR32F:
return "r32f";
case EiifRGBA32UI:
return "rgba32ui";
case EiifRGBA16UI:
return "rgba16ui";
case EiifRGBA8UI:
return "rgba8ui";
case EiifR32UI:
return "r32ui";
case EiifRGBA32I:
return "rgba32i";
case EiifRGBA16I:
return "rgba16i";
case EiifRGBA8I:
return "rgba8i";
case EiifR32I:
return "r32i";
case EiifRGBA8:
return "rgba8";
case EiifRGBA8_SNORM:
return "rgba8_snorm";
default:
UNREACHABLE();
return "unknown internal image format";
case EvqSmoothOut: return "smooth"; break;
case EvqCentroidOut: return "smooth centroid"; break;
case EvqFlatOut: return "flat"; break;
case EvqSmoothIn: return "smooth"; break;
case EvqCentroidIn: return "smooth centroid"; break;
case EvqFlatIn: return "flat"; break;
default: UNREACHABLE(); return "unknown interpolation";
}
}
} // namespace sh
#endif // COMPILER_TRANSLATOR_BASETYPES_H_

View file

@ -1,106 +0,0 @@
//
// 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 sh
{
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
void BreakVariableAliasingInInnerLoops(TIntermNode *root)
{
AliasingBreaker breaker;
root->traverse(&breaker);
}
} // namespace sh

View file

@ -1,23 +0,0 @@
//
// 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_

View file

@ -9,9 +9,6 @@
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/Cache.h"
namespace sh
{
class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
{
public:
@ -245,5 +242,3 @@ BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy
{
return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
}
} // namespace sh

View file

@ -10,9 +10,6 @@
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
namespace sh
{
//
// This class decides which built-in functions need to be replaced with the
// emulated ones.
@ -85,6 +82,4 @@ class BuiltInFunctionEmulator
std::vector<FunctionId> mFunctions;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_

View file

@ -11,68 +11,32 @@
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
namespace sh
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType)
{
void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
sh::GLenum shaderType)
{
if (shaderType == GL_VERTEX_SHADER)
{
const TType *int1 = TCache::getType(EbtInt);
emu->addEmulatedFunction(EOpAbs, int1, "int webgl_abs_emu(int x) { return x * sign(x); }");
}
}
void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion)
{
// isnan() is supported since GLSL 1.3.
if (targetGLSLVersion < GLSL_VERSION_130)
return;
// 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);
// !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
emu->addEmulatedFunction(
EOpIsNan, float1,
"bool webgl_isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
emu->addEmulatedFunction(
EOpIsNan, float2,
"bvec2 webgl_isnan_emu(vec2 x)\n"
"{\n"
" bvec2 isnan;\n"
" for (int i = 0; i < 2; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
emu->addEmulatedFunction(
EOpIsNan, float3,
"bvec3 webgl_isnan_emu(vec3 x)\n"
"{\n"
" bvec3 isnan;\n"
" for (int i = 0; i < 3; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
emu->addEmulatedFunction(
EOpIsNan, float4,
"bvec4 webgl_isnan_emu(vec4 x)\n"
"{\n"
" bvec4 isnan;\n"
" for (int i = 0; i < 4; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
if (shaderType == GL_FRAGMENT_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); }");
}
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
@ -217,9 +181,7 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
" float scale;\n"
" if(exponent < 0)\n"
" {\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"
" scale = 1.0 / (1 << -exponent);\n"
" }\n"
" else\n"
" {\n"
@ -251,5 +213,3 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator
// clang-format on
}
}
} // namespace sh

View file

@ -9,27 +9,17 @@
#include "GLSLANG/ShaderLang.h"
namespace sh
{
class BuiltInFunctionEmulator;
//
// This works around bug in Intel Mac drivers.
// This is only a workaround for OpenGL driver bugs, and isn't needed in general.
//
void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
sh::GLenum shaderType);
//
// This works around isnan() bug in Intel Mac drivers
//
void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion);
void InitBuiltInFunctionEmulatorForGLSLWorkarounds(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);
} // namespace sh
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_

View file

@ -8,62 +8,6 @@
#include "compiler/translator/BuiltInFunctionEmulator.h"
#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/VersionGLSL.h"
namespace sh
{
void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion)
{
if (targetGLSLVersion < GLSL_VERSION_130)
return;
TType *float1 = new TType(EbtFloat);
TType *float2 = new TType(EbtFloat, 2);
TType *float3 = new TType(EbtFloat, 3);
TType *float4 = new TType(EbtFloat, 4);
emu->addEmulatedFunction(EOpIsNan, float1,
"bool webgl_isnan_emu(float x)\n"
"{\n"
" return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n"
"}\n"
"\n");
emu->addEmulatedFunction(EOpIsNan, float2,
"bool2 webgl_isnan_emu(float2 x)\n"
"{\n"
" bool2 isnan;\n"
" for (int i = 0; i < 2; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
emu->addEmulatedFunction(EOpIsNan, float3,
"bool3 webgl_isnan_emu(float3 x)\n"
"{\n"
" bool3 isnan;\n"
" for (int i = 0; i < 3; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
emu->addEmulatedFunction(EOpIsNan, float4,
"bool4 webgl_isnan_emu(float4 x)\n"
"{\n"
" bool4 isnan;\n"
" for (int i = 0; i < 4; i++)\n"
" {\n"
" isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
" }\n"
" return isnan;\n"
"}\n");
}
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
{
@ -495,5 +439,3 @@ void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
"}\n");
}
} // namespace sh

View file

@ -9,19 +9,8 @@
#include "GLSLANG/ShaderLang.h"
namespace sh
{
class BuiltInFunctionEmulator;
void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu);
//
// This works around isnan() bug on some Intel drivers.
//
void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
int targetGLSLVersion);
} // namespace sh
#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_

View file

@ -12,9 +12,6 @@
#include "common/debug.h"
#include "compiler/translator/Cache.h"
namespace sh
{
namespace
{
@ -47,6 +44,7 @@ TCache::TypeKey::TypeKey(TBasicType basicType,
"TypeKey::value is too small");
const size_t MaxEnumValue = std::numeric_limits<EnumComponentType>::max();
UNUSED_ASSERTION_VARIABLE(MaxEnumValue);
// TODO: change to static_assert() once we deprecate MSVC 2013 support
ASSERT(MaxEnumValue >= EbtLast &&
@ -100,5 +98,3 @@ const TType *TCache::getType(TBasicType basicType,
return type;
}
} // namespace sh

View file

@ -16,9 +16,6 @@
#include "compiler/translator/Types.h"
#include "compiler/translator/PoolAlloc.h"
namespace sh
{
class TCache
{
public:
@ -90,6 +87,4 @@ class TCache
static TCache *sCache;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_CACHE_H_

View file

@ -11,9 +11,6 @@
#include "compiler/translator/CallDAG.h"
#include "compiler/translator/InfoSink.h"
namespace sh
{
// The CallDAGCreator does all the processing required to create the CallDAG
// structure so that the latter contains only the necessary variables.
class CallDAG::CallDAGCreator : public TIntermTraverser
@ -47,7 +44,6 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
skipped++;
}
}
ASSERT(mFunctions.size() == mCurrentIndex + skipped);
return INITDAG_SUCCESS;
}
@ -79,8 +75,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
record.callees.push_back(static_cast<int>(callee->index));
}
(*idToIndex)[data.node->getFunctionSymbolInfo()->getId()] =
static_cast<int>(data.index);
(*idToIndex)[data.node->getFunctionId()] = static_cast<int>(data.index);
}
}
@ -97,39 +92,13 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
}
std::set<CreatorFunctionData*> callees;
TIntermFunctionDefinition *node;
TIntermAggregate *node;
TString name;
size_t index;
bool indexAssigned;
bool visiting;
};
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override
{
// Create the record if need be and remember the node.
if (visit == PreVisit)
{
auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
if (it == mFunctions.end())
{
mCurrentFunction = &mFunctions[node->getFunctionSymbolInfo()->getName()];
}
else
{
mCurrentFunction = &it->second;
}
mCurrentFunction->node = node;
mCurrentFunction->name = node->getFunctionSymbolInfo()->getName();
}
else if (visit == PostVisit)
{
mCurrentFunction = nullptr;
}
return true;
}
// Aggregates the AST node for each function as well as the name of the functions called by it
bool visitAggregate(Visit visit, TIntermAggregate *node) override
{
@ -139,10 +108,36 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
if (visit == PreVisit)
{
// Function declaration, create an empty record.
auto &record = mFunctions[node->getFunctionSymbolInfo()->getName()];
record.name = node->getFunctionSymbolInfo()->getName();
auto& record = mFunctions[node->getName()];
record.name = node->getName();
}
break;
case EOpFunction:
{
// Function definition, create the record if need be and remember the node.
if (visit == PreVisit)
{
auto it = mFunctions.find(node->getName());
if (it == mFunctions.end())
{
mCurrentFunction = &mFunctions[node->getName()];
}
else
{
mCurrentFunction = &it->second;
}
mCurrentFunction->node = node;
mCurrentFunction->name = node->getName();
}
else if (visit == PostVisit)
{
mCurrentFunction = nullptr;
}
break;
}
case EOpFunctionCall:
{
// Function call, add the callees
@ -151,7 +146,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
// Do not handle calls to builtin functions
if (node->isUserDefined())
{
auto it = mFunctions.find(node->getFunctionSymbolInfo()->getName());
auto it = mFunctions.find(node->getName());
ASSERT(it != mFunctions.end());
// We might be in a top-level function call to set a global variable
@ -170,102 +165,52 @@ class CallDAG::CallDAGCreator : public TIntermTraverser
}
// Recursively assigns indices to a sub DAG
InitResult assignIndicesInternal(CreatorFunctionData *root)
InitResult assignIndicesInternal(CreatorFunctionData *function)
{
// Iterative implementation of the index assignment algorithm. A recursive version
// would be prettier but since the CallDAG creation runs before the limiting of the
// call depth, we might get stack overflows (computation of the call depth uses the
// CallDAG).
ASSERT(function);
ASSERT(root);
if (!function->node)
{
*mCreationInfo << "Undefined function '" << function->name
<< ")' used in the following call chain:";
return INITDAG_UNDEFINED;
}
if (root->indexAssigned)
if (function->indexAssigned)
{
return INITDAG_SUCCESS;
}
// If we didn't have to detect recursion, functionsToProcess could be a simple queue
// in which we add the function being processed's callees. However in order to detect
// recursion we need to know which functions we are currently visiting. For that reason
// functionsToProcess will look like a concatenation of segments of the form
// [F visiting = true, subset of F callees with visiting = false] and the following
// segment (if any) will be start with a callee of F.
// This way we can remember when we started visiting a function, to put visiting back
// to false.
TVector<CreatorFunctionData *> functionsToProcess;
functionsToProcess.push_back(root);
InitResult result = INITDAG_SUCCESS;
while (!functionsToProcess.empty())
if (function->visiting)
{
CreatorFunctionData *function = functionsToProcess.back();
if (function->visiting)
if (mCreationInfo)
{
function->visiting = false;
function->index = mCurrentIndex++;
function->indexAssigned = true;
functionsToProcess.pop_back();
continue;
}
if (!function->node)
{
*mCreationInfo << "Undefined function '" << function->name
<< ")' used in the following call chain:";
result = INITDAG_UNDEFINED;
break;
}
if (function->indexAssigned)
{
functionsToProcess.pop_back();
continue;
}
function->visiting = true;
for (auto callee : function->callees)
{
functionsToProcess.push_back(callee);
// Check if the callee is already being visited after pushing it so that it appears
// in the chain printed in the info log.
if (callee->visiting)
{
*mCreationInfo << "Recursive function call in the following call chain:";
result = INITDAG_RECURSION;
break;
}
*mCreationInfo << "Recursive function call in the following call chain:" << function->name;
}
return INITDAG_RECURSION;
}
function->visiting = true;
for (auto &callee : function->callees)
{
InitResult result = assignIndicesInternal(callee);
if (result != INITDAG_SUCCESS)
{
break;
}
}
// The call chain is made of the function we were visiting when the error was detected.
if (result != INITDAG_SUCCESS)
{
bool first = true;
for (auto function : functionsToProcess)
{
if (function->visiting)
// We know that there is an issue with the call chain in the AST,
// print the link of the chain we were processing.
if (mCreationInfo)
{
if (!first)
{
*mCreationInfo << " -> ";
}
*mCreationInfo << function->name << ")";
first = false;
*mCreationInfo << " <- " << function->name << ")";
}
return result;
}
}
return result;
function->index = mCurrentIndex++;
function->indexAssigned = true;
function->visiting = false;
return INITDAG_SUCCESS;
}
TInfoSinkBase *mCreationInfo;
@ -287,9 +232,13 @@ CallDAG::~CallDAG()
const size_t CallDAG::InvalidIndex = std::numeric_limits<size_t>::max();
size_t CallDAG::findIndex(const TFunctionSymbolInfo *functionInfo) const
size_t CallDAG::findIndex(const TIntermAggregate *function) const
{
auto it = mFunctionIdToIndex.find(functionInfo->getId());
TOperator op = function->getOp();
ASSERT(op == EOpPrototype || op == EOpFunction || op == EOpFunctionCall);
UNUSED_ASSERTION_VARIABLE(op);
auto it = mFunctionIdToIndex.find(function->getFunctionId());
if (it == mFunctionIdToIndex.end())
{
@ -309,7 +258,7 @@ const CallDAG::Record &CallDAG::getRecordFromIndex(size_t index) const
const CallDAG::Record &CallDAG::getRecord(const TIntermAggregate *function) const
{
size_t index = findIndex(function->getFunctionSymbolInfo());
size_t index = findIndex(function);
ASSERT(index != InvalidIndex && index < mRecords.size());
return mRecords[index];
}
@ -327,8 +276,6 @@ void CallDAG::clear()
CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info)
{
ASSERT(info);
CallDAGCreator creator(info);
// Creates the mapping of functions to callees
@ -344,5 +291,3 @@ CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info)
creator.fillDataStructures(&mRecords, &mFunctionIdToIndex);
return INITDAG_SUCCESS;
}
} // namespace sh

View file

@ -16,8 +16,6 @@
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/VariableInfo.h"
namespace sh
{
// The translator needs to analyze the the graph of the function calls
// to run checks and analyses; since in GLSL recursion is not allowed
@ -43,7 +41,7 @@ class CallDAG : angle::NonCopyable
struct Record
{
std::string name;
TIntermFunctionDefinition *node;
TIntermAggregate *node;
std::vector<int> callees;
};
@ -59,7 +57,7 @@ class CallDAG : angle::NonCopyable
InitResult init(TIntermNode *root, TInfoSinkBase *info);
// Returns InvalidIndex if the function wasn't found
size_t findIndex(const TFunctionSymbolInfo *functionInfo) const;
size_t findIndex(const TIntermAggregate *function) const;
const Record &getRecordFromIndex(size_t index) const;
const Record &getRecord(const TIntermAggregate *function) const;
@ -74,6 +72,4 @@ class CallDAG : angle::NonCopyable
class CallDAGCreator;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_CALLDAG_H_

View file

@ -6,79 +6,71 @@
#ifdef ANGLE_ENABLE_ESSL
#include "compiler/translator/TranslatorESSL.h"
#endif // ANGLE_ENABLE_ESSL
#endif
#ifdef ANGLE_ENABLE_GLSL
#include "compiler/translator/TranslatorGLSL.h"
#endif // ANGLE_ENABLE_GLSL
#endif
#ifdef ANGLE_ENABLE_HLSL
#include "compiler/translator/TranslatorHLSL.h"
#endif // ANGLE_ENABLE_HLSL
namespace sh
{
#endif // ANGLE_ENABLE_HLSL
//
// This function must be provided to create the actual
// compile object used by higher level code. It returns
// a subclass of TCompiler.
//
TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
TCompiler* ConstructCompiler(
sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
{
switch (output)
{
case SH_ESSL_OUTPUT:
switch (output) {
case SH_ESSL_OUTPUT:
#ifdef ANGLE_ENABLE_ESSL
return new TranslatorESSL(type, spec);
return new TranslatorESSL(type, spec);
#else
// This compiler is not supported in this configuration. Return NULL per the
// sh::ConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_ESSL
case SH_GLSL_130_OUTPUT:
case SH_GLSL_140_OUTPUT:
case SH_GLSL_150_CORE_OUTPUT:
case SH_GLSL_330_CORE_OUTPUT:
case SH_GLSL_400_CORE_OUTPUT:
case SH_GLSL_410_CORE_OUTPUT:
case SH_GLSL_420_CORE_OUTPUT:
case SH_GLSL_430_CORE_OUTPUT:
case SH_GLSL_440_CORE_OUTPUT:
case SH_GLSL_450_CORE_OUTPUT:
case SH_GLSL_COMPATIBILITY_OUTPUT:
// This compiler is not supported in this
// configuration. Return NULL per the ShConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_ESSL
case SH_GLSL_130_OUTPUT:
case SH_GLSL_140_OUTPUT:
case SH_GLSL_150_CORE_OUTPUT:
case SH_GLSL_330_CORE_OUTPUT:
case SH_GLSL_400_CORE_OUTPUT:
case SH_GLSL_410_CORE_OUTPUT:
case SH_GLSL_420_CORE_OUTPUT:
case SH_GLSL_430_CORE_OUTPUT:
case SH_GLSL_440_CORE_OUTPUT:
case SH_GLSL_450_CORE_OUTPUT:
case SH_GLSL_COMPATIBILITY_OUTPUT:
#ifdef ANGLE_ENABLE_GLSL
return new TranslatorGLSL(type, spec, output);
return new TranslatorGLSL(type, spec, output);
#else
// This compiler is not supported in this configuration. Return NULL per the
// sh::ConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_GLSL
case SH_HLSL_3_0_OUTPUT:
case SH_HLSL_4_1_OUTPUT:
case SH_HLSL_4_0_FL9_3_OUTPUT:
// This compiler is not supported in this
// configuration. Return NULL per the ShConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_GLSL
case SH_HLSL_3_0_OUTPUT:
case SH_HLSL_4_1_OUTPUT:
case SH_HLSL_4_0_FL9_3_OUTPUT:
#ifdef ANGLE_ENABLE_HLSL
return new TranslatorHLSL(type, spec, output);
return new TranslatorHLSL(type, spec, output);
#else
// This compiler is not supported in this configuration. Return NULL per the
// sh::ConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_HLSL
default:
// Unknown format. Return NULL per the sh::ConstructCompiler API.
return nullptr;
// This compiler is not supported in this
// configuration. Return NULL per the ShConstructCompiler API.
return nullptr;
#endif // ANGLE_ENABLE_HLSL
default:
// Unknown format. Return NULL per the ShConstructCompiler API.
return nullptr;
}
}
//
// Delete the compiler made by ConstructCompiler
//
void DeleteCompiler(TCompiler *compiler)
void DeleteCompiler(TCompiler* compiler)
{
SafeDelete(compiler);
delete compiler;
}
} // namespace sh

View file

@ -18,9 +18,6 @@
#include "common/debug.h"
#include "compiler/translator/PoolAlloc.h"
namespace sh
{
struct TSourceLoc {
int first_file;
int first_line;
@ -95,6 +92,4 @@ inline TString str(T i)
return buffer;
}
} // namespace sh
#endif // COMPILER_TRANSLATOR_COMMON_H_

View file

@ -4,18 +4,11 @@
// found in the LICENSE file.
//
#include "compiler/translator/Compiler.h"
#include <sstream>
#include "angle_gl.h"
#include "common/utilities.h"
#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/EmulatePrecision.h"
#include "compiler/translator/ForLoopUnroll.h"
#include "compiler/translator/Initialize.h"
#include "compiler/translator/InitializeParseContext.h"
@ -23,100 +16,41 @@
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
#include "compiler/translator/RemoveInvariantDeclaration.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/UseInterfaceBlockFields.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"
namespace sh
{
namespace
{
#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
void DumpFuzzerCase(char const *const *shaderStrings,
size_t numStrings,
uint32_t type,
uint32_t spec,
uint32_t output,
uint64_t options)
{
static int fileIndex = 0;
std::ostringstream o;
o << "corpus/" << fileIndex++ << ".sample";
std::string s = o.str();
// Must match the input format of the fuzzer
FILE *f = fopen(s.c_str(), "w");
fwrite(&type, sizeof(type), 1, f);
fwrite(&spec, sizeof(spec), 1, f);
fwrite(&output, sizeof(output), 1, f);
fwrite(&options, sizeof(options), 1, f);
char zero[128 - 20] = {0};
fwrite(&zero, 128 - 20, 1, f);
for (size_t i = 0; i < numStrings; i++)
{
fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f);
}
fwrite(&zero, 1, 1, f);
fclose(f);
}
#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
} // anonymous namespace
#include "angle_gl.h"
#include "common/utilities.h"
bool IsWebGLBasedSpec(ShShaderSpec spec)
{
return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
return (spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_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 ||
output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT ||
output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
}
bool IsGLSL420OrNewer(ShShaderOutput output)
{
return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
}
bool IsGLSL410OrOlder(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 ||
output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT);
}
bool RemoveInvariant(sh::GLenum shaderType,
int shaderVersion,
ShShaderOutput outputType,
ShCompileOptions compileOptions)
{
if ((compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) == 0 &&
shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
return true;
if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 &&
shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER && IsGLSL410OrOlder(outputType))
return true;
return false;
return (output == SH_GLSL_130_OUTPUT ||
output == SH_GLSL_140_OUTPUT ||
output == SH_GLSL_150_CORE_OUTPUT ||
output == SH_GLSL_330_CORE_OUTPUT ||
output == SH_GLSL_400_CORE_OUTPUT ||
output == SH_GLSL_410_CORE_OUTPUT ||
output == SH_GLSL_420_CORE_OUTPUT ||
output == SH_GLSL_430_CORE_OUTPUT ||
output == SH_GLSL_440_CORE_OUTPUT ||
output == SH_GLSL_450_CORE_OUTPUT);
}
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
@ -125,10 +59,11 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
// size undefined. ES3 defines a max size of 1024 characters.
switch (spec)
{
case SH_WEBGL_SPEC:
return 256;
default:
return 1024;
case SH_WEBGL_SPEC:
case SH_CSS_SHADERS_SPEC:
return 256;
default:
return 1024;
}
}
@ -174,18 +109,19 @@ int MapSpecToShaderVersion(ShShaderSpec spec)
{
switch (spec)
{
case SH_GLES2_SPEC:
case SH_WEBGL_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:
UNREACHABLE();
return 0;
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:
UNREACHABLE();
return 0;
}
}
@ -226,7 +162,7 @@ TCompiler::~TCompiler()
{
}
bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
bool TCompiler::shouldRunLoopAndIndexingValidation(int 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
@ -261,16 +197,15 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
return true;
}
TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions)
TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions)
{
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const ShCompileOptions compileOptions)
TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const int compileOptions)
{
clearResults();
@ -288,7 +223,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
++firstSource;
}
TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
TIntermediate intermediate(infoSink);
TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
compileOptions, true, infoSink, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
@ -311,7 +247,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
success = false;
}
TIntermBlock *root = nullptr;
TIntermNode *root = nullptr;
if (success)
{
@ -322,6 +258,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
root = parseContext.getTreeRoot();
root = intermediate.postProcess(root);
// Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
@ -358,17 +295,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
success = validateLimitations(root);
// Fail compilation if precision emulation not supported.
if (success && getResources().WEBGL_debug_shader_precision &&
getPragma().debugShaderPrecision)
{
if (!EmulatePrecision::SupportedInLanguage(outputType))
{
infoSink.info.prefix(EPrefixError);
infoSink.info << "Precision emulation not supported for this output type.";
success = false;
}
}
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))
@ -410,16 +341,10 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
initializeGLPosition(root);
if (success && RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
sh::RemoveInvariantDeclaration(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;
@ -435,10 +360,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && shouldCollectVariables(compileOptions))
{
collectVariables(root);
if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
{
useAllMembersInUnusedStandardAndSharedBlocks(root);
}
if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
{
success = enforcePackingRestrictions();
@ -456,8 +377,9 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
{
ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh,
&mTemporaryIndex);
ScalarizeVecAndMatConstructorArgs scalarizer(
shaderType, fragmentPrecisionHigh);
root->traverse(&scalarizer);
}
if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
@ -486,18 +408,12 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
return NULL;
}
bool TCompiler::compile(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptionsIn)
bool TCompiler::compile(const char *const shaderStrings[], size_t numStrings, int compileOptionsIn)
{
#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn);
#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
if (numStrings == 0)
return true;
ShCompileOptions compileOptions = compileOptionsIn;
int compileOptions = compileOptionsIn;
// Apply key workarounds.
if (shouldFlattenPragmaStdglInvariantAll())
@ -506,19 +422,8 @@ bool TCompiler::compile(const char *const shaderStrings[],
compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
}
ShCompileOptions unrollFlags =
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX | SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
if ((compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION) != 0 &&
(compileOptions & unrollFlags) != 0)
{
infoSink.info.prefix(EPrefixError);
infoSink.info
<< "Unsupported compile flag combination: unroll & ADD_TRUE_TO_LOOP_CONDITION";
return false;
}
TScopedPoolAllocator scopedAlloc(&allocator);
TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
if (root)
{
@ -547,26 +452,32 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.push(); // ESSL3_1_BUILTINS
TPublicType integer;
integer.initializeBasicType(EbtInt);
integer.type = EbtInt;
integer.primarySize = 1;
integer.secondarySize = 1;
integer.array = false;
TPublicType floatingPoint;
floatingPoint.initializeBasicType(EbtFloat);
floatingPoint.type = EbtFloat;
floatingPoint.primarySize = 1;
floatingPoint.secondarySize = 1;
floatingPoint.array = false;
switch (shaderType)
switch(shaderType)
{
case GL_FRAGMENT_SHADER:
symbolTable.setDefaultPrecision(integer, EbpMedium);
break;
case GL_VERTEX_SHADER:
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
case GL_COMPUTE_SHADER:
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
default:
assert(false && "Language not supported");
case GL_FRAGMENT_SHADER:
symbolTable.setDefaultPrecision(integer, EbpMedium);
break;
case GL_VERTEX_SHADER:
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
case GL_COMPUTE_SHADER:
symbolTable.setDefaultPrecision(integer, EbpHigh);
symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
break;
default:
assert(false && "Language not supported");
}
// Set defaults for sampler types that have default precision, even those that are
// only available if an extension exists.
@ -589,7 +500,10 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
{
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
TPublicType sampler;
sampler.initializeBasicType(samplerType);
sampler.primarySize = 1;
sampler.secondarySize = 1;
sampler.array = false;
sampler.type = samplerType;
symbolTable.setDefaultPrecision(sampler, EbpLow);
}
@ -599,60 +513,60 @@ void TCompiler::setResourceString()
// clang-format off
strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
<< ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
<< ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
<< ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
<< ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
<< ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
<< ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
<< ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
<< ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
<< ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
<< ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3
<< ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external
<< ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
<< ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
<< ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
<< ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":EXT_frag_depth:" << compileResources.EXT_frag_depth
<< ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
<< ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
<< ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
<< ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
<< ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
<< ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
<< ":MaxImageUnits:" << compileResources.MaxImageUnits
<< ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
<< ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
<< ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms
<< ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms
<< ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources
<< ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0]
<< ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1]
<< ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2]
<< ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0]
<< ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1]
<< ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2]
<< ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents
<< ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits
<< ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters
<< ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers
<< ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters
<< ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters
<< ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters
<< ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings
<< ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
<< ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
<< ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize;
<< ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
<< ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
<< ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
<< ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
<< ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
<< ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
<< ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
<< ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
<< ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
<< ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3
<< ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external
<< ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
<< ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
<< ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
<< ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":EXT_frag_depth:" << compileResources.EXT_frag_depth
<< ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
<< ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
<< ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
<< ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
<< ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
<< ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
<< ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
<< ":MaxImageUnits:" << compileResources.MaxImageUnits
<< ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
<< ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
<< ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms
<< ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms
<< ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources
<< ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0]
<< ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1]
<< ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2]
<< ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0]
<< ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1]
<< ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2]
<< ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents
<< ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits
<< ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters
<< ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers
<< ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters
<< ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters
<< ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters
<< ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings
<< ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
<< ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
<< ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize;
// clang-format on
builtInResourcesString = strstream.str();
@ -687,16 +601,16 @@ bool TCompiler::initCallDag(TIntermNode *root)
switch (mCallDag.init(root, &infoSink.info))
{
case CallDAG::INITDAG_SUCCESS:
return true;
case CallDAG::INITDAG_RECURSION:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Function recursion detected";
return false;
case CallDAG::INITDAG_UNDEFINED:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Unimplemented function detected";
return false;
case CallDAG::INITDAG_SUCCESS:
return true;
case CallDAG::INITDAG_RECURSION:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Function recursion detected";
return false;
case CallDAG::INITDAG_UNDEFINED:
infoSink.info.prefix(EPrefixError);
infoSink.info << "Unimplemented function detected";
return false;
}
UNREACHABLE();
@ -790,38 +704,30 @@ class TCompiler::UnusedPredicate
{
public:
UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
: mCallDag(callDag), mMetadatas(metadatas)
: mCallDag(callDag),
mMetadatas(metadatas)
{
}
bool operator ()(TIntermNode *node)
{
const TIntermAggregate *asAggregate = node->getAsAggregate();
const TIntermFunctionDefinition *asFunction = node->getAsFunctionDefinition();
const TFunctionSymbolInfo *functionInfo = nullptr;
if (asFunction)
{
functionInfo = asFunction->getFunctionSymbolInfo();
}
else if (asAggregate)
{
if (asAggregate->getOp() == EOpPrototype)
{
functionInfo = asAggregate->getFunctionSymbolInfo();
}
}
if (functionInfo == nullptr)
if (asAggregate == nullptr)
{
return false;
}
size_t callDagIndex = mCallDag->findIndex(functionInfo);
if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype))
{
return false;
}
size_t callDagIndex = mCallDag->findIndex(asAggregate);
if (callDagIndex == CallDAG::InvalidIndex)
{
// This happens only for unimplemented prototypes which are thus unused
ASSERT(asAggregate && asAggregate->getOp() == EOpPrototype);
ASSERT(asAggregate->getOp() == EOpPrototype);
return true;
}
@ -834,10 +740,13 @@ class TCompiler::UnusedPredicate
const std::vector<FunctionMetadata> *mMetadatas;
};
bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
{
TIntermAggregate *rootNode = root->getAsAggregate();
ASSERT(rootNode != nullptr);
UnusedPredicate isUnused(&mCallDag, &functionMetadata);
TIntermSequence *sequence = root->getSequence();
TIntermSequence *sequence = rootNode->getSequence();
if (!sequence->empty())
{
@ -854,6 +763,12 @@ bool TCompiler::validateOutputs(TIntermNode* root)
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);
@ -861,9 +776,39 @@ bool TCompiler::validateLimitations(TIntermNode* root)
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);
TMaxDepthTraverser traverser(maxExpressionComplexity+1);
root->traverse(&traverser);
if (traverser.getMaxDepth() > maxExpressionComplexity)
@ -881,13 +826,26 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
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);
&interfaceBlocks, hashFunction, symbolTable, extensionBehavior);
root->traverse(&collect);
// This is for enforcePackingRestriction().
@ -896,16 +854,6 @@ void TCompiler::collectVariables(TIntermNode* root)
}
}
bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions)
{
return (compileOptions & SH_VARIABLES) != 0;
}
bool TCompiler::wereVariablesCollected() const
{
return variablesCollected;
}
bool TCompiler::enforcePackingRestrictions()
{
VariablePacker packer;
@ -918,23 +866,7 @@ void TCompiler::initializeGLPosition(TIntermNode* root)
sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
var.name = "gl_Position";
list.push_back(var);
InitializeVariables(root, list, symbolTable);
}
void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
{
sh::InterfaceBlockList list;
for (auto block : interfaceBlocks)
{
if (!block.staticUse &&
(block.layout == sh::BLOCKLAYOUT_STANDARD || block.layout == sh::BLOCKLAYOUT_SHARED))
{
list.push_back(block);
}
}
sh::UseInterfaceBlockFields(root, list, symbolTable);
InitializeVariables(root, list);
}
void TCompiler::initializeOutputVariables(TIntermNode *root)
@ -955,7 +887,7 @@ void TCompiler::initializeOutputVariables(TIntermNode *root)
list.push_back(var);
}
}
InitializeVariables(root, list, symbolTable);
InitializeVariables(root, list);
}
const TExtensionBehavior& TCompiler::getExtensionBehavior() const
@ -988,7 +920,7 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
return builtInFunctionEmulator;
}
void TCompiler::writePragma(ShCompileOptions compileOptions)
void TCompiler::writePragma(int compileOptions)
{
if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
{
@ -1011,5 +943,3 @@ bool TCompiler::isVaryingDefined(const char *varyingName)
return false;
}
} // namespace sh

View file

@ -24,16 +24,15 @@
#include "compiler/translator/VariableInfo.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
namespace sh
{
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.
// Helper function to identify specs that are based on the WebGL spec,
// like the CSS Shaders spec.
//
bool IsWebGLBasedSpec(ShShaderSpec spec);
@ -41,16 +40,6 @@ bool IsWebGLBasedSpec(ShShaderSpec spec);
// Helper function to check if the shader type is GLSL.
//
bool IsGLSL130OrNewer(ShShaderOutput output);
bool IsGLSL420OrNewer(ShShaderOutput output);
bool IsGLSL410OrOlder(ShShaderOutput output);
//
// Helper function to check if the invariant qualifier can be removed.
//
bool RemoveInvariant(sh::GLenum shaderType,
int shaderVersion,
ShShaderOutput outputType,
ShCompileOptions compileOptions);
//
// The base class used to back handles returned to the driver.
@ -85,14 +74,12 @@ class TCompiler : public TShHandleBase
// 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 nullptr whenever there are compilation errors.
TIntermBlock *compileTreeForTesting(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions);
// allocator. Returns NULL whenever there are compilation errors.
TIntermNode *compileTreeForTesting(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
bool compile(const char *const shaderStrings[],
size_t numStrings,
ShCompileOptions compileOptions);
bool compile(const char* const shaderStrings[],
size_t numStrings, int compileOptions);
// Get results of the last compilation.
int getShaderVersion() const { return shaderVersion; }
@ -117,7 +104,7 @@ class TCompiler : public TShHandleBase
ShShaderOutput getOutputType() const { return outputType; }
const std::string &getBuiltInResourcesString() const { return builtInResourcesString; }
bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const;
bool shouldRunLoopAndIndexingValidation(int compileOptions) const;
// Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources& getResources() const;
@ -132,21 +119,20 @@ class TCompiler : public TShHandleBase
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,
ShCompileOptions compileOptions){};
virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {};
// Translate to object code.
virtual void translate(TIntermNode *root, ShCompileOptions compileOptions) = 0;
virtual void translate(TIntermNode *root, int 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 reference all members in unused uniform blocks with standard and shared
// layout. This is to work around a Mac driver that treats unused standard/shared
// uniform blocks as inactive.
void useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root);
// Insert statements to initialize output variables in the beginning of main().
// This is to avoid undefined behaviors.
void initializeOutputVariables(TIntermNode *root);
@ -155,13 +141,20 @@ class TCompiler : public TShHandleBase
// 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(ShCompileOptions compileOptions);
void writePragma(int compileOptions);
unsigned int *getTemporaryIndex() { return &mTemporaryIndex; }
// Relies on collectVariables having been called.
bool isVaryingDefined(const char *varyingName);
@ -170,16 +163,20 @@ class TCompiler : public TShHandleBase
ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
virtual bool shouldCollectVariables(ShCompileOptions compileOptions);
virtual bool shouldCollectVariables(int compileOptions)
{
return (compileOptions & SH_VARIABLES) != 0;
}
virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
bool wereVariablesCollected() const;
std::vector<sh::Attribute> attributes;
std::vector<sh::OutputVariable> outputVariables;
std::vector<sh::Uniform> uniforms;
std::vector<sh::ShaderVariable> expandedUniforms;
std::vector<sh::Varying> varyings;
std::vector<sh::InterfaceBlock> interfaceBlocks;
bool variablesCollected;
private:
// Creates the function call DAG for further analysis, returning false if there is a recursion
@ -190,18 +187,13 @@ class TCompiler : public TShHandleBase
void initSamplerDefaultPrecision(TBasicType samplerType);
// Collect info for all attribs, uniforms, varyings.
void collectVariables(TIntermNode *root);
bool variablesCollected;
// Removes unused function declarations and prototypes from the AST
class UnusedPredicate;
bool pruneUnusedFunctions(TIntermBlock *root);
bool pruneUnusedFunctions(TIntermNode *root);
TIntermBlock *compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const ShCompileOptions compileOptions);
TIntermNode *compileTreeImpl(const char *const shaderStrings[],
size_t numStrings,
const int compileOptions);
sh::GLenum shaderType;
ShShaderSpec shaderSpec;
@ -269,6 +261,4 @@ TCompiler* ConstructCompiler(
sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
void DeleteCompiler(TCompiler*);
} // namespace sh
#endif // COMPILER_TRANSLATOR_COMPILER_H_

View file

@ -1,642 +0,0 @@
//
// 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 "base/numerics/safe_math.h"
#include "common/mathutil.h"
#include "compiler/translator/Diagnostics.h"
namespace sh
{
namespace
{
template <typename T>
T CheckedSum(base::CheckedNumeric<T> lhs,
base::CheckedNumeric<T> rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
ASSERT(lhs.IsValid() && rhs.IsValid());
auto result = lhs + rhs;
if (!result.IsValid())
{
diag->error(line, "Addition out of range", "*", "");
return 0;
}
return result.ValueOrDefault(0);
}
template <typename T>
T CheckedDiff(base::CheckedNumeric<T> lhs,
base::CheckedNumeric<T> rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
ASSERT(lhs.IsValid() && rhs.IsValid());
auto result = lhs - rhs;
if (!result.IsValid())
{
diag->error(line, "Difference out of range", "*", "");
return 0;
}
return result.ValueOrDefault(0);
}
template <typename T>
T CheckedMul(base::CheckedNumeric<T> lhs,
base::CheckedNumeric<T> rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
ASSERT(lhs.IsValid() && rhs.IsValid());
auto result = lhs * rhs;
if (!result.IsValid())
{
diag->error(line, "Multiplication out of range", "*", "");
return 0;
}
return result.ValueOrDefault(0);
}
} // anonymous namespace
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,
const TSourceLoc &line)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
break;
case EbtUInt:
returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
break;
case EbtFloat:
returnValue.setFConst(CheckedSum<float>(lhs.fConst, rhs.fConst, diag, line));
break;
default:
UNREACHABLE();
}
return returnValue;
}
// static
TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
break;
case EbtUInt:
returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
break;
case EbtFloat:
returnValue.setFConst(CheckedDiff<float>(lhs.fConst, rhs.fConst, diag, line));
break;
default:
UNREACHABLE();
}
return returnValue;
}
// static
TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
TConstantUnion returnValue;
ASSERT(lhs.type == rhs.type);
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
break;
case EbtUInt:
// Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that
// to implement wrapping multiplication.
returnValue.setUConst(lhs.uConst * rhs.uConst);
break;
case EbtFloat:
returnValue.setFConst(CheckedMul<float>(lhs.fConst, rhs.fConst, diag, line));
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;
}
// static
TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
TConstantUnion returnValue;
ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
(rhs.type == EbtUInt && rhs.uConst > 31u))
{
diag->error(line, "Undefined shift (operand out of range)", ">>", "");
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(0);
break;
case EbtUInt:
returnValue.setUConst(0u);
break;
default:
UNREACHABLE();
}
return returnValue;
}
switch (lhs.type)
{
case EbtInt:
{
unsigned int shiftOffset = 0;
switch (rhs.type)
{
case EbtInt:
shiftOffset = static_cast<unsigned int>(rhs.iConst);
break;
case EbtUInt:
shiftOffset = rhs.uConst;
break;
default:
UNREACHABLE();
}
if (shiftOffset > 0)
{
// ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
// the sign bit." In C++ shifting negative integers is undefined, so we implement
// extending the sign bit manually.
int lhsSafe = lhs.iConst;
if (lhsSafe == std::numeric_limits<int>::min())
{
// The min integer needs special treatment because only bit it has set is the
// sign bit, which we clear later to implement safe right shift of negative
// numbers.
lhsSafe = -0x40000000;
--shiftOffset;
}
if (shiftOffset > 0)
{
bool extendSignBit = false;
if (lhsSafe < 0)
{
extendSignBit = true;
// Clear the sign bit so that bitshift right is defined in C++.
lhsSafe &= 0x7fffffff;
ASSERT(lhsSafe > 0);
}
returnValue.setIConst(lhsSafe >> shiftOffset);
// Manually fill in the extended sign bit if necessary.
if (extendSignBit)
{
int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
}
}
else
{
returnValue.setIConst(lhsSafe);
}
}
else
{
returnValue.setIConst(lhs.iConst);
}
break;
}
case EbtUInt:
switch (rhs.type)
{
case EbtInt:
returnValue.setUConst(lhs.uConst >> rhs.iConst);
break;
case EbtUInt:
returnValue.setUConst(lhs.uConst >> rhs.uConst);
break;
default:
UNREACHABLE();
}
break;
default:
UNREACHABLE();
}
return returnValue;
}
// static
TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line)
{
TConstantUnion returnValue;
ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
(rhs.type == EbtUInt && rhs.uConst > 31u))
{
diag->error(line, "Undefined shift (operand out of range)", "<<", "");
switch (lhs.type)
{
case EbtInt:
returnValue.setIConst(0);
break;
case EbtUInt:
returnValue.setUConst(0u);
break;
default:
UNREACHABLE();
}
return returnValue;
}
switch (lhs.type)
{
case EbtInt:
switch (rhs.type)
{
// Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
// lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
// integer overflow or undefined shift of a negative integer.
case EbtInt:
returnValue.setIConst(
static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
break;
case EbtUInt:
returnValue.setIConst(
static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
break;
default:
UNREACHABLE();
}
break;
case EbtUInt:
switch (rhs.type)
{
case EbtInt:
returnValue.setUConst(lhs.uConst << rhs.iConst);
break;
case EbtUInt:
returnValue.setUConst(lhs.uConst << rhs.uConst);
break;
default:
UNREACHABLE();
}
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;
}
} // namespace sh

View file

@ -9,21 +9,77 @@
#include <assert.h>
#include "compiler/translator/Common.h"
#include "compiler/translator/BaseTypes.h"
namespace sh
{
class TDiagnostics;
class TConstantUnion
{
public:
class TConstantUnion {
public:
POOL_ALLOCATOR_NEW_DELETE();
TConstantUnion();
TConstantUnion()
{
iConst = 0;
type = EbtVoid;
}
bool cast(TBasicType newType, const TConstantUnion &constant);
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;
}
return true;
}
void setIConst(int i) {iConst = i; type = EbtInt; }
void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
@ -35,57 +91,258 @@ class TConstantUnion
float getFConst() const { return fConst; }
bool getBConst() const { return bConst; }
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,
const TSourceLoc &line);
static TConstantUnion sub(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line);
static TConstantUnion mul(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line);
TConstantUnion operator%(const TConstantUnion &constant) const;
static TConstantUnion rshift(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line);
static TConstantUnion lshift(const TConstantUnion &lhs,
const TConstantUnion &rhs,
TDiagnostics *diag,
const TSourceLoc &line);
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;
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;
}
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;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_

View file

@ -15,43 +15,42 @@
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
namespace
{
void SetInternalFunctionName(TFunctionSymbolInfo *functionInfo, const char *name)
void SetInternalFunctionName(TIntermAggregate *functionNode, const char *name)
{
TString nameStr(name);
nameStr = TFunction::mangleName(nameStr);
TName nameObj(nameStr);
nameObj.setInternal(true);
functionInfo->setNameObj(nameObj);
functionNode->setNameObj(nameObj);
}
TIntermAggregate *CreateFunctionPrototypeNode(const char *name, const int functionId)
{
TIntermAggregate *functionNode = new TIntermAggregate(EOpPrototype);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
SetInternalFunctionName(functionNode, name);
TType returnType(EbtVoid);
functionNode->setType(returnType);
functionNode->getFunctionSymbolInfo()->setId(functionId);
functionNode->setFunctionId(functionId);
return functionNode;
}
TIntermFunctionDefinition *CreateFunctionDefinitionNode(const char *name,
TIntermBlock *functionBody,
const int functionId)
TIntermAggregate *CreateFunctionDefinitionNode(const char *name,
TIntermAggregate *functionBody,
const int functionId)
{
TType returnType(EbtVoid);
TIntermAggregate *functionNode = new TIntermAggregate(EOpFunction);
TIntermAggregate *paramsNode = new TIntermAggregate(EOpParameters);
TIntermFunctionDefinition *functionNode =
new TIntermFunctionDefinition(returnType, paramsNode, functionBody);
functionNode->getSequence()->push_back(paramsNode);
functionNode->getSequence()->push_back(functionBody);
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
functionNode->getFunctionSymbolInfo()->setId(functionId);
SetInternalFunctionName(functionNode, name);
TType returnType(EbtVoid);
functionNode->setType(returnType);
functionNode->setFunctionId(functionId);
return functionNode;
}
@ -60,10 +59,10 @@ TIntermAggregate *CreateFunctionCallNode(const char *name, const int functionId)
TIntermAggregate *functionNode = new TIntermAggregate(EOpFunctionCall);
functionNode->setUserDefined();
SetInternalFunctionName(functionNode->getFunctionSymbolInfo(), name);
SetInternalFunctionName(functionNode, name);
TType returnType(EbtVoid);
functionNode->setType(returnType);
functionNode->getFunctionSymbolInfo()->setId(functionId);
functionNode->setFunctionId(functionId);
return functionNode;
}
@ -74,7 +73,7 @@ class DeferGlobalInitializersTraverser : public TIntermTraverser
bool visitBinary(Visit visit, TIntermBinary *node) override;
void insertInitFunction(TIntermBlock *root);
void insertInitFunction(TIntermNode *root);
private:
TIntermSequence mDeferredInitializers;
@ -102,8 +101,10 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n
// 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, symbolNode->deepCopy(), node->getRight());
TIntermBinary *deferredInit = new TIntermBinary(EOpAssign);
deferredInit->setLeft(symbolNode->deepCopy());
deferredInit->setRight(node->getRight());
deferredInit->setType(node->getType());
mDeferredInitializers.push_back(deferredInit);
// Change const global to a regular global if its initialization is deferred.
@ -114,7 +115,7 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n
if (symbolNode->getQualifier() == EvqConst)
{
// All of the siblings in the same declaration need to have consistent qualifiers.
auto *siblings = getParentNode()->getAsDeclarationNode()->getSequence();
auto *siblings = getParentNode()->getAsAggregate()->getSequence();
for (TIntermNode *siblingNode : *siblings)
{
TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
@ -135,51 +136,56 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n
return false;
}
void DeferGlobalInitializersTraverser::insertInitFunction(TIntermBlock *root)
void DeferGlobalInitializersTraverser::insertInitFunction(TIntermNode *root)
{
if (mDeferredInitializers.empty())
{
return;
}
const int initFunctionId = TSymbolTable::nextUniqueId();
TIntermAggregate *rootAgg = root->getAsAggregate();
ASSERT(rootAgg != nullptr && rootAgg->getOp() == EOpSequence);
const char *functionName = "initializeDeferredGlobals";
// Add function prototype to the beginning of the shader
TIntermAggregate *functionPrototypeNode =
CreateFunctionPrototypeNode(functionName, initFunctionId);
root->getSequence()->insert(root->getSequence()->begin(), functionPrototypeNode);
rootAgg->getSequence()->insert(rootAgg->getSequence()->begin(), functionPrototypeNode);
// Add function definition to the end of the shader
TIntermBlock *functionBodyNode = new TIntermBlock();
TIntermAggregate *functionBodyNode = new TIntermAggregate(EOpSequence);
TIntermSequence *functionBody = functionBodyNode->getSequence();
for (const auto &deferredInit : mDeferredInitializers)
{
functionBody->push_back(deferredInit);
}
TIntermFunctionDefinition *functionDefinition =
TIntermAggregate *functionDefinition =
CreateFunctionDefinitionNode(functionName, functionBodyNode, initFunctionId);
root->getSequence()->push_back(functionDefinition);
rootAgg->getSequence()->push_back(functionDefinition);
// Insert call into main function
for (TIntermNode *node : *root->getSequence())
for (TIntermNode *node : *rootAgg->getSequence())
{
TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
if (nodeFunction != nullptr && nodeFunction->getFunctionSymbolInfo()->isMain())
TIntermAggregate *nodeAgg = node->getAsAggregate();
if (nodeAgg != nullptr && nodeAgg->getOp() == EOpFunction &&
TFunction::unmangleName(nodeAgg->getName()) == "main")
{
TIntermAggregate *functionCallNode =
CreateFunctionCallNode(functionName, initFunctionId);
TIntermBlock *mainBody = nodeFunction->getBody();
ASSERT(mainBody != nullptr);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), functionCallNode);
TIntermNode *mainBody = nodeAgg->getSequence()->back();
TIntermAggregate *mainBodyAgg = mainBody->getAsAggregate();
ASSERT(mainBodyAgg != nullptr && mainBodyAgg->getOp() == EOpSequence);
mainBodyAgg->getSequence()->insert(mainBodyAgg->getSequence()->begin(),
functionCallNode);
}
}
}
} // namespace
void DeferGlobalInitializers(TIntermBlock *root)
void DeferGlobalInitializers(TIntermNode *root)
{
DeferGlobalInitializersTraverser traverser;
root->traverse(&traverser);
@ -190,5 +196,3 @@ void DeferGlobalInitializers(TIntermBlock *root)
// Add the function with initialization and the call to that.
traverser.insertInitFunction(root);
}
} // namespace sh

View file

@ -13,11 +13,8 @@
#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
class TIntermBlock;
class TIntermNode;
namespace sh
{
void DeferGlobalInitializers(TIntermBlock *root);
} // namespace sh
void DeferGlobalInitializers(TIntermNode *root);
#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_

View file

@ -11,9 +11,6 @@
#include "compiler/translator/Common.h"
#include "compiler/translator/InfoSink.h"
namespace sh
{
TDiagnostics::TDiagnostics(TInfoSink& infoSink) :
mInfoSink(infoSink),
mNumErrors(0),
@ -82,5 +79,3 @@ void TDiagnostics::print(ID id,
{
writeInfo(severity(id), loc, message(id), text, "");
}
} // namespace sh

View file

@ -10,9 +10,6 @@
#include "common/angleutils.h"
#include "compiler/preprocessor/DiagnosticsBase.h"
namespace sh
{
class TInfoSink;
struct TSourceLoc;
@ -48,6 +45,4 @@ class TDiagnostics : public pp::Diagnostics, angle::NonCopyable
int mNumWarnings;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_

View file

@ -12,9 +12,6 @@
#include "common/debug.h"
#include "compiler/translator/Diagnostics.h"
namespace sh
{
static TBehavior getBehavior(const std::string& str)
{
const char kRequire[] = "require";
@ -198,5 +195,3 @@ void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
"version number", str, "not supported");
}
}
} // namespace sh

View file

@ -13,8 +13,6 @@
#include "compiler/preprocessor/DirectiveHandlerBase.h"
#include "GLSLANG/ShaderLang.h"
namespace sh
{
class TDiagnostics;
class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable
@ -52,6 +50,4 @@ class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable
bool mDebugShaderPrecisionSupported;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_

View file

@ -14,60 +14,59 @@
#include "compiler/translator/EmulateGLFragColorBroadcast.h"
#include "compiler/translator/IntermNode.h"
namespace sh
{
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(int maxDrawBuffers)
: TIntermTraverser(true, false, false),
mMainSequence(nullptr),
mGLFragColorUsed(false),
mMaxDrawBuffers(maxDrawBuffers)
GLFragColorBroadcastTraverser()
: TIntermTraverser(true, false, false), mMainSequence(nullptr), mGLFragColorUsed(false)
{
}
void broadcastGLFragColor();
void broadcastGLFragColor(int maxDrawBuffers);
bool isGLFragColorUsed() const { return mGLFragColorUsed; }
protected:
void visitSymbol(TIntermSymbol *node) override;
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
TIntermBinary *constructGLFragDataNode(int index) const;
TIntermBinary *constructGLFragDataAssignNode(int index) const;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
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")
@ -77,22 +76,34 @@ void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
}
}
bool GLFragColorBroadcastTraverser::visitFunctionDefinition(Visit visit,
TIntermFunctionDefinition *node)
bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
{
ASSERT(visit == PreVisit);
if (node->getFunctionSymbolInfo()->isMain())
switch (node->getOp())
{
TIntermBlock *body = node->getBody();
ASSERT(body);
mMainSequence = body->getSequence();
case EOpFunction:
// Function definition.
ASSERT(visit == PreVisit);
if (node->getName() == "main(")
{
TIntermSequence *sequence = node->getSequence();
ASSERT((sequence->size() == 1) || (sequence->size() == 2));
if (sequence->size() == 2)
{
TIntermAggregate *body = (*sequence)[1]->getAsAggregate();
ASSERT(body);
mMainSequence = body->getSequence();
}
}
break;
default:
break;
}
return true;
}
void GLFragColorBroadcastTraverser::broadcastGLFragColor()
void GLFragColorBroadcastTraverser::broadcastGLFragColor(int maxDrawBuffers)
{
ASSERT(mMaxDrawBuffers > 1);
ASSERT(maxDrawBuffers > 1);
if (!mGLFragColorUsed)
{
return;
@ -102,7 +113,7 @@ void GLFragColorBroadcastTraverser::broadcastGLFragColor()
// gl_FragData[1] = gl_FragData[0];
// ...
// gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
for (int colorIndex = 1; colorIndex < maxDrawBuffers; ++colorIndex)
{
mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex));
}
@ -115,12 +126,12 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
std::vector<sh::OutputVariable> *outputVariables)
{
ASSERT(maxDrawBuffers > 1);
GLFragColorBroadcastTraverser traverser(maxDrawBuffers);
GLFragColorBroadcastTraverser traverser;
root->traverse(&traverser);
if (traverser.isGLFragColorUsed())
{
traverser.updateTree();
traverser.broadcastGLFragColor();
traverser.broadcastGLFragColor(maxDrawBuffers);
for (auto &var : *outputVariables)
{
if (var.name == "gl_FragColor")
@ -133,5 +144,3 @@ void EmulateGLFragColorBroadcast(TIntermNode *root,
}
}
}
} // namespace sh

View file

@ -15,6 +15,8 @@
namespace sh
{
struct OutputVariable;
}
class TIntermNode;
// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function,
@ -22,7 +24,6 @@ class TIntermNode;
// If gl_FragColor is in outputVariables, it is replaced by gl_FragData.
void EmulateGLFragColorBroadcast(TIntermNode *root,
int maxDrawBuffers,
std::vector<OutputVariable> *outputVariables);
}
std::vector<sh::OutputVariable> *outputVariables);
#endif // COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_

View file

@ -8,9 +8,6 @@
#include <memory>
namespace sh
{
namespace
{
@ -94,7 +91,6 @@ class RoundingHelperWriterHLSL : public RoundingHelperWriter
RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage)
{
ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage));
switch (outputLanguage)
{
case SH_HLSL_4_1_OUTPUT:
@ -102,6 +98,9 @@ RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOut
case SH_ESSL_OUTPUT:
return new RoundingHelperWriterESSL(outputLanguage);
default:
// Other languages not yet supported
ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
IsGLSL130OrNewer(outputLanguage));
return new RoundingHelperWriterGLSL(outputLanguage);
}
}
@ -433,7 +432,7 @@ TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *chil
callNode->setOp(EOpFunctionCall);
TName nameObj(TFunction::mangleName(name));
nameObj.setInternal(true);
callNode->getFunctionSymbolInfo()->setNameObj(nameObj);
callNode->setNameObj(nameObj);
callNode->getSequence()->push_back(child);
return callNode;
}
@ -470,16 +469,15 @@ bool parentUsesResult(TIntermNode* parent, TIntermNode* node)
return false;
}
TIntermBlock *blockParent = parent->getAsBlock();
// If the parent is a block, the result is not assigned anywhere,
TIntermAggregate *aggParent = parent->getAsAggregate();
// If the parent's op is EOpSequence, the result is not assigned anywhere,
// so rounding it is not needed. In particular, this can avoid a lot of
// unnecessary rounding of unused return values of assignment.
if (blockParent)
if (aggParent && aggParent->getOp() == EOpSequence)
{
return false;
}
TIntermBinary *binaryParent = parent->getAsBinaryNode();
if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node))
if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node))
{
return false;
}
@ -513,7 +511,7 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node)
if (op == EOpInitialize && visit == InVisit)
mDeclaringVariables = false;
if ((op == EOpIndexDirectStruct) && visit == InVisit)
if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && visit == InVisit)
visitChildren = false;
if (visit != PreVisit)
@ -601,30 +599,14 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node)
return visitChildren;
}
bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node)
{
// Variable or interface block declaration.
if (visit == PreVisit)
{
mDeclaringVariables = true;
}
else if (visit == InVisit)
{
mDeclaringVariables = true;
}
else
{
mDeclaringVariables = false;
}
return true;
}
bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = true;
switch (node->getOp())
{
case EOpSequence:
case EOpConstructStruct:
case EOpFunction:
break;
case EOpPrototype:
visitChildren = false;
@ -635,6 +617,21 @@ bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpInvariantDeclaration:
visitChildren = false;
break;
case EOpDeclaration:
// Variable declaration.
if (visit == PreVisit)
{
mDeclaringVariables = true;
}
else if (visit == InVisit)
{
mDeclaringVariables = true;
}
else
{
mDeclaringVariables = false;
}
break;
case EOpFunctionCall:
{
// Function call.
@ -708,19 +705,3 @@ void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink,
roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul");
}
// static
bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage)
{
switch (outputLanguage)
{
case SH_HLSL_4_1_OUTPUT:
case SH_ESSL_OUTPUT:
return true;
default:
// Other languages not yet supported
return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
sh::IsGLSL130OrNewer(outputLanguage));
}
}
} // namespace sh

View file

@ -18,9 +18,6 @@
// need to write a huge number of variations of the emulated compound assignment
// to every translated shader with emulation enabled.
namespace sh
{
class EmulatePrecision : public TLValueTrackingTraverser
{
public:
@ -30,14 +27,11 @@ class EmulatePrecision : public TLValueTrackingTraverser
bool visitBinary(Visit visit, TIntermBinary *node) override;
bool visitUnary(Visit visit, TIntermUnary *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
void writeEmulationHelpers(TInfoSinkBase &sink,
const int shaderVersion,
const ShShaderOutput outputLanguage);
static bool SupportedInLanguage(const ShShaderOutput outputLanguage);
private:
struct TypePair
{
@ -67,6 +61,4 @@ class EmulatePrecision : public TLValueTrackingTraverser
bool mDeclaringVariables;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_

View file

@ -116,7 +116,7 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
TIntermTyped *lhs = sequence->at(0)->getAsTyped();
ASSERT(lhs);
TIntermDeclaration *init = createTempInitDeclaration(lhs);
TIntermAggregate *init = createTempInitDeclaration(lhs);
TIntermTyped *current = createTempSymbol(lhs->getType());
insertStatementInParentBlock(init);
@ -124,7 +124,10 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
// Create a chain of n-1 multiples.
for (int i = 1; i < n; ++i)
{
TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType()));
TIntermBinary *mul = new TIntermBinary(EOpMul);
mul->setLeft(current);
mul->setRight(createTempSymbol(lhs->getType()));
mul->setType(node->getType());
mul->setLine(node->getLine());
current = mul;
}
@ -135,7 +138,9 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
TConstantUnion *oneVal = new TConstantUnion();
oneVal->setFConst(1.0f);
TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current);
TIntermBinary *div = new TIntermBinary(EOpDiv);
div->setLeft(oneNode);
div->setRight(current);
current = div;
}

View file

@ -10,9 +10,6 @@
#include "compiler/translator/VersionGLSL.h"
namespace sh
{
TExtensionGLSL::TExtensionGLSL(ShShaderOutput output)
: TIntermTraverser(true, false, false), mTargetVersion(ShaderOutputTypeToGLSLVersion(output))
{
@ -101,5 +98,3 @@ void TExtensionGLSL::checkOperator(TIntermOperator *node)
break;
}
}
} // namespace sh

View file

@ -14,9 +14,6 @@
#include "compiler/translator/IntermNode.h"
namespace sh
{
// Traverses the intermediate tree to determine which GLSL extensions are required
// to support the shader.
class TExtensionGLSL : public TIntermTraverser
@ -39,6 +36,4 @@ class TExtensionGLSL : public TIntermTraverser
std::set<std::string> mRequiredExtensions;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_EXTENSIONGLSL_H_

View file

@ -9,9 +9,6 @@
#include "compiler/translator/ValidateLimitations.h"
#include "angle_gl.h"
namespace sh
{
bool ForLoopUnrollMarker::visitBinary(Visit, TIntermBinary *node)
{
if (mUnrollCondition != kSamplerArrayIndex)
@ -54,7 +51,7 @@ bool ForLoopUnrollMarker::visitLoop(Visit, TIntermLoop *node)
// Check if loop index type is integer.
// This is called after ValidateLimitations pass, so the loop has the limited form specified
// in ESSL 1.00 appendix A.
TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
TIntermSequence *declSeq = node->getInit()->getAsAggregate()->getSequence();
TIntermSymbol *symbol = (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
if (symbol->getBasicType() == EbtInt)
node->setUnrollFlag(true);
@ -98,5 +95,3 @@ void ForLoopUnrollMarker::visitSymbol(TIntermSymbol* symbol)
}
}
}
} // namespace sh

View file

@ -9,9 +9,6 @@
#include "compiler/translator/LoopInfo.h"
namespace sh
{
// This class detects for-loops that needs to be unrolled.
// Currently we support two unroll conditions:
// 1) kForLoopWithIntegerIndex: unroll if the index type is integer.
@ -53,6 +50,4 @@ class ForLoopUnrollMarker : public TIntermTraverser
bool mHasRunLoopValidation;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_

View file

@ -6,9 +6,6 @@
#include "compiler/translator/InfoSink.h"
namespace sh
{
void TInfoSinkBase::prefix(TPrefixType p) {
switch(p) {
case EPrefixNone:
@ -55,5 +52,3 @@ void TInfoSinkBase::message(TPrefixType p, const TSourceLoc& loc, const char* m)
sink.append(m);
sink.append("\n");
}
} // namespace sh

View file

@ -11,9 +11,6 @@
#include <stdlib.h>
#include "compiler/translator/Common.h"
namespace sh
{
// Returns the fractional part of the given floating-point number.
inline float fractionalPart(float f) {
float intPart = 0.0f;
@ -116,6 +113,4 @@ public:
TInfoSinkBase obj;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_INFOSINK_H_

View file

@ -16,12 +16,8 @@
#include "compiler/translator/IntermNode.h"
#include "angle_gl.h"
namespace sh
{
void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
{
const TType *voidType = TCache::getType(EbtVoid);
const TType *float1 = TCache::getType(EbtFloat);
const TType *float2 = TCache::getType(EbtFloat, 2);
const TType *float3 = TCache::getType(EbtFloat, 3);
@ -473,26 +469,6 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjGradOffset", gsampler3D, float4, float3, float3, int3);
symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow, float4, float2, float2, int2);
const TType *gimage2D = TCache::getType(EbtGImage2D);
const TType *gimage3D = TCache::getType(EbtGImage3D);
const TType *gimage2DArray = TCache::getType(EbtGImage2DArray);
const TType *gimageCube = TCache::getType(EbtGImageCube);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2D, int2, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage3D, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2DArray, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimageCube, int3, gvec4);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2D, int2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage3D, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimage2DArray, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "imageLoad", gimageCube, int3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int2, "imageSize", gimage2D);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage3D);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimage2DArray);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int3, "imageSize", gimageCube);
//
// Depth range in window coordinates
//
@ -535,13 +511,16 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR
symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors,
EbpMedium);
symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers,
EbpMedium);
if (resources.EXT_blend_func_extended)
if (spec != SH_CSS_SHADERS_SPEC)
{
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
"gl_MaxDualSourceDrawBuffersEXT",
resources.MaxDualSourceDrawBuffers);
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.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
@ -611,73 +590,85 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
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)));
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));
//
// 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));
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)));
}
}
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)));
}
break;
@ -758,5 +749,3 @@ void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
ext_iter->second = EBhUndefined;
}
}
} // namespace sh

View file

@ -11,9 +11,6 @@
#include "compiler/translator/Compiler.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table);
void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
@ -29,6 +26,4 @@ void InitExtensionBehavior(const ShBuiltInResources& resources,
// extensions will remain unsupported.
void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior);
} // namespace sh
#endif // COMPILER_TRANSLATOR_INITIALIZE_H_

View file

@ -13,9 +13,6 @@
#include <assert.h>
namespace sh
{
bool InitProcess()
{
if (!InitializePoolIndex()) {
@ -39,5 +36,3 @@ void DetachProcess()
FreePoolIndex();
TCache::destroy();
}
} // namespace sh

View file

@ -6,11 +6,8 @@
#ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_
#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_
namespace sh
{
bool InitProcess();
void DetachProcess();
} // namespace sh
#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_

View file

@ -10,9 +10,6 @@
#include <assert.h>
namespace sh
{
TLSIndex GlobalParseContextIndex = TLS_INVALID_INDEX;
bool InitializeParseContextIndex()
@ -43,4 +40,3 @@ TParseContext* GetGlobalParseContext()
return static_cast<TParseContext*>(GetTLSValue(GlobalParseContextIndex));
}
} // namespace sh

View file

@ -7,15 +7,11 @@
#ifndef COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_
namespace sh
{
bool InitializeParseContextIndex();
void FreeParseContextIndex();
class TParseContext;
extern void SetGlobalParseContext(TParseContext* context);
extern TParseContext* GetGlobalParseContext();
} // namespace sh
#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_

View file

@ -9,122 +9,191 @@
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
namespace sh
{
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, const TSymbolTable &symbolTable)
: TIntermTraverser(true, false, false),
mVariables(vars),
mSymbolTable(symbolTable),
mCodeInserted(false)
VariableInitializer(const InitVariableList &vars)
: TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
{
ASSERT(mSymbolTable.atGlobalLevel());
}
protected:
bool visitBinary(Visit, TIntermBinary *node) override { return false; }
bool visitUnary(Visit, TIntermUnary *node) override { return false; }
bool visitIfElse(Visit, TIntermIfElse *node) override { return false; }
bool visitSelection(Visit, TIntermSelection *node) override { return false; }
bool visitLoop(Visit, TIntermLoop *node) override { return false; }
bool visitBranch(Visit, TIntermBranch *node) override { return false; }
bool visitAggregate(Visit, TIntermAggregate *node) override { return false; }
bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
const InitVariableList &mVariables;
const TSymbolTable &mSymbolTable;
bool mCodeInserted;
};
// VariableInitializer implementation.
bool VariableInitializer::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
{
// Function definition.
ASSERT(visit == PreVisit);
if (node->getFunctionSymbolInfo()->isMain())
bool visitChildren = !mCodeInserted;
switch (node->getOp())
{
TIntermBlock *body = node->getBody();
insertInitCode(body->getSequence());
mCodeInserted = true;
case EOpSequence:
break;
case EOpFunction:
{
// Function definition.
ASSERT(visit == PreVisit);
if (node->getName() == "main(")
{
TIntermSequence *sequence = node->getSequence();
ASSERT((sequence->size() == 1) || (sequence->size() == 2));
TIntermAggregate *body = NULL;
if (sequence->size() == 1)
{
body = new TIntermAggregate(EOpSequence);
sequence->push_back(body);
}
else
{
body = (*sequence)[1]->getAsAggregate();
}
ASSERT(body);
insertInitCode(body->getSequence());
mCodeInserted = true;
}
break;
}
default:
visitChildren = false;
break;
}
return false;
return visitChildren;
}
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
for (const auto &var : mVariables)
for (size_t ii = 0; ii < mVariables.size(); ++ii)
{
const sh::ShaderVariable &var = mVariables[ii];
TString name = TString(var.name.c_str());
if (var.isArray())
{
// Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
// doesn't have array assignment.
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
size_t pos = name.find_last_of('[');
if (pos != TString::npos)
{
name = name.substr(0, pos);
}
TType elementType = sh::GetShaderVariableBasicType(var);
TType arrayType = elementType;
arrayType.setArraySize(var.elementCount());
for (unsigned int i = 0; i < var.arraySize; ++i)
for (int index = static_cast<int>(var.arraySize) - 1; index >= 0; --index)
{
TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, arrayType);
TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol,
TIntermTyped::CreateIndexNode(i));
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermTyped *zero = TIntermTyped::CreateZero(elementType);
TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero);
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
indexDirect->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(index);
indexDirect->setRight(indexNode);
sequence->insert(sequence->begin(), assignment);
assign->setLeft(indexDirect);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
}
else if (var.isStruct())
{
TVariable *structInfo = reinterpret_cast<TVariable *>(mSymbolTable.findGlobal(name));
ASSERT(structInfo);
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)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermSymbol *symbol = new TIntermSymbol(0, name, structInfo->getType());
TIntermTyped *zero = TIntermTyped::CreateZero(structInfo->getType());
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);
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
sequence->insert(sequence->begin(), assign);
const sh::ShaderVariable &field = var.fields[fieldIndex];
TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType);
assign->setRight(zeroConst);
}
}
else
{
TType type = sh::GetShaderVariableBasicType(var);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
TIntermTyped *zero = TIntermTyped::CreateZero(type);
TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero);
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
TIntermBinary *assign = new TIntermBinary(EOpAssign);
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,
const TSymbolTable &symbolTable)
void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
{
VariableInitializer initializer(vars, symbolTable);
VariableInitializer initializer(vars);
root->traverse(&initializer);
}
} // namespace sh

View file

@ -9,23 +9,10 @@
#include <GLSLANG/ShaderLang.h>
namespace sh
{
class TIntermNode;
class TSymbolTable;
typedef std::vector<sh::ShaderVariable> InitVariableList;
// Currently this function is only capable of initializing variables of basic types,
// array of basic types, or struct of basic types.
// For now it is used for the following two scenarios:
// 1. initializing gl_Position;
// 2. initializing ESSL 3.00 shaders' output variables (which might be structs).
// Specifically, it's not feasible to make it work for local variables because if their
// types are structs, we can't look into TSymbolTable to find the TType data.
void InitializeVariables(TIntermNode *root,
const InitVariableList &vars,
const TSymbolTable &symbolTable);
} // namespace sh
void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_

File diff suppressed because it is too large Load diff

View file

@ -27,22 +27,14 @@
#include "compiler/translator/Operator.h"
#include "compiler/translator/Types.h"
namespace sh
{
class TDiagnostics;
class TIntermTraverser;
class TIntermAggregate;
class TIntermBlock;
class TIntermDeclaration;
class TIntermFunctionDefinition;
class TIntermSwizzle;
class TIntermBinary;
class TIntermUnary;
class TIntermConstantUnion;
class TIntermTernary;
class TIntermIfElse;
class TIntermSelection;
class TIntermSwitch;
class TIntermCase;
class TIntermTyped;
@ -54,7 +46,6 @@ class TIntermRaw;
class TIntermBranch;
class TSymbolTable;
class TFunction;
// Encapsulate an identifier string and track whether it is coming from the original shader code
// (not internal) or from ANGLE (internal). Usually internal names shouldn't be decorated or hashed.
@ -99,15 +90,10 @@ class TIntermNode : angle::NonCopyable
virtual void traverse(TIntermTraverser *) = 0;
virtual TIntermTyped *getAsTyped() { return 0; }
virtual TIntermConstantUnion *getAsConstantUnion() { return 0; }
virtual TIntermFunctionDefinition *getAsFunctionDefinition() { return nullptr; }
virtual TIntermAggregate *getAsAggregate() { return 0; }
virtual TIntermBlock *getAsBlock() { return nullptr; }
virtual TIntermDeclaration *getAsDeclarationNode() { return nullptr; }
virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; }
virtual TIntermBinary *getAsBinaryNode() { return 0; }
virtual TIntermUnary *getAsUnaryNode() { return 0; }
virtual TIntermTernary *getAsTernaryNode() { return nullptr; }
virtual TIntermIfElse *getAsIfElseNode() { return nullptr; }
virtual TIntermSelection *getAsSelectionNode() { return 0; }
virtual TIntermSwitch *getAsSwitchNode() { return 0; }
virtual TIntermCase *getAsCaseNode() { return 0; }
virtual TIntermSymbol *getAsSymbolNode() { return 0; }
@ -155,7 +141,6 @@ class TIntermTyped : public TIntermNode
TBasicType getBasicType() const { return mType.getBasicType(); }
TQualifier getQualifier() const { return mType.getQualifier(); }
TPrecision getPrecision() const { return mType.getPrecision(); }
TMemoryQualifier getMemoryQualifier() const { return mType.getMemoryQualifier(); }
int getCols() const { return mType.getCols(); }
int getRows() const { return mType.getRows(); }
int getNominalSize() const { return mType.getNominalSize(); }
@ -174,9 +159,6 @@ class TIntermTyped : public TIntermNode
bool isConstructorWithOnlyConstantUnionParameters();
static TIntermTyped *CreateIndexNode(int index);
static TIntermTyped *CreateZero(const TType &type);
protected:
TType mType;
@ -200,7 +182,7 @@ class TIntermLoop : public TIntermNode
TIntermNode *init,
TIntermTyped *cond,
TIntermTyped *expr,
TIntermBlock *body)
TIntermAggregate *body)
: mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body), mUnrollFlag(false)
{
}
@ -213,11 +195,11 @@ class TIntermLoop : public TIntermNode
TIntermNode *getInit() { return mInit; }
TIntermTyped *getCondition() { return mCond; }
TIntermTyped *getExpression() { return mExpr; }
TIntermBlock *getBody() { return mBody; }
TIntermAggregate *getBody() { return mBody; }
void setCondition(TIntermTyped *condition) { mCond = condition; }
void setExpression(TIntermTyped *expression) { mExpr = expression; }
void setBody(TIntermBlock *body) { mBody = body; }
void setBody(TIntermAggregate *body) { mBody = body; }
void setUnrollFlag(bool flag) { mUnrollFlag = flag; }
bool getUnrollFlag() const { return mUnrollFlag; }
@ -227,7 +209,7 @@ class TIntermLoop : public TIntermNode
TIntermNode *mInit; // for-loop initialization
TIntermTyped *mCond; // loop exit condition
TIntermTyped *mExpr; // for-loop expression
TIntermBlock *mBody; // loop body
TIntermAggregate *mBody; // loop body
bool mUnrollFlag; // Whether the loop should be unrolled or not.
};
@ -334,7 +316,6 @@ class TIntermConstantUnion : public TIntermTyped
TIntermConstantUnion(const TConstantUnion *unionPointer, const TType &type)
: TIntermTyped(type), mUnionArrayPointer(unionPointer)
{
ASSERT(unionPointer);
}
TIntermTyped *deepCopy() const override { return new TIntermConstantUnion(*this); }
@ -362,7 +343,6 @@ class TIntermConstantUnion : public TIntermTyped
void replaceConstantUnion(const TConstantUnion *safeConstantUnion)
{
ASSERT(safeConstantUnion);
// Previous union pointer freed on pool deallocation.
mUnionArrayPointer = safeConstantUnion;
}
@ -373,15 +353,13 @@ class TIntermConstantUnion : public TIntermTyped
TConstantUnion *foldBinary(TOperator op,
TIntermConstantUnion *rightNode,
TDiagnostics *diagnostics,
const TSourceLoc &line);
const TConstantUnion *foldIndexing(int index);
TConstantUnion *foldUnaryNonComponentWise(TOperator op);
TConstantUnion *foldUnaryComponentWise(TOperator op, TDiagnostics *diagnostics);
TDiagnostics *diagnostics);
TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink);
TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics);
static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate,
TInfoSink &infoSink);
static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink);
protected:
// Same data may be shared between multiple constant unions, so it can't be modified.
@ -389,9 +367,7 @@ class TIntermConstantUnion : public TIntermTyped
private:
typedef float(*FloatTypeUnaryFunc) (float);
void foldFloatTypeUnary(const TConstantUnion &parameter,
FloatTypeUnaryFunc builtinFunc,
TConstantUnion *result) const;
bool foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private!
};
@ -403,6 +379,7 @@ class TIntermOperator : public TIntermTyped
{
public:
TOperator getOp() const { return mOp; }
void setOp(TOperator op) { mOp = op; }
bool isAssignment() const;
bool isMultiplication() const;
@ -423,54 +400,24 @@ class TIntermOperator : public TIntermTyped
TOperator mOp;
};
// Node for vector swizzles.
class TIntermSwizzle : public TIntermTyped
{
public:
// This constructor determines the type of the node based on the operand.
TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets);
TIntermTyped *deepCopy() const override { return new TIntermSwizzle(*this); }
TIntermSwizzle *getAsSwizzleNode() override { return this; };
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override { return mOperand->hasSideEffects(); }
TIntermTyped *getOperand() { return mOperand; }
void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
bool hasDuplicateOffsets() const;
TIntermTyped *fold();
protected:
TIntermTyped *mOperand;
TVector<int> mSwizzleOffsets;
private:
void promote();
TIntermSwizzle(const TIntermSwizzle &node); // Note: not deleted, just private!
};
//
// 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);
static TQualifier GetCommaQualifier(int shaderVersion,
const TIntermTyped *left,
const TIntermTyped *right);
TIntermBinary *getAsBinaryNode() override { return this; };
void traverse(TIntermTraverser *it) override;
@ -481,6 +428,8 @@ class TIntermBinary : public TIntermOperator
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);
@ -507,7 +456,14 @@ class TIntermBinary : public TIntermOperator
class TIntermUnary : public TIntermOperator
{
public:
TIntermUnary(TOperator op, TIntermTyped *operand);
TIntermUnary(TOperator op, const TType &type)
: TIntermOperator(op, type),
mOperand(NULL),
mUseEmulatedFunction(false) {}
TIntermUnary(TOperator op)
: TIntermOperator(op),
mOperand(NULL),
mUseEmulatedFunction(false) {}
TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
@ -517,8 +473,10 @@ class TIntermUnary : public TIntermOperator
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
TIntermTyped *fold(TDiagnostics *diagnostics);
void promote(const TType *funcReturnType);
TIntermTyped *fold(TInfoSink &infoSink);
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
@ -531,107 +489,22 @@ class TIntermUnary : public TIntermOperator
bool mUseEmulatedFunction;
private:
void promote();
TIntermUnary(const TIntermUnary &node); // note: not deleted, just private!
};
class TFunctionSymbolInfo
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TFunctionSymbolInfo() : mId(0) {}
TFunctionSymbolInfo(const TFunctionSymbolInfo &) = default;
TFunctionSymbolInfo &operator=(const TFunctionSymbolInfo &) = default;
void setFromFunction(const TFunction &function);
void setNameObj(const TName &name) { mName = name; }
const TName &getNameObj() const { return mName; }
const TString &getName() const { return mName.getString(); }
void setName(const TString &name) { mName.setString(name); }
bool isMain() const { return mName.getString() == "main("; }
void setId(int functionId) { mId = functionId; }
int getId() const { return mId; }
private:
TName mName;
int mId;
};
// Node for function definitions.
class TIntermFunctionDefinition : public TIntermTyped
{
public:
// TODO(oetuaho@nvidia.com): See if TFunctionSymbolInfo could be added to constructor
// parameters.
TIntermFunctionDefinition(const TType &type, TIntermAggregate *parameters, TIntermBlock *body)
: TIntermTyped(type), mParameters(parameters), mBody(body)
{
ASSERT(parameters != nullptr);
ASSERT(body != nullptr);
}
TIntermFunctionDefinition *getAsFunctionDefinition() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermTyped *deepCopy() const override
{
UNREACHABLE();
return nullptr;
}
bool hasSideEffects() const override
{
UNREACHABLE();
return true;
}
TIntermAggregate *getFunctionParameters() const { return mParameters; }
TIntermBlock *getBody() const { return mBody; }
TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
private:
TIntermAggregate *mParameters;
TIntermBlock *mBody;
TFunctionSymbolInfo mFunctionInfo;
};
typedef TVector<TIntermNode *> TIntermSequence;
typedef TVector<int> TQualifierList;
// Interface for node classes that have an arbitrarily sized set of children.
class TIntermAggregateBase
{
public:
virtual ~TIntermAggregateBase() {}
virtual TIntermSequence *getSequence() = 0;
virtual const TIntermSequence *getSequence() const = 0;
bool replaceChildNodeWithMultiple(TIntermNode *original, const TIntermSequence &replacements);
bool insertChildNodes(TIntermSequence::size_type position, const TIntermSequence &insertions);
protected:
TIntermAggregateBase() {}
bool replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement);
};
//
// Nodes that operate on an arbitrary sized set of children.
//
class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
class TIntermAggregate : public TIntermOperator
{
public:
TIntermAggregate()
: TIntermOperator(EOpNull),
mUserDefined(false),
mFunctionId(0),
mUseEmulatedFunction(false),
mGotPrecisionFromChildren(false)
{
@ -639,6 +512,7 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
TIntermAggregate(TOperator op)
: TIntermOperator(op),
mUserDefined(false),
mFunctionId(0),
mUseEmulatedFunction(false),
mGotPrecisionFromChildren(false)
{
@ -648,22 +522,29 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
// 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(TDiagnostics *diagnostics);
TIntermTyped *fold(TInfoSink &infoSink);
TIntermSequence *getSequence() override { return &mSequence; }
const TIntermSequence *getSequence() const override { return &mSequence; }
TIntermSequence *getSequence() { 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; }
bool isUserDefined() const { return mUserDefined; }
void setFunctionId(int functionId) { mFunctionId = functionId; }
int getFunctionId() const { return mFunctionId; }
void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
@ -674,12 +555,11 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
// Returns true if changing parameter precision may affect the return value.
bool gotPrecisionFromChildren() const { return mGotPrecisionFromChildren; }
TFunctionSymbolInfo *getFunctionSymbolInfo() { return &mFunctionInfo; }
const TFunctionSymbolInfo *getFunctionSymbolInfo() const { return &mFunctionInfo; }
protected:
TIntermSequence mSequence;
TName mName;
bool mUserDefined; // used for user defined function names
int mFunctionId;
// If set to true, replace the built-in function call with an emulated one
// to work around driver bugs.
@ -687,110 +567,50 @@ class TIntermAggregate : public TIntermOperator, public TIntermAggregateBase
bool mGotPrecisionFromChildren;
TFunctionSymbolInfo mFunctionInfo;
private:
TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private!
};
// A list of statements. Either the root node which contains declarations and function definitions,
// or a block that can be marked with curly braces {}.
class TIntermBlock : public TIntermNode, public TIntermAggregateBase
//
// For if tests.
//
class TIntermSelection : public TIntermTyped
{
public:
TIntermBlock() : TIntermNode() {}
~TIntermBlock() {}
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); }
TIntermBlock *getAsBlock() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
// Only intended for initially building the block.
void appendStatement(TIntermNode *statement);
// Conservatively assume selections have side-effects
bool hasSideEffects() const override { return true; }
TIntermSequence *getSequence() override { return &mStatements; }
const TIntermSequence *getSequence() const override { return &mStatements; }
bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
TIntermNode *getCondition() const { return mCondition; }
TIntermNode *getTrueBlock() const { return mTrueBlock; }
TIntermNode *getFalseBlock() const { return mFalseBlock; }
TIntermSelection *getAsSelectionNode() override { return this; }
protected:
TIntermSequence mStatements;
};
// Struct, interface block or variable declaration. Can contain multiple variable declarators.
class TIntermDeclaration : public TIntermNode, public TIntermAggregateBase
{
public:
TIntermDeclaration() : TIntermNode() {}
~TIntermDeclaration() {}
TIntermDeclaration *getAsDeclarationNode() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
// Only intended for initially building the declaration.
// The declarator node should be either TIntermSymbol or TIntermBinary with op set to
// EOpInitialize.
void appendDeclarator(TIntermTyped *declarator);
TIntermSequence *getSequence() override { return &mDeclarators; }
const TIntermSequence *getSequence() const override { return &mDeclarators; }
protected:
TIntermSequence mDeclarators;
};
// For ternary operators like a ? b : c.
class TIntermTernary : public TIntermTyped
{
public:
TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression);
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
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);
TIntermTyped *mCondition;
TIntermNode *mTrueBlock;
TIntermNode *mFalseBlock;
private:
TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private!
TIntermTyped *mCondition;
TIntermTyped *mTrueExpression;
TIntermTyped *mFalseExpression;
};
class TIntermIfElse : public TIntermNode
{
public:
TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *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; }
TIntermBlock *getTrueBlock() const { return mTrueBlock; }
TIntermBlock *getFalseBlock() const { return mFalseBlock; }
TIntermIfElse *getAsIfElseNode() override { return this; }
protected:
TIntermTyped *mCondition;
TIntermBlock *mTrueBlock;
TIntermBlock *mFalseBlock;
TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private!
};
//
@ -799,8 +619,10 @@ class TIntermIfElse : public TIntermNode
class TIntermSwitch : public TIntermNode
{
public:
TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
: TIntermNode(), mInit(init), mStatementList(statementList)
TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList)
: TIntermNode(),
mInit(init),
mStatementList(statementList)
{
}
@ -811,12 +633,12 @@ class TIntermSwitch : public TIntermNode
TIntermSwitch *getAsSwitchNode() override { return this; }
TIntermTyped *getInit() { return mInit; }
TIntermBlock *getStatementList() { return mStatementList; }
void setStatementList(TIntermBlock *statementList) { mStatementList = statementList; }
TIntermAggregate *getStatementList() { return mStatementList; }
void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; }
protected:
TIntermTyped *mInit;
TIntermBlock *mStatementList;
TIntermAggregate *mStatementList;
};
//
@ -872,20 +694,12 @@ class TIntermTraverser : angle::NonCopyable
virtual void visitSymbol(TIntermSymbol *node) {}
virtual void visitRaw(TIntermRaw *node) {}
virtual void visitConstantUnion(TIntermConstantUnion *node) {}
virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
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 visitIfElse(Visit visit, TIntermIfElse *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 visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
{
return true;
}
virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
@ -895,17 +709,12 @@ class TIntermTraverser : angle::NonCopyable
virtual void traverseSymbol(TIntermSymbol *node);
virtual void traverseRaw(TIntermRaw *node);
virtual void traverseConstantUnion(TIntermConstantUnion *node);
virtual void traverseSwizzle(TIntermSwizzle *node);
virtual void traverseBinary(TIntermBinary *node);
virtual void traverseUnary(TIntermUnary *node);
virtual void traverseTernary(TIntermTernary *node);
virtual void traverseIfElse(TIntermIfElse *node);
virtual void traverseSelection(TIntermSelection *node);
virtual void traverseSwitch(TIntermSwitch *node);
virtual void traverseCase(TIntermCase *node);
virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
virtual void traverseAggregate(TIntermAggregate *node);
virtual void traverseBlock(TIntermBlock *node);
virtual void traverseDeclaration(TIntermDeclaration *node);
virtual void traverseLoop(TIntermLoop *node);
virtual void traverseBranch(TIntermBranch *node);
@ -952,7 +761,7 @@ class TIntermTraverser : angle::NonCopyable
return nullptr;
}
void pushParentBlock(TIntermBlock *node);
void pushParentBlock(TIntermAggregate *node);
void incrementParentBlockPos();
void popParentBlock();
@ -964,14 +773,14 @@ class TIntermTraverser : angle::NonCopyable
// To replace a single node with multiple nodes on the parent aggregate node
struct NodeReplaceWithMultipleEntry
{
NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
TIntermNode *_original,
TIntermSequence _replacements)
: parent(_parent), original(_original), replacements(_replacements)
NodeReplaceWithMultipleEntry(TIntermAggregate *_parent, TIntermNode *_original, TIntermSequence _replacements)
: parent(_parent),
original(_original),
replacements(_replacements)
{
}
TIntermAggregateBase *parent;
TIntermAggregate *parent;
TIntermNode *original;
TIntermSequence replacements;
};
@ -979,7 +788,7 @@ class TIntermTraverser : angle::NonCopyable
// To insert multiple nodes on the parent aggregate node
struct NodeInsertMultipleEntry
{
NodeInsertMultipleEntry(TIntermBlock *_parent,
NodeInsertMultipleEntry(TIntermAggregate *_parent,
TIntermSequence::size_type _position,
TIntermSequence _insertionsBefore,
TIntermSequence _insertionsAfter)
@ -990,7 +799,7 @@ class TIntermTraverser : angle::NonCopyable
{
}
TIntermBlock *parent;
TIntermAggregate *parent;
TIntermSequence::size_type position;
TIntermSequence insertionsBefore;
TIntermSequence insertionsAfter;
@ -1016,11 +825,11 @@ class TIntermTraverser : angle::NonCopyable
// Helper to create a temporary symbol node.
TIntermSymbol *createTempSymbol(const TType &type);
// Create a node that declares but doesn't initialize a temporary symbol.
TIntermDeclaration *createTempDeclaration(const TType &type);
TIntermAggregate *createTempDeclaration(const TType &type);
// Create a node that initializes the current temporary symbol with initializer having the given qualifier.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
// Create a node that initializes the current temporary symbol with initializer.
TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
TIntermAggregate *createTempInitDeclaration(TIntermTyped *initializer);
// Create a node that assigns rightNode to the current temporary symbol.
TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
// Increment temporary symbol index.
@ -1082,12 +891,13 @@ class TIntermTraverser : angle::NonCopyable
struct ParentBlock
{
ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn), pos(posIn)
ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn)
: node(nodeIn),
pos(posIn)
{
}
TIntermBlock *node;
TIntermAggregate *node;
TIntermSequence::size_type pos;
};
@ -1120,7 +930,6 @@ class TLValueTrackingTraverser : public TIntermTraverser
void traverseBinary(TIntermBinary *node) final;
void traverseUnary(TIntermUnary *node) final;
void traverseFunctionDefinition(TIntermFunctionDefinition *node) final;
void traverseAggregate(TIntermAggregate *node) final;
protected:
@ -1189,10 +998,8 @@ class TMaxDepthTraverser : public TIntermTraverser
bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
bool visitSelection(Visit, TIntermSelection *) override { return depthCheck(); }
bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
@ -1202,6 +1009,4 @@ class TMaxDepthTraverser : public TIntermTraverser
int mDepthLimit;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMNODE_H_

View file

@ -12,9 +12,17 @@
#include "compiler/translator/IntermNode.h"
namespace sh
namespace
{
bool IsNodeBlock(TIntermNode *node)
{
ASSERT(node != nullptr);
return (node->getAsAggregate() && node->getAsAggregate()->getOp() == EOpSequence);
}
} // anonymous namespace
IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask)
{
}
@ -31,7 +39,7 @@ bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *p
if ((mMask & kExpressionReturningArray) != 0)
{
if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
!parentNode->getAsBlock())
!IsNodeBlock(parentNode))
{
return true;
}
@ -88,7 +96,7 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent
if (node->getType().isArray() && !parentIsAssignment &&
(node->isConstructor() || node->getOp() == EOpFunctionCall) &&
!parentNode->getAsBlock())
!IsNodeBlock(parentNode))
{
return true;
}
@ -97,13 +105,14 @@ bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parent
return false;
}
bool IntermNodePatternMatcher::match(TIntermTernary *node)
bool IntermNodePatternMatcher::match(TIntermSelection *node)
{
if ((mMask & kUnfoldedShortCircuitExpression) != 0)
{
return true;
if (node->usesTernaryOperator())
{
return true;
}
}
return false;
}
} // namespace sh

View file

@ -11,13 +11,10 @@
#ifndef COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
namespace sh
{
class TIntermAggregate;
class TIntermBinary;
class TIntermNode;
class TIntermTernary;
class TIntermSelection;
class IntermNodePatternMatcher
{
@ -45,7 +42,7 @@ class IntermNodePatternMatcher
bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
bool match(TIntermAggregate *node, TIntermNode *parentNode);
bool match(TIntermTernary *node);
bool match(TIntermSelection *node);
private:
const unsigned int mMask;
@ -53,6 +50,4 @@ class IntermNodePatternMatcher
bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
};
} // namespace sh
#endif

View file

@ -8,9 +8,6 @@
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
void TIntermSymbol::traverse(TIntermTraverser *it)
{
it->traverseSymbol(this);
@ -26,11 +23,6 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it)
it->traverseConstantUnion(this);
}
void TIntermSwizzle::traverse(TIntermTraverser *it)
{
it->traverseSwizzle(this);
}
void TIntermBinary::traverse(TIntermTraverser *it)
{
it->traverseBinary(this);
@ -41,14 +33,9 @@ void TIntermUnary::traverse(TIntermTraverser *it)
it->traverseUnary(this);
}
void TIntermTernary::traverse(TIntermTraverser *it)
void TIntermSelection::traverse(TIntermTraverser *it)
{
it->traverseTernary(this);
}
void TIntermIfElse::traverse(TIntermTraverser *it)
{
it->traverseIfElse(this);
it->traverseSelection(this);
}
void TIntermSwitch::traverse(TIntermTraverser *it)
@ -61,21 +48,6 @@ void TIntermCase::traverse(TIntermTraverser *it)
it->traverseCase(this);
}
void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
{
it->traverseFunctionDefinition(this);
}
void TIntermBlock::traverse(TIntermTraverser *it)
{
it->traverseBlock(this);
}
void TIntermDeclaration::traverse(TIntermTraverser *it)
{
it->traverseDeclaration(this);
}
void TIntermAggregate::traverse(TIntermTraverser *it)
{
it->traverseAggregate(this);
@ -106,7 +78,7 @@ TIntermTraverser::~TIntermTraverser()
{
}
void TIntermTraverser::pushParentBlock(TIntermBlock *node)
void TIntermTraverser::pushParentBlock(TIntermAggregate *node)
{
mParentBlockStack.push_back(ParentBlock(node, 0));
}
@ -154,11 +126,7 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier
TIntermSymbol *node = new TIntermSymbol(0, symbolName, type);
node->setInternal(true);
ASSERT(qualifier == EvqTemporary || qualifier == EvqConst || qualifier == EvqGlobal);
node->getTypePointer()->setQualifier(qualifier);
// TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
// symbol. This might need to be done in other places as well.
return node;
}
@ -167,25 +135,27 @@ TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type)
return createTempSymbol(type, EvqTemporary);
}
TIntermDeclaration *TIntermTraverser::createTempDeclaration(const TType &type)
TIntermAggregate *TIntermTraverser::createTempDeclaration(const TType &type)
{
TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
tempDeclaration->appendDeclarator(createTempSymbol(type));
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
tempDeclaration->getSequence()->push_back(createTempSymbol(type));
return tempDeclaration;
}
TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer,
TQualifier qualifier)
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier)
{
ASSERT(initializer != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier);
TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
tempDeclaration->appendDeclarator(tempInit);
TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration);
TIntermBinary *tempInit = new TIntermBinary(EOpInitialize);
tempInit->setLeft(tempSymbol);
tempInit->setRight(initializer);
tempInit->setType(tempSymbol->getType());
tempDeclaration->getSequence()->push_back(tempInit);
return tempDeclaration;
}
TIntermDeclaration *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *initializer)
{
return createTempInitDeclaration(initializer, EvqTemporary);
}
@ -194,7 +164,10 @@ TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode)
{
ASSERT(rightNode != nullptr);
TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType());
TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode);
TIntermBinary *assignment = new TIntermBinary(EOpAssign);
assignment->setLeft(tempSymbol);
assignment->setRight(rightNode);
assignment->setType(tempSymbol->getType());
return assignment;
}
@ -217,14 +190,13 @@ void TLValueTrackingTraverser::addToFunctionMap(const TName &name, TIntermSequen
bool TLValueTrackingTraverser::isInFunctionMap(const TIntermAggregate *callNode) const
{
ASSERT(callNode->getOp() == EOpFunctionCall);
return (mFunctionMap.find(callNode->getFunctionSymbolInfo()->getNameObj()) !=
mFunctionMap.end());
return (mFunctionMap.find(callNode->getNameObj()) != mFunctionMap.end());
}
TIntermSequence *TLValueTrackingTraverser::getFunctionParameters(const TIntermAggregate *callNode)
{
ASSERT(isInFunctionMap(callNode));
return mFunctionMap[callNode->getFunctionSymbolInfo()->getNameObj()];
return mFunctionMap[callNode->getNameObj()];
}
void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
@ -261,26 +233,6 @@ void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
visitConstantUnion(node);
}
void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
{
bool visit = true;
if (preVisit)
visit = visitSwizzle(PreVisit, node);
if (visit)
{
incrementDepth(node);
node->getOperand()->traverse(this);
decrementDepth();
}
if (visit && postVisit)
visitSwizzle(PostVisit, node);
}
//
// Traverse a binary node.
//
@ -442,99 +394,9 @@ void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
visitUnary(PostVisit, node);
}
// Traverse a function definition node.
void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
{
bool visit = true;
if (preVisit)
visit = visitFunctionDefinition(PreVisit, node);
if (visit)
{
incrementDepth(node);
mInGlobalScope = false;
node->getFunctionParameters()->traverse(this);
if (inVisit)
visit = visitFunctionDefinition(InVisit, node);
node->getBody()->traverse(this);
mInGlobalScope = true;
decrementDepth();
}
if (visit && postVisit)
visitFunctionDefinition(PostVisit, node);
}
// Traverse a block node.
void TIntermTraverser::traverseBlock(TIntermBlock *node)
{
bool visit = true;
TIntermSequence *sequence = node->getSequence();
if (preVisit)
visit = visitBlock(PreVisit, node);
if (visit)
{
incrementDepth(node);
pushParentBlock(node);
for (auto *child : *sequence)
{
child->traverse(this);
if (visit && inVisit)
{
if (child != sequence->back())
visit = visitBlock(InVisit, node);
}
incrementParentBlockPos();
}
popParentBlock();
decrementDepth();
}
if (visit && postVisit)
visitBlock(PostVisit, node);
}
// Traverse a declaration node.
void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
{
bool visit = true;
TIntermSequence *sequence = node->getSequence();
if (preVisit)
visit = visitDeclaration(PreVisit, node);
if (visit)
{
incrementDepth(node);
for (auto *child : *sequence)
{
child->traverse(this);
if (visit && inVisit)
{
if (child != sequence->back())
visit = visitDeclaration(InVisit, node);
}
}
decrementDepth();
}
if (visit && postVisit)
visitDeclaration(PostVisit, node);
}
//
// Traverse an aggregate node. Same comments in binary node apply here.
//
void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
{
bool visit = true;
@ -548,6 +410,11 @@ void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
{
incrementDepth(node);
if (node->getOp() == EOpSequence)
pushParentBlock(node);
else if (node->getOp() == EOpFunction)
mInGlobalScope = false;
for (auto *child : *sequence)
{
child->traverse(this);
@ -556,8 +423,16 @@ void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
if (child != sequence->back())
visit = visitAggregate(InVisit, node);
}
if (node->getOp() == EOpSequence)
incrementParentBlockPos();
}
if (node->getOp() == EOpSequence)
popParentBlock();
else if (node->getOp() == EOpFunction)
mInGlobalScope = true;
decrementDepth();
}
@ -565,24 +440,26 @@ void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
visitAggregate(PostVisit, node);
}
void TLValueTrackingTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
{
TIntermAggregate *params = node->getFunctionParameters();
ASSERT(params != nullptr);
ASSERT(params->getOp() == EOpParameters);
addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), params->getSequence());
TIntermTraverser::traverseFunctionDefinition(node);
}
void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
{
bool visit = true;
TIntermSequence *sequence = node->getSequence();
if (node->getOp() == EOpPrototype)
switch (node->getOp())
{
addToFunctionMap(node->getFunctionSymbolInfo()->getNameObj(), sequence);
case EOpFunction:
{
TIntermAggregate *params = sequence->front()->getAsAggregate();
ASSERT(params != nullptr);
ASSERT(params->getOp() == EOpParameters);
addToFunctionMap(node->getNameObj(), params->getSequence());
break;
}
case EOpPrototype:
addToFunctionMap(node->getNameObj(), sequence);
break;
default:
break;
}
if (preVisit)
@ -628,6 +505,11 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
}
else
{
if (node->getOp() == EOpSequence)
pushParentBlock(node);
else if (node->getOp() == EOpFunction)
mInGlobalScope = false;
// Find the built-in function corresponding to this op so that we can determine the
// in/out qualifiers of its parameters.
TFunction *builtInFunc = nullptr;
@ -669,10 +551,18 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
visit = visitAggregate(InVisit, node);
}
if (node->getOp() == EOpSequence)
incrementParentBlockPos();
++paramIndex;
}
setInFunctionCallOutParameter(false);
if (node->getOp() == EOpSequence)
popParentBlock();
else if (node->getOp() == EOpFunction)
mInGlobalScope = true;
}
decrementDepth();
@ -683,37 +573,14 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
}
//
// Traverse a ternary node. Same comments in binary node apply here.
// Traverse a selection node. Same comments in binary node apply here.
//
void TIntermTraverser::traverseTernary(TIntermTernary *node)
void TIntermTraverser::traverseSelection(TIntermSelection *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 an if-else node. Same comments in binary node apply here.
void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
{
bool visit = true;
if (preVisit)
visit = visitIfElse(PreVisit, node);
visit = visitSelection(PreVisit, node);
if (visit)
{
@ -727,7 +594,7 @@ void TIntermTraverser::traverseIfElse(TIntermIfElse *node)
}
if (visit && postVisit)
visitIfElse(PostVisit, node);
visitSelection(PostVisit, node);
}
//
@ -766,11 +633,7 @@ void TIntermTraverser::traverseCase(TIntermCase *node)
visit = visitCase(PreVisit, node);
if (visit && node->getCondition())
{
incrementDepth(node);
node->getCondition()->traverse(this);
decrementDepth();
}
if (visit && postVisit)
visitCase(PostVisit, node);
@ -834,5 +697,3 @@ void TIntermTraverser::traverseRaw(TIntermRaw *node)
{
visitRaw(node);
}
} // namespace sh

View file

@ -15,9 +15,6 @@
#include "compiler/translator/Intermediate.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
{
////////////////////////////////////////////////////////////////////////////
//
// First set of functions are to help build the intermediate representation.
@ -47,30 +44,52 @@ TIntermSymbol *TIntermediate::addSymbol(
// 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,
TDiagnostics *diagnostics)
TIntermTyped *TIntermediate::addIndex(
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line)
{
TIntermBinary *node = new TIntermBinary(op, base, index);
TIntermBinary *node = new TIntermBinary(op);
node->setLine(line);
node->setLeft(base);
node->setRight(index);
TIntermTyped *folded = node->fold(diagnostics);
if (folded)
{
return folded;
}
// 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;
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.
// a function call's operation on it's set of parameters. Sequences
// of instructions are also aggregates, but they just direnctly set
// their operator to EOpSequence.
//
// Returns an aggregate node, which could be the one passed in if
// it was already an aggregate but no operator was set.
//
TIntermAggregate *TIntermediate::setAggregateOperator(
TIntermNode *node, TOperator op, const TSourceLoc &line)
{
@ -141,10 +160,11 @@ TIntermAggregate *TIntermediate::growAggregate(
//
// Returns an aggregate, unless NULL was passed in for the existing node.
//
TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceLoc &line)
TIntermAggregate *TIntermediate::makeAggregate(
TIntermNode *node, const TSourceLoc &line)
{
if (node == nullptr)
return nullptr;
if (node == NULL)
return NULL;
TIntermAggregate *aggNode = new TIntermAggregate;
aggNode->getSequence()->push_back(node);
@ -155,57 +175,70 @@ TIntermAggregate *TIntermediate::MakeAggregate(TIntermNode *node, const TSourceL
}
// If the input node is nullptr, return nullptr.
// If the input node is a block node, return it.
// If the input node is not a block node, put it inside a block node and return that.
TIntermBlock *TIntermediate::EnsureBlock(TIntermNode *node)
// If the input node is a sequence (block) node, return it.
// If the input node is not a sequence node, put it inside a sequence node and return that.
TIntermAggregate *TIntermediate::ensureSequence(TIntermNode *node)
{
if (node == nullptr)
return nullptr;
TIntermBlock *blockNode = node->getAsBlock();
if (blockNode != nullptr)
return blockNode;
TIntermAggregate *aggNode = node->getAsAggregate();
if (aggNode != nullptr && aggNode->getOp() == EOpSequence)
return aggNode;
blockNode = new TIntermBlock();
blockNode->setLine(node->getLine());
blockNode->getSequence()->push_back(node);
return blockNode;
aggNode = makeAggregate(node, node->getLine());
aggNode->setOp(EOpSequence);
return aggNode;
}
//
// For "if" test nodes. There are three children; a condition,
// a true path, and a false path. The two paths are in the
// nodePair.
//
// Returns the node created.
TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond,
TIntermNodePair nodePair,
const TSourceLoc &line)
// Returns the selection node created.
//
TIntermNode *TIntermediate::addSelection(
TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line)
{
// For compile time constant conditions, prune the code now.
//
// For compile time constant selections, prune the code and
// test now.
//
if (cond->getAsConstantUnion())
{
if (cond->getAsConstantUnion()->getBConst(0) == true)
{
return EnsureBlock(nodePair.node1);
return nodePair.node1 ? setAggregateOperator(
nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
}
else
{
return EnsureBlock(nodePair.node2);
return nodePair.node2 ? setAggregateOperator(
nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
}
}
TIntermIfElse *node =
new TIntermIfElse(cond, EnsureBlock(nodePair.node1), EnsureBlock(nodePair.node2));
TIntermSelection *node = new TIntermSelection(
cond, ensureSequence(nodePair.node1), ensureSequence(nodePair.node2));
node->setLine(line);
return node;
}
TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
TIntermTyped *TIntermediate::addComma(TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &line,
int shaderVersion)
{
TQualifier resultQualifier = EvqConst;
// ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
right->getQualifier() != EvqConst)
{
resultQualifier = EvqTemporary;
}
TIntermTyped *commaNode = nullptr;
if (!left->hasSideEffects())
{
@ -213,53 +246,58 @@ TIntermTyped *TIntermediate::AddComma(TIntermTyped *left,
}
else
{
commaNode = new TIntermBinary(EOpComma, left, right);
commaNode->setLine(line);
commaNode = growAggregate(left, right, line);
commaNode->getAsAggregate()->setOp(EOpComma);
commaNode->setType(right->getType());
}
TQualifier resultQualifier = TIntermBinary::GetCommaQualifier(shaderVersion, left, right);
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 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)
// 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)
{
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))
{
trueExpression->getTypePointer()->setQualifier(resultQualifier);
return trueExpression;
trueBlock->getTypePointer()->setQualifier(resultQualifier);
return trueBlock;
}
else
{
falseExpression->getTypePointer()->setQualifier(resultQualifier);
return falseExpression;
falseBlock->getTypePointer()->setQualifier(resultQualifier);
return falseBlock;
}
}
// Make a ternary node.
TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression);
//
// Make a selection node.
//
TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
node->getTypePointer()->setQualifier(resultQualifier);
node->setLine(line);
return node;
}
TIntermSwitch *TIntermediate::addSwitch(TIntermTyped *init,
TIntermBlock *statementList,
const TSourceLoc &line)
TIntermSwitch *TIntermediate::addSwitch(
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line)
{
TIntermSwitch *node = new TIntermSwitch(init, statementList);
node->setLine(line);
@ -292,22 +330,24 @@ TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *cons
return node;
}
TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression,
const TVectorFields &fields,
const TSourceLoc &dotLocation)
TIntermTyped *TIntermediate::addSwizzle(
TVectorFields &fields, const TSourceLoc &line)
{
TVector<int> fieldsVector;
for (int i = 0; i < fields.num; ++i)
{
fieldsVector.push_back(fields.offsets[i]);
}
TIntermSwizzle *node = new TIntermSwizzle(baseExpression, fieldsVector);
node->setLine(dotLocation);
TIntermTyped *folded = node->fold();
if (folded)
TIntermAggregate *node = new TIntermAggregate(EOpSequence);
node->setLine(line);
TIntermConstantUnion *constIntNode;
TIntermSequence *sequenceVector = node->getSequence();
TConstantUnion *unionArray;
for (int i = 0; i < fields.num; i++)
{
return folded;
unionArray = new TConstantUnion[1];
unionArray->setIConst(fields.offsets[i]);
constIntNode = addConstantUnion(
unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
sequenceVector->push_back(constIntNode);
}
return node;
@ -320,7 +360,7 @@ TIntermNode *TIntermediate::addLoop(
TLoopType type, TIntermNode *init, TIntermTyped *cond, TIntermTyped *expr,
TIntermNode *body, const TSourceLoc &line)
{
TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureBlock(body));
TIntermNode *node = new TIntermLoop(type, init, cond, expr, ensureSequence(body));
node->setLine(line);
return node;
@ -344,8 +384,34 @@ TIntermBranch* TIntermediate::addBranch(
return node;
}
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
TDiagnostics *diagnostics)
//
// This is to be executed once the final root is put on top by the parsing
// process.
//
TIntermAggregate *TIntermediate::postProcess(TIntermNode *root)
{
if (root == nullptr)
return nullptr;
//
// Finish off the top level sequence, if any
//
TIntermAggregate *aggRoot = root->getAsAggregate();
if (aggRoot != nullptr && aggRoot->getOp() == EOpNull)
{
aggRoot->setOp(EOpSequence);
}
else if (aggRoot == nullptr || aggRoot->getOp() != EOpSequence)
{
aggRoot = new TIntermAggregate(EOpSequence);
aggRoot->setLine(root->getLine());
aggRoot->getSequence()->push_back(root);
}
return aggRoot;
}
TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate)
{
switch (aggregate->getOp())
{
@ -372,16 +438,14 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate,
case EOpFaceForward:
case EOpReflect:
case EOpRefract:
return aggregate->fold(diagnostics);
return aggregate->fold(mInfoSink);
default:
// TODO: Add support for folding array constructors
if (aggregate->isConstructor() && !aggregate->isArray())
{
return aggregate->fold(diagnostics);
return aggregate->fold(mInfoSink);
}
// Constant folding not supported for the built-in.
return nullptr;
}
}
} // namespace sh

View file

@ -9,9 +9,6 @@
#include "compiler/translator/IntermNode.h"
namespace sh
{
struct TVectorFields
{
int offsets[4];
@ -19,42 +16,38 @@ struct TVectorFields
};
//
// Set of helper functions to help build the tree.
// Set of helper functions to help parse and build the tree.
//
class TInfoSink;
class TIntermediate
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TIntermediate() {}
TIntermediate(TInfoSink &i)
: mInfoSink(i) { }
TIntermSymbol *addSymbol(
int id, const TString &, const TType &, const TSourceLoc &);
TIntermTyped *addIndex(TOperator op,
TIntermTyped *base,
TIntermTyped *index,
const TSourceLoc &line,
TDiagnostics *diagnostics);
TIntermTyped *addIndex(
TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &);
TIntermTyped *addUnaryMath(
TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType);
TIntermAggregate *growAggregate(
TIntermNode *left, TIntermNode *right, const TSourceLoc &);
static TIntermAggregate *MakeAggregate(TIntermNode *node, const TSourceLoc &line);
static TIntermBlock *EnsureBlock(TIntermNode *node);
TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &);
TIntermAggregate *ensureSequence(TIntermNode *node);
TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &);
TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line);
static TIntermTyped *AddTernarySelection(TIntermTyped *cond,
TIntermTyped *trueExpression,
TIntermTyped *falseExpression,
const TSourceLoc &line);
TIntermSwitch *addSwitch(TIntermTyped *init,
TIntermBlock *statementList,
const TSourceLoc &line);
TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &);
TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock,
const TSourceLoc &line);
TIntermSwitch *addSwitch(
TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line);
TIntermCase *addCase(
TIntermTyped *condition, const TSourceLoc &line);
static TIntermTyped *AddComma(TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &line,
int shaderVersion);
TIntermTyped *addComma(TIntermTyped *left,
TIntermTyped *right,
const TSourceLoc &line,
int shaderVersion);
TIntermConstantUnion *addConstantUnion(const TConstantUnion *constantUnion,
const TType &type,
const TSourceLoc &line);
@ -62,18 +55,17 @@ class TIntermediate
TIntermNode *, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, const TSourceLoc &);
TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &);
static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression,
const TVectorFields &fields,
const TSourceLoc &dotLocation);
TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &);
TIntermAggregate *postProcess(TIntermNode *root);
static void outputTree(TIntermNode *, TInfoSinkBase &);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate);
private:
void operator=(TIntermediate &); // prevent assignments
TInfoSink & mInfoSink;
};
} // namespace sh
#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_

View file

@ -6,9 +6,6 @@
#include "compiler/translator/LoopInfo.h"
namespace sh
{
namespace
{
@ -96,7 +93,8 @@ void TLoopIndexInfo::fillInfo(TIntermLoop *node)
// Here we assume all the operations are valid, because the loop node is
// already validated in ValidateLimitations.
TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
TIntermSequence *declSeq =
node->getInit()->getAsAggregate()->getSequence();
TIntermBinary *declInit = (*declSeq)[0]->getAsBinaryNode();
TIntermSymbol *symbol = declInit->getLeft()->getAsSymbolNode();
@ -211,4 +209,3 @@ void TLoopStack::pop()
pop_back();
}
} // namespace sh

Some files were not shown because too many files have changed in this diff Show more