diff options
Diffstat (limited to 'chromium/third_party/angle/src/compiler/translator')
115 files changed, 9806 insertions, 7324 deletions
diff --git a/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.cpp index 31bfae9966f..1fa3c59a690 100644 --- a/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.cpp @@ -72,9 +72,9 @@ class PullGradient : public TIntermTraverser return true; } - bool visitSelection(Visit visit, TIntermSelection *selection) override + bool visitIfElse(Visit visit, TIntermIfElse *ifElse) override { - visitControlFlow(visit, selection); + visitControlFlow(visit, ifElse); return true; } @@ -196,7 +196,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser return true; } - bool visitSelection(Visit visit, TIntermSelection *node) override + bool visitIfElse(Visit visit, TIntermIfElse *node) override { if (visit == PreVisit) { @@ -310,7 +310,7 @@ class PullComputeDiscontinuousAndGradientLoops : public TIntermTraverser const CallDAG &mDag; std::vector<TIntermNode*> mLoopsAndSwitches; - std::vector<TIntermSelection*> mIfs; + std::vector<TIntermIfElse *> mIfs; }; // Tags all the functions called in a discontinuous loop @@ -385,7 +385,7 @@ bool ASTMetadataHLSL::hasGradientInCallGraph(TIntermLoop *node) return mControlFlowsContainingGradient.count(node) > 0; } -bool ASTMetadataHLSL::hasGradientLoop(TIntermSelection *node) +bool ASTMetadataHLSL::hasGradientLoop(TIntermIfElse *node) { return mIfsContainingGradientLoop.count(node) > 0; } diff --git a/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.h b/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.h index 39e671e3e02..4795bc38779 100644 --- a/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.h @@ -14,7 +14,7 @@ class CallDAG; class TIntermNode; -class TIntermSelection; +class TIntermIfElse; class TIntermLoop; struct ASTMetadataHLSL @@ -30,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(TIntermSelection *node); + bool hasGradientLoop(TIntermIfElse *node); // Does the function use a gradient. bool mUsesGradient; @@ -44,7 +44,7 @@ struct ASTMetadataHLSL bool mCalledInDiscontinuousLoop; bool mHasGradientLoopInCallGraph; std::set<TIntermLoop*> mDiscontinuousLoops; - std::set<TIntermSelection *> mIfsContainingGradientLoop; + std::set<TIntermIfElse *> mIfsContainingGradientLoop; // Will we need to generate a Lod0 version of the function. bool mNeedsLod0; diff --git a/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp b/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp new file mode 100644 index 00000000000..0177fea968a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp @@ -0,0 +1,59 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "compiler/translator/AddAndTrueToLoopCondition.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ + +// An AST traverser that rewrites for and while loops by replacing "condition" with +// "condition && true" to work around condition bug on Intel Mac. +class AddAndTrueToLoopConditionTraverser : public TIntermTraverser +{ + public: + AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {} + + bool visitLoop(Visit, TIntermLoop *loop) override + { + // do-while loop doesn't have this bug. + if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile) + { + return true; + } + + // For loop may not have a condition. + if (loop->getCondition() == nullptr) + { + return true; + } + + // Constant true. + TConstantUnion *trueConstant = new TConstantUnion(); + trueConstant->setBConst(true); + TIntermTyped *trueValue = new TIntermConstantUnion(trueConstant, TType(EbtBool)); + + // CONDITION && true. + TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue); + loop->setCondition(andOp); + + return true; + } +}; + +} // anonymous namespace + +void AddAndTrueToLoopCondition(TIntermNode *root) +{ + AddAndTrueToLoopConditionTraverser traverser; + root->traverse(&traverser); +} + +} // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.h b/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.h new file mode 100644 index 00000000000..34debe0ed97 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Rewrite condition in for and while loops to work around driver bug on Intel Mac. + +#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ +#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ + +class TIntermNode; +namespace sh +{ + +void AddAndTrueToLoopCondition(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.cpp b/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.cpp new file mode 100644 index 00000000000..25493a50bec --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.cpp @@ -0,0 +1,77 @@ +// +// 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. +// +// AddDefaultReturnStatements.cpp: Add default return statements to functions that do not end in a +// return. +// + +#include "compiler/translator/AddDefaultReturnStatements.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/util.h" + +namespace sh +{ + +namespace +{ + +class AddDefaultReturnStatementsTraverser : private TIntermTraverser +{ + public: + static void Apply(TIntermNode *root) + { + AddDefaultReturnStatementsTraverser separateInit; + root->traverse(&separateInit); + separateInit.updateTree(); + } + + private: + AddDefaultReturnStatementsTraverser() : TIntermTraverser(true, false, false) {} + + static bool IsFunctionWithoutReturnStatement(TIntermAggregate *node, TType *returnType) + { + *returnType = node->getType(); + if (node->getOp() != EOpFunction || node->getType().getBasicType() == EbtVoid) + { + return false; + } + + TIntermAggregate *bodyNode = node->getSequence()->back()->getAsAggregate(); + ASSERT(bodyNode); + TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode(); + if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn) + { + return false; + } + + return true; + } + + bool visitAggregate(Visit, TIntermAggregate *node) override + { + TType returnType; + if (IsFunctionWithoutReturnStatement(node, &returnType)) + { + TIntermBranch *branch = + new TIntermBranch(EOpReturn, TIntermTyped::CreateZero(returnType)); + + TIntermAggregate *bodyNode = node->getSequence()->back()->getAsAggregate(); + bodyNode->getSequence()->push_back(branch); + + return false; + } + + return true; + } +}; +} // anonymous namespace + +void AddDefaultReturnStatements(TIntermNode *node) +{ + AddDefaultReturnStatementsTraverser::Apply(node); +} + +} // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.h b/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.h new file mode 100644 index 00000000000..d765a7ae4ab --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.h @@ -0,0 +1,22 @@ +// +// 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. +// +// AddDefaultReturnStatements.h: Add default return statements to functions that do not end in a +// return. +// + +#ifndef COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ +#define COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ + +class TIntermNode; + +namespace sh +{ + +void AddDefaultReturnStatements(TIntermNode *node); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/chromium/third_party/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp index 510ade84c1f..562d53d7b04 100644 --- a/chromium/third_party/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp @@ -103,7 +103,8 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter replacementParams->getSequence()->push_back(CreateReturnValueOutSymbol(node->getType())); replacementParams->setLine(params->getLine()); - mReplacements.push_back(NodeUpdateEntry(node, params, replacementParams, false)); + queueReplacementWithParent(node, params, replacementParams, + OriginalNode::IS_DROPPED); node->setType(TType(EbtVoid)); @@ -122,7 +123,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TInter replacement->setLine(node->getLine()); replacement->setType(TType(EbtVoid)); - mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacement, false)); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); } else if (node->getOp() == EOpFunctionCall) { @@ -166,12 +167,11 @@ 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); - replacementAssignment->setLeft(CreateReturnValueSymbol(expression->getType())); - replacementAssignment->setRight(node->getExpression()); - replacementAssignment->setType(expression->getType()); + TIntermSymbol *returnValueSymbol = CreateReturnValueSymbol(expression->getType()); + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, returnValueSymbol, expression); replacementAssignment->setLine(expression->getLine()); replacements.push_back(replacementAssignment); @@ -192,7 +192,7 @@ bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBi if (rightAgg != nullptr && rightAgg->getOp() == EOpFunctionCall && rightAgg->isUserDefined()) { TIntermAggregate *replacementCall = CreateReplacementCall(rightAgg, node->getLeft()); - mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, replacementCall, false)); + queueReplacement(node, replacementCall, OriginalNode::IS_DROPPED); } } return false; diff --git a/chromium/third_party/angle/src/compiler/translator/BaseTypes.h b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h index 69dd60f0d69..0919955f574 100644 --- a/chromium/third_party/angle/src/compiler/translator/BaseTypes.h +++ b/chromium/third_party/angle/src/compiler/translator/BaseTypes.h @@ -7,7 +7,11 @@ #ifndef COMPILER_TRANSLATOR_BASETYPES_H_ #define COMPILER_TRANSLATOR_BASETYPES_H_ +#include <algorithm> +#include <array> + #include "common/debug.h" +#include "GLSLANG/ShaderLang.h" // // Precision qualifiers @@ -337,19 +341,34 @@ enum TQualifier EvqLastFragData, // GLSL ES 3.0 vertex output and fragment input - EvqSmooth, // Incomplete qualifier, smooth is the default - EvqFlat, // Incomplete qualifier - EvqSmoothOut = EvqSmooth, - EvqFlatOut = EvqFlat, + EvqSmooth, // Incomplete qualifier, smooth is the default + EvqFlat, // Incomplete qualifier + EvqCentroid, // Incomplete qualifier + EvqSmoothOut, + EvqFlatOut, EvqCentroidOut, // Implies smooth EvqSmoothIn, EvqFlatIn, EvqCentroidIn, // Implies smooth + // GLSL ES 3.1 compute shader special variables + EvqComputeIn, + EvqNumWorkGroups, + EvqWorkGroupSize, + EvqWorkGroupID, + EvqLocalInvocationID, + EvqGlobalInvocationID, + EvqLocalInvocationIndex, + // end of list EvqLast }; +inline bool IsQualifierUnspecified(TQualifier qualifier) +{ + return (qualifier == EvqTemporary || qualifier == EvqGlobal); +} + enum TLayoutMatrixPacking { EmpUnspecified, @@ -368,26 +387,65 @@ enum TLayoutBlockStorage struct TLayoutQualifier { int location; + unsigned int locationsSpecified; TLayoutMatrixPacking matrixPacking; TLayoutBlockStorage blockStorage; + // Compute shader layout qualifiers. + sh::WorkGroupSize localSize; + static TLayoutQualifier create() { TLayoutQualifier layoutQualifier; layoutQualifier.location = -1; + layoutQualifier.locationsSpecified = 0; layoutQualifier.matrixPacking = EmpUnspecified; layoutQualifier.blockStorage = EbsUnspecified; + layoutQualifier.localSize.fill(-1); + return layoutQualifier; } bool isEmpty() const { - return location == -1 && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified; + return location == -1 && matrixPacking == EmpUnspecified && + blockStorage == EbsUnspecified && !localSize.isAnyValueSet(); + } + + bool isCombinationValid() const + { + bool workSizeSpecified = localSize.isAnyValueSet(); + bool otherLayoutQualifiersSpecified = + (location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified); + + // we can have either the work group size specified, or the other layout qualifiers + return !(workSizeSpecified && otherLayoutQualifiersSpecified); + } + + bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const + { + return localSize.isWorkGroupSizeMatching(localSizeIn); } }; +inline const char *getWorkGroupSizeString(size_t dimension) +{ + switch (dimension) + { + case 0u: + return "local_size_x"; + case 1u: + return "local_size_y"; + case 2u: + return "local_size_z"; + default: + UNREACHABLE(); + return "dimension out of bounds"; + } +} + // // This is just for debug print out, carried along with the definitions above. // @@ -427,11 +485,21 @@ inline const char* getQualifierString(TQualifier q) case EvqLastFragColor: return "LastFragColor"; case EvqLastFragData: return "LastFragData"; case EvqSmoothOut: return "smooth out"; - case EvqCentroidOut: return "centroid out"; + case EvqCentroidOut: return "smooth centroid out"; case EvqFlatOut: return "flat out"; case EvqSmoothIn: return "smooth in"; case EvqFlatIn: return "flat in"; - case EvqCentroidIn: return "centroid in"; + case EvqCentroidIn: return "smooth centroid in"; + case EvqCentroid: return "centroid"; + case EvqFlat: return "flat"; + case EvqSmooth: return "smooth"; + case EvqComputeIn: return "in"; + case EvqNumWorkGroups: return "NumWorkGroups"; + case EvqWorkGroupSize: return "WorkGroupSize"; + case EvqWorkGroupID: return "WorkGroupID"; + case EvqLocalInvocationID: return "LocalInvocationID"; + case EvqGlobalInvocationID: return "GlobalInvocationID"; + case EvqLocalInvocationIndex: return "LocalInvocationIndex"; default: UNREACHABLE(); return "unknown qualifier"; } // clang-format on @@ -465,10 +533,10 @@ inline const char* getInterpolationString(TQualifier q) switch(q) { case EvqSmoothOut: return "smooth"; break; - case EvqCentroidOut: return "centroid"; break; + case EvqCentroidOut: return "smooth centroid"; break; case EvqFlatOut: return "flat"; break; case EvqSmoothIn: return "smooth"; break; - case EvqCentroidIn: return "centroid"; break; + case EvqCentroidIn: return "smooth centroid"; break; case EvqFlatIn: return "flat"; break; default: UNREACHABLE(); return "unknown interpolation"; } diff --git a/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp b/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp new file mode 100644 index 00000000000..aada0fac7df --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp @@ -0,0 +1,106 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#include "BreakVariableAliasingInInnerLoops.h" + +#include "compiler/translator/IntermNode.h" + +// A HLSL compiler developer gave us more details on the root cause and the workaround needed: +// The root problem is that if the HLSL compiler is applying aliasing information even on +// incomplete simulations (in this case, a single pass). The bug is triggered by an assignment +// that comes from a series of assignments, possibly with swizzled or ternary operators with +// known conditionals, where the source is before the loop. +// So, a workaround is to add a +0 term to variables the first time they are assigned to in +// an inner loop (if they are declared in an outside scope, otherwise there is no need). +// This will break the aliasing chain. + +// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because +// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure +// assignment don't need a workaround. + +namespace +{ + +class AliasingBreaker : public TIntermTraverser +{ + public: + AliasingBreaker() : TIntermTraverser(true, false, true) {} + + protected: + bool visitBinary(Visit visit, TIntermBinary *binary) + { + if (visit != PreVisit) + { + return false; + } + + if (mLoopLevel < 2 || !binary->isAssignment()) + { + return true; + } + + TIntermTyped *B = binary->getRight(); + TType type = B->getType(); + + if (!type.isScalar() && !type.isVector() && !type.isMatrix()) + { + return true; + } + + if (type.isArray() || IsSampler(type.getBasicType())) + { + return true; + } + + // We have a scalar / vector / matrix assignment with loop depth 2. + // Transform it from + // A = B + // to + // A = (B + typeof<B>(0)); + + TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, TIntermTyped::CreateZero(type)); + bPlusZero->setLine(B->getLine()); + + binary->replaceChildNode(B, bPlusZero); + + return true; + } + + bool visitLoop(Visit visit, TIntermLoop *loop) + { + if (visit == PreVisit) + { + mLoopLevel++; + } + else + { + ASSERT(mLoopLevel > 0); + mLoopLevel--; + } + + return true; + } + + private: + int mLoopLevel = 0; +}; + +} // anonymous namespace + +namespace sh +{ + +void BreakVariableAliasingInInnerLoops(TIntermNode *root) +{ + AliasingBreaker breaker; + root->traverse(&breaker); +} + +} // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h b/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h new file mode 100644 index 00000000000..b1d906f9198 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend +// may record a variable as aliasing another. Sometimes the alias information gets garbled +// so we work around this issue by breaking the aliasing chain in inner loops. + +#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ +#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ + +class TIntermNode; + +namespace sh +{ + +void BreakVariableAliasingInInnerLoops(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp index 098560d1107..0c8e2d9cfc1 100644 --- a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp @@ -11,37 +11,96 @@ #include "compiler/translator/SymbolTable.h" #include "compiler/translator/VersionGLSL.h" -void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType) +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType) { - // we use macros here instead of function definitions to work around more GLSL - // compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are - // problematic because if the argument has side-effects they will be repeatedly - // evaluated. This is unlikely to show up in real shaders, but is something to - // consider. + 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; const TType *float1 = TCache::getType(EbtFloat); const TType *float2 = TCache::getType(EbtFloat, 2); const TType *float3 = TCache::getType(EbtFloat, 3); const TType *float4 = TCache::getType(EbtFloat, 4); - if (shaderType == GL_FRAGMENT_SHADER) - { - 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))"); + // !(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"); } // Emulate built-in functions missing from GLSL 1.30 and higher void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu, sh::GLenum shaderType, int targetGLSLVersion) { + // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10) + if (targetGLSLVersion < GLSL_VERSION_410) + { + const TType *float2 = TCache::getType(EbtFloat, 2); + const TType *uint1 = TCache::getType(EbtUInt); + + // clang-format off + emu->addEmulatedFunction(EOpPackUnorm2x16, float2, + "uint webgl_packUnorm2x16_emu(vec2 v)\n" + "{\n" + " int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n" + " int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n" + " return uint((y << 16) | (x & 0xFFFF));\n" + "}\n"); + + emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1, + "vec2 webgl_unpackUnorm2x16_emu(uint u)\n" + "{\n" + " float x = float(u & 0xFFFFu) / 65535.0;\n" + " float y = float(u >> 16) / 65535.0;\n" + " return vec2(x, y);\n" + "}\n"); + // clang-format on + } + // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20) // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30). if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420) @@ -155,7 +214,9 @@ void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator " float scale;\n" " if(exponent < 0)\n" " {\n" - " scale = 1.0 / (1 << -exponent);\n" + " // The negative unary operator is buggy on OSX.\n" + " // Work around this by using abs instead.\n" + " scale = 1.0 / (1 << abs(exponent));\n" " }\n" " else\n" " {\n" diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h index 56242598af5..2bc5f2c8801 100644 --- a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h @@ -12,9 +12,16 @@ class BuiltInFunctionEmulator; // -// This is only a workaround for OpenGL driver bugs, and isn't needed in general. +// This works around bug in Intel Mac drivers. // -void InitBuiltInFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, sh::GLenum shaderType); +void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + sh::GLenum shaderType); + +// +// This works around isnan() bug in Intel Mac drivers +// +void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); // // This function is emulating built-in functions missing from GLSL 1.30 and higher. diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp index 50e15cbc282..988f1e2bf5e 100644 --- a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp @@ -8,6 +8,59 @@ #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/VersionGLSL.h" + +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) { diff --git a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h index 4c45a93dc4f..f47449dfb26 100644 --- a/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h @@ -13,4 +13,10 @@ class BuiltInFunctionEmulator; void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu); +// +// This works around isnan() bug on some Intel drivers. +// +void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu, + int targetGLSLVersion); + #endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/CallDAG.cpp b/chromium/third_party/angle/src/compiler/translator/CallDAG.cpp index 10f0eb937c4..1c603ef8863 100644 --- a/chromium/third_party/angle/src/compiler/translator/CallDAG.cpp +++ b/chromium/third_party/angle/src/compiler/translator/CallDAG.cpp @@ -44,6 +44,7 @@ class CallDAG::CallDAGCreator : public TIntermTraverser skipped++; } } + ASSERT(mFunctions.size() == mCurrentIndex + skipped); return INITDAG_SUCCESS; } @@ -165,52 +166,102 @@ class CallDAG::CallDAGCreator : public TIntermTraverser } // Recursively assigns indices to a sub DAG - InitResult assignIndicesInternal(CreatorFunctionData *function) + InitResult assignIndicesInternal(CreatorFunctionData *root) { - ASSERT(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). - if (!function->node) - { - *mCreationInfo << "Undefined function '" << function->name - << ")' used in the following call chain:"; - return INITDAG_UNDEFINED; - } + ASSERT(root); - if (function->indexAssigned) + if (root->indexAssigned) { return INITDAG_SUCCESS; } - if (function->visiting) + // 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 (mCreationInfo) + CreatorFunctionData *function = functionsToProcess.back(); + + if (function->visiting) + { + function->visiting = false; + function->index = mCurrentIndex++; + function->indexAssigned = true; + + functionsToProcess.pop_back(); + continue; + } + + if (!function->node) { - *mCreationInfo << "Recursive function call in the following call chain:" << function->name; + *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; + } + } + + if (result != INITDAG_SUCCESS) + { + break; } - return INITDAG_RECURSION; } - function->visiting = true; - for (auto &callee : function->callees) + // The call chain is made of the function we were visiting when the error was detected. + if (result != INITDAG_SUCCESS) { - InitResult result = assignIndicesInternal(callee); - if (result != INITDAG_SUCCESS) + bool first = true; + for (auto function : functionsToProcess) { - // 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 (function->visiting) { - *mCreationInfo << " <- " << function->name << ")"; + if (!first) + { + *mCreationInfo << " -> "; + } + *mCreationInfo << function->name << ")"; + first = false; } - return result; } } - function->index = mCurrentIndex++; - function->indexAssigned = true; - - function->visiting = false; - return INITDAG_SUCCESS; + return result; } TInfoSinkBase *mCreationInfo; @@ -276,6 +327,8 @@ void CallDAG::clear() CallDAG::InitResult CallDAG::init(TIntermNode *root, TInfoSinkBase *info) { + ASSERT(info); + CallDAGCreator creator(info); // Creates the mapping of functions to callees diff --git a/chromium/third_party/angle/src/compiler/translator/Compiler.cpp b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp index 3c7742a68a0..547c09b1c46 100644 --- a/chromium/third_party/angle/src/compiler/translator/Compiler.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Compiler.cpp @@ -4,10 +4,18 @@ // found in the LICENSE file. // -#include "compiler/translator/Cache.h" #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/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" @@ -16,7 +24,6 @@ #include "compiler/translator/PruneEmptyDeclarations.h" #include "compiler/translator/RegenerateStructNames.h" #include "compiler/translator/RemovePow.h" -#include "compiler/translator/RenameFunction.h" #include "compiler/translator/RewriteDoWhile.h" #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" #include "compiler/translator/UnfoldShortCircuitAST.h" @@ -24,19 +31,49 @@ #include "compiler/translator/ValidateMaxParameters.h" #include "compiler/translator/ValidateOutputs.h" #include "compiler/translator/VariablePacker.h" -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/depgraph/DependencyGraphOutput.h" -#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" -#include "compiler/translator/timing/RestrictVertexShaderTiming.h" #include "third_party/compiler/ArrayBoundsClamper.h" -#include "angle_gl.h" -#include "common/utilities.h" + +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 bool IsWebGLBasedSpec(ShShaderSpec spec) { - return (spec == SH_WEBGL_SPEC || - spec == SH_CSS_SHADERS_SPEC || - spec == SH_WEBGL2_SPEC); + return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC); } bool IsGLSL130OrNewer(ShShaderOutput output) @@ -60,7 +97,6 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec) switch (spec) { case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: return 256; default: return 1024; @@ -111,11 +147,13 @@ int MapSpecToShaderVersion(ShShaderSpec spec) { case SH_GLES2_SPEC: case SH_WEBGL_SPEC: - case SH_CSS_SHADERS_SPEC: return 100; case SH_GLES3_SPEC: case SH_WEBGL2_SPEC: return 300; + case SH_GLES3_1_SPEC: + case SH_WEBGL3_SPEC: + return 310; default: UNREACHABLE(); return 0; @@ -137,7 +175,8 @@ TShHandleBase::~TShHandleBase() } TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) - : shaderType(type), + : variablesCollected(false), + shaderType(type), shaderSpec(spec), outputType(output), maxUniformVectors(0), @@ -148,15 +187,17 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), builtInFunctionEmulator(), mSourcePath(NULL), + mComputeShaderLocalSizeDeclared(false), mTemporaryIndex(0) { + mComputeShaderLocalSize.fill(1); } TCompiler::~TCompiler() { } -bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const +bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const { // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API, // validate loop and indexing as well (to verify that the shader only uses minimal functionality @@ -191,15 +232,16 @@ bool TCompiler::Init(const ShBuiltInResources& resources) return true; } -TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +TIntermNode *TCompiler::compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) { return compileTreeImpl(shaderStrings, numStrings, compileOptions); } TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], size_t numStrings, - const int compileOptions) + const ShCompileOptions compileOptions) { clearResults(); @@ -217,8 +259,7 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], ++firstSource; } - TIntermediate intermediate(infoSink); - TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, + TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec, compileOptions, true, infoSink, getResources()); parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh); @@ -246,13 +287,13 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], if (success) { mPragma = parseContext.pragma(); - if (mPragma.stdgl.invariantAll) - { - symbolTable.setGlobalInvariant(); - } + symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll); + + mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); + mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); root = parseContext.getTreeRoot(); - root = intermediate.postProcess(root); + root = TIntermediate::PostProcess(root); // Highp might have been auto-enabled based on shader version fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); @@ -289,11 +330,17 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], if (success && shouldRunLoopAndIndexingValidation(compileOptions)) success = validateLimitations(root); - if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) - success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); - - if (success && shaderSpec == SH_CSS_SHADERS_SPEC) - rewriteCSSShader(root); + // 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; + } + } // Unroll for-loop markup needs to happen after validateLimitations pass. if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) @@ -339,6 +386,9 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], 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; @@ -363,9 +413,10 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], infoSink.info << "too many uniforms"; } } - if (success && shaderType == GL_VERTEX_SHADER && - (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) - initializeVaryingsWithoutStaticUse(root); + if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES)) + { + initializeOutputVariables(root); + } } if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) @@ -381,6 +432,13 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], root->traverse(&gen); } + if (success && shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 && + compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 && + IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers")) + { + EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables); + } + if (success) { DeferGlobalInitializers(root); @@ -394,12 +452,26 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[], return NULL; } -bool TCompiler::compile(const char* const shaderStrings[], - size_t numStrings, int compileOptions) +bool TCompiler::compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions 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; + + // Apply key workarounds. + if (shouldFlattenPragmaStdglInvariantAll()) + { + // This should be harmless to do in all cases, but for the moment, do it only conditionally. + compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL; + } + TScopedPoolAllocator scopedAlloc(&allocator); TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); @@ -427,17 +499,16 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) symbolTable.push(); // COMMON_BUILTINS symbolTable.push(); // ESSL1_BUILTINS symbolTable.push(); // ESSL3_BUILTINS + symbolTable.push(); // ESSL3_1_BUILTINS TPublicType integer; - integer.type = EbtInt; - integer.primarySize = 1; - integer.secondarySize = 1; + integer.setBasicType(EbtInt); + integer.initializeSizeForScalarTypes(); integer.array = false; TPublicType floatingPoint; - floatingPoint.type = EbtFloat; - floatingPoint.primarySize = 1; - floatingPoint.secondarySize = 1; + floatingPoint.setBasicType(EbtFloat); + floatingPoint.initializeSizeForScalarTypes(); floatingPoint.array = false; switch(shaderType) @@ -449,6 +520,10 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 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"); } @@ -473,10 +548,9 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType) { ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd); TPublicType sampler; - sampler.primarySize = 1; - sampler.secondarySize = 1; + sampler.initializeSizeForScalarTypes(); + sampler.setBasicType(samplerType); sampler.array = false; - sampler.type = samplerType; symbolTable.setDefaultPrecision(sampler, EbpLow); } @@ -515,7 +589,31 @@ void TCompiler::setResourceString() << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers << ":NV_draw_buffers:" << compileResources.NV_draw_buffers - << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; + << ":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(); @@ -534,6 +632,7 @@ void TCompiler::clearResults() expandedUniforms.clear(); varyings.clear(); interfaceBlocks.clear(); + variablesCollected = false; builtInFunctionEmulator.Cleanup(); @@ -711,12 +810,6 @@ 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); @@ -724,36 +817,6 @@ 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); @@ -774,33 +837,18 @@ 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) { - sh::CollectVariables collect(&attributes, - &outputVariables, - &uniforms, - &varyings, - &interfaceBlocks, - hashFunction, - symbolTable); - root->traverse(&collect); + if (!variablesCollected) + { + sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings, + &interfaceBlocks, hashFunction, symbolTable, extensionBehavior); + root->traverse(&collect); - // This is for enforcePackingRestriction(). - sh::ExpandUniforms(uniforms, &expandedUniforms); + // This is for enforcePackingRestriction(). + sh::ExpandUniforms(uniforms, &expandedUniforms); + variablesCollected = true; + } } bool TCompiler::enforcePackingRestrictions() @@ -811,37 +859,32 @@ bool TCompiler::enforcePackingRestrictions() void TCompiler::initializeGLPosition(TIntermNode* root) { - InitializeVariables::InitVariableInfoList variables; - InitializeVariables::InitVariableInfo var( - "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); - variables.push_back(var); - InitializeVariables initializer(variables); - root->traverse(&initializer); + InitVariableList list; + sh::ShaderVariable var(GL_FLOAT_VEC4, 0); + var.name = "gl_Position"; + list.push_back(var); + InitializeVariables(root, list); } -void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) +void TCompiler::initializeOutputVariables(TIntermNode *root) { - InitializeVariables::InitVariableInfoList variables; - for (size_t ii = 0; ii < varyings.size(); ++ii) + InitVariableList list; + if (shaderType == GL_VERTEX_SHADER) { - const sh::Varying& varying = varyings[ii]; - if (varying.staticUse) - continue; - unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type)); - unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type)); - TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray()); - TString name = varying.name.c_str(); - if (varying.isArray()) + for (auto var : varyings) { - type.setArraySize(varying.arraySize); - name = name.substr(0, name.find_first_of('[')); + list.push_back(var); } - - InitializeVariables::InitVariableInfo var(name, type); - variables.push_back(var); } - InitializeVariables initializer(variables); - root->traverse(&initializer); + else + { + ASSERT(shaderType == GL_FRAGMENT_SHADER); + for (auto var : outputVariables) + { + list.push_back(var); + } + } + InitializeVariables(root, list); } const TExtensionBehavior& TCompiler::getExtensionBehavior() const @@ -874,9 +917,26 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const return builtInFunctionEmulator; } -void TCompiler::writePragma() +void TCompiler::writePragma(ShCompileOptions compileOptions) +{ + if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL)) + { + TInfoSinkBase &sink = infoSink.obj; + if (mPragma.stdgl.invariantAll) + sink << "#pragma STDGL invariant(all)\n"; + } +} + +bool TCompiler::isVaryingDefined(const char *varyingName) { - TInfoSinkBase &sink = infoSink.obj; - if (mPragma.stdgl.invariantAll) - sink << "#pragma STDGL invariant(all)\n"; + ASSERT(variablesCollected); + for (size_t ii = 0; ii < varyings.size(); ++ii) + { + if (varyings[ii].name == varyingName) + { + return true; + } + } + + return false; } diff --git a/chromium/third_party/angle/src/compiler/translator/Compiler.h b/chromium/third_party/angle/src/compiler/translator/Compiler.h index 99c155c33df..ace1abbaef6 100644 --- a/chromium/third_party/angle/src/compiler/translator/Compiler.h +++ b/chromium/third_party/angle/src/compiler/translator/Compiler.h @@ -25,14 +25,12 @@ #include "third_party/compiler/ArrayBoundsClamper.h" class TCompiler; -class TDependencyGraph; #ifdef ANGLE_ENABLE_HLSL class TranslatorHLSL; #endif // ANGLE_ENABLE_HLSL // -// Helper function to identify specs that are based on the WebGL spec, -// like the CSS Shaders spec. +// Helper function to identify specs that are based on the WebGL spec. // bool IsWebGLBasedSpec(ShShaderSpec spec); @@ -75,16 +73,21 @@ 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 NULL whenever there are compilation errors. - TIntermNode *compileTreeForTesting(const char* const shaderStrings[], - size_t numStrings, int compileOptions); + TIntermNode *compileTreeForTesting(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); - bool compile(const char* const shaderStrings[], - size_t numStrings, int compileOptions); + bool compile(const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions); // Get results of the last compilation. int getShaderVersion() const { return shaderVersion; } TInfoSink& getInfoSink() { return infoSink; } + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + const sh::WorkGroupSize &getComputeShaderLocalSize() { return mComputeShaderLocalSize; } + // Clears the results from the previous compilation. void clearResults(); @@ -101,7 +104,7 @@ class TCompiler : public TShHandleBase ShShaderOutput getOutputType() const { return outputType; } const std::string &getBuiltInResourcesString() const { return builtInResourcesString; } - bool shouldRunLoopAndIndexingValidation(int compileOptions) const; + bool shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const; // Get the resources set by InitBuiltInSymbolTable const ShBuiltInResources& getResources() const; @@ -116,61 +119,56 @@ 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, int compileOptions) {}; + virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions){}; // Translate to object code. - virtual void translate(TIntermNode *root, int compileOptions) = 0; + virtual void translate(TIntermNode *root, ShCompileOptions compileOptions) = 0; // Returns true if, after applying the packing rules in the GLSL 1.017 spec // Appendix A, section 7, the shader does not use too many uniforms. bool enforcePackingRestrictions(); - // Insert statements to initialize varyings without static use in the beginning - // of main(). It is to work around a Mac driver where such varyings in a vertex - // shader may be optimized out incorrectly at compile time, causing a link failure. - // This function should only be applied to vertex shaders. - void initializeVaryingsWithoutStaticUse(TIntermNode* root); + // Insert statements to initialize output variables in the beginning of main(). + // This is to avoid undefined behaviors. + void initializeOutputVariables(TIntermNode *root); // Insert gl_Position = vec4(0,0,0,0) to the beginning of main(). // It is to work around a Linux driver bug where missing this causes compile failure // while spec says it is allowed. // This function should only be applied to vertex shaders. void initializeGLPosition(TIntermNode* root); - // Returns true if the shader passes the restrictions that aim to prevent timing attacks. - bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph); - // Returns true if the shader does not use samplers. - bool enforceVertexShaderTimingRestrictions(TIntermNode* root); - // Returns true if the shader does not use sampler dependent values to affect control - // flow or in operations whose time can depend on the input values. - bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph); // Return true if the maximum expression complexity is below the limit. bool limitExpressionComplexity(TIntermNode* root); // Get built-in extensions with default behavior. const TExtensionBehavior& getExtensionBehavior() const; const char *getSourcePath() const; const TPragma& getPragma() const { return mPragma; } - void writePragma(); + void writePragma(ShCompileOptions compileOptions); unsigned int *getTemporaryIndex() { return &mTemporaryIndex; } + // Relies on collectVariables having been called. + bool isVaryingDefined(const char *varyingName); const ArrayBoundsClamper& getArrayBoundsClamper() const; ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const; + virtual bool shouldCollectVariables(ShCompileOptions compileOptions) + { + return (compileOptions & SH_VARIABLES) != 0; + } + + virtual bool shouldFlattenPragmaStdglInvariantAll() = 0; + 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; - - virtual bool shouldCollectVariables(int compileOptions) - { - return (compileOptions & SH_VARIABLES) != 0; - } + bool variablesCollected; private: // Creates the function call DAG for further analysis, returning false if there is a recursion @@ -187,7 +185,7 @@ class TCompiler : public TShHandleBase TIntermNode *compileTreeImpl(const char *const shaderStrings[], size_t numStrings, - const int compileOptions); + const ShCompileOptions compileOptions); sh::GLenum shaderType; ShShaderSpec shaderSpec; @@ -229,6 +227,10 @@ class TCompiler : public TShHandleBase TInfoSink infoSink; // Output sink. const char *mSourcePath; // Path of source file or NULL + // compute shader local group size + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + // name hashing. ShHashFunction64 hashFunction; NameMap nameMap; diff --git a/chromium/third_party/angle/src/compiler/translator/ConstantUnion.cpp b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.cpp new file mode 100644 index 00000000000..10a70f34ec8 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.cpp @@ -0,0 +1,590 @@ +// +// 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 +{ + +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 ((lhs.type == EbtInt && lhs.iConst < 0) || + (rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) || + (rhs.type == EbtUInt && rhs.uConst > 31)) + { + 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) + { + case EbtInt: + returnValue.setIConst(lhs.iConst >> rhs.iConst); + break; + case EbtUInt: + returnValue.setIConst(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; +} + +// 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 ((lhs.type == EbtInt && lhs.iConst < 0) || + (rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) || + (rhs.type == EbtUInt && rhs.uConst > 31)) + { + 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) + { + case EbtInt: + returnValue.setIConst(lhs.iConst << rhs.iConst); + break; + case EbtUInt: + returnValue.setIConst(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; +} diff --git a/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h index a86d27f3ff3..eec0f0ff97d 100644 --- a/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h +++ b/chromium/third_party/angle/src/compiler/translator/ConstantUnion.h @@ -9,77 +9,18 @@ #include <assert.h> +#include "compiler/translator/Common.h" #include "compiler/translator/BaseTypes.h" -class TConstantUnion { -public: - POOL_ALLOCATOR_NEW_DELETE(); - TConstantUnion() - { - iConst = 0; - type = EbtVoid; - } +class TDiagnostics; - bool cast(TBasicType newType, const TConstantUnion &constant) - { - switch (newType) - { - case EbtFloat: - switch (constant.type) - { - case EbtInt: setFConst(static_cast<float>(constant.getIConst())); break; - case EbtUInt: setFConst(static_cast<float>(constant.getUConst())); break; - case EbtBool: setFConst(static_cast<float>(constant.getBConst())); break; - case EbtFloat: setFConst(static_cast<float>(constant.getFConst())); break; - default: return false; - } - break; - case EbtInt: - switch (constant.type) - { - case EbtInt: setIConst(static_cast<int>(constant.getIConst())); break; - case EbtUInt: setIConst(static_cast<int>(constant.getUConst())); break; - case EbtBool: setIConst(static_cast<int>(constant.getBConst())); break; - case EbtFloat: setIConst(static_cast<int>(constant.getFConst())); break; - default: return false; - } - break; - case EbtUInt: - switch (constant.type) - { - case EbtInt: setUConst(static_cast<unsigned int>(constant.getIConst())); break; - case EbtUInt: setUConst(static_cast<unsigned int>(constant.getUConst())); break; - case EbtBool: setUConst(static_cast<unsigned int>(constant.getBConst())); break; - case EbtFloat: setUConst(static_cast<unsigned int>(constant.getFConst())); break; - default: return false; - } - break; - case EbtBool: - switch (constant.type) - { - case EbtInt: setBConst(constant.getIConst() != 0); break; - case EbtUInt: setBConst(constant.getUConst() != 0); break; - case EbtBool: setBConst(constant.getBConst()); break; - case EbtFloat: setBConst(constant.getFConst() != 0.0f); break; - default: return false; - } - break; - case EbtStruct: // Struct fields don't get cast - switch (constant.type) - { - case EbtInt: setIConst(constant.getIConst()); break; - case EbtUInt: setUConst(constant.getUConst()); break; - case EbtBool: setBConst(constant.getBConst()); break; - case EbtFloat: setFConst(constant.getFConst()); break; - default: return false; - } - break; - default: - return false; - } +class TConstantUnion +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TConstantUnion(); - return true; - } + bool cast(TBasicType newType, const TConstantUnion &constant); void setIConst(int i) {iConst = i; type = EbtInt; } void setUConst(unsigned int u) { uConst = u; type = EbtUInt; } @@ -91,256 +32,53 @@ public: float getFConst() const { return fConst; } bool getBConst() const { return bConst; } - bool operator==(const int i) const - { - return i == iConst; - } - - bool operator==(const unsigned int u) const - { - return u == uConst; - } - - bool operator==(const float f) const - { - return f == fConst; - } - - bool operator==(const bool b) const - { - return b == bConst; - } - - bool operator==(const TConstantUnion& constant) const - { - if (constant.type != type) - return false; - - switch (type) { - case EbtInt: - return constant.iConst == iConst; - case EbtUInt: - return constant.uConst == uConst; - case EbtFloat: - return constant.fConst == fConst; - case EbtBool: - return constant.bConst == bConst; - default: - return false; - } - } - - bool operator!=(const int i) const - { - return !operator==(i); - } - - bool operator!=(const unsigned int u) const - { - return !operator==(u); - } - - bool operator!=(const float f) const - { - return !operator==(f); - } - - bool operator!=(const bool b) const - { - return !operator==(b); - } - - bool operator!=(const TConstantUnion& constant) const - { - return !operator==(constant); - } - - bool operator>(const TConstantUnion& constant) const - { - assert(type == constant.type); - switch (type) { - case EbtInt: - return iConst > constant.iConst; - case EbtUInt: - return uConst > constant.uConst; - case EbtFloat: - return fConst > constant.fConst; - default: - return false; // Invalid operation, handled at semantic analysis - } - } - - bool operator<(const TConstantUnion& constant) const - { - assert(type == constant.type); - switch (type) { - case EbtInt: - return iConst < constant.iConst; - case EbtUInt: - return uConst < constant.uConst; - case EbtFloat: - return fConst < constant.fConst; - default: - return false; // Invalid operation, handled at semantic analysis - } - } - - TConstantUnion operator+(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator-(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator*(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break; - case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator%(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator>>(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator<<(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - // The signedness of the second parameter might be different, but we - // don't care, since the result is undefined if the second parameter is - // negative, and aliasing should not be a problem with unions. - assert(constant.type == EbtInt || constant.type == EbtUInt); - switch (type) { - case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator&(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(constant.type == EbtInt || constant.type == EbtUInt); - switch (type) { - case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator|(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator^(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; - case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator&&(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } - - TConstantUnion operator||(const TConstantUnion& constant) const - { - TConstantUnion returnValue; - assert(type == constant.type); - switch (type) { - case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; - default: assert(false && "Default missing"); - } - - return returnValue; - } + bool operator==(const int i) const; + bool operator==(const unsigned int u) const; + bool operator==(const float f) const; + bool operator==(const bool b) const; + bool operator==(const TConstantUnion &constant) const; + bool operator!=(const int i) const; + bool operator!=(const unsigned int u) const; + bool operator!=(const float f) const; + bool operator!=(const bool b) const; + bool operator!=(const TConstantUnion &constant) const; + bool operator>(const TConstantUnion &constant) const; + bool operator<(const TConstantUnion &constant) const; + static TConstantUnion add(const TConstantUnion &lhs, + const TConstantUnion &rhs, + TDiagnostics *diag, + 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; 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; }; diff --git a/chromium/third_party/angle/src/compiler/translator/DeferGlobalInitializers.cpp b/chromium/third_party/angle/src/compiler/translator/DeferGlobalInitializers.cpp index 6904f9401a1..285aa183b0a 100644 --- a/chromium/third_party/angle/src/compiler/translator/DeferGlobalInitializers.cpp +++ b/chromium/third_party/angle/src/compiler/translator/DeferGlobalInitializers.cpp @@ -101,10 +101,8 @@ 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); - deferredInit->setLeft(symbolNode->deepCopy()); - deferredInit->setRight(node->getRight()); - deferredInit->setType(node->getType()); + TIntermBinary *deferredInit = + new TIntermBinary(EOpAssign, symbolNode->deepCopy(), node->getRight()); mDeferredInitializers.push_back(deferredInit); // Change const global to a regular global if its initialization is deferred. @@ -130,7 +128,7 @@ bool DeferGlobalInitializersTraverser::visitBinary(Visit visit, TIntermBinary *n ASSERT(symbolNode->getQualifier() == EvqGlobal); } // Remove the initializer from the global scope and just declare the global instead. - mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, symbolNode, false)); + queueReplacement(node, symbolNode, OriginalNode::IS_DROPPED); } } return false; diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp index 593137fb0ae..6ba4679c459 100644 --- a/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp @@ -7,8 +7,9 @@ #include "compiler/translator/Diagnostics.h" #include "common/debug.h" -#include "compiler/translator/InfoSink.h" #include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/Common.h" +#include "compiler/translator/InfoSink.h" TDiagnostics::TDiagnostics(TInfoSink& infoSink) : mInfoSink(infoSink), @@ -50,6 +51,28 @@ void TDiagnostics::writeInfo(Severity severity, sink << "'" << token << "' : " << reason << " " << extra << "\n"; } +void TDiagnostics::error(const TSourceLoc &loc, + const char *reason, + const char *token, + const char *extraInfo) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo); +} + +void TDiagnostics::warning(const TSourceLoc &loc, + const char *reason, + const char *token, + const char *extraInfo) +{ + pp::SourceLocation srcLoc; + srcLoc.file = loc.first_file; + srcLoc.line = loc.first_line; + writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo); +} + void TDiagnostics::print(ID id, const pp::SourceLocation& loc, const std::string& text) diff --git a/chromium/third_party/angle/src/compiler/translator/Diagnostics.h b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h index bc26e4584fa..bb521da1a2a 100644 --- a/chromium/third_party/angle/src/compiler/translator/Diagnostics.h +++ b/chromium/third_party/angle/src/compiler/translator/Diagnostics.h @@ -11,6 +11,7 @@ #include "compiler/preprocessor/DiagnosticsBase.h" class TInfoSink; +struct TSourceLoc; class TDiagnostics : public pp::Diagnostics, angle::NonCopyable { @@ -29,6 +30,12 @@ class TDiagnostics : public pp::Diagnostics, angle::NonCopyable const std::string& token, const std::string& extra); + void error(const TSourceLoc &loc, const char *reason, const char *token, const char *extraInfo); + void warning(const TSourceLoc &loc, + const char *reason, + const char *token, + const char *extraInfo); + protected: void print(ID id, const pp::SourceLocation &loc, const std::string &text) override; diff --git a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp index ff8a69efa52..f8081ecd659 100644 --- a/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp @@ -182,8 +182,7 @@ void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc, int version) { - if (version == 100 || - version == 300) + if (version == 100 || version == 300 || version == 310) { mShaderVersion = version; } diff --git a/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp new file mode 100644 index 00000000000..431a326a5af --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp @@ -0,0 +1,141 @@ +// +// Copyright (c) 2002-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. +// +// gl_FragColor needs to broadcast to all color buffers in ES2 if +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// +// We emulate this by replacing all gl_FragColor with gl_FragData[0], and in the end +// of main() function, assigning gl_FragData[1], ..., gl_FragData[maxDrawBuffers-1] +// with gl_FragData[0]. +// + +#include "compiler/translator/EmulateGLFragColorBroadcast.h" +#include "compiler/translator/IntermNode.h" + +namespace +{ + +class GLFragColorBroadcastTraverser : public TIntermTraverser +{ + public: + GLFragColorBroadcastTraverser(int maxDrawBuffers) + : TIntermTraverser(true, false, false), + mMainSequence(nullptr), + mGLFragColorUsed(false), + mMaxDrawBuffers(maxDrawBuffers) + { + } + + void broadcastGLFragColor(); + + bool isGLFragColorUsed() const { return mGLFragColorUsed; } + + protected: + void visitSymbol(TIntermSymbol *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + + TIntermBinary *constructGLFragDataNode(int index) const; + TIntermBinary *constructGLFragDataAssignNode(int index) const; + + private: + TIntermSequence *mMainSequence; + bool mGLFragColorUsed; + int mMaxDrawBuffers; +}; + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const +{ + TType gl_FragDataType = TType(EbtFloat, EbpMedium, EvqFragData, 4); + gl_FragDataType.setArraySize(mMaxDrawBuffers); + + TIntermSymbol *symbol = new TIntermSymbol(0, "gl_FragData", gl_FragDataType); + TIntermTyped *indexNode = TIntermTyped::CreateIndexNode(index); + + TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode); + return binary; +} + +TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const +{ + TIntermTyped *fragDataIndex = constructGLFragDataNode(index); + TIntermTyped *fragDataZero = constructGLFragDataNode(0); + + return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero); +} + +void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node) +{ + if (node->getSymbol() == "gl_FragColor") + { + queueReplacement(node, constructGLFragDataNode(0), OriginalNode::IS_DROPPED); + mGLFragColorUsed = true; + } +} + +bool GLFragColorBroadcastTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + switch (node->getOp()) + { + case EOpFunction: + // Function definition. + ASSERT(visit == PreVisit); + if (node->getName() == "main(") + { + TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 2); + TIntermAggregate *body = (*sequence)[1]->getAsAggregate(); + ASSERT(body); + mMainSequence = body->getSequence(); + } + break; + default: + break; + } + return true; +} + +void GLFragColorBroadcastTraverser::broadcastGLFragColor() +{ + ASSERT(mMaxDrawBuffers > 1); + if (!mGLFragColorUsed) + { + return; + } + ASSERT(mMainSequence); + // Now insert statements + // gl_FragData[1] = gl_FragData[0]; + // ... + // gl_FragData[maxDrawBuffers - 1] = gl_FragData[0]; + for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex) + { + mMainSequence->insert(mMainSequence->end(), constructGLFragDataAssignNode(colorIndex)); + } +} + +} // namespace anonymous + +void EmulateGLFragColorBroadcast(TIntermNode *root, + int maxDrawBuffers, + std::vector<sh::OutputVariable> *outputVariables) +{ + ASSERT(maxDrawBuffers > 1); + GLFragColorBroadcastTraverser traverser(maxDrawBuffers); + root->traverse(&traverser); + if (traverser.isGLFragColorUsed()) + { + traverser.updateTree(); + traverser.broadcastGLFragColor(); + for (auto &var : *outputVariables) + { + if (var.name == "gl_FragColor") + { + // TODO(zmo): Find a way to keep the original variable information. + var.name = "gl_FragData"; + var.mappedName = "gl_FragData"; + var.arraySize = maxDrawBuffers; + } + } + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h b/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h new file mode 100644 index 00000000000..627c4c67fe9 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h @@ -0,0 +1,29 @@ +// +// Copyright (c) 2002-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. +// +// Emulate gl_FragColor broadcast behaviors in ES2 where +// GL_EXT_draw_buffers is explicitly enabled in a fragment shader. +// + +#ifndef COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ +#define COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ + +#include <vector> + +namespace sh +{ +struct OutputVariable; +} + +class TIntermNode; + +// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function, +// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0]. +// If gl_FragColor is in outputVariables, it is replaced by gl_FragData. +void EmulateGLFragColorBroadcast(TIntermNode *root, + int maxDrawBuffers, + std::vector<sh::OutputVariable> *outputVariables); + +#endif // COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.cpp b/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.cpp index 4a7fa541558..a3025f07afe 100644 --- a/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.cpp +++ b/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.cpp @@ -6,88 +6,203 @@ #include "compiler/translator/EmulatePrecision.h" +#include <memory> + namespace { -static void writeVectorPrecisionEmulationHelpers( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size) +class RoundingHelperWriter : angle::NonCopyable { - std::stringstream vecTypeStrStr; - if (outputLanguage == SH_ESSL_OUTPUT) - vecTypeStrStr << "highp "; - vecTypeStrStr << "vec" << size; - std::string vecType = vecTypeStrStr.str(); - - sink << - vecType << " angle_frm(in " << vecType << " v) {\n" - " v = clamp(v, -65504.0, 65504.0);\n" - " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" - " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" - " v = v * exp2(-exponent);\n" - " v = sign(v) * floor(abs(v));\n" - " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" - "}\n"; - - sink << - vecType << " angle_frl(in " << vecType << " v) {\n" - " v = clamp(v, -2.0, 2.0);\n" - " v = v * 256.0;\n" - " v = sign(v) * floor(abs(v));\n" - " return v * 0.00390625;\n" - "}\n"; -} + public: + static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage); + + void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion); + void writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr); + + virtual ~RoundingHelperWriter() {} + + protected: + RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {} + RoundingHelperWriter() = delete; + + const ShShaderOutput mOutputLanguage; + + private: + virtual std::string getTypeString(const char *glslType) = 0; + virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0; + virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0; + virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) = 0; +}; + +class RoundingHelperWriterGLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) + { + } -static void writeMatrixPrecisionEmulationHelper( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size, const char *functionName) + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL { - std::stringstream matTypeStrStr; - if (outputLanguage == SH_ESSL_OUTPUT) - matTypeStrStr << "highp "; - matTypeStrStr << "mat" << size; - std::string matType = matTypeStrStr.str(); + public: + RoundingHelperWriterESSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriterGLSL(outputLanguage) + { + } - sink << matType << " " << functionName << "(in " << matType << " m) {\n" - " " << matType << " rounded;\n"; + private: + std::string getTypeString(const char *glslType) override; +}; - for (unsigned int i = 0; i < size; ++i) +class RoundingHelperWriterHLSL : public RoundingHelperWriter +{ + public: + RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage) + : RoundingHelperWriter(outputLanguage) { - sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; } - sink << " return rounded;\n" - "}\n"; + private: + std::string getTypeString(const char *glslType) override; + void writeFloatRoundingHelpers(TInfoSinkBase &sink) override; + void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override; + void writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) override; +}; + +RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage) +{ + ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage)); + switch (outputLanguage) + { + case SH_HLSL_4_1_OUTPUT: + return new RoundingHelperWriterHLSL(outputLanguage); + case SH_ESSL_OUTPUT: + return new RoundingHelperWriterESSL(outputLanguage); + default: + return new RoundingHelperWriterGLSL(outputLanguage); + } } -static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion) { // Write the angle_frm functions that round floating point numbers to // half precision, and angle_frl functions that round them to minimum lowp // precision. + writeFloatRoundingHelpers(sink); + writeVectorRoundingHelpers(sink, 2); + writeVectorRoundingHelpers(sink, 3); + writeVectorRoundingHelpers(sink, 4); + if (shaderVersion > 100) + { + for (unsigned int columns = 2; columns <= 4; ++columns) + { + for (unsigned int rows = 2; rows <= 4; ++rows) + { + writeMatrixRoundingHelper(sink, columns, rows, "angle_frm"); + writeMatrixRoundingHelper(sink, columns, rows, "angle_frl"); + } + } + } + else + { + for (unsigned int size = 2; size <= 4; ++size) + { + writeMatrixRoundingHelper(sink, size, size, "angle_frm"); + writeMatrixRoundingHelper(sink, size, size, "angle_frl"); + } + } +} + +void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink, + const char *lType, + const char *rType, + const char *opStr, + const char *opNameStr) +{ + std::string lTypeStr = getTypeString(lType); + std::string rTypeStr = getTypeString(rType); + + // Note that y should be passed through angle_frm at the function call site, + // but x can't be passed through angle_frm there since it is an inout parameter. + // So only pass x and the result through angle_frm here. + // clang-format off + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frm(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frl(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + // clang-format on +} + +std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType) +{ + return glslType; +} + +std::string RoundingHelperWriterESSL::getTypeString(const char *glslType) +{ + std::stringstream typeStrStr; + typeStrStr << "highp " << glslType; + return typeStrStr.str(); +} + +void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ // Unoptimized version of angle_frm for single floats: // - // int webgl_maxNormalExponent(in int exponentBits) { + // int webgl_maxNormalExponent(in int exponentBits) + // { // int possibleExponents = int(exp2(float(exponentBits))); // int exponentBias = possibleExponents / 2 - 1; // int allExponentBitsOne = possibleExponents - 1; // return (allExponentBitsOne - 1) - exponentBias; // } // - // float angle_frm(in float x) { + // float angle_frm(in float x) + // { // int mantissaBits = 10; // int exponentBits = 5; // float possibleMantissas = exp2(float(mantissaBits)); // float mantissaMax = 2.0 - 1.0 / possibleMantissas; // int maxNE = webgl_maxNormalExponent(exponentBits); // float max = exp2(float(maxNE)) * mantissaMax; - // if (x > max) { + // if (x > max) + // { // return max; // } - // if (x < -max) { + // if (x < -max) + // { // return -max; // } // float exponent = floor(log2(abs(x))); - // if (abs(x) == 0.0 || exponent < -float(maxNE)) { + // if (abs(x) == 0.0 || exponent < -float(maxNE)) + // { // return 0.0 * sign(x) // } // x = x * exp2(-(exponent - float(mantissaBits))); @@ -109,130 +224,204 @@ static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOu // numbers will be flushed to zero either way (2^-15 is the smallest // normal positive number), this does not introduce any error. - std::string floatType = "float"; - if (outputLanguage == SH_ESSL_OUTPUT) - floatType = "highp float"; + std::string floatType = getTypeString("float"); + // clang-format off sink << - floatType << " angle_frm(in " << floatType << " x) {\n" - " x = clamp(x, -65504.0, 65504.0);\n" - " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" - " bool isNonZero = (exponent >= -25.0);\n" - " x = x * exp2(-exponent);\n" - " x = sign(x) * floor(abs(x));\n" - " return x * exp2(exponent) * float(isNonZero);\n" - "}\n"; + floatType << " angle_frm(in " << floatType << " x) {\n" + " x = clamp(x, -65504.0, 65504.0);\n" + " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" + " bool isNonZero = (exponent >= -25.0);\n" + " x = x * exp2(-exponent);\n" + " x = sign(x) * floor(abs(x));\n" + " return x * exp2(exponent) * float(isNonZero);\n" + "}\n"; sink << - floatType << " angle_frl(in " << floatType << " x) {\n" - " x = clamp(x, -2.0, 2.0);\n" - " x = x * 256.0;\n" - " x = sign(x) * floor(abs(x));\n" - " return x * 0.00390625;\n" - "}\n"; - - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 2); - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 3); - writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 4); - for (unsigned int size = 2; size <= 4; ++size) + floatType << " angle_frl(in " << floatType << " x) {\n" + " x = clamp(x, -2.0, 2.0);\n" + " x = x * 256.0;\n" + " x = sign(x) * floor(abs(x));\n" + " return x * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr; + vecTypeStrStr << "vec" << size; + std::string vecType = getTypeString(vecTypeStrStr.str().c_str()); + + // clang-format off + sink << + vecType << " angle_frm(in " << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" + "}\n"; + + sink << + vecType << " angle_frl(in " << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on +} + +void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) +{ + std::stringstream matTypeStrStr; + matTypeStrStr << "mat" << columns; + if (rows != columns) { - writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frm"); - writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frl"); + matTypeStrStr << "x" << rows; } + std::string matType = getTypeString(matTypeStrStr.str().c_str()); + + sink << matType << " " << functionName << "(in " << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; + } + + sink << " return rounded;\n" + "}\n"; } -static void writeCompoundAssignmentPrecisionEmulation( - TInfoSinkBase& sink, ShShaderOutput outputLanguage, - const char *lType, const char *rType, const char *opStr, const char *opNameStr) +static const char *GetHLSLTypeStr(const char *floatTypeStr) { - std::string lTypeStr = lType; - std::string rTypeStr = rType; - if (outputLanguage == SH_ESSL_OUTPUT) + if (strcmp(floatTypeStr, "float") == 0) { - std::stringstream lTypeStrStr; - lTypeStrStr << "highp " << lType; - lTypeStr = lTypeStrStr.str(); - std::stringstream rTypeStrStr; - rTypeStrStr << "highp " << rType; - rTypeStr = rTypeStrStr.str(); + return "float"; + } + if (strcmp(floatTypeStr, "vec2") == 0) + { + return "float2"; + } + if (strcmp(floatTypeStr, "vec3") == 0) + { + return "float3"; + } + if (strcmp(floatTypeStr, "vec4") == 0) + { + return "float4"; + } + if (strcmp(floatTypeStr, "mat2") == 0) + { + return "float2x2"; + } + if (strcmp(floatTypeStr, "mat3") == 0) + { + return "float3x3"; + } + if (strcmp(floatTypeStr, "mat4") == 0) + { + return "float4x4"; + } + if (strcmp(floatTypeStr, "mat2x3") == 0) + { + return "float2x3"; + } + if (strcmp(floatTypeStr, "mat2x4") == 0) + { + return "float2x4"; + } + if (strcmp(floatTypeStr, "mat3x2") == 0) + { + return "float3x2"; } + if (strcmp(floatTypeStr, "mat3x4") == 0) + { + return "float3x4"; + } + if (strcmp(floatTypeStr, "mat4x2") == 0) + { + return "float4x2"; + } + if (strcmp(floatTypeStr, "mat4x3") == 0) + { + return "float4x3"; + } + UNREACHABLE(); + return nullptr; +} - // Note that y should be passed through angle_frm at the function call site, - // but x can't be passed through angle_frm there since it is an inout parameter. - // So only pass x and the result through angle_frm here. +std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType) +{ + return GetHLSLTypeStr(glslType); +} + +void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink) +{ + // In HLSL scalars are the same as 1-vectors. + writeVectorRoundingHelpers(sink, 1); +} + +void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink, + const unsigned int size) +{ + std::stringstream vecTypeStrStr; + vecTypeStrStr << "float" << size; + std::string vecType = vecTypeStrStr.str(); + + // clang-format off sink << - lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" - " x = angle_frm(angle_frm(x) " << opStr << " y);\n" - " return x;\n" - "}\n"; + vecType << " angle_frm(" << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bool" << size << " isNonZero = exponent < -25.0;\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * (float" << size << ")(isNonZero);\n" + "}\n"; + sink << - lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" - " x = angle_frl(angle_frm(x) " << opStr << " y);\n" - " return x;\n" - "}\n"; + vecType << " angle_frl(" << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; + // clang-format on } -const char *getFloatTypeStr(const TType& type) +void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink, + const unsigned int columns, + const unsigned int rows, + const char *functionName) { - switch (type.getNominalSize()) + std::stringstream matTypeStrStr; + matTypeStrStr << "float" << columns << "x" << rows; + std::string matType = matTypeStrStr.str(); + + sink << matType << " " << functionName << "(" << matType << " m) {\n" + << " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < columns; ++i) { - case 1: - return "float"; - case 2: - switch(type.getSecondarySize()) - { - case 1: - return "vec2"; - case 2: - return "mat2"; - case 3: - return "mat2x3"; - case 4: - return "mat2x4"; - default: - UNREACHABLE(); - return NULL; - } - case 3: - switch(type.getSecondarySize()) - { - case 1: - return "vec3"; - case 2: - return "mat3x2"; - case 3: - return "mat3"; - case 4: - return "mat3x4"; - default: - UNREACHABLE(); - return NULL; - } - case 4: - switch(type.getSecondarySize()) - { - case 1: - return "vec4"; - case 2: - return "mat4x2"; - case 3: - return "mat4x3"; - case 4: - return "mat4"; - default: - UNREACHABLE(); - return NULL; - } - default: - UNREACHABLE(); - return NULL; + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; } + + sink << " return rounded;\n" + "}\n"; } bool canRoundFloat(const TType &type) { - return type.getBasicType() == EbtFloat && !type.isNonSquareMatrix() && !type.isArray() && - (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); + return type.getBasicType() == EbtFloat && !type.isArray() && + (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); } TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child) @@ -253,7 +442,9 @@ TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild) roundFunctionName = "angle_frm"; else roundFunctionName = "angle_frl"; - return createInternalFunctionCallNode(roundFunctionName, roundedChild); + TIntermAggregate *callNode = createInternalFunctionCallNode(roundFunctionName, roundedChild); + callNode->setType(roundedChild->getType()); + return callNode; } TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr) @@ -302,9 +493,8 @@ void EmulatePrecision::visitSymbol(TIntermSymbol *node) { if (canRoundFloat(node->getType()) && !mDeclaringVariables && !isLValueRequiredHere()) { - TIntermNode *parent = getParentNode(); TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD); } } @@ -319,7 +509,7 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) if (op == EOpInitialize && visit == InVisit) mDeclaringVariables = false; - if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && visit == InVisit) + if ((op == EOpIndexDirectStruct) && visit == InVisit) visitChildren = false; if (visit != PreVisit) @@ -350,26 +540,30 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) break; } TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD); break; } // Compound assignment cases need to replace the operator with a function call. case EOpAddAssign: { - mEmulateCompoundAdd.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "add"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; + mEmulateCompoundAdd.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "add"); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); + break; } case EOpSubAssign: { - mEmulateCompoundSub.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "sub"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; + mEmulateCompoundSub.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "sub"); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); + break; } case EOpMulAssign: case EOpVectorTimesMatrixAssign: @@ -377,19 +571,23 @@ bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: { - mEmulateCompoundMul.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "mul"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; + mEmulateCompoundMul.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "mul"); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); + break; } case EOpDivAssign: { - mEmulateCompoundDiv.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); - TIntermNode *parent = getParentNode(); - TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "div"); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); - break; + mEmulateCompoundDiv.insert( + TypePair(type.getBuiltInTypeNameString(), + node->getRight()->getType().getBuiltInTypeNameString())); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( + node->getLeft(), node->getRight(), "div"); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); + break; } default: // The rest of the binary operations should not need precision emulation. @@ -444,7 +642,7 @@ bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) parentUsesResult(parent, node)) { TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD); } } break; @@ -454,7 +652,7 @@ bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node)) { TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD); } break; } @@ -476,9 +674,8 @@ bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) default: if (canRoundFloat(node->getType()) && visit == PreVisit) { - TIntermNode *parent = getParentNode(); TIntermNode *replacement = createRoundingFunctionCallNode(node); - mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + queueReplacement(node, replacement, OriginalNode::BECOMES_CHILD); } break; } @@ -486,22 +683,37 @@ bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) return true; } -void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage) { - // Other languages not yet supported - ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || - IsGLSL130OrNewer(outputLanguage) || - outputLanguage == SH_ESSL_OUTPUT); - writeCommonPrecisionEmulationHelpers(sink, outputLanguage); + std::unique_ptr<RoundingHelperWriter> roundingHelperWriter( + RoundingHelperWriter::createHelperWriter(outputLanguage)); + + roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion); EmulationSet::const_iterator it; for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "+", "add"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add"); for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "-", "sub"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub"); for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "/", "div"); + roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div"); for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++) - writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "*", "mul"); + 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 || + IsGLSL130OrNewer(outputLanguage)); + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.h b/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.h index 08177b3414f..f23e40be7f5 100644 --- a/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.h +++ b/chromium/third_party/angle/src/compiler/translator/EmulatePrecision.h @@ -28,7 +28,11 @@ class EmulatePrecision : public TLValueTrackingTraverser bool visitUnary(Visit visit, TIntermUnary *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override; - void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage); + void writeEmulationHelpers(TInfoSinkBase &sink, + const int shaderVersion, + const ShShaderOutput outputLanguage); + + static bool SupportedInLanguage(const ShShaderOutput outputLanguage); private: struct TypePair diff --git a/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp b/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp new file mode 100644 index 00000000000..9409c010f14 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp @@ -0,0 +1,154 @@ +// +// 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. +// +// Implementation of the integer pow expressions HLSL bug workaround. +// See header for more info. + +#include "compiler/translator/ExpandIntegerPowExpressions.h" + +#include <cmath> +#include <cstdlib> + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, unsigned int *tempIndex); + + private: + Traverser(); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root, unsigned int *tempIndex) +{ + Traverser traverser; + traverser.useTemporaryIndex(tempIndex); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) +{ +} + +void Traverser::nextIteration() +{ + mFound = false; + nextTemporaryIndex(); +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Test 0: skip non-pow operators. + if (node->getOp() != EOpPow) + { + return true; + } + + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 2u); + const TIntermConstantUnion *constantNode = sequence->at(1)->getAsConstantUnion(); + + // Test 1: check for a single constant. + if (!constantNode || constantNode->getNominalSize() != 1) + { + return true; + } + + const TConstantUnion *constant = constantNode->getUnionArrayPointer(); + + TConstantUnion asFloat; + asFloat.cast(EbtFloat, *constant); + + float value = asFloat.getFConst(); + + // Test 2: value is in the problematic range. + if (value < -5.0f || value > 9.0f) + { + return true; + } + + // Test 3: value is integer or pretty close to an integer. + float absval = std::abs(value); + float frac = absval - std::round(absval); + if (frac > 0.0001f) + { + return true; + } + + // Test 4: skip -1, 0, and 1 + int exponent = static_cast<int>(value); + int n = std::abs(exponent); + if (n < 2) + { + return true; + } + + // Potential problem case detected, apply workaround. + nextTemporaryIndex(); + + TIntermTyped *lhs = sequence->at(0)->getAsTyped(); + ASSERT(lhs); + + TIntermAggregate *init = createTempInitDeclaration(lhs); + TIntermTyped *current = createTempSymbol(lhs->getType()); + + insertStatementInParentBlock(init); + + // Create a chain of n-1 multiples. + for (int i = 1; i < n; ++i) + { + TIntermBinary *mul = new TIntermBinary(EOpMul, current, createTempSymbol(lhs->getType())); + mul->setLine(node->getLine()); + current = mul; + } + + // For negative pow, compute the reciprocal of the positive pow. + if (exponent < 0) + { + TConstantUnion *oneVal = new TConstantUnion(); + oneVal->setFConst(1.0f); + TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType()); + TIntermBinary *div = new TIntermBinary(EOpDiv, oneNode, current); + current = div; + } + + queueReplacement(node, current, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void ExpandIntegerPowExpressions(TIntermNode *root, unsigned int *tempIndex) +{ + Traverser::Apply(root, tempIndex); +} + +} // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.h b/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.h new file mode 100644 index 00000000000..8bc8c9664ed --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.h @@ -0,0 +1,28 @@ +// +// 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. +// +// This mutating tree traversal works around a bug in the HLSL compiler optimizer with "pow" that +// manifests under the following conditions: +// +// - If pow() has a literal exponent value +// - ... and this value is integer or within 10e-6 of an integer +// - ... and it is in {-4, -3, -2, 2, 3, 4, 5, 6, 7, 8} +// +// The workaround is to replace the pow with a series of multiplies. +// See http://anglebug.com/851 + +#ifndef COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ +#define COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ + +class TIntermNode; + +namespace sh +{ + +void ExpandIntegerPowExpressions(TIntermNode *root, unsigned int *tempIndex); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/Initialize.cpp b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp index b45e47ba992..759834f8575 100644 --- a/chromium/third_party/angle/src/compiler/translator/Initialize.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Initialize.cpp @@ -495,30 +495,85 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR // // Implementation dependent built-in constants. // - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", resources.MaxTextureImageUnits); - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors); - - symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors); - - if (spec != SH_CSS_SHADERS_SPEC) + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexAttribs", resources.MaxVertexAttribs, + EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexUniformVectors", + resources.MaxVertexUniformVectors, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxVertexTextureImageUnits", + resources.MaxVertexTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxCombinedTextureImageUnits", + resources.MaxCombinedTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxTextureImageUnits", + resources.MaxTextureImageUnits, EbpMedium); + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxFragmentUniformVectors", + resources.MaxFragmentUniformVectors, EbpMedium); + + symbolTable.insertConstInt(ESSL1_BUILTINS, "gl_MaxVaryingVectors", resources.MaxVaryingVectors, + EbpMedium); + + symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers, + EbpMedium); + if (resources.EXT_blend_func_extended) { - symbolTable.insertConstInt(COMMON_BUILTINS, "gl_MaxDrawBuffers", resources.MaxDrawBuffers); - if (resources.EXT_blend_func_extended) - { - symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended", - "gl_MaxDualSourceDrawBuffersEXT", - resources.MaxDualSourceDrawBuffers); - } + symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended", + "gl_MaxDualSourceDrawBuffersEXT", + resources.MaxDualSourceDrawBuffers); } - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", resources.MaxVertexOutputVectors); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", resources.MaxFragmentInputVectors); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", resources.MinProgramTexelOffset); - symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", resources.MaxProgramTexelOffset); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors", + resources.MaxVertexOutputVectors, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxFragmentInputVectors", + resources.MaxFragmentInputVectors, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MinProgramTexelOffset", + resources.MinProgramTexelOffset, EbpMedium); + symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxProgramTexelOffset", + resources.MaxProgramTexelOffset, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxImageUnits", resources.MaxImageUnits, + EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexImageUniforms", + resources.MaxVertexImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentImageUniforms", + resources.MaxFragmentImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeImageUniforms", + resources.MaxComputeImageUniforms, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedImageUniforms", + resources.MaxCombinedImageUniforms, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedShaderOutputResources", + resources.MaxCombinedShaderOutputResources, EbpMedium); + + symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupCount", + resources.MaxComputeWorkGroupCount, EbpHigh); + symbolTable.insertConstIvec3(ESSL3_1_BUILTINS, "gl_MaxComputeWorkGroupSize", + resources.MaxComputeWorkGroupSize, EbpHigh); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeUniformComponents", + resources.MaxComputeUniformComponents, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeTextureImageUnits", + resources.MaxComputeTextureImageUnits, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounters", + resources.MaxComputeAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxComputeAtomicCounterBuffers", + resources.MaxComputeAtomicCounterBuffers, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounters", + resources.MaxVertexAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounters", + resources.MaxFragmentAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounters", + resources.MaxCombinedAtomicCounters, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBindings", + resources.MaxAtomicCounterBindings, EbpMedium); + + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxVertexAtomicCounterBuffers", + resources.MaxVertexAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxFragmentAtomicCounterBuffers", + resources.MaxFragmentAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxCombinedAtomicCounterBuffers", + resources.MaxCombinedAtomicCounterBuffers, EbpMedium); + symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBufferSize", + resources.MaxAtomicCounterBufferSize, EbpMedium); } void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, @@ -532,85 +587,73 @@ 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))); - - // - // 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_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))); - - if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) - { - TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); - lastFragData.setArraySize(resources.MaxDrawBuffers); - - if (resources.EXT_shader_framebuffer_fetch) - { - symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); - } - else if (resources.NV_shader_framebuffer_fetch) - { - symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragColor"), - TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); - symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); - } - } - else if (resources.ARM_shader_framebuffer_fetch) - { - symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", - new TVariable(NewPoolTString("gl_LastFragColorARM"), - TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); - } - } - else - { - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), - TType(EbtFloat, EbpMedium, EvqGlobal, 4))); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"), - TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); - } + { + 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)); + + 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))); + } + + 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) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + else if (resources.NV_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColor"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + } + else if (resources.ARM_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColorARM"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + } + } break; @@ -624,6 +667,29 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_VertexID"), TType(EbtInt, EbpHigh, EvqVertexID, 1))); break; + case GL_COMPUTE_SHADER: + { + symbolTable.insert(ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_NumWorkGroups"), + TType(EbtUInt, EbpUndefined, EvqNumWorkGroups, 3))); + symbolTable.insert(ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_WorkGroupSize"), + TType(EbtUInt, EbpUndefined, EvqWorkGroupSize, 3))); + symbolTable.insert(ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_WorkGroupID"), + TType(EbtUInt, EbpUndefined, EvqWorkGroupID, 3))); + symbolTable.insert(ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_LocalInvocationID"), + TType(EbtUInt, EbpUndefined, EvqLocalInvocationID, 3))); + symbolTable.insert(ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_GlobalInvocationID"), + TType(EbtUInt, EbpUndefined, EvqGlobalInvocationID, 3))); + symbolTable.insert( + ESSL3_1_BUILTINS, + new TVariable(NewPoolTString("gl_LocalInvocationIndex"), + TType(EbtUInt, EbpUndefined, EvqLocalInvocationIndex, 1))); + } + break; default: assert(false && "Language not supported"); diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp index 86d3e6bc839..235f49893c4 100644 --- a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp +++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp @@ -6,40 +6,41 @@ #include "compiler/translator/InitializeVariables.h" +#include "angle_gl.h" #include "common/debug.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/util.h" namespace { -TIntermConstantUnion *constructFloatConstUnionNode(const TType &type) +class VariableInitializer : public TIntermTraverser { - TType myType = type; - unsigned char size = static_cast<unsigned char>(myType.getNominalSize()); - if (myType.isMatrix()) - size *= size; - TConstantUnion *u = new TConstantUnion[size]; - for (int ii = 0; ii < size; ++ii) - u[ii].setFConst(0.0f); - - myType.clearArrayness(); - myType.setQualifier(EvqConst); - TIntermConstantUnion *node = new TIntermConstantUnion(u, myType); - return node; -} + public: + VariableInitializer(const InitVariableList &vars) + : TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false) + { + } -TIntermConstantUnion *constructIndexNode(int index) -{ - TConstantUnion *u = new TConstantUnion[1]; - u[0].setIConst(index); + 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 visitLoop(Visit, TIntermLoop *node) override { return false; } + bool visitBranch(Visit, TIntermBranch *node) override { return false; } - TType type(EbtInt, EbpUndefined, EvqConst, 1); - TIntermConstantUnion *node = new TIntermConstantUnion(u, type); - return node; -} + bool visitAggregate(Visit visit, TIntermAggregate *node) override; -} // namespace anonymous + private: + void insertInitCode(TIntermSequence *sequence); + + const InitVariableList &mVariables; + bool mCodeInserted; +}; + +// VariableInitializer implementation. -bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) +bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = !mCodeInserted; switch (node->getOp()) @@ -53,17 +54,8 @@ bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) 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(sequence->size() == 2); + TIntermAggregate *body = (*sequence)[1]->getAsAggregate(); ASSERT(body); insertInitCode(body->getSequence()); mCodeInserted = true; @@ -77,41 +69,52 @@ bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node) return visitChildren; } -void InitializeVariables::insertInitCode(TIntermSequence *sequence) +void VariableInitializer::insertInitCode(TIntermSequence *sequence) { - for (size_t ii = 0; ii < mVariables.size(); ++ii) + for (const auto &var : mVariables) { - const InitVariableInfo &varInfo = mVariables[ii]; + TString name = TString(var.name.c_str()); + TType type = sh::GetShaderVariableType(var); - if (varInfo.type.isArray()) + // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which + // doesn't have array assignment. + if (var.isArray()) { - for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index) + size_t pos = name.find_last_of('['); + if (pos != TString::npos) { - TIntermBinary *assign = new TIntermBinary(EOpAssign); - sequence->insert(sequence->begin(), assign); + name = name.substr(0, pos); + } + TType elementType = type; + elementType.clearArrayness(); - TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); - TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); - indexDirect->setLeft(symbol); - TIntermConstantUnion *indexNode = constructIndexNode(index); - indexDirect->setRight(indexNode); + for (unsigned int i = 0; i < var.arraySize; ++i) + { + TIntermSymbol *arraySymbol = new TIntermSymbol(0, name, type); + TIntermBinary *element = new TIntermBinary(EOpIndexDirect, arraySymbol, + TIntermTyped::CreateIndexNode(i)); - assign->setLeft(indexDirect); + TIntermTyped *zero = TIntermTyped::CreateZero(elementType); + TIntermBinary *assignment = new TIntermBinary(EOpAssign, element, zero); - TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); - assign->setRight(zeroConst); + sequence->insert(sequence->begin(), assignment); } } else { - TIntermBinary *assign = new TIntermBinary(EOpAssign); + TIntermSymbol *symbol = new TIntermSymbol(0, name, type); + TIntermTyped *zero = TIntermTyped::CreateZero(type); + + TIntermBinary *assign = new TIntermBinary(EOpAssign, symbol, zero); sequence->insert(sequence->begin(), assign); - TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type); - assign->setLeft(symbol); - TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type); - assign->setRight(zeroConst); } - } } +} // namespace anonymous + +void InitializeVariables(TIntermNode *root, const InitVariableList &vars) +{ + VariableInitializer initializer(vars); + root->traverse(&initializer); +} diff --git a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h index 2a141ec91cf..dce1083f66b 100644 --- a/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h +++ b/chromium/third_party/angle/src/compiler/translator/InitializeVariables.h @@ -7,45 +7,13 @@ #ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ #define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ -#include "compiler/translator/IntermNode.h" +#include <GLSLANG/ShaderLang.h> -class InitializeVariables : public TIntermTraverser -{ - public: - struct InitVariableInfo - { - TString name; - TType type; +class TIntermNode; - InitVariableInfo(const TString &_name, const TType &_type) - : name(_name), - type(_type) - { - } - }; - typedef TVector<InitVariableInfo> InitVariableInfoList; +typedef std::vector<sh::ShaderVariable> InitVariableList; - InitializeVariables(const InitVariableInfoList &vars) - : TIntermTraverser(true, false, false), - mVariables(vars), - mCodeInserted(false) - { - } - - protected: - bool visitBinary(Visit, TIntermBinary *node) override { return false; } - bool visitUnary(Visit, TIntermUnary *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 visit, TIntermAggregate *node) override; - - private: - void insertInitCode(TIntermSequence *sequence); - - InitVariableInfoList mVariables; - bool mCodeInserted; -}; +// This function cannot currently initialize structures containing arrays for an ESSL 1.00 backend. +void InitializeVariables(TIntermNode *root, const InitVariableList &vars); #endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/IntermNode.cpp b/chromium/third_party/angle/src/compiler/translator/IntermNode.cpp index ccbd80f4766..09bc972a976 100644 --- a/chromium/third_party/angle/src/compiler/translator/IntermNode.cpp +++ b/chromium/third_party/angle/src/compiler/translator/IntermNode.cpp @@ -17,9 +17,11 @@ #include "common/mathutil.h" #include "common/matrix_utils.h" +#include "compiler/translator/Diagnostics.h" #include "compiler/translator/HashNames.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/util.h" namespace { @@ -33,41 +35,6 @@ TPrecision GetHigherPrecision(TPrecision left, TPrecision right) return left > right ? left : right; } -bool ValidateMultiplication(TOperator op, const TType &left, const TType &right) -{ - switch (op) - { - case EOpMul: - case EOpMulAssign: - return left.getNominalSize() == right.getNominalSize() && - left.getSecondarySize() == right.getSecondarySize(); - case EOpVectorTimesScalar: - case EOpVectorTimesScalarAssign: - return true; - case EOpVectorTimesMatrix: - return left.getNominalSize() == right.getRows(); - case EOpVectorTimesMatrixAssign: - return left.getNominalSize() == right.getRows() && - left.getNominalSize() == right.getCols(); - case EOpMatrixTimesVector: - return left.getCols() == right.getNominalSize(); - case EOpMatrixTimesScalar: - case EOpMatrixTimesScalarAssign: - return true; - case EOpMatrixTimesMatrix: - return left.getCols() == right.getRows(); - case EOpMatrixTimesMatrixAssign: - // We need to check two things: - // 1. The matrix multiplication step is valid. - // 2. The result will have the same number of columns as the lvalue. - return left.getCols() == right.getRows() && left.getCols() == right.getCols(); - - default: - UNREACHABLE(); - return false; - } -} - TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size) { TConstantUnion *constUnion = new TConstantUnion[size]; @@ -77,13 +44,14 @@ TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size) return constUnion; } -void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType, - TInfoSink &infoSink, TConstantUnion *result) +void UndefinedConstantFoldingError(const TSourceLoc &loc, + TOperator op, + TBasicType basicType, + TDiagnostics *diagnostics, + TConstantUnion *result) { - std::stringstream constantFoldingErrorStream; - constantFoldingErrorStream << "'" << GetOperatorString(op) - << "' operation result is undefined for the values passed in"; - infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str()); + diagnostics->warning(loc, "operation result is undefined for the values passed in", + GetOperatorString(op), ""); switch (basicType) { @@ -125,7 +93,7 @@ float VectorDotProduct(const TConstantUnion *paramArray1, return result; } -TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, +TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode, TQualifier qualifier) { @@ -147,8 +115,9 @@ angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, for (size_t i = 0; i < rows * cols; i++) elements.push_back(paramArray[i].getFConst()); // Transpose is used since the Matrix constructor expects arguments in row-major order, - // whereas the paramArray is in column-major order. - return angle::Matrix<float>(elements, rows, cols).transpose(); + // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below + // so that the created matrix will have the expected dimensions after the transpose. + return angle::Matrix<float>(elements, cols, rows).transpose(); } angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size) @@ -197,6 +166,7 @@ void TIntermTyped::setTypePreservePrecision(const TType &t) bool TIntermLoop::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { + ASSERT(original != nullptr); // This risks replacing multiple children. REPLACE_IF_IS(mInit, TIntermNode, original, replacement); REPLACE_IF_IS(mCond, TIntermTyped, original, replacement); REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement); @@ -211,6 +181,13 @@ bool TIntermBranch::replaceChildNode( return false; } +bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); + REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); + return false; +} + bool TIntermBinary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -222,6 +199,7 @@ bool TIntermBinary::replaceChildNode( bool TIntermUnary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { + ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType()); REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement); return false; } @@ -321,12 +299,19 @@ void TIntermAggregate::setBuiltInFunctionPrecision() mType.setPrecision(precision); } -bool TIntermSelection::replaceChildNode( - TIntermNode *original, TIntermNode *replacement) +bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement) { REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); - REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement); - REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement); + REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement); + REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement); + return false; +} + +bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + REPLACE_IF_IS(mTrueBlock, TIntermAggregate, original, replacement); + REPLACE_IF_IS(mFalseBlock, TIntermAggregate, original, replacement); return false; } @@ -368,6 +353,83 @@ bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters() return true; } +// static +TIntermTyped *TIntermTyped::CreateIndexNode(int index) +{ + TConstantUnion *u = new TConstantUnion[1]; + u[0].setIConst(index); + + TType type(EbtInt, EbpUndefined, EvqConst, 1); + TIntermConstantUnion *node = new TIntermConstantUnion(u, type); + return node; +} + +// static +TIntermTyped *TIntermTyped::CreateZero(const TType &type) +{ + TType constType(type); + constType.setQualifier(EvqConst); + + if (!type.isArray() && type.getBasicType() != EbtStruct) + { + ASSERT(type.isScalar() || type.isVector() || type.isMatrix()); + + size_t size = constType.getObjectSize(); + TConstantUnion *u = new TConstantUnion[size]; + for (size_t i = 0; i < size; ++i) + { + switch (type.getBasicType()) + { + case EbtFloat: + u[i].setFConst(0.0f); + break; + case EbtInt: + u[i].setIConst(0); + break; + case EbtUInt: + u[i].setUConst(0u); + break; + case EbtBool: + u[i].setBConst(false); + break; + default: + UNREACHABLE(); + return nullptr; + } + } + + TIntermConstantUnion *node = new TIntermConstantUnion(u, constType); + return node; + } + + TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type)); + constructor->setType(constType); + + if (type.isArray()) + { + TType elementType(type); + elementType.clearArrayness(); + + size_t arraySize = type.getArraySize(); + for (size_t i = 0; i < arraySize; ++i) + { + constructor->getSequence()->push_back(CreateZero(elementType)); + } + } + else + { + ASSERT(type.getBasicType() == EbtStruct); + + TStructure *structure = type.getStruct(); + for (const auto &field : structure->fields()) + { + constructor->getSequence()->push_back(CreateZero(*field->type())); + } + } + + return constructor; +} + TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node) { mUnionArrayPointer = node.mUnionArrayPointer; @@ -390,6 +452,13 @@ TIntermAggregate::TIntermAggregate(const TIntermAggregate &node) } } +TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node) +{ + TIntermTyped *operandCopy = node.mOperand->deepCopy(); + ASSERT(operandCopy != nullptr); + mOperand = operandCopy; +} + TIntermBinary::TIntermBinary(const TIntermBinary &node) : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp) { @@ -408,52 +477,20 @@ TIntermUnary::TIntermUnary(const TIntermUnary &node) mOperand = operandCopy; } -TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node) +TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node) { - // Only supported for ternary nodes, not if statements. - TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped(); - TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped(); - ASSERT(trueTyped != nullptr); - ASSERT(falseTyped != nullptr); TIntermTyped *conditionCopy = node.mCondition->deepCopy(); - TIntermTyped *trueCopy = trueTyped->deepCopy(); - TIntermTyped *falseCopy = falseTyped->deepCopy(); + TIntermTyped *trueCopy = node.mTrueExpression->deepCopy(); + TIntermTyped *falseCopy = node.mFalseExpression->deepCopy(); ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr); - mCondition = conditionCopy; - mTrueBlock = trueCopy; - mFalseBlock = falseCopy; + mCondition = conditionCopy; + mTrueExpression = trueCopy; + mFalseExpression = falseCopy; } -// -// Say whether or not an operation node changes the value of a variable. -// bool TIntermOperator::isAssignment() const { - switch (mOp) - { - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - case EOpAssign: - case EOpAddAssign: - case EOpSubAssign: - case EOpMulAssign: - case EOpVectorTimesMatrixAssign: - case EOpVectorTimesScalarAssign: - case EOpMatrixTimesScalarAssign: - case EOpMatrixTimesMatrixAssign: - case EOpDivAssign: - case EOpIModAssign: - case EOpBitShiftLeftAssign: - case EOpBitShiftRightAssign: - case EOpBitwiseAndAssign: - case EOpBitwiseXorAssign: - case EOpBitwiseOrAssign: - return true; - default: - return false; - } + return IsAssignment(mOp); } bool TIntermOperator::isMultiplication() const @@ -511,74 +548,260 @@ bool TIntermOperator::isConstructor() const } } +TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right) +{ + if (left.isMatrix()) + { + if (right.isMatrix()) + { + return EOpMatrixTimesMatrix; + } + else + { + if (right.isVector()) + { + return EOpMatrixTimesVector; + } + else + { + return EOpMatrixTimesScalar; + } + } + } + else + { + if (right.isMatrix()) + { + if (left.isVector()) + { + return EOpVectorTimesMatrix; + } + else + { + return EOpMatrixTimesScalar; + } + } + else + { + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMul; + } + else + { + return EOpVectorTimesScalar; + } + } + } +} + +TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right) +{ + if (left.isMatrix()) + { + if (right.isMatrix()) + { + return EOpMatrixTimesMatrixAssign; + } + else + { + // right should be scalar, but this may not be validated yet. + return EOpMatrixTimesScalarAssign; + } + } + else + { + if (right.isMatrix()) + { + // Left should be a vector, but this may not be validated yet. + return EOpVectorTimesMatrixAssign; + } + else + { + // Neither operand is a matrix. + if (left.isVector() == right.isVector()) + { + // Leave as component product. + return EOpMulAssign; + } + else + { + // left should be vector and right should be scalar, but this may not be validated + // yet. + return EOpVectorTimesScalarAssign; + } + } + } +} + // // Make sure the type of a unary operator is appropriate for its // combination of operation and operand type. // -void TIntermUnary::promote(const TType *funcReturnType) +void TIntermUnary::promote() { + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; + + unsigned char operandPrimarySize = + static_cast<unsigned char>(mOperand->getType().getNominalSize()); switch (mOp) { - case EOpFloatBitsToInt: - case EOpFloatBitsToUint: - case EOpIntBitsToFloat: - case EOpUintBitsToFloat: - case EOpPackSnorm2x16: - case EOpPackUnorm2x16: - case EOpPackHalf2x16: - case EOpUnpackSnorm2x16: - case EOpUnpackUnorm2x16: - mType.setPrecision(EbpHigh); - break; - case EOpUnpackHalf2x16: - mType.setPrecision(EbpMedium); - break; - default: - setType(mOperand->getType()); + case EOpFloatBitsToInt: + setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpFloatBitsToUint: + setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize)); + break; + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + setType(TType(EbtUInt, EbpHigh, resultQualifier)); + break; + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + setType(TType(EbtFloat, EbpHigh, resultQualifier, 2)); + break; + case EOpUnpackHalf2x16: + setType(TType(EbtFloat, EbpMedium, resultQualifier, 2)); + break; + case EOpAny: + case EOpAll: + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; + case EOpLength: + case EOpDeterminant: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier)); + break; + case EOpTranspose: + setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier, + static_cast<unsigned char>(mOperand->getType().getRows()), + static_cast<unsigned char>(mOperand->getType().getCols()))); + break; + case EOpIsInf: + case EOpIsNan: + setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize)); + break; + default: + setType(mOperand->getType()); + mType.setQualifier(resultQualifier); + break; + } +} + +TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets) + : TIntermTyped(TType(EbtFloat, EbpUndefined)), + mOperand(operand), + mSwizzleOffsets(swizzleOffsets) +{ + ASSERT(mSwizzleOffsets.size() <= 4); + promote(); +} + +TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand) + : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false) +{ + promote(); +} + +TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right) + : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false) +{ + promote(); +} + +TIntermTernary::TIntermTernary(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) + : TIntermTyped(trueExpression->getType()), + mCondition(cond), + mTrueExpression(trueExpression), + mFalseExpression(falseExpression) +{ + getTypePointer()->setQualifier( + TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression)); +} + +// static +TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression) +{ + if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst && + falseExpression->getQualifier() == EvqConst) + { + return EvqConst; } + return EvqTemporary; +} + +void TIntermSwizzle::promote() +{ + TQualifier resultQualifier = EvqTemporary; + if (mOperand->getQualifier() == EvqConst) + resultQualifier = EvqConst; - if (funcReturnType != nullptr) + auto numFields = mSwizzleOffsets.size(); + setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier, + static_cast<unsigned char>(numFields))); +} + +bool TIntermSwizzle::hasDuplicateOffsets() const +{ + int offsetCount[4] = {0u, 0u, 0u, 0u}; + for (const auto offset : mSwizzleOffsets) { - if (funcReturnType->getBasicType() == EbtBool) + offsetCount[offset]++; + if (offsetCount[offset] > 1) { - // Bool types should not have precision. - setType(*funcReturnType); + return true; } - else + } + return false; +} + +void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const +{ + for (const int offset : mSwizzleOffsets) + { + switch (offset) { - // Precision of the node has been set based on the operand. - setTypePreservePrecision(*funcReturnType); + case 0: + *out << "x"; + break; + case 1: + *out << "y"; + break; + case 2: + *out << "z"; + break; + case 3: + *out << "w"; + break; + default: + UNREACHABLE(); } } - - if (mOperand->getQualifier() == EvqConst) - mType.setQualifier(EvqConst); - else - mType.setQualifier(EvqTemporary); } -// -// Establishes the type of the resultant operation, as well as -// makes the operator the correct one for the operands. -// -// For lots of operations it should already be established that the operand -// combination is valid, but returns false if operator can't work on operands. -// -bool TIntermBinary::promote(TInfoSink &infoSink) + +// Establishes the type of the result of the binary operation. +void TIntermBinary::promote() { - ASSERT(mLeft->isArray() == mRight->isArray()); + ASSERT(!isMultiplication() || + mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType())); - // // Base assumption: just make the type the same as the left // operand. Then only deviations from this need be coded. - // setType(mLeft->getType()); - // The result gets promoted to the highest precision. - TPrecision higherPrecision = GetHigherPrecision( - mLeft->getPrecision(), mRight->getPrecision()); - getTypePointer()->setPrecision(higherPrecision); - TQualifier resultQualifier = EvqConst; // Binary operations results in temporary variables unless both // operands are const. @@ -588,6 +811,55 @@ bool TIntermBinary::promote(TInfoSink &infoSink) getTypePointer()->setQualifier(EvqTemporary); } + // Handle indexing ops. + switch (mOp) + { + case EOpIndexDirect: + case EOpIndexIndirect: + if (mLeft->isArray()) + { + mType.clearArrayness(); + } + else if (mLeft->isMatrix()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier, + static_cast<unsigned char>(mLeft->getRows()))); + } + else if (mLeft->isVector()) + { + setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier)); + } + else + { + UNREACHABLE(); + } + return; + case EOpIndexDirectStruct: + { + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + case EOpIndexDirectInterfaceBlock: + { + const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields(); + const int i = mRight->getAsConstantUnion()->getIConst(0); + setType(*fields[i]->type()); + getTypePointer()->setQualifier(resultQualifier); + return; + } + default: + break; + } + + ASSERT(mLeft->isArray() == mRight->isArray()); + + // The result gets promoted to the highest precision. + TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision()); + getTypePointer()->setPrecision(higherPrecision); + const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize()); @@ -607,8 +879,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - setType(TType(EbtBool, EbpUndefined)); - break; + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; // // And and Or operate on conditionals @@ -617,244 +889,210 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpLogicalXor: case EOpLogicalOr: ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); - setType(TType(EbtBool, EbpUndefined)); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); break; default: break; } - return true; + return; } // If we reach here, at least one of the operands is vector or matrix. // The other operand could be a scalar, vector, or matrix. - // Can these two operands be combined? - // TBasicType basicType = mLeft->getBasicType(); + switch (mOp) { - case EOpMul: - if (!mLeft->isMatrix() && mRight->isMatrix()) - { - if (mLeft->isVector()) - { - mOp = EOpVectorTimesMatrix; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(mRight->getCols()), 1)); - } - else + case EOpMul: + break; + case EOpMatrixTimesScalar: + if (mRight->isMatrix()) { - mOp = EOpMatrixTimesScalar; setType(TType(basicType, higherPrecision, resultQualifier, static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows()))); } - } - else if (mLeft->isMatrix() && !mRight->isMatrix()) - { - if (mRight->isVector()) - { - mOp = EOpMatrixTimesVector; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(mLeft->getRows()), 1)); - } - else - { - mOp = EOpMatrixTimesScalar; - } - } - else if (mLeft->isMatrix() && mRight->isMatrix()) - { - mOp = EOpMatrixTimesMatrix; + break; + case EOpMatrixTimesVector: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mLeft->getRows()), 1)); + break; + case EOpMatrixTimesMatrix: setType(TType(basicType, higherPrecision, resultQualifier, static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows()))); + break; + case EOpVectorTimesScalar: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(nominalSize), 1)); + break; + case EOpVectorTimesMatrix: + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(mRight->getCols()), 1)); + break; + case EOpMulAssign: + case EOpVectorTimesScalarAssign: + case EOpVectorTimesMatrixAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType())); + break; + case EOpAssign: + case EOpInitialize: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + { + const int secondarySize = + std::max(mLeft->getSecondarySize(), mRight->getSecondarySize()); + setType(TType(basicType, higherPrecision, resultQualifier, + static_cast<unsigned char>(nominalSize), + static_cast<unsigned char>(secondarySize))); + ASSERT(!mLeft->isArray() && !mRight->isArray()); + break; } - else if (!mLeft->isMatrix() && !mRight->isMatrix()) - { - if (mLeft->isVector() && mRight->isVector()) - { - // leave as component product - } - else if (mLeft->isVector() || mRight->isVector()) - { - mOp = EOpVectorTimesScalar; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(nominalSize), 1)); - } - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Missing elses"); - return false; - } + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + setType(TType(EbtBool, EbpUndefined, resultQualifier)); + break; - if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) - { - return false; - } - break; + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + case EOpIndexDirectStruct: + // These ops should be already fully handled. + UNREACHABLE(); + break; + default: + UNREACHABLE(); + break; + } +} - case EOpMulAssign: - if (!mLeft->isMatrix() && mRight->isMatrix()) - { - if (mLeft->isVector()) - { - mOp = EOpVectorTimesMatrixAssign; - } - else - { - return false; - } - } - else if (mLeft->isMatrix() && !mRight->isMatrix()) +const TConstantUnion *TIntermConstantUnion::foldIndexing(int index) +{ + if (isArray()) + { + ASSERT(index < static_cast<int>(getType().getArraySize())); + TType arrayElementType = getType(); + arrayElementType.clearArrayness(); + size_t arrayElementSize = arrayElementType.getObjectSize(); + return &mUnionArrayPointer[arrayElementSize * index]; + } + else if (isMatrix()) + { + ASSERT(index < getType().getCols()); + int size = getType().getRows(); + return &mUnionArrayPointer[size * index]; + } + else if (isVector()) + { + ASSERT(index < getType().getNominalSize()); + return &mUnionArrayPointer[index]; + } + else + { + UNREACHABLE(); + return nullptr; + } +} + +TIntermTyped *TIntermSwizzle::fold() +{ + TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); + if (operandConstant == nullptr) + { + return nullptr; + } + + TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()]; + for (size_t i = 0; i < mSwizzleOffsets.size(); ++i) + { + constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i)); + } + return CreateFoldedNode(constArray, this, mType.getQualifier()); +} + +TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics) +{ + TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion(); + TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion(); + switch (mOp) + { + case EOpIndexDirect: { - if (mRight->isVector()) + if (leftConstant == nullptr || rightConstant == nullptr) { - return false; - } - else - { - mOp = EOpMatrixTimesScalarAssign; + return nullptr; } + int index = rightConstant->getIConst(0); + + const TConstantUnion *constArray = leftConstant->foldIndexing(index); + return CreateFoldedNode(constArray, this, mType.getQualifier()); } - else if (mLeft->isMatrix() && mRight->isMatrix()) - { - mOp = EOpMatrixTimesMatrixAssign; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(mRight->getCols()), - static_cast<unsigned char>(mLeft->getRows()))); - } - else if (!mLeft->isMatrix() && !mRight->isMatrix()) + case EOpIndexDirectStruct: { - if (mLeft->isVector() && mRight->isVector()) + if (leftConstant == nullptr || rightConstant == nullptr) { - // leave as component product + return nullptr; } - else if (mLeft->isVector() || mRight->isVector()) + const TFieldList &fields = mLeft->getType().getStruct()->fields(); + size_t index = static_cast<size_t>(rightConstant->getIConst(0)); + + size_t previousFieldsSize = 0; + for (size_t i = 0; i < index; ++i) { - if (!mLeft->isVector()) - return false; - mOp = EOpVectorTimesScalarAssign; - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(mLeft->getNominalSize()), 1)); + previousFieldsSize += fields[i]->type()->getObjectSize(); } - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Missing elses"); - return false; - } - if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType())) - { - return false; + const TConstantUnion *constArray = leftConstant->getUnionArrayPointer(); + return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier()); } - break; - - case EOpAssign: - case EOpInitialize: - // No more additional checks are needed. - ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && - (mLeft->getSecondarySize() == mRight->getSecondarySize())); - break; - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpIMod: - case EOpBitShiftLeft: - case EOpBitShiftRight: - case EOpBitwiseAnd: - case EOpBitwiseXor: - case EOpBitwiseOr: - case EOpAddAssign: - case EOpSubAssign: - case EOpDivAssign: - case EOpIModAssign: - case EOpBitShiftLeftAssign: - case EOpBitShiftRightAssign: - case EOpBitwiseAndAssign: - case EOpBitwiseXorAssign: - case EOpBitwiseOrAssign: - if ((mLeft->isMatrix() && mRight->isVector()) || - (mLeft->isVector() && mRight->isMatrix())) - { - return false; - } - - // Are the sizes compatible? - if (mLeft->getNominalSize() != mRight->getNominalSize() || - mLeft->getSecondarySize() != mRight->getSecondarySize()) - { - // If the nominal sizes of operands do not match: - // One of them must be a scalar. - if (!mLeft->isScalar() && !mRight->isScalar()) - return false; - - // In the case of compound assignment other than multiply-assign, - // the right side needs to be a scalar. Otherwise a vector/matrix - // would be assigned to a scalar. A scalar can't be shifted by a - // vector either. - if (!mRight->isScalar() && - (isAssignment() || - mOp == EOpBitShiftLeft || - mOp == EOpBitShiftRight)) - return false; - } - + case EOpIndexIndirect: + case EOpIndexDirectInterfaceBlock: + // Can never be constant folded. + return nullptr; + default: { - const int secondarySize = std::max( - mLeft->getSecondarySize(), mRight->getSecondarySize()); - setType(TType(basicType, higherPrecision, resultQualifier, - static_cast<unsigned char>(nominalSize), - static_cast<unsigned char>(secondarySize))); - if (mLeft->isArray()) + if (leftConstant == nullptr || rightConstant == nullptr) { - ASSERT(mLeft->getArraySize() == mRight->getArraySize()); - mType.setArraySize(mLeft->getArraySize()); + return nullptr; } - } - break; - - case EOpEqual: - case EOpNotEqual: - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && - (mLeft->getSecondarySize() == mRight->getSecondarySize())); - setType(TType(EbtBool, EbpUndefined)); - break; - - default: - return false; - } - return true; -} - -TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink) -{ - TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion(); - TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion(); - if (leftConstant == nullptr || rightConstant == nullptr) - { - return nullptr; - } - TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink); + TConstantUnion *constArray = + leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine()); - // Nodes may be constant folded without being qualified as constant. - TQualifier resultQualifier = EvqConst; - if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst) - { - resultQualifier = EvqTemporary; + // Nodes may be constant folded without being qualified as constant. + return CreateFoldedNode(constArray, this, mType.getQualifier()); + } } - return CreateFoldedNode(constArray, this, resultQualifier); } -TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) +TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics) { TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion(); if (operandConstant == nullptr) @@ -877,19 +1115,18 @@ TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink) case EOpUnpackUnorm2x16: case EOpPackHalf2x16: case EOpUnpackHalf2x16: - constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink); - break; + constArray = operandConstant->foldUnaryNonComponentWise(mOp); + break; default: - constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink); - break; + constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics); + break; } // Nodes may be constant folded without being qualified as constant. - TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary; - return CreateFoldedNode(constArray, this, resultQualifier); + return CreateFoldedNode(constArray, this, mType.getQualifier()); } -TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) +TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics) { // Make sure that all params are constant before actual constant folding. for (auto *param : *getSequence()) @@ -901,9 +1138,9 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) } TConstantUnion *constArray = nullptr; if (isConstructor()) - constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink); + constArray = TIntermConstantUnion::FoldAggregateConstructor(this); else - constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink); + constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics); // Nodes may be constant folded without being qualified as constant. TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary; @@ -916,15 +1153,15 @@ TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink) // // Returns the constant value to keep using or nullptr. // -TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, + TIntermConstantUnion *rightNode, + TDiagnostics *diagnostics, + const TSourceLoc &line) { const TConstantUnion *leftArray = getUnionArrayPointer(); const TConstantUnion *rightArray = rightNode->getUnionArrayPointer(); - if (!leftArray) - return nullptr; - if (!rightArray) - return nullptr; + ASSERT(leftArray && rightArray); size_t objectSize = getType().getObjectSize(); @@ -947,12 +1184,12 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpAdd: resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) - resultArray[i] = leftArray[i] + rightArray[i]; + resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line); break; case EOpSub: resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) - resultArray[i] = leftArray[i] - rightArray[i]; + resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line); break; case EOpMul: @@ -960,19 +1197,13 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpMatrixTimesScalar: resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) - resultArray[i] = leftArray[i] * rightArray[i]; + resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line); break; case EOpMatrixTimesMatrix: { - if (getType().getBasicType() != EbtFloat || - rightNode->getBasicType() != EbtFloat) - { - infoSink.info.message( - EPrefixInternalError, getLine(), - "Constant Folding cannot be done for matrix multiply"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat); const int leftCols = getCols(); const int leftRows = getRows(); @@ -1010,8 +1241,8 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EbtFloat: if (rightArray[i] == 0.0f) { - infoSink.info.message(EPrefixWarning, getLine(), - "Divide by zero error during constant folding"); + diagnostics->warning( + getLine(), "Divide by zero error during constant folding", "/", ""); resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX); } else @@ -1024,20 +1255,48 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EbtInt: if (rightArray[i] == 0) { - infoSink.info.message(EPrefixWarning, getLine(), - "Divide by zero error during constant folding"); + diagnostics->warning( + getLine(), "Divide by zero error during constant folding", "/", ""); resultArray[i].setIConst(INT_MAX); } else { + int lhs = leftArray[i].getIConst(); + int divisor = rightArray[i].getIConst(); if (op == EOpDiv) { - resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst()); + // Check for the special case where the minimum representable number is + // divided by -1. If left alone this leads to integer overflow in C++. + // ESSL 3.00.6 section 4.1.3 Integers: + // "However, for the case where the minimum representable value is + // divided by -1, it is allowed to return either the minimum + // representable value or the maximum representable value." + if (lhs == -0x7fffffff - 1 && divisor == -1) + { + resultArray[i].setIConst(0x7fffffff); + } + else + { + resultArray[i].setIConst(lhs / divisor); + } } else { ASSERT(op == EOpIMod); - resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst()); + if (lhs < 0 || divisor < 0) + { + // ESSL 3.00.6 section 5.9: Results of modulus are undefined when + // either one of the operands is negative. + diagnostics->warning(getLine(), + "Negative modulus operator operand " + "encountered during constant folding", + "%", ""); + resultArray[i].setIConst(0); + } + else + { + resultArray[i].setIConst(lhs % divisor); + } } } break; @@ -1045,8 +1304,8 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EbtUInt: if (rightArray[i] == 0) { - infoSink.info.message(EPrefixWarning, getLine(), - "Divide by zero error during constant folding"); + diagnostics->warning( + getLine(), "Divide by zero error during constant folding", "/", ""); resultArray[i].setUConst(UINT_MAX); } else @@ -1064,9 +1323,8 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn break; default: - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant folding cannot be done for \"/\""); - return nullptr; + UNREACHABLE(); + return nullptr; } } } @@ -1074,12 +1332,8 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpMatrixTimesVector: { - if (rightNode->getBasicType() != EbtFloat) - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant Folding cannot be done for matrix times vector"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(rightNode->getBasicType() == EbtFloat); const int matrixCols = getCols(); const int matrixRows = getRows(); @@ -1101,12 +1355,8 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpVectorTimesMatrix: { - if (getType().getBasicType() != EbtFloat) - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Constant Folding cannot be done for vector times matrix"); - return nullptr; - } + // TODO(jmadll): This code should check for overflows. + ASSERT(getType().getBasicType() == EbtFloat); const int matrixCols = rightNode->getType().getCols(); const int matrixRows = rightNode->getType().getRows(); @@ -1148,18 +1398,11 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpLogicalXor: { + ASSERT(getType().getBasicType() == EbtBool); resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) { - switch (getType().getBasicType()) - { - case EbtBool: - resultArray[i].setBConst(leftArray[i] != rightArray[i]); - break; - default: - UNREACHABLE(); - break; - } + resultArray[i].setBConst(leftArray[i] != rightArray[i]); } } break; @@ -1182,12 +1425,12 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn case EOpBitShiftLeft: resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) - resultArray[i] = leftArray[i] << rightArray[i]; + resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line); break; case EOpBitShiftRight: resultArray = new TConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) - resultArray[i] = leftArray[i] >> rightArray[i]; + resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line); break; case EOpLessThan: @@ -1239,37 +1482,28 @@ TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUn break; default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Invalid operator for constant folding"); - return nullptr; + UNREACHABLE(); + return nullptr; } return resultArray; } -// -// The fold functions see if an operation on a constant can be done in place, -// without generating run-time code. -// -// Returns the constant value to keep using or nullptr. -// -TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink) +// The fold functions do operations on a constant at GLSL compile time, without generating run-time +// code. Returns the constant value to keep using. Nullptr should not be returned. +TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op) { - // - // Do operations where the return type has a different number of components compared to the operand type. - // + // Do operations where the return type may have a different number of components compared to the + // operand type. const TConstantUnion *operandArray = getUnionArrayPointer(); - if (!operandArray) - return nullptr; + ASSERT(operandArray); size_t objectSize = getType().getObjectSize(); TConstantUnion *resultArray = nullptr; switch (op) { - case EOpAny: - if (getType().getBasicType() == EbtBool) - { + case EOpAny: + ASSERT(getType().getBasicType() == EbtBool); resultArray = new TConstantUnion(); resultArray->setBConst(false); for (size_t i = 0; i < objectSize; i++) @@ -1281,16 +1515,9 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator } } break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpAll: - if (getType().getBasicType() == EbtBool) - { + case EOpAll: + ASSERT(getType().getBasicType() == EbtBool); resultArray = new TConstantUnion(); resultArray->setBConst(true); for (size_t i = 0; i < objectSize; i++) @@ -1302,89 +1529,55 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator } } break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpLength: - if (getType().getBasicType() == EbtFloat) - { + case EOpLength: + ASSERT(getType().getBasicType() == EbtFloat); resultArray = new TConstantUnion(); resultArray->setFConst(VectorLength(operandArray, objectSize)); break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpTranspose: - if (getType().getBasicType() == EbtFloat) + case EOpTranspose: { + ASSERT(getType().getBasicType() == EbtFloat); resultArray = new TConstantUnion[objectSize]; angle::Matrix<float> result = - GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose(); + GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose(); SetUnionArrayFromMatrix(result, resultArray); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpDeterminant: - if (getType().getBasicType() == EbtFloat) + case EOpDeterminant: { + ASSERT(getType().getBasicType() == EbtFloat); unsigned int size = getType().getNominalSize(); ASSERT(size >= 2 && size <= 4); resultArray = new TConstantUnion(); resultArray->setFConst(GetMatrix(operandArray, size).determinant()); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpInverse: - if (getType().getBasicType() == EbtFloat) + case EOpInverse: { + ASSERT(getType().getBasicType() == EbtFloat); unsigned int size = getType().getNominalSize(); ASSERT(size >= 2 && size <= 4); - resultArray = new TConstantUnion[objectSize]; + resultArray = new TConstantUnion[objectSize]; angle::Matrix<float> result = GetMatrix(operandArray, size).inverse(); SetUnionArrayFromMatrix(result, resultArray); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpPackSnorm2x16: - if (getType().getBasicType() == EbtFloat) - { + case EOpPackSnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); ASSERT(getType().getNominalSize() == 2); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + resultArray->setUConst( + gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpUnpackSnorm2x16: - if (getType().getBasicType() == EbtUInt) + case EOpUnpackSnorm2x16: { + ASSERT(getType().getBasicType() == EbtUInt); resultArray = new TConstantUnion[2]; float f1, f2; gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2); @@ -1392,29 +1585,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator resultArray[1].setFConst(f2); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpPackUnorm2x16: - if (getType().getBasicType() == EbtFloat) - { + case EOpPackUnorm2x16: + ASSERT(getType().getBasicType() == EbtFloat); ASSERT(getType().getNominalSize() == 2); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + resultArray->setUConst( + gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpUnpackUnorm2x16: - if (getType().getBasicType() == EbtUInt) + case EOpUnpackUnorm2x16: { + ASSERT(getType().getBasicType() == EbtUInt); resultArray = new TConstantUnion[2]; float f1, f2; gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2); @@ -1422,29 +1604,18 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator resultArray[1].setFConst(f2); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpPackHalf2x16: - if (getType().getBasicType() == EbtFloat) - { + case EOpPackHalf2x16: + ASSERT(getType().getBasicType() == EbtFloat); ASSERT(getType().getNominalSize() == 2); resultArray = new TConstantUnion(); - resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); + resultArray->setUConst( + gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst())); break; - } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - case EOpUnpackHalf2x16: - if (getType().getBasicType() == EbtUInt) + case EOpUnpackHalf2x16: { + ASSERT(getType().getBasicType() == EbtUInt); resultArray = new TConstantUnion[2]; float f1, f2; gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2); @@ -1452,29 +1623,24 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator resultArray[1].setFConst(f2); break; } - else - { - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - } - break; - default: - break; + default: + UNREACHABLE(); + break; } return resultArray; } -TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op, + TDiagnostics *diagnostics) { - // - // Do unary operations where the return type is the same as operand type. - // + // Do unary operations where each component of the result is computed based on the corresponding + // component of the operand. Also folds normalize, though the divisor in that case takes all + // components into account. const TConstantUnion *operandArray = getUnionArrayPointer(); - if (!operandArray) - return nullptr; + ASSERT(operandArray); size_t objectSize = getType().getObjectSize(); @@ -1483,243 +1649,232 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, { switch(op) { - case EOpNegative: - switch (getType().getBasicType()) - { - case EbtFloat: - resultArray[i].setFConst(-operandArray[i].getFConst()); - break; - case EbtInt: - resultArray[i].setIConst(-operandArray[i].getIConst()); - break; - case EbtUInt: - resultArray[i].setUConst(static_cast<unsigned int>( - -static_cast<int>(operandArray[i].getUConst()))); + case EOpNegative: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(-operandArray[i].getFConst()); + break; + case EbtInt: + if (operandArray[i] == std::numeric_limits<int>::min()) + { + // The minimum representable integer doesn't have a positive + // counterpart, rather the negation overflows and in ESSL is supposed to + // wrap back to the minimum representable integer. Make sure that we + // don't actually let the negation overflow, which has undefined + // behavior in C++. + resultArray[i].setIConst(std::numeric_limits<int>::min()); + } + else + { + resultArray[i].setIConst(-operandArray[i].getIConst()); + } + break; + case EbtUInt: + if (operandArray[i] == 0x80000000u) + { + resultArray[i].setUConst(0x80000000u); + } + else + { + resultArray[i].setUConst(static_cast<unsigned int>( + -static_cast<int>(operandArray[i].getUConst()))); + } + break; + default: + UNREACHABLE(); + return nullptr; + } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpPositive: - switch (getType().getBasicType()) - { - case EbtFloat: - resultArray[i].setFConst(operandArray[i].getFConst()); - break; - case EbtInt: - resultArray[i].setIConst(operandArray[i].getIConst()); - break; - case EbtUInt: - resultArray[i].setUConst(static_cast<unsigned int>( - static_cast<int>(operandArray[i].getUConst()))); + case EOpPositive: + switch (getType().getBasicType()) + { + case EbtFloat: + resultArray[i].setFConst(operandArray[i].getFConst()); + break; + case EbtInt: + resultArray[i].setIConst(operandArray[i].getIConst()); + break; + case EbtUInt: + resultArray[i].setUConst(static_cast<unsigned int>( + static_cast<int>(operandArray[i].getUConst()))); + break; + default: + UNREACHABLE(); + return nullptr; + } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpLogicalNot: - // this code is written for possible future use, - // will not get executed currently - switch (getType().getBasicType()) - { - case EbtBool: - resultArray[i].setBConst(!operandArray[i].getBConst()); + case EOpLogicalNot: + switch (getType().getBasicType()) + { + case EbtBool: + resultArray[i].setBConst(!operandArray[i].getBConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpBitwiseNot: - switch (getType().getBasicType()) - { - case EbtInt: - resultArray[i].setIConst(~operandArray[i].getIConst()); - break; - case EbtUInt: - resultArray[i].setUConst(~operandArray[i].getUConst()); + case EOpBitwiseNot: + switch (getType().getBasicType()) + { + case EbtInt: + resultArray[i].setIConst(~operandArray[i].getIConst()); + break; + case EbtUInt: + resultArray[i].setUConst(~operandArray[i].getUConst()); + break; + default: + UNREACHABLE(); + return nullptr; + } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpRadians: - if (getType().getBasicType() == EbtFloat) - { + case EOpRadians: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst()); break; - } - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - case EOpDegrees: - if (getType().getBasicType() == EbtFloat) - { + case EOpDegrees: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst()); break; - } - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - - case EOpSin: - if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i])) - return nullptr; - break; - - case EOpCos: - if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i])) - return nullptr; - break; - case EOpTan: - if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpSin: + foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]); + break; - case EOpAsin: - // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpCos: + foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]); + break; - case EOpAcos: - // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpTan: + foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]); + break; - case EOpAtan: - if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpAsin: + // For asin(x), results are undefined if |x| > 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]); + break; - case EOpSinh: - if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpAcos: + // For acos(x), results are undefined if |x| > 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) > 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]); + break; - case EOpCosh: - if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpAtan: + foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]); + break; - case EOpTanh: - if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpSinh: + foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]); + break; - case EOpAsinh: - if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpCosh: + foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]); + break; - case EOpAcosh: - // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpTanh: + foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]); + break; - case EOpAtanh: - // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpAsinh: + foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]); + break; - case EOpAbs: - switch (getType().getBasicType()) - { - case EbtFloat: - resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); + case EOpAcosh: + // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]); break; - case EbtInt: - resultArray[i].setIConst(abs(operandArray[i].getIConst())); + + case EOpAtanh: + // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to + // 0. + if (fabsf(operandArray[i].getFConst()) >= 1.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]); break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpSign: - switch (getType().getBasicType()) - { - case EbtFloat: + case EOpAbs: + switch (getType().getBasicType()) { - float fConst = operandArray[i].getFConst(); - float fResult = 0.0f; - if (fConst > 0.0f) - fResult = 1.0f; - else if (fConst < 0.0f) - fResult = -1.0f; - resultArray[i].setFConst(fResult); + case EbtFloat: + resultArray[i].setFConst(fabsf(operandArray[i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst(abs(operandArray[i].getIConst())); + break; + default: + UNREACHABLE(); + return nullptr; } break; - case EbtInt: + + case EOpSign: + switch (getType().getBasicType()) { - int iConst = operandArray[i].getIConst(); - int iResult = 0; - if (iConst > 0) - iResult = 1; - else if (iConst < 0) - iResult = -1; - resultArray[i].setIConst(iResult); + case EbtFloat: + { + float fConst = operandArray[i].getFConst(); + float fResult = 0.0f; + if (fConst > 0.0f) + fResult = 1.0f; + else if (fConst < 0.0f) + fResult = -1.0f; + resultArray[i].setFConst(fResult); + break; + } + case EbtInt: + { + int iConst = operandArray[i].getIConst(); + int iResult = 0; + if (iConst > 0) + iResult = 1; + else if (iConst < 0) + iResult = -1; + resultArray[i].setIConst(iResult); + break; + } + default: + UNREACHABLE(); + return nullptr; } break; - default: - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - } - break; - case EOpFloor: - if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpFloor: + foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]); + break; - case EOpTrunc: - if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpTrunc: + foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]); + break; - case EOpRound: - if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpRound: + foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]); + break; - case EOpRoundEven: - if (getType().getBasicType() == EbtFloat) + case EOpRoundEven: { + ASSERT(getType().getBasicType() == EbtFloat); float x = operandArray[i].getFConst(); float result; float fractPart = modff(x, &result); @@ -1730,197 +1885,151 @@ TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, resultArray[i].setFConst(result); break; } - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - case EOpCeil: - if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpCeil: + foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]); + break; - case EOpFract: - if (getType().getBasicType() == EbtFloat) + case EOpFract: { + ASSERT(getType().getBasicType() == EbtFloat); float x = operandArray[i].getFConst(); resultArray[i].setFConst(x - floorf(x)); break; } - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - case EOpIsNan: - if (getType().getBasicType() == EbtFloat) - { + case EOpIsNan: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpIsInf: - if (getType().getBasicType() == EbtFloat) - { + case EOpIsInf: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpFloatBitsToInt: - if (getType().getBasicType() == EbtFloat) - { + case EOpFloatBitsToInt: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpFloatBitsToUint: - if (getType().getBasicType() == EbtFloat) - { + case EOpFloatBitsToUint: + ASSERT(getType().getBasicType() == EbtFloat); resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpIntBitsToFloat: - if (getType().getBasicType() == EbtInt) - { + case EOpIntBitsToFloat: + ASSERT(getType().getBasicType() == EbtInt); resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpUintBitsToFloat: - if (getType().getBasicType() == EbtUInt) - { + case EOpUintBitsToFloat: + ASSERT(getType().getBasicType() == EbtUInt); resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst())); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpExp: - if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpExp: + foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]); + break; - case EOpLog: - // For log(x), results are undefined if x <= 0, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpLog: + // For log(x), results are undefined if x <= 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + break; - case EOpExp2: - if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpExp2: + foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]); + break; - case EOpLog2: - // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0. - // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here. - if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i])) - return nullptr; - else - resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f)); - break; + case EOpLog2: + // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0. + // And log2f is not available on some plarforms like old android, so just using + // log(x)/log(2) here. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]); + resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f)); + } + break; - case EOpSqrt: - // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i])) - return nullptr; - break; + case EOpSqrt: + // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0. + if (operandArray[i].getFConst() < 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + break; - case EOpInverseSqrt: - // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(), - // so getting the square root first using builtin function sqrt() and then taking its inverse. - // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0. - if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f) - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]); - else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i])) - return nullptr; - else - resultArray[i].setFConst(1.0f / resultArray[i].getFConst()); - break; + case EOpInverseSqrt: + // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(), + // so getting the square root first using builtin function sqrt() and then taking + // its inverse. + // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set + // result to 0. + if (operandArray[i].getFConst() <= 0.0f) + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); + else + { + foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]); + resultArray[i].setFConst(1.0f / resultArray[i].getFConst()); + } + break; - case EOpVectorLogicalNot: - if (getType().getBasicType() == EbtBool) - { + case EOpVectorLogicalNot: + ASSERT(getType().getBasicType() == EbtBool); resultArray[i].setBConst(!operandArray[i].getBConst()); break; - } - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return nullptr; - case EOpNormalize: - if (getType().getBasicType() == EbtFloat) + case EOpNormalize: { - float x = operandArray[i].getFConst(); + ASSERT(getType().getBasicType() == EbtFloat); + float x = operandArray[i].getFConst(); float length = VectorLength(operandArray, objectSize); if (length) resultArray[i].setFConst(x / length); else - UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, - &resultArray[i]); + UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), + diagnostics, &resultArray[i]); break; } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - case EOpDFdx: - case EOpDFdy: - case EOpFwidth: - if (getType().getBasicType() == EbtFloat) - { + case EOpDFdx: + case EOpDFdy: + case EOpFwidth: + ASSERT(getType().getBasicType() == EbtFloat); // Derivatives of constant arguments should be 0. resultArray[i].setFConst(0.0f); break; - } - infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant"); - return nullptr; - default: - return nullptr; + default: + return nullptr; } } return resultArray; } -bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc, - TInfoSink &infoSink, TConstantUnion *result) const +void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + TConstantUnion *result) const { ASSERT(builtinFunc); - if (getType().getBasicType() == EbtFloat) - { - result->setFConst(builtinFunc(parameter.getFConst())); - return true; - } - - infoSink.info.message( - EPrefixInternalError, getLine(), - "Unary operation not folded into constant"); - return false; + ASSERT(getType().getBasicType() == EbtFloat); + result->setFConst(builtinFunc(parameter.getFConst())); } // static -TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate, - TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate) { ASSERT(aggregate->getSequence()->size() > 0u); size_t resultSize = aggregate->getType().getObjectSize(); @@ -2019,7 +2128,8 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate } // static -TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink) +TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics) { TOperator op = aggregate->getOp(); TIntermSequence *sequence = aggregate->getSequence(); @@ -2045,7 +2155,7 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg maxObjectSize = objectSizes[i]; } - if (!(*sequence)[0]->getAsTyped()->isMatrix()) + if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct) { for (unsigned int i = 0; i < paramsCount; i++) if (objectSizes[i] != maxObjectSize) @@ -2060,284 +2170,298 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg // switch (op) { - case EOpAtan: + case EOpAtan: { - if (basicType == EbtFloat) + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) - { - float y = unionArrays[0][i].getFConst(); - float x = unionArrays[1][i].getFConst(); - // Results are undefined if x and y are both 0. - if (x == 0.0f && y == 0.0f) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); - else - resultArray[i].setFConst(atan2f(y, x)); - } + float y = unionArrays[0][i].getFConst(); + float x = unionArrays[1][i].getFConst(); + // Results are undefined if x and y are both 0. + if (x == 0.0f && y == 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else + resultArray[i].setFConst(atan2f(y, x)); } - else - UNREACHABLE(); + break; } - break; - case EOpPow: + case EOpPow: { - if (basicType == EbtFloat) + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) - { - float x = unionArrays[0][i].getFConst(); - float y = unionArrays[1][i].getFConst(); - // Results are undefined if x < 0. - // Results are undefined if x = 0 and y <= 0. - if (x < 0.0f) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); - else if (x == 0.0f && y <= 0.0f) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); - else - resultArray[i].setFConst(powf(x, y)); - } + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + // Results are undefined if x < 0. + // Results are undefined if x = 0 and y <= 0. + if (x < 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else if (x == 0.0f && y <= 0.0f) + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + else + resultArray[i].setFConst(powf(x, y)); } - else - UNREACHABLE(); + break; } - break; - case EOpMod: + case EOpMod: { - if (basicType == EbtFloat) + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) - { - float x = unionArrays[0][i].getFConst(); - float y = unionArrays[1][i].getFConst(); - resultArray[i].setFConst(x - y * floorf(x / y)); - } + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + resultArray[i].setFConst(x - y * floorf(x / y)); } - else - UNREACHABLE(); + break; } - break; - case EOpMin: + case EOpMin: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); - break; - case EbtInt: - resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); - break; - case EbtUInt: - resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), + unionArrays[1][i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), + unionArrays[1][i].getIConst())); + break; + case EbtUInt: + resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), + unionArrays[1][i].getUConst())); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpMax: + case EOpMax: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst())); - break; - case EbtInt: - resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst())); - break; - case EbtUInt: - resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst())); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), + unionArrays[1][i].getFConst())); + break; + case EbtInt: + resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), + unionArrays[1][i].getIConst())); + break; + case EbtUInt: + resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), + unionArrays[1][i].getUConst())); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpStep: + case EOpStep: { - if (basicType == EbtFloat) - { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) - resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f); - } - else - UNREACHABLE(); + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) + resultArray[i].setFConst( + unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f + : 1.0f); + break; } - break; - case EOpLessThan: + case EOpLessThan: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() < + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() < + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() < + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpLessThanEqual: + case EOpLessThanEqual: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() <= + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() <= + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() <= + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpGreaterThan: + case EOpGreaterThan: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() > + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() > + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() > + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - - case EOpGreaterThanEqual: + case EOpGreaterThanEqual: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() >= + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() >= + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() >= + unionArrays[1][i].getUConst()); + break; + default: + UNREACHABLE(); + break; } } } break; - case EOpVectorEqual: + case EOpVectorEqual: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst()); - break; - case EbtBool: - resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() == + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() == + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() == + unionArrays[1][i].getUConst()); + break; + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() == + unionArrays[1][i].getBConst()); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpVectorNotEqual: + case EOpVectorNotEqual: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: - resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst()); - break; - case EbtInt: - resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst()); - break; - case EbtUInt: - resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst()); - break; - case EbtBool: - resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst()); - break; - default: - UNREACHABLE(); - break; + case EbtFloat: + resultArray[i].setBConst(unionArrays[0][i].getFConst() != + unionArrays[1][i].getFConst()); + break; + case EbtInt: + resultArray[i].setBConst(unionArrays[0][i].getIConst() != + unionArrays[1][i].getIConst()); + break; + case EbtUInt: + resultArray[i].setBConst(unionArrays[0][i].getUConst() != + unionArrays[1][i].getUConst()); + break; + case EbtBool: + resultArray[i].setBConst(unionArrays[0][i].getBConst() != + unionArrays[1][i].getBConst()); + break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpDistance: - if (basicType == EbtFloat) + case EOpDistance: { + ASSERT(basicType == EbtFloat); TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize]; - resultArray = new TConstantUnion(); + resultArray = new TConstantUnion(); for (size_t i = 0; i < maxObjectSize; i++) { float x = unionArrays[0][i].getFConst(); @@ -2345,47 +2469,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg distanceArray[i].setFConst(x - y); } resultArray->setFConst(VectorLength(distanceArray, maxObjectSize)); + break; } - else - UNREACHABLE(); - break; - case EOpDot: - - if (basicType == EbtFloat) - { + case EOpDot: + ASSERT(basicType == EbtFloat); resultArray = new TConstantUnion(); - resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); - } - else - UNREACHABLE(); - break; + resultArray->setFConst( + VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize)); + break; - case EOpCross: - if (basicType == EbtFloat && maxObjectSize == 3) + case EOpCross: { + ASSERT(basicType == EbtFloat && maxObjectSize == 3); resultArray = new TConstantUnion[maxObjectSize]; - float x0 = unionArrays[0][0].getFConst(); - float x1 = unionArrays[0][1].getFConst(); - float x2 = unionArrays[0][2].getFConst(); - float y0 = unionArrays[1][0].getFConst(); - float y1 = unionArrays[1][1].getFConst(); - float y2 = unionArrays[1][2].getFConst(); + float x0 = unionArrays[0][0].getFConst(); + float x1 = unionArrays[0][1].getFConst(); + float x2 = unionArrays[0][2].getFConst(); + float y0 = unionArrays[1][0].getFConst(); + float y1 = unionArrays[1][1].getFConst(); + float y2 = unionArrays[1][2].getFConst(); resultArray[0].setFConst(x1 * y2 - y1 * x2); resultArray[1].setFConst(x2 * y0 - y2 * x0); resultArray[2].setFConst(x0 * y1 - y0 * x1); + break; } - else - UNREACHABLE(); - break; - case EOpReflect: - if (basicType == EbtFloat) + case EOpReflect: { + ASSERT(basicType == EbtFloat); // genType reflect (genType I, genType N) : - // For the incident vector I and surface orientation N, returns the reflection direction: + // For the incident vector I and surface orientation N, returns the reflection + // direction: // I - 2 * dot(N, I) * N. - resultArray = new TConstantUnion[maxObjectSize]; + resultArray = new TConstantUnion[maxObjectSize]; float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); for (size_t i = 0; i < maxObjectSize; i++) { @@ -2393,45 +2510,40 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg 2.0f * dotProduct * unionArrays[1][i].getFConst(); resultArray[i].setFConst(result); } + break; } - else - UNREACHABLE(); - break; - case EOpMul: - if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() && - (*sequence)[1]->getAsTyped()->isMatrix()) + case EOpMul: { + ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() && + (*sequence)[1]->getAsTyped()->isMatrix()); // Perform component-wise matrix multiplication. resultArray = new TConstantUnion[maxObjectSize]; - int size = (*sequence)[0]->getAsTyped()->getNominalSize(); + int size = (*sequence)[0]->getAsTyped()->getNominalSize(); angle::Matrix<float> result = GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size)); SetUnionArrayFromMatrix(result, resultArray); + break; } - else - UNREACHABLE(); - break; - case EOpOuterProduct: - if (basicType == EbtFloat) + case EOpOuterProduct: { + ASSERT(basicType == EbtFloat); size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize(); size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize(); - resultArray = new TConstantUnion[numRows * numCols]; + resultArray = new TConstantUnion[numRows * numCols]; angle::Matrix<float> result = - GetMatrix(unionArrays[0], 1, static_cast<int>(numCols)) - .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1)); + GetMatrix(unionArrays[0], static_cast<int>(numRows), 1) + .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols))); SetUnionArrayFromMatrix(result, resultArray); + break; } - else - UNREACHABLE(); - break; - default: - UNREACHABLE(); - // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above. - return nullptr; + default: + UNREACHABLE(); + // TODO: Add constant folding support for other built-in operations that take 2 + // parameters and not handled above. + return nullptr; } } else if (paramsCount == 3) @@ -2441,124 +2553,123 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg // switch (op) { - case EOpClamp: + case EOpClamp: { resultArray = new TConstantUnion[maxObjectSize]; for (size_t i = 0; i < maxObjectSize; i++) { switch (basicType) { - case EbtFloat: + case EbtFloat: { - float x = unionArrays[0][i].getFConst(); + float x = unionArrays[0][i].getFConst(); float min = unionArrays[1][i].getFConst(); float max = unionArrays[2][i].getFConst(); // Results are undefined if min > max. if (min > max) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); else resultArray[i].setFConst(gl::clamp(x, min, max)); + break; } - break; - case EbtInt: + + case EbtInt: { - int x = unionArrays[0][i].getIConst(); + int x = unionArrays[0][i].getIConst(); int min = unionArrays[1][i].getIConst(); int max = unionArrays[2][i].getIConst(); // Results are undefined if min > max. if (min > max) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); else resultArray[i].setIConst(gl::clamp(x, min, max)); + break; } - break; - case EbtUInt: + case EbtUInt: { - unsigned int x = unionArrays[0][i].getUConst(); + unsigned int x = unionArrays[0][i].getUConst(); unsigned int min = unionArrays[1][i].getUConst(); unsigned int max = unionArrays[2][i].getUConst(); // Results are undefined if min > max. if (min > max) - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); else resultArray[i].setUConst(gl::clamp(x, min, max)); + break; } - break; - default: - UNREACHABLE(); - break; + default: + UNREACHABLE(); + break; } } + break; } - break; - case EOpMix: + case EOpMix: { - if (basicType == EbtFloat) + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + float x = unionArrays[0][i].getFConst(); + float y = unionArrays[1][i].getFConst(); + TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType(); + if (type == EbtFloat) { - float x = unionArrays[0][i].getFConst(); - float y = unionArrays[1][i].getFConst(); - TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType(); - if (type == EbtFloat) - { - // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a. - float a = unionArrays[2][i].getFConst(); - resultArray[i].setFConst(x * (1.0f - a) + y * a); - } - else // 3rd parameter is EbtBool - { - ASSERT(type == EbtBool); - // Selects which vector each returned component comes from. - // For a component of a that is false, the corresponding component of x is returned. - // For a component of a that is true, the corresponding component of y is returned. - bool a = unionArrays[2][i].getBConst(); - resultArray[i].setFConst(a ? y : x); - } + // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a. + float a = unionArrays[2][i].getFConst(); + resultArray[i].setFConst(x * (1.0f - a) + y * a); + } + else // 3rd parameter is EbtBool + { + ASSERT(type == EbtBool); + // Selects which vector each returned component comes from. + // For a component of a that is false, the corresponding component of x is + // returned. + // For a component of a that is true, the corresponding component of y is + // returned. + bool a = unionArrays[2][i].getBConst(); + resultArray[i].setFConst(a ? y : x); } } - else - UNREACHABLE(); + break; } - break; - case EOpSmoothStep: + case EOpSmoothStep: { - if (basicType == EbtFloat) + ASSERT(basicType == EbtFloat); + resultArray = new TConstantUnion[maxObjectSize]; + for (size_t i = 0; i < maxObjectSize; i++) { - resultArray = new TConstantUnion[maxObjectSize]; - for (size_t i = 0; i < maxObjectSize; i++) + float edge0 = unionArrays[0][i].getFConst(); + float edge1 = unionArrays[1][i].getFConst(); + float x = unionArrays[2][i].getFConst(); + // Results are undefined if edge0 >= edge1. + if (edge0 >= edge1) { - float edge0 = unionArrays[0][i].getFConst(); - float edge1 = unionArrays[1][i].getFConst(); - float x = unionArrays[2][i].getFConst(); - // Results are undefined if edge0 >= edge1. - if (edge0 >= edge1) - { - UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]); - } - else - { - // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth - // Hermite interpolation between 0 and 1 when edge0 < x < edge1. - float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); - resultArray[i].setFConst(t * t * (3.0f - 2.0f * t)); - } + UndefinedConstantFoldingError(loc, op, basicType, diagnostics, + &resultArray[i]); + } + else + { + // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth + // Hermite interpolation between 0 and 1 when edge0 < x < edge1. + float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + resultArray[i].setFConst(t * t * (3.0f - 2.0f * t)); } } - else - UNREACHABLE(); + break; } - break; - case EOpFaceForward: - if (basicType == EbtFloat) + case EOpFaceForward: { + ASSERT(basicType == EbtFloat); // genType faceforward(genType N, genType I, genType Nref) : // If dot(Nref, I) < 0 return N, otherwise return -N. - resultArray = new TConstantUnion[maxObjectSize]; + resultArray = new TConstantUnion[maxObjectSize]; float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize); for (size_t i = 0; i < maxObjectSize; i++) { @@ -2567,43 +2678,42 @@ TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *agg else resultArray[i].setFConst(-unionArrays[0][i].getFConst()); } + break; } - else - UNREACHABLE(); - break; - case EOpRefract: - if (basicType == EbtFloat) + case EOpRefract: { + ASSERT(basicType == EbtFloat); // genType refract(genType I, genType N, float eta) : - // For the incident vector I and surface normal N, and the ratio of indices of refraction eta, + // For the incident vector I and surface normal N, and the ratio of indices of + // refraction eta, // return the refraction vector. The result is computed by // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) // if (k < 0.0) // return genType(0.0) // else // return eta * I - (eta * dot(N, I) + sqrt(k)) * N - resultArray = new TConstantUnion[maxObjectSize]; + resultArray = new TConstantUnion[maxObjectSize]; float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize); for (size_t i = 0; i < maxObjectSize; i++) { float eta = unionArrays[2][i].getFConst(); - float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct); + float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct); if (k < 0.0f) resultArray[i].setFConst(0.0f); else resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() - - (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst()); + (eta * dotProduct + sqrtf(k)) * + unionArrays[1][i].getFConst()); } + break; } - else - UNREACHABLE(); - break; - default: - UNREACHABLE(); - // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above. - return nullptr; + default: + UNREACHABLE(); + // TODO: Add constant folding support for other built-in operations that take 3 + // parameters and not handled above. + return nullptr; } } return resultArray; @@ -2675,7 +2785,28 @@ void TIntermTraverser::updateTree() UNUSED_ASSERTION_VARIABLE(replaced); } - mInsertions.clear(); + clearReplacementQueue(); +} + +void TIntermTraverser::clearReplacementQueue() +{ mReplacements.clear(); mMultiReplacements.clear(); + mInsertions.clear(); +} + +void TIntermTraverser::queueReplacement(TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus) +{ + queueReplacementWithParent(getParentNode(), original, replacement, originalStatus); +} + +void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus) +{ + bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD); + mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild)); } diff --git a/chromium/third_party/angle/src/compiler/translator/IntermNode.h b/chromium/third_party/angle/src/compiler/translator/IntermNode.h index 58c8c74379e..f261e76aca3 100644 --- a/chromium/third_party/angle/src/compiler/translator/IntermNode.h +++ b/chromium/third_party/angle/src/compiler/translator/IntermNode.h @@ -27,12 +27,16 @@ #include "compiler/translator/Operator.h" #include "compiler/translator/Types.h" +class TDiagnostics; + class TIntermTraverser; class TIntermAggregate; +class TIntermSwizzle; class TIntermBinary; class TIntermUnary; class TIntermConstantUnion; -class TIntermSelection; +class TIntermTernary; +class TIntermIfElse; class TIntermSwitch; class TIntermCase; class TIntermTyped; @@ -89,9 +93,11 @@ class TIntermNode : angle::NonCopyable virtual TIntermTyped *getAsTyped() { return 0; } virtual TIntermConstantUnion *getAsConstantUnion() { return 0; } virtual TIntermAggregate *getAsAggregate() { return 0; } + virtual TIntermSwizzle *getAsSwizzleNode() { return nullptr; } virtual TIntermBinary *getAsBinaryNode() { return 0; } virtual TIntermUnary *getAsUnaryNode() { return 0; } - virtual TIntermSelection *getAsSelectionNode() { return 0; } + virtual TIntermTernary *getAsTernaryNode() { return nullptr; } + virtual TIntermIfElse *getAsIfElseNode() { return nullptr; } virtual TIntermSwitch *getAsSwitchNode() { return 0; } virtual TIntermCase *getAsCaseNode() { return 0; } virtual TIntermSymbol *getAsSymbolNode() { return 0; } @@ -153,10 +159,13 @@ class TIntermTyped : public TIntermNode const char *getBasicString() const { return mType.getBasicString(); } TString getCompleteString() const { return mType.getCompleteString(); } - int getArraySize() const { return mType.getArraySize(); } + unsigned int getArraySize() const { return mType.getArraySize(); } bool isConstructorWithOnlyConstantUnionParameters(); + static TIntermTyped *CreateIndexNode(int index); + static TIntermTyped *CreateZero(const TType &type); + protected: TType mType; @@ -195,6 +204,10 @@ class TIntermLoop : public TIntermNode TIntermTyped *getExpression() { return mExpr; } TIntermAggregate *getBody() { return mBody; } + void setCondition(TIntermTyped *condition) { mCond = condition; } + void setExpression(TIntermTyped *expression) { mExpr = expression; } + void setBody(TIntermAggregate *body) { mBody = body; } + void setUnrollFlag(bool flag) { mUnrollFlag = flag; } bool getUnrollFlag() const { return mUnrollFlag; } @@ -310,6 +323,7 @@ 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); } @@ -337,6 +351,7 @@ class TIntermConstantUnion : public TIntermTyped void replaceConstantUnion(const TConstantUnion *safeConstantUnion) { + ASSERT(safeConstantUnion); // Previous union pointer freed on pool deallocation. mUnionArrayPointer = safeConstantUnion; } @@ -345,13 +360,17 @@ class TIntermConstantUnion : public TIntermTyped void traverse(TIntermTraverser *it) override; bool replaceChildNode(TIntermNode *, TIntermNode *) override { return false; } - TConstantUnion *foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink); - TConstantUnion *foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink); - TConstantUnion *foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink); + 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); - static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate, - TInfoSink &infoSink); - static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink); + static TConstantUnion *FoldAggregateConstructor(TIntermAggregate *aggregate); + static TConstantUnion *FoldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics); protected: // Same data may be shared between multiple constant unions, so it can't be modified. @@ -359,7 +378,9 @@ class TIntermConstantUnion : public TIntermTyped private: typedef float(*FloatTypeUnaryFunc) (float); - bool foldFloatTypeUnary(const TConstantUnion ¶meter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const; + void foldFloatTypeUnary(const TConstantUnion ¶meter, + FloatTypeUnaryFunc builtinFunc, + TConstantUnion *result) const; TIntermConstantUnion(const TIntermConstantUnion &node); // Note: not deleted, just private! }; @@ -371,7 +392,6 @@ class TIntermOperator : public TIntermTyped { public: TOperator getOp() const { return mOp; } - void setOp(TOperator op) { mOp = op; } bool isAssignment() const; bool isMultiplication() const; @@ -392,18 +412,52 @@ 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. + TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right); TIntermTyped *deepCopy() const override { return new TIntermBinary(*this); } + static TOperator GetMulOpBasedOnOperands(const TType &left, const TType &right); + static TOperator GetMulAssignOpBasedOnOperands(const TType &left, const TType &right); + TIntermBinary *getAsBinaryNode() override { return this; }; void traverse(TIntermTraverser *it) override; bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; @@ -413,12 +467,9 @@ 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; } - bool promote(TInfoSink &); - TIntermTyped *fold(TInfoSink &infoSink); + TIntermTyped *fold(TDiagnostics *diagnostics); void setAddIndexClamp() { mAddIndexClamp = true; } bool getAddIndexClamp() { return mAddIndexClamp; } @@ -431,6 +482,8 @@ class TIntermBinary : public TIntermOperator bool mAddIndexClamp; private: + void promote(); + TIntermBinary(const TIntermBinary &node); // Note: not deleted, just private! }; @@ -440,14 +493,7 @@ class TIntermBinary : public TIntermOperator class TIntermUnary : public TIntermOperator { public: - TIntermUnary(TOperator op, const TType &type) - : TIntermOperator(op, type), - mOperand(NULL), - mUseEmulatedFunction(false) {} - TIntermUnary(TOperator op) - : TIntermOperator(op), - mOperand(NULL), - mUseEmulatedFunction(false) {} + TIntermUnary(TOperator op, TIntermTyped *operand); TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); } @@ -457,10 +503,8 @@ class TIntermUnary : public TIntermOperator bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); } - void setOperand(TIntermTyped *operand) { mOperand = operand; } TIntermTyped *getOperand() { return mOperand; } - void promote(const TType *funcReturnType); - TIntermTyped *fold(TInfoSink &infoSink); + TIntermTyped *fold(TDiagnostics *diagnostics); void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } @@ -473,6 +517,8 @@ class TIntermUnary : public TIntermOperator bool mUseEmulatedFunction; private: + void promote(); + TIntermUnary(const TIntermUnary &node); // note: not deleted, just private! }; @@ -506,6 +552,8 @@ class TIntermAggregate : public TIntermOperator // 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; @@ -513,9 +561,10 @@ class TIntermAggregate : public TIntermOperator bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions); // Conservatively assume function calls and other aggregate operators have side-effects bool hasSideEffects() const override { return true; } - TIntermTyped *fold(TInfoSink &infoSink); + TIntermTyped *fold(TDiagnostics *diagnostics); TIntermSequence *getSequence() { return &mSequence; } + const TIntermSequence *getSequence() const { return &mSequence; } void setNameObj(const TName &name) { mName = name; } const TName &getNameObj() const { return mName; } @@ -555,46 +604,60 @@ class TIntermAggregate : public TIntermOperator TIntermAggregate(const TIntermAggregate &node); // note: not deleted, just private! }; -// -// For if tests. -// -class TIntermSelection : public TIntermTyped +// For ternary operators like a ? b : c. +class TIntermTernary : public TIntermTyped { public: - TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB) - : TIntermTyped(TType(EbtVoid, EbpUndefined)), - mCondition(cond), - mTrueBlock(trueB), - mFalseBlock(falseB) {} - TIntermSelection(TIntermTyped *cond, TIntermNode *trueB, TIntermNode *falseB, - const TType &type) - : TIntermTyped(type), - mCondition(cond), - mTrueBlock(trueB), - mFalseBlock(falseB) {} - - // Note: only supported for ternary operator nodes. - TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); } + TIntermTernary(TIntermTyped *cond, TIntermTyped *trueExpression, TIntermTyped *falseExpression); void traverse(TIntermTraverser *it) override; bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override; - // Conservatively assume selections have side-effects - bool hasSideEffects() const override { return true; } + TIntermTyped *getCondition() const { return mCondition; } + TIntermTyped *getTrueExpression() const { return mTrueExpression; } + TIntermTyped *getFalseExpression() const { return mFalseExpression; } + TIntermTernary *getAsTernaryNode() override { return this; } - 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; } + TIntermTyped *deepCopy() const override { return new TIntermTernary(*this); } - protected: - TIntermTyped *mCondition; - TIntermNode *mTrueBlock; - TIntermNode *mFalseBlock; + bool hasSideEffects() const override + { + return mCondition->hasSideEffects() || mTrueExpression->hasSideEffects() || + mFalseExpression->hasSideEffects(); + } + + static TQualifier DetermineQualifier(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression); private: - TIntermSelection(const TIntermSelection &node); // Note: not deleted, just private! + TIntermTernary(const TIntermTernary &node); // Note: not deleted, just private! + + TIntermTyped *mCondition; + TIntermTyped *mTrueExpression; + TIntermTyped *mFalseExpression; +}; + +class TIntermIfElse : public TIntermNode +{ + public: + TIntermIfElse(TIntermTyped *cond, TIntermAggregate *trueB, TIntermAggregate *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; } + TIntermAggregate *getTrueBlock() const { return mTrueBlock; } + TIntermAggregate *getFalseBlock() const { return mFalseBlock; } + TIntermIfElse *getAsIfElseNode() override { return this; } + + protected: + TIntermTyped *mCondition; + TIntermAggregate *mTrueBlock; + TIntermAggregate *mFalseBlock; }; // @@ -672,24 +735,17 @@ class TIntermTraverser : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); - TIntermTraverser(bool preVisit, bool inVisit, bool postVisit) - : preVisit(preVisit), - inVisit(inVisit), - postVisit(postVisit), - mDepth(0), - mMaxDepth(0), - mInGlobalScope(true), - mTemporaryIndex(nullptr) - { - } - virtual ~TIntermTraverser() {} + TIntermTraverser(bool preVisit, bool inVisit, bool postVisit); + virtual ~TIntermTraverser(); virtual void visitSymbol(TIntermSymbol *node) {} virtual void visitRaw(TIntermRaw *node) {} virtual void visitConstantUnion(TIntermConstantUnion *node) {} + virtual bool 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 visitSelection(Visit visit, TIntermSelection *node) { return true; } + virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; } + virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; } virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; } virtual bool visitCase(Visit visit, TIntermCase *node) { return true; } virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; } @@ -702,9 +758,11 @@ 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 traverseSelection(TIntermSelection *node); + virtual void traverseTernary(TIntermTernary *node); + virtual void traverseIfElse(TIntermIfElse *node); virtual void traverseSwitch(TIntermSwitch *node); virtual void traverseCase(TIntermCase *node); virtual void traverseAggregate(TIntermAggregate *node); @@ -763,36 +821,6 @@ class TIntermTraverser : angle::NonCopyable return !mParentBlockStack.empty() && getParentNode() == mParentBlockStack.back().node; } - const bool preVisit; - const bool inVisit; - const bool postVisit; - - int mDepth; - int mMaxDepth; - - // All the nodes from root to the current node's parent during traversing. - TVector<TIntermNode *> mPath; - - bool mInGlobalScope; - - // To replace a single node with another on the parent node - struct NodeUpdateEntry - { - NodeUpdateEntry(TIntermNode *_parent, - TIntermNode *_original, - TIntermNode *_replacement, - bool _originalBecomesChildOfReplacement) - : parent(_parent), - original(_original), - replacement(_replacement), - originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {} - - TIntermNode *parent; - TIntermNode *original; - TIntermNode *replacement; - bool originalBecomesChildOfReplacement; - }; - // To replace a single node with multiple nodes on the parent aggregate node struct NodeReplaceWithMultipleEntry { @@ -828,13 +856,6 @@ class TIntermTraverser : angle::NonCopyable TIntermSequence insertionsAfter; }; - // During traversing, save all the changes that need to happen into - // mReplacements/mMultiReplacements, then do them by calling updateTree(). - // Multi replacements are processed after single replacements. - std::vector<NodeUpdateEntry> mReplacements; - std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements; - std::vector<NodeInsertMultipleEntry> mInsertions; - // Helper to insert statements in the parent block (sequence) of the node currently being traversed. // The statements will be inserted before the node being traversed once updateTree is called. // Should only be called during PreVisit or PostVisit from sequence nodes. @@ -847,6 +868,9 @@ class TIntermTraverser : angle::NonCopyable void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore, const TIntermSequence &insertionsAfter); + // Helper to insert a single statement. + void insertStatementInParentBlock(TIntermNode *statement); + // Helper to create a temporary symbol node with the given qualifier. TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier); // Helper to create a temporary symbol node. @@ -862,7 +886,60 @@ class TIntermTraverser : angle::NonCopyable // Increment temporary symbol index. void nextTemporaryIndex(); + enum class OriginalNode + { + BECOMES_CHILD, + IS_DROPPED + }; + + void clearReplacementQueue(); + void queueReplacement(TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus); + void queueReplacementWithParent(TIntermNode *parent, + TIntermNode *original, + TIntermNode *replacement, + OriginalNode originalStatus); + + const bool preVisit; + const bool inVisit; + const bool postVisit; + + int mDepth; + int mMaxDepth; + + // All the nodes from root to the current node's parent during traversing. + TVector<TIntermNode *> mPath; + + bool mInGlobalScope; + + // During traversing, save all the changes that need to happen into + // mReplacements/mMultiReplacements, then do them by calling updateTree(). + // Multi replacements are processed after single replacements. + std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements; + std::vector<NodeInsertMultipleEntry> mInsertions; + private: + // To replace a single node with another on the parent node + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement, + bool _originalBecomesChildOfReplacement) + : parent(_parent), + original(_original), + replacement(_replacement), + originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) + { + } + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + bool originalBecomesChildOfReplacement; + }; + struct ParentBlock { ParentBlock(TIntermAggregate *nodeIn, TIntermSequence::size_type posIn) @@ -874,6 +951,9 @@ class TIntermTraverser : angle::NonCopyable TIntermAggregate *node; TIntermSequence::size_type pos; }; + + std::vector<NodeUpdateEntry> mReplacements; + // All the code blocks from the root to the current node's parent during traversal. std::vector<ParentBlock> mParentBlockStack; @@ -899,9 +979,9 @@ class TLValueTrackingTraverser : public TIntermTraverser } virtual ~TLValueTrackingTraverser() {} - void traverseBinary(TIntermBinary *node) override; - void traverseUnary(TIntermUnary *node) override; - void traverseAggregate(TIntermAggregate *node) override; + void traverseBinary(TIntermBinary *node) final; + void traverseUnary(TIntermUnary *node) final; + void traverseAggregate(TIntermAggregate *node) final; protected: bool isLValueRequiredHere() const @@ -969,7 +1049,8 @@ class TMaxDepthTraverser : public TIntermTraverser bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); } bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); } - bool visitSelection(Visit, TIntermSelection *) override { return depthCheck(); } + bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); } + bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); } bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); } bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); } bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); } diff --git a/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.cpp b/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.cpp new file mode 100644 index 00000000000..63075635cf9 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.cpp @@ -0,0 +1,115 @@ +// +// 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. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#include "compiler/translator/IntermNodePatternMatcher.h" + +#include "compiler/translator/IntermNode.h" + +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) +{ +} + +// static +bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node) +{ + return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() && + node->getLeft()->getBasicType() != EbtStruct; +} + +bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr && + !IsNodeBlock(parentNode)) + { + return true; + } + } + + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + if (node->getRight()->hasSideEffects() && + (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode) +{ + // L-value tracking information is needed to check for dynamic indexing in L-value. + // Traversers that don't track l-values can still use this class and match binary nodes with + // this variation of this method if they don't need to check for dynamic indexing in l-values. + ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0); + return matchInternal(node, parentNode); +} + +bool IntermNodePatternMatcher::match(TIntermBinary *node, + TIntermNode *parentNode, + bool isLValueRequiredHere) +{ + if (matchInternal(node, parentNode)) + { + return true; + } + if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0) + { + if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node)) + { + return true; + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode) +{ + if ((mMask & kExpressionReturningArray) != 0) + { + if (parentNode != nullptr) + { + TIntermBinary *parentBinary = parentNode->getAsBinaryNode(); + bool parentIsAssignment = + (parentBinary != nullptr && + (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize)); + + if (node->getType().isArray() && !parentIsAssignment && + (node->isConstructor() || node->getOp() == EOpFunctionCall) && + !IsNodeBlock(parentNode)) + { + return true; + } + } + } + return false; +} + +bool IntermNodePatternMatcher::match(TIntermTernary *node) +{ + if ((mMask & kUnfoldedShortCircuitExpression) != 0) + { + return true; + } + return false; +} diff --git a/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.h b/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.h new file mode 100644 index 00000000000..3e24f8560e1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.h @@ -0,0 +1,53 @@ +// +// 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. +// +// IntermNodePatternMatcher is a helper class for matching node trees to given patterns. +// It can be used whenever the same checks for certain node structures are common to multiple AST +// traversers. +// + +#ifndef COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_ +#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_ + +class TIntermAggregate; +class TIntermBinary; +class TIntermNode; +class TIntermTernary; + +class IntermNodePatternMatcher +{ + public: + static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node); + + enum PatternType + { + // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf + kUnfoldedShortCircuitExpression = 0x0001, + + // Matches expressions that return arrays with the exception of simple statements where a + // constructor or function call result is assigned. + kExpressionReturningArray = 0x0002, + + // Matches dynamic indexing of vectors or matrices in l-values. + kDynamicIndexingOfVectorOrMatrixInLValue = 0x0004 + }; + IntermNodePatternMatcher(const unsigned int mask); + + bool match(TIntermBinary *node, TIntermNode *parentNode); + + // Use this version for checking binary node matches in case you're using flag + // kDynamicIndexingOfVectorOrMatrixInLValue. + bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere); + + bool match(TIntermAggregate *node, TIntermNode *parentNode); + bool match(TIntermTernary *node); + + private: + const unsigned int mMask; + + bool matchInternal(TIntermBinary *node, TIntermNode *parentNode); +}; + +#endif diff --git a/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp index b785c40f14a..189a422d40a 100644 --- a/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp +++ b/chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp @@ -23,6 +23,11 @@ void TIntermConstantUnion::traverse(TIntermTraverser *it) it->traverseConstantUnion(this); } +void TIntermSwizzle::traverse(TIntermTraverser *it) +{ + it->traverseSwizzle(this); +} + void TIntermBinary::traverse(TIntermTraverser *it) { it->traverseBinary(this); @@ -33,9 +38,14 @@ void TIntermUnary::traverse(TIntermTraverser *it) it->traverseUnary(this); } -void TIntermSelection::traverse(TIntermTraverser *it) +void TIntermTernary::traverse(TIntermTraverser *it) +{ + it->traverseTernary(this); +} + +void TIntermIfElse::traverse(TIntermTraverser *it) { - it->traverseSelection(this); + it->traverseIfElse(this); } void TIntermSwitch::traverse(TIntermTraverser *it) @@ -63,6 +73,21 @@ void TIntermBranch::traverse(TIntermTraverser *it) it->traverseBranch(this); } +TIntermTraverser::TIntermTraverser(bool preVisit, bool inVisit, bool postVisit) + : preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + mDepth(0), + mMaxDepth(0), + mInGlobalScope(true), + mTemporaryIndex(nullptr) +{ +} + +TIntermTraverser::~TIntermTraverser() +{ +} + void TIntermTraverser::pushParentBlock(TIntermAggregate *node) { mParentBlockStack.push_back(ParentBlock(node, 0)); @@ -94,6 +119,13 @@ void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &inse mInsertions.push_back(insert); } +void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement) +{ + TIntermSequence insertions; + insertions.push_back(statement); + insertStatementsInParentBlock(insertions); +} + TIntermSymbol *TIntermTraverser::createTempSymbol(const TType &type, TQualifier qualifier) { // Each traversal uses at most one temporary variable, so the index stays the same within a single traversal. @@ -125,10 +157,7 @@ TIntermAggregate *TIntermTraverser::createTempInitDeclaration(TIntermTyped *init ASSERT(initializer != nullptr); TIntermSymbol *tempSymbol = createTempSymbol(initializer->getType(), qualifier); TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration); - TIntermBinary *tempInit = new TIntermBinary(EOpInitialize); - tempInit->setLeft(tempSymbol); - tempInit->setRight(initializer); - tempInit->setType(tempSymbol->getType()); + TIntermBinary *tempInit = new TIntermBinary(EOpInitialize, tempSymbol, initializer); tempDeclaration->getSequence()->push_back(tempInit); return tempDeclaration; } @@ -142,10 +171,7 @@ TIntermBinary *TIntermTraverser::createTempAssignment(TIntermTyped *rightNode) { ASSERT(rightNode != nullptr); TIntermSymbol *tempSymbol = createTempSymbol(rightNode->getType()); - TIntermBinary *assignment = new TIntermBinary(EOpAssign); - assignment->setLeft(tempSymbol); - assignment->setRight(rightNode); - assignment->setType(tempSymbol->getType()); + TIntermBinary *assignment = new TIntermBinary(EOpAssign, tempSymbol, rightNode); return assignment; } @@ -211,6 +237,26 @@ 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. // @@ -551,14 +597,37 @@ void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node) } // -// Traverse a selection node. Same comments in binary node apply here. +// Traverse a ternary node. Same comments in binary node apply here. // -void TIntermTraverser::traverseSelection(TIntermSelection *node) +void TIntermTraverser::traverseTernary(TIntermTernary *node) +{ + bool visit = true; + + if (preVisit) + visit = visitTernary(PreVisit, node); + + if (visit) + { + incrementDepth(node); + node->getCondition()->traverse(this); + if (node->getTrueExpression()) + node->getTrueExpression()->traverse(this); + if (node->getFalseExpression()) + node->getFalseExpression()->traverse(this); + decrementDepth(); + } + + if (visit && postVisit) + visitTernary(PostVisit, node); +} + +// Traverse an if-else node. Same comments in binary node apply here. +void TIntermTraverser::traverseIfElse(TIntermIfElse *node) { bool visit = true; if (preVisit) - visit = visitSelection(PreVisit, node); + visit = visitIfElse(PreVisit, node); if (visit) { @@ -572,7 +641,7 @@ void TIntermTraverser::traverseSelection(TIntermSelection *node) } if (visit && postVisit) - visitSelection(PostVisit, node); + visitIfElse(PostVisit, node); } // diff --git a/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp index 0adb7212b76..57d53bf21ea 100644 --- a/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Intermediate.cpp @@ -38,99 +38,26 @@ TIntermSymbol *TIntermediate::addSymbol( } // -// Connect two nodes with a new parent that does a binary operation on the nodes. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addBinaryMath( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) -{ - // - // Need a new node holding things together then. Make - // one and promote it to the right type. - // - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - - node->setLeft(left); - node->setRight(right); - if (!node->promote(mInfoSink)) - return NULL; - - // See if we can fold constants. - TIntermTyped *foldedNode = node->fold(mInfoSink); - if (foldedNode) - return foldedNode; - - return node; -} - -// -// Connect two nodes through an assignment. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addAssign( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) -{ - if (left->getType().getStruct() || right->getType().getStruct()) - { - if (left->getType() != right->getType()) - { - return NULL; - } - } - - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - - node->setLeft(left); - node->setRight(right); - if (!node->promote(mInfoSink)) - return NULL; - - return node; -} - -// // Connect two nodes through an index operator, where the left node is the base // of an array or struct, and the right node is a direct or indirect offset. // // Returns the added node. // The caller should set the type of the returned node. // -TIntermTyped *TIntermediate::addIndex( - TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &line) -{ - TIntermBinary *node = new TIntermBinary(op); - node->setLine(line); - node->setLeft(base); - node->setRight(index); - - // caller should set the type - - return node; -} - -// -// Add one node as the parent of another that it operates on. -// -// Returns the added node. -// -TIntermTyped *TIntermediate::addUnaryMath( - TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType) +TIntermTyped *TIntermediate::addIndex(TOperator op, + TIntermTyped *base, + TIntermTyped *index, + const TSourceLoc &line, + TDiagnostics *diagnostics) { - // - // Make a new node for the operator. - // - TIntermUnary *node = new TIntermUnary(op); + TIntermBinary *node = new TIntermBinary(op, base, index); node->setLine(line); - node->setOperand(child); - node->promote(funcReturnType); - TIntermTyped *foldedNode = node->fold(mInfoSink); - if (foldedNode) - return foldedNode; + TIntermTyped *folded = node->fold(diagnostics); + if (folded) + { + return folded; + } return node; } @@ -215,11 +142,10 @@ 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 == NULL) - return NULL; + if (node == nullptr) + return nullptr; TIntermAggregate *aggNode = new TIntermAggregate; aggNode->getSequence()->push_back(node); @@ -232,7 +158,7 @@ TIntermAggregate *TIntermediate::makeAggregate( // If the input node is nullptr, return nullptr. // 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) +TIntermAggregate *TIntermediate::EnsureSequence(TIntermNode *node) { if (node == nullptr) return nullptr; @@ -240,42 +166,40 @@ TIntermAggregate *TIntermediate::ensureSequence(TIntermNode *node) if (aggNode != nullptr && aggNode->getOp() == EOpSequence) return aggNode; - aggNode = makeAggregate(node, node->getLine()); + 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 selection node created. -// -TIntermNode *TIntermediate::addSelection( - TIntermTyped *cond, TIntermNodePair nodePair, const TSourceLoc &line) +// Returns the node created. +TIntermNode *TIntermediate::addIfElse(TIntermTyped *cond, + TIntermNodePair nodePair, + const TSourceLoc &line) { - // - // For compile time constant selections, prune the code and - // test now. - // + // For compile time constant conditions, prune the code now. if (cond->getAsConstantUnion()) { if (cond->getAsConstantUnion()->getBConst(0) == true) { - return nodePair.node1 ? setAggregateOperator( - nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL; + return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, + nodePair.node1->getLine()) + : nullptr; } else { - return nodePair.node2 ? setAggregateOperator( - nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL; + return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, + nodePair.node2->getLine()) + : nullptr; } } - TIntermSelection *node = new TIntermSelection( - cond, ensureSequence(nodePair.node1), ensureSequence(nodePair.node2)); + TIntermIfElse *node = + new TIntermIfElse(cond, EnsureSequence(nodePair.node1), EnsureSequence(nodePair.node2)); node->setLine(line); return node; @@ -309,43 +233,37 @@ TIntermTyped *TIntermediate::addComma(TIntermTyped *left, return commaNode; } -// // For "?:" test nodes. There are three children; a condition, // a true path, and a false path. The two paths are specified // as separate parameters. // -// Returns the selection node created, or one of trueBlock and falseBlock if the expression could be folded. -// -TIntermTyped *TIntermediate::addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, - const TSourceLoc &line) +// Returns the ternary node created, or one of trueExpression and falseExpression if the expression +// could be folded. +TIntermTyped *TIntermediate::AddTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &line) { - TQualifier resultQualifier = EvqTemporary; - if (cond->getQualifier() == EvqConst && trueBlock->getQualifier() == EvqConst && - falseBlock->getQualifier() == EvqConst) - { - resultQualifier = EvqConst; - } // Note that the node resulting from here can be a constant union without being qualified as // constant. if (cond->getAsConstantUnion()) { + TQualifier resultQualifier = + TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression); if (cond->getAsConstantUnion()->getBConst(0)) { - trueBlock->getTypePointer()->setQualifier(resultQualifier); - return trueBlock; + trueExpression->getTypePointer()->setQualifier(resultQualifier); + return trueExpression; } else { - falseBlock->getTypePointer()->setQualifier(resultQualifier); - return falseBlock; + falseExpression->getTypePointer()->setQualifier(resultQualifier); + return falseExpression; } } - // - // Make a selection node. - // - TIntermSelection *node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); - node->getTypePointer()->setQualifier(resultQualifier); + // Make a ternary node. + TIntermTernary *node = new TIntermTernary(cond, trueExpression, falseExpression); node->setLine(line); return node; @@ -385,24 +303,22 @@ TIntermConstantUnion *TIntermediate::addConstantUnion(const TConstantUnion *cons return node; } -TIntermTyped *TIntermediate::addSwizzle( - TVectorFields &fields, const TSourceLoc &line) +TIntermTyped *TIntermediate::AddSwizzle(TIntermTyped *baseExpression, + const TVectorFields &fields, + const TSourceLoc &dotLocation) { + 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); - TIntermAggregate *node = new TIntermAggregate(EOpSequence); - - node->setLine(line); - TIntermConstantUnion *constIntNode; - TIntermSequence *sequenceVector = node->getSequence(); - TConstantUnion *unionArray; - - for (int i = 0; i < fields.num; i++) + TIntermTyped *folded = node->fold(); + if (folded) { - unionArray = new TConstantUnion[1]; - unionArray->setIConst(fields.offsets[i]); - constIntNode = addConstantUnion( - unionArray, TType(EbtInt, EbpUndefined, EvqConst), line); - sequenceVector->push_back(constIntNode); + return folded; } return node; @@ -415,7 +331,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, ensureSequence(body)); + TIntermNode *node = new TIntermLoop(type, init, cond, expr, EnsureSequence(body)); node->setLine(line); return node; @@ -443,7 +359,7 @@ TIntermBranch* TIntermediate::addBranch( // This is to be executed once the final root is put on top by the parsing // process. // -TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) +TIntermAggregate *TIntermediate::PostProcess(TIntermNode *root) { if (root == nullptr) return nullptr; @@ -466,7 +382,8 @@ TIntermAggregate *TIntermediate::postProcess(TIntermNode *root) return aggRoot; } -TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate) +TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate, + TDiagnostics *diagnostics) { switch (aggregate->getOp()) { @@ -493,16 +410,14 @@ TIntermTyped *TIntermediate::foldAggregateBuiltIn(TIntermAggregate *aggregate) case EOpFaceForward: case EOpReflect: case EOpRefract: - return aggregate->fold(mInfoSink); + return aggregate->fold(diagnostics); default: // TODO: Add support for folding array constructors if (aggregate->isConstructor() && !aggregate->isArray()) { - return aggregate->fold(mInfoSink); + return aggregate->fold(diagnostics); } // Constant folding not supported for the built-in. return nullptr; } - - return nullptr; } diff --git a/chromium/third_party/angle/src/compiler/translator/Intermediate.h b/chromium/third_party/angle/src/compiler/translator/Intermediate.h index f723fc76481..c4a21d84bb3 100644 --- a/chromium/third_party/angle/src/compiler/translator/Intermediate.h +++ b/chromium/third_party/angle/src/compiler/translator/Intermediate.h @@ -16,34 +16,33 @@ struct TVectorFields }; // -// Set of helper functions to help parse and build the tree. +// Set of helper functions to help build the tree. // -class TInfoSink; class TIntermediate { public: POOL_ALLOCATOR_NEW_DELETE(); - TIntermediate(TInfoSink &i) - : mInfoSink(i) { } + TIntermediate() {} TIntermSymbol *addSymbol( int id, const TString &, const TType &, const TSourceLoc &); - TIntermTyped *addBinaryMath( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addAssign( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addIndex( - TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &); + TIntermTyped *addIndex(TOperator op, + TIntermTyped *base, + TIntermTyped *index, + const TSourceLoc &line, + TDiagnostics *diagnostics); TIntermTyped *addUnaryMath( TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType); TIntermAggregate *growAggregate( TIntermNode *left, TIntermNode *right, const TSourceLoc &); - TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &); - TIntermAggregate *ensureSequence(TIntermNode *node); + static TIntermAggregate *MakeAggregate(TIntermNode *node, const TSourceLoc &line); + static TIntermAggregate *EnsureSequence(TIntermNode *node); TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &); - TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &); - TIntermTyped *addSelection(TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, - const TSourceLoc &line); + TIntermNode *addIfElse(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &line); + static TIntermTyped *AddTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &line); TIntermSwitch *addSwitch( TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line); TIntermCase *addCase( @@ -59,17 +58,17 @@ class TIntermediate TIntermNode *, const TSourceLoc &); TIntermBranch *addBranch(TOperator, const TSourceLoc &); TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &); - TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &); - TIntermAggregate *postProcess(TIntermNode *root); + static TIntermTyped *AddSwizzle(TIntermTyped *baseExpression, + const TVectorFields &fields, + const TSourceLoc &dotLocation); + static TIntermAggregate *PostProcess(TIntermNode *root); static void outputTree(TIntermNode *, TInfoSinkBase &); - TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate); + TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics); private: void operator=(TIntermediate &); // prevent assignments - - TInfoSink & mInfoSink; }; #endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/Operator.cpp b/chromium/third_party/angle/src/compiler/translator/Operator.cpp index 20e47f290e1..57878b93017 100644 --- a/chromium/third_party/angle/src/compiler/translator/Operator.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Operator.cpp @@ -62,8 +62,6 @@ const char *GetOperatorString(TOperator op) case EOpIndexDirectStruct: case EOpIndexDirectInterfaceBlock: return "."; - case EOpVectorSwizzle: return "."; - case EOpRadians: return "radians"; case EOpDegrees: return "degrees"; case EOpSin: return "sin"; @@ -199,3 +197,31 @@ const char *GetOperatorString(TOperator op) return ""; } +bool IsAssignment(TOperator op) +{ + switch (op) + { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + return true; + default: + return false; + } +}
\ No newline at end of file diff --git a/chromium/third_party/angle/src/compiler/translator/Operator.h b/chromium/third_party/angle/src/compiler/translator/Operator.h index b0efb8f48bd..479372111ef 100644 --- a/chromium/third_party/angle/src/compiler/translator/Operator.h +++ b/chromium/third_party/angle/src/compiler/translator/Operator.h @@ -77,8 +77,6 @@ enum TOperator EOpIndexDirectStruct, EOpIndexDirectInterfaceBlock, - EOpVectorSwizzle, - // // Built-in functions potentially mapped to operators // @@ -228,4 +226,7 @@ enum TOperator // Returns the string corresponding to the operator in GLSL const char* GetOperatorString(TOperator op); +// Say whether or not a binary or unary operation changes the value of a variable. +bool IsAssignment(TOperator op); + #endif // COMPILER_TRANSLATOR_OPERATOR_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp index f048b050b7e..32db9de24f0 100644 --- a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -27,11 +27,9 @@ bool isSingleStatement(TIntermNode *node) return (aggregate->getOp() != EOpFunction) && (aggregate->getOp() != EOpSequence); } - else if (const TIntermSelection *selection = node->getAsSelectionNode()) + else if (node->getAsIfElseNode()) { - // Ternary operators are usually part of an assignment operator. - // This handles those rare cases in which they are all by themselves. - return selection->usesTernaryOperator(); + return false; } else if (node->getAsLoopNode()) { @@ -243,20 +241,20 @@ const TConstantUnion *TOutputGLSLBase::writeConstantUnion( return pConstUnion; } -void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType) +void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type) { TInfoSinkBase &out = objSink(); if (visit == PreVisit) { if (type.isArray()) { - out << constructorBaseType; + out << getTypeName(type); out << arrayBrackets(type); out << "("; } else { - out << constructorBaseType << "("; + out << getTypeName(type) << "("; } } else @@ -282,6 +280,17 @@ void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node) writeConstantUnion(node->getType(), node->getUnionArrayPointer()); } +bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = objSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; @@ -357,7 +366,7 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) if (left->isArray()) { // The shader will fail validation if the array length is not > 0. - maxSize = leftType.getArraySize() - 1; + maxSize = static_cast<int>(leftType.getArraySize()) - 1; } else { @@ -412,40 +421,6 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) visitChildren = false; } break; - case EOpVectorSwizzle: - if (visit == InVisit) - { - out << "."; - TIntermAggregate *rightChild = node->getRight()->getAsAggregate(); - TIntermSequence *sequence = rightChild->getSequence(); - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit) - { - TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); - ASSERT(element->getBasicType() == EbtInt); - ASSERT(element->getNominalSize() == 1); - const TConstantUnion& data = element->getUnionArrayPointer()[0]; - ASSERT(data.getType() == EbtInt); - switch (data.getIConst()) - { - case 0: - out << "x"; - break; - case 1: - out << "y"; - break; - case 2: - out << "z"; - break; - case 3: - out << "w"; - break; - default: - UNREACHABLE(); - } - } - visitChildren = false; - } - break; case EOpAdd: writeTriplet(visit, "(", " + ", ")"); @@ -711,40 +686,40 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) return true; } -bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) +bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node) { TInfoSinkBase &out = objSink(); + // Notice two brackets at the beginning and end. The outer ones + // encapsulate the whole ternary expression. This preserves the + // order of precedence when ternary expressions are used in a + // compound expression, i.e., c = 2 * (a < b ? 1 : 2). + out << "(("; + node->getCondition()->traverse(this); + out << ") ? ("; + node->getTrueExpression()->traverse(this); + out << ") : ("; + node->getFalseExpression()->traverse(this); + out << "))"; + return false; +} - if (node->usesTernaryOperator()) - { - // Notice two brackets at the beginning and end. The outer ones - // encapsulate the whole ternary expression. This preserves the - // order of precedence when ternary expressions are used in a - // compound expression, i.e., c = 2 * (a < b ? 1 : 2). - out << "(("; - node->getCondition()->traverse(this); - out << ") ? ("; - node->getTrueBlock()->traverse(this); - out << ") : ("; - node->getFalseBlock()->traverse(this); - out << "))"; - } - else - { - out << "if ("; - node->getCondition()->traverse(this); - out << ")\n"; +bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = objSink(); - incrementDepth(node); - visitCodeBlock(node->getTrueBlock()); + out << "if ("; + node->getCondition()->traverse(this); + out << ")\n"; - if (node->getFalseBlock()) - { - out << "else\n"; - visitCodeBlock(node->getFalseBlock()); - } - decrementDepth(); + incrementDepth(node); + visitCodeBlock(node->getTrueBlock()); + + if (node->getFalseBlock()) + { + out << "else\n"; + visitCodeBlock(node->getFalseBlock()); } + decrementDepth(); return false; } @@ -843,22 +818,19 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) out << " " << hashFunctionNameIfNeeded(node->getNameObj()); incrementDepth(node); - // Function definition node contains one or two children nodes - // representing function parameters and function body. The latter - // is not present in case of empty function bodies. + // Function definition node contains two child nodes representing the function parameters + // and the function body. const TIntermSequence &sequence = *(node->getSequence()); - ASSERT((sequence.size() == 1) || (sequence.size() == 2)); - TIntermSequence::const_iterator seqIter = sequence.begin(); + ASSERT(sequence.size() == 2); // Traverse function parameters. - TIntermAggregate *params = (*seqIter)->getAsAggregate(); + TIntermAggregate *params = sequence[0]->getAsAggregate(); ASSERT(params != NULL); ASSERT(params->getOp() == EOpParameters); params->traverse(this); // Traverse function body. - TIntermAggregate *body = ++seqIter != sequence.end() ? - (*seqIter)->getAsAggregate() : NULL; + TIntermAggregate *body = sequence[1]->getAsAggregate(); visitCodeBlock(body); decrementDepth(); @@ -917,88 +889,33 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) visitChildren = false; break; case EOpConstructFloat: - writeConstructorTriplet(visit, node->getType(), "float"); - break; case EOpConstructVec2: - writeConstructorTriplet(visit, node->getType(), "vec2"); - break; case EOpConstructVec3: - writeConstructorTriplet(visit, node->getType(), "vec3"); - break; case EOpConstructVec4: - writeConstructorTriplet(visit, node->getType(), "vec4"); - break; case EOpConstructBool: - writeConstructorTriplet(visit, node->getType(), "bool"); - break; case EOpConstructBVec2: - writeConstructorTriplet(visit, node->getType(), "bvec2"); - break; case EOpConstructBVec3: - writeConstructorTriplet(visit, node->getType(), "bvec3"); - break; case EOpConstructBVec4: - writeConstructorTriplet(visit, node->getType(), "bvec4"); - break; case EOpConstructInt: - writeConstructorTriplet(visit, node->getType(), "int"); - break; case EOpConstructIVec2: - writeConstructorTriplet(visit, node->getType(), "ivec2"); - break; case EOpConstructIVec3: - writeConstructorTriplet(visit, node->getType(), "ivec3"); - break; case EOpConstructIVec4: - writeConstructorTriplet(visit, node->getType(), "ivec4"); - break; case EOpConstructUInt: - writeConstructorTriplet(visit, node->getType(), "uint"); - break; case EOpConstructUVec2: - writeConstructorTriplet(visit, node->getType(), "uvec2"); - break; case EOpConstructUVec3: - writeConstructorTriplet(visit, node->getType(), "uvec3"); - break; case EOpConstructUVec4: - writeConstructorTriplet(visit, node->getType(), "uvec4"); - break; case EOpConstructMat2: - writeConstructorTriplet(visit, node->getType(), "mat2"); - break; case EOpConstructMat2x3: - writeConstructorTriplet(visit, node->getType(), "mat2x3"); - break; case EOpConstructMat2x4: - writeConstructorTriplet(visit, node->getType(), "mat2x4"); - break; case EOpConstructMat3x2: - writeConstructorTriplet(visit, node->getType(), "mat3x2"); - break; case EOpConstructMat3: - writeConstructorTriplet(visit, node->getType(), "mat3"); - break; case EOpConstructMat3x4: - writeConstructorTriplet(visit, node->getType(), "mat3x4"); - break; case EOpConstructMat4x2: - writeConstructorTriplet(visit, node->getType(), "mat4x2"); - break; case EOpConstructMat4x3: - writeConstructorTriplet(visit, node->getType(), "mat4x3"); - break; case EOpConstructMat4: - writeConstructorTriplet(visit, node->getType(), "mat4"); - break; case EOpConstructStruct: - { - const TType &type = node->getType(); - ASSERT(type.getBasicType() == EbtStruct); - TString constructorName = hashName(type.getStruct()->name()); - writeConstructorTriplet(visit, node->getType(), constructorName.c_str()); - break; - } + writeConstructorTriplet(visit, node->getType()); + break; case EOpOuterProduct: writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction); @@ -1208,45 +1125,10 @@ void TOutputGLSLBase::visitCodeBlock(TIntermNode *node) TString TOutputGLSLBase::getTypeName(const TType &type) { - TInfoSinkBase out; - if (type.isMatrix()) - { - out << "mat"; - out << type.getNominalSize(); - if (type.getSecondarySize() != type.getNominalSize()) - { - out << "x" << type.getSecondarySize(); - } - } - else if (type.isVector()) - { - switch (type.getBasicType()) - { - case EbtFloat: - out << "vec"; - break; - case EbtInt: - out << "ivec"; - break; - case EbtBool: - out << "bvec"; - break; - case EbtUInt: - out << "uvec"; - break; - default: - UNREACHABLE(); - } - out << type.getNominalSize(); - } + if (type.getBasicType() == EbtStruct) + return hashName(type.getStruct()->name()); else - { - if (type.getBasicType() == EbtStruct) - out << hashName(type.getStruct()->name()); - else - out << type.getBasicString(); - } - return TString(out.c_str()); + return type.getBuiltInTypeNameString(); } TString TOutputGLSLBase::hashName(const TString &name) diff --git a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h index 2ae82d15b21..f8df0cd0275 100644 --- a/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h +++ b/chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h @@ -37,14 +37,16 @@ class TOutputGLSLBase : public TIntermTraverser virtual bool writeVariablePrecision(TPrecision precision) = 0; void writeFunctionParameters(const TIntermSequence &args); const TConstantUnion *writeConstantUnion(const TType &type, const TConstantUnion *pConstUnion); - void writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType); + void writeConstructorTriplet(Visit visit, const TType &type); TString getTypeName(const TType &type); void visitSymbol(TIntermSymbol *node) override; void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; bool visitBinary(Visit visit, TIntermBinary *node) override; bool visitUnary(Visit visit, TIntermUnary *node) override; - bool visitSelection(Visit visit, TIntermSelection *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; bool visitSwitch(Visit visit, TIntermSwitch *node) override; bool visitCase(Visit visit, TIntermCase *node) override; bool visitAggregate(Visit visit, TIntermAggregate *node) override; diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp index 3badefd5a51..4ed4b42f562 100644 --- a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp @@ -80,11 +80,14 @@ const TConstantUnion *WriteConstantUnionArray(TInfoSinkBase &out, namespace sh { -OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, - const TExtensionBehavior &extensionBehavior, - const char *sourcePath, ShShaderOutput outputType, - int numRenderTargets, const std::vector<Uniform> &uniforms, - int compileOptions) +OutputHLSL::OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + const std::vector<Uniform> &uniforms, + ShCompileOptions compileOptions) : TIntermTraverser(true, true, true), mShaderType(shaderType), mShaderVersion(shaderVersion), @@ -158,6 +161,12 @@ void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) BuiltInFunctionEmulator builtInFunctionEmulator; InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator); + if ((mCompileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) != 0) + { + InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(&builtInFunctionEmulator, + mShaderVersion); + } + builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot); // Now that we are done changing the AST, do the analyses need for HLSL generation @@ -224,7 +233,7 @@ const std::map<std::string, unsigned int> &OutputHLSL::getUniformRegisterMap() c int OutputHLSL::vectorSize(const TType &type) const { int elementSize = type.isMatrix() ? type.getCols() : 1; - int arraySize = type.isArray() ? type.getArraySize() : 1; + unsigned int arraySize = type.isArray() ? type.getArraySize() : 1u; return elementSize * arraySize; } @@ -605,7 +614,9 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built } } - mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType); + bool getDimensionsIgnoresBaseLevel = + (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0; + mTextureFunctionHLSL->textureFunctionHeader(out, mOutputType, getDimensionsIgnoresBaseLevel); if (mUsesFragCoord) { @@ -837,6 +848,17 @@ bool OutputHLSL::ancestorEvaluatesToSamplerInStruct(Visit visit) return false; } +bool OutputHLSL::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = getInfoSink(); + if (visit == PostVisit) + { + out << "."; + node->writeOffsetsAsXYZW(&out); + } + return true; +} + bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { TInfoSinkBase &out = getInfoSink(); @@ -1055,42 +1077,6 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) return false; } break; - case EOpVectorSwizzle: - if (visit == InVisit) - { - out << "."; - - TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); - - if (swizzle) - { - TIntermSequence *sequence = swizzle->getSequence(); - - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) - { - TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); - - if (element) - { - int i = element->getIConst(0); - - switch (i) - { - case 0: out << "x"; break; - case 1: out << "y"; break; - case 2: out << "z"; break; - case 3: out << "w"; break; - default: UNREACHABLE(); - } - } - else UNREACHABLE(); - } - } - else UNREACHABLE(); - - return false; // Fully processed - } - break; case EOpAdd: outputTriplet(out, visit, "(", " + ", ")"); break; @@ -1294,9 +1280,12 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) outputTriplet(out, visit, "frac(", "", ")"); break; case EOpIsNan: - outputTriplet(out, visit, "isnan(", "", ")"); - mRequiresIEEEStrictCompiling = true; - break; + if (node->getUseEmulatedFunction()) + writeEmulatedFunctionTriplet(out, visit, "isnan("); + else + outputTriplet(out, visit, "isnan(", "", ")"); + mRequiresIEEEStrictCompiling = true; + break; case EOpIsInf: outputTriplet(out, visit, "isinf(", "", ")"); break; @@ -1452,11 +1441,10 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) // Don't output ; after case labels, they're terminated by : // This is needed especially since outputting a ; after a case statement would turn empty // case statements into non-empty case statements, disallowing fall-through from them. - // Also no need to output ; after selection (if) statements or sequences. This is done just - // for code clarity. - TIntermSelection *asSelection = (*sit)->getAsSelectionNode(); - ASSERT(asSelection == nullptr || !asSelection->usesTernaryOperator()); - if ((*sit)->getAsCaseNode() == nullptr && asSelection == nullptr && !IsSequence(*sit)) + // Also no need to output ; after if statements or sequences. This is done just for + // code clarity. + if ((*sit)->getAsCaseNode() == nullptr && (*sit)->getAsIfElseNode() == nullptr && + !IsSequence(*sit)) out << ";\n"; } @@ -1630,19 +1618,13 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << ")\n"; - if (sequence->size() > 1) - { - mInsideFunction = true; - TIntermNode *body = (*sequence)[1]; - // The function body node will output braces. - ASSERT(IsSequence(body)); - body->traverse(this); - mInsideFunction = false; - } - else - { - out << "{}\n"; - } + mInsideFunction = true; + ASSERT(sequence->size() == 2); + TIntermNode *body = (*sequence)[1]; + // The function body node will output braces. + ASSERT(IsSequence(body)); + body->traverse(this); + mInsideFunction = false; mCurrentFunctionMetadata = nullptr; @@ -1677,6 +1659,12 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << DisambiguateFunctionName(node->getSequence()); out << (lod0 ? "Lod0(" : "("); } + else if (node->getNameObj().isInternal()) + { + // This path is used for internal functions that don't have their definitions in the + // AST, such as precision emulation functions. + out << DecorateFunctionIfNeeded(node->getNameObj()) << "("; + } else { TString name = TFunction::unmangleName(node->getNameObj().getString()); @@ -1705,7 +1693,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) TVector<TIntermSymbol *> samplerSymbols; TString structName = samplerNamePrefixFromStruct(typedArg); argType.createSamplerSymbols("angle_" + structName, "", - argType.isArray() ? argType.getArraySize() : 0, + argType.isArray() ? argType.getArraySize() : 0u, &samplerSymbols, nullptr); for (const TIntermSymbol *sampler : samplerSymbols) { @@ -1919,7 +1907,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) return true; } -void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) +void OutputHLSL::writeIfElse(TInfoSinkBase &out, TIntermIfElse *node) { out << "if ("; @@ -1956,8 +1944,8 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) outputLineDirective(out, node->getFalseBlock()->getLine().first_line); - // Either this is "else if" or the falseBlock child node will output braces. - ASSERT(IsSequence(node->getFalseBlock()) || node->getFalseBlock()->getAsSelectionNode() != nullptr); + // The falseBlock child node will output braces. + ASSERT(IsSequence(node->getFalseBlock())); node->getFalseBlock()->traverse(this); @@ -1974,11 +1962,18 @@ void OutputHLSL::writeSelection(TInfoSinkBase &out, TIntermSelection *node) } } -bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) +bool OutputHLSL::visitTernary(Visit, TIntermTernary *) +{ + // Ternary ops should have been already converted to something else in the AST. HLSL ternary + // operator doesn't short-circuit, so it's not the same as the GLSL ternary operator. + UNREACHABLE(); + return false; +} + +bool OutputHLSL::visitIfElse(Visit visit, TIntermIfElse *node) { TInfoSinkBase &out = getInfoSink(); - ASSERT(!node->usesTernaryOperator()); ASSERT(mInsideFunction); // D3D errors when there is a gradient operation in a loop in an unflattened if. @@ -1987,7 +1982,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) out << "FLATTEN "; } - writeSelection(out, node); + writeIfElse(out, node); return false; } @@ -2496,7 +2491,7 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol) { ASSERT(qualifier != EvqOut && qualifier != EvqInOut); TVector<TIntermSymbol *> samplerSymbols; - type.createSamplerSymbols("angle" + nameStr, "", 0, &samplerSymbols, nullptr); + type.createSamplerSymbols("angle" + nameStr, "", 0u, &samplerSymbols, nullptr); for (const TIntermSymbol *sampler : samplerSymbols) { if (mOutputType == SH_HLSL_4_1_OUTPUT) @@ -2864,14 +2859,14 @@ TString OutputHLSL::addArrayConstructIntoFunction(const TType& type) fnOut << "void " << function.functionName << "(out " << typeName << " a[" << type.getArraySize() << "]"; - for (int i = 0; i < type.getArraySize(); ++i) + for (unsigned int i = 0u; i < type.getArraySize(); ++i) { fnOut << ", " << typeName << " b" << i; } fnOut << ")\n" "{\n"; - for (int i = 0; i < type.getArraySize(); ++i) + for (unsigned int i = 0u; i < type.getArraySize(); ++i) { fnOut << " a[" << i << "] = b" << i << ";\n"; } diff --git a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h index e5204e419d9..ab4f9b3b9c8 100644 --- a/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/OutputHLSL.h @@ -30,11 +30,14 @@ typedef std::map<TString, TIntermSymbol*> ReferencedSymbols; class OutputHLSL : public TIntermTraverser { public: - OutputHLSL(sh::GLenum shaderType, int shaderVersion, - const TExtensionBehavior &extensionBehavior, - const char *sourcePath, ShShaderOutput outputType, - int numRenderTargets, const std::vector<Uniform> &uniforms, - int compileOptions); + OutputHLSL(sh::GLenum shaderType, + int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, + ShShaderOutput outputType, + int numRenderTargets, + const std::vector<Uniform> &uniforms, + ShCompileOptions compileOptions); ~OutputHLSL(); @@ -56,9 +59,11 @@ class OutputHLSL : public TIntermTraverser void visitSymbol(TIntermSymbol*); void visitRaw(TIntermRaw*); void visitConstantUnion(TIntermConstantUnion*); + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; bool visitBinary(Visit visit, TIntermBinary*); bool visitUnary(Visit visit, TIntermUnary*); - bool visitSelection(Visit visit, TIntermSelection*); + bool visitTernary(Visit visit, TIntermTernary *); + bool visitIfElse(Visit visit, TIntermIfElse *); bool visitSwitch(Visit visit, TIntermSwitch *); bool visitCase(Visit visit, TIntermCase *); bool visitAggregate(Visit visit, TIntermAggregate*); @@ -101,7 +106,7 @@ class OutputHLSL : public TIntermTraverser TIntermTyped *expression); void writeDeferredGlobalInitializers(TInfoSinkBase &out); - void writeSelection(TInfoSinkBase &out, TIntermSelection *node); + void writeIfElse(TInfoSinkBase &out, TIntermIfElse *node); // Returns the function name TString addStructEqualityFunction(const TStructure &structure); @@ -117,7 +122,7 @@ class OutputHLSL : public TIntermTraverser const TExtensionBehavior &mExtensionBehavior; const char *mSourcePath; const ShShaderOutput mOutputType; - int mCompileOptions; + ShCompileOptions mCompileOptions; bool mInsideFunction; diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp index 9e836d1b5f8..99d696857b7 100644 --- a/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.cpp @@ -132,12 +132,6 @@ bool TParseContext::parseVectorFields(const TString &compString, // //////////////////////////////////////////////////////////////////////// -// -// Track whether errors have occurred. -// -void TParseContext::recover() -{ -} // // Used by flex/bison to output all syntax and parsing errors. @@ -147,10 +141,7 @@ void TParseContext::error(const TSourceLoc &loc, const char *token, const char *extraInfo) { - pp::SourceLocation srcLoc; - srcLoc.file = loc.first_file; - srcLoc.line = loc.first_line; - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, srcLoc, reason, token, extraInfo); + mDiagnostics.error(loc, reason, token, extraInfo); } void TParseContext::warning(const TSourceLoc &loc, @@ -158,10 +149,7 @@ void TParseContext::warning(const TSourceLoc &loc, const char *token, const char *extraInfo) { - pp::SourceLocation srcLoc; - srcLoc.file = loc.first_file; - srcLoc.line = loc.first_line; - mDiagnostics.writeInfo(pp::Diagnostics::PP_WARNING, srcLoc, reason, token, extraInfo); + mDiagnostics.warning(loc, reason, token, extraInfo); } void TParseContext::outOfRangeError(bool isError, @@ -173,7 +161,6 @@ void TParseContext::outOfRangeError(bool isError, if (isError) { error(loc, reason, token, extraInfo); - recover(); } else { @@ -220,87 +207,73 @@ void TParseContext::binaryOpError(const TSourceLoc &line, error(line, " wrong operand types ", op, extraInfo.c_str()); } -bool TParseContext::precisionErrorCheck(const TSourceLoc &line, - TPrecision precision, - TBasicType type) +void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, + TPrecision precision, + TBasicType type) { if (!mChecksPrecisionErrors) - return false; + return; + + if (precision != EbpUndefined && !SupportsPrecision(type)) + { + error(line, "illegal type for precision qualifier", getBasicString(type)); + } + if (precision == EbpUndefined) { switch (type) { case EbtFloat: error(line, "No precision specified for (float)", ""); - return true; + return; case EbtInt: case EbtUInt: UNREACHABLE(); // there's always a predeclared qualifier error(line, "No precision specified (int)", ""); - return true; + return; default: if (IsSampler(type)) { error(line, "No precision specified (sampler)", ""); - return true; + return; } } } - return false; } -// // Both test and if necessary, spit out an error, to see if the node is really // an l-value that can be operated on this way. -// -// Returns true if the was an error. -// -bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped *node) +bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node) { TIntermSymbol *symNode = node->getAsSymbolNode(); TIntermBinary *binaryNode = node->getAsBinaryNode(); + TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); - if (binaryNode) + if (swizzleNode) { - bool errorReturn; + bool ok = checkCanBeLValue(line, op, swizzleNode->getOperand()); + if (ok && swizzleNode->hasDuplicateOffsets()) + { + error(line, " l-value of swizzle cannot have duplicate components", op); + return false; + } + return ok; + } + if (binaryNode) + { switch (binaryNode->getOp()) { case EOpIndexDirect: case EOpIndexIndirect: case EOpIndexDirectStruct: case EOpIndexDirectInterfaceBlock: - return lValueErrorCheck(line, op, binaryNode->getLeft()); - case EOpVectorSwizzle: - errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); - if (!errorReturn) - { - int offset[4] = {0, 0, 0, 0}; - - TIntermTyped *rightNode = binaryNode->getRight(); - TIntermAggregate *aggrNode = rightNode->getAsAggregate(); - - for (TIntermSequence::iterator p = aggrNode->getSequence()->begin(); - p != aggrNode->getSequence()->end(); p++) - { - int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0); - offset[value]++; - if (offset[value] > 1) - { - error(line, " l-value of swizzle cannot have duplicate components", op); - - return true; - } - } - } - - return errorReturn; + return checkCanBeLValue(line, op, binaryNode->getLeft()); default: break; } error(line, " l-value required", op); - - return true; + return false; } const char *symbol = 0; @@ -340,6 +313,27 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + case EvqNumWorkGroups: + message = "can't modify gl_NumWorkGroups"; + break; + case EvqWorkGroupSize: + message = "can't modify gl_WorkGroupSize"; + break; + case EvqWorkGroupID: + message = "can't modify gl_WorkGroupID"; + break; + case EvqLocalInvocationID: + message = "can't modify gl_LocalInvocationID"; + break; + case EvqGlobalInvocationID: + message = "can't modify gl_GlobalInvocationID"; + break; + case EvqLocalInvocationIndex: + message = "can't modify gl_LocalInvocationIndex"; + break; + case EvqComputeIn: + message = "can't modify work group size variable"; + break; default: // // Type that can't be written to? @@ -358,14 +352,14 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn { error(line, " l-value required", op); - return true; + return false; } // // Everything else is okay, no error. // if (message == 0) - return false; + return true; // // If we get here, we have an error and a message. @@ -385,67 +379,47 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc &line, const char *op, TIn error(line, " l-value required", op, extraInfo.c_str()); } - return true; + return false; } -// // Both test, and if necessary spit out an error, to see if the node is really // a constant. -// -// Returns true if the was an error. -// -bool TParseContext::constErrorCheck(TIntermTyped *node) +void TParseContext::checkIsConst(TIntermTyped *node) { - if (node->getQualifier() == EvqConst) - return false; - - error(node->getLine(), "constant expression required", ""); - - return true; + if (node->getQualifier() != EvqConst) + { + error(node->getLine(), "constant expression required", ""); + } } -// // Both test, and if necessary spit out an error, to see if the node is really // an integer. -// -// Returns true if the was an error. -// -bool TParseContext::integerErrorCheck(TIntermTyped *node, const char *token) +void TParseContext::checkIsScalarInteger(TIntermTyped *node, const char *token) { - if (node->isScalarInt()) - return false; - - error(node->getLine(), "integer expression required", token); - - return true; + if (!node->isScalarInt()) + { + error(node->getLine(), "integer expression required", token); + } } -// // Both test, and if necessary spit out an error, to see if we are currently // globally scoped. -// -// Returns true if the was an error. -// -bool TParseContext::globalErrorCheck(const TSourceLoc &line, bool global, const char *token) +bool TParseContext::checkIsAtGlobalLevel(const TSourceLoc &line, const char *token) { - if (global) + if (!symbolTable.atGlobalLevel()) + { + error(line, "only allowed at global scope", token); return false; - - error(line, "only allowed at global scope", token); - + } return true; } -// // For now, keep it simple: if it starts "gl_", it's reserved, independent // of scope. Except, if the symbol table is at the built-in push-level, // which is when we are parsing built-ins. // Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a // webgl shader. -// -// Returns true if there was an error. -// -bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &identifier) +bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &identifier) { static const char *reservedErrMsg = "reserved built-in name"; if (!symbolTable.atBuiltInLevel()) @@ -453,24 +427,19 @@ bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &id if (identifier.compare(0, 3, "gl_") == 0) { error(line, reservedErrMsg, "gl_"); - return true; + return false; } if (IsWebGLBasedSpec(mShaderSpec)) { if (identifier.compare(0, 6, "webgl_") == 0) { error(line, reservedErrMsg, "webgl_"); - return true; + return false; } if (identifier.compare(0, 7, "_webgl_") == 0) { error(line, reservedErrMsg, "_webgl_"); - return true; - } - if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) - { - error(line, reservedErrMsg, "css_"); - return true; + return false; } } if (identifier.find("__") != TString::npos) @@ -479,28 +448,22 @@ bool TParseContext::reservedErrorCheck(const TSourceLoc &line, const TString &id "identifiers containing two consecutive underscores (__) are reserved as " "possible future keywords", identifier.c_str()); - return true; + return false; } } - return false; + return true; } -// // Make sure there is enough data provided to the constructor to build // something of the type of the constructor. Also returns the type of // the constructor. -// -// Returns true if there was an error in construction. -// -bool TParseContext::constructorErrorCheck(const TSourceLoc &line, - TIntermNode *argumentsNode, - TFunction &function, - TOperator op, - TType *type) +bool TParseContext::checkConstructorArguments(const TSourceLoc &line, + TIntermNode *argumentsNode, + const TFunction &function, + TOperator op, + const TType &type) { - *type = function.getReturnType(); - bool constructingMatrix = false; switch (op) { @@ -526,7 +489,6 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, // size_t size = 0; - bool constType = true; bool full = false; bool overFull = false; bool matrixInMatrix = false; @@ -540,75 +502,68 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, matrixInMatrix = true; if (full) overFull = true; - if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + if (op != EOpConstructStruct && !type.isArray() && size >= type.getObjectSize()) full = true; - if (param.type->getQualifier() != EvqConst) - constType = false; if (param.type->isArray()) arrayArg = true; } - if (constType) - type->setQualifier(EvqConst); - - if (type->isArray()) + if (type.isArray()) { - if (type->isUnsizedArray()) - { - type->setArraySize(static_cast<int>(function.getParamCount())); - } - else if (static_cast<size_t>(type->getArraySize()) != function.getParamCount()) + // The size of an unsized constructor should already have been determined. + ASSERT(!type.isUnsizedArray()); + if (static_cast<size_t>(type.getArraySize()) != function.getParamCount()) { error(line, "array constructor needs one argument per array element", "constructor"); - return true; + return false; } } if (arrayArg && op != EOpConstructStruct) { error(line, "constructing from a non-dereferenced array", "constructor"); - return true; + return false; } - if (matrixInMatrix && !type->isArray()) + if (matrixInMatrix && !type.isArray()) { if (function.getParamCount() != 1) { error(line, "constructing matrix from matrix can only take one argument", "constructor"); - return true; + return false; } } if (overFull) { error(line, "too many arguments", "constructor"); - return true; + return false; } - if (op == EOpConstructStruct && !type->isArray() && - type->getStruct()->fields().size() != function.getParamCount()) + if (op == EOpConstructStruct && !type.isArray() && + type.getStruct()->fields().size() != function.getParamCount()) { error(line, "Number of constructor parameters does not match the number of structure fields", "constructor"); - return true; + return false; } - if (!type->isMatrix() || !matrixInMatrix) + if (!type.isMatrix() || !matrixInMatrix) { - if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || - (op == EOpConstructStruct && size < type->getObjectSize())) + if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) || + (op == EOpConstructStruct && size < type.getObjectSize())) { error(line, "not enough data provided for construction", "constructor"); - return true; + return false; } } if (argumentsNode == nullptr) { error(line, "constructor does not have any arguments", "constructor"); - return true; + return false; } TIntermAggregate *argumentsAgg = argumentsNode->getAsAggregate(); @@ -619,16 +574,48 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType())) { error(line, "cannot convert a sampler", "constructor"); - return true; + return false; } if (argTyped->getBasicType() == EbtVoid) { error(line, "cannot convert a void", "constructor"); - return true; + return false; } } - return false; + if (type.isArray()) + { + // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of + // the array. + for (TIntermNode *&argNode : *argumentsAgg->getSequence()) + { + const TType &argType = argNode->getAsTyped()->getType(); + // It has already been checked that the argument is not an array. + ASSERT(!argType.isArray()); + if (!argType.sameElementType(type)) + { + error(line, "Array constructor argument has an incorrect type", "Error"); + return false; + } + } + } + else if (op == EOpConstructStruct) + { + const TFieldList &fields = type.getStruct()->fields(); + TIntermSequence *args = argumentsAgg->getSequence(); + + for (size_t i = 0; i < fields.size(); i++) + { + if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type()) + { + error(line, "Structure constructor arguments do not match structure fields", + "Error"); + return false; + } + } + } + + return true; } // This function checks to see if a void variable has been declared and raise an error message for @@ -636,53 +623,41 @@ bool TParseContext::constructorErrorCheck(const TSourceLoc &line, // // returns true in case of an error // -bool TParseContext::voidErrorCheck(const TSourceLoc &line, +bool TParseContext::checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type) { if (type == EbtVoid) { error(line, "illegal use of type 'void'", identifier.c_str()); - return true; + return false; } - return false; + return true; } // This function checks to see if the node (for the expression) contains a scalar boolean expression -// or not -// -// returns true in case of an error -// -bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TIntermTyped *type) +// or not. +void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type) { if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { error(line, "boolean expression expected", ""); - return true; } - - return false; } // This function checks to see if the node (for the expression) contains a scalar boolean expression -// or not -// -// returns true in case of an error -// -bool TParseContext::boolErrorCheck(const TSourceLoc &line, const TPublicType &pType) +// or not. +void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType) { - if (pType.type != EbtBool || pType.isAggregate()) + if (pType.getBasicType() != EbtBool || pType.isAggregate()) { error(line, "boolean expression expected", ""); - return true; } - - return false; } -bool TParseContext::samplerErrorCheck(const TSourceLoc &line, - const TPublicType &pType, +bool TParseContext::checkIsNotSampler(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, const char *reason) { if (pType.type == EbtStruct) @@ -690,46 +665,49 @@ bool TParseContext::samplerErrorCheck(const TSourceLoc &line, if (containsSampler(*pType.userDef)) { error(line, reason, getBasicString(pType.type), "(structure contains a sampler)"); - - return true; + return false; } - return false; + return true; } else if (IsSampler(pType.type)) { error(line, reason, getBasicString(pType.type)); - - return true; + return false; } - return false; + return true; } -bool TParseContext::locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType) +void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, + const TPublicType &pType) { if (pType.layoutQualifier.location != -1) { error(line, "location must only be specified for a single input or output variable", "location"); - return true; } +} - return false; +void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) +{ + if (layoutQualifier.location != -1) + { + error(location, "invalid layout qualifier:", "location", + "only valid on program inputs and outputs"); + } } -bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc &line, - TQualifier qualifier, - const TType &type) +void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line, + TQualifier qualifier, + const TType &type) { if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { error(line, "samplers cannot be output parameters", type.getBasicString()); - return true; } - - return false; } bool TParseContext::containsSampler(const TType &type) @@ -750,12 +728,8 @@ bool TParseContext::containsSampler(const TType &type) return false; } -// // Do size checking for an array type's size. -// -// Returns true if there was an error. -// -bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size) +unsigned int TParseContext::checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr) { TIntermConstantUnion *constant = expr->getAsConstantUnion(); @@ -765,36 +739,32 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *ex if (expr->getQualifier() != EvqConst || constant == nullptr || !constant->isScalarInt()) { error(line, "array size must be a constant integer expression", ""); - size = 1; - return true; + return 1u; } - unsigned int unsignedSize = 0; + unsigned int size = 0u; if (constant->getBasicType() == EbtUInt) { - unsignedSize = constant->getUConst(0); - size = static_cast<int>(unsignedSize); + size = constant->getUConst(0); } else { - size = constant->getIConst(0); + int signedSize = constant->getIConst(0); - if (size < 0) + if (signedSize < 0) { error(line, "array size must be non-negative", ""); - size = 1; - return true; + return 1u; } - unsignedSize = static_cast<unsigned int>(size); + size = static_cast<unsigned int>(signedSize); } - if (size == 0) + if (size == 0u) { error(line, "array size must be greater than zero", ""); - size = 1; - return true; + return 1u; } // The size of arrays is restricted here to prevent issues further down the @@ -802,70 +772,72 @@ bool TParseContext::arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *ex // 4096 registers so this should be reasonable even for aggressively optimizable code. const unsigned int sizeLimit = 65536; - if (unsignedSize > sizeLimit) + if (size > sizeLimit) { error(line, "array size too large", ""); - size = 1; - return true; + return 1u; } - return false; + return size; } -// // See if this qualifier can be an array. -// -// Returns true if there is an error. -// -bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type) +bool TParseContext::checkIsValidQualifierForArray(const TSourceLoc &line, + const TPublicType &elementQualifier) { - if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || - (type.qualifier == EvqConst && mShaderVersion < 300)) + if ((elementQualifier.qualifier == EvqAttribute) || + (elementQualifier.qualifier == EvqVertexIn) || + (elementQualifier.qualifier == EvqConst && mShaderVersion < 300)) { error(line, "cannot declare arrays of this qualifier", - TType(type).getCompleteString().c_str()); - return true; + TType(elementQualifier).getQualifierString()); + return false; } - return false; + return true; } -// -// See if this type can be an array. -// -// Returns true if there is an error. -// -bool TParseContext::arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type) +// See if this element type can be formed into an array. +bool TParseContext::checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType) { // // Can the type be an array? // - if (type.array) + if (elementType.array) { - error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str()); - return true; + error(line, "cannot declare arrays of arrays", + TType(elementType).getCompleteString().c_str()); + return false; } // In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere. // In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section // 4.3.4). - if (mShaderVersion >= 300 && type.type == EbtStruct && sh::IsVarying(type.qualifier)) + if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct && + sh::IsVarying(elementType.qualifier)) { error(line, "cannot declare arrays of structs of this qualifier", - TType(type).getCompleteString().c_str()); - return true; + TType(elementType).getCompleteString().c_str()); + return false; } + return true; +} + +// Check if this qualified element type can be formed into an array. +bool TParseContext::checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType) +{ + if (checkIsValidTypeForArray(indexLocation, elementType)) + { + return checkIsValidQualifierForArray(indexLocation, elementType); + } return false; } -// // Enforce non-initializer type/qualifier rules. -// -// Returns true if there was an error. -// -bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, - const TString &identifier, - TPublicType *type) +void TParseContext::checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const TString &identifier, + TPublicType *type) { ASSERT(type != nullptr); if (type->qualifier == EvqConst) @@ -886,15 +858,12 @@ bool TParseContext::nonInitErrorCheck(const TSourceLoc &line, { error(line, "variables with qualifier 'const' must be initialized", identifier.c_str()); } - - return true; + return; } if (type->isUnsizedArray()) { error(line, "implicitly sized arrays need to be initialized", identifier.c_str()); - return true; } - return false; } // Do some simple checks that are shared between all variable declarations, @@ -909,18 +878,18 @@ bool TParseContext::declareVariable(const TSourceLoc &line, { ASSERT((*variable) == nullptr); - bool needsReservedErrorCheck = true; + bool needsReservedCheck = true; // gl_LastFragData may be redeclared with a new precision qualifier if (type.isArray() && identifier.compare(0, 15, "gl_LastFragData") == 0) { const TVariable *maxDrawBuffers = static_cast<const TVariable *>( symbolTable.findBuiltIn("gl_MaxDrawBuffers", mShaderVersion)); - if (type.getArraySize() == maxDrawBuffers->getConstPointer()->getIConst()) + if (static_cast<int>(type.getArraySize()) == maxDrawBuffers->getConstPointer()->getIConst()) { if (TSymbol *builtInSymbol = symbolTable.findBuiltIn(identifier, mShaderVersion)) { - needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension()); + needsReservedCheck = !checkCanUseExtension(line, builtInSymbol->getExtension()); } } else @@ -931,7 +900,7 @@ bool TParseContext::declareVariable(const TSourceLoc &line, } } - if (needsReservedErrorCheck && reservedErrorCheck(line, identifier)) + if (needsReservedCheck && !checkIsNotReserved(line, identifier)) return false; (*variable) = new TVariable(&identifier, type); @@ -942,65 +911,59 @@ bool TParseContext::declareVariable(const TSourceLoc &line, return false; } - if (voidErrorCheck(line, identifier, type.getBasicType())) + if (!checkIsNonVoid(line, identifier, type.getBasicType())) return false; return true; } -bool TParseContext::paramErrorCheck(const TSourceLoc &line, - TQualifier qualifier, - TQualifier paramQualifier, - TType *type) +void TParseContext::checkIsParameterQualifierValid( + const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type) { - if (qualifier != EvqConst && qualifier != EvqTemporary) - { - error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier)); - return true; - } - if (qualifier == EvqConst && paramQualifier != EvqIn) + TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics); + + if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut) { - error(line, "qualifier not allowed with ", getQualifierString(qualifier), - getQualifierString(paramQualifier)); - return true; + checkOutParameterIsNotSampler(line, typeQualifier.qualifier, *type); } - if (qualifier == EvqConst) - type->setQualifier(EvqConstReadOnly); - else - type->setQualifier(paramQualifier); + type->setQualifier(typeQualifier.qualifier); - return false; + if (typeQualifier.precision != EbpUndefined) + { + type->setPrecision(typeQualifier.precision); + } } -bool TParseContext::extensionErrorCheck(const TSourceLoc &line, const TString &extension) +bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension) { const TExtensionBehavior &extBehavior = extensionBehavior(); TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str()); if (iter == extBehavior.end()) { error(line, "extension", extension.c_str(), "is not supported"); - return true; + return false; } // In GLSL ES, an extension's default behavior is "disable". if (iter->second == EBhDisable || iter->second == EBhUndefined) { error(line, "extension", extension.c_str(), "is disabled"); - return true; + return false; } if (iter->second == EBhWarn) { warning(line, "extension", extension.c_str(), "is being used"); - return false; + return true; } - return false; + return true; } // These checks are common for all declarations starting a declarator list, and declarators that // follow an empty declaration. -// -bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, +void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation) { switch (publicType.qualifier) @@ -1010,11 +973,12 @@ bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, case EvqAttribute: case EvqVertexIn: case EvqFragmentOut: - if (publicType.type == EbtStruct) + case EvqComputeIn: + if (publicType.getBasicType() == EbtStruct) { error(identifierLocation, "cannot be used with a structure", getQualifierString(publicType.qualifier)); - return true; + return; } default: @@ -1022,9 +986,10 @@ bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, } if (publicType.qualifier != EvqUniform && - samplerErrorCheck(identifierLocation, publicType, "samplers must be uniform")) + !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray, + "samplers must be uniform")) { - return true; + return; } // check for layout qualifier issues @@ -1035,7 +1000,7 @@ bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks"); - return true; + return; } if (layoutQualifier.blockStorage != EbsUnspecified) @@ -1043,59 +1008,83 @@ bool TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType, error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks"); - return true; + return; } - if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut && - layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier)) + if (publicType.qualifier != EvqVertexIn && publicType.qualifier != EvqFragmentOut) { - return true; + checkLocationIsNotSpecified(identifierLocation, publicType.layoutQualifier); } +} - return false; +void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location, + const TString &layoutQualifierName, + int versionRequired) +{ + + if (mShaderVersion < versionRequired) + { + error(location, "invalid layout qualifier:", layoutQualifierName.c_str(), "not supported"); + } } -bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, - const TLayoutQualifier &layoutQualifier) +bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier) { - if (layoutQualifier.location != -1) + const sh::WorkGroupSize &localSize = layoutQualifier.localSize; + for (size_t i = 0u; i < localSize.size(); ++i) { - error(location, "invalid layout qualifier:", "location", - "only valid on program inputs and outputs"); - return true; + if (localSize[i] != -1) + { + error(location, "invalid layout qualifier:", getWorkGroupSizeString(i), + "only valid when used with 'in' in a compute shader global layout declaration"); + return false; + } } - return false; + return true; } -bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, - TIntermAggregate *aggregate) +void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, + TIntermAggregate *fnCall) { for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) { TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); if (qual == EvqOut || qual == EvqInOut) { - TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped(); - if (lValueErrorCheck(node->getLine(), "assign", node)) + TIntermTyped *argument = (*(fnCall->getSequence()))[i]->getAsTyped(); + if (!checkCanBeLValue(argument->getLine(), "assign", argument)) { - error(node->getLine(), + error(argument->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); - recover(); - return true; + return; } } } - return false; } -void TParseContext::es3InvariantErrorCheck(const TQualifier qualifier, - const TSourceLoc &invariantLocation) +void TParseContext::checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation) { - if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut) + if (!invariant) + return; + + if (mShaderVersion < 300) + { + // input variables in the fragment shader can be also qualified as invariant + if (!sh::CanBeInvariantESSL1(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } + } + else { - error(invariantLocation, "Only out variables can be invariant.", "invariant"); - recover(); + if (!sh::CanBeInvariantESSL3OrGreater(qualifier)) + { + error(invariantLocation, "Cannot be qualified as invariant.", "invariant"); + } } } @@ -1132,6 +1121,23 @@ void TParseContext::handlePragmaDirective(const TSourceLoc &loc, mDirectiveHandler.handlePragma(srcLoc, name, value, stdgl); } +sh::WorkGroupSize TParseContext::getComputeShaderLocalSize() const +{ + sh::WorkGroupSize result; + for (size_t i = 0u; i < result.size(); ++i) + { + if (mComputeShaderLocalSizeDeclared && mComputeShaderLocalSize[i] == -1) + { + result[i] = 1; + } + else + { + result[i] = mComputeShaderLocalSize[i]; + } + } + return result; +} + ///////////////////////////////////////////////////////////////////////////////// // // Non-Errors. @@ -1147,22 +1153,19 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, if (!symbol) { error(location, "undeclared identifier", name->c_str()); - recover(); } else if (!symbol->isVariable()) { error(location, "variable expected", name->c_str()); - recover(); } else { variable = static_cast<const TVariable *>(symbol); if (symbolTable.findBuiltIn(variable->getName(), mShaderVersion) && - !variable->getExtension().empty() && - extensionErrorCheck(location, variable->getExtension())) + !variable->getExtension().empty()) { - recover(); + checkCanUseExtension(location, variable->getExtension()); } // Reject shaders using both gl_FragData and gl_FragColor @@ -1194,7 +1197,15 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, " and (gl_FragColor, gl_SecondaryFragColorEXT)"; } error(location, errorMessage, name->c_str()); - recover(); + } + + // GLSL ES 3.1 Revision 4, 7.1.3 Compute Shader Special Variables + if (getShaderType() == GL_COMPUTE_SHADER && !mComputeShaderLocalSizeDeclared && + qualifier == EvqWorkGroupSize) + { + error(location, + "It is an error to use gl_WorkGroupSize before declaring the local group size", + "gl_WorkGroupSize"); } } @@ -1376,66 +1387,82 @@ bool TParseContext::executeInitializer(const TSourceLoc &line, return false; } -TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, - bool invariant, - TLayoutQualifier layoutQualifier, +TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, const TPublicType &typeSpecifier) { + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics); + TPublicType returnType = typeSpecifier; - returnType.qualifier = qualifier; - returnType.invariant = invariant; - returnType.layoutQualifier = layoutQualifier; + returnType.qualifier = typeQualifier.qualifier; + returnType.invariant = typeQualifier.invariant; + returnType.layoutQualifier = typeQualifier.layoutQualifier; + returnType.precision = typeSpecifier.precision; + + if (typeQualifier.precision != EbpUndefined) + { + returnType.precision = typeQualifier.precision; + } + + checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision, + typeSpecifier.getBasicType()); + + checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier, + typeSpecifier.getLine()); + + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier); if (mShaderVersion < 300) { if (typeSpecifier.array) { - error(typeSpecifier.line, "not supported", "first-class array"); - recover(); + error(typeSpecifier.getLine(), "not supported", "first-class array"); returnType.clearArrayness(); } - if (qualifier == EvqAttribute && - (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + if (returnType.qualifier == EvqAttribute && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) { - error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); - recover(); + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); } - if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) && - (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt)) + if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) && + (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt)) { - error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier)); - recover(); + error(typeSpecifier.getLine(), "cannot be bool or int", + getQualifierString(returnType.qualifier)); } } else { - if (!layoutQualifier.isEmpty()) + if (!returnType.layoutQualifier.isEmpty()) { - if (globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout")) - { - recover(); - } + checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout"); } - if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut) + if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || + returnType.qualifier == EvqFragmentOut) { - es3InputOutputTypeCheck(qualifier, typeSpecifier, typeSpecifier.line); + checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, + typeSpecifier.getLine()); + } + if (returnType.qualifier == EvqComputeIn) + { + error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size", + "in"); } } return returnType; } -void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, - const TPublicType &type, - const TSourceLoc &qualifierLocation) +void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation) { // An input/output variable can never be bool or a sampler. Samplers are checked elsewhere. - if (type.type == EbtBool) + if (type.getBasicType() == EbtBool) { error(qualifierLocation, "cannot be bool", getQualifierString(qualifier)); - recover(); } // Specific restrictions apply for vertex shader inputs and fragment shader outputs. @@ -1446,16 +1473,14 @@ void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, if (type.array) { error(qualifierLocation, "cannot be array", getQualifierString(qualifier)); - recover(); } // Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck return; case EvqFragmentOut: // ESSL 3.00 section 4.3.6 - if (type.isMatrix()) + if (type.typeSpecifierNonArray.isMatrix()) { error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier)); - recover(); } // Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck return; @@ -1466,16 +1491,15 @@ void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, // Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of // restrictions. bool typeContainsIntegers = - (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) || - type.isStructureContainingType(EbtUInt)); + (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt || + type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt)); if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut) { error(qualifierLocation, "must use 'flat' interpolation here", getQualifierString(qualifier)); - recover(); } - if (type.type == EbtStruct) + if (type.getBasicType() == EbtStruct) { // ESSL 3.00 sections 4.3.4 and 4.3.6. // These restrictions are only implied by the ESSL 3.00 spec, but @@ -1484,25 +1508,21 @@ void TParseContext::es3InputOutputTypeCheck(const TQualifier qualifier, { error(qualifierLocation, "cannot be an array of structures", getQualifierString(qualifier)); - recover(); } if (type.isStructureContainingArrays()) { error(qualifierLocation, "cannot be a structure containing an array", getQualifierString(qualifier)); - recover(); } if (type.isStructureContainingType(EbtStruct)) { error(qualifierLocation, "cannot be a structure containing a structure", getQualifierString(qualifier)); - recover(); } if (type.isStructureContainingType(EbtBool)) { error(qualifierLocation, "cannot be a structure containing a bool", getQualifierString(qualifier)); - recover(); } } } @@ -1511,8 +1531,35 @@ TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType, const TSourceLoc &identifierOrTypeLocation, const TString &identifier) { - TIntermSymbol *symbol = - intermediate.addSymbol(0, identifier, TType(publicType), identifierOrTypeLocation); + TType type(publicType); + if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && + mDirectiveHandler.pragma().stdgl.invariantAll) + { + TQualifier qualifier = type.getQualifier(); + + // The directive handler has already taken care of rejecting invalid uses of this pragma + // (for example, in ESSL 3.00 fragment shaders), so at this point, flatten it into all + // affected variable declarations: + // + // 1. Built-in special variables which are inputs to the fragment shader. (These are handled + // elsewhere, in TranslatorGLSL.) + // + // 2. Outputs from vertex shaders in ESSL 1.00 and 3.00 (EvqVaryingOut and EvqVertexOut). It + // is actually less likely that there will be bugs in the handling of ESSL 3.00 shaders, but + // the way this is currently implemented we have to enable this compiler option before + // parsing the shader and determining the shading language version it uses. If this were + // implemented as a post-pass, the workaround could be more targeted. + // + // 3. Inputs in ESSL 1.00 fragment shaders (EvqVaryingIn). This is somewhat in violation of + // the specification, but there are desktop OpenGL drivers that expect that this is the + // behavior of the #pragma when specified in ESSL 1.00 fragment shaders. + if (qualifier == EvqVaryingOut || qualifier == EvqVertexOut || qualifier == EvqVaryingIn) + { + type.setInvariant(true); + } + } + + TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, type, identifierOrTypeLocation); bool emptyDeclaration = (identifier == ""); @@ -1530,21 +1577,18 @@ TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType, } else { - if (singleDeclarationErrorCheck(publicType, identifierOrTypeLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierOrTypeLocation); - if (nonInitErrorCheck(identifierOrTypeLocation, identifier, &publicType)) - recover(); + checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &publicType); TVariable *variable = nullptr; - if (!declareVariable(identifierOrTypeLocation, identifier, TType(publicType), &variable)) - recover(); + declareVariable(identifierOrTypeLocation, identifier, type, &variable); if (variable && symbol) symbol->setId(variable->getUniqueId()); } - return intermediate.makeAggregate(symbol, identifierOrTypeLocation); + return TIntermediate::MakeAggregate(symbol, identifierOrTypeLocation); } TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType, @@ -1555,38 +1599,27 @@ TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &public { mDeferredSingleDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType); - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) - { - recover(); - } + checkIsValidTypeAndQualifierForArray(indexLocation, publicType); TType arrayType(publicType); - int size; - if (arraySizeErrorCheck(identifierLocation, indexExpression, size)) - { - recover(); - } + unsigned int size = checkIsValidArraySize(identifierLocation, indexExpression); // Make the type an array even if size check failed. // This ensures useless error messages regarding the variable's non-arrayness won't follow. arrayType.setArraySize(size); TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, arrayType, &variable)) - recover(); + declareVariable(identifierLocation, identifier, arrayType, &variable); TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation); if (variable && symbol) symbol->setId(variable->getUniqueId()); - return intermediate.makeAggregate(symbol, identifierLocation); + return TIntermediate::MakeAggregate(symbol, identifierLocation); } TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType, @@ -1597,8 +1630,7 @@ TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &p { mDeferredSingleDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); TIntermNode *intermNode = nullptr; if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) @@ -1606,11 +1638,10 @@ TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &p // // Build intermediate representation // - return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr; + return intermNode ? TIntermediate::MakeAggregate(intermNode, initLocation) : nullptr; } else { - recover(); return nullptr; } } @@ -1626,24 +1657,18 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration( { mDeferredSingleDeclarationErrorCheck = false; - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) - { - recover(); - } + checkIsValidTypeAndQualifierForArray(indexLocation, publicType); TPublicType arrayType(publicType); - int size = 0; + unsigned int size = 0u; // If indexExpression is nullptr, then the array will eventually get its size implicitly from // the initializer. - if (indexExpression != nullptr && - arraySizeErrorCheck(identifierLocation, indexExpression, size)) + if (indexExpression != nullptr) { - recover(); + size = checkIsValidArraySize(identifierLocation, indexExpression); } // Make the type an array even if size check failed. // This ensures useless error messages regarding the variable's non-arrayness won't follow. @@ -1653,53 +1678,66 @@ TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration( TIntermNode *initNode = nullptr; if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode)) { - return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr; + return initNode ? TIntermediate::MakeAggregate(initNode, initLocation) : nullptr; } else { - recover(); return nullptr; } } -TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc, - const TSourceLoc &identifierLoc, - const TString *identifier, - const TSymbol *symbol) +TIntermAggregate *TParseContext::parseInvariantDeclaration( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &identifierLoc, + const TString *identifier, + const TSymbol *symbol) { - // invariant declaration - if (globalErrorCheck(invariantLoc, symbolTable.atGlobalLevel(), "invariant varying")) + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics); + + if (!typeQualifier.invariant) { - recover(); + error(identifierLoc, "Expected invariant", identifier->c_str()); + return nullptr; + } + if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying")) + { + return nullptr; } - if (!symbol) { error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str()); - recover(); return nullptr; } - else + if (!IsQualifierUnspecified(typeQualifier.qualifier)) { - const TString kGlFrontFacing("gl_FrontFacing"); - if (*identifier == kGlFrontFacing) - { - error(identifierLoc, "identifier should not be declared as invariant", - identifier->c_str()); - recover(); - return nullptr; - } - symbolTable.addInvariantVarying(std::string(identifier->c_str())); - const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); - ASSERT(variable); - const TType &type = variable->getType(); - TIntermSymbol *intermSymbol = - intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc); - - TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc); - aggregate->setOp(EOpInvariantDeclaration); - return aggregate; + error(identifierLoc, "invariant declaration specifies qualifier", + getQualifierString(typeQualifier.qualifier)); + } + if (typeQualifier.precision != EbpUndefined) + { + error(identifierLoc, "invariant declaration specifies precision", + getPrecisionString(typeQualifier.precision)); + } + if (!typeQualifier.layoutQualifier.isEmpty()) + { + error(identifierLoc, "invariant declaration specifies layout", "'layout'"); } + + const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); + ASSERT(variable); + const TType &type = variable->getType(); + + checkInvariantVariableQualifier(typeQualifier.invariant, type.getQualifier(), + typeQualifier.line); + + symbolTable.addInvariantVarying(std::string(identifier->c_str())); + + TIntermSymbol *intermSymbol = + intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc); + + TIntermAggregate *aggregate = TIntermediate::MakeAggregate(intermSymbol, identifierLoc); + aggregate->setOp(EOpInvariantDeclaration); + return aggregate; } TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, @@ -1711,20 +1749,16 @@ TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType, // not performed. if (mDeferredSingleDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); mDeferredSingleDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType); TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, TType(publicType), &variable)) - recover(); + declareVariable(identifierLocation, identifier, TType(publicType), &variable); TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation); @@ -1745,35 +1779,22 @@ TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType, // not performed. if (mDeferredSingleDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); mDeferredSingleDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); - if (nonInitErrorCheck(identifierLocation, identifier, &publicType)) - recover(); + checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &publicType); - if (arrayTypeErrorCheck(arrayLocation, publicType) || - arrayQualifierErrorCheck(arrayLocation, publicType)) - { - recover(); - } - else + if (checkIsValidTypeAndQualifierForArray(arrayLocation, publicType)) { TType arrayType = TType(publicType); - int size; - if (arraySizeErrorCheck(arrayLocation, indexExpression, size)) - { - recover(); - } + unsigned int size = checkIsValidArraySize(arrayLocation, indexExpression); arrayType.setArraySize(size); TVariable *variable = nullptr; - if (!declareVariable(identifierLocation, identifier, arrayType, &variable)) - recover(); + declareVariable(identifierLocation, identifier, arrayType, &variable); TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation); @@ -1797,13 +1818,11 @@ TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicTy // not performed. if (mDeferredSingleDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); mDeferredSingleDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); TIntermNode *intermNode = nullptr; if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode)) @@ -1822,7 +1841,6 @@ TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicTy } else { - recover(); return nullptr; } } @@ -1840,29 +1858,22 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &pub // not performed. if (mDeferredSingleDeclarationErrorCheck) { - if (singleDeclarationErrorCheck(publicType, identifierLocation)) - recover(); + singleDeclarationErrorCheck(publicType, identifierLocation); mDeferredSingleDeclarationErrorCheck = false; } - if (locationDeclaratorListCheck(identifierLocation, publicType)) - recover(); + checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType); - if (arrayTypeErrorCheck(indexLocation, publicType) || - arrayQualifierErrorCheck(indexLocation, publicType)) - { - recover(); - } + checkIsValidTypeAndQualifierForArray(indexLocation, publicType); TPublicType arrayType(publicType); - int size = 0; + unsigned int size = 0u; // If indexExpression is nullptr, then the array will eventually get its size implicitly from // the initializer. - if (indexExpression != nullptr && - arraySizeErrorCheck(identifierLocation, indexExpression, size)) + if (indexExpression != nullptr) { - recover(); + size = checkIsValidArraySize(identifierLocation, indexExpression); } // Make the type an array even if size check failed. // This ensures useless error messages regarding the variable's non-arrayness won't follow. @@ -1883,45 +1894,115 @@ TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &pub } else { - recover(); return nullptr; } } -void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier) +void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) { - if (typeQualifier.qualifier != EvqUniform) - { - error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), - "global layout must be uniform"); - recover(); - return; - } - + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics); const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier; - ASSERT(!layoutQualifier.isEmpty()); - if (mShaderVersion < 300) + checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier, + typeQualifier.line); + + // It should never be the case, but some strange parser errors can send us here. + if (layoutQualifier.isEmpty()) { - error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 only", "layout"); - recover(); + error(typeQualifier.line, "Error during layout qualifier parsing.", "?"); return; } - if (layoutLocationErrorCheck(typeQualifier.line, typeQualifier.layoutQualifier)) + if (!layoutQualifier.isCombinationValid()) { - recover(); + error(typeQualifier.line, "invalid combination:", "layout"); return; } - if (layoutQualifier.matrixPacking != EmpUnspecified) + if (typeQualifier.qualifier == EvqComputeIn) { - mDefaultMatrixPacking = layoutQualifier.matrixPacking; - } + if (mComputeShaderLocalSizeDeclared && + !layoutQualifier.isLocalSizeEqual(mComputeShaderLocalSize)) + { + error(typeQualifier.line, "Work group size does not match the previous declaration", + "layout"); + return; + } - if (layoutQualifier.blockStorage != EbsUnspecified) + if (mShaderVersion < 310) + { + error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout"); + return; + } + + if (!layoutQualifier.localSize.isAnyValueSet()) + { + error(typeQualifier.line, "No local work group size specified", "layout"); + return; + } + + const TVariable *maxComputeWorkGroupSize = static_cast<const TVariable *>( + symbolTable.findBuiltIn("gl_MaxComputeWorkGroupSize", mShaderVersion)); + + const TConstantUnion *maxComputeWorkGroupSizeData = + maxComputeWorkGroupSize->getConstPointer(); + + for (size_t i = 0u; i < layoutQualifier.localSize.size(); ++i) + { + if (layoutQualifier.localSize[i] != -1) + { + mComputeShaderLocalSize[i] = layoutQualifier.localSize[i]; + const int maxComputeWorkGroupSizeValue = maxComputeWorkGroupSizeData[i].getIConst(); + if (mComputeShaderLocalSize[i] < 1 || + mComputeShaderLocalSize[i] > maxComputeWorkGroupSizeValue) + { + std::stringstream errorMessageStream; + errorMessageStream << "Value must be at least 1 and no greater than " + << maxComputeWorkGroupSizeValue; + const std::string &errorMessage = errorMessageStream.str(); + + error(typeQualifier.line, "invalid value:", getWorkGroupSizeString(i), + errorMessage.c_str()); + return; + } + } + } + + mComputeShaderLocalSizeDeclared = true; + } + else { - mDefaultBlockStorage = layoutQualifier.blockStorage; + + if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier)) + { + return; + } + + if (typeQualifier.qualifier != EvqUniform) + { + error(typeQualifier.line, "invalid qualifier:", + getQualifierString(typeQualifier.qualifier), "global layout must be uniform"); + return; + } + + if (mShaderVersion < 300) + { + error(typeQualifier.line, "layout qualifiers supported in GLSL ES 3.00 and above", + "layout"); + return; + } + + checkLocationIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier); + + if (layoutQualifier.matrixPacking != EmpUnspecified) + { + mDefaultMatrixPacking = layoutQualifier.matrixPacking; + } + + if (layoutQualifier.blockStorage != EbsUnspecified) + { + mDefaultBlockStorage = layoutQualifier.blockStorage; + } } } @@ -1938,7 +2019,6 @@ TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction // ESSL 1.00.17 section 4.2.7. // Doesn't apply to ESSL 3.00.4: see section 4.2.3. error(location, "duplicate function prototype declarations are not allowed", "function"); - recover(); } symbolTableFunction->setHasPrototypeDeclaration(); @@ -1973,7 +2053,6 @@ TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction { // ESSL 3.00.4 section 4.2.4. error(location, "local function prototype declarations are not allowed", "function"); - recover(); } return prototype; @@ -1984,23 +2063,31 @@ TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function TIntermAggregate *functionBody, const TSourceLoc &location) { - //?? Check that all paths return a value if return type != void ? - // May be best done as post process phase on intermediate code + // Check that non-void functions have at least one return statement. if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue) { error(location, "function does not return a value:", "", function.getName().c_str()); - recover(); } - TIntermAggregate *aggregate = - intermediate.growAggregate(functionPrototype, functionBody, location); - intermediate.setAggregateOperator(aggregate, EOpFunction, location); - aggregate->setName(function.getMangledName().c_str()); - aggregate->setType(function.getReturnType()); - aggregate->setFunctionId(function.getUniqueId()); + TIntermAggregate *functionNode = new TIntermAggregate(EOpFunction); + functionNode->setLine(location); + + ASSERT(functionPrototype != nullptr); + functionNode->getSequence()->push_back(functionPrototype); + + if (functionBody == nullptr) + { + functionBody = new TIntermAggregate(EOpSequence); + functionBody->setLine(location); + } + functionNode->getSequence()->push_back(functionBody); + + functionNode->setName(function.getMangledName().c_str()); + functionNode->setType(function.getReturnType()); + functionNode->setFunctionId(function.getUniqueId()); symbolTable.pop(); - return aggregate; + return functionNode; } void TParseContext::parseFunctionPrototype(const TSourceLoc &location, @@ -2013,7 +2100,6 @@ void TParseContext::parseFunctionPrototype(const TSourceLoc &location, if (builtIn) { error(location, "built-in functions cannot be redefined", function->getName().c_str()); - recover(); } TFunction *prevDec = @@ -2027,7 +2113,6 @@ void TParseContext::parseFunctionPrototype(const TSourceLoc &location, { // Then this function already has a body. error(location, "function already has a body", function->getName().c_str()); - recover(); } prevDec->setDefined(); // @@ -2043,13 +2128,11 @@ void TParseContext::parseFunctionPrototype(const TSourceLoc &location, if (function->getParamCount() > 0) { error(location, "function cannot take any parameter(s)", function->getName().c_str()); - recover(); } if (function->getReturnType().getBasicType() != EbtVoid) { error(location, "", function->getReturnType().getBasicString(), "main function cannot return a value"); - recover(); } } @@ -2080,7 +2163,6 @@ void TParseContext::parseFunctionPrototype(const TSourceLoc &location, if (!symbolTable.declare(variable)) { error(location, "redefinition", variable->getName().c_str()); - recover(); paramNodes = intermediate.growAggregate( paramNodes, intermediate.addSymbol(0, "", *param.type, location), location); continue; @@ -2124,7 +2206,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF // Therefore overloading or redefining builtin functions is an error. error(location, "Name of a built-in function cannot be redeclared as function", function->getName().c_str()); - recover(); } else if (prevDec) { @@ -2132,7 +2213,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF { error(location, "overloaded functions must have the same return type", function->getReturnType().getBasicString()); - recover(); } for (size_t i = 0; i < prevDec->getParamCount(); ++i) { @@ -2141,7 +2221,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF { error(location, "overloaded functions must have the same parameter qualifiers", function->getParam(i).type->getQualifierString()); - recover(); } } } @@ -2155,7 +2234,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF if (!prevSym->isFunction()) { error(location, "redefinition", function->getName().c_str(), "function"); - recover(); } } else @@ -2186,18 +2264,14 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, { error(location, "no qualifiers allowed for function return", getQualifierString(type.qualifier)); - recover(); } if (!type.layoutQualifier.isEmpty()) { error(location, "no qualifiers allowed for function return", "layout"); - recover(); } // make sure a sampler is not involved as well... - if (samplerErrorCheck(location, type, "samplers can't be function return values")) - { - recover(); - } + checkIsNotSampler(location, type.typeSpecifierNonArray, + "samplers can't be function return values"); if (mShaderVersion < 300) { // Array return values are forbidden, but there's also no valid syntax for declaring array @@ -2209,7 +2283,6 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, // ESSL 1.00.17 section 6.1 Function Definitions error(location, "structures containing arrays can't be function return values", TType(type).getCompleteString().c_str()); - recover(); } } @@ -2220,154 +2293,25 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) { TPublicType publicType = publicTypeIn; - if (publicType.isStructSpecifier) + if (publicType.isStructSpecifier()) { - error(publicType.line, "constructor can't be a structure definition", - getBasicString(publicType.type)); - recover(); + error(publicType.getLine(), "constructor can't be a structure definition", + getBasicString(publicType.getBasicType())); } TOperator op = EOpNull; - if (publicType.userDef) + if (publicType.getUserDef()) { op = EOpConstructStruct; } else { - switch (publicType.type) - { - case EbtFloat: - if (publicType.isMatrix()) - { - switch (publicType.getCols()) - { - case 2: - switch (publicType.getRows()) - { - case 2: - op = EOpConstructMat2; - break; - case 3: - op = EOpConstructMat2x3; - break; - case 4: - op = EOpConstructMat2x4; - break; - } - break; - case 3: - switch (publicType.getRows()) - { - case 2: - op = EOpConstructMat3x2; - break; - case 3: - op = EOpConstructMat3; - break; - case 4: - op = EOpConstructMat3x4; - break; - } - break; - case 4: - switch (publicType.getRows()) - { - case 2: - op = EOpConstructMat4x2; - break; - case 3: - op = EOpConstructMat4x3; - break; - case 4: - op = EOpConstructMat4; - break; - } - break; - } - } - else - { - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructFloat; - break; - case 2: - op = EOpConstructVec2; - break; - case 3: - op = EOpConstructVec3; - break; - case 4: - op = EOpConstructVec4; - break; - } - } - break; - - case EbtInt: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructInt; - break; - case 2: - op = EOpConstructIVec2; - break; - case 3: - op = EOpConstructIVec3; - break; - case 4: - op = EOpConstructIVec4; - break; - } - break; - - case EbtUInt: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructUInt; - break; - case 2: - op = EOpConstructUVec2; - break; - case 3: - op = EOpConstructUVec3; - break; - case 4: - op = EOpConstructUVec4; - break; - } - break; - - case EbtBool: - switch (publicType.getNominalSize()) - { - case 1: - op = EOpConstructBool; - break; - case 2: - op = EOpConstructBVec2; - break; - case 3: - op = EOpConstructBVec3; - break; - case 4: - op = EOpConstructBVec4; - break; - } - break; - - default: - break; - } - + op = sh::TypeToConstructorOperator(TType(publicType)); if (op == EOpNull) { - error(publicType.line, "cannot construct this type", getBasicString(publicType.type)); - recover(); - publicType.type = EbtFloat; + error(publicType.getLine(), "cannot construct this type", + getBasicString(publicType.getBasicType())); + publicType.setBasicType(EbtFloat); op = EOpConstructFloat; } } @@ -2380,52 +2324,36 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn) // This function is used to test for the correctness of the parameters passed to various constructor // functions and also convert them to the right datatype if it is allowed and required. // -// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// Returns a node to add to the tree regardless of if an error was generated or not. // TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, - TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line) { - TIntermAggregate *constructor = arguments->getAsAggregate(); - ASSERT(constructor != nullptr); - - if (type->isArray()) + TType type = fnCall->getReturnType(); + if (type.isUnsizedArray()) { - // GLSL ES 3.00 section 5.4.4: Each argument must be the same type as the element type of - // the array. - TIntermSequence *args = constructor->getSequence(); - for (size_t i = 0; i < args->size(); i++) - { - const TType &argType = (*args)[i]->getAsTyped()->getType(); - // It has already been checked that the argument is not an array. - ASSERT(!argType.isArray()); - if (!argType.sameElementType(*type)) - { - error(line, "Array constructor argument has an incorrect type", "Error"); - recover(); - return nullptr; - } - } + type.setArraySize(static_cast<unsigned int>(fnCall->getParamCount())); } - else if (op == EOpConstructStruct) + bool constType = true; + for (size_t i = 0; i < fnCall->getParamCount(); ++i) { - const TFieldList &fields = type->getStruct()->fields(); - TIntermSequence *args = constructor->getSequence(); - - for (size_t i = 0; i < fields.size(); i++) - { - if (i >= args->size() || (*args)[i]->getAsTyped()->getType() != *fields[i]->type()) - { - error(line, "Structure constructor arguments do not match structure fields", - "Error"); - recover(); + const TConstParameter ¶m = fnCall->getParam(i); + if (param.type->getQualifier() != EvqConst) + constType = false; + } + if (constType) + type.setQualifier(EvqConst); - return 0; - } - } + if (!checkConstructorArguments(line, arguments, *fnCall, op, type)) + { + TIntermTyped *dummyNode = intermediate.setAggregateOperator(nullptr, op, line); + dummyNode->setType(type); + return dummyNode; } + TIntermAggregate *constructor = arguments->getAsAggregate(); + ASSERT(constructor != nullptr); // Turn the argument list itself into a constructor constructor->setOp(op); @@ -2433,17 +2361,19 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, ASSERT(constructor->isConstructor()); // Need to set type before setPrecisionFromChildren() because bool doesn't have precision. - constructor->setType(*type); + constructor->setType(type); // Structs should not be precision qualified, the individual members may be. // Built-in types on the other hand should be precision qualified. if (op != EOpConstructStruct) { constructor->setPrecisionFromChildren(); - type->setPrecision(constructor->getPrecision()); + type.setPrecision(constructor->getPrecision()); } - TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor); + constructor->setType(type); + + TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics); if (constConstructor) { return constConstructor; @@ -2453,169 +2383,36 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, } // -// This function returns the tree representation for the vector field(s) being accessed from contant -// vector. -// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a -// contant node is returned, else an aggregate node is returned (for v.xy). The input to this -// function could either be the symbol node or it could be the intermediate tree representation of -// accessing fields in a constant structure or column of a constant matrix. -// -TIntermTyped *TParseContext::addConstVectorNode(TVectorFields &fields, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) -{ - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - ASSERT(unionArray); - - TConstantUnion *constArray = new TConstantUnion[fields.num]; - - for (int i = 0; i < fields.num; i++) - { - if (fields.offsets[i] >= node->getType().getNominalSize()) - { - std::stringstream extraInfoStream; - extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - fields.offsets[i] = node->getType().getNominalSize() - 1; - } - - constArray[i] = unionArray[fields.offsets[i]]; - } - return intermediate.addConstantUnion(constArray, node->getType(), line); -} - -// -// This function returns the column being accessed from a constant matrix. The values are retrieved -// from the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). -// The input to the function could either be a symbol node (m[0] where m is a constant matrix)that -// represents a constant matrix or it could be the tree representation of the constant matrix -// (s.m1[0] where s is a constant structure) -// -TIntermTyped *TParseContext::addConstMatrixNode(int index, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) -{ - if (index >= node->getType().getCols()) - { - std::stringstream extraInfoStream; - extraInfoStream << "matrix field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - index = node->getType().getCols() - 1; - } - - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - int size = node->getType().getCols(); - return intermediate.addConstantUnion(&unionArray[size * index], node->getType(), line); -} - -// -// This function returns an element of an array accessed from a constant array. The values are -// retrieved from the symbol table and parse-tree is built for the type of the element. The input -// to the function could either be a symbol node (a[0] where a is a constant array)that represents a -// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a -// constant structure) -// -TIntermTyped *TParseContext::addConstArrayNode(int index, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError) -{ - TType arrayElementType = node->getType(); - arrayElementType.clearArrayness(); - - if (index >= node->getType().getArraySize()) - { - std::stringstream extraInfoStream; - extraInfoStream << "array field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, line, "", "[", extraInfo.c_str()); - index = node->getType().getArraySize() - 1; - } - size_t arrayElementSize = arrayElementType.getObjectSize(); - const TConstantUnion *unionArray = node->getUnionArrayPointer(); - return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], node->getType(), - line); -} - -// -// This function returns the value of a particular field inside a constant structure from the symbol -// table. -// If there is an embedded/nested struct, it appropriately calls addConstStructNested or -// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested -// struct. -// -TIntermTyped *TParseContext::addConstStruct(const TString &identifier, - TIntermTyped *node, - const TSourceLoc &line) -{ - const TFieldList &fields = node->getType().getStruct()->fields(); - size_t instanceSize = 0; - - for (size_t index = 0; index < fields.size(); ++index) - { - if (fields[index]->name() == identifier) - { - break; - } - else - { - instanceSize += fields[index]->type()->getObjectSize(); - } - } - - TIntermTyped *typedNode; - TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); - if (tempConstantNode) - { - const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer(); - - // type will be changed in the calling function - typedNode = intermediate.addConstantUnion(constArray + instanceSize, - tempConstantNode->getType(), line); - } - else - { - error(line, "Cannot offset into the structure", "Error"); - recover(); - - return 0; - } - - return typedNode; -} - -// // Interface/uniform blocks // -TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualifier, - const TSourceLoc &nameLine, - const TString &blockName, - TFieldList *fieldList, - const TString *instanceName, - const TSourceLoc &instanceLine, - TIntermTyped *arrayIndex, - const TSourceLoc &arrayIndexLine) +TIntermAggregate *TParseContext::addInterfaceBlock( + const TTypeQualifierBuilder &typeQualifierBuilder, + const TSourceLoc &nameLine, + const TString &blockName, + TFieldList *fieldList, + const TString *instanceName, + const TSourceLoc &instanceLine, + TIntermTyped *arrayIndex, + const TSourceLoc &arrayIndexLine) { - if (reservedErrorCheck(nameLine, blockName)) - recover(); + checkIsNotReserved(nameLine, blockName); + + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics); if (typeQualifier.qualifier != EvqUniform) { error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier), "interface blocks must be uniform"); - recover(); } - TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; - if (layoutLocationErrorCheck(typeQualifier.line, blockLayoutQualifier)) + if (typeQualifier.invariant) { - recover(); + error(typeQualifier.line, "invalid qualifier on interface block member", "invariant"); } + TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier; + checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier); + if (blockLayoutQualifier.matrixPacking == EmpUnspecified) { blockLayoutQualifier.matrixPacking = mDefaultMatrixPacking; @@ -2626,11 +2423,12 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif blockLayoutQualifier.blockStorage = mDefaultBlockStorage; } + checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier); + TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName); if (!symbolTable.declare(blockNameSymbol)) { error(nameLine, "redefinition", blockName.c_str(), "interface block name"); - recover(); } // check for sampler types and apply layout qualifiers @@ -2642,7 +2440,6 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif { error(field->line(), "unsupported type", fieldType->getBasicString(), "sampler types are not allowed in interface blocks"); - recover(); } const TQualifier qualifier = fieldType->getQualifier(); @@ -2654,22 +2451,22 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif default: error(field->line(), "invalid qualifier on interface block member", getQualifierString(qualifier)); - recover(); break; } - // check layout qualifiers - TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); - if (layoutLocationErrorCheck(field->line(), fieldLayoutQualifier)) + if (fieldType->isInvariant()) { - recover(); + error(field->line(), "invalid qualifier on interface block member", "invariant"); } + // check layout qualifiers + TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); + checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier); + if (fieldLayoutQualifier.blockStorage != EbsUnspecified) { error(field->line(), "invalid layout qualifier:", getBlockStorageString(fieldLayoutQualifier.blockStorage), "cannot be used here"); - recover(); } if (fieldLayoutQualifier.matrixPacking == EmpUnspecified) @@ -2687,11 +2484,10 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif } // add array index - int arraySize = 0; - if (arrayIndex != NULL) + unsigned int arraySize = 0; + if (arrayIndex != nullptr) { - if (arraySizeErrorCheck(arrayIndexLine, arrayIndex, arraySize)) - recover(); + arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex); } TInterfaceBlock *interfaceBlock = @@ -2720,14 +2516,12 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif { error(field->line(), "redefinition", field->name().c_str(), "interface block member name"); - recover(); } } } else { - if (reservedErrorCheck(instanceLine, *instanceName)) - recover(); + checkIsNotReserved(instanceLine, *instanceName); // add a symbol for this interface block TVariable *instanceTypeDef = new TVariable(instanceName, interfaceBlockType, false); @@ -2737,14 +2531,13 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif { error(instanceLine, "redefinition", instanceName->c_str(), "interface block instance name"); - recover(); } symbolId = instanceTypeDef->getUniqueId(); symbolName = instanceTypeDef->getName(); } - TIntermAggregate *aggregate = intermediate.makeAggregate( + TIntermAggregate *aggregate = TIntermediate::MakeAggregate( intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line), nameLine); aggregate->setOp(EOpDeclaration); @@ -2753,7 +2546,7 @@ TIntermAggregate *TParseContext::addInterfaceBlock(const TPublicType &typeQualif return aggregate; } -bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier) +void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier) { ++mStructNestingLevel; @@ -2763,10 +2556,7 @@ bool TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString if (mStructNestingLevel > 1) { error(line, "", "Embedded struct definitions are not allowed"); - return true; } - - return false; } void TParseContext::exitStructDeclaration() @@ -2780,16 +2570,16 @@ const int kWebGLMaxStructNesting = 4; } // namespace -bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField &field) +void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field) { if (!IsWebGLBasedSpec(mShaderSpec)) { - return false; + return; } if (field.type()->getBasicType() != EbtStruct) { - return false; + return; } // We're already inside a structure definition at this point, so add @@ -2801,10 +2591,8 @@ bool TParseContext::structNestingErrorCheck(const TSourceLoc &line, const TField << " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting; std::string reason = reasonStream.str(); error(line, reason.c_str(), field.name().c_str(), ""); - return true; + return; } - - return false; } // @@ -2814,8 +2602,6 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc &location, TIntermTyped *indexExpression) { - TIntermTyped *indexedExpression = NULL; - if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector()) { if (baseExpression->getAsSymbolNode()) @@ -2827,7 +2613,11 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, { error(location, " left of '[' is not of type array, matrix, or vector ", "expression"); } - recover(); + + TConstantUnion *unionArray = new TConstantUnion[1]; + unionArray->setFConst(0.0f); + return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), + location); } TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); @@ -2843,171 +2633,117 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, error( location, "", "[", "array indexes for interface blocks arrays must be constant integral expressions"); - recover(); } else if (baseExpression->getQualifier() == EvqFragmentOut) { error(location, "", "[", "array indexes for fragment outputs must be constant integral expressions"); - recover(); } else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData) { error(location, "", "[", "array index for gl_FragData must be constant zero"); - recover(); } } if (indexConstantUnion) { - // If the index is not qualified as constant, the behavior in the spec is undefined. This - // applies even if ANGLE has been able to constant fold it (ANGLE may constant fold - // expressions that are not constant expressions). The most compatible way to handle this - // case is to report a warning instead of an error and force the index to be in the - // correct range. + // If an out-of-range index is not qualified as constant, the behavior in the spec is + // undefined. This applies even if ANGLE has been able to constant fold it (ANGLE may + // constant fold expressions that are not constant expressions). The most compatible way to + // handle this case is to report a warning instead of an error and force the index to be in + // the correct range. bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst; int index = indexConstantUnion->getIConst(0); - if (index < 0) - { - std::stringstream infoStream; - infoStream << index; - std::string info = infoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "negative index", info.c_str()); - index = 0; - } - TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion(); - if (baseConstantUnion) - { - if (baseExpression->isArray()) - { - // constant folding for array indexing - indexedExpression = - addConstArrayNode(index, baseConstantUnion, location, outOfRangeIndexIsError); - } - else if (baseExpression->isVector()) - { - // constant folding for vector indexing - TVectorFields fields; - fields.num = 1; - fields.offsets[0] = - index; // need to do it this way because v.xy sends fields integer array - indexedExpression = - addConstVectorNode(fields, baseConstantUnion, location, outOfRangeIndexIsError); - } - else if (baseExpression->isMatrix()) - { - // constant folding for matrix indexing - indexedExpression = - addConstMatrixNode(index, baseConstantUnion, location, outOfRangeIndexIsError); - } - } - else - { - int safeIndex = -1; - if (baseExpression->isArray()) + int safeIndex = -1; + + if (baseExpression->isArray()) + { + if (baseExpression->getQualifier() == EvqFragData && index > 0) { - if (baseExpression->getQualifier() == EvqFragData && index > 0) + if (mShaderSpec == SH_WEBGL2_SPEC) { - if (mShaderSpec == SH_WEBGL2_SPEC) - { - // Error has been already generated if index is not const. - if (indexExpression->getQualifier() == EvqConst) - { - error(location, "", "[", - "array index for gl_FragData must be constant zero"); - recover(); - } - safeIndex = 0; - } - else if (!isExtensionEnabled("GL_EXT_draw_buffers")) + // Error has been already generated if index is not const. + if (indexExpression->getQualifier() == EvqConst) { - outOfRangeError(outOfRangeIndexIsError, location, "", "[", - "array index for gl_FragData must be zero when " - "GL_EXT_draw_buffers is disabled"); - safeIndex = 0; + error(location, "", "[", + "array index for gl_FragData must be constant zero"); } + safeIndex = 0; } - // Only do generic out-of-range check if similar error hasn't already been reported. - if (safeIndex < 0 && index >= baseExpression->getType().getArraySize()) + else if (!isExtensionEnabled("GL_EXT_draw_buffers")) { - std::stringstream extraInfoStream; - extraInfoStream << "array index out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str()); - safeIndex = baseExpression->getType().getArraySize() - 1; + outOfRangeError(outOfRangeIndexIsError, location, "", "[", + "array index for gl_FragData must be zero when " + "GL_EXT_draw_buffers is disabled"); + safeIndex = 0; } } - else if ((baseExpression->isVector() || baseExpression->isMatrix()) && - baseExpression->getType().getNominalSize() <= index) - { - std::stringstream extraInfoStream; - extraInfoStream << "field selection out of range '" << index << "'"; - std::string extraInfo = extraInfoStream.str(); - outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str()); - safeIndex = baseExpression->getType().getNominalSize() - 1; - } - - // Data of constant unions can't be changed, because it may be shared with other - // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new - // sanitized object. - if (safeIndex != -1) + // Only do generic out-of-range check if similar error hasn't already been reported. + if (safeIndex < 0) { - TConstantUnion *safeConstantUnion = new TConstantUnion(); - safeConstantUnion->setIConst(safeIndex); - indexConstantUnion->replaceConstantUnion(safeConstantUnion); + safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index, + baseExpression->getArraySize(), + "array index out of range", "[]"); } + } + else if (baseExpression->isMatrix()) + { + safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index, + baseExpression->getType().getCols(), + "matrix field selection out of range", "[]"); + } + else if (baseExpression->isVector()) + { + safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index, + baseExpression->getType().getNominalSize(), + "vector field selection out of range", "[]"); + } - indexedExpression = - intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); + ASSERT(safeIndex >= 0); + // Data of constant unions can't be changed, because it may be shared with other + // constant unions or even builtins, like gl_MaxDrawBuffers. Instead use a new + // sanitized object. + if (safeIndex != index) + { + TConstantUnion *safeConstantUnion = new TConstantUnion(); + safeConstantUnion->setIConst(safeIndex); + indexConstantUnion->replaceConstantUnion(safeConstantUnion); } - } - else - { - indexedExpression = - intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location); - } - if (indexedExpression == 0) - { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setFConst(0.0f); - indexedExpression = - intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location); - } - else if (baseExpression->isArray()) - { - TType indexedType = baseExpression->getType(); - indexedType.clearArrayness(); - indexedExpression->setType(indexedType); - } - else if (baseExpression->isMatrix()) - { - indexedExpression->setType(TType(baseExpression->getBasicType(), - baseExpression->getPrecision(), EvqTemporary, - static_cast<unsigned char>(baseExpression->getRows()))); - } - else if (baseExpression->isVector()) - { - indexedExpression->setType( - TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary)); + return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location, + &mDiagnostics); } else { - indexedExpression->setType(baseExpression->getType()); + return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location, + &mDiagnostics); } +} - if (baseExpression->getType().getQualifier() == EvqConst && - indexExpression->getType().getQualifier() == EvqConst) - { - indexedExpression->getTypePointer()->setQualifier(EvqConst); - } - else +int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason, + const char *token) +{ + if (index >= arraySize || index < 0) { - indexedExpression->getTypePointer()->setQualifier(EvqTemporary); + std::stringstream extraInfoStream; + extraInfoStream << "'" << index << "'"; + std::string extraInfo = extraInfoStream.str(); + outOfRangeError(outOfRangeIndexIsError, location, reason, token, extraInfo.c_str()); + if (index < 0) + { + return 0; + } + else + { + return arraySize - 1; + } } - - return indexedExpression; + return index; } TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpression, @@ -3015,12 +2751,10 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre const TString &fieldString, const TSourceLoc &fieldLocation) { - TIntermTyped *indexedExpression = NULL; - if (baseExpression->isArray()) { error(fieldLocation, "cannot apply dot operator to an array", "."); - recover(); + return baseExpression; } if (baseExpression->isVector()) @@ -3031,46 +2765,21 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre { fields.num = 1; fields.offsets[0] = 0; - recover(); } - if (baseExpression->getAsConstantUnion()) - { - // constant folding for vector fields - indexedExpression = addConstVectorNode(fields, baseExpression->getAsConstantUnion(), - fieldLocation, true); - } - else - { - TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation); - indexedExpression = - intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation); - } - if (indexedExpression == nullptr) - { - recover(); - indexedExpression = baseExpression; - } - else - { - // Note that the qualifier set here will be corrected later. - indexedExpression->setType(TType(baseExpression->getBasicType(), - baseExpression->getPrecision(), EvqTemporary, - (unsigned char)(fieldString).size())); - } + return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation); } else if (baseExpression->getBasicType() == EbtStruct) { - bool fieldFound = false; const TFieldList &fields = baseExpression->getType().getStruct()->fields(); if (fields.empty()) { error(dotLocation, "structure has no fields", "Internal Error"); - recover(); - indexedExpression = baseExpression; + return baseExpression; } else { + bool fieldFound = false; unsigned int i; for (i = 0; i < fields.size(); ++i) { @@ -3082,50 +2791,29 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre } if (fieldFound) { - if (baseExpression->getAsConstantUnion()) - { - indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation); - if (indexedExpression == 0) - { - recover(); - indexedExpression = baseExpression; - } - else - { - indexedExpression->setType(*fields[i]->type()); - } - } - else - { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped *index = intermediate.addConstantUnion( - unionArray, *fields[i]->type(), fieldLocation); - indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, - index, dotLocation); - indexedExpression->setType(*fields[i]->type()); - } + TIntermTyped *index = TIntermTyped::CreateIndexNode(i); + index->setLine(fieldLocation); + return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, + dotLocation, &mDiagnostics); } else { error(dotLocation, " no such field in structure", fieldString.c_str()); - recover(); - indexedExpression = baseExpression; + return baseExpression; } } } else if (baseExpression->isInterfaceBlock()) { - bool fieldFound = false; const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields(); if (fields.empty()) { error(dotLocation, "interface block has no fields", "Internal Error"); - recover(); - indexedExpression = baseExpression; + return baseExpression; } else { + bool fieldFound = false; unsigned int i; for (i = 0; i < fields.size(); ++i) { @@ -3137,19 +2825,15 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre } if (fieldFound) { - TConstantUnion *unionArray = new TConstantUnion[1]; - unionArray->setIConst(i); - TIntermTyped *index = - intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation); - indexedExpression = intermediate.addIndex(EOpIndexDirectInterfaceBlock, - baseExpression, index, dotLocation); - indexedExpression->setType(*fields[i]->type()); + TIntermTyped *index = TIntermTyped::CreateIndexNode(i); + index->setLine(fieldLocation); + return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index, + dotLocation, &mDiagnostics); } else { error(dotLocation, " no such field in interface block", fieldString.c_str()); - recover(); - indexedExpression = baseExpression; + return baseExpression; } } } @@ -3167,30 +2851,14 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre "side", fieldString.c_str()); } - recover(); - indexedExpression = baseExpression; - } - - if (baseExpression->getQualifier() == EvqConst) - { - indexedExpression->getTypePointer()->setQualifier(EvqConst); - } - else - { - indexedExpression->getTypePointer()->setQualifier(EvqTemporary); + return baseExpression; } - - return indexedExpression; } TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc &qualifierTypeLine) { - TLayoutQualifier qualifier; - - qualifier.location = -1; - qualifier.matrixPacking = EmpUnspecified; - qualifier.blockStorage = EbsUnspecified; + TLayoutQualifier qualifier = TLayoutQualifier::create(); if (qualifierType == "shared") { @@ -3216,139 +2884,119 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp { error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), "location requires an argument"); - recover(); } else { error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); - recover(); } return qualifier; } +void TParseContext::parseLocalSize(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize) +{ + checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); + if (intValue < 1) + { + std::string errorMessage = std::string(getWorkGroupSizeString(index)) + " must be positive"; + error(intValueLine, "out of range:", intValueString.c_str(), errorMessage.c_str()); + } + (*localSize)[index] = intValue; +} + TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, const TSourceLoc &qualifierTypeLine, - const TString &intValueString, int intValue, const TSourceLoc &intValueLine) { - TLayoutQualifier qualifier; + TLayoutQualifier qualifier = TLayoutQualifier::create(); - qualifier.location = -1; - qualifier.matrixPacking = EmpUnspecified; - qualifier.blockStorage = EbsUnspecified; + std::string intValueString = Str(intValue); - if (qualifierType != "location") - { - error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(), - "only location may have arguments"); - recover(); - } - else + if (qualifierType == "location") { // must check that location is non-negative if (intValue < 0) { error(intValueLine, "out of range:", intValueString.c_str(), "location must be non-negative"); - recover(); } else { qualifier.location = intValue; + qualifier.locationsSpecified = 1; } } - - return qualifier; -} - -TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, - TLayoutQualifier rightQualifier) -{ - TLayoutQualifier joinedQualifier = leftQualifier; - - if (rightQualifier.location != -1) + else if (qualifierType == "local_size_x") + { + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 0u, + &qualifier.localSize); + } + else if (qualifierType == "local_size_y") { - joinedQualifier.location = rightQualifier.location; + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 1u, + &qualifier.localSize); } - if (rightQualifier.matrixPacking != EmpUnspecified) + else if (qualifierType == "local_size_z") { - joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, + &qualifier.localSize); } - if (rightQualifier.blockStorage != EbsUnspecified) + else { - joinedQualifier.blockStorage = rightQualifier.blockStorage; + error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); } - return joinedQualifier; + return qualifier; } -TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, - TQualifier interpolationQualifier, - const TSourceLoc &storageLoc, - TQualifier storageQualifier) +TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc) { - TQualifier mergedQualifier = EvqSmoothIn; + return new TTypeQualifierBuilder( + new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc), + mShaderVersion); +} - if (storageQualifier == EvqFragmentIn) - { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqSmoothIn; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatIn; - else - UNREACHABLE(); - } - else if (storageQualifier == EvqCentroidIn) - { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqCentroidIn; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatIn; - else - UNREACHABLE(); - } - else if (storageQualifier == EvqVertexOut) - { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqSmoothOut; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatOut; - else - UNREACHABLE(); - } - else if (storageQualifier == EvqCentroidOut) - { - if (interpolationQualifier == EvqSmooth) - mergedQualifier = EvqCentroidOut; - else if (interpolationQualifier == EvqFlat) - mergedQualifier = EvqFlatOut; - else - UNREACHABLE(); - } - else - { - error(interpolationLoc, - "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", - getInterpolationString(interpolationQualifier)); - recover(); +TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation) +{ + return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation, + &mDiagnostics); +} - mergedQualifier = storageQualifier; - } +TFieldList *TParseContext::addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + TFieldList *fieldList) +{ + TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics); - TPublicType type; - type.setBasic(EbtVoid, mergedQualifier, storageLoc); - return type; + typeSpecifier->qualifier = typeQualifier.qualifier; + typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier; + typeSpecifier->invariant = typeQualifier.invariant; + if (typeQualifier.precision != EbpUndefined) + { + typeSpecifier->precision = typeQualifier.precision; + } + return addStructDeclaratorList(*typeSpecifier, fieldList); } TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList) { - if (voidErrorCheck(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type)) - { - recover(); - } + checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision, + typeSpecifier.getBasicType()); + + checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType()); + + checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier); for (unsigned int i = 0; i < fieldList->size(); ++i) { @@ -3356,59 +3004,51 @@ TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecif // Careful not to replace already known aspects of type, like array-ness // TType *type = (*fieldList)[i]->type(); - type->setBasicType(typeSpecifier.type); - type->setPrimarySize(typeSpecifier.primarySize); - type->setSecondarySize(typeSpecifier.secondarySize); + type->setBasicType(typeSpecifier.getBasicType()); + type->setPrimarySize(typeSpecifier.getPrimarySize()); + type->setSecondarySize(typeSpecifier.getSecondarySize()); type->setPrecision(typeSpecifier.precision); type->setQualifier(typeSpecifier.qualifier); type->setLayoutQualifier(typeSpecifier.layoutQualifier); + type->setInvariant(typeSpecifier.invariant); // don't allow arrays of arrays if (type->isArray()) { - if (arrayTypeErrorCheck(typeSpecifier.line, typeSpecifier)) - recover(); + checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier); } if (typeSpecifier.array) - type->setArraySize(typeSpecifier.arraySize); - if (typeSpecifier.userDef) + type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize)); + if (typeSpecifier.getUserDef()) { - type->setStruct(typeSpecifier.userDef->getStruct()); + type->setStruct(typeSpecifier.getUserDef()->getStruct()); } - if (structNestingErrorCheck(typeSpecifier.line, *(*fieldList)[i])) - { - recover(); - } + checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]); } return fieldList; } -TPublicType TParseContext::addStructure(const TSourceLoc &structLine, - const TSourceLoc &nameLine, - const TString *structName, - TFieldList *fieldList) +TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, + const TSourceLoc &nameLine, + const TString *structName, + TFieldList *fieldList) { TStructure *structure = new TStructure(structName, fieldList); TType *structureType = new TType(structure); // Store a bool in the struct if we're at global scope, to allow us to // skip the local struct scoping workaround in HLSL. - structure->setUniqueId(TSymbolTable::nextUniqueId()); structure->setAtGlobalScope(symbolTable.atGlobalLevel()); if (!structName->empty()) { - if (reservedErrorCheck(nameLine, *structName)) - { - recover(); - } + checkIsNotReserved(nameLine, *structName); TVariable *userTypeDef = new TVariable(structName, *structureType, true); if (!symbolTable.declare(userTypeDef)) { error(nameLine, "redefinition", structName->c_str(), "struct"); - recover(); } } @@ -3425,18 +3065,23 @@ TPublicType TParseContext::addStructure(const TSourceLoc &structLine, default: error(field.line(), "invalid qualifier on struct member", getQualifierString(qualifier)); - recover(); break; } + if (field.type()->isInvariant()) + { + error(field.line(), "invalid qualifier on struct member", "invariant"); + } + + checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); } - TPublicType publicType; - publicType.setBasic(EbtStruct, EvqTemporary, structLine); - publicType.userDef = structureType; - publicType.isStructSpecifier = true; + TTypeSpecifierNonArray typeSpecifierNonArray; + typeSpecifierNonArray.initialize(EbtStruct, structLine); + typeSpecifierNonArray.userDef = structureType; + typeSpecifierNonArray.isStructSpecifier = true; exitStructDeclaration(); - return publicType; + return typeSpecifierNonArray; } TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, @@ -3449,7 +3094,6 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, { error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch"); - recover(); return nullptr; } @@ -3457,7 +3101,6 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, { if (!ValidateSwitch::validate(switchType, this, statementList, loc)) { - recover(); return nullptr; } } @@ -3466,7 +3109,6 @@ TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, if (node == nullptr) { error(loc, "erroneous switch statement", "switch"); - recover(); return nullptr; } return node; @@ -3477,20 +3119,17 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l if (mSwitchNestingLevel == 0) { error(loc, "case labels need to be inside switch statements", "case"); - recover(); return nullptr; } if (condition == nullptr) { error(loc, "case label must have a condition", "case"); - recover(); return nullptr; } if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || condition->isMatrix() || condition->isArray() || condition->isVector()) { error(condition->getLine(), "case label must be a scalar integer", "case"); - recover(); } TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); // TODO(oetuaho@nvidia.com): Get rid of the conditionConst == nullptr check once all constant @@ -3499,13 +3138,11 @@ TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &l if (condition->getQualifier() != EvqConst || conditionConst == nullptr) { error(condition->getLine(), "case label must be constant", "case"); - recover(); } TIntermCase *node = intermediate.addCase(condition, loc); if (node == nullptr) { error(loc, "erroneous case statement", "case"); - recover(); return nullptr; } return node; @@ -3516,14 +3153,12 @@ TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) if (mSwitchNestingLevel == 0) { error(loc, "default labels need to be inside switch statements", "default"); - recover(); return nullptr; } TIntermCase *node = intermediate.addCase(nullptr, loc); if (node == nullptr) { error(loc, "erroneous default statement", "default"); - recover(); return nullptr; } return node; @@ -3562,7 +3197,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, case EOpNegative: case EOpPositive: if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool || - child->isArray()) + child->isArray() || IsSampler(child->getBasicType())) { return nullptr; } @@ -3571,7 +3206,14 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op, break; } - return intermediate.addUnaryMath(op, child, loc, funcReturnType); + TIntermUnary *node = new TIntermUnary(op, child); + node->setLine(loc); + + TIntermTyped *foldedNode = node->fold(&mDiagnostics); + if (foldedNode) + return foldedNode; + + return node; } TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) @@ -3580,7 +3222,6 @@ TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, con if (node == nullptr) { unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); - recover(); return child; } return node; @@ -3590,8 +3231,7 @@ TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc) { - if (lValueErrorCheck(loc, GetOperatorString(op), child)) - recover(); + checkCanBeLValue(loc, GetOperatorString(op), child); return addUnaryMath(op, child, loc); } @@ -3600,6 +3240,28 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *right, const TSourceLoc &loc) { + if (left->getType().getStruct() || right->getType().getStruct()) + { + switch (op) + { + case EOpIndexDirectStruct: + ASSERT(left->getType().getStruct()); + break; + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + if (left->getType() != right->getType()) + { + return false; + } + break; + default: + error(loc, "Invalid operation for structs", GetOperatorString(op)); + return false; + } + } + if (left->isArray() || right->isArray()) { if (mShaderVersion < 300) @@ -3673,8 +3335,10 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, return false; } - // Check that type sizes match exactly on ops that require that. - // Also check restrictions for structs that contain arrays or samplers. + // Check that: + // 1. Type sizes match exactly on ops that require that. + // 2. Restrictions for structs that contain arrays or samplers are respected. + // 3. Arithmetic op type dimensionality restrictions for ops other than multiply are respected. switch (op) { case EOpAssign: @@ -3707,6 +3371,48 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, { return false; } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + if ((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix())) + { + return false; + } + + // Are the sizes compatible? + if (left->getNominalSize() != right->getNominalSize() || + left->getSecondarySize() != right->getSecondarySize()) + { + // If the nominal sizes of operands do not match: + // One of them must be a scalar. + if (!left->isScalar() && !right->isScalar()) + return false; + + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if (!right->isScalar() && + (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight)) + return false; + } + break; default: break; } @@ -3714,6 +3420,49 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, return true; } +bool TParseContext::isMultiplicationTypeCombinationValid(TOperator op, + const TType &left, + const TType &right) +{ + switch (op) + { + case EOpMul: + case EOpMulAssign: + return left.getNominalSize() == right.getNominalSize() && + left.getSecondarySize() == right.getSecondarySize(); + case EOpVectorTimesScalar: + return true; + case EOpVectorTimesScalarAssign: + ASSERT(!left.isMatrix() && !right.isMatrix()); + return left.isVector() && !right.isVector(); + case EOpVectorTimesMatrix: + return left.getNominalSize() == right.getRows(); + case EOpVectorTimesMatrixAssign: + ASSERT(!left.isMatrix() && right.isMatrix()); + return left.isVector() && left.getNominalSize() == right.getRows() && + left.getNominalSize() == right.getCols(); + case EOpMatrixTimesVector: + return left.getCols() == right.getNominalSize(); + case EOpMatrixTimesScalar: + return true; + case EOpMatrixTimesScalarAssign: + ASSERT(left.isMatrix() && !right.isMatrix()); + return !right.isVector(); + case EOpMatrixTimesMatrix: + return left.getCols() == right.getRows(); + case EOpMatrixTimesMatrixAssign: + ASSERT(left.isMatrix() && right.isMatrix()); + // We need to check two things: + // 1. The matrix multiplication step is valid. + // 2. The result will have the same number of columns as the lvalue. + return left.getCols() == right.getRows() && left.getCols() == right.getCols(); + + default: + UNREACHABLE(); + return false; + } +} + TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, @@ -3731,8 +3480,9 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - ASSERT(!left->isArray() && !right->isArray()); - if (left->isMatrix() || left->isVector() || left->getBasicType() == EbtStruct) + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->isMatrix() || left->isVector()) { return nullptr; } @@ -3740,7 +3490,8 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, case EOpLogicalOr: case EOpLogicalXor: case EOpLogicalAnd: - ASSERT(!left->isArray() && !right->isArray()); + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector()) { return nullptr; @@ -3750,28 +3501,44 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, case EOpSub: case EOpDiv: case EOpMul: - ASSERT(!left->isArray() && !right->isArray()); - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); + if (left->getBasicType() == EbtBool) { return nullptr; } break; case EOpIMod: - ASSERT(!left->isArray() && !right->isArray()); + ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() && + !right->getType().getStruct()); // Note that this is only for the % operator, not for mod() - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || - left->getBasicType() == EbtFloat) + if (left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) { return nullptr; } break; - // Note that for bitwise ops, type checking is done in promote() to - // share code between ops and compound assignment default: break; } - return intermediate.addBinaryMath(op, left, right, loc); + if (op == EOpMul) + { + op = TIntermBinary::GetMulOpBasedOnOperands(left->getType(), right->getType()); + if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + return nullptr; + } + } + + TIntermBinary *node = new TIntermBinary(op, left, right); + node->setLine(loc); + + // See if we can fold constants. + TIntermTyped *foldedNode = node->fold(&mDiagnostics); + if (foldedNode) + return foldedNode; + + return node; } TIntermTyped *TParseContext::addBinaryMath(TOperator op, @@ -3784,7 +3551,6 @@ TIntermTyped *TParseContext::addBinaryMath(TOperator op, { binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); - recover(); return left; } return node; @@ -3800,7 +3566,6 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, { binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); - recover(); TConstantUnion *unionArray = new TConstantUnion[1]; unionArray->setBConst(false); return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @@ -3816,7 +3581,18 @@ TIntermTyped *TParseContext::createAssign(TOperator op, { if (binaryOpCommonCheck(op, left, right, loc)) { - return intermediate.addAssign(op, left, right, loc); + if (op == EOpMulAssign) + { + op = TIntermBinary::GetMulAssignOpBasedOnOperands(left->getType(), right->getType()); + if (!isMultiplicationTypeCombinationValid(op, left->getType(), right->getType())) + { + return nullptr; + } + } + TIntermBinary *node = new TIntermBinary(op, left, right); + node->setLine(loc); + + return node; } return nullptr; } @@ -3830,7 +3606,6 @@ TIntermTyped *TParseContext::addAssign(TOperator op, if (node == nullptr) { assignError(loc, "assign", left->getCompleteString(), right->getCompleteString()); - recover(); return left; } return node; @@ -3840,6 +3615,18 @@ TIntermTyped *TParseContext::addComma(TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc) { + // WebGL2 section 5.26, the following results in an error: + // "Sequence operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && (left->isArray() || left->getBasicType() == EbtVoid || + left->getType().isStructureContainingArrays() || + right->isArray() || right->getBasicType() == EbtVoid || + right->getType().isStructureContainingArrays())) + { + error(loc, + "sequence operator is not allowed for void, arrays, or structs containing arrays", + ","); + } + return intermediate.addComma(left, right, loc, mShaderVersion); } @@ -3851,21 +3638,18 @@ TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) if (mLoopNestingLevel <= 0) { error(loc, "continue statement only allowed in loops", ""); - recover(); } break; case EOpBreak: if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) { error(loc, "break statement only allowed in loops and switch statements", ""); - recover(); } break; case EOpReturn: if (mCurrentFunctionType->getBasicType() != EbtVoid) { error(loc, "non-void function must return a value", "return"); - recover(); } break; default: @@ -3884,12 +3668,10 @@ TIntermBranch *TParseContext::addBranch(TOperator op, if (mCurrentFunctionType->getBasicType() == EbtVoid) { error(loc, "void function cannot return a value", "return"); - recover(); } else if (*mCurrentFunctionType != returnValue->getType()) { error(loc, "function return is not matching type:", "return"); - recover(); } return intermediate.addBranch(op, returnValue, loc); } @@ -3923,7 +3705,6 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) TString unmangledName = TFunction::unmangleName(name); error(functionCall->getLine(), "Texture offset must be a constant expression", unmangledName.c_str()); - recover(); } else { @@ -3940,7 +3721,6 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) std::string token = tokenStream.str(); error(offset->getLine(), "Texture offset value out of valid range", token.c_str()); - recover(); } } } @@ -3965,17 +3745,14 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, if (fnCall->getName() != "length") { error(loc, "invalid method", fnCall->getName().c_str()); - recover(); } else if (paramNode != nullptr) { error(loc, "method takes no parameters", "length"); - recover(); } else if (typedThis == nullptr || !typedThis->isArray()) { error(loc, "length can only be called on arrays", "length"); - recover(); } else { @@ -3993,7 +3770,6 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, // length method applied". error(loc, "length can only be called on array names, not on array expressions", "length"); - recover(); } } unionArray->setIConst(arraySize); @@ -4002,26 +3778,8 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, } else if (op != EOpNull) { - // // Then this should be a constructor. - // Don't go through the symbol table for constructors. - // Their parameters will be verified algorithmically. - // - TType type(EbtVoid, EbpUndefined); // use this to get the type back - if (!constructorErrorCheck(loc, paramNode, *fnCall, op, &type)) - { - // - // It's a constructor, of type 'type'. - // - callNode = addConstructor(paramNode, &type, op, fnCall, loc); - } - - if (callNode == nullptr) - { - recover(); - callNode = intermediate.setAggregateOperator(nullptr, op, loc); - } - callNode->setType(type); + callNode = addConstructor(paramNode, op, fnCall, loc); } else { @@ -4036,10 +3794,9 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, // // A declared function. // - if (builtIn && !fnCandidate->getExtension().empty() && - extensionErrorCheck(loc, fnCandidate->getExtension())) + if (builtIn && !fnCandidate->getExtension().empty()) { - recover(); + checkCanUseExtension(loc, fnCandidate->getExtension()); } op = fnCandidate->getBuiltInOp(); if (builtIn && op != EOpNull) @@ -4085,7 +3842,8 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, // See if we can constant fold a built-in. Note that this may be possible even // if it is not const-qualified. - TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate); + TIntermTyped *foldedNode = + intermediate.foldAggregateBuiltIn(aggregate, &mDiagnostics); if (foldedNode) { callNode = foldedNode; @@ -4134,36 +3892,41 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, unionArray->setFConst(0.0f); callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc); - recover(); } } return callNode; } TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond, - TIntermTyped *trueBlock, - TIntermTyped *falseBlock, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, const TSourceLoc &loc) { - if (boolErrorCheck(loc, cond)) - recover(); + checkIsScalarBool(loc, cond); - if (trueBlock->getType() != falseBlock->getType()) + if (trueExpression->getType() != falseExpression->getType()) { - binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString()); - recover(); - return falseBlock; + binaryOpError(loc, ":", trueExpression->getCompleteString(), + falseExpression->getCompleteString()); + return falseExpression; } // ESSL1 sections 5.2 and 5.7: // ESSL3 section 5.7: // Ternary operator is not among the operators allowed for structures/arrays. - if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct) + if (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct) { error(loc, "ternary operator is not allowed for structures or arrays", ":"); - recover(); - return falseBlock; + return falseExpression; } - return intermediate.addSelection(cond, trueBlock, falseBlock, loc); + // WebGL2 section 5.26, the following results in an error: + // "Ternary operator applied to void, arrays, or structs containing arrays" + if (mShaderSpec == SH_WEBGL2_SPEC && trueExpression->getBasicType() == EbtVoid) + { + error(loc, "ternary operator is not allowed for void", ":"); + return falseExpression; + } + + return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc); } // diff --git a/chromium/third_party/angle/src/compiler/translator/ParseContext.h b/chromium/third_party/angle/src/compiler/translator/ParseContext.h index c511330721f..c2c4bf2b4ac 100644 --- a/chromium/third_party/angle/src/compiler/translator/ParseContext.h +++ b/chromium/third_party/angle/src/compiler/translator/ParseContext.h @@ -11,6 +11,7 @@ #include "compiler/translator/DirectiveHandler.h" #include "compiler/translator/Intermediate.h" #include "compiler/translator/SymbolTable.h" +#include "compiler/translator/QualifierTypes.h" #include "compiler/preprocessor/Preprocessor.h" struct TMatrixFields @@ -30,18 +31,18 @@ class TParseContext : angle::NonCopyable public: TParseContext(TSymbolTable &symt, TExtensionBehavior &ext, - TIntermediate &interm, sh::GLenum type, ShShaderSpec spec, - int options, + ShCompileOptions options, bool checksPrecErrors, TInfoSink &is, const ShBuiltInResources &resources) - : intermediate(interm), + : intermediate(), symbolTable(symt), mDeferredSingleDeclarationErrorCheck(false), mShaderType(type), mShaderSpec(spec), + mCompileOptions(options), mShaderVersion(100), mTreeRoot(nullptr), mLoopNestingLevel(0), @@ -65,8 +66,11 @@ class TParseContext : angle::NonCopyable mUsesFragColor(false), mUsesSecondaryOutputs(false), mMinProgramTexelOffset(resources.MinProgramTexelOffset), - mMaxProgramTexelOffset(resources.MaxProgramTexelOffset) + mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), + mComputeShaderLocalSizeDeclared(false), + mDeclaringFunction(false) { + mComputeShaderLocalSize.fill(-1); } const pp::Preprocessor &getPreprocessor() const { return mPreprocessor; } @@ -90,7 +94,6 @@ class TParseContext : angle::NonCopyable const char *token, const char *extraInfo = ""); - void recover(); TIntermNode *getTreeRoot() const { return mTreeRoot; } void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; } @@ -114,6 +117,15 @@ class TParseContext : angle::NonCopyable void incrSwitchNestingLevel() { ++mSwitchNestingLevel; } void decrSwitchNestingLevel() { --mSwitchNestingLevel; } + bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } + sh::WorkGroupSize getComputeShaderLocalSize() const; + + void enterFunctionDeclaration() { mDeclaringFunction = true; } + + void exitFunctionDeclaration() { mDeclaringFunction = false; } + + bool declaringFunction() const { return mDeclaringFunction; } + // This method is guaranteed to succeed, even if no variable with 'name' exists. const TVariable *getNamedVariable(const TSourceLoc &location, const TString *name, const TSymbol *symbol); TIntermTyped *parseVariableIdentifier(const TSourceLoc &location, @@ -122,38 +134,59 @@ class TParseContext : angle::NonCopyable bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc &line); - bool reservedErrorCheck(const TSourceLoc &line, const TString &identifier); void assignError(const TSourceLoc &line, const char *op, TString left, TString right); void unaryOpError(const TSourceLoc &line, const char *op, TString operand); void binaryOpError(const TSourceLoc &line, const char *op, TString left, TString right); - bool precisionErrorCheck(const TSourceLoc &line, TPrecision precision, TBasicType type); - bool lValueErrorCheck(const TSourceLoc &line, const char *op, TIntermTyped*); - bool constErrorCheck(TIntermTyped *node); - bool integerErrorCheck(TIntermTyped *node, const char *token); - bool globalErrorCheck(const TSourceLoc &line, bool global, const char *token); - bool constructorErrorCheck(const TSourceLoc &line, - TIntermNode *argumentsNode, - TFunction &function, - TOperator op, - TType *type); - bool arraySizeErrorCheck(const TSourceLoc &line, TIntermTyped *expr, int &size); - bool arrayQualifierErrorCheck(const TSourceLoc &line, const TPublicType &type); - bool arrayTypeErrorCheck(const TSourceLoc &line, const TPublicType &type); - bool voidErrorCheck(const TSourceLoc &line, const TString &identifier, const TBasicType &type); - bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*); - bool boolErrorCheck(const TSourceLoc&, const TPublicType&); - bool samplerErrorCheck(const TSourceLoc &line, const TPublicType &pType, const char *reason); - bool locationDeclaratorListCheck(const TSourceLoc &line, const TPublicType &pType); - bool parameterSamplerErrorCheck(const TSourceLoc &line, TQualifier qualifier, const TType &type); - bool paramErrorCheck(const TSourceLoc &line, TQualifier qualifier, TQualifier paramQualifier, TType *type); - bool extensionErrorCheck(const TSourceLoc &line, const TString&); - bool singleDeclarationErrorCheck(const TPublicType &publicType, const TSourceLoc &identifierLocation); - bool layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier); - bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *); - void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation); - void es3InputOutputTypeCheck(const TQualifier qualifier, - const TPublicType &type, - const TSourceLoc &qualifierLocation); + + // Check functions - the ones that return bool return false if an error was generated. + + bool checkIsNotReserved(const TSourceLoc &line, const TString &identifier); + void checkPrecisionSpecified(const TSourceLoc &line, TPrecision precision, TBasicType type); + bool checkCanBeLValue(const TSourceLoc &line, const char *op, TIntermTyped *node); + void checkIsConst(TIntermTyped *node); + void checkIsScalarInteger(TIntermTyped *node, const char *token); + bool checkIsAtGlobalLevel(const TSourceLoc &line, const char *token); + bool checkConstructorArguments(const TSourceLoc &line, + TIntermNode *argumentsNode, + const TFunction &function, + TOperator op, + const TType &type); + + // Returns a sanitized array size to use (the size is at least 1). + unsigned int checkIsValidArraySize(const TSourceLoc &line, TIntermTyped *expr); + bool checkIsValidQualifierForArray(const TSourceLoc &line, const TPublicType &elementQualifier); + bool checkIsValidTypeForArray(const TSourceLoc &line, const TPublicType &elementType); + bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type); + void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type); + void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType); + bool checkIsNotSampler(const TSourceLoc &line, + const TTypeSpecifierNonArray &pType, + const char *reason); + void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType); + void checkLocationIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + void checkOutParameterIsNotSampler(const TSourceLoc &line, + TQualifier qualifier, + const TType &type); + void checkIsParameterQualifierValid(const TSourceLoc &line, + const TTypeQualifierBuilder &typeQualifierBuilder, + TType *type); + bool checkCanUseExtension(const TSourceLoc &line, const TString &extension); + void singleDeclarationErrorCheck(const TPublicType &publicType, + const TSourceLoc &identifierLocation); + void checkLayoutQualifierSupported(const TSourceLoc &location, + const TString &layoutQualifierName, + int versionRequired); + bool checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location, + const TLayoutQualifier &layoutQualifier); + + void functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *fnCall); + void checkInvariantVariableQualifier(bool invariant, + const TQualifier qualifier, + const TSourceLoc &invariantLocation); + void checkInputOutputTypeIsValidES3(const TQualifier qualifier, + const TPublicType &type, + const TSourceLoc &qualifierLocation); const TPragma &pragma() const { return mDirectiveHandler.pragma(); } const TExtensionBehavior &extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); } @@ -171,9 +204,7 @@ class TParseContext : angle::NonCopyable TIntermTyped *initializer, TIntermNode **intermNode); - TPublicType addFullySpecifiedType(TQualifier qualifier, - bool invariant, - TLayoutQualifier layoutQualifier, + TPublicType addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder, const TPublicType &typeSpecifier); TIntermAggregate *parseSingleDeclaration(TPublicType &publicType, @@ -200,7 +231,7 @@ class TParseContext : angle::NonCopyable const TSourceLoc &initLocation, TIntermTyped *initializer); - TIntermAggregate *parseInvariantDeclaration(const TSourceLoc &invariantLoc, + TIntermAggregate *parseInvariantDeclaration(const TTypeQualifierBuilder &typeQualifierBuilder, const TSourceLoc &identifierLoc, const TString *identifier, const TSymbol *symbol); @@ -232,7 +263,7 @@ class TParseContext : angle::NonCopyable const TSourceLoc &initLocation, TIntermTyped *initializer); - void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); + void parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder); TIntermAggregate *addFunctionPrototypeDeclaration(const TFunction &function, const TSourceLoc &location); TIntermAggregate *addFunctionDefinition(const TFunction &function, @@ -249,24 +280,10 @@ class TParseContext : angle::NonCopyable const TSourceLoc &location); TFunction *addConstructorFunc(const TPublicType &publicType); TIntermTyped *addConstructor(TIntermNode *arguments, - TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line); - TIntermTyped *addConstVectorNode(TVectorFields &fields, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError); - TIntermTyped *addConstMatrixNode(int index, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError); - TIntermTyped *addConstArrayNode(int index, - TIntermConstantUnion *node, - const TSourceLoc &line, - bool outOfRangeIndexIsError); - TIntermTyped *addConstStruct( - const TString &identifier, TIntermTyped *node, const TSourceLoc& line); + TIntermTyped *addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression); @@ -275,39 +292,48 @@ class TParseContext : angle::NonCopyable const TString &fieldString, const TSourceLoc &fieldLocation); + TFieldList *addStructDeclaratorListWithQualifiers( + const TTypeQualifierBuilder &typeQualifierBuilder, + TPublicType *typeSpecifier, + TFieldList *fieldList); TFieldList *addStructDeclaratorList(const TPublicType &typeSpecifier, TFieldList *fieldList); - TPublicType addStructure(const TSourceLoc &structLine, - const TSourceLoc &nameLine, - const TString *structName, - TFieldList *fieldList); + TTypeSpecifierNonArray addStructure(const TSourceLoc &structLine, + const TSourceLoc &nameLine, + const TString *structName, + TFieldList *fieldList); - TIntermAggregate* addInterfaceBlock(const TPublicType &typeQualifier, + TIntermAggregate *addInterfaceBlock(const TTypeQualifierBuilder &typeQualifierBuilder, const TSourceLoc &nameLine, const TString &blockName, TFieldList *fieldList, const TString *instanceName, const TSourceLoc &instanceLine, TIntermTyped *arrayIndex, - const TSourceLoc& arrayIndexLine); - + const TSourceLoc &arrayIndexLine); + + void parseLocalSize(const TString &qualifierType, + const TSourceLoc &qualifierTypeLine, + int intValue, + const TSourceLoc &intValueLine, + const std::string &intValueString, + size_t index, + sh::WorkGroupSize *localSize); TLayoutQualifier parseLayoutQualifier( const TString &qualifierType, const TSourceLoc &qualifierTypeLine); TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, const TSourceLoc &qualifierTypeLine, - const TString &intValueString, int intValue, const TSourceLoc &intValueLine); - TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier); - TPublicType joinInterpolationQualifiers(const TSourceLoc &interpolationLoc, TQualifier interpolationQualifier, - const TSourceLoc &storageLoc, TQualifier storageQualifier); + TTypeQualifierBuilder *createTypeQualifierBuilder(const TSourceLoc &loc); + TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation); // Performs an error check for embedded struct declarations. - // Returns true if an error was raised due to the declaration of - // this struct. - bool enterStructDeclaration(const TSourceLoc &line, const TString &identifier); + void enterStructDeclaration(const TSourceLoc &line, const TString &identifier); void exitStructDeclaration(); - bool structNestingErrorCheck(const TSourceLoc &line, const TField &field); + void checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field); TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc); TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc); @@ -334,17 +360,35 @@ class TParseContext : angle::NonCopyable const TSourceLoc &loc, bool *fatalError); - TIntermTyped *addTernarySelection( - TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &line); + TIntermTyped *addTernarySelection(TIntermTyped *cond, + TIntermTyped *trueExpression, + TIntermTyped *falseExpression, + const TSourceLoc &line); // TODO(jmadill): make these private - TIntermediate &intermediate; // to hold and build a parse tree + TIntermediate intermediate; // to build a parse tree TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed private: + // Returns a clamped index. + int checkIndexOutOfRange(bool outOfRangeIndexIsError, + const TSourceLoc &location, + int index, + int arraySize, + const char *reason, + const char *token); + bool declareVariable(const TSourceLoc &line, const TString &identifier, const TType &type, TVariable **variable); - bool nonInitErrorCheck(const TSourceLoc &line, const TString &identifier, TPublicType *type); + void checkCanBeDeclaredWithoutInitializer(const TSourceLoc &line, + const TString &identifier, + TPublicType *type); + + bool checkIsValidTypeAndQualifierForArray(const TSourceLoc &indexLocation, + const TPublicType &elementType); + + // Assumes that multiplication op has already been set based on the types. + bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right); TIntermTyped *addBinaryMathInternal( TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &loc); @@ -363,15 +407,18 @@ class TParseContext : angle::NonCopyable bool mDeferredSingleDeclarationErrorCheck; sh::GLenum mShaderType; // vertex or fragment language (future: pack or unpack) - ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + ShShaderSpec mShaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. + ShCompileOptions mCompileOptions; // Options passed to TCompiler int mShaderVersion; - TIntermNode *mTreeRoot; // root of parse tree being created + TIntermNode *mTreeRoot; // root of parse tree being created int mLoopNestingLevel; // 0 if outside all loops - int mStructNestingLevel; // incremented while parsing a struct declaration + int mStructNestingLevel; // incremented while parsing a struct declaration int mSwitchNestingLevel; // 0 if outside all switch statements - const TType *mCurrentFunctionType; // the return type of the function that's currently being parsed + const TType + *mCurrentFunctionType; // the return type of the function that's currently being parsed bool mFunctionReturnsValue; // true if a non-void function has a return - bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit. + bool mChecksPrecisionErrors; // true if an error will be generated when a variable is declared + // without precision, explicit or implicit. bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling // ESSL1. TLayoutMatrixPacking mDefaultMatrixPacking; @@ -387,6 +434,12 @@ class TParseContext : angle::NonCopyable // gl_Secondary FragColor or both. int mMinProgramTexelOffset; int mMaxProgramTexelOffset; + + // keep track of local group size declared in layout. It should be declared only once. + bool mComputeShaderLocalSizeDeclared; + sh::WorkGroupSize mComputeShaderLocalSize; + // keeps track whether we are declaring / defining a function + bool mDeclaringFunction; }; int PaParseStrings( diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp index 27e1c06b5b8..3b44afe3358 100644 --- a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp +++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp @@ -50,29 +50,18 @@ void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator) // Implement the functionality of the TPoolAllocator class, which // is documented in PoolAlloc.h. // -TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : - pageSize(growthIncrement), - alignment(allocationAlignment), - freeList(0), - inUseList(0), - numCalls(0), - totalBytes(0), - mLocked(false) +TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) + : alignment(allocationAlignment), +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + pageSize(growthIncrement), + freeList(0), + inUseList(0), + numCalls(0), + totalBytes(0), +#endif + mLocked(false) { // - // Don't allow page sizes we know are smaller than all common - // OS page sizes. - // - if (pageSize < 4*1024) - pageSize = 4*1024; - - // - // A large currentPageOffset indicates a new page needs to - // be obtained to allocate memory. - // - currentPageOffset = pageSize; - - // // Adjust alignment to be at least pointer aligned and // power of 2. // @@ -86,6 +75,20 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : alignment = a; alignmentMask = a - 1; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4 * 1024) + pageSize = 4 * 1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + // // Align header skip // @@ -93,10 +96,14 @@ TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) : if (headerSkip < sizeof(tHeader)) { headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; } +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + mStack.push_back({}); +#endif } TPoolAllocator::~TPoolAllocator() { +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) while (inUseList) { tHeader* next = inUseList->nextPage; inUseList->~tHeader(); @@ -113,6 +120,16 @@ TPoolAllocator::~TPoolAllocator() delete [] reinterpret_cast<char*>(freeList); freeList = next; } +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + for (auto &allocs : mStack) + { + for (auto alloc : allocs) + { + free(alloc); + } + } + mStack.clear(); +#endif } // Support MSVC++ 6.0 @@ -153,14 +170,18 @@ void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, co void TPoolAllocator::push() { +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) tAllocState state = { currentPageOffset, inUseList }; - stack.push_back(state); - + mStack.push_back(state); + // // Indicate there is no current page to allocate from. // currentPageOffset = pageSize; +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + mStack.push_back({}); +#endif } // @@ -172,11 +193,12 @@ void TPoolAllocator::push() // void TPoolAllocator::pop() { - if (stack.size() < 1) + if (mStack.size() < 1) return; - tHeader* page = stack.back().page; - currentPageOffset = stack.back().offset; +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + tHeader *page = mStack.back().page; + currentPageOffset = mStack.back().offset; while (inUseList != page) { // invoke destructor to free allocation list @@ -192,7 +214,14 @@ void TPoolAllocator::pop() inUseList = nextInUse; } - stack.pop_back(); + mStack.pop_back(); +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + for (auto &alloc : mStack.back()) + { + free(alloc); + } + mStack.pop_back(); +#endif } // @@ -201,7 +230,7 @@ void TPoolAllocator::pop() // void TPoolAllocator::popAll() { - while (stack.size() > 0) + while (mStack.size() > 0) pop(); } @@ -209,6 +238,7 @@ void* TPoolAllocator::allocate(size_t numBytes) { ASSERT(!mLocked); +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) // // Just keep some interesting statistics. // @@ -285,6 +315,14 @@ void* TPoolAllocator::allocate(size_t numBytes) currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; return initializeAllocation(inUseList, ret, numBytes); +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + void *alloc = malloc(numBytes + alignmentMask); + mStack.back().push_back(alloc); + + intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc); + intAlloc = (intAlloc + alignmentMask) & ~alignmentMask; + return reinterpret_cast<void *>(intAlloc); +#endif } void TPoolAllocator::lock() diff --git a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h index 026e7a5c110..f15b3e05d84 100644 --- a/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h +++ b/chromium/third_party/angle/src/compiler/translator/PoolAlloc.h @@ -157,7 +157,12 @@ public: void lock(); void unlock(); -protected: + private: + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + +#if !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) friend struct tHeader; struct tHeader { @@ -200,20 +205,21 @@ protected: } size_t pageSize; // granularity of allocation from the OS - size_t alignment; // all returned allocations will be aligned at - // this granularity, which will be a power of 2 - size_t alignmentMask; size_t headerSkip; // amount of memory to skip to make room for the // header (basically, size of header, rounded // up to make it aligned size_t currentPageOffset; // next offset in top of inUseList to allocate from tHeader* freeList; // list of popped memory tHeader* inUseList; // list of all memory currently being used - tAllocStack stack; // stack of where to allocate from, to partition pool + tAllocStack mStack; // stack of where to allocate from, to partition pool int numCalls; // just an interesting statistic size_t totalBytes; // just an interesting statistic -private: + +#else // !defined(ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC) + std::vector<std::vector<void *>> mStack; +#endif + TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor bool mLocked; diff --git a/chromium/third_party/angle/src/compiler/translator/PruneEmptyDeclarations.cpp b/chromium/third_party/angle/src/compiler/translator/PruneEmptyDeclarations.cpp index ef62dbfce71..8cbeb7dee1f 100644 --- a/chromium/third_party/angle/src/compiler/translator/PruneEmptyDeclarations.cpp +++ b/chromium/third_party/angle/src/compiler/translator/PruneEmptyDeclarations.cpp @@ -66,6 +66,27 @@ bool PruneEmptyDeclarationsTraverser::visitAggregate(Visit, TIntermAggregate *no ASSERT(parentAgg != nullptr); mMultiReplacements.push_back(NodeReplaceWithMultipleEntry(parentAgg, node, emptyReplacement)); } + else if (sym->getType().getQualifier() != EvqGlobal && + sym->getType().getQualifier() != EvqTemporary) + { + // We've hit an empty struct declaration with a qualifier, for example like + // this: + // const struct a { int i; }; + // NVIDIA GL driver version 367.27 doesn't accept this kind of declarations, so + // we convert the declaration to a regular struct declaration. This is okay, + // since ESSL 1.00 spec section 4.1.8 says about structs that "The optional + // qualifiers only apply to any declarators, and are not part of the type being + // defined for name." + + if (mInGlobalScope) + { + sym->getTypePointer()->setQualifier(EvqGlobal); + } + else + { + sym->getTypePointer()->setQualifier(EvqTemporary); + } + } } } return false; diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierTypes.cpp b/chromium/third_party/angle/src/compiler/translator/QualifierTypes.cpp new file mode 100644 index 00000000000..30d8c4eed08 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/QualifierTypes.cpp @@ -0,0 +1,646 @@ +// +// Copyright (c) 2002-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/QualifierTypes.h" + +#include "compiler/translator/Diagnostics.h" + +#include <algorithm> + +namespace sh +{ +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics) +{ + TLayoutQualifier joinedQualifier = leftQualifier; + + if (rightQualifier.location != -1) + { + joinedQualifier.location = rightQualifier.location; + ++joinedQualifier.locationsSpecified; + } + if (rightQualifier.matrixPacking != EmpUnspecified) + { + joinedQualifier.matrixPacking = rightQualifier.matrixPacking; + } + if (rightQualifier.blockStorage != EbsUnspecified) + { + joinedQualifier.blockStorage = rightQualifier.blockStorage; + } + + for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i) + { + if (rightQualifier.localSize[i] != -1) + { + if (joinedQualifier.localSize[i] != -1 && + joinedQualifier.localSize[i] != rightQualifier.localSize[i]) + { + diagnostics->error(rightQualifierLocation, + "Cannot have multiple different work group size specifiers", + getWorkGroupSizeString(i), ""); + } + joinedQualifier.localSize[i] = rightQualifier.localSize[i]; + } + } + + return joinedQualifier; +} +} // namespace sh + +namespace +{ + +// GLSL ES 3.10 does not impose a strict order on type qualifiers and allows multiple layout +// declarations. +// GLSL ES 3.10 Revision 4, 4.10 Order of Qualification +bool AreTypeQualifierChecksRelaxed(int shaderVersion) +{ + return shaderVersion >= 310; +} + +#if defined(ANGLE_ENABLE_ASSERTS) +bool IsScopeQualifier(TQualifier qualifier) +{ + return qualifier == EvqGlobal || qualifier == EvqTemporary; +} + +bool IsScopeQualifierWrapper(const TQualifierWrapperBase *qualifier) +{ + if (qualifier->getType() != QtStorage) + return false; + const TStorageQualifierWrapper *storageQualifier = + static_cast<const TStorageQualifierWrapper *>(qualifier); + TQualifier q = storageQualifier->getQualifier(); + return IsScopeQualifier(q); +} + +// Returns true if the invariant for the qualifier sequence holds +bool IsInvariantCorrect(const TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We should have at least one qualifier. + // The first qualifier always tells the scope. + return qualifiers.size() >= 1 && IsScopeQualifierWrapper(qualifiers[0]); +} +#endif + +// Returns true if there are qualifiers which have been specified multiple times +// If areQualifierChecksRelaxed is set to true, then layout qualifier repetition is allowed. +bool HasRepeatingQualifiers(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + bool areQualifierChecksRelaxed, + std::string *errorMessage) +{ + bool invariantFound = false; + bool precisionFound = false; + bool layoutFound = false; + bool interpolationFound = false; + + unsigned int locationsSpecified = 0; + bool isOut = false; + + // The iteration starts from one since the first qualifier only reveals the scope of the + // expression. It is inserted first whenever the sequence gets created. + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + { + if (invariantFound) + { + *errorMessage = "The invariant qualifier specified multiple times."; + return true; + } + invariantFound = true; + break; + } + case QtPrecision: + { + if (precisionFound) + { + *errorMessage = "The precision qualifier specified multiple times."; + return true; + } + precisionFound = true; + break; + } + case QtLayout: + { + if (layoutFound && !areQualifierChecksRelaxed) + { + *errorMessage = "The layout qualifier specified multiple times."; + return true; + } + if (invariantFound && !areQualifierChecksRelaxed) + { + // This combination is not correct according to the syntax specified in the + // formal grammar in the ESSL 3.00 spec. In ESSL 3.10 the grammar does not have + // a similar restriction. + *errorMessage = + "The layout qualifier and invariant qualifier cannot coexist in the same " + "declaration according to the grammar."; + return true; + } + layoutFound = true; + const TLayoutQualifier ¤tQualifier = + static_cast<const TLayoutQualifierWrapper *>(qualifiers[i])->getQualifier(); + locationsSpecified += currentQualifier.locationsSpecified; + break; + } + case QtInterpolation: + { + // 'centroid' is treated as a storage qualifier + // 'flat centroid' will be squashed to 'flat' + // 'smooth centroid' will be squashed to 'centroid' + if (interpolationFound) + { + *errorMessage = "The interpolation qualifier specified multiple times."; + return true; + } + interpolationFound = true; + break; + } + case QtStorage: + { + // Go over all of the storage qualifiers up until the current one and check for + // repetitions. + TQualifier currentQualifier = + static_cast<const TStorageQualifierWrapper *>(qualifiers[i])->getQualifier(); + if (currentQualifier == EvqVertexOut || currentQualifier == EvqFragmentOut) + { + isOut = true; + } + for (size_t j = 1; j < i; ++j) + { + if (qualifiers[j]->getType() == QtStorage) + { + const TStorageQualifierWrapper *previousQualifierWrapper = + static_cast<const TStorageQualifierWrapper *>(qualifiers[j]); + TQualifier previousQualifier = previousQualifierWrapper->getQualifier(); + if (currentQualifier == previousQualifier) + { + *errorMessage = previousQualifierWrapper->getQualifierString().c_str(); + *errorMessage += " specified multiple times"; + return true; + } + } + } + break; + } + default: + UNREACHABLE(); + } + } + + if (locationsSpecified > 1 && isOut) + { + // GLSL ES 3.00.6 section 4.3.8.2 Output Layout Qualifiers + // GLSL ES 3.10 section 4.4.2 Output Layout Qualifiers + // "The qualifier may appear at most once within a declaration." + *errorMessage = "Output layout location specified multiple times."; + return true; + } + + return false; +} + +// GLSL ES 3.00_6, 4.7 Order of Qualification +// The correct order of qualifiers is: +// invariant-qualifier interpolation-qualifier storage-qualifier precision-qualifier +// layout-qualifier has to be before storage-qualifier. +bool AreQualifiersInOrder(const TTypeQualifierBuilder::QualifierSequence &qualifiers, + std::string *errorMessage) +{ + bool foundInterpolation = false; + bool foundStorage = false; + bool foundPrecision = false; + for (size_t i = 1; i < qualifiers.size(); ++i) + { + switch (qualifiers[i]->getType()) + { + case QtInvariant: + if (foundInterpolation || foundStorage || foundPrecision) + { + *errorMessage = "The invariant qualifier has to be first in the expression."; + return false; + } + break; + case QtInterpolation: + if (foundStorage) + { + *errorMessage = "Storage qualifiers have to be after interpolation qualifiers."; + return false; + } + else if (foundPrecision) + { + *errorMessage = + "Precision qualifiers have to be after interpolation qualifiers."; + return false; + } + foundInterpolation = true; + break; + case QtLayout: + if (foundStorage) + { + *errorMessage = "Storage qualifiers have to be after layout qualifiers."; + return false; + } + else if (foundPrecision) + { + *errorMessage = "Precision qualifiers have to be after layout qualifiers."; + return false; + } + break; + case QtStorage: + if (foundPrecision) + { + *errorMessage = "Precision qualifiers have to be after storage qualifiers."; + return false; + } + foundStorage = true; + break; + case QtPrecision: + foundPrecision = true; + break; + default: + UNREACHABLE(); + } + } + return true; +} + +struct QualifierComparator +{ + bool operator()(const TQualifierWrapperBase *q1, const TQualifierWrapperBase *q2) + { + return q1->getRank() < q2->getRank(); + } +}; + +void SortSequence(TTypeQualifierBuilder::QualifierSequence &qualifiers) +{ + // We need a stable sorting algorithm since the order of layout-qualifier declarations matter. + // The sorting starts from index 1, instead of 0, since the element at index 0 tells the scope + // and we always want it to be first. + std::stable_sort(qualifiers.begin() + 1, qualifiers.end(), QualifierComparator()); +} + +// Handles the joining of storage qualifiers for variables. +bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqGlobal: + *joinedQualifier = storageQualifier; + break; + case EvqTemporary: + { + switch (storageQualifier) + { + case EvqConst: + *joinedQualifier = storageQualifier; + break; + default: + return false; + } + break; + } + case EvqSmooth: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqCentroid; + break; + case EvqVertexOut: + *joinedQualifier = EvqSmoothOut; + break; + case EvqFragmentIn: + *joinedQualifier = EvqSmoothIn; + break; + default: + return false; + } + break; + } + case EvqFlat: + { + switch (storageQualifier) + { + case EvqCentroid: + *joinedQualifier = EvqFlat; + break; + case EvqVertexOut: + *joinedQualifier = EvqFlatOut; + break; + case EvqFragmentIn: + *joinedQualifier = EvqFlatIn; + break; + default: + return false; + } + break; + } + case EvqCentroid: + { + switch (storageQualifier) + { + case EvqVertexOut: + *joinedQualifier = EvqCentroidOut; + break; + case EvqFragmentIn: + *joinedQualifier = EvqCentroidIn; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +// Handles the joining of storage qualifiers for a parameter in a function. +bool JoinParameterStorageQualifier(TQualifier *joinedQualifier, TQualifier storageQualifier) +{ + switch (*joinedQualifier) + { + case EvqTemporary: + *joinedQualifier = storageQualifier; + break; + case EvqConst: + { + switch (storageQualifier) + { + case EvqIn: + *joinedQualifier = EvqConstReadOnly; + break; + default: + return false; + } + break; + } + default: + return false; + } + return true; +} + +TTypeQualifier GetVariableTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier( + static_cast<const TStorageQualifierWrapper *>(sortedSequence[0])->getQualifier(), + sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + isQualifierValid = true; + typeQualifier.invariant = true; + break; + case QtInterpolation: + { + switch (typeQualifier.qualifier) + { + case EvqGlobal: + isQualifierValid = true; + typeQualifier.qualifier = + static_cast<const TInterpolationQualifierWrapper *>(qualifier) + ->getQualifier(); + break; + default: + isQualifierValid = false; + } + break; + } + case QtLayout: + { + const TLayoutQualifierWrapper *layoutQualifierWrapper = + static_cast<const TLayoutQualifierWrapper *>(qualifier); + isQualifierValid = true; + typeQualifier.layoutQualifier = sh::JoinLayoutQualifiers( + typeQualifier.layoutQualifier, layoutQualifierWrapper->getQualifier(), + layoutQualifierWrapper->getLine(), diagnostics); + break; + } + case QtStorage: + isQualifierValid = JoinVariableStorageQualifier( + &typeQualifier.qualifier, + static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const TString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid qualifier combination", + qualifierString.c_str(), ""); + break; + } + } + return typeQualifier; +} + +TTypeQualifier GetParameterTypeQualifierFromSortedSequence( + const TTypeQualifierBuilder::QualifierSequence &sortedSequence, + TDiagnostics *diagnostics) +{ + TTypeQualifier typeQualifier(EvqTemporary, sortedSequence[0]->getLine()); + for (size_t i = 1; i < sortedSequence.size(); ++i) + { + const TQualifierWrapperBase *qualifier = sortedSequence[i]; + bool isQualifierValid = false; + switch (qualifier->getType()) + { + case QtInvariant: + case QtInterpolation: + case QtLayout: + break; + case QtStorage: + isQualifierValid = JoinParameterStorageQualifier( + &typeQualifier.qualifier, + static_cast<const TStorageQualifierWrapper *>(qualifier)->getQualifier()); + break; + case QtPrecision: + isQualifierValid = true; + typeQualifier.precision = + static_cast<const TPrecisionQualifierWrapper *>(qualifier)->getQualifier(); + ASSERT(typeQualifier.precision != EbpUndefined); + break; + default: + UNREACHABLE(); + } + if (!isQualifierValid) + { + const TString &qualifierString = qualifier->getQualifierString(); + diagnostics->error(qualifier->getLine(), "invalid parameter qualifier", + qualifierString.c_str(), ""); + break; + } + } + + switch (typeQualifier.qualifier) + { + case EvqIn: + case EvqConstReadOnly: // const in + case EvqOut: + case EvqInOut: + break; + case EvqConst: + typeQualifier.qualifier = EvqConstReadOnly; + break; + case EvqTemporary: + // no qualifier has been specified, set it to EvqIn which is the default + typeQualifier.qualifier = EvqIn; + break; + default: + diagnostics->error(sortedSequence[0]->getLine(), "Invalid parameter qualifier ", + getQualifierString(typeQualifier.qualifier), ""); + } + return typeQualifier; +} +} // namespace + +unsigned int TInvariantQualifierWrapper::getRank() const +{ + return 0u; +} + +unsigned int TInterpolationQualifierWrapper::getRank() const +{ + return 1u; +} + +unsigned int TLayoutQualifierWrapper::getRank() const +{ + return 2u; +} + +unsigned int TStorageQualifierWrapper::getRank() const +{ + // Force the 'centroid' auxilary storage qualifier to be always first among all storage + // qualifiers. + if (mStorageQualifier == EvqCentroid) + { + return 3u; + } + else + { + return 4u; + } +} + +unsigned int TPrecisionQualifierWrapper::getRank() const +{ + return 5u; +} + +TTypeQualifier::TTypeQualifier(TQualifier scope, const TSourceLoc &loc) + : layoutQualifier(TLayoutQualifier::create()), + precision(EbpUndefined), + qualifier(scope), + invariant(false), + line(loc) +{ + ASSERT(IsScopeQualifier(qualifier)); +} + +TTypeQualifierBuilder::TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, + int shaderVersion) + : mShaderVersion(shaderVersion) +{ + ASSERT(IsScopeQualifier(scope->getQualifier())); + mQualifiers.push_back(scope); +} + +void TTypeQualifierBuilder::appendQualifier(const TQualifierWrapperBase *qualifier) +{ + mQualifiers.push_back(qualifier); +} + +bool TTypeQualifierBuilder::checkSequenceIsValid(TDiagnostics *diagnostics) const +{ + bool areQualifierChecksRelaxed = AreTypeQualifierChecksRelaxed(mShaderVersion); + std::string errorMessage; + if (HasRepeatingQualifiers(mQualifiers, areQualifierChecksRelaxed, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(), + ""); + return false; + } + + if (!areQualifierChecksRelaxed && !AreQualifiersInOrder(mQualifiers, &errorMessage)) + { + diagnostics->error(mQualifiers[0]->getLine(), "qualifier sequence", errorMessage.c_str(), + ""); + return false; + } + + return true; +} + +TTypeQualifier TTypeQualifierBuilder::getParameterTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + ASSERT(static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier() == + EvqTemporary); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier(EvqTemporary, mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetParameterTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetParameterTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} + +TTypeQualifier TTypeQualifierBuilder::getVariableTypeQualifier(TDiagnostics *diagnostics) const +{ + ASSERT(IsInvariantCorrect(mQualifiers)); + + if (!checkSequenceIsValid(diagnostics)) + { + return TTypeQualifier( + static_cast<const TStorageQualifierWrapper *>(mQualifiers[0])->getQualifier(), + mQualifiers[0]->getLine()); + } + + // If the qualifier checks are relaxed, then it is easier to sort the qualifiers so + // that the order imposed by the GLSL ES 3.00 spec is kept. Then we can use the same code to + // combine the qualifiers. + if (AreTypeQualifierChecksRelaxed(mShaderVersion)) + { + // Copy the qualifier sequence so that we can sort them. + QualifierSequence sortedQualifierSequence = mQualifiers; + SortSequence(sortedQualifierSequence); + return GetVariableTypeQualifierFromSortedSequence(sortedQualifierSequence, diagnostics); + } + return GetVariableTypeQualifierFromSortedSequence(mQualifiers, diagnostics); +} diff --git a/chromium/third_party/angle/src/compiler/translator/QualifierTypes.h b/chromium/third_party/angle/src/compiler/translator/QualifierTypes.h new file mode 100644 index 00000000000..0bcc39a16e4 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/QualifierTypes.h @@ -0,0 +1,170 @@ +// +// Copyright (c) 2002-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. +// + +#ifndef COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ +#define COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ + +#include "common/angleutils.h" +#include "compiler/translator/BaseTypes.h" +#include "compiler/translator/Types.h" + +class TDiagnostics; + +namespace sh +{ +TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, + TLayoutQualifier rightQualifier, + const TSourceLoc &rightQualifierLocation, + TDiagnostics *diagnostics); +} // namespace sh + +enum TQualifierType +{ + QtInvariant, + QtInterpolation, + QtLayout, + QtStorage, + QtPrecision +}; + +class TQualifierWrapperBase : angle::NonCopyable +{ + public: + POOL_ALLOCATOR_NEW_DELETE(); + TQualifierWrapperBase(const TSourceLoc &line) : mLine(line) {} + virtual ~TQualifierWrapperBase(){}; + virtual TQualifierType getType() const = 0; + virtual TString getQualifierString() const = 0; + virtual unsigned int getRank() const = 0; + const TSourceLoc &getLine() const { return mLine; } + private: + TSourceLoc mLine; +}; + +class TInvariantQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInvariantQualifierWrapper(const TSourceLoc &line) : TQualifierWrapperBase(line) {} + ~TInvariantQualifierWrapper() {} + + TQualifierType getType() const { return QtInvariant; } + TString getQualifierString() const { return "invariant"; } + unsigned int getRank() const; +}; + +class TInterpolationQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TInterpolationQualifierWrapper(TQualifier interpolationQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mInterpolationQualifier(interpolationQualifier) + { + } + ~TInterpolationQualifierWrapper() {} + + TQualifierType getType() const { return QtInterpolation; } + TString getQualifierString() const { return ::getQualifierString(mInterpolationQualifier); } + TQualifier getQualifier() const { return mInterpolationQualifier; } + unsigned int getRank() const; + + private: + TQualifier mInterpolationQualifier; +}; + +class TLayoutQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TLayoutQualifierWrapper(TLayoutQualifier layoutQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mLayoutQualifier(layoutQualifier) + { + } + ~TLayoutQualifierWrapper() {} + + TQualifierType getType() const { return QtLayout; } + TString getQualifierString() const { return "layout"; } + const TLayoutQualifier &getQualifier() const { return mLayoutQualifier; } + unsigned int getRank() const; + + private: + TLayoutQualifier mLayoutQualifier; +}; + +class TStorageQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TStorageQualifierWrapper(TQualifier storageQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mStorageQualifier(storageQualifier) + { + } + ~TStorageQualifierWrapper() {} + + TQualifierType getType() const { return QtStorage; } + TString getQualifierString() const { return ::getQualifierString(mStorageQualifier); } + TQualifier getQualifier() const { return mStorageQualifier; } + unsigned int getRank() const; + + private: + TQualifier mStorageQualifier; +}; + +class TPrecisionQualifierWrapper final : public TQualifierWrapperBase +{ + public: + TPrecisionQualifierWrapper(TPrecision precisionQualifier, const TSourceLoc &line) + : TQualifierWrapperBase(line), mPrecisionQualifier(precisionQualifier) + { + } + ~TPrecisionQualifierWrapper() {} + + TQualifierType getType() const { return QtPrecision; } + TString getQualifierString() const { return ::getPrecisionString(mPrecisionQualifier); } + TPrecision getQualifier() const { return mPrecisionQualifier; } + unsigned int getRank() const; + + private: + TPrecision mPrecisionQualifier; +}; + +// TTypeQualifier tightly covers type_qualifier from the grammar +struct TTypeQualifier +{ + // initializes all of the qualifiers and sets the scope + TTypeQualifier(TQualifier scope, const TSourceLoc &loc); + + TLayoutQualifier layoutQualifier; + TPrecision precision; + TQualifier qualifier; + bool invariant; + TSourceLoc line; +}; + +// TTypeQualifierBuilder contains all of the qualifiers when type_qualifier gets parsed. +// It is to be used to validate the qualifier sequence and build a TTypeQualifier from it. +class TTypeQualifierBuilder : angle::NonCopyable +{ + public: + using QualifierSequence = TVector<const TQualifierWrapperBase *>; + + public: + POOL_ALLOCATOR_NEW_DELETE(); + TTypeQualifierBuilder(const TStorageQualifierWrapper *scope, int shaderVersion); + // Adds the passed qualifier to the end of the sequence. + void appendQualifier(const TQualifierWrapperBase *qualifier); + // Checks for the order of qualification and repeating qualifiers. + bool checkSequenceIsValid(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a function + // parameter. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getParameterTypeQualifier(TDiagnostics *diagnostics) const; + // Goes over the qualifier sequence and parses it to form a type qualifier for a variable. + // The returned object is initialized even if the parsing fails. + TTypeQualifier getVariableTypeQualifier(TDiagnostics *diagnostics) const; + + private: + QualifierSequence mQualifiers; + int mShaderVersion; +}; + +#endif // COMPILER_TRANSLATOR_QUALIFIER_TYPES_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/RecordConstantPrecision.cpp b/chromium/third_party/angle/src/compiler/translator/RecordConstantPrecision.cpp index 14e88b749a7..af1d1d1a38c 100644 --- a/chromium/third_party/angle/src/compiler/translator/RecordConstantPrecision.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RecordConstantPrecision.cpp @@ -128,7 +128,7 @@ void RecordConstantPrecisionTraverser::visitConstantUnion(TIntermConstantUnion * TIntermSequence insertions; insertions.push_back(createTempInitDeclaration(node, EvqConst)); insertStatementsInParentBlock(insertions); - mReplacements.push_back(NodeUpdateEntry(getParentNode(), node, createTempSymbol(node->getType()), false)); + queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); mFoundHigherPrecisionConstant = true; } diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveDynamicIndexing.cpp b/chromium/third_party/angle/src/compiler/translator/RemoveDynamicIndexing.cpp index 74814f22a79..4ac3e9fcd12 100644 --- a/chromium/third_party/angle/src/compiler/translator/RemoveDynamicIndexing.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RemoveDynamicIndexing.cpp @@ -11,6 +11,7 @@ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" #include "compiler/translator/SymbolTable.h" namespace @@ -91,21 +92,15 @@ TIntermBinary *CreateIndexDirectBaseSymbolNode(const TType &indexedType, const int index, TQualifier baseQualifier) { - TIntermBinary *indexNode = new TIntermBinary(EOpIndexDirect); - indexNode->setType(fieldType); TIntermSymbol *baseSymbol = CreateBaseSymbol(indexedType, baseQualifier); - indexNode->setLeft(baseSymbol); - indexNode->setRight(CreateIntConstantNode(index)); + TIntermBinary *indexNode = + new TIntermBinary(EOpIndexDirect, baseSymbol, TIntermTyped::CreateIndexNode(index)); return indexNode; } TIntermBinary *CreateAssignValueSymbolNode(TIntermTyped *targetNode, const TType &assignedValueType) { - TIntermBinary *assignNode = new TIntermBinary(EOpAssign); - assignNode->setType(assignedValueType); - assignNode->setLeft(targetNode); - assignNode->setRight(CreateValueSymbol(assignedValueType)); - return assignNode; + return new TIntermBinary(EOpAssign, targetNode, CreateValueSymbol(assignedValueType)); } TIntermTyped *EnsureSignedInt(TIntermTyped *node) @@ -255,10 +250,9 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermAggregate *bodyNode = new TIntermAggregate(EOpSequence); bodyNode->getSequence()->push_back(switchNode); - TIntermBinary *cond = new TIntermBinary(EOpLessThan); + TIntermBinary *cond = + new TIntermBinary(EOpLessThan, CreateIndexSymbol(), CreateIntConstantNode(0)); cond->setType(TType(EbtBool, EbpUndefined)); - cond->setLeft(CreateIndexSymbol()); - cond->setRight(CreateIntConstantNode(0)); // Two blocks: one accesses (either reads or writes) the first element and returns, // the other accesses the last element. @@ -286,7 +280,7 @@ TIntermAggregate *GetIndexFunctionDefinition(TType type, bool write) TIntermBranch *returnLastNode = new TIntermBranch(EOpReturn, indexLastNode); useLastBlock->getSequence()->push_back(returnLastNode); } - TIntermSelection *ifNode = new TIntermSelection(cond, useFirstBlock, nullptr); + TIntermIfElse *ifNode = new TIntermIfElse(cond, useFirstBlock, nullptr); bodyNode->getSequence()->push_back(ifNode); bodyNode->getSequence()->push_back(useLastBlock); @@ -398,20 +392,25 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod // Init the temp variable holding the index TIntermAggregate *initIndex = createTempInitDeclaration(node->getRight()); - TIntermSequence insertions; - insertions.push_back(initIndex); - insertStatementsInParentBlock(insertions); + insertStatementInParentBlock(initIndex); mUsedTreeInsertion = true; // Replace the index with the temp variable TIntermSymbol *tempIndex = createTempSymbol(node->getRight()->getType()); - NodeUpdateEntry replaceIndex(node, node->getRight(), tempIndex, false); - mReplacements.push_back(replaceIndex); + queueReplacementWithParent(node, node->getRight(), tempIndex, OriginalNode::IS_DROPPED); } - else if (!node->getLeft()->isArray() && node->getLeft()->getBasicType() != EbtStruct) + else if (IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(node)) { bool write = isLValueRequiredHere(); +#if defined(ANGLE_ENABLE_ASSERTS) + // Make sure that IntermNodePatternMatcher is consistent with the slightly differently + // implemented checks in this traverser. + IntermNodePatternMatcher matcher( + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue); + ASSERT(matcher.match(node, getParentNode(), isLValueRequiredHere()) == write); +#endif + TType type = node->getLeft()->getType(); mIndexedVecAndMatrixTypes.insert(type); @@ -462,9 +461,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod CreateIndexedWriteFunctionCall(node, tempIndex, createTempSymbol(fieldType)); insertionsAfter.push_back(indexedWriteCall); insertStatementsInParentBlock(insertionsBefore, insertionsAfter); - NodeUpdateEntry replaceIndex(getParentNode(), node, createTempSymbol(fieldType), - false); - mReplacements.push_back(replaceIndex); + queueReplacement(node, createTempSymbol(fieldType), OriginalNode::IS_DROPPED); mUsedTreeInsertion = true; } else @@ -477,8 +474,7 @@ bool RemoveDynamicIndexingTraverser::visitBinary(Visit visit, TIntermBinary *nod ASSERT(!mRemoveIndexSideEffectsInSubtree); TIntermAggregate *indexingCall = CreateIndexFunctionCall( node, node->getLeft(), EnsureSignedInt(node->getRight())); - NodeUpdateEntry replaceIndex(getParentNode(), node, indexingCall, false); - mReplacements.push_back(replaceIndex); + queueReplacement(node, indexingCall, OriginalNode::IS_DROPPED); } } } diff --git a/chromium/third_party/angle/src/compiler/translator/RemovePow.cpp b/chromium/third_party/angle/src/compiler/translator/RemovePow.cpp index 6dbb48da9cd..4b0fe694886 100644 --- a/chromium/third_party/angle/src/compiler/translator/RemovePow.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RemovePow.cpp @@ -52,31 +52,20 @@ bool RemovePowTraverser::visitAggregate(Visit visit, TIntermAggregate *node) { if (IsProblematicPow(node)) { - TInfoSink nullSink; - TIntermTyped *x = node->getSequence()->at(0)->getAsTyped(); TIntermTyped *y = node->getSequence()->at(1)->getAsTyped(); - TIntermUnary *log = new TIntermUnary(EOpLog2); - log->setOperand(x); + TIntermUnary *log = new TIntermUnary(EOpLog2, x); log->setLine(node->getLine()); - log->setType(x->getType()); - TIntermBinary *mul = new TIntermBinary(EOpMul); - mul->setLeft(y); - mul->setRight(log); + TOperator op = TIntermBinary::GetMulOpBasedOnOperands(y->getType(), log->getType()); + TIntermBinary *mul = new TIntermBinary(op, y, log); mul->setLine(node->getLine()); - bool valid = mul->promote(nullSink); - UNUSED_ASSERTION_VARIABLE(valid); - ASSERT(valid); - TIntermUnary *exp = new TIntermUnary(EOpExp2); - exp->setOperand(mul); + TIntermUnary *exp = new TIntermUnary(EOpExp2, mul); exp->setLine(node->getLine()); - exp->setType(node->getType()); - NodeUpdateEntry replacePow(getParentNode(), node, exp, false); - mReplacements.push_back(replacePow); + queueReplacement(node, exp, OriginalNode::IS_DROPPED); // If the x parameter also needs to be replaced, we need to do that in another traversal, // since it's parent node will change in a way that's not handled correctly by updateTree(). diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp b/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp index b278b53436e..521cbeb6dbe 100644 --- a/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp @@ -62,7 +62,14 @@ bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node) return false; } -bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node) +bool RemoveSwitchFallThrough::visitTernary(Visit, TIntermTernary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitIfElse(Visit, TIntermIfElse *node) { mPreviousCase->getSequence()->push_back(node); mLastStatementWasBreak = false; diff --git a/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.h b/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.h index db8699327c1..fc73da7a3c3 100644 --- a/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.h +++ b/chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.h @@ -23,7 +23,8 @@ class RemoveSwitchFallThrough : public TIntermTraverser void visitConstantUnion(TIntermConstantUnion *node) override; bool visitBinary(Visit, TIntermBinary *node) override; bool visitUnary(Visit, TIntermUnary *node) override; - bool visitSelection(Visit visit, TIntermSelection *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; bool visitSwitch(Visit, TIntermSwitch *node) override; bool visitCase(Visit, TIntermCase *node) override; bool visitAggregate(Visit, TIntermAggregate *node) override; diff --git a/chromium/third_party/angle/src/compiler/translator/RenameFunction.h b/chromium/third_party/angle/src/compiler/translator/RenameFunction.h deleted file mode 100644 index fd6a365fea8..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/RenameFunction.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ -#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ - -#include "compiler/translator/IntermNode.h" - -// -// Renames a function, including its declaration and any calls to it. -// -class RenameFunction : public TIntermTraverser -{ -public: - RenameFunction(const TString& oldFunctionName, const TString& newFunctionName) - : TIntermTraverser(true, false, false) - , mOldFunctionName(oldFunctionName) - , mNewFunctionName(newFunctionName) {} - - bool visitAggregate(Visit visit, TIntermAggregate *node) override - { - TOperator op = node->getOp(); - if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName) - node->setName(mNewFunctionName); - return true; - } - -private: - const TString mOldFunctionName; - const TString mNewFunctionName; -}; - -#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteDoWhile.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteDoWhile.cpp index 83474475461..3a62de2d3a1 100644 --- a/chromium/third_party/angle/src/compiler/translator/RewriteDoWhile.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RewriteDoWhile.cpp @@ -95,23 +95,22 @@ class DoWhileRewriter : public TIntermTraverser // break; // } // } - TIntermSelection *breakIf = nullptr; + TIntermIfElse *breakIf = nullptr; { TIntermBranch *breakStatement = new TIntermBranch(EOpBreak, nullptr); TIntermAggregate *breakBlock = new TIntermAggregate(EOpSequence); breakBlock->getSequence()->push_back(breakStatement); - TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot); - negatedCondition->setOperand(loop->getCondition()); + TIntermUnary *negatedCondition = + new TIntermUnary(EOpLogicalNot, loop->getCondition()); - TIntermSelection *innerIf = - new TIntermSelection(negatedCondition, breakBlock, nullptr); + TIntermIfElse *innerIf = new TIntermIfElse(negatedCondition, breakBlock, nullptr); TIntermAggregate *innerIfBlock = new TIntermAggregate(EOpSequence); innerIfBlock->getSequence()->push_back(innerIf); - breakIf = new TIntermSelection(createTempSymbol(boolType), innerIfBlock, nullptr); + breakIf = new TIntermIfElse(createTempSymbol(boolType), innerIfBlock, nullptr); } // Assemble the replacement loops, reusing the do-while loop's body and inserting our diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp index 52ede17434a..13d71c799f1 100644 --- a/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp +++ b/chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp @@ -8,6 +8,8 @@ // #include "compiler/translator/RewriteElseBlocks.h" + +#include "compiler/translator/Intermediate.h" #include "compiler/translator/NodeSearch.h" #include "compiler/translator/SymbolTable.h" @@ -28,16 +30,9 @@ class ElseBlockRewriter : public TIntermTraverser private: const TType *mFunctionType; - TIntermNode *rewriteSelection(TIntermSelection *selection); + TIntermNode *rewriteIfElse(TIntermIfElse *ifElse); }; -TIntermUnary *MakeNewUnary(TOperator op, TIntermTyped *operand) -{ - TIntermUnary *unary = new TIntermUnary(op, operand->getType()); - unary->setOperand(operand); - return unary; -} - ElseBlockRewriter::ElseBlockRewriter() : TIntermTraverser(true, false, true), mFunctionType(NULL) @@ -53,19 +48,10 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) for (size_t statementIndex = 0; statementIndex != node->getSequence()->size(); statementIndex++) { TIntermNode *statement = (*node->getSequence())[statementIndex]; - TIntermSelection *selection = statement->getAsSelectionNode(); - if (selection && selection->getFalseBlock() != nullptr) + TIntermIfElse *ifElse = statement->getAsIfElseNode(); + if (ifElse && ifElse->getFalseBlock() != nullptr) { - // Check for if / else if - TIntermSelection *elseIfBranch = selection->getFalseBlock()->getAsSelectionNode(); - if (elseIfBranch) - { - selection->replaceChildNode(elseIfBranch, rewriteSelection(elseIfBranch)); - delete elseIfBranch; - } - - (*node->getSequence())[statementIndex] = rewriteSelection(selection); - delete selection; + (*node->getSequence())[statementIndex] = rewriteIfElse(ifElse); } } } @@ -82,20 +68,20 @@ bool ElseBlockRewriter::visitAggregate(Visit visit, TIntermAggregate *node) return true; } -TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) +TIntermNode *ElseBlockRewriter::rewriteIfElse(TIntermIfElse *ifElse) { - ASSERT(selection != nullptr); + ASSERT(ifElse != nullptr); nextTemporaryIndex(); - TIntermTyped *typedCondition = selection->getCondition()->getAsTyped(); + TIntermTyped *typedCondition = ifElse->getCondition()->getAsTyped(); TIntermAggregate *storeCondition = createTempInitDeclaration(typedCondition); - TIntermSelection *falseBlock = nullptr; + TIntermAggregate *falseBlock = nullptr; TType boolType(EbtBool, EbpUndefined, EvqTemporary); - if (selection->getFalseBlock()) + if (ifElse->getFalseBlock()) { TIntermAggregate *negatedElse = nullptr; // crbug.com/346463 @@ -113,17 +99,19 @@ TIntermNode *ElseBlockRewriter::rewriteSelection(TIntermSelection *selection) } TIntermSymbol *conditionSymbolElse = createTempSymbol(boolType); - TIntermUnary *negatedCondition = MakeNewUnary(EOpLogicalNot, conditionSymbolElse); - falseBlock = new TIntermSelection(negatedCondition, - selection->getFalseBlock(), negatedElse); + TIntermUnary *negatedCondition = new TIntermUnary(EOpLogicalNot, conditionSymbolElse); + TIntermIfElse *falseIfElse = + new TIntermIfElse(negatedCondition, ifElse->getFalseBlock(), negatedElse); + falseBlock = TIntermediate::EnsureSequence(falseIfElse); } TIntermSymbol *conditionSymbolSel = createTempSymbol(boolType); - TIntermSelection *newSelection = new TIntermSelection(conditionSymbolSel, selection->getTrueBlock(), falseBlock); + TIntermIfElse *newIfElse = + new TIntermIfElse(conditionSymbolSel, ifElse->getTrueBlock(), falseBlock); TIntermAggregate *block = new TIntermAggregate(EOpSequence); block->getSequence()->push_back(storeCondition); - block->getSequence()->push_back(newSelection); + block->getSequence()->push_back(newIfElse); return block; } diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp new file mode 100644 index 00000000000..bcd0bb5b21b --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp @@ -0,0 +1,171 @@ +// +// 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. +// +// Implementation of texelFetchOffset translation issue workaround. +// See header for more info. + +#include "compiler/translator/RewriteTexelFetchOffset.h" + +#include "common/angleutils.h" +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion); + + private: + Traverser(const TSymbolTable &symbolTable, int shaderVersion); + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + void nextIteration(); + + const TSymbolTable *symbolTable; + const int shaderVersion; + bool mFound = false; +}; + +Traverser::Traverser(const TSymbolTable &symbolTable, int shaderVersion) + : TIntermTraverser(true, false, false), symbolTable(&symbolTable), shaderVersion(shaderVersion) +{ +} + +// static +void Traverser::Apply(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + Traverser traverser(symbolTable, shaderVersion); + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFound) + { + return false; + } + + // Decide if the node represents the call of texelFetchOffset. + if (node->getOp() != EOpFunctionCall || node->isUserDefined()) + { + return true; + } + + if (node->getName().compare(0, 16, "texelFetchOffset") != 0) + { + return true; + } + + // Potential problem case detected, apply workaround. + const TIntermSequence *sequence = node->getSequence(); + ASSERT(sequence->size() == 4u); + + // Decide if there is a 2DArray sampler. + bool is2DArray = node->getName().find("s2a1") != TString::npos; + + // Create new argument list from node->getName(). + // e.g. Get "(is2a1;vi3;i1;" from "texelFetchOffset(is2a1;vi3;i1;vi2;" + TString newArgs = node->getName().substr(16, node->getName().length() - 20); + TString newName = "texelFetch" + newArgs; + TSymbol *texelFetchSymbol = symbolTable->findBuiltIn(newName, shaderVersion); + ASSERT(texelFetchSymbol); + int uniqueId = texelFetchSymbol->getUniqueId(); + + // Create new node that represents the call of function texelFetch. + TIntermAggregate *texelFetchNode = new TIntermAggregate(EOpFunctionCall); + texelFetchNode->setName(newName); + texelFetchNode->setFunctionId(uniqueId); + texelFetchNode->setType(node->getType()); + texelFetchNode->setLine(node->getLine()); + + // Create argument List of texelFetch(sampler, Position+offset, lod). + TIntermSequence newsequence; + + // sampler + newsequence.push_back(sequence->at(0)); + + // Position + TIntermTyped *texCoordNode = sequence->at(1)->getAsTyped(); + ASSERT(texCoordNode); + // offset + TIntermTyped *offsetNode = nullptr; + ASSERT(sequence->at(3)->getAsTyped()); + if (is2DArray) + { + // For 2DArray samplers, Position is ivec3 and offset is ivec2; + // So offset must be converted into an ivec3 before being added to Position. + TIntermAggregate *constructIVec3Node = new TIntermAggregate(EOpConstructIVec3); + constructIVec3Node->setLine(texCoordNode->getLine()); + constructIVec3Node->setType(texCoordNode->getType()); + + TIntermSequence ivec3Sequence; + ivec3Sequence.push_back(sequence->at(3)->getAsTyped()); + + TConstantUnion *zero = new TConstantUnion(); + zero->setIConst(0); + TType *intType = new TType(EbtInt); + + TIntermConstantUnion *zeroNode = new TIntermConstantUnion(zero, *intType); + ivec3Sequence.push_back(zeroNode); + constructIVec3Node->insertChildNodes(0, ivec3Sequence); + + offsetNode = constructIVec3Node; + } + else + { + offsetNode = sequence->at(3)->getAsTyped(); + } + + // Position+offset + TIntermBinary *add = new TIntermBinary(EOpAdd, texCoordNode, offsetNode); + add->setLine(texCoordNode->getLine()); + newsequence.push_back(add); + + // lod + newsequence.push_back(sequence->at(2)); + texelFetchNode->insertChildNodes(0, newsequence); + + // Replace the old node by this new node. + queueReplacement(node, texelFetchNode, OriginalNode::IS_DROPPED); + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteTexelFetchOffset(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + // texelFetchOffset is only valid in GLSL 3.0 and later. + if (shaderVersion < 300) + return; + + Traverser::Apply(root, symbolTable, shaderVersion); +} + +} // namespace sh
\ No newline at end of file diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.h b/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.h new file mode 100644 index 00000000000..4218f0b69a1 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.h @@ -0,0 +1,30 @@ +// +// 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. +// +// This mutating tree traversal works around an issue on the translation +// from texelFetchOffset into HLSL function Load on INTEL drivers. It +// works by translating texelFetchOffset into texelFetch: +// +// - From: texelFetchOffset(sampler, Position, lod, offset) +// - To: texelFetch(sampler, Position+offset, lod) +// +// See http://anglebug.com/1469 + +#ifndef COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_ +#define COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_ + +class TIntermNode; +class TSymbolTable; + +namespace sh +{ + +void RewriteTexelFetchOffset(TIntermNode *root, + const TSymbolTable &symbolTable, + int shaderVersion); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REWRITE_TEXELFETCHOFFSET_H_
\ No newline at end of file diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp b/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp new file mode 100644 index 00000000000..ef708cb2e2e --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp @@ -0,0 +1,112 @@ +// +// 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. +// +// Implementation of evaluating unary integer variable bug workaround. +// See header for more info. + +#include "compiler/translator/RewriteUnaryMinusOperatorInt.h" + +#include "compiler/translator/IntermNode.h" + +namespace sh +{ + +namespace +{ + +class Traverser : public TIntermTraverser +{ + public: + static void Apply(TIntermNode *root); + + private: + Traverser(); + bool visitUnary(Visit visit, TIntermUnary *node) override; + void nextIteration(); + + bool mFound = false; +}; + +// static +void Traverser::Apply(TIntermNode *root) +{ + Traverser traverser; + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.mFound) + { + traverser.updateTree(); + } + } while (traverser.mFound); +} + +Traverser::Traverser() : TIntermTraverser(true, false, false) +{ +} + +void Traverser::nextIteration() +{ + mFound = false; +} + +bool Traverser::visitUnary(Visit visit, TIntermUnary *node) +{ + if (mFound) + { + return false; + } + + // Decide if the current unary operator is unary minus. + if (node->getOp() != EOpNegative) + { + return true; + } + + // Decide if the current operand is an integer variable. + TIntermTyped *opr = node->getOperand(); + if (!opr->getType().isScalarInt()) + { + return true; + } + + // Potential problem case detected, apply workaround: -(int) -> ~(int) + 1. + // ~(int) + TIntermUnary *bitwiseNot = new TIntermUnary(EOpBitwiseNot, opr); + bitwiseNot->setLine(opr->getLine()); + + // Constant 1 (or 1u) + TConstantUnion *one = new TConstantUnion(); + if (opr->getType().getBasicType() == EbtInt) + { + one->setIConst(1); + } + else + { + one->setUConst(1u); + } + TIntermConstantUnion *oneNode = new TIntermConstantUnion(one, opr->getType()); + oneNode->getTypePointer()->setQualifier(EvqConst); + oneNode->setLine(opr->getLine()); + + // ~(int) + 1 + TIntermBinary *add = new TIntermBinary(EOpAdd, bitwiseNot, oneNode); + add->setLine(opr->getLine()); + + queueReplacement(node, add, OriginalNode::IS_DROPPED); + + mFound = true; + return false; +} + +} // anonymous namespace + +void RewriteUnaryMinusOperatorInt(TIntermNode *root) +{ + Traverser::Apply(root); +} + +} // namespace sh
\ No newline at end of file diff --git a/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h b/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h new file mode 100644 index 00000000000..50f0c442a73 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h @@ -0,0 +1,20 @@ +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This mutating tree traversal works around a bug on evaluating unary +// integer variable on Intel D3D driver. It works by rewriting -(int) to +// ~(int) + 1 when evaluating unary integer variables. + +#ifndef COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_ +#define COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_ + +class TIntermNode; +namespace sh +{ + +void RewriteUnaryMinusOperatorInt(TIntermNode *root); + +} // namespace sh + +#endif // COMPILER_TRANSLATOR_REWRITEUNARYMINUSOPERATORINT_H_
\ No newline at end of file diff --git a/chromium/third_party/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/chromium/third_party/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp index 775c5d87101..cb690595924 100644 --- a/chromium/third_party/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp @@ -37,23 +37,9 @@ bool ContainsVectorNode(const TIntermSequence &sequence) return false; } -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 *ConstructVectorIndexBinaryNode(TIntermSymbol *symbolNode, int index) { - TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); - binary->setLeft(symbolNode); - TIntermConstantUnion *indexNode = ConstructIndexNode(index); - binary->setRight(indexNode); - return binary; + return new TIntermBinary(EOpIndexDirect, symbolNode, TIntermTyped::CreateIndexNode(index)); } TIntermBinary *ConstructMatrixIndexBinaryNode( @@ -62,11 +48,8 @@ TIntermBinary *ConstructMatrixIndexBinaryNode( TIntermBinary *colVectorNode = ConstructVectorIndexBinaryNode(symbolNode, colIndex); - TIntermBinary *binary = new TIntermBinary(EOpIndexDirect); - binary->setLeft(colVectorNode); - TIntermConstantUnion *rowIndexNode = ConstructIndexNode(rowIndex); - binary->setRight(rowIndexNode); - return binary; + return new TIntermBinary(EOpIndexDirect, colVectorNode, + TIntermTyped::CreateIndexNode(rowIndex)); } } // namespace anonymous @@ -278,11 +261,8 @@ TString ScalarizeVecAndMatConstructorArgs::createTempVariable(TIntermTyped *orig type.setPrecision(mFragmentPrecisionHigh ? EbpHigh : EbpMedium); } - TIntermBinary *init = new TIntermBinary(EOpInitialize); TIntermSymbol *symbolNode = new TIntermSymbol(-1, tempVarName, type); - init->setLeft(symbolNode); - init->setRight(original); - init->setType(type); + TIntermBinary *init = new TIntermBinary(EOpInitialize, symbolNode, original); TIntermAggregate *decl = new TIntermAggregate(EOpDeclaration); decl->getSequence()->push_back(init); diff --git a/chromium/third_party/angle/src/compiler/translator/SeparateArrayInitialization.cpp b/chromium/third_party/angle/src/compiler/translator/SeparateArrayInitialization.cpp index de9050cd80a..e166eac4aa4 100644 --- a/chromium/third_party/angle/src/compiler/translator/SeparateArrayInitialization.cpp +++ b/chromium/third_party/angle/src/compiler/translator/SeparateArrayInitialization.cpp @@ -69,10 +69,8 @@ bool SeparateArrayInitTraverser::visitAggregate(Visit, TIntermAggregate *node) replacementDeclaration->setLine(symbol->getLine()); replacements.push_back(replacementDeclaration); - TIntermBinary *replacementAssignment = new TIntermBinary(EOpAssign); - replacementAssignment->setLeft(symbol); - replacementAssignment->setRight(initializer); - replacementAssignment->setType(initializer->getType()); + TIntermBinary *replacementAssignment = + new TIntermBinary(EOpAssign, symbol, initializer); replacementAssignment->setLine(symbol->getLine()); replacements.push_back(replacementAssignment); diff --git a/chromium/third_party/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/chromium/third_party/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp index e8e1a21d9c4..20e47974c6d 100644 --- a/chromium/third_party/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp +++ b/chromium/third_party/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp @@ -12,6 +12,7 @@ #include "compiler/translator/SeparateExpressionsReturningArrays.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" namespace { @@ -32,11 +33,14 @@ class SeparateExpressionsTraverser : public TIntermTraverser // Marked to true once an operation that needs to be hoisted out of the expression has been found. // After that, no more AST updates are performed on that traversal. bool mFoundArrayExpression; + + IntermNodePatternMatcher mPatternToSeparateMatcher; }; SeparateExpressionsTraverser::SeparateExpressionsTraverser() : TIntermTraverser(true, false, false), - mFoundArrayExpression(false) + mFoundArrayExpression(false), + mPatternToSeparateMatcher(IntermNodePatternMatcher::kExpressionReturningArray) { } @@ -45,11 +49,7 @@ SeparateExpressionsTraverser::SeparateExpressionsTraverser() // and also needs to be replaced in its original location by a different node. TIntermBinary *CopyAssignmentNode(TIntermBinary *node) { - TIntermBinary *copyNode = new TIntermBinary(node->getOp()); - copyNode->setLeft(node->getLeft()); - copyNode->setRight(node->getRight()); - copyNode->setType(node->getType()); - return copyNode; + return new TIntermBinary(node->getOp(), node->getLeft(), node->getRight()); } // Performs a shallow copy of a constructor/function call node. @@ -73,31 +73,25 @@ bool SeparateExpressionsTraverser::visitBinary(Visit visit, TIntermBinary *node) if (mFoundArrayExpression) return false; - // Early return if the expression is not an array or if we're not inside a complex expression. - if (!node->getType().isArray() || parentNodeIsBlock()) + // Return if the expression is not an array or if we're not inside a complex expression. + if (!mPatternToSeparateMatcher.match(node, getParentNode())) return true; - switch (node->getOp()) - { - case EOpAssign: - { - mFoundArrayExpression = true; - - TIntermSequence insertions; - insertions.push_back(CopyAssignmentNode(node)); - // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just use the - // original target of the assignment. Care must be taken so that this doesn't happen when the same array - // symbol is a target of assignment more than once in one expression. - insertions.push_back(createTempInitDeclaration(node->getLeft())); - insertStatementsInParentBlock(insertions); - - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false); - mReplacements.push_back(replaceVariable); - } - return false; - default: - return true; - } + ASSERT(node->getOp() == EOpAssign); + + mFoundArrayExpression = true; + + TIntermSequence insertions; + insertions.push_back(CopyAssignmentNode(node)); + // TODO(oetuaho): In some cases it would be more optimal to not add the temporary node, but just + // use the original target of the assignment. Care must be taken so that this doesn't happen + // when the same array symbol is a target of assignment more than once in one expression. + insertions.push_back(createTempInitDeclaration(node->getLeft())); + insertStatementsInParentBlock(insertions); + + queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); + + return false; } bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) @@ -105,43 +99,20 @@ bool SeparateExpressionsTraverser::visitAggregate(Visit visit, TIntermAggregate if (mFoundArrayExpression) return false; // No need to traverse further - if (getParentNode() != nullptr) - { - TIntermBinary *parentBinary = getParentNode()->getAsBinaryNode(); - bool parentIsAssignment = (parentBinary != nullptr && - (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize)); - - if (!node->getType().isArray() || parentNodeIsBlock() || parentIsAssignment) - return true; - - if (node->isConstructor()) - { - mFoundArrayExpression = true; - - TIntermSequence insertions; - insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node))); - insertStatementsInParentBlock(insertions); + if (!mPatternToSeparateMatcher.match(node, getParentNode())) + return true; - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false); - mReplacements.push_back(replaceVariable); + ASSERT(node->isConstructor() || node->getOp() == EOpFunctionCall); - return false; - } - else if (node->getOp() == EOpFunctionCall) - { - mFoundArrayExpression = true; + mFoundArrayExpression = true; - TIntermSequence insertions; - insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node))); - insertStatementsInParentBlock(insertions); + TIntermSequence insertions; + insertions.push_back(createTempInitDeclaration(CopyAggregateNode(node))); + insertStatementsInParentBlock(insertions); - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(node->getType()), false); - mReplacements.push_back(replaceVariable); + queueReplacement(node, createTempSymbol(node->getType()), OriginalNode::IS_DROPPED); - return false; - } - } - return true; + return false; } void SeparateExpressionsTraverser::nextIteration() diff --git a/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp index e4f27fb1b56..b6db0f0aef1 100644 --- a/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp @@ -182,6 +182,37 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->MaxExpressionComplexity = 256; resources->MaxCallStackDepth = 256; resources->MaxFunctionParameters = 1024; + + // ES 3.1 Revision 4, 7.2 Built-in Constants + resources->MaxImageUnits = 4; + resources->MaxVertexImageUniforms = 0; + resources->MaxFragmentImageUniforms = 0; + resources->MaxComputeImageUniforms = 4; + resources->MaxCombinedImageUniforms = 4; + + resources->MaxCombinedShaderOutputResources = 4; + + resources->MaxComputeWorkGroupCount[0] = 65535; + resources->MaxComputeWorkGroupCount[1] = 65535; + resources->MaxComputeWorkGroupCount[2] = 65535; + resources->MaxComputeWorkGroupSize[0] = 128; + resources->MaxComputeWorkGroupSize[1] = 128; + resources->MaxComputeWorkGroupSize[2] = 64; + resources->MaxComputeUniformComponents = 512; + resources->MaxComputeTextureImageUnits = 16; + + resources->MaxComputeAtomicCounters = 8; + resources->MaxComputeAtomicCounterBuffers = 1; + + resources->MaxVertexAtomicCounters = 0; + resources->MaxFragmentAtomicCounters = 0; + resources->MaxCombinedAtomicCounters = 8; + resources->MaxAtomicCounterBindings = 1; + + resources->MaxVertexAtomicCounterBuffers = 0; + resources->MaxFragmentAtomicCounterBuffers = 0; + resources->MaxCombinedAtomicCounterBuffers = 1; + resources->MaxAtomicCounterBufferSize = 32; } // @@ -237,11 +268,10 @@ const std::string &ShGetBuiltInResourcesString(const ShHandle handle) // Return: The return value of ShCompile is really boolean, indicating // success or failure. // -bool ShCompile( - const ShHandle handle, - const char *const shaderStrings[], - size_t numStrings, - int compileOptions) +bool ShCompile(const ShHandle handle, + const char *const shaderStrings[], + size_t numStrings, + ShCompileOptions compileOptions) { TCompiler *compiler = GetCompilerFromHandle(handle); ASSERT(compiler); @@ -327,18 +357,20 @@ const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handl return GetShaderVariables<sh::InterfaceBlock>(handle); } -bool ShCheckVariablesWithinPackingLimits( - int maxVectors, ShVariableInfo *varInfoArray, size_t varInfoArraySize) +sh::WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast<TShHandleBase *>(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getComputeShaderLocalSize(); +} + +bool ShCheckVariablesWithinPackingLimits(int maxVectors, + const std::vector<sh::ShaderVariable> &variables) { - if (varInfoArraySize == 0) - return true; - ASSERT(varInfoArray); - std::vector<sh::ShaderVariable> variables; - for (size_t ii = 0; ii < varInfoArraySize; ++ii) - { - sh::ShaderVariable var(varInfoArray[ii].type, varInfoArray[ii].size); - variables.push_back(var); - } VariablePacker packer; return packer.CheckVariablesWithinPackingLimits(maxVectors, variables); } @@ -376,4 +408,4 @@ const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(const ShHandl static std::map<std::string, unsigned int> map; return ↦ #endif // ANGLE_ENABLE_HLSL -}
\ No newline at end of file +} diff --git a/chromium/third_party/angle/src/compiler/translator/ShaderVars.cpp b/chromium/third_party/angle/src/compiler/translator/ShaderVars.cpp index 8f931b9bdd3..8e217f1c0da 100644 --- a/chromium/third_party/angle/src/compiler/translator/ShaderVars.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ShaderVars.cpp @@ -355,7 +355,7 @@ bool Varying::isSameVaryingAtLinkTime(const Varying &other) const bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const { return (ShaderVariable::isSameVariableAtLinkTime(other, false) && - interpolation == other.interpolation && + InterpolationTypesMatch(interpolation, other.interpolation) && (shaderVersion >= 300 || isInvariant == other.isInvariant)); } @@ -398,4 +398,91 @@ std::string InterfaceBlock::fieldPrefix() const return instanceName.empty() ? "" : name; } +bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const +{ + if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize || + layout != other.layout || isRowMajorLayout != other.isRowMajorLayout || + fields.size() != other.fields.size()) + { + return false; + } + + for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex) + { + if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex])) + { + return false; + } + } + + return true; +} + +void WorkGroupSize::fill(int fillValue) +{ + localSizeQualifiers[0] = fillValue; + localSizeQualifiers[1] = fillValue; + localSizeQualifiers[2] = fillValue; +} + +void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ) +{ + localSizeQualifiers[0] = localSizeX; + localSizeQualifiers[1] = localSizeY; + localSizeQualifiers[2] = localSizeZ; +} + +// check that if one of them is less than 1, then all of them are. +// Or if one is positive, then all of them are positive. +bool WorkGroupSize::isLocalSizeValid() const +{ + return ( + (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) || + (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0)); +} + +bool WorkGroupSize::isAnyValueSet() const +{ + return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0; +} + +bool WorkGroupSize::isDeclared() const +{ + bool localSizeDeclared = localSizeQualifiers[0] > 0; + ASSERT(isLocalSizeValid()); + return localSizeDeclared; +} + +bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const +{ + for (size_t i = 0u; i < size(); ++i) + { + bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] || + (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) || + (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1)); + if (!result) + { + return false; + } + } + return true; +} + +int &WorkGroupSize::operator[](size_t index) +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +int WorkGroupSize::operator[](size_t index) const +{ + ASSERT(index < size()); + return localSizeQualifiers[index]; +} + +size_t WorkGroupSize::size() const +{ + return 3u; +} + } // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.cpp b/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.cpp new file mode 100644 index 00000000000..da8da481f24 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.cpp @@ -0,0 +1,282 @@ +// +// 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. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#include "compiler/translator/SimplifyLoopConditions.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" + +namespace +{ + +TIntermConstantUnion *CreateBoolConstantNode(bool value) +{ + TConstantUnion *u = new TConstantUnion; + u->setBConst(value); + TIntermConstantUnion *node = + new TIntermConstantUnion(u, TType(EbtBool, EbpUndefined, EvqConst, 1)); + return node; +} + +class SimplifyLoopConditionsTraverser : public TLValueTrackingTraverser +{ + public: + SimplifyLoopConditionsTraverser(unsigned int conditionsToSimplifyMask, + const TSymbolTable &symbolTable, + int shaderVersion); + + void traverseLoop(TIntermLoop *node) override; + + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + + void nextIteration(); + bool foundLoopToChange() const { return mFoundLoopToChange; } + + protected: + // Marked to true once an operation that needs to be hoisted out of the expression has been + // found. After that, no more AST updates are performed on that traversal. + bool mFoundLoopToChange; + bool mInsideLoopConditionOrExpression; + IntermNodePatternMatcher mConditionsToSimplify; +}; + +SimplifyLoopConditionsTraverser::SimplifyLoopConditionsTraverser( + unsigned int conditionsToSimplifyMask, + const TSymbolTable &symbolTable, + int shaderVersion) + : TLValueTrackingTraverser(true, false, false, symbolTable, shaderVersion), + mFoundLoopToChange(false), + mInsideLoopConditionOrExpression(false), + mConditionsToSimplify(conditionsToSimplifyMask) +{ +} + +void SimplifyLoopConditionsTraverser::nextIteration() +{ + mFoundLoopToChange = false; + mInsideLoopConditionOrExpression = false; + nextTemporaryIndex(); +} + +bool SimplifyLoopConditionsTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + // The visit functions operate in three modes: + // 1. If a matching expression has already been found, we return early since only one loop can + // be transformed on one traversal. + // 2. We try to find loops. In case a node is not inside a loop and can not contain loops, we + // stop traversing the subtree. + // 3. If we're inside a loop condition or expression, we check for expressions that should be + // moved out of the loop condition or expression. If one is found, the loop is processed. + + if (mFoundLoopToChange) + return false; + + if (!mInsideLoopConditionOrExpression) + return false; + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (mFoundLoopToChange) + return false; + + // If we're outside a loop condition, we only need to traverse nodes that may contain loops. + if (!mInsideLoopConditionOrExpression) + return (node->getOp() == EOpSequence || node->getOp() == EOpFunction); + + mFoundLoopToChange = mConditionsToSimplify.match(node, getParentNode()); + return !mFoundLoopToChange; +} + +bool SimplifyLoopConditionsTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (mFoundLoopToChange) + return false; + + // Don't traverse ternary operators outside loop conditions. + if (!mInsideLoopConditionOrExpression) + return false; + + mFoundLoopToChange = mConditionsToSimplify.match(node); + return !mFoundLoopToChange; +} + +void SimplifyLoopConditionsTraverser::traverseLoop(TIntermLoop *node) +{ + if (mFoundLoopToChange) + return; + + // Mark that we're inside a loop condition or expression, and transform the loop if needed. + + incrementDepth(node); + + // Note: No need to traverse the loop init node. + + mInsideLoopConditionOrExpression = true; + TLoopType loopType = node->getType(); + + if (node->getCondition()) + { + node->getCondition()->traverse(this); + + if (mFoundLoopToChange) + { + // Replace the loop condition with a boolean variable that's updated on each iteration. + if (loopType == ELoopWhile) + { + // Transform: + // while (expr) { body; } + // into + // bool s0 = expr; + // while (s0) { { body; } s0 = expr; } + TIntermSequence tempInitSeq; + tempInitSeq.push_back(createTempInitDeclaration(node->getCondition()->deepCopy())); + insertStatementsInParentBlock(tempInitSeq); + + TIntermAggregate *newBody = new TIntermAggregate(EOpSequence); + if (node->getBody()) + { + ASSERT(node->getBody()->getOp() == EOpSequence); + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - this node won't be traversed + // further. + node->setBody(newBody); + node->setCondition(createTempSymbol(node->getCondition()->getType())); + } + else if (loopType == ELoopDoWhile) + { + // Transform: + // do { + // body; + // } while (expr); + // into + // bool s0 = true; + // do { + // { body; } + // s0 = expr; + // while (s0); + TIntermSequence tempInitSeq; + tempInitSeq.push_back(createTempInitDeclaration(CreateBoolConstantNode(true))); + insertStatementsInParentBlock(tempInitSeq); + + TIntermAggregate *newBody = new TIntermAggregate(EOpSequence); + if (node->getBody()) + { + ASSERT(node->getBody()->getOp() == EOpSequence); + newBody->getSequence()->push_back(node->getBody()); + } + newBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + + // Can't use queueReplacement to replace old body, since it may have been nullptr. + // It's safe to do the replacements in place here - this node won't be traversed + // further. + node->setBody(newBody); + node->setCondition(createTempSymbol(node->getCondition()->getType())); + } + else if (loopType == ELoopFor) + { + // Move the loop condition inside the loop. + // Transform: + // for (init; expr; exprB) { body; } + // into + // { + // init; + // bool s0 = expr; + // while (s0) { { body; } exprB; s0 = expr; } + // } + TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence); + if (node->getInit()) + { + loopScope->getSequence()->push_back(node->getInit()); + } + loopScope->getSequence()->push_back( + createTempInitDeclaration(node->getCondition()->deepCopy())); + + TIntermAggregate *whileLoopBody = new TIntermAggregate(EOpSequence); + if (node->getBody()) + { + whileLoopBody->getSequence()->push_back(node->getBody()); + } + whileLoopBody->getSequence()->push_back(node->getExpression()); + whileLoopBody->getSequence()->push_back( + createTempAssignment(node->getCondition()->deepCopy())); + TIntermLoop *whileLoop = new TIntermLoop( + ELoopWhile, nullptr, createTempSymbol(node->getCondition()->getType()), nullptr, + whileLoopBody); + loopScope->getSequence()->push_back(whileLoop); + queueReplacementWithParent(getAncestorNode(1), node, loopScope, + OriginalNode::IS_DROPPED); + } + } + } + + if (!mFoundLoopToChange && node->getExpression()) + { + node->getExpression()->traverse(this); + + if (mFoundLoopToChange) + { + ASSERT(loopType == ELoopFor); + // Move the loop expression to inside the loop. + // Transform: + // for (init; expr; exprB) { body; } + // into + // for (init; expr; ) { { body; } exprB; } + TIntermTyped *loopExpression = node->getExpression(); + node->setExpression(nullptr); + TIntermAggregate *oldBody = node->getBody(); + node->setBody(new TIntermAggregate(EOpSequence)); + if (oldBody != nullptr) + { + node->getBody()->getSequence()->push_back(oldBody); + } + node->getBody()->getSequence()->push_back(loopExpression); + } + } + + mInsideLoopConditionOrExpression = false; + + if (!mFoundLoopToChange && node->getBody()) + node->getBody()->traverse(this); + + decrementDepth(); +} + +} // namespace + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplifyMask, + unsigned int *temporaryIndex, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + SimplifyLoopConditionsTraverser traverser(conditionsToSimplifyMask, symbolTable, shaderVersion); + ASSERT(temporaryIndex != nullptr); + traverser.useTemporaryIndex(temporaryIndex); + // Process one loop at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundLoopToChange()) + traverser.updateTree(); + } while (traverser.foundLoopToChange()); +} diff --git a/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.h b/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.h new file mode 100644 index 00000000000..b8802aa11af --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.h @@ -0,0 +1,23 @@ +// +// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SimplifyLoopConditions is an AST traverser that converts loop conditions and loop expressions +// to regular statements inside the loop. This way further transformations that generate statements +// from loop conditions and loop expressions work correctly. +// + +#ifndef COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ +#define COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ + +class TIntermNode; +class TSymbolTable; + +void SimplifyLoopConditions(TIntermNode *root, + unsigned int conditionsToSimplify, + unsigned int *temporaryIndex, + const TSymbolTable &symbolTable, + int shaderVersion); + +#endif // COMPILER_TRANSLATOR_SIMPLIFYLOOPCONDITIONS_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.cpp b/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.cpp new file mode 100644 index 00000000000..ff6443d30e2 --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.cpp @@ -0,0 +1,160 @@ +// +// 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. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#include "compiler/translator/SplitSequenceOperator.h" + +#include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" + +namespace +{ + +class SplitSequenceOperatorTraverser : public TLValueTrackingTraverser +{ + public: + SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, + const TSymbolTable &symbolTable, + int shaderVersion); + + bool visitBinary(Visit visit, TIntermBinary *node) override; + bool visitAggregate(Visit visit, TIntermAggregate *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + + void nextIteration(); + bool foundExpressionToSplit() const { return mFoundExpressionToSplit; } + + protected: + // Marked to true once an operation that needs to be hoisted out of the expression has been + // found. After that, no more AST updates are performed on that traversal. + bool mFoundExpressionToSplit; + int mInsideSequenceOperator; + + IntermNodePatternMatcher mPatternToSplitMatcher; +}; + +SplitSequenceOperatorTraverser::SplitSequenceOperatorTraverser(unsigned int patternsToSplitMask, + const TSymbolTable &symbolTable, + int shaderVersion) + : TLValueTrackingTraverser(true, false, true, symbolTable, shaderVersion), + mFoundExpressionToSplit(false), + mInsideSequenceOperator(0), + mPatternToSplitMatcher(patternsToSplitMask) +{ +} + +void SplitSequenceOperatorTraverser::nextIteration() +{ + mFoundExpressionToSplit = false; + mInsideSequenceOperator = 0; + nextTemporaryIndex(); +} + +bool SplitSequenceOperatorTraverser::visitBinary(Visit visit, TIntermBinary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = + mPatternToSplitMatcher.match(node, getParentNode(), isLValueRequiredHere()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitAggregate(Visit visit, TIntermAggregate *node) +{ + if (node->getOp() == EOpComma) + { + if (visit == PreVisit) + { + if (mFoundExpressionToSplit) + { + return false; + } + mInsideSequenceOperator++; + } + else if (visit == PostVisit) + { + // Split sequence operators starting from the outermost one to preserve correct + // execution order. + if (mFoundExpressionToSplit && mInsideSequenceOperator == 1) + { + // Move all operands of the sequence operation except the last one into separate + // statements in the parent block. + TIntermSequence insertions; + for (auto *sequenceChild : *node->getSequence()) + { + if (sequenceChild != node->getSequence()->back()) + { + insertions.push_back(sequenceChild); + } + } + insertStatementsInParentBlock(insertions); + // Replace the sequence with its last operand + queueReplacement(node, node->getSequence()->back(), OriginalNode::IS_DROPPED); + } + mInsideSequenceOperator--; + } + return true; + } + + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node, getParentNode()); + return !mFoundExpressionToSplit; + } + + return true; +} + +bool SplitSequenceOperatorTraverser::visitTernary(Visit visit, TIntermTernary *node) +{ + if (mFoundExpressionToSplit) + return false; + + if (mInsideSequenceOperator > 0 && visit == PreVisit) + { + // Detect expressions that need to be simplified + mFoundExpressionToSplit = mPatternToSplitMatcher.match(node); + return !mFoundExpressionToSplit; + } + + return true; +} + +} // namespace + +void SplitSequenceOperator(TIntermNode *root, + int patternsToSplitMask, + unsigned int *temporaryIndex, + const TSymbolTable &symbolTable, + int shaderVersion) +{ + SplitSequenceOperatorTraverser traverser(patternsToSplitMask, symbolTable, shaderVersion); + ASSERT(temporaryIndex != nullptr); + traverser.useTemporaryIndex(temporaryIndex); + // Separate one expression at a time, and reset the traverser between iterations. + do + { + traverser.nextIteration(); + root->traverse(&traverser); + if (traverser.foundExpressionToSplit()) + traverser.updateTree(); + } while (traverser.foundExpressionToSplit()); +} diff --git a/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.h b/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.h new file mode 100644 index 00000000000..4a46fe36c0a --- /dev/null +++ b/chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.h @@ -0,0 +1,24 @@ +// +// 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. +// +// SplitSequenceOperator is an AST traverser that detects sequence operator expressions that +// go through further AST transformations that generate statements, and splits them so that +// possible side effects of earlier parts of the sequence operator expression are guaranteed to be +// evaluated before the latter parts of the sequence operator expression are evaluated. +// + +#ifndef COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ +#define COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ + +class TIntermNode; +class TSymbolTable; + +void SplitSequenceOperator(TIntermNode *root, + int patternsToSplitMask, + unsigned int *temporaryIndex, + const TSymbolTable &symbolTable, + int shaderVersion); + +#endif // COMPILER_TRANSLATOR_SPLITSEQUENCEOPERATOR_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp index f5789091425..059c5c76ab5 100644 --- a/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp +++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp @@ -88,7 +88,9 @@ TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, do { - if (level == ESSL3_BUILTINS && shaderVersion != 300) + if (level == ESSL3_1_BUILTINS && shaderVersion != 310) + level--; + if (level == ESSL3_BUILTINS && shaderVersion < 300) level--; if (level == ESSL1_BUILTINS && shaderVersion != 100) level--; @@ -110,7 +112,9 @@ TSymbol *TSymbolTable::findBuiltIn( { for (int level = LAST_BUILTIN_LEVEL; level >= 0; level--) { - if (level == ESSL3_BUILTINS && shaderVersion != 300) + if (level == ESSL3_1_BUILTINS && shaderVersion != 310) + level--; + if (level == ESSL3_BUILTINS && shaderVersion < 300) level--; if (level == ESSL1_BUILTINS && shaderVersion != 100) level--; diff --git a/chromium/third_party/angle/src/compiler/translator/SymbolTable.h b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h index 6de7c988300..f092412ad83 100644 --- a/chromium/third_party/angle/src/compiler/translator/SymbolTable.h +++ b/chromium/third_party/angle/src/compiler/translator/SymbolTable.h @@ -30,6 +30,7 @@ // are tracked in the intermediate representation, not the symbol table. // +#include <array> #include <assert.h> #include <set> @@ -295,6 +296,7 @@ class TSymbolTableLevel typedef std::pair<tLevel::iterator, bool> tInsertResult; TSymbolTableLevel() + : mGlobalInvariant(false) { } ~TSymbolTableLevel(); @@ -306,8 +308,22 @@ class TSymbolTableLevel TSymbol *find(const TString &name) const; + void addInvariantVarying(const std::string &name) + { + mInvariantVaryings.insert(name); + } + + bool isVaryingInvariant(const std::string &name) + { + return (mGlobalInvariant || mInvariantVaryings.count(name) > 0); + } + + void setGlobalInvariant(bool invariant) { mGlobalInvariant = invariant; } + protected: tLevel level; + std::set<std::string> mInvariantVaryings; + bool mGlobalInvariant; }; // Define ESymbolLevel as int rather than an enum since level can go @@ -317,14 +333,14 @@ typedef int ESymbolLevel; const int COMMON_BUILTINS = 0; const int ESSL1_BUILTINS = 1; const int ESSL3_BUILTINS = 2; -const int LAST_BUILTIN_LEVEL = ESSL3_BUILTINS; -const int GLOBAL_LEVEL = 3; +const int ESSL3_1_BUILTINS = 3; +const int LAST_BUILTIN_LEVEL = ESSL3_1_BUILTINS; +const int GLOBAL_LEVEL = 4; class TSymbolTable : angle::NonCopyable { public: TSymbolTable() - : mGlobalInvariant(false) { // The symbol table cannot be used until push() is called, but // the lack of an initial call to push() can be used to detect @@ -346,7 +362,7 @@ class TSymbolTable : angle::NonCopyable } bool atGlobalLevel() const { - return currentLevel() <= GLOBAL_LEVEL; + return currentLevel() == GLOBAL_LEVEL; } void push() { @@ -379,10 +395,10 @@ class TSymbolTable : angle::NonCopyable return table[level]->insert(symbol); } - bool insertConstInt(ESymbolLevel level, const char *name, int value) + bool insertConstInt(ESymbolLevel level, const char *name, int value, TPrecision precision) { - TVariable *constant = new TVariable( - NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); + TVariable *constant = + new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 1)); TConstantUnion *unionArray = new TConstantUnion[1]; unionArray[0].setIConst(value); constant->shareConstPointer(unionArray); @@ -399,6 +415,24 @@ class TSymbolTable : angle::NonCopyable return insert(level, ext, constant); } + bool insertConstIvec3(ESymbolLevel level, + const char *name, + const std::array<int, 3> &values, + TPrecision precision) + { + TVariable *constantIvec3 = + new TVariable(NewPoolTString(name), TType(EbtInt, precision, EvqConst, 3)); + + TConstantUnion *unionArray = new TConstantUnion[3]; + for (size_t index = 0u; index < 3u; ++index) + { + unionArray[index].setIConst(values[index]); + } + constantIvec3->shareConstPointer(unionArray); + + return insert(level, constantIvec3); + } + void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, const TType *rvalue, const char *name, const TType *ptype1, const TType *ptype2 = 0, const TType *ptype3 = 0, const TType *ptype4 = 0, const TType *ptype5 = 0); @@ -437,15 +471,15 @@ class TSymbolTable : angle::NonCopyable bool setDefaultPrecision(const TPublicType &type, TPrecision prec) { - if (!SupportsPrecision(type.type)) + if (!SupportsPrecision(type.getBasicType())) return false; - if (type.type == EbtUInt) + if (type.getBasicType() == EbtUInt) return false; // ESSL 3.00.4 section 4.5.4 if (type.isAggregate()) return false; // Not allowed to set for aggregate types int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; // Uses map operator [], overwrites the current value - (*precisionStack[indexOfLastElement])[type.type] = prec; + (*precisionStack[indexOfLastElement])[type.getBasicType()] = prec; return true; } @@ -457,7 +491,8 @@ class TSymbolTable : angle::NonCopyable // "invariant varying_name;". void addInvariantVarying(const std::string &originalName) { - mInvariantVaryings.insert(originalName); + ASSERT(atGlobalLevel()); + table[currentLevel()]->addInvariantVarying(originalName); } // If this returns false, the varying could still be invariant // if it is set as invariant during the varying variable @@ -465,12 +500,15 @@ class TSymbolTable : angle::NonCopyable // variable's type, not here. bool isVaryingInvariant(const std::string &originalName) const { - return (mGlobalInvariant || - mInvariantVaryings.count(originalName) > 0); + ASSERT(atGlobalLevel()); + return table[currentLevel()]->isVaryingInvariant(originalName); } - void setGlobalInvariant() { mGlobalInvariant = true; } - bool getGlobalInvariant() const { return mGlobalInvariant; } + void setGlobalInvariant(bool invariant) + { + ASSERT(atGlobalLevel()); + table[currentLevel()]->setGlobalInvariant(invariant); + } static int nextUniqueId() { @@ -500,9 +538,6 @@ class TSymbolTable : angle::NonCopyable std::set<std::string> mUnmangledBuiltinNames; - std::set<std::string> mInvariantVaryings; - bool mGlobalInvariant; - static int uniqueIdCounter; }; diff --git a/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.cpp index f0b48d047c8..a0719006b9e 100644 --- a/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.cpp @@ -473,22 +473,40 @@ void GetTextureReference(TInfoSinkBase &out, void OutputTextureSizeFunctionBody(TInfoSinkBase &out, const TextureFunctionHLSL::TextureFunction &textureFunction, - const TString &textureReference) + const TString &textureReference, + bool getDimensionsIgnoresBaseLevel) { - out << "int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n"; + if (getDimensionsIgnoresBaseLevel) + { + out << "int baseLevel = samplerMetadata[samplerIndex].baseLevel;\n"; + } + else + { + out << "int baseLevel = 0;\n"; + } + if (IsSampler3D(textureFunction.sampler) || IsSamplerArray(textureFunction.sampler) || (IsIntegerSampler(textureFunction.sampler) && IsSamplerCube(textureFunction.sampler))) { // "depth" stores either the number of layers in an array texture or 3D depth out << " uint width; uint height; uint depth; uint numberOfLevels;\n" << " " << textureReference - << ".GetDimensions(baseLevel + lod, width, height, depth, numberOfLevels);\n"; + << ".GetDimensions(baseLevel, width, height, depth, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; + + if (!IsSamplerArray(textureFunction.sampler)) + { + out << " depth = max(depth >> lod, 1);\n"; + } } else if (IsSampler2D(textureFunction.sampler) || IsSamplerCube(textureFunction.sampler)) { out << " uint width; uint height; uint numberOfLevels;\n" << " " << textureReference - << ".GetDimensions(baseLevel + lod, width, height, numberOfLevels);\n"; + << ".GetDimensions(baseLevel, width, height, numberOfLevels);\n" + << " width = max(width >> lod, 1);\n" + << " height = max(height >> lod, 1);\n"; } else UNREACHABLE(); @@ -1095,32 +1113,8 @@ const char *TextureFunctionHLSL::TextureFunction::getReturnType() const bool TextureFunctionHLSL::TextureFunction::operator<(const TextureFunction &rhs) const { - if (sampler < rhs.sampler) - return true; - if (sampler > rhs.sampler) - return false; - - if (coords < rhs.coords) - return true; - if (coords > rhs.coords) - return false; - - if (!proj && rhs.proj) - return true; - if (proj && !rhs.proj) - return false; - - if (!offset && rhs.offset) - return true; - if (offset && !rhs.offset) - return false; - - if (method < rhs.method) - return true; - if (method > rhs.method) - return false; - - return false; + return std::tie(sampler, coords, proj, offset, method) < + std::tie(rhs.sampler, rhs.coords, rhs.proj, rhs.offset, rhs.method); } TString TextureFunctionHLSL::useTextureFunction(const TString &name, @@ -1249,7 +1243,9 @@ TString TextureFunctionHLSL::useTextureFunction(const TString &name, return textureFunction.name(); } -void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, const ShShaderOutput outputType) +void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel) { for (const TextureFunction &textureFunction : mUsesTexture) { @@ -1272,7 +1268,8 @@ void TextureFunctionHLSL::textureFunctionHeader(TInfoSinkBase &out, const ShShad if (textureFunction.method == TextureFunction::SIZE) { - OutputTextureSizeFunctionBody(out, textureFunction, textureReference); + OutputTextureSizeFunctionBody(out, textureFunction, textureReference, + getDimensionsIgnoresBaseLevel); } else { diff --git a/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.h b/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.h index 6c8ce3130f5..68bf8c0898c 100644 --- a/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.h @@ -62,7 +62,9 @@ class TextureFunctionHLSL final : angle::NonCopyable bool lod0, sh::GLenum shaderType); - void textureFunctionHeader(TInfoSinkBase &out, const ShShaderOutput outputType); + void textureFunctionHeader(TInfoSinkBase &out, + const ShShaderOutput outputType, + bool getDimensionsIgnoresBaseLevel); private: typedef std::set<TextureFunction> TextureFunctionSet; diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp index 76d006fd11d..109b1700d5d 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp @@ -6,7 +6,6 @@ #include "compiler/translator/TranslatorESSL.h" -#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" #include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/RecordConstantPrecision.h" #include "compiler/translator/OutputESSL.h" @@ -17,15 +16,8 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) { } -void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOptions) { - if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) - { - InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); - } -} - -void TranslatorESSL::translate(TIntermNode *root, int) { TInfoSinkBase& sink = getInfoSink().obj; int shaderVer = getShaderVersion(); @@ -34,11 +26,13 @@ void TranslatorESSL::translate(TIntermNode *root, int) { sink << "#version " << shaderVer << " es\n"; } - writePragma(); - // Write built-in extension behaviors. writeExtensionBehavior(); + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) @@ -46,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode *root, int) { EmulatePrecision emulatePrecision(getSymbolTable(), shaderVer); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); - emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT); + emulatePrecision.writeEmulationHelpers(sink, shaderVer, SH_ESSL_OUTPUT); } RecordConstantPrecision(root, getTemporaryIndex()); @@ -75,12 +69,25 @@ void TranslatorESSL::translate(TIntermNode *root, int) { // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) + { + const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); + sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] + << ", local_size_z=" << localSize[2] << ") in;\n"; + } + // Write translated shader. TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), shaderVer, precisionEmulation); root->traverse(&outputESSL); } +bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Not necessary when translating to ESSL. + return false; +} + void TranslatorESSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; const TExtensionBehavior& extBehavior = getExtensionBehavior(); diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h index 2cc61074d48..f147ca06610 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h @@ -15,9 +15,8 @@ class TranslatorESSL : public TCompiler TranslatorESSL(sh::GLenum type, ShShaderSpec spec); protected: - void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; - - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermNode *root, ShCompileOptions compileOptions) override; + bool shouldFlattenPragmaStdglInvariantAll() override; private: void writeExtensionBehavior(); diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp index a05802fbcda..a0ee01f55b8 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -11,6 +11,7 @@ #include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/ExtensionGLSL.h" #include "compiler/translator/OutputGLSL.h" +#include "compiler/translator/RewriteTexelFetchOffset.h" #include "compiler/translator/VersionGLSL.h" TranslatorGLSL::TranslatorGLSL(sh::GLenum type, @@ -19,29 +20,73 @@ TranslatorGLSL::TranslatorGLSL(sh::GLenum type, : TCompiler(type, spec, output) { } -void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) { - if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + if (compileOptions & SH_EMULATE_ABS_INT_FUNCTION) { - InitBuiltInFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(emu, getShaderType()); + } + + if (compileOptions & SH_EMULATE_ISNAN_FLOAT_FUNCTION) + { + InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(emu, getShaderVersion()); } int targetGLSLVersion = ShaderOutputTypeToGLSLVersion(getOutputType()); InitBuiltInFunctionEmulatorForGLSLMissingFunctions(emu, getShaderType(), targetGLSLVersion); } -void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) +void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); - writePragma(); - // Write extension behaviour as needed writeExtensionBehavior(root); + // Write pragmas after extensions because some drivers consider pragmas + // like non-preprocessor tokens. + writePragma(compileOptions); + + // If flattening the global invariant pragma, write invariant declarations for built-in + // variables. It should be harmless to do this twice in the case that the shader also explicitly + // did this. However, it's important to emit invariant qualifiers only for those built-in + // variables that are actually used, to avoid affecting the behavior of the shader. + if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && getPragma().stdgl.invariantAll) + { + collectVariables(root); + + switch (getShaderType()) + { + case GL_VERTEX_SHADER: + sink << "invariant gl_Position;\n"; + + // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment + // shaders if it's statically referenced. + conditionallyOutputInvariantDeclaration("gl_PointSize"); + break; + case GL_FRAGMENT_SHADER: + // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment + // shaders, so we can use simple logic to determine whether to declare these + // variables invariant. + conditionallyOutputInvariantDeclaration("gl_FragCoord"); + conditionallyOutputInvariantDeclaration("gl_PointCoord"); + break; + default: + // Currently not reached, but leave this in for future expansion. + ASSERT(false); + break; + } + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) @@ -49,7 +94,7 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); - emulatePrecision.writeEmulationHelpers(sink, getOutputType()); + emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType()); } // Write emulated built-in functions if needed. @@ -132,6 +177,13 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) } } + if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) + { + const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); + sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] + << ", local_size_z=" << localSize[2] << ") in;\n"; + } + // Write translated shader. TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), @@ -143,6 +195,13 @@ void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) root->traverse(&outputGLSL); } +bool TranslatorGLSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Required when outputting to any GLSL version greater than 1.20, but since ANGLE doesn't + // translate to that version, return true for the next higher version. + return IsGLSL130OrNewer(getOutputType()); +} + void TranslatorGLSL::writeVersion(TIntermNode *root) { TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType()); @@ -221,3 +280,12 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) sink << "#extension " << ext << " : require\n"; } } + +void TranslatorGLSL::conditionallyOutputInvariantDeclaration(const char *builtinVaryingName) +{ + if (isVaryingDefined(builtinVaryingName)) + { + TInfoSinkBase &sink = getInfoSink().obj; + sink << "invariant " << builtinVaryingName << ";\n"; + } +} diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h index 4f07b219800..f234c18eca2 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h @@ -15,13 +15,16 @@ class TranslatorGLSL : public TCompiler TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); protected: - void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, + ShCompileOptions compileOptions) override; - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermNode *root, ShCompileOptions compileOptions) override; + bool shouldFlattenPragmaStdglInvariantAll() override; private: void writeVersion(TIntermNode *root); void writeExtensionBehavior(TIntermNode *root); + void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName); }; #endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp index 111a38b7ede..fb011da7667 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -6,13 +6,22 @@ #include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/AddDefaultReturnStatements.h" #include "compiler/translator/ArrayReturnValueToOutParameter.h" +#include "compiler/translator/BreakVariableAliasingInInnerLoops.h" +#include "compiler/translator/EmulatePrecision.h" +#include "compiler/translator/ExpandIntegerPowExpressions.h" +#include "compiler/translator/IntermNodePatternMatcher.h" #include "compiler/translator/OutputHLSL.h" #include "compiler/translator/RemoveDynamicIndexing.h" #include "compiler/translator/RewriteElseBlocks.h" +#include "compiler/translator/RewriteTexelFetchOffset.h" +#include "compiler/translator/RewriteUnaryMinusOperatorInt.h" #include "compiler/translator/SeparateArrayInitialization.h" #include "compiler/translator/SeparateDeclarations.h" #include "compiler/translator/SeparateExpressionsReturningArrays.h" +#include "compiler/translator/SimplifyLoopConditions.h" +#include "compiler/translator/SplitSequenceOperator.h" #include "compiler/translator/UnfoldShortCircuitToIf.h" TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) @@ -20,13 +29,29 @@ TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutpu { } -void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) +void TranslatorHLSL::translate(TIntermNode *root, ShCompileOptions compileOptions) { const ShBuiltInResources &resources = getResources(); int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + sh::AddDefaultReturnStatements(root); + SeparateDeclarations(root); + // Note that SimplifyLoopConditions needs to be run before any other AST transformations that + // may need to generate new statements from loop conditions or loop expressions. + SimplifyLoopConditions(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + getTemporaryIndex(), getSymbolTable(), getShaderVersion()); + + SplitSequenceOperator(root, + IntermNodePatternMatcher::kExpressionReturningArray | + IntermNodePatternMatcher::kUnfoldedShortCircuitExpression | + IntermNodePatternMatcher::kDynamicIndexingOfVectorOrMatrixInLValue, + getTemporaryIndex(), getSymbolTable(), getShaderVersion()); + // Note that SeparateDeclarations needs to be run before UnfoldShortCircuitToIf. UnfoldShortCircuitToIf(root, getTemporaryIndex()); @@ -52,6 +77,40 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) sh::RewriteElseBlocks(root, getTemporaryIndex()); } + // Work around an HLSL compiler frontend aliasing optimization bug. + // TODO(cwallez) The date is 2016-08-25, Microsoft said the bug would be fixed + // in the next release of d3dcompiler.dll, it would be nice to detect the DLL + // version and only apply the workaround if it is too old. + sh::BreakVariableAliasingInInnerLoops(root); + + bool precisionEmulation = + getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(getInfoSink().obj, getShaderVersion(), + getOutputType()); + } + + if ((compileOptions & SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS) != 0) + { + sh::ExpandIntegerPowExpressions(root, getTemporaryIndex()); + } + + if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) + { + sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); + } + + if (((compileOptions & SH_REWRITE_INTEGER_UNARY_MINUS_OPERATOR) != 0) && + getShaderType() == GL_VERTEX_SHADER) + { + sh::RewriteUnaryMinusOperatorInt(root); + } + sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions); @@ -61,6 +120,12 @@ void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); } +bool TranslatorHLSL::shouldFlattenPragmaStdglInvariantAll() +{ + // Not necessary when translating to HLSL. + return false; +} + bool TranslatorHLSL::hasInterfaceBlock(const std::string &interfaceBlockName) const { return (mInterfaceBlockRegisterMap.count(interfaceBlockName) > 0); @@ -75,4 +140,4 @@ unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interf const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const { return &mUniformRegisterMap; -}
\ No newline at end of file +} diff --git a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h index 40cfd70f7b6..213d8606822 100644 --- a/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h +++ b/chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h @@ -21,10 +21,11 @@ class TranslatorHLSL : public TCompiler const std::map<std::string, unsigned int> *getUniformRegisterMap() const; protected: - void translate(TIntermNode *root, int compileOptions) override; + void translate(TIntermNode *root, ShCompileOptions compileOptions) override; + bool shouldFlattenPragmaStdglInvariantAll() override; // collectVariables needs to be run always so registers can be assigned. - bool shouldCollectVariables(int compileOptions) override { return true; } + bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; } std::map<std::string, unsigned int> mInterfaceBlockRegisterMap; std::map<std::string, unsigned int> mUniformRegisterMap; diff --git a/chromium/third_party/angle/src/compiler/translator/Types.cpp b/chromium/third_party/angle/src/compiler/translator/Types.cpp index dffdd370aee..a1dac123aed 100644 --- a/chromium/third_party/angle/src/compiler/translator/Types.cpp +++ b/chromium/third_party/angle/src/compiler/translator/Types.cpp @@ -11,6 +11,7 @@ #include "compiler/translator/Types.h" #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/SymbolTable.h" #include <algorithm> #include <climits> @@ -48,12 +49,20 @@ const char* getBasicString(TBasicType t) } TType::TType(const TPublicType &p) - : type(p.type), precision(p.precision), qualifier(p.qualifier), invariant(p.invariant), - layoutQualifier(p.layoutQualifier), primarySize(p.primarySize), secondarySize(p.secondarySize), - array(p.array), arraySize(p.arraySize), interfaceBlock(0), structure(0) + : type(p.getBasicType()), + precision(p.precision), + qualifier(p.qualifier), + invariant(p.invariant), + layoutQualifier(p.layoutQualifier), + primarySize(p.getPrimarySize()), + secondarySize(p.getSecondarySize()), + array(p.array), + arraySize(p.arraySize), + interfaceBlock(0), + structure(0) { - if (p.userDef) - structure = p.userDef->getStruct(); + if (p.getUserDef()) + structure = p.getUserDef()->getStruct(); } bool TStructure::equals(const TStructure &other) const @@ -61,6 +70,122 @@ bool TStructure::equals(const TStructure &other) const return (uniqueId() == other.uniqueId()); } +const char *TType::getBuiltInTypeNameString() const +{ + if (isMatrix()) + { + switch (getCols()) + { + case 2: + switch (getRows()) + { + case 2: + return "mat2"; + case 3: + return "mat2x3"; + case 4: + return "mat2x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 3: + switch (getRows()) + { + case 2: + return "mat3x2"; + case 3: + return "mat3"; + case 4: + return "mat3x4"; + default: + UNREACHABLE(); + return nullptr; + } + case 4: + switch (getRows()) + { + case 2: + return "mat4x2"; + case 3: + return "mat4x3"; + case 4: + return "mat4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + if (isVector()) + { + switch (getBasicType()) + { + case EbtFloat: + switch (getNominalSize()) + { + case 2: + return "vec2"; + case 3: + return "vec3"; + case 4: + return "vec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtInt: + switch (getNominalSize()) + { + case 2: + return "ivec2"; + case 3: + return "ivec3"; + case 4: + return "ivec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtBool: + switch (getNominalSize()) + { + case 2: + return "bvec2"; + case 3: + return "bvec3"; + case 4: + return "bvec4"; + default: + UNREACHABLE(); + return nullptr; + } + case EbtUInt: + switch (getNominalSize()) + { + case 2: + return "uvec2"; + case 3: + return "uvec3"; + case 4: + return "uvec4"; + default: + UNREACHABLE(); + return nullptr; + } + default: + UNREACHABLE(); + return nullptr; + } + } + ASSERT(getBasicType() != EbtStruct); + ASSERT(getBasicType() != EbtInterfaceBlock); + return getBasicString(); +} + TString TType::getCompleteString() const { TStringStream stream; @@ -202,7 +327,9 @@ size_t TType::getObjectSize() const if (isArray()) { - // TODO: getArraySize() returns an int, not a size_t + if (totalSize == 0) + return 0; + size_t currentArraySize = getArraySize(); if (currentArraySize > INT_MAX / totalSize) totalSize = INT_MAX; @@ -213,6 +340,14 @@ size_t TType::getObjectSize() const return totalSize; } +TStructure::TStructure(const TString *name, TFieldList *fields) + : TFieldListCollection(name, fields), + mDeepestNesting(0), + mUniqueId(TSymbolTable::nextUniqueId()), + mAtGlobalScope(false) +{ +} + bool TStructure::containsArrays() const { for (size_t i = 0; i < mFields->size(); ++i) @@ -248,7 +383,7 @@ bool TStructure::containsSamplers() const void TStructure::createSamplerSymbols(const TString &structName, const TString &structAPIName, - const int arrayOfStructsSize, + const unsigned int arrayOfStructsSize, TVector<TIntermSymbol *> *outputSymbols, TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const { @@ -257,9 +392,9 @@ void TStructure::createSamplerSymbols(const TString &structName, const TType *fieldType = field->type(); if (IsSampler(fieldType->getBasicType())) { - if (arrayOfStructsSize > 0) + if (arrayOfStructsSize > 0u) { - for (int arrayIndex = 0; arrayIndex < arrayOfStructsSize; ++arrayIndex) + for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex) { TStringStream name; name << structName << "_" << arrayIndex << "_" << field->name(); @@ -289,10 +424,11 @@ void TStructure::createSamplerSymbols(const TString &structName, } else if (fieldType->isStructureContainingSamplers()) { - int nestedArrayOfStructsSize = fieldType->isArray() ? fieldType->getArraySize() : 0; + unsigned int nestedArrayOfStructsSize = + fieldType->isArray() ? fieldType->getArraySize() : 0u; if (arrayOfStructsSize > 0) { - for (int arrayIndex = 0; arrayIndex < arrayOfStructsSize; ++arrayIndex) + for (unsigned int arrayIndex = 0u; arrayIndex < arrayOfStructsSize; ++arrayIndex) { TStringStream fieldName; fieldName << structName << "_" << arrayIndex << "_" << field->name(); diff --git a/chromium/third_party/angle/src/compiler/translator/Types.h b/chromium/third_party/angle/src/compiler/translator/Types.h index ee14aa7a3b2..ab1b6c3ff77 100644 --- a/chromium/third_party/angle/src/compiler/translator/Types.h +++ b/chromium/third_party/angle/src/compiler/translator/Types.h @@ -103,13 +103,7 @@ class TStructure : public TFieldListCollection { public: POOL_ALLOCATOR_NEW_DELETE(); - TStructure(const TString *name, TFieldList *fields) - : TFieldListCollection(name, fields), - mDeepestNesting(0), - mUniqueId(0), - mAtGlobalScope(false) - { - } + TStructure(const TString *name, TFieldList *fields); int deepestNesting() const { @@ -123,7 +117,7 @@ class TStructure : public TFieldListCollection void createSamplerSymbols(const TString &structName, const TString &structAPIName, - const int arrayOfStructsSize, + const unsigned int arrayOfStructsSize, TVector<TIntermSymbol *> *outputSymbols, TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const; @@ -326,6 +320,8 @@ class TType return invariant; } + void setInvariant(bool i) { invariant = i; } + TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; @@ -387,13 +383,10 @@ class TType } bool isUnsizedArray() const { - return array && arraySize == 0; + return array && arraySize == 0u; } - int getArraySize() const - { - return arraySize; - } - void setArraySize(int s) + unsigned int getArraySize() const { return arraySize; } + void setArraySize(unsigned int s) { if (!array || arraySize != s) { @@ -407,7 +400,7 @@ class TType if (array) { array = false; - arraySize = 0; + arraySize = 0u; invalidateMangledName(); } } @@ -508,6 +501,7 @@ class TType { return ::getBasicString(type); } + const char *getPrecisionString() const { return ::getPrecisionString(precision); @@ -516,6 +510,9 @@ class TType { return ::getQualifierString(qualifier); } + + const char *getBuiltInTypeNameString() const; + TString getCompleteString() const; // If this type is a struct, returns the deepest struct nesting of @@ -552,7 +549,7 @@ class TType void createSamplerSymbols(const TString &structName, const TString &structAPIName, - const int arrayOfStructsSize, + const unsigned int arrayOfStructsSize, TVector<TIntermSymbol *> *outputSymbols, TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const { @@ -580,7 +577,7 @@ class TType unsigned char primarySize; // size of vector or cols matrix unsigned char secondarySize; // rows of a matrix bool array; - int arraySize; + unsigned int arraySize; // 0 unless this is an interface block, or interface block member variable TInterfaceBlock *interfaceBlock; @@ -591,44 +588,25 @@ class TType mutable TString mangled; }; -// -// This is a workaround for a problem with the yacc stack, It can't have -// types that it thinks have non-trivial constructors. It should -// just be used while recognizing the grammar, not anything else. Pointers -// could be used, but also trying to avoid lots of memory management overhead. -// -// Not as bad as it looks, there is no actual assumption that the fields -// match up or are name the same or anything like that. -// -struct TPublicType +// TTypeSpecifierNonArray stores all of the necessary fields for type_specifier_nonarray from the +// grammar +struct TTypeSpecifierNonArray { TBasicType type; - TLayoutQualifier layoutQualifier; - TQualifier qualifier; - bool invariant; - TPrecision precision; unsigned char primarySize; // size of vector or cols of matrix unsigned char secondarySize; // rows of matrix - bool array; - int arraySize; TType *userDef; TSourceLoc line; // true if the type was defined by a struct specifier rather than a reference to a type name. bool isStructSpecifier; - void setBasic(TBasicType bt, TQualifier q, const TSourceLoc &ln) + void initialize(TBasicType bt, const TSourceLoc &ln) { type = bt; - layoutQualifier = TLayoutQualifier::create(); - qualifier = q; - invariant = false; - precision = EbpUndefined; primarySize = 1; secondarySize = 1; - array = false; - arraySize = 0; - userDef = 0; + userDef = nullptr; line = ln; isStructSpecifier = false; } @@ -638,78 +616,99 @@ struct TPublicType primarySize = size; } - void setMatrix(unsigned char c, unsigned char r) + void setMatrix(unsigned char columns, unsigned char rows) { - ASSERT(c > 1 && r > 1 && c <= 4 && r <= 4); - primarySize = c; - secondarySize = r; + ASSERT(columns > 1 && rows > 1 && columns <= 4 && rows <= 4); + primarySize = columns; + secondarySize = rows; } - bool isUnsizedArray() const - { - return array && arraySize == 0; - } - void setArraySize(int s) + bool isMatrix() const { return primarySize > 1 && secondarySize > 1; } + + bool isVector() const { return primarySize > 1 && secondarySize == 1; } +}; + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +struct TPublicType +{ + TTypeSpecifierNonArray typeSpecifierNonArray; + TLayoutQualifier layoutQualifier; + TQualifier qualifier; + bool invariant; + TPrecision precision; + bool array; + int arraySize; + + void initialize(const TTypeSpecifierNonArray &typeSpecifier, TQualifier q) { - array = true; - arraySize = s; + typeSpecifierNonArray = typeSpecifier; + layoutQualifier = TLayoutQualifier::create(); + qualifier = q; + invariant = false; + precision = EbpUndefined; + array = false; + arraySize = 0; } - void clearArrayness() + + TBasicType getBasicType() const { return typeSpecifierNonArray.type; } + void setBasicType(TBasicType basicType) { typeSpecifierNonArray.type = basicType; } + + unsigned char getPrimarySize() const { return typeSpecifierNonArray.primarySize; } + unsigned char getSecondarySize() const { return typeSpecifierNonArray.secondarySize; } + void initializeSizeForScalarTypes() { - array = false; - arraySize = 0; + typeSpecifierNonArray.primarySize = 1; + typeSpecifierNonArray.secondarySize = 1; } + const TType *getUserDef() const { return typeSpecifierNonArray.userDef; } + const TSourceLoc &getLine() const { return typeSpecifierNonArray.line; } + + bool isStructSpecifier() const { return typeSpecifierNonArray.isStructSpecifier; } + bool isStructureContainingArrays() const { - if (!userDef) + if (!typeSpecifierNonArray.userDef) { return false; } - return userDef->isStructureContainingArrays(); + return typeSpecifierNonArray.userDef->isStructureContainingArrays(); } bool isStructureContainingType(TBasicType t) const { - if (!userDef) + if (!typeSpecifierNonArray.userDef) { return false; } - return userDef->isStructureContainingType(t); - } - - bool isMatrix() const - { - return primarySize > 1 && secondarySize > 1; + return typeSpecifierNonArray.userDef->isStructureContainingType(t); } - bool isVector() const - { - return primarySize > 1 && secondarySize == 1; - } - - int getCols() const - { - ASSERT(isMatrix()); - return primarySize; - } - - int getRows() const + bool isUnsizedArray() const { return array && arraySize == 0; } + void setArraySize(int s) { - ASSERT(isMatrix()); - return secondarySize; + array = true; + arraySize = s; } - - int getNominalSize() const + void clearArrayness() { - return primarySize; + array = false; + arraySize = 0; } bool isAggregate() const { - return array || isMatrix() || isVector(); + return array || typeSpecifierNonArray.isMatrix() || typeSpecifierNonArray.isVector(); } }; diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp index e50bf202efd..e57681edad6 100644 --- a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp @@ -10,32 +10,30 @@ namespace { // "x || y" is equivalent to "x ? true : y". -TIntermSelection *UnfoldOR(TIntermTyped *x, TIntermTyped *y) +TIntermTernary *UnfoldOR(TIntermTyped *x, TIntermTyped *y) { - const TType boolType(EbtBool, EbpUndefined); TConstantUnion *u = new TConstantUnion; u->setBConst(true); TIntermConstantUnion *trueNode = new TIntermConstantUnion( u, TType(EbtBool, EbpUndefined, EvqConst, 1)); - return new TIntermSelection(x, trueNode, y, boolType); + return new TIntermTernary(x, trueNode, y); } // "x && y" is equivalent to "x ? y : false". -TIntermSelection *UnfoldAND(TIntermTyped *x, TIntermTyped *y) +TIntermTernary *UnfoldAND(TIntermTyped *x, TIntermTyped *y) { - const TType boolType(EbtBool, EbpUndefined); TConstantUnion *u = new TConstantUnion; u->setBConst(false); TIntermConstantUnion *falseNode = new TIntermConstantUnion( u, TType(EbtBool, EbpUndefined, EvqConst, 1)); - return new TIntermSelection(x, y, falseNode, boolType); + return new TIntermTernary(x, y, falseNode); } } // namespace anonymous bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) { - TIntermSelection *replacement = NULL; + TIntermTernary *replacement = nullptr; switch (node->getOp()) { @@ -50,8 +48,7 @@ bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) } if (replacement) { - mReplacements.push_back( - NodeUpdateEntry(getParentNode(), node, replacement, false)); + queueReplacement(node, replacement, OriginalNode::IS_DROPPED); } return true; } diff --git a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp index be23b524d75..f6e9a2ec3ed 100644 --- a/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp +++ b/chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp @@ -11,6 +11,7 @@ #include "compiler/translator/UnfoldShortCircuitToIf.h" #include "compiler/translator/IntermNode.h" +#include "compiler/translator/IntermNodePatternMatcher.h" namespace { @@ -22,41 +23,23 @@ class UnfoldShortCircuitTraverser : public TIntermTraverser UnfoldShortCircuitTraverser(); bool visitBinary(Visit visit, TIntermBinary *node) override; - bool visitAggregate(Visit visit, TIntermAggregate *node) override; - bool visitSelection(Visit visit, TIntermSelection *node) override; - bool visitLoop(Visit visit, TIntermLoop *node) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; void nextIteration(); bool foundShortCircuit() const { return mFoundShortCircuit; } protected: - // Check if the traversal is inside a loop condition or expression, in which case the unfolded - // expression needs to be copied inside the loop. Returns true if the copying is done, in which - // case no further unfolding should be done on the same traversal. - // The parameters are the node that will be unfolded to multiple statements and so can't remain - // inside a loop condition, and its parent. - bool copyLoopConditionOrExpression(TIntermNode *parent, TIntermTyped *node); - // Marked to true once an operation that needs to be unfolded has been found. // After that, no more unfolding is performed on that traversal. bool mFoundShortCircuit; - // Set to the loop node while a loop condition or expression is being traversed. - TIntermLoop *mParentLoop; - // Parent of the loop node while a loop condition or expression is being traversed. - TIntermNode *mLoopParent; - - bool mInLoopCondition; - bool mInLoopExpression; + IntermNodePatternMatcher mPatternToUnfoldMatcher; }; UnfoldShortCircuitTraverser::UnfoldShortCircuitTraverser() : TIntermTraverser(true, false, true), mFoundShortCircuit(false), - mParentLoop(nullptr), - mLoopParent(nullptr), - mInLoopCondition(false), - mInLoopExpression(false) + mPatternToUnfoldMatcher(IntermNodePatternMatcher::kUnfoldedShortCircuitExpression) { } @@ -64,282 +47,115 @@ bool UnfoldShortCircuitTraverser::visitBinary(Visit visit, TIntermBinary *node) { if (mFoundShortCircuit) return false; + + if (visit != PreVisit) + return true; + + if (!mPatternToUnfoldMatcher.match(node, getParentNode())) + return true; + // If our right node doesn't have side effects, we know we don't need to unfold this // expression: there will be no short-circuiting side effects to avoid // (note: unfolding doesn't depend on the left node -- it will always be evaluated) - if (!node->getRight()->hasSideEffects()) - { - return true; - } + ASSERT(node->getRight()->hasSideEffects()); + + mFoundShortCircuit = true; switch (node->getOp()) { case EOpLogicalOr: - mFoundShortCircuit = true; - if (!copyLoopConditionOrExpression(getParentNode(), node)) - { - // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; - // else s = y;", - // and then further simplifies down to "bool s = x; if(!s) s = y;". + { + // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; + // else s = y;", + // and then further simplifies down to "bool s = x; if(!s) s = y;". - TIntermSequence insertions; - TType boolType(EbtBool, EbpUndefined, EvqTemporary); + TIntermSequence insertions; + TType boolType(EbtBool, EbpUndefined, EvqTemporary); - ASSERT(node->getLeft()->getType() == boolType); - insertions.push_back(createTempInitDeclaration(node->getLeft())); + ASSERT(node->getLeft()->getType() == boolType); + insertions.push_back(createTempInitDeclaration(node->getLeft())); - TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); - ASSERT(node->getRight()->getType() == boolType); - assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); + TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); + ASSERT(node->getRight()->getType() == boolType); + assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); - TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, boolType); - notTempSymbol->setOperand(createTempSymbol(boolType)); - TIntermSelection *ifNode = new TIntermSelection(notTempSymbol, assignRightBlock, nullptr); - insertions.push_back(ifNode); + TIntermUnary *notTempSymbol = new TIntermUnary(EOpLogicalNot, createTempSymbol(boolType)); + TIntermIfElse *ifNode = new TIntermIfElse(notTempSymbol, assignRightBlock, nullptr); + insertions.push_back(ifNode); - insertStatementsInParentBlock(insertions); + insertStatementsInParentBlock(insertions); - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false); - mReplacements.push_back(replaceVariable); - } - return false; + queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED); + return false; + } case EOpLogicalAnd: - mFoundShortCircuit = true; - if (!copyLoopConditionOrExpression(getParentNode(), node)) - { - // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; - // else s = false;", - // and then further simplifies down to "bool s = x; if(s) s = y;". - TIntermSequence insertions; - TType boolType(EbtBool, EbpUndefined, EvqTemporary); - - ASSERT(node->getLeft()->getType() == boolType); - insertions.push_back(createTempInitDeclaration(node->getLeft())); - - TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); - ASSERT(node->getRight()->getType() == boolType); - assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); - - TIntermSelection *ifNode = new TIntermSelection(createTempSymbol(boolType), assignRightBlock, nullptr); - insertions.push_back(ifNode); - - insertStatementsInParentBlock(insertions); - - NodeUpdateEntry replaceVariable(getParentNode(), node, createTempSymbol(boolType), false); - mReplacements.push_back(replaceVariable); - } - return false; + { + // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; + // else s = false;", + // and then further simplifies down to "bool s = x; if(s) s = y;". + TIntermSequence insertions; + TType boolType(EbtBool, EbpUndefined, EvqTemporary); + + ASSERT(node->getLeft()->getType() == boolType); + insertions.push_back(createTempInitDeclaration(node->getLeft())); + + TIntermAggregate *assignRightBlock = new TIntermAggregate(EOpSequence); + ASSERT(node->getRight()->getType() == boolType); + assignRightBlock->getSequence()->push_back(createTempAssignment(node->getRight())); + + TIntermIfElse *ifNode = + new TIntermIfElse(createTempSymbol(boolType), assignRightBlock, nullptr); + insertions.push_back(ifNode); + + insertStatementsInParentBlock(insertions); + + queueReplacement(node, createTempSymbol(boolType), OriginalNode::IS_DROPPED); + return false; + } default: - return true; + UNREACHABLE(); + return true; } } -bool UnfoldShortCircuitTraverser::visitSelection(Visit visit, TIntermSelection *node) +bool UnfoldShortCircuitTraverser::visitTernary(Visit visit, TIntermTernary *node) { if (mFoundShortCircuit) return false; + if (visit != PreVisit) + return true; + + if (!mPatternToUnfoldMatcher.match(node)) + return true; + + mFoundShortCircuit = true; + // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" - if (visit == PreVisit && node->usesTernaryOperator()) - { - mFoundShortCircuit = true; - if (!copyLoopConditionOrExpression(getParentNode(), node)) - { - TIntermSequence insertions; - - TIntermSymbol *tempSymbol = createTempSymbol(node->getType()); - TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration); - tempDeclaration->getSequence()->push_back(tempSymbol); - insertions.push_back(tempDeclaration); - - TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence); - TIntermBinary *trueAssignment = - createTempAssignment(node->getTrueBlock()->getAsTyped()); - trueBlock->getSequence()->push_back(trueAssignment); - - TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence); - TIntermBinary *falseAssignment = - createTempAssignment(node->getFalseBlock()->getAsTyped()); - falseBlock->getSequence()->push_back(falseAssignment); - - TIntermSelection *ifNode = - new TIntermSelection(node->getCondition()->getAsTyped(), trueBlock, falseBlock); - insertions.push_back(ifNode); - - insertStatementsInParentBlock(insertions); - - TIntermSymbol *ternaryResult = createTempSymbol(node->getType()); - NodeUpdateEntry replaceVariable(getParentNode(), node, ternaryResult, false); - mReplacements.push_back(replaceVariable); - } - return false; - } + TIntermSequence insertions; - return true; -} + TIntermSymbol *tempSymbol = createTempSymbol(node->getType()); + TIntermAggregate *tempDeclaration = new TIntermAggregate(EOpDeclaration); + tempDeclaration->getSequence()->push_back(tempSymbol); + insertions.push_back(tempDeclaration); -bool UnfoldShortCircuitTraverser::visitAggregate(Visit visit, TIntermAggregate *node) -{ - if (visit == PreVisit && mFoundShortCircuit) - return false; // No need to traverse further + TIntermAggregate *trueBlock = new TIntermAggregate(EOpSequence); + TIntermBinary *trueAssignment = createTempAssignment(node->getTrueExpression()); + trueBlock->getSequence()->push_back(trueAssignment); - if (node->getOp() == EOpComma) - { - ASSERT(visit != PreVisit || !mFoundShortCircuit); - - if (visit == PostVisit && mFoundShortCircuit) - { - // We can be sure that we arrived here because there was a short-circuiting operator - // inside the sequence operator since we only start traversing the sequence operator in - // case a short-circuiting operator has not been found so far. - // We need to unfold the sequence (comma) operator, otherwise the evaluation order of - // statements would be messed up by unfolded operations inside. - // Don't do any other unfolding on this round of traversal. - mReplacements.clear(); - mMultiReplacements.clear(); - mInsertions.clear(); - - if (!copyLoopConditionOrExpression(getParentNode(), node)) - { - TIntermSequence insertions; - TIntermSequence *seq = node->getSequence(); - - TIntermSequence::size_type i = 0; - ASSERT(!seq->empty()); - while (i < seq->size() - 1) - { - TIntermTyped *child = (*seq)[i]->getAsTyped(); - insertions.push_back(child); - ++i; - } - - insertStatementsInParentBlock(insertions); - - NodeUpdateEntry replaceVariable(getParentNode(), node, (*seq)[i], false); - mReplacements.push_back(replaceVariable); - } - } - } - return true; -} + TIntermAggregate *falseBlock = new TIntermAggregate(EOpSequence); + TIntermBinary *falseAssignment = createTempAssignment(node->getFalseExpression()); + falseBlock->getSequence()->push_back(falseAssignment); -bool UnfoldShortCircuitTraverser::visitLoop(Visit visit, TIntermLoop *node) -{ - if (visit == PreVisit) - { - if (mFoundShortCircuit) - return false; // No need to traverse further - - mLoopParent = getParentNode(); - mParentLoop = node; - incrementDepth(node); - - if (node->getInit()) - { - node->getInit()->traverse(this); - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } - - if (node->getCondition()) - { - mInLoopCondition = true; - node->getCondition()->traverse(this); - mInLoopCondition = false; - - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } - - if (node->getExpression()) - { - mInLoopExpression = true; - node->getExpression()->traverse(this); - mInLoopExpression = false; - - if (mFoundShortCircuit) - { - decrementDepth(); - return false; - } - } - - if (node->getBody()) - node->getBody()->traverse(this); - - decrementDepth(); - } - return false; -} + TIntermIfElse *ifNode = + new TIntermIfElse(node->getCondition()->getAsTyped(), trueBlock, falseBlock); + insertions.push_back(ifNode); -bool UnfoldShortCircuitTraverser::copyLoopConditionOrExpression(TIntermNode *parent, - TIntermTyped *node) -{ - if (mInLoopCondition) - { - mReplacements.push_back( - NodeUpdateEntry(parent, node, createTempSymbol(node->getType()), false)); - TIntermAggregate *body = mParentLoop->getBody(); - TIntermSequence empty; - if (mParentLoop->getType() == ELoopDoWhile) - { - // Declare the temporary variable before the loop. - TIntermSequence insertionsBeforeLoop; - insertionsBeforeLoop.push_back(createTempDeclaration(node->getType())); - insertStatementsInParentBlock(insertionsBeforeLoop); - - // Move a part of do-while loop condition to inside the loop. - TIntermSequence insertionsInLoop; - insertionsInLoop.push_back(createTempAssignment(node)); - mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, - empty, insertionsInLoop)); - } - else - { - // The loop initializer expression and one copy of the part of the loop condition are - // executed before the loop. They need to be in a new scope. - TIntermAggregate *loopScope = new TIntermAggregate(EOpSequence); - - TIntermNode *initializer = mParentLoop->getInit(); - if (initializer != nullptr) - { - // Move the initializer to the newly created outer scope, so that condition can - // depend on it. - mReplacements.push_back(NodeUpdateEntry(mParentLoop, initializer, nullptr, false)); - loopScope->getSequence()->push_back(initializer); - } - - loopScope->getSequence()->push_back(createTempInitDeclaration(node)); - loopScope->getSequence()->push_back(mParentLoop); - mReplacements.push_back(NodeUpdateEntry(mLoopParent, mParentLoop, loopScope, true)); - - // The second copy of the part of the loop condition is executed inside the loop. - TIntermSequence insertionsInLoop; - insertionsInLoop.push_back(createTempAssignment(node->deepCopy())); - mInsertions.push_back(NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, - empty, insertionsInLoop)); - } - return true; - } + insertStatementsInParentBlock(insertions); + + TIntermSymbol *ternaryResult = createTempSymbol(node->getType()); + queueReplacement(node, ternaryResult, OriginalNode::IS_DROPPED); - if (mInLoopExpression) - { - TIntermTyped *movedExpression = mParentLoop->getExpression(); - mReplacements.push_back(NodeUpdateEntry(mParentLoop, movedExpression, nullptr, false)); - TIntermAggregate *body = mParentLoop->getBody(); - TIntermSequence empty; - TIntermSequence insertions; - insertions.push_back(movedExpression); - mInsertions.push_back( - NodeInsertMultipleEntry(body, body->getSequence()->size() - 1, empty, insertions)); - return true; - } return false; } diff --git a/chromium/third_party/angle/src/compiler/translator/UniformHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/UniformHLSL.cpp index 24d7760cb3a..3a85c60fc1b 100644 --- a/chromium/third_party/angle/src/compiler/translator/UniformHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/UniformHLSL.cpp @@ -128,7 +128,7 @@ unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type ASSERT(IsSampler(type.getBasicType())); unsigned int registerIndex = mSamplerRegister; mUniformRegisterMap[std::string(name.c_str())] = registerIndex; - unsigned int registerCount = type.isArray() ? type.getArraySize() : 1; + unsigned int registerCount = type.isArray() ? type.getArraySize() : 1u; mSamplerRegister += registerCount; if (outRegisterCount) { @@ -175,9 +175,9 @@ void UniformHLSL::outputHLSLSamplerUniformGroup( { out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type) << " = {"; - for (int i = 0; i < type.getArraySize(); ++i) + for (unsigned int i = 0u; i < type.getArraySize(); ++i) { - if (i > 0) + if (i > 0u) out << ", "; out << (samplerArrayIndex + i); } @@ -281,7 +281,7 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, { TVector<TIntermSymbol *> samplerSymbols; TMap<TIntermSymbol *, TString> symbolsToAPINames; - int arrayOfStructsSize = type.isArray() ? type.getArraySize() : 0; + unsigned int arrayOfStructsSize = type.isArray() ? type.getArraySize() : 0u; type.createSamplerSymbols("angle_" + name.getString(), name.getString(), arrayOfStructsSize, &samplerSymbols, &symbolsToAPINames); for (TIntermSymbol *sampler : samplerSymbols) diff --git a/chromium/third_party/angle/src/compiler/translator/UtilsHLSL.cpp b/chromium/third_party/angle/src/compiler/translator/UtilsHLSL.cpp index b3a065f19f8..221d5d9b56a 100644 --- a/chromium/third_party/angle/src/compiler/translator/UtilsHLSL.cpp +++ b/chromium/third_party/angle/src/compiler/translator/UtilsHLSL.cpp @@ -173,6 +173,8 @@ TString TextureTypeSuffix(const TBasicType type) return "Cube_int4_"; case EbtUSamplerCube: return "Cube_uint4_"; + case EbtSamplerExternalOES: + return "_External"; default: // All other types are identified by their group suffix return TextureGroupSuffix(type); diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp index 29ca68d9cab..9f5f8f577d2 100644 --- a/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp @@ -60,7 +60,7 @@ int ValidateOutputs::validateAndCountErrors(TInfoSinkBase &sink) const for (const auto &symbol : mOutputs) { const TType &type = symbol->getType(); - const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1); + const size_t elementCount = static_cast<size_t>(type.isArray() ? type.getArraySize() : 1u); const size_t location = static_cast<size_t>(type.getLayoutQualifier().location); ASSERT(type.getLayoutQualifier().location != -1); diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.cpp b/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.cpp index 9a4ed33632c..1ebdffd290d 100644 --- a/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.cpp +++ b/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.cpp @@ -59,11 +59,19 @@ bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) { if (!mFirstCaseFound) mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitTernary(Visit, TIntermTernary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; mLastStatementWasCase = false; return true; } -bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *) +bool ValidateSwitch::visitIfElse(Visit visit, TIntermIfElse *) { if (visit == PreVisit) ++mControlFlowDepth; diff --git a/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.h b/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.h index ddbefc56197..fb6a614791e 100644 --- a/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.h +++ b/chromium/third_party/angle/src/compiler/translator/ValidateSwitch.h @@ -23,7 +23,8 @@ class ValidateSwitch : public TIntermTraverser void visitConstantUnion(TIntermConstantUnion *) override; bool visitBinary(Visit, TIntermBinary *) override; bool visitUnary(Visit, TIntermUnary *) override; - bool visitSelection(Visit visit, TIntermSelection *) override; + bool visitTernary(Visit, TIntermTernary *) override; + bool visitIfElse(Visit visit, TIntermIfElse *) override; bool visitSwitch(Visit, TIntermSwitch *) override; bool visitCase(Visit, TIntermCase *node) override; bool visitAggregate(Visit, TIntermAggregate *) override; diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp index 611c1512d1f..7e1e5cd82a1 100644 --- a/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp +++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp @@ -31,58 +31,6 @@ void ExpandUserDefinedVariable(const ShaderVariable &variable, const std::string &name, const std::string &mappedName, bool markStaticUse, - std::vector<ShaderVariable> *expanded); - -void ExpandVariable(const ShaderVariable &variable, - const std::string &name, - const std::string &mappedName, - bool markStaticUse, - std::vector<ShaderVariable> *expanded) -{ - if (variable.isStruct()) - { - if (variable.isArray()) - { - for (unsigned int elementIndex = 0; elementIndex < variable.elementCount(); - elementIndex++) - { - std::string lname = name + ::ArrayString(elementIndex); - std::string lmappedName = mappedName + ::ArrayString(elementIndex); - ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded); - } - } - else - { - ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded); - } - } - else - { - ShaderVariable expandedVar = variable; - - expandedVar.name = name; - expandedVar.mappedName = mappedName; - - // Mark all expanded fields as used if the parent is used - if (markStaticUse) - { - expandedVar.staticUse = true; - } - - if (expandedVar.isArray()) - { - expandedVar.name += "[0]"; - expandedVar.mappedName += "[0]"; - } - - expanded->push_back(expandedVar); - } -} - -void ExpandUserDefinedVariable(const ShaderVariable &variable, - const std::string &name, - const std::string &mappedName, - bool markStaticUse, std::vector<ShaderVariable> *expanded) { ASSERT(variable.isStruct()); @@ -122,7 +70,8 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, std::vector<sh::Varying> *varyings, std::vector<sh::InterfaceBlock> *interfaceBlocks, ShHashFunction64 hashFunction, - const TSymbolTable &symbolTable) + const TSymbolTable &symbolTable, + const TExtensionBehavior &extensionBehavior) : TIntermTraverser(true, false, false), mAttribs(attribs), mOutputVariables(outputVariables), @@ -145,7 +94,8 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, mSecondaryFragColorEXTAdded(false), mSecondaryFragDataEXTAdded(false), mHashFunction(hashFunction), - mSymbolTable(symbolTable) + mSymbolTable(symbolTable), + mExtensionBehavior(extensionBehavior) { } @@ -401,10 +351,17 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; - info.arraySize = static_cast<const TVariable *>( - mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100)) - ->getConstPointer() - ->getIConst(); + if (::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers")) + { + info.arraySize = static_cast<const TVariable *>( + mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100)) + ->getConstPointer() + ->getIConst(); + } + else + { + info.arraySize = 1; + } info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; mOutputVariables->push_back(info); @@ -520,7 +477,7 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable, attribute.type = GLVariableType(type); attribute.precision = GLVariablePrecision(type); attribute.name = variable->getSymbol().c_str(); - attribute.arraySize = static_cast<unsigned int>(type.getArraySize()); + attribute.arraySize = type.getArraySize(); attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); attribute.location = variable->getType().getLayoutQualifier().location; @@ -540,7 +497,7 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable, attribute.type = GLVariableType(type); attribute.precision = GLVariablePrecision(type); attribute.name = variable->getSymbol().c_str(); - attribute.arraySize = static_cast<unsigned int>(type.getArraySize()); + attribute.arraySize = type.getArraySize(); attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); attribute.location = variable->getType().getLayoutQualifier().location; @@ -677,6 +634,52 @@ bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode) return true; } +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + const std::string &mappedName, + bool markStaticUse, + std::vector<ShaderVariable> *expanded) +{ + if (variable.isStruct()) + { + if (variable.isArray()) + { + for (unsigned int elementIndex = 0; elementIndex < variable.elementCount(); + elementIndex++) + { + std::string lname = name + ::ArrayString(elementIndex); + std::string lmappedName = mappedName + ::ArrayString(elementIndex); + ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded); + } + } + else + { + ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded); + } + } + else + { + ShaderVariable expandedVar = variable; + + expandedVar.name = name; + expandedVar.mappedName = mappedName; + + // Mark all expanded fields as used if the parent is used + if (markStaticUse) + { + expandedVar.staticUse = true; + } + + if (expandedVar.isArray()) + { + expandedVar.name += "[0]"; + expandedVar.mappedName += "[0]"; + } + + expanded->push_back(expandedVar); + } +} + void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded) { diff --git a/chromium/third_party/angle/src/compiler/translator/VariableInfo.h b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h index e6d01758ec6..f79035d3842 100644 --- a/chromium/third_party/angle/src/compiler/translator/VariableInfo.h +++ b/chromium/third_party/angle/src/compiler/translator/VariableInfo.h @@ -9,6 +9,7 @@ #include <GLSLANG/ShaderLang.h> +#include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/IntermNode.h" class TSymbolTable; @@ -26,7 +27,8 @@ class CollectVariables : public TIntermTraverser std::vector<Varying> *varyings, std::vector<InterfaceBlock> *interfaceBlocks, ShHashFunction64 hashFunction, - const TSymbolTable &symbolTable); + const TSymbolTable &symbolTable, + const TExtensionBehavior &extensionBehavior); void visitSymbol(TIntermSymbol *symbol) override; bool visitAggregate(Visit, TIntermAggregate *node) override; @@ -67,8 +69,15 @@ class CollectVariables : public TIntermTraverser ShHashFunction64 mHashFunction; const TSymbolTable &mSymbolTable; + const TExtensionBehavior &mExtensionBehavior; }; +void ExpandVariable(const ShaderVariable &variable, + const std::string &name, + const std::string &mappedName, + bool markStaticUse, + std::vector<ShaderVariable> *expanded); + // Expand struct uniforms to flattened lists of split variables void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded); diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp index e69052162a6..a981c8ae0b3 100644 --- a/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp +++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp @@ -148,15 +148,21 @@ bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* de return true; } -template <typename VarT> -bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors, - const std::vector<VarT> &in_variables) +bool VariablePacker::CheckVariablesWithinPackingLimits( + unsigned int maxVectors, + const std::vector<sh::ShaderVariable> &in_variables) { ASSERT(maxVectors > 0); maxRows_ = maxVectors; topNonFullRow_ = 0; bottomNonFullRow_ = maxRows_ - 1; - std::vector<VarT> variables(in_variables); + std::vector<sh::ShaderVariable> variables; + + for (const auto &variable : in_variables) + { + ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, + &variables); + } // Check whether each variable fits in the available vectors. for (size_t i = 0; i < variables.size(); i++) { @@ -261,9 +267,3 @@ bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int maxVectors, return true; } - -// Instantiate all possible variable packings -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::ShaderVariable> &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Attribute> &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Uniform> &); -template bool VariablePacker::CheckVariablesWithinPackingLimits(unsigned int, const std::vector<sh::Varying> &); diff --git a/chromium/third_party/angle/src/compiler/translator/VariablePacker.h b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h index 9c80eea6187..5f38a0a98de 100644 --- a/chromium/third_party/angle/src/compiler/translator/VariablePacker.h +++ b/chromium/third_party/angle/src/compiler/translator/VariablePacker.h @@ -12,30 +12,29 @@ class VariablePacker { public: - // Returns true if the passed in variables pack in maxVectors following - // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. - template <typename VarT> - bool CheckVariablesWithinPackingLimits(unsigned int maxVectors, - const std::vector<VarT> &in_variables); - - // Gets how many components in a row a data type takes. - static int GetNumComponentsPerRow(sh::GLenum type); - - // Gets how many rows a data type takes. - static int GetNumRows(sh::GLenum type); - - private: - static const int kNumColumns = 4; - static const unsigned kColumnMask = (1 << kNumColumns) - 1; - - unsigned makeColumnFlags(int column, int numComponentsPerRow); - void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); - bool searchColumn(int column, int numRows, int* destRow, int* destSize); - - int topNonFullRow_; - int bottomNonFullRow_; - int maxRows_; - std::vector<unsigned> rows_; + // Returns true if the passed in variables pack in maxVectors following + // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. + bool CheckVariablesWithinPackingLimits(unsigned int maxVectors, + const std::vector<sh::ShaderVariable> &in_variables); + + // Gets how many components in a row a data type takes. + static int GetNumComponentsPerRow(sh::GLenum type); + + // Gets how many rows a data type takes. + static int GetNumRows(sh::GLenum type); + + private: + static const int kNumColumns = 4; + static const unsigned kColumnMask = (1 << kNumColumns) - 1; + + unsigned makeColumnFlags(int column, int numComponentsPerRow); + void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow); + bool searchColumn(int column, int numRows, int *destRow, int *destSize); + + int topNonFullRow_; + int bottomNonFullRow_; + int maxRows_; + std::vector<unsigned> rows_; }; #endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp deleted file mode 100644 index 4dee0dbd2e9..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/depgraph/DependencyGraphBuilder.h" - -TDependencyGraph::TDependencyGraph(TIntermNode* intermNode) -{ - TDependencyGraphBuilder::build(intermNode, this); -} - -TDependencyGraph::~TDependencyGraph() -{ - for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter) - { - TGraphNode* node = *iter; - delete node; - } -} - -TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall, - int argumentNumber) -{ - TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber); - mAllNodes.push_back(argument); - return argument; -} - -TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall) -{ - TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall); - mAllNodes.push_back(functionCall); - if (functionCall->getIntermFunctionCall()->isUserDefined()) - mUserDefinedFunctionCalls.push_back(functionCall); - return functionCall; -} - -TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol) -{ - TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId()); - - TGraphSymbol* symbol = NULL; - - if (iter != mSymbolIdMap.end()) { - TSymbolIdPair pair = *iter; - symbol = pair.second; - } else { - symbol = new TGraphSymbol(intermSymbol); - mAllNodes.push_back(symbol); - - TSymbolIdPair pair(intermSymbol->getId(), symbol); - mSymbolIdMap.insert(pair); - - // We save all sampler symbols in a collection, so we can start graph traversals from them quickly. - if (IsSampler(intermSymbol->getBasicType())) - mSamplerSymbols.push_back(symbol); - } - - return symbol; -} - -TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection) -{ - TGraphSelection* selection = new TGraphSelection(intermSelection); - mAllNodes.push_back(selection); - return selection; -} - -TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop) -{ - TGraphLoop* loop = new TGraphLoop(intermLoop); - mAllNodes.push_back(loop); - return loop; -} - -TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp) -{ - TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp); - mAllNodes.push_back(logicalOp); - return logicalOp; -} - -const char* TGraphLogicalOp::getOpString() const -{ - const char* opString = NULL; - switch (getIntermLogicalOp()->getOp()) { - case EOpLogicalAnd: opString = "and"; break; - case EOpLogicalOr: opString = "or"; break; - default: opString = "unknown"; break; - } - return opString; -} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h deleted file mode 100644 index 2f7f7b9ab85..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ - -#include "compiler/translator/IntermNode.h" - -#include <set> -#include <stack> - -class TGraphNode; -class TGraphParentNode; -class TGraphArgument; -class TGraphFunctionCall; -class TGraphSymbol; -class TGraphSelection; -class TGraphLoop; -class TGraphLogicalOp; -class TDependencyGraphTraverser; -class TDependencyGraphOutput; - -typedef std::set<TGraphNode*> TGraphNodeSet; -typedef std::vector<TGraphNode*> TGraphNodeVector; -typedef std::vector<TGraphSymbol*> TGraphSymbolVector; -typedef std::vector<TGraphFunctionCall*> TFunctionCallVector; - -// -// Base class for all dependency graph nodes. -// -class TGraphNode { -public: - TGraphNode(TIntermNode* node) : intermNode(node) {} - virtual ~TGraphNode() {} - virtual void traverse(TDependencyGraphTraverser* graphTraverser); -protected: - TIntermNode* intermNode; -}; - -// -// Base class for dependency graph nodes that may have children. -// -class TGraphParentNode : public TGraphNode { -public: - TGraphParentNode(TIntermNode* node) : TGraphNode(node) {} - ~TGraphParentNode() override {} - void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; - -private: - TGraphNodeSet mDependentNodes; -}; - -// -// Handle function call arguments. -// -class TGraphArgument : public TGraphParentNode { -public: - TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber) - : TGraphParentNode(intermFunctionCall) - , mArgumentNumber(argumentNumber) {} - ~TGraphArgument() override {} - const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } - int getArgumentNumber() const { return mArgumentNumber; } - void traverse(TDependencyGraphTraverser *graphTraverser) override; - -private: - int mArgumentNumber; -}; - -// -// Handle function calls. -// -class TGraphFunctionCall : public TGraphParentNode { -public: - TGraphFunctionCall(TIntermAggregate* intermFunctionCall) - : TGraphParentNode(intermFunctionCall) {} - ~TGraphFunctionCall() override {} - const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle symbols. -// -class TGraphSymbol : public TGraphParentNode { -public: - TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {} - ~TGraphSymbol() override {} - const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle if statements and ternary operators. -// -class TGraphSelection : public TGraphNode { -public: - TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {} - ~TGraphSelection() override {} - const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle for, do-while, and while loops. -// -class TGraphLoop : public TGraphNode { -public: - TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {} - ~TGraphLoop() override {} - const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); } - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// Handle logical and, or. -// -class TGraphLogicalOp : public TGraphNode { -public: - TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {} - ~TGraphLogicalOp() override {} - const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); } - const char* getOpString() const; - void traverse(TDependencyGraphTraverser *graphTraverser) override; -}; - -// -// A dependency graph of symbols, function calls, conditions etc. -// -// This class provides an interface to the entry points of the dependency graph. -// -// Dependency graph nodes should be created by using one of the provided "create..." methods. -// This class (and nobody else) manages the memory of the created nodes. -// Nodes may not be removed after being added, so all created nodes will exist while the -// TDependencyGraph instance exists. -// -class TDependencyGraph { -public: - TDependencyGraph(TIntermNode* intermNode); - ~TDependencyGraph(); - const TGraphNodeVector &allNodes() const { return mAllNodes; } - const TGraphSymbolVector &samplerSymbols() const { return mSamplerSymbols; } - const TFunctionCallVector &userDefinedFunctionCalls() const - { - return mUserDefinedFunctionCalls; - } - - TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber); - TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall); - TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol); - TGraphSelection* createSelection(TIntermSelection* intermSelection); - TGraphLoop* createLoop(TIntermLoop* intermLoop); - TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp); -private: - typedef TMap<int, TGraphSymbol*> TSymbolIdMap; - typedef std::pair<int, TGraphSymbol*> TSymbolIdPair; - - TGraphNodeVector mAllNodes; - TGraphSymbolVector mSamplerSymbols; - TFunctionCallVector mUserDefinedFunctionCalls; - TSymbolIdMap mSymbolIdMap; -}; - -// -// For traversing the dependency graph. Users should derive from this, -// put their traversal specific data in it, and then pass it to a -// traverse method. -// -// When using this, just fill in the methods for nodes you want visited. -// -class TDependencyGraphTraverser : angle::NonCopyable { -public: - TDependencyGraphTraverser() : mDepth(0) {} - virtual ~TDependencyGraphTraverser() {} - - virtual void visitSymbol(TGraphSymbol* symbol) {}; - virtual void visitArgument(TGraphArgument* selection) {}; - virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {}; - virtual void visitSelection(TGraphSelection* selection) {}; - virtual void visitLoop(TGraphLoop* loop) {}; - virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {}; - - int getDepth() const { return mDepth; } - void incrementDepth() { ++mDepth; } - void decrementDepth() { --mDepth; } - - void clearVisited() { mVisited.clear(); } - void markVisited(TGraphNode* node) { mVisited.insert(node); } - bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); } -private: - int mDepth; - TGraphNodeSet mVisited; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp deleted file mode 100644 index 1aeb822d512..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp +++ /dev/null @@ -1,255 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/depgraph/DependencyGraphBuilder.h" - -void TDependencyGraphBuilder::build(TIntermNode *node, TDependencyGraph *graph) -{ - TDependencyGraphBuilder builder(graph); - builder.build(node); -} - -bool TDependencyGraphBuilder::visitAggregate( - Visit visit, TIntermAggregate *intermAggregate) -{ - switch (intermAggregate->getOp()) - { - case EOpFunction: - visitFunctionDefinition(intermAggregate); - break; - case EOpFunctionCall: - visitFunctionCall(intermAggregate); - break; - default: - visitAggregateChildren(intermAggregate); - break; - } - return false; -} - -void TDependencyGraphBuilder::visitFunctionDefinition( - TIntermAggregate *intermAggregate) -{ - // Currently, we do not support user defined functions. - if (intermAggregate->getName() != "main(") - return; - - visitAggregateChildren(intermAggregate); -} - -// Takes an expression like "f(x)" and creates a dependency graph like -// "x -> argument 0 -> function call". -void TDependencyGraphBuilder::visitFunctionCall( - TIntermAggregate *intermFunctionCall) -{ - TGraphFunctionCall *functionCall = - mGraph->createFunctionCall(intermFunctionCall); - - // Run through the function call arguments. - int argumentNumber = 0; - TIntermSequence *intermArguments = intermFunctionCall->getSequence(); - for (TIntermSequence::const_iterator iter = intermArguments->begin(); - iter != intermArguments->end(); - ++iter, ++argumentNumber) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - TIntermNode *intermArgument = *iter; - intermArgument->traverse(this); - - if (TParentNodeSet *argumentNodes = mNodeSets.getTopSet()) - { - TGraphArgument *argument = mGraph->createArgument( - intermFunctionCall, argumentNumber); - connectMultipleNodesToSingleNode(argumentNodes, argument); - argument->addDependentNode(functionCall); - } - } - - // Push the leftmost symbol of this function call into the current set of - // dependent symbols to represent the result of this function call. - // Thus, an expression like "y = f(x)" will yield a dependency graph like - // "x -> argument 0 -> function call -> y". - // This line essentially passes the function call node back up to an earlier - // visitAssignment call, which will create the connection "function call -> y". - mNodeSets.insertIntoTopSet(functionCall); -} - -void TDependencyGraphBuilder::visitAggregateChildren( - TIntermAggregate *intermAggregate) -{ - TIntermSequence *sequence = intermAggregate->getSequence(); - for (TIntermSequence::const_iterator iter = sequence->begin(); - iter != sequence->end(); ++iter) - { - TIntermNode *intermChild = *iter; - intermChild->traverse(this); - } -} - -void TDependencyGraphBuilder::visitSymbol(TIntermSymbol *intermSymbol) -{ - // Push this symbol into the set of dependent symbols for the current - // assignment or condition that we are traversing. - TGraphSymbol *symbol = mGraph->getOrCreateSymbol(intermSymbol); - mNodeSets.insertIntoTopSet(symbol); - - // If this symbol is the current leftmost symbol under an assignment, replace - // the previous leftmost symbol with this symbol. - if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) - { - mLeftmostSymbols.pop(); - mLeftmostSymbols.push(symbol); - } -} - -bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary *intermBinary) -{ - TOperator op = intermBinary->getOp(); - if (op == EOpInitialize || intermBinary->isAssignment()) - visitAssignment(intermBinary); - else if (op == EOpLogicalAnd || op == EOpLogicalOr) - visitLogicalOp(intermBinary); - else - visitBinaryChildren(intermBinary); - - return false; -} - -void TDependencyGraphBuilder::visitAssignment(TIntermBinary *intermAssignment) -{ - TIntermTyped *intermLeft = intermAssignment->getLeft(); - if (!intermLeft) - return; - - TGraphSymbol *leftmostSymbol = NULL; - - { - TNodeSetMaintainer nodeSetMaintainer(this); - - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree); - intermLeft->traverse(this); - leftmostSymbol = mLeftmostSymbols.top(); - - // After traversing the left subtree of this assignment, we should - // have found a real leftmost symbol, and the leftmost symbol should - // not be a placeholder. - ASSERT(leftmostSymbol != &mLeftSubtree); - ASSERT(leftmostSymbol != &mRightSubtree); - } - - if (TIntermTyped *intermRight = intermAssignment->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } - - if (TParentNodeSet *assignmentNodes = mNodeSets.getTopSet()) - connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol); - } - - // Push the leftmost symbol of this assignment into the current set of dependent - // symbols to represent the result of this assignment. - // An expression like "a = (b = c)" will yield a dependency graph like - // "c -> b -> a". - // This line essentially passes the leftmost symbol of the nested assignment - // ("b" in this example) back up to the earlier visitAssignment call for the - // outer assignment, which will create the connection "b -> a". - mNodeSets.insertIntoTopSet(leftmostSymbol); -} - -void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary *intermLogicalOp) -{ - if (TIntermTyped *intermLeft = intermLogicalOp->getLeft()) - { - TNodeSetPropagatingMaintainer nodeSetMaintainer(this); - - intermLeft->traverse(this); - if (TParentNodeSet *leftNodes = mNodeSets.getTopSet()) - { - TGraphLogicalOp *logicalOp = mGraph->createLogicalOp(intermLogicalOp); - connectMultipleNodesToSingleNode(leftNodes, logicalOp); - } - } - - if (TIntermTyped *intermRight = intermLogicalOp->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } -} - -void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary *intermBinary) -{ - if (TIntermTyped *intermLeft = intermBinary->getLeft()) - intermLeft->traverse(this); - - if (TIntermTyped *intermRight = intermBinary->getRight()) - { - TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree); - intermRight->traverse(this); - } -} - -bool TDependencyGraphBuilder::visitSelection( - Visit visit, TIntermSelection *intermSelection) -{ - if (TIntermNode *intermCondition = intermSelection->getCondition()) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - intermCondition->traverse(this); - if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) - { - TGraphSelection *selection = mGraph->createSelection(intermSelection); - connectMultipleNodesToSingleNode(conditionNodes, selection); - } - } - - if (TIntermNode *intermTrueBlock = intermSelection->getTrueBlock()) - intermTrueBlock->traverse(this); - - if (TIntermNode *intermFalseBlock = intermSelection->getFalseBlock()) - intermFalseBlock->traverse(this); - - return false; -} - -bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop *intermLoop) -{ - if (TIntermTyped *intermCondition = intermLoop->getCondition()) - { - TNodeSetMaintainer nodeSetMaintainer(this); - - intermCondition->traverse(this); - if (TParentNodeSet *conditionNodes = mNodeSets.getTopSet()) - { - TGraphLoop *loop = mGraph->createLoop(intermLoop); - connectMultipleNodesToSingleNode(conditionNodes, loop); - } - } - - if (TIntermNode* intermBody = intermLoop->getBody()) - intermBody->traverse(this); - - if (TIntermTyped *intermExpression = intermLoop->getExpression()) - intermExpression->traverse(this); - - return false; -} - - -void TDependencyGraphBuilder::connectMultipleNodesToSingleNode( - TParentNodeSet *nodes, TGraphNode *node) const -{ - for (TParentNodeSet::const_iterator iter = nodes->begin(); - iter != nodes->end(); ++iter) - { - TGraphParentNode *currentNode = *iter; - currentNode->addDependentNode(node); - } -} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h deleted file mode 100644 index c7b54f66b74..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ - -#include "compiler/translator/depgraph/DependencyGraph.h" - -// -// Creates a dependency graph of symbols, function calls, conditions etc. by -// traversing a intermediate tree. -// -class TDependencyGraphBuilder : public TIntermTraverser -{ - public: - static void build(TIntermNode *node, TDependencyGraph *graph); - - void visitSymbol(TIntermSymbol *) override; - bool visitBinary(Visit visit, TIntermBinary *) override; - bool visitSelection(Visit visit, TIntermSelection *) override; - bool visitAggregate(Visit visit, TIntermAggregate *) override; - bool visitLoop(Visit visit, TIntermLoop *) override; - - private: - typedef std::stack<TGraphSymbol *> TSymbolStack; - typedef std::set<TGraphParentNode *> TParentNodeSet; - - // - // For collecting the dependent nodes of assignments, conditions, etc. - // while traversing the intermediate tree. - // - // This data structure is stack of sets. Each set contains dependency graph - // parent nodes. - // - class TNodeSetStack - { - public: - TNodeSetStack() {}; - ~TNodeSetStack() { clear(); } - - // This should only be called after a pushSet. - // Returns NULL if the top set is empty. - TParentNodeSet *getTopSet() const - { - ASSERT(!mNodeSets.empty()); - TParentNodeSet *topSet = mNodeSets.top(); - return !topSet->empty() ? topSet : NULL; - } - - void pushSet() { mNodeSets.push(new TParentNodeSet()); } - void popSet() - { - ASSERT(!mNodeSets.empty()); - delete mNodeSets.top(); - mNodeSets.pop(); - } - - // Pops the top set and adds its contents to the new top set. - // This should only be called after a pushSet. - // If there is no set below the top set, the top set is just deleted. - void popSetIntoNext() - { - ASSERT(!mNodeSets.empty()); - TParentNodeSet *oldTopSet = mNodeSets.top(); - mNodeSets.pop(); - - if (!mNodeSets.empty()) - { - TParentNodeSet *newTopSet = mNodeSets.top(); - newTopSet->insert(oldTopSet->begin(), oldTopSet->end()); - } - - delete oldTopSet; - } - - // Does nothing if there is no top set. - // This can be called when there is no top set if we are visiting - // symbols that are not under an assignment or condition. - // We don't need to track those symbols. - void insertIntoTopSet(TGraphParentNode *node) - { - if (mNodeSets.empty()) - return; - - mNodeSets.top()->insert(node); - } - - void clear() - { - while (!mNodeSets.empty()) - popSet(); - } - - private: - typedef std::stack<TParentNodeSet *> TParentNodeSetStack; - - TParentNodeSetStack mNodeSets; - }; - - // - // An instance of this class pushes a new node set when instantiated. - // When the instance goes out of scope, it and pops the node set. - // - class TNodeSetMaintainer : angle::NonCopyable - { - public: - TNodeSetMaintainer(TDependencyGraphBuilder *factory) - : mSets(factory->mNodeSets) - { - mSets.pushSet(); - } - ~TNodeSetMaintainer() { mSets.popSet(); } - protected: - TNodeSetStack &mSets; - }; - - // - // An instance of this class pushes a new node set when instantiated. - // When the instance goes out of scope, it and pops the top node set and adds - // its contents to the new top node set. - // - class TNodeSetPropagatingMaintainer : angle::NonCopyable - { - public: - TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory) - : mSets(factory->mNodeSets) - { - mSets.pushSet(); - } - ~TNodeSetPropagatingMaintainer() { mSets.popSetIntoNext(); } - protected: - TNodeSetStack &mSets; - }; - - // - // An instance of this class keeps track of the leftmost symbol while we're - // exploring an assignment. - // It will push the placeholder symbol kLeftSubtree when instantiated under a - // left subtree, and kRightSubtree under a right subtree. - // When it goes out of scope, it will pop the leftmost symbol at the top of the - // scope. - // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with - // a real symbol. - // kRightSubtree will never be replaced by a real symbol because we are tracking - // the leftmost symbol. - // - class TLeftmostSymbolMaintainer : angle::NonCopyable - { - public: - TLeftmostSymbolMaintainer( - TDependencyGraphBuilder *factory, TGraphSymbol &subtree) - : mLeftmostSymbols(factory->mLeftmostSymbols) - { - mNeedsPlaceholderSymbol = - mLeftmostSymbols.empty() || mLeftmostSymbols.top() != &subtree; - if (mNeedsPlaceholderSymbol) - mLeftmostSymbols.push(&subtree); - } - - ~TLeftmostSymbolMaintainer() - { - if (mNeedsPlaceholderSymbol) - mLeftmostSymbols.pop(); - } - - protected: - TSymbolStack& mLeftmostSymbols; - bool mNeedsPlaceholderSymbol; - }; - - TDependencyGraphBuilder(TDependencyGraph *graph) - : TIntermTraverser(true, false, false), - mLeftSubtree(NULL), - mRightSubtree(NULL), - mGraph(graph) {} - void build(TIntermNode *intermNode) { intermNode->traverse(this); } - - void connectMultipleNodesToSingleNode( - TParentNodeSet *nodes, TGraphNode *node) const; - - void visitAssignment(TIntermBinary *); - void visitLogicalOp(TIntermBinary *); - void visitBinaryChildren(TIntermBinary *); - void visitFunctionDefinition(TIntermAggregate *); - void visitFunctionCall(TIntermAggregate *intermFunctionCall); - void visitAggregateChildren(TIntermAggregate *); - - TGraphSymbol mLeftSubtree; - TGraphSymbol mRightSubtree; - - TDependencyGraph *mGraph; - TNodeSetStack mNodeSets; - TSymbolStack mLeftmostSymbols; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp deleted file mode 100644 index 32a2f30141d..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/depgraph/DependencyGraphOutput.h" - -void TDependencyGraphOutput::outputIndentation() -{ - for (int i = 0; i < getDepth(); ++i) - mSink << " "; -} - -void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter) -{ - outputIndentation(); - mSink << "argument " << parameter->getArgumentNumber() << " of call to " - << parameter->getIntermFunctionCall()->getName() << "\n"; -} - -void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall) -{ - outputIndentation(); - mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n"; -} - -void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol) -{ - outputIndentation(); - mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: " - << symbol->getIntermSymbol()->getId() << ")\n"; -} - -void TDependencyGraphOutput::visitSelection(TGraphSelection* selection) -{ - outputIndentation(); - mSink << "selection\n"; -} - -void TDependencyGraphOutput::visitLoop(TGraphLoop* loop) -{ - outputIndentation(); - mSink << "loop condition\n"; -} - -void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp) -{ - outputIndentation(); - mSink << "logical " << logicalOp->getOpString() << "\n"; -} - -void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph) -{ - mSink << "\n"; - - for (auto symbol : graph.allNodes()) - { - mSink << "--- Dependency graph spanning tree ---\n"; - clearVisited(); - symbol->traverse(this); - mSink << "\n"; - } -} diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h deleted file mode 100644 index b201e0a6712..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ - -#include "compiler/translator/depgraph/DependencyGraph.h" -#include "compiler/translator/InfoSink.h" - -class TDependencyGraphOutput : public TDependencyGraphTraverser -{ - public: - TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {} - void visitSymbol(TGraphSymbol* symbol) override; - void visitArgument(TGraphArgument* parameter) override; - void visitFunctionCall(TGraphFunctionCall* functionCall) override; - void visitSelection(TGraphSelection* selection) override; - void visitLoop(TGraphLoop* loop) override; - void visitLogicalOp(TGraphLogicalOp* logicalOp) override; - - void outputAllSpanningTrees(TDependencyGraph& graph); - private: - void outputIndentation(); - - TInfoSinkBase& mSink; -}; - -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp b/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp deleted file mode 100644 index 197fde97e26..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/depgraph/DependencyGraph.h" - -// These methods do a breadth-first traversal through the graph and mark visited nodes. - -void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->markVisited(this); -} - -void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser) -{ - TGraphNode::traverse(graphTraverser); - - graphTraverser->incrementDepth(); - - // Visit the parent node's children. - for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin(); - iter != mDependentNodes.end(); - ++iter) - { - TGraphNode* node = *iter; - if (!graphTraverser->isVisited(node)) - node->traverse(graphTraverser); - } - - graphTraverser->decrementDepth(); -} - -void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitArgument(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitFunctionCall(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitSymbol(this); - TGraphParentNode::traverse(graphTraverser); -} - -void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitSelection(this); - TGraphNode::traverse(graphTraverser); -} - -void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitLoop(this); - TGraphNode::traverse(graphTraverser); -} - -void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser) -{ - graphTraverser->visitLogicalOp(this); - TGraphNode::traverse(graphTraverser); -} diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.l b/chromium/third_party/angle/src/compiler/translator/glslang.l index a4a296121dd..7fe28930275 100644 --- a/chromium/third_party/angle/src/compiler/translator/glslang.l +++ b/chromium/third_party/angle/src/compiler/translator/glslang.l @@ -392,7 +392,6 @@ O [0-7] <FIELDS>[ \t\v\f\r] {} <FIELDS>. { yyextra->error(*yylloc, "Illegal character at fieldname start", yytext, ""); - yyextra->recover(); return 0; } @@ -437,7 +436,6 @@ int reserved_word(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); - yyextra->recover(); return 0; } @@ -487,7 +485,6 @@ int uint_constant(TParseContext *context) if (context->getShaderVersion() < 300) { context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); - context->recover(); return 0; } @@ -504,7 +501,6 @@ int floatsuffix_check(TParseContext* context) if (context->getShaderVersion() < 300) { context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); - context->recover(); return 0; } @@ -518,7 +514,6 @@ int floatsuffix_check(TParseContext* context) void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { context->error(*lloc, reason, yyget_text(scanner)); - context->recover(); } int int_constant(TParseContext *context) { diff --git a/chromium/third_party/angle/src/compiler/translator/glslang.y b/chromium/third_party/angle/src/compiler/translator/glslang.y index f6903278b5b..ef2dcaa0a21 100644 --- a/chromium/third_party/angle/src/compiler/translator/glslang.y +++ b/chromium/third_party/angle/src/compiler/translator/glslang.y @@ -80,6 +80,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). TIntermCase* intermCase; }; union { + TTypeSpecifierNonArray typeSpecifierNonArray; TPublicType type; TPrecision precision; TLayoutQualifier layoutQualifier; @@ -88,6 +89,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). TParameter param; TField* field; TFieldList* fieldList; + TQualifierWrapperBase* qualifierWrapper; + TTypeQualifierBuilder* typeQualifierBuilder; }; } interm; } @@ -115,28 +118,42 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons #define VERTEX_ONLY(S, L) { \ if (context->getShaderType() != GL_VERTEX_SHADER) { \ context->error(L, " supported in vertex shaders only ", S); \ - context->recover(); \ } \ } #define FRAG_ONLY(S, L) { \ if (context->getShaderType() != GL_FRAGMENT_SHADER) { \ context->error(L, " supported in fragment shaders only ", S); \ - context->recover(); \ + } \ +} + +#define COMPUTE_ONLY(S, L) { \ + if (context->getShaderType() != GL_COMPUTE_SHADER) { \ + context->error(L, " supported in compute shaders only ", S); \ + } \ +} + +#define NON_COMPUTE_ONLY(S, L) { \ + if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \ + context->error(L, " supported in vertex and fragment shaders only ", S); \ } \ } #define ES2_ONLY(S, L) { \ if (context->getShaderVersion() != 100) { \ context->error(L, " supported in GLSL ES 1.00 only ", S); \ - context->recover(); \ } \ } -#define ES3_ONLY(TOKEN, LINE, REASON) { \ - if (context->getShaderVersion() != 300) { \ - context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ - context->recover(); \ +#define ES3_OR_NEWER(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() < 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 and above only ", TOKEN); \ + } \ +} + +#define ES3_1_ONLY(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() != 310) { \ + context->error(LINE, REASON " supported in GLSL ES 3.10 only ", TOKEN); \ } \ } %} @@ -191,13 +208,18 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons %type <interm> single_declaration init_declarator_list %type <interm> parameter_declaration parameter_declarator parameter_type_specifier -%type <interm.qualifier> parameter_qualifier parameter_type_qualifier -%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id +%type <interm.layoutQualifier> layout_qualifier_id_list layout_qualifier_id + +%type <interm.type> fully_specified_type type_specifier %type <interm.precision> precision_qualifier -%type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier -%type <interm.type> type_specifier_no_prec type_specifier_nonarray -%type <interm.type> struct_specifier +%type <interm.layoutQualifier> layout_qualifier +%type <interm.qualifier> storage_qualifier interpolation_qualifier +%type <interm.qualifierWrapper> single_type_qualifier invariant_qualifier +%type <interm.typeQualifierBuilder> type_qualifier + +%type <interm.typeSpecifierNonArray> type_specifier_nonarray struct_specifier +%type <interm.type> type_specifier_no_prec %type <interm.field> struct_declarator %type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list %type <interm.function> function_header function_declarator function_identifier @@ -276,8 +298,7 @@ postfix_expression integer_expression : expression { - if (context->integerErrorCheck($1, "[]")) - context->recover(); + context->checkIsScalarInteger($1, "[]"); $$ = $1; } ; @@ -299,7 +320,7 @@ function_call_or_method $$.nodePair.node2 = nullptr; } | postfix_expression DOT function_call_generic { - ES3_ONLY("", @3, "methods"); + ES3_OR_NEWER("", @3, "methods"); $$ = $3; $$.nodePair.node2 = $1; } @@ -330,7 +351,7 @@ function_call_header_with_parameters const TType *type = new TType($2->getType()); $1->addParameter(TConstParameter(type)); $$.function = $1; - $$.nodePair.node1 = context->intermediate.makeAggregate($2, @2); + $$.nodePair.node1 = TIntermediate::MakeAggregate($2, @2); } | function_call_header_with_parameters COMMA assignment_expression { const TType *type = new TType($3->getType()); @@ -351,20 +372,18 @@ function_call_header function_identifier : type_specifier_no_prec { if ($1.array) { - ES3_ONLY("[]", @1, "array constructor"); + ES3_OR_NEWER("[]", @1, "array constructor"); } $$ = context->addConstructorFunc($1); } | IDENTIFIER { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); + context->checkIsNotReserved(@1, *$1.string); const TType *type = TCache::getType(EbtVoid, EbpUndefined); TFunction *function = new TFunction($1.string, type); $$ = function; } | FIELD_SELECTION { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); + context->checkIsNotReserved(@1, *$1.string); const TType *type = TCache::getType(EbtVoid, EbpUndefined); TFunction *function = new TFunction($1.string, type); $$ = function; @@ -395,7 +414,7 @@ unary_operator | DASH { $$.op = EOpNegative; } | BANG { $$.op = EOpLogicalNot; } | TILDE { - ES3_ONLY("~", @$, "bit-wise operator"); + ES3_OR_NEWER("~", @$, "bit-wise operator"); $$.op = EOpBitwiseNot; } ; @@ -410,7 +429,7 @@ multiplicative_expression $$ = context->addBinaryMath(EOpDiv, $1, $3, @2); } | multiplicative_expression PERCENT unary_expression { - ES3_ONLY("%", @2, "integer modulus operator"); + ES3_OR_NEWER("%", @2, "integer modulus operator"); $$ = context->addBinaryMath(EOpIMod, $1, $3, @2); } ; @@ -428,11 +447,11 @@ additive_expression shift_expression : additive_expression { $$ = $1; } | shift_expression LEFT_OP additive_expression { - ES3_ONLY("<<", @2, "bit-wise operator"); + ES3_OR_NEWER("<<", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2); } | shift_expression RIGHT_OP additive_expression { - ES3_ONLY(">>", @2, "bit-wise operator"); + ES3_OR_NEWER(">>", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2); } ; @@ -466,7 +485,7 @@ equality_expression and_expression : equality_expression { $$ = $1; } | and_expression AMPERSAND equality_expression { - ES3_ONLY("&", @2, "bit-wise operator"); + ES3_OR_NEWER("&", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2); } ; @@ -474,7 +493,7 @@ and_expression exclusive_or_expression : and_expression { $$ = $1; } | exclusive_or_expression CARET and_expression { - ES3_ONLY("^", @2, "bit-wise operator"); + ES3_OR_NEWER("^", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2); } ; @@ -482,7 +501,7 @@ exclusive_or_expression inclusive_or_expression : exclusive_or_expression { $$ = $1; } | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { - ES3_ONLY("|", @2, "bit-wise operator"); + ES3_OR_NEWER("|", @2, "bit-wise operator"); $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2); } ; @@ -518,8 +537,7 @@ conditional_expression assignment_expression : conditional_expression { $$ = $1; } | unary_expression assignment_operator assignment_expression { - if (context->lValueErrorCheck(@2, "assign", $1)) - context->recover(); + context->checkCanBeLValue(@2, "assign", $1); $$ = context->addAssign($2.op, $1, $3, @2); } ; @@ -529,29 +547,29 @@ assignment_operator | MUL_ASSIGN { $$.op = EOpMulAssign; } | DIV_ASSIGN { $$.op = EOpDivAssign; } | MOD_ASSIGN { - ES3_ONLY("%=", @$, "integer modulus operator"); + ES3_OR_NEWER("%=", @$, "integer modulus operator"); $$.op = EOpIModAssign; } | ADD_ASSIGN { $$.op = EOpAddAssign; } | SUB_ASSIGN { $$.op = EOpSubAssign; } | LEFT_ASSIGN { - ES3_ONLY("<<=", @$, "bit-wise operator"); + ES3_OR_NEWER("<<=", @$, "bit-wise operator"); $$.op = EOpBitShiftLeftAssign; } | RIGHT_ASSIGN { - ES3_ONLY(">>=", @$, "bit-wise operator"); + ES3_OR_NEWER(">>=", @$, "bit-wise operator"); $$.op = EOpBitShiftRightAssign; } | AND_ASSIGN { - ES3_ONLY("&=", @$, "bit-wise operator"); + ES3_OR_NEWER("&=", @$, "bit-wise operator"); $$.op = EOpBitwiseAndAssign; } | XOR_ASSIGN { - ES3_ONLY("^=", @$, "bit-wise operator"); + ES3_OR_NEWER("^=", @$, "bit-wise operator"); $$.op = EOpBitwiseXorAssign; } | OR_ASSIGN { - ES3_ONLY("|=", @$, "bit-wise operator"); + ES3_OR_NEWER("|=", @$, "bit-wise operator"); $$.op = EOpBitwiseOrAssign; } ; @@ -567,16 +585,14 @@ expression constant_expression : conditional_expression { - if (context->constErrorCheck($1)) - context->recover(); + context->checkIsConst($1); $$ = $1; } ; enter_struct : IDENTIFIER LEFT_BRACE { - if (context->enterStructDeclaration(@1, *$1.string)) - context->recover(); + context->enterStructDeclaration(@1, *$1.string); $$ = $1; } ; @@ -594,35 +610,38 @@ declaration | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { if (($2 == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) { context->error(@1, "precision is not supported in fragment shader", "highp"); - context->recover(); } if (!context->symbolTable.setDefaultPrecision( $3, $2 )) { - context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type)); - context->recover(); + context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.getBasicType())); } $$ = 0; } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, NULL, @$, NULL, @$); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, NULL, @$, NULL, @$); } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, NULL, @$); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, NULL, @$); } | type_qualifier enter_struct struct_declaration_list RIGHT_BRACE IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET SEMICOLON { - ES3_ONLY(getQualifierString($1.qualifier), @1, "interface blocks"); - $$ = context->addInterfaceBlock($1, @2, *$2.string, $3, $5.string, @5, $7, @6); + ES3_OR_NEWER($2.string->c_str(), @1, "interface blocks"); + $$ = context->addInterfaceBlock(*$1, @2, *$2.string, $3, $5.string, @5, $7, @6); } | type_qualifier SEMICOLON { - context->parseGlobalLayoutQualifier($1); + context->parseGlobalLayoutQualifier(*$1); $$ = 0; } + | type_qualifier IDENTIFIER SEMICOLON // e.g. to qualify an existing variable as invariant + { + $$ = context->parseInvariantDeclaration(*$1, @2, $2.string, $2.symbol); + } ; function_prototype : function_declarator RIGHT_PAREN { $$.function = context->parseFunctionDeclarator(@2, $1); + context->exitFunctionDeclaration(); } ; @@ -655,7 +674,6 @@ function_header_with_parameters // This parameter > first is void // context->error(@2, "cannot be an argument type except for '(void)'", "void"); - context->recover(); delete $3.param.type; } else { // Add the parameter @@ -670,32 +688,28 @@ function_header $$ = context->parseFunctionHeader($1, $2.string, @2); context->symbolTable.push(); + context->enterFunctionDeclaration(); } ; parameter_declarator // Type + name : type_specifier identifier { - if ($1.type == EbtVoid) { + if ($1.getBasicType() == EbtVoid) { context->error(@2, "illegal use of type 'void'", $2.string->c_str()); - context->recover(); } - if (context->reservedErrorCheck(@2, *$2.string)) - context->recover(); + context->checkIsNotReserved(@2, *$2.string); TParameter param = {$2.string, new TType($1)}; $$.param = param; } | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { // Check that we can make an array out of this type - if (context->arrayTypeErrorCheck(@3, $1)) - context->recover(); + context->checkIsValidTypeForArray(@3, $1); - if (context->reservedErrorCheck(@2, *$2.string)) - context->recover(); + context->checkIsNotReserved(@2, *$2.string); + + unsigned int size = context->checkIsValidArraySize(@3, $4); - int size; - if (context->arraySizeErrorCheck(@3, $4, size)) - context->recover(); $1.setArraySize(size); TType* type = new TType($1); @@ -713,47 +727,21 @@ parameter_declaration // // Type + name // - : parameter_type_qualifier parameter_qualifier parameter_declarator { - $$ = $3; - if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) - context->recover(); - } - | parameter_qualifier parameter_declarator { + : type_qualifier parameter_declarator { $$ = $2; - if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) - context->recover(); - if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) - context->recover(); + context->checkIsParameterQualifierValid(@2, *$1, $2.param.type); } - // - // Only type - // - | parameter_type_qualifier parameter_qualifier parameter_type_specifier { - $$ = $3; - if (context->paramErrorCheck(@3, $1, $2, $$.param.type)) - context->recover(); + | parameter_declarator { + $$ = $1; + $$.param.type->setQualifier(EvqIn); } - | parameter_qualifier parameter_type_specifier { + | type_qualifier parameter_type_specifier { $$ = $2; - if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type)) - context->recover(); - if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type)) - context->recover(); - } - ; - -parameter_qualifier - : /* empty */ { - $$ = EvqIn; - } - | IN_QUAL { - $$ = EvqIn; - } - | OUT_QUAL { - $$ = EvqOut; + context->checkIsParameterQualifierValid(@2, *$1, $2.param.type); } - | INOUT_QUAL { - $$ = EvqInOut; + | parameter_type_specifier { + $$ = $1; + $$.param.type->setQualifier(EvqIn); } ; @@ -777,12 +765,12 @@ init_declarator_list $$.intermAggregate = context->parseArrayDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5); } | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("[]", @3, "implicitly sized array"); + ES3_OR_NEWER("[]", @3, "implicitly sized array"); $$ = $1; $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, nullptr, @6, $7); } | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("=", @7, "first-class arrays (array initializer)"); + ES3_OR_NEWER("=", @7, "first-class arrays (array initializer)"); $$ = $1; $$.intermAggregate = context->parseArrayInitDeclarator($$.type, $1.intermAggregate, @3, *$3.string, @4, $5, @7, $8); } @@ -806,12 +794,12 @@ single_declaration $$.intermAggregate = context->parseSingleArrayDeclaration($$.type, @2, *$2.string, @3, $4); } | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("[]", @3, "implicitly sized array"); + ES3_OR_NEWER("[]", @3, "implicitly sized array"); $$.type = $1; $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, nullptr, @5, $6); } | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { - ES3_ONLY("=", @6, "first-class arrays (array initializer)"); + ES3_OR_NEWER("=", @6, "first-class arrays (array initializer)"); $$.type = $1; $$.intermAggregate = context->parseSingleArrayInitDeclaration($$.type, @2, *$2.string, @3, $4, @6, $7); } @@ -819,10 +807,6 @@ single_declaration $$.type = $1; $$.intermAggregate = context->parseSingleInitDeclaration($$.type, @2, *$2.string, @3, $4); } - | INVARIANT IDENTIFIER { - // $$.type is not used in invariant declarations. - $$.intermAggregate = context->parseInvariantDeclaration(@1, @2, $2.string, $2.symbol); - } ; fully_specified_type @@ -830,131 +814,140 @@ fully_specified_type $$ = $1; if ($1.array) { - ES3_ONLY("[]", @1, "first-class-array"); + ES3_OR_NEWER("[]", @1, "first-class-array"); if (context->getShaderVersion() != 300) { $1.clearArrayness(); } } } - | type_qualifier type_specifier { - $$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2); + | type_qualifier type_specifier { + $$ = context->addFullySpecifiedType(*$1, $2); } ; interpolation_qualifier : SMOOTH { - $$.qualifier = EvqSmooth; + $$ = EvqSmooth; } | FLAT { - $$.qualifier = EvqFlat; - } - ; - -parameter_type_qualifier - : CONST_QUAL { - $$ = EvqConst; + $$ = EvqFlat; } ; type_qualifier - : ATTRIBUTE { - VERTEX_ONLY("attribute", @1); - ES2_ONLY("attribute", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute")) - context->recover(); - $$.setBasic(EbtVoid, EvqAttribute, @1); + : single_type_qualifier { + $$ = context->createTypeQualifierBuilder(@1); + $$->appendQualifier($1); } - | VARYING { - ES2_ONLY("varying", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - $$.setBasic(EbtVoid, EvqVaryingOut, @1); - else - $$.setBasic(EbtVoid, EvqVaryingIn, @1); + | type_qualifier single_type_qualifier { + $$ = $1; + $$->appendQualifier($2); } - | INVARIANT VARYING { - ES2_ONLY("varying", @1); - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - $$.setBasic(EbtVoid, EvqVaryingOut, @1); - else - $$.setBasic(EbtVoid, EvqVaryingIn, @1); - $$.invariant = true; + ; + +invariant_qualifier + : INVARIANT { + // empty } - | storage_qualifier { - if ($1.qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) + ; + +single_type_qualifier + : storage_qualifier { + if (!context->declaringFunction() && $1 != EvqConst && !context->symbolTable.atGlobalLevel()) { - context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1.qualifier)); - context->recover(); + context->error(@1, "Local variables can only use the const storage qualifier.", getQualifierString($1)); } - $$.setBasic(EbtVoid, $1.qualifier, @1); - } - | interpolation_qualifier storage_qualifier { - $$ = context->joinInterpolationQualifiers(@1, $1.qualifier, @2, $2.qualifier); - } - | interpolation_qualifier { - context->error(@1, "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString($1.qualifier)); - context->recover(); - - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtVoid, qual, @1); + $$ = new TStorageQualifierWrapper($1, @1); } | layout_qualifier { - $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.layoutQualifier = $1; + context->checkIsAtGlobalLevel(@1, "layout"); + $$ = new TLayoutQualifierWrapper($1, @1); } - | layout_qualifier storage_qualifier { - $$.setBasic(EbtVoid, $2.qualifier, @2); - $$.layoutQualifier = $1; + | precision_qualifier { + $$ = new TPrecisionQualifierWrapper($1, @1); } - | INVARIANT storage_qualifier { - context->es3InvariantErrorCheck($2.qualifier, @1); - $$.setBasic(EbtVoid, $2.qualifier, @2); - $$.invariant = true; + | interpolation_qualifier { + $$ = new TInterpolationQualifierWrapper($1, @1); } - | INVARIANT interpolation_qualifier storage_qualifier { - context->es3InvariantErrorCheck($3.qualifier, @1); - $$ = context->joinInterpolationQualifiers(@2, $2.qualifier, @3, $3.qualifier); - $$.invariant = true; + | invariant_qualifier { + context->checkIsAtGlobalLevel(@1, "invariant"); + $$ = new TInvariantQualifierWrapper(@1); } ; + storage_qualifier - : CONST_QUAL { - $$.qualifier = EvqConst; + : + ATTRIBUTE { + VERTEX_ONLY("attribute", @1); + ES2_ONLY("attribute", @1); + context->checkIsAtGlobalLevel(@1, "attribute"); + $$ = EvqAttribute; + } + | VARYING { + ES2_ONLY("varying", @1); + context->checkIsAtGlobalLevel(@1, "varying"); + if (context->getShaderType() == GL_VERTEX_SHADER) + $$ = EvqVaryingOut; + else + $$ = EvqVaryingIn; + } + | CONST_QUAL { + $$ = EvqConst; } | IN_QUAL { - ES3_ONLY("in", @1, "storage qualifier"); - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + if (context->declaringFunction()) + { + $$ = EvqIn; + } + else if (context->getShaderType() == GL_FRAGMENT_SHADER) + { + ES3_OR_NEWER("in", @1, "storage qualifier"); + $$ = EvqFragmentIn; + } + else if (context->getShaderType() == GL_VERTEX_SHADER) + { + ES3_OR_NEWER("in", @1, "storage qualifier"); + $$ = EvqVertexIn; + } + else + { + $$ = EvqComputeIn; + } } | OUT_QUAL { - ES3_ONLY("out", @1, "storage qualifier"); - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; - } - | CENTROID IN_QUAL { - ES3_ONLY("centroid in", @1, "storage qualifier"); - if (context->getShaderType() == GL_VERTEX_SHADER) + if (context->declaringFunction()) + { + $$ = EvqOut; + } + else { - context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); - context->recover(); + ES3_OR_NEWER("out", @1, "storage qualifier"); + NON_COMPUTE_ONLY("out", @1); + if (context->getShaderType() == GL_FRAGMENT_SHADER) + { + $$ = EvqFragmentOut; + } + else + { + $$ = EvqVertexOut; + } } - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; } - | CENTROID OUT_QUAL { - ES3_ONLY("centroid out", @1, "storage qualifier"); - if (context->getShaderType() == GL_FRAGMENT_SHADER) + | INOUT_QUAL { + if (!context->declaringFunction()) { - context->error(@1, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); - context->recover(); + context->error(@1, "invalid inout qualifier", "'inout' can be only used with function parameters"); } - $$.qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + $$ = EvqInOut; + } + | CENTROID { + ES3_OR_NEWER("centroid", @1, "storage qualifier"); + $$ = EvqCentroid; } | UNIFORM { - if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform")) - context->recover(); - $$.qualifier = EvqUniform; + context->checkIsAtGlobalLevel(@1, "uniform"); + $$ = EvqUniform; } ; @@ -963,19 +956,7 @@ type_specifier $$ = $1; if ($$.precision == EbpUndefined) { - $$.precision = context->symbolTable.getDefaultPrecision($1.type); - if (context->precisionErrorCheck(@1, $$.precision, $1.type)) { - context->recover(); - } - } - } - | precision_qualifier type_specifier_no_prec { - $$ = $2; - $$.precision = $1; - - if (!SupportsPrecision($2.type)) { - context->error(@1, "illegal type for precision qualifier", getBasicString($2.type)); - context->recover(); + $$.precision = context->symbolTable.getDefaultPrecision($1.getBasicType()); } } ; @@ -994,7 +975,7 @@ precision_qualifier layout_qualifier : LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN { - ES3_ONLY("layout", @1, "qualifier"); + ES3_OR_NEWER("layout", @1, "qualifier"); $$ = $3; } ; @@ -1004,7 +985,7 @@ layout_qualifier_id_list $$ = $1; } | layout_qualifier_id_list COMMA layout_qualifier_id { - $$ = context->joinLayoutQualifiers($1, $3); + $$ = context->joinLayoutQualifiers($1, $3, @3); } ; @@ -1013,31 +994,27 @@ layout_qualifier_id $$ = context->parseLayoutQualifier(*$1.string, @1); } | IDENTIFIER EQUAL INTCONSTANT { - $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3); } | IDENTIFIER EQUAL UINTCONSTANT { - $$ = context->parseLayoutQualifier(*$1.string, @1, *$3.string, $3.i, @3); + $$ = context->parseLayoutQualifier(*$1.string, @1, $3.i, @3); } ; type_specifier_no_prec : type_specifier_nonarray { - $$ = $1; + $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); } | type_specifier_nonarray LEFT_BRACKET RIGHT_BRACKET { - ES3_ONLY("[]", @2, "implicitly sized array"); - $$ = $1; + ES3_OR_NEWER("[]", @2, "implicitly sized array"); + $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); $$.setArraySize(0); } | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { - $$ = $1; - - if (context->arrayTypeErrorCheck(@2, $1)) - context->recover(); - else { - int size; - if (context->arraySizeErrorCheck(@2, $3, size)) - context->recover(); + $$.initialize($1, (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + if (context->checkIsValidTypeForArray(@2, $$)) + { + unsigned int size = context->checkIsValidArraySize(@2, $3); $$.setArraySize(size); } } @@ -1045,210 +1022,164 @@ type_specifier_no_prec type_specifier_nonarray : VOID_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtVoid, qual, @1); + $$.initialize(EbtVoid, @1); } | FLOAT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); } | INT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); } | UINT_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); } | BOOL_TYPE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); } | VEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(2); } | VEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(3); } | VEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setAggregate(4); } | BVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(2); } | BVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(3); } | BVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtBool, qual, @1); + $$.initialize(EbtBool, @1); $$.setAggregate(4); } | IVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(2); } | IVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(3); } | IVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtInt, qual, @1); + $$.initialize(EbtInt, @1); $$.setAggregate(4); } | UVEC2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(2); } | UVEC3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(3); } | UVEC4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUInt, qual, @1); + $$.initialize(EbtUInt, @1); $$.setAggregate(4); } | MATRIX2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 2); } | MATRIX3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 3); } | MATRIX4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 4); } | MATRIX2x3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 3); } | MATRIX3x2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 2); } | MATRIX2x4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(2, 4); } | MATRIX4x2 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 2); } | MATRIX3x4 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(3, 4); } | MATRIX4x3 { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtFloat, qual, @1); + $$.initialize(EbtFloat, @1); $$.setMatrix(4, 3); } | SAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2D, qual, @1); + $$.initialize(EbtSampler2D, @1); } | SAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler3D, qual, @1); + $$.initialize(EbtSampler3D, @1); } | SAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerCube, qual, @1); + $$.initialize(EbtSamplerCube, @1); } | SAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DArray, qual, @1); + $$.initialize(EbtSampler2DArray, @1); } | ISAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler2D, qual, @1); + $$.initialize(EbtISampler2D, @1); } | ISAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler3D, qual, @1); + $$.initialize(EbtISampler3D, @1); } | ISAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISamplerCube, qual, @1); + $$.initialize(EbtISamplerCube, @1); } | ISAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtISampler2DArray, qual, @1); + $$.initialize(EbtISampler2DArray, @1); } | USAMPLER2D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler2D, qual, @1); + $$.initialize(EbtUSampler2D, @1); } | USAMPLER3D { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler3D, qual, @1); + $$.initialize(EbtUSampler3D, @1); } | USAMPLERCUBE { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSamplerCube, qual, @1); + $$.initialize(EbtUSamplerCube, @1); } | USAMPLER2DARRAY { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtUSampler2DArray, qual, @1); + $$.initialize(EbtUSampler2DArray, @1); } | SAMPLER2DSHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DShadow, qual, @1); + $$.initialize(EbtSampler2DShadow, @1); } | SAMPLERCUBESHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerCubeShadow, qual, @1); + $$.initialize(EbtSamplerCubeShadow, @1); } | SAMPLER2DARRAYSHADOW { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DArrayShadow, qual, @1); + $$.initialize(EbtSampler2DArrayShadow, @1); } | SAMPLER_EXTERNAL_OES { if (!context->supportsExtension("GL_OES_EGL_image_external") && !context->supportsExtension("GL_NV_EGL_stream_consumer_external")) { context->error(@1, "unsupported type", "samplerExternalOES"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSamplerExternalOES, qual, @1); + $$.initialize(EbtSamplerExternalOES, @1); } | SAMPLER2DRECT { if (!context->supportsExtension("GL_ARB_texture_rectangle")) { context->error(@1, "unsupported type", "sampler2DRect"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtSampler2DRect, qual, @1); + $$.initialize(EbtSampler2DRect, @1); } | struct_specifier { $$ = $1; - $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; } | TYPE_NAME { // @@ -1256,17 +1187,16 @@ type_specifier_nonarray // type. // TType& structure = static_cast<TVariable*>($1.symbol)->getType(); - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - $$.setBasic(EbtStruct, qual, @1); + $$.initialize(EbtStruct, @1); $$.userDef = &structure; } ; struct_specifier - : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + : STRUCT identifier LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE { $$ = context->addStructure(@1, @2, $2.string, $5); } - | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE { + | STRUCT LEFT_BRACE { context->enterStructDeclaration(@2, *$2.string); } struct_declaration_list RIGHT_BRACE { $$ = context->addStructure(@1, @$, NewPoolTString(""), $4); } ; @@ -1282,7 +1212,6 @@ struct_declaration_list for (size_t j = 0; j < $$->size(); ++j) { if ((*$$)[j]->name() == field->name()) { context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str()); - context->recover(); } } $$->push_back(field); @@ -1296,9 +1225,7 @@ struct_declaration } | type_qualifier type_specifier struct_declarator_list SEMICOLON { // ES3 Only, but errors should be handled elsewhere - $2.qualifier = $1.qualifier; - $2.layoutQualifier = $1.layoutQualifier; - $$ = context->addStructDeclaratorList($2, $3); + $$ = context->addStructDeclaratorListWithQualifiers(*$1, &$2, $3); } ; @@ -1314,20 +1241,16 @@ struct_declarator_list struct_declarator : identifier { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); + context->checkIsNotReserved(@1, *$1.string); TType* type = new TType(EbtVoid, EbpUndefined); $$ = new TField(type, $1.string, @1); } | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET { - if (context->reservedErrorCheck(@1, *$1.string)) - context->recover(); + context->checkIsNotReserved(@1, *$1.string); TType* type = new TType(EbtVoid, EbpUndefined); - int size; - if (context->arraySizeErrorCheck(@3, $3, size)) - context->recover(); + unsigned int size = context->checkIsValidArraySize(@3, $3); type->setArraySize(size); $$ = new TField(type, $1.string, @1); @@ -1396,7 +1319,7 @@ compound_statement_no_new_scope statement_list : statement { - $$ = context->intermediate.makeAggregate($1, @$); + $$ = TIntermediate::MakeAggregate($1, @$); } | statement_list statement { $$ = context->intermediate.growAggregate($1, $2, @$); @@ -1410,9 +1333,8 @@ expression_statement selection_statement : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { - if (context->boolErrorCheck(@1, $3)) - context->recover(); - $$ = context->intermediate.addSelection($3, $5, @1); + context->checkIsScalarBool(@1, $3); + $$ = context->intermediate.addIfElse($3, $5, @1); } ; @@ -1447,18 +1369,15 @@ condition // In 1996 c++ draft, conditions can include single declarations : expression { $$ = $1; - if (context->boolErrorCheck($1->getLine(), $1)) - context->recover(); + context->checkIsScalarBool($1->getLine(), $1); } | fully_specified_type identifier EQUAL initializer { TIntermNode *intermNode; - if (context->boolErrorCheck(@2, $1)) - context->recover(); + context->checkIsScalarBool(@2, $1); if (!context->executeInitializer(@2, *$2.string, $1, $4, &intermNode)) $$ = $4; else { - context->recover(); $$ = 0; } } @@ -1471,8 +1390,7 @@ iteration_statement context->decrLoopNestingLevel(); } | DO { context->incrLoopNestingLevel(); } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { - if (context->boolErrorCheck(@8, $6)) - context->recover(); + context->checkIsScalarBool(@8, $6); $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); context->decrLoopNestingLevel(); diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp index ff6c2d6b1cc..8ad7b1464d4 100644 --- a/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp +++ b/chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp @@ -2075,7 +2075,6 @@ case 237: YY_RULE_SETUP { yyextra->error(*yylloc, "Illegal character at fieldname start", yytext, ""); - yyextra->recover(); return 0; } YY_BREAK @@ -3275,7 +3274,6 @@ int reserved_word(yyscan_t yyscanner) { struct yyguts_t* yyg = (struct yyguts_t*) yyscanner; yyextra->error(*yylloc, "Illegal use of reserved word", yytext, ""); - yyextra->recover(); return 0; } @@ -3325,7 +3323,6 @@ int uint_constant(TParseContext *context) if (context->getShaderVersion() < 300) { context->error(*yylloc, "Unsigned integers are unsupported prior to GLSL ES 3.00", yytext, ""); - context->recover(); return 0; } @@ -3342,7 +3339,6 @@ int floatsuffix_check(TParseContext* context) if (context->getShaderVersion() < 300) { context->error(*yylloc, "Floating-point suffix unsupported prior to GLSL ES 3.00", yytext); - context->recover(); return 0; } @@ -3356,7 +3352,6 @@ int floatsuffix_check(TParseContext* context) void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { context->error(*lloc, reason, yyget_text(scanner)); - context->recover(); } int int_constant(TParseContext *context) { diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp index a2784d3685b..2d3f170e7de 100644 --- a/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp +++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp @@ -295,6 +295,7 @@ union YYSTYPE TIntermCase* intermCase; }; union { + TTypeSpecifierNonArray typeSpecifierNonArray; TPublicType type; TPrecision precision; TLayoutQualifier layoutQualifier; @@ -303,6 +304,8 @@ union YYSTYPE TParameter param; TField* field; TFieldList* fieldList; + TQualifierWrapperBase* qualifierWrapper; + TTypeQualifierBuilder* typeQualifierBuilder; }; } interm; @@ -359,28 +362,42 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons #define VERTEX_ONLY(S, L) { \ if (context->getShaderType() != GL_VERTEX_SHADER) { \ context->error(L, " supported in vertex shaders only ", S); \ - context->recover(); \ } \ } #define FRAG_ONLY(S, L) { \ if (context->getShaderType() != GL_FRAGMENT_SHADER) { \ context->error(L, " supported in fragment shaders only ", S); \ - context->recover(); \ + } \ +} + +#define COMPUTE_ONLY(S, L) { \ + if (context->getShaderType() != GL_COMPUTE_SHADER) { \ + context->error(L, " supported in compute shaders only ", S); \ + } \ +} + +#define NON_COMPUTE_ONLY(S, L) { \ + if (context->getShaderType() != GL_VERTEX_SHADER && context->getShaderType() != GL_FRAGMENT_SHADER) { \ + context->error(L, " supported in vertex and fragment shaders only ", S); \ } \ } #define ES2_ONLY(S, L) { \ if (context->getShaderVersion() != 100) { \ context->error(L, " supported in GLSL ES 1.00 only ", S); \ - context->recover(); \ } \ } -#define ES3_ONLY(TOKEN, LINE, REASON) { \ - if (context->getShaderVersion() != 300) { \ - context->error(LINE, REASON " supported in GLSL ES 3.00 only ", TOKEN); \ - context->recover(); \ +#define ES3_OR_NEWER(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() < 300) { \ + context->error(LINE, REASON " supported in GLSL ES 3.00 and above only ", TOKEN); \ + } \ +} + +#define ES3_1_ONLY(TOKEN, LINE, REASON) { \ + if (context->getShaderVersion() != 310) { \ + context->error(LINE, REASON " supported in GLSL ES 3.10 only ", TOKEN); \ } \ } @@ -626,18 +643,18 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 116 +#define YYFINAL 109 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 2516 +#define YYLAST 2432 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 128 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 94 /* YYNRULES -- Number of rules. */ -#define YYNRULES 275 +#define YYNRULES 269 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 417 +#define YYNSTATES 405 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -696,34 +713,33 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 214, 214, 215, 218, 228, 231, 236, 241, 246, - 251, 257, 260, 263, 266, 269, 272, 278, 286, 297, - 301, 309, 312, 318, 322, 329, 335, 344, 352, 358, - 365, 375, 378, 381, 384, 394, 395, 396, 397, 405, - 406, 409, 412, 419, 420, 423, 429, 430, 434, 441, - 442, 445, 448, 451, 457, 458, 461, 467, 468, 475, - 476, 483, 484, 491, 492, 498, 499, 505, 506, 512, - 513, 519, 520, 528, 529, 530, 531, 535, 536, 537, - 541, 545, 549, 553, 560, 563, 569, 577, 585, 588, - 594, 605, 609, 613, 617, 624, 630, 633, 640, 648, - 669, 678, 688, 716, 721, 731, 736, 746, 749, 752, - 755, 761, 768, 771, 775, 779, 784, 789, 796, 800, - 804, 808, 813, 818, 822, 829, 839, 845, 848, 854, - 860, 867, 876, 886, 894, 897, 904, 908, 912, 917, - 925, 928, 932, 936, 945, 954, 962, 972, 984, 987, - 990, 996, 1003, 1006, 1012, 1015, 1018, 1024, 1027, 1032, - 1047, 1051, 1055, 1059, 1063, 1067, 1072, 1077, 1082, 1087, - 1092, 1097, 1102, 1107, 1112, 1117, 1122, 1127, 1132, 1137, - 1142, 1147, 1152, 1157, 1162, 1167, 1172, 1176, 1180, 1184, - 1188, 1192, 1196, 1200, 1204, 1208, 1212, 1216, 1220, 1224, - 1228, 1232, 1241, 1249, 1253, 1266, 1266, 1269, 1269, 1275, - 1278, 1294, 1297, 1306, 1310, 1316, 1323, 1338, 1342, 1346, - 1347, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1363, 1364, - 1364, 1364, 1374, 1375, 1379, 1379, 1380, 1380, 1385, 1388, - 1398, 1401, 1407, 1408, 1412, 1420, 1424, 1431, 1431, 1438, - 1441, 1448, 1453, 1468, 1468, 1473, 1473, 1480, 1480, 1488, - 1491, 1497, 1500, 1506, 1510, 1517, 1520, 1523, 1526, 1529, - 1538, 1542, 1549, 1552, 1558, 1558 + 0, 236, 236, 237, 240, 250, 253, 258, 263, 268, + 273, 279, 282, 285, 288, 291, 294, 300, 307, 318, + 322, 330, 333, 339, 343, 350, 356, 365, 373, 379, + 385, 394, 397, 400, 403, 413, 414, 415, 416, 424, + 425, 428, 431, 438, 439, 442, 448, 449, 453, 460, + 461, 464, 467, 470, 476, 477, 480, 486, 487, 494, + 495, 502, 503, 510, 511, 517, 518, 524, 525, 531, + 532, 538, 539, 546, 547, 548, 549, 553, 554, 555, + 559, 563, 567, 571, 578, 581, 587, 594, 601, 604, + 610, 619, 623, 627, 631, 635, 642, 649, 652, 659, + 667, 687, 697, 705, 730, 734, 738, 742, 749, 756, + 759, 763, 767, 772, 777, 784, 788, 792, 796, 801, + 806, 813, 823, 829, 832, 838, 842, 849, 855, 862, + 866, 869, 872, 881, 887, 895, 898, 918, 937, 944, + 948, 955, 965, 968, 971, 977, 984, 987, 993, 996, + 999, 1005, 1008, 1013, 1024, 1027, 1030, 1033, 1036, 1039, + 1043, 1047, 1051, 1055, 1059, 1063, 1067, 1071, 1075, 1079, + 1083, 1087, 1091, 1095, 1099, 1103, 1107, 1111, 1115, 1119, + 1123, 1126, 1129, 1132, 1135, 1138, 1141, 1144, 1147, 1150, + 1153, 1156, 1159, 1162, 1165, 1168, 1175, 1181, 1184, 1196, + 1196, 1199, 1199, 1205, 1208, 1223, 1226, 1233, 1237, 1243, + 1249, 1261, 1265, 1269, 1270, 1276, 1277, 1278, 1279, 1280, + 1281, 1282, 1286, 1287, 1287, 1287, 1297, 1298, 1302, 1302, + 1303, 1303, 1308, 1311, 1321, 1324, 1330, 1331, 1335, 1342, + 1346, 1353, 1353, 1360, 1363, 1370, 1374, 1387, 1387, 1392, + 1392, 1398, 1398, 1406, 1409, 1415, 1418, 1424, 1428, 1435, + 1438, 1441, 1444, 1447, 1456, 1460, 1467, 1470, 1476, 1476 }; #endif @@ -770,10 +786,10 @@ static const char *const yytname[] = "constant_expression", "enter_struct", "declaration", "function_prototype", "function_declarator", "function_header_with_parameters", "function_header", - "parameter_declarator", "parameter_declaration", "parameter_qualifier", + "parameter_declarator", "parameter_declaration", "parameter_type_specifier", "init_declarator_list", "single_declaration", - "fully_specified_type", "interpolation_qualifier", - "parameter_type_qualifier", "type_qualifier", "storage_qualifier", + "fully_specified_type", "interpolation_qualifier", "type_qualifier", + "invariant_qualifier", "single_type_qualifier", "storage_qualifier", "type_specifier", "precision_qualifier", "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id", "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier", @@ -812,12 +828,12 @@ static const yytype_uint16 yytoknum[] = }; # endif -#define YYPACT_NINF -361 +#define YYPACT_NINF -348 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-361))) + (!!((Yystate) == (-348))) -#define YYTABLE_NINF -235 +#define YYTABLE_NINF -229 #define yytable_value_is_error(Yytable_value) \ 0 @@ -826,48 +842,47 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 2154, 224, -361, -361, -361, 130, -361, -361, -361, -361, - -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, - -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, - -361, -361, -361, -361, -361, -361, -361, 145, -361, -361, - -46, -361, -361, -361, -361, -361, -361, -361, -361, -361, - -361, -361, -361, -361, -361, -361, -361, -361, -361, -82, - -361, -361, -68, -41, -45, 9, 7, -361, 117, 16, - 1173, -361, -361, 2439, 16, -361, -9, -361, 2079, -361, - -361, -361, -361, 16, -361, 2439, -361, -361, -361, -361, - -361, -31, 23, -361, 11, -361, 63, -361, -361, -361, - -361, -361, 2303, 168, 120, -361, 13, -66, -361, 31, - -361, 2229, -361, -361, -361, 1243, -361, -361, -361, 56, - 2229, -361, 17, -50, -361, 401, -361, -361, -361, -361, - 120, 2303, -18, -361, 1341, 1632, -361, 179, 2303, 120, - 1824, -361, 70, -361, -361, -361, -361, -361, 1632, 1632, - 1632, -361, -361, -361, -361, -361, -361, -361, 22, -361, - -361, -361, 101, -29, 1727, 114, -361, 1632, 96, -97, - 128, -54, 111, 118, 102, 115, 154, 153, -69, -361, - 140, -361, -361, 1909, 2229, 124, -361, 23, 134, 136, - -361, 147, 149, 143, 1439, 155, 1632, 148, 157, 160, - -361, -361, 184, -361, -361, 52, -361, -68, 158, -361, - -361, -361, -361, 517, -361, -361, -361, -361, -361, -361, - 166, -361, -361, 1534, 1632, 150, 159, -361, -361, 120, - 167, 61, -361, -62, -361, -361, -361, -5, -361, -361, - 1632, 2371, -361, -361, 1632, 185, -361, -361, -361, 1632, - 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, - 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, 1632, -361, - -361, 1994, -361, -361, -361, -361, -361, 181, -361, 1632, - -361, -361, 67, 1632, 180, -361, -361, -361, 633, -361, - -361, -361, -361, -361, -361, -361, -361, -361, -361, -361, - 1632, 1632, -361, -361, -361, 1632, 178, 186, -361, 1632, - 182, 68, 1632, 120, -361, -71, -361, -361, 187, 188, - -361, 192, -361, -361, -361, -361, -361, 96, 96, -97, - -97, 128, 128, 128, 128, -54, -54, 111, 118, 102, - 115, 154, 153, 113, -361, 242, 11, 865, 981, 4, - -361, 18, -361, 1078, 633, -361, -361, 194, 1632, 189, - -361, 1632, -361, 196, -361, 1632, -361, -361, 1632, 200, - -361, -361, -361, -361, 1078, 181, -361, 188, 120, 2303, - 201, 198, -361, -361, 1632, -361, -361, 202, -361, 1632, - -361, 191, 203, 293, -361, 204, 205, 749, -361, -361, - 197, 60, 1632, 749, 181, -361, 1632, -361, -361, -361, - -361, 199, 188, -361, -361, -361, -361 + 2144, -348, -348, -348, -348, 144, -348, -348, -348, -348, + -348, -348, -348, -348, -348, -348, -348, -348, -348, -348, + -348, -348, -348, -348, -348, -348, -348, -348, -348, -348, + -348, -348, -348, -348, -348, -348, -348, -348, -348, -348, + -348, -53, -348, -348, -348, -348, -348, -348, -348, -348, + -348, -348, -348, -348, -348, -348, -348, -348, -348, -348, + -83, -348, -348, -89, -70, -81, 2219, -26, -348, 60, + -348, 1163, -348, -348, -348, -348, -348, -348, -348, -66, + -348, 2069, -348, -348, 2355, -348, -348, -348, -41, -2, + -348, -30, -348, 2219, -348, -348, -348, 2219, 80, 80, + -348, -17, -75, -65, -348, 2219, -348, -348, 1233, -348, + -348, -15, 2219, -348, -10, -85, -348, 389, -348, -348, + -348, -348, 1, -49, -348, 1331, 1622, -348, -348, 2219, + 80, 1814, -348, 19, -348, -348, -348, -348, -348, 1622, + 1622, 1622, -348, -348, -348, -348, -348, -348, -348, -24, + -348, -348, -348, 37, -22, 1717, 67, -348, 1622, 34, + 14, 76, -46, 72, 51, 75, 78, 112, 113, -77, + -348, 98, -348, -348, 1899, 2219, 84, -348, -2, 94, + 97, -348, 108, 109, 100, 1429, 114, 1622, 104, 115, + 111, -348, -348, 190, -348, -348, -19, -348, -89, 117, + -348, -348, -348, -348, 505, -348, -348, -348, -348, -348, + -348, 1622, 1524, 1622, 116, 110, -348, -348, 80, 118, + 27, -348, -58, -348, -348, -348, -5, -348, -348, 1622, + 2287, -348, -348, 1622, 121, -348, -348, -348, 1622, 1622, + 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, + 1622, 1622, 1622, 1622, 1622, 1622, 1622, 1622, -348, -348, + 1984, -348, -348, -348, -348, -348, 119, -348, 1622, -348, + -348, 32, 1622, 122, -348, -348, -348, 621, -348, -348, + -348, -348, -348, -348, -348, -348, -348, -348, -348, 1622, + 1622, -348, -348, -348, 124, 120, 129, -348, 1622, 125, + 33, 1622, 80, -348, -87, -348, -348, 130, 128, -348, + 136, -348, -348, -348, -348, -348, 34, 34, 14, 14, + 76, 76, 76, 76, -46, -46, 72, 51, 75, 78, + 112, 113, 54, -348, 166, -30, 853, 969, -3, -348, + -1, -348, 1066, 621, -348, -348, -348, 1622, 132, -348, + 1622, -348, 135, -348, 1622, -348, -348, 1622, 139, -348, + -348, -348, -348, 1066, 119, -348, 128, 80, 2219, 141, + 140, -348, 1622, -348, -348, 145, -348, 1622, -348, 134, + 146, 236, -348, 147, 143, 737, -348, -348, 148, 17, + 1622, 737, 119, -348, 1622, -348, -348, -348, -348, 149, + 128, -348, -348, -348, -348 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -875,78 +890,77 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 0, 0, 148, 149, 150, 0, 130, 140, 164, 161, - 162, 163, 168, 169, 170, 171, 172, 173, 165, 166, - 167, 174, 175, 176, 177, 178, 179, 141, 142, 145, - 131, 180, 181, 182, 183, 184, 185, 0, 128, 127, - 0, 160, 186, 188, 201, 202, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 187, 198, 199, 200, 0, - 204, 273, 274, 0, 97, 107, 0, 112, 118, 135, - 0, 133, 125, 0, 136, 146, 157, 203, 0, 270, - 272, 132, 124, 0, 138, 0, 143, 144, 2, 3, - 207, 0, 0, 88, 0, 95, 107, 129, 108, 109, - 110, 98, 0, 107, 0, 89, 2, 119, 134, 0, - 94, 0, 126, 147, 137, 0, 1, 271, 139, 0, - 0, 205, 154, 0, 152, 0, 275, 99, 104, 106, - 111, 0, 113, 100, 0, 0, 87, 0, 0, 0, - 0, 209, 4, 8, 6, 7, 9, 30, 0, 0, - 0, 158, 37, 36, 38, 35, 5, 11, 31, 13, - 18, 19, 0, 0, 24, 0, 39, 0, 43, 46, - 49, 54, 57, 59, 61, 63, 65, 67, 69, 86, - 0, 28, 90, 0, 0, 0, 151, 0, 0, 0, - 255, 0, 0, 0, 0, 0, 0, 0, 0, 229, - 238, 242, 39, 71, 84, 0, 218, 0, 146, 221, - 240, 220, 219, 0, 222, 223, 224, 225, 226, 227, - 101, 103, 105, 0, 0, 0, 0, 217, 123, 0, - 215, 0, 213, 0, 210, 32, 33, 0, 15, 16, - 0, 0, 22, 21, 0, 160, 25, 27, 34, 0, + 0, 127, 142, 143, 144, 0, 133, 135, 158, 155, + 156, 157, 162, 163, 164, 165, 166, 167, 159, 160, + 161, 168, 169, 170, 171, 172, 173, 136, 137, 138, + 140, 134, 174, 175, 176, 177, 178, 179, 139, 124, + 123, 0, 154, 180, 182, 195, 196, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 181, 192, 193, 194, + 0, 198, 267, 268, 0, 98, 97, 0, 109, 115, + 131, 0, 132, 125, 128, 121, 130, 129, 141, 151, + 197, 0, 264, 266, 0, 2, 3, 201, 0, 0, + 88, 0, 96, 0, 105, 99, 107, 0, 108, 0, + 89, 2, 116, 0, 94, 0, 126, 122, 0, 1, + 265, 0, 0, 199, 148, 0, 146, 0, 269, 100, + 104, 106, 102, 110, 101, 0, 0, 87, 95, 0, + 0, 0, 203, 4, 8, 6, 7, 9, 30, 0, + 0, 0, 152, 37, 36, 38, 35, 5, 11, 31, + 13, 18, 19, 0, 0, 24, 0, 39, 0, 43, + 46, 49, 54, 57, 59, 61, 63, 65, 67, 69, + 86, 0, 28, 90, 0, 0, 0, 145, 0, 0, + 0, 249, 0, 0, 0, 0, 0, 0, 0, 0, + 223, 232, 236, 39, 71, 84, 0, 212, 0, 141, + 215, 234, 214, 213, 0, 216, 217, 218, 219, 220, + 221, 0, 0, 0, 0, 0, 211, 120, 0, 209, + 0, 207, 0, 204, 32, 33, 0, 15, 16, 0, + 0, 22, 21, 0, 154, 25, 27, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, - 208, 0, 155, 156, 153, 266, 265, 236, 257, 0, - 269, 267, 0, 0, 0, 250, 253, 228, 0, 74, - 75, 77, 76, 79, 80, 81, 82, 83, 78, 73, - 0, 0, 243, 239, 241, 0, 0, 0, 117, 0, - 120, 0, 0, 0, 211, 0, 91, 10, 0, 17, - 29, 14, 20, 26, 40, 41, 42, 45, 44, 47, - 48, 52, 53, 50, 51, 55, 56, 58, 60, 62, - 64, 66, 68, 0, 206, 0, 0, 0, 0, 0, - 268, 0, 249, 0, 230, 72, 85, 0, 0, 114, - 121, 0, 212, 0, 214, 0, 92, 12, 0, 0, - 235, 237, 260, 259, 262, 236, 247, 251, 0, 0, - 0, 0, 102, 115, 0, 122, 216, 0, 70, 0, - 261, 0, 0, 246, 244, 0, 0, 0, 231, 116, - 0, 0, 263, 0, 236, 248, 0, 233, 254, 232, - 93, 0, 264, 258, 245, 252, 256 + 0, 0, 0, 0, 0, 0, 0, 0, 153, 202, + 0, 149, 150, 147, 260, 259, 230, 251, 0, 263, + 261, 0, 0, 0, 244, 247, 222, 0, 74, 75, + 77, 76, 79, 80, 81, 82, 83, 78, 73, 0, + 0, 237, 233, 235, 0, 0, 0, 114, 0, 117, + 0, 0, 0, 205, 0, 91, 10, 0, 17, 29, + 14, 20, 26, 40, 41, 42, 45, 44, 47, 48, + 52, 53, 50, 51, 55, 56, 58, 60, 62, 64, + 66, 68, 0, 200, 0, 0, 0, 0, 0, 262, + 0, 243, 0, 224, 72, 85, 103, 0, 111, 118, + 0, 206, 0, 208, 0, 92, 12, 0, 0, 229, + 231, 254, 253, 256, 230, 241, 245, 0, 0, 0, + 0, 112, 0, 119, 210, 0, 70, 0, 255, 0, + 0, 240, 238, 0, 0, 0, 225, 113, 0, 0, + 257, 0, 230, 242, 0, 227, 248, 226, 93, 0, + 258, 252, 239, 246, 250 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -361, -39, -361, -361, -361, -361, -361, -361, 73, -361, - -361, -361, -361, -107, -361, -15, -20, -67, -19, 53, - 54, 55, 51, 57, 58, -361, -110, -132, -361, -146, - -125, -361, 6, 12, -361, -361, -361, 190, 228, 217, - 195, -361, -361, -336, 25, -361, -104, 27, -57, 322, - -361, -361, 141, 0, -361, -361, -361, -361, -109, -130, - 100, 19, -185, -17, -193, -310, -65, -361, -361, -70, - -360, -361, -361, -92, 46, -13, -361, -361, -361, -361, - -361, -38, -361, -361, -361, -361, -361, -361, -361, -361, - -361, 259, -361, -361 + -348, -40, -348, -348, -348, -348, -348, -348, 28, -348, + -348, -348, -348, -60, -348, -72, -71, -127, -52, 8, + 12, 16, 7, 10, 11, -348, -86, -122, -348, -133, + -78, -348, 9, 13, -348, -348, -348, 169, 177, 174, + -348, -348, -326, -348, -59, -348, -69, -348, -61, 268, + -348, -348, 96, 0, -348, -348, -348, -348, -100, -120, + 57, -23, -140, -57, -198, -322, -105, -348, -348, -110, + -347, -348, -348, -88, 5, -42, -348, -348, -348, -348, + -348, -67, -348, -348, -348, -348, -348, -348, -348, -348, + -348, 216, -348, -348 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 230, 156, 157, 158, 318, 159, 160, 161, 162, - 163, 164, 165, 202, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 203, 204, 300, 205, - 180, 111, 206, 207, 63, 64, 65, 128, 101, 102, - 129, 66, 67, 68, 69, 103, 70, 71, 72, 73, - 74, 123, 124, 181, 76, 77, 184, 120, 140, 141, - 231, 232, 228, 209, 210, 211, 212, 288, 381, 408, - 345, 346, 347, 409, 213, 214, 215, 394, 216, 395, - 217, 380, 218, 353, 277, 348, 374, 391, 392, 219, - 78, 79, 80, 94 + -1, 219, 147, 148, 149, 307, 150, 151, 152, 153, + 154, 155, 156, 193, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 194, 195, 289, 196, + 171, 105, 197, 198, 64, 65, 66, 94, 95, 96, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 115, 116, 172, 79, 80, 175, 112, 131, 132, + 220, 221, 217, 200, 201, 202, 203, 277, 370, 396, + 334, 335, 336, 397, 204, 205, 206, 382, 207, 383, + 208, 369, 209, 342, 266, 337, 363, 379, 380, 210, + 81, 82, 83, 91 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -954,387 +968,378 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 75, 91, 126, 227, 237, 179, 61, 138, 166, 226, - 234, 183, 62, 112, 315, 393, 138, 378, 97, 252, - 304, 253, 92, 267, 179, 7, 83, 166, 84, 107, - 88, 89, 246, 256, 257, 365, 138, 371, 378, 308, - 134, 235, 236, 366, 414, 130, 93, 135, 282, 98, - 99, 100, 316, 234, 139, 186, 27, 28, 268, 29, - 248, 187, 90, 139, 95, 132, 96, 37, 258, 259, - 75, 284, 97, 113, 130, 271, 243, 121, 75, 138, - 138, 229, 244, 139, 61, 119, 179, 407, 223, 166, - 62, 220, 227, 407, 319, 224, 108, 115, 307, 122, - 317, 114, 75, 98, 99, 100, 301, 238, 239, 375, - 118, 75, 323, 179, -96, 301, 166, 133, 104, 125, - 75, 105, 343, 376, 360, 208, 139, 139, 240, 301, - 185, 75, 241, 349, 2, 3, 4, 351, 75, 136, - 75, 234, 324, 325, 326, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 304, 83, 301, 84, 411, 302, 138, 355, 356, - 182, 301, 313, 383, -29, 314, 385, 227, 301, 313, - 357, 350, 362, 75, 75, 86, 87, 363, 7, 331, - 332, 333, 334, 106, 89, 179, 88, 89, 166, 399, - 260, 261, 179, 272, 273, 166, 242, 377, 98, 99, - 100, 254, 255, 208, 139, 249, 250, 251, 247, 27, - 28, 415, 29, 81, 301, 368, 227, 263, 377, 227, - 37, 38, 39, 7, 329, 330, 388, 327, 328, 264, - 387, 335, 336, 401, 262, 265, 266, 269, 275, 379, - 276, 278, 227, 279, 370, 179, 412, 280, 166, 283, - 285, 286, -28, 309, 27, 28, 310, 29, 81, 287, - 379, 75, 305, 312, 227, 37, 38, 39, 289, 290, - 291, 292, 293, 294, 295, 296, 297, 298, 208, -234, - -23, 358, 352, 359, 367, 361, -30, 299, 369, 301, - 82, 382, 384, 386, 389, 402, 397, 398, 403, 400, - 404, 410, 199, 416, 322, 337, 340, 338, 406, 339, - 131, 221, 112, 341, 127, 342, 222, 85, 274, 311, - 405, 372, 364, 413, 354, 373, 390, 117, 0, 396, - 0, 0, 0, 0, 0, 0, 0, 208, 208, 0, - 0, 0, 0, 208, 208, 0, 0, 0, 0, 0, + 78, 88, 106, 118, 216, 98, 293, 97, 226, 62, + 107, 223, 174, 63, 360, 256, 367, 381, 304, 354, + 177, 89, 170, 85, 86, 90, 178, 355, 106, 102, + 93, 125, 98, 235, 97, 92, 98, 367, 126, 170, + 108, 245, 246, 127, 130, 402, 129, 215, 157, 128, + 257, 130, 271, 129, 223, 87, 305, 212, 122, 123, + 106, 227, 228, 395, 213, 157, 78, 113, 218, 395, + 130, 78, 129, 297, 114, 260, 247, 248, 117, 224, + 225, 78, 229, 232, 111, 99, 230, 124, 100, 233, + 62, 216, 290, 78, 63, 291, 308, 78, 237, 173, + 306, 170, 364, 176, 365, 78, 290, 211, 290, 273, + 290, 312, 78, 130, 130, 129, 129, 199, 320, 321, + 322, 323, 399, -29, 332, 170, 170, 157, 290, 78, + 241, 78, 242, 294, 296, 338, 101, 86, 302, 340, + 223, 303, 231, 290, 302, 293, 339, 351, 2, 3, + 4, 157, 157, 238, 239, 240, 85, 86, 349, 243, + 244, 249, 250, 261, 262, 290, 357, 344, 345, 316, + 317, 236, 318, 319, 78, 78, 216, 251, 313, 314, + 315, 157, 157, 157, 157, 157, 157, 157, 157, 157, + 157, 157, 157, 157, 157, 157, 157, 324, 325, 130, + 252, 129, 253, 254, 199, 258, 255, 371, 264, 366, + 373, 265, 267, 268, 269, 170, 274, 299, 272, 275, + 276, -28, 358, 352, 301, 216, -23, -228, 216, 298, + 366, 346, 387, 347, 341, 376, 348, 356, 350, 290, + -30, 157, 374, 377, 389, 372, 385, 359, 390, 386, + 216, 391, 388, 392, 403, 190, 394, 400, 311, 326, + 78, 329, 398, 404, 327, 330, 120, 331, 170, 328, + 119, 121, 216, 84, 263, 300, 375, 199, 393, 353, + 361, 401, 343, 368, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 157, 362, 378, 110, 0, 106, + 0, 0, 0, 288, 368, 0, 0, 107, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, + 0, 0, 0, 0, 0, 0, 199, 199, 0, 0, + 0, 0, 199, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 208, 0, 0, 0, 0, 75, + 0, 0, 0, 199, 0, 0, 0, 0, 78, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, + 0, 199, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 179, 180, 181, 0, 182, 183, 184, + 185, 186, 187, 188, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 189, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 60, 133, 61, 134, 135, 136, + 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, - 0, 0, 0, 208, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 188, 189, 190, 0, 191, - 192, 193, 194, 195, 196, 197, 12, 13, 14, 15, + 0, 0, 0, 141, 0, 0, 0, 190, 191, 0, + 0, 0, 0, 192, 143, 144, 145, 146, 1, 2, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 179, + 180, 181, 0, 182, 183, 184, 185, 186, 187, 188, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 189, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 0, 57, 58, 59, + 60, 133, 61, 134, 135, 136, 137, 138, 0, 0, + 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, + 0, 0, 0, 190, 292, 0, 0, 0, 0, 192, + 143, 144, 145, 146, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 179, 180, 181, 0, 182, + 183, 184, 185, 186, 187, 188, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 0, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 198, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 0, 56, 57, 58, 59, 142, 60, 143, - 144, 145, 146, 147, 0, 0, 148, 149, 0, 0, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 189, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 0, 57, 58, 59, 60, 133, 61, 134, + 135, 136, 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 150, 0, 0, 0, 199, - 200, 0, 0, 0, 0, 201, 152, 153, 154, 155, + 0, 0, 0, 0, 0, 141, 0, 0, 0, 190, + 0, 0, 0, 0, 0, 192, 143, 144, 145, 146, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 188, 189, 190, 0, 191, 192, 193, 194, 195, - 196, 197, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 0, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 198, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 0, 56, - 57, 58, 59, 142, 60, 143, 144, 145, 146, 147, - 0, 0, 148, 149, 0, 0, 0, 0, 0, 0, + 11, 179, 180, 181, 0, 182, 183, 184, 185, 186, + 187, 188, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 189, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 0, 57, + 58, 59, 60, 133, 61, 134, 135, 136, 137, 138, + 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 150, 0, 0, 0, 199, 303, 0, 0, 0, - 0, 201, 152, 153, 154, 155, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 188, 189, 190, - 0, 191, 192, 193, 194, 195, 196, 197, 12, 13, + 0, 141, 0, 0, 0, 117, 0, 0, 0, 0, + 0, 192, 143, 144, 145, 146, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 179, 180, 181, + 0, 182, 183, 184, 185, 186, 187, 188, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 0, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 198, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 0, 56, 57, 58, 59, 142, - 60, 143, 144, 145, 146, 147, 0, 0, 148, 149, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 189, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 0, 57, 58, 59, 60, 133, + 61, 134, 135, 136, 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, - 0, 199, 0, 0, 0, 0, 0, 201, 152, 153, - 154, 155, 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 188, 189, 190, 0, 191, 192, 193, - 194, 195, 196, 197, 12, 13, 14, 15, 16, 17, + 0, 0, 0, 0, 0, 0, 0, 141, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 192, 143, 144, + 145, 146, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 0, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 198, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 59, 142, 60, 143, 144, 145, - 146, 147, 0, 0, 148, 149, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 150, 0, 0, 0, 125, 0, 0, - 0, 0, 0, 201, 152, 153, 154, 155, 1, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 188, - 189, 190, 0, 191, 192, 193, 194, 195, 196, 197, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 0, 29, 30, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 0, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 60, 133, 61, 134, 135, 136, + 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 141, 6, 7, 8, 9, 10, 11, + 0, 0, 0, 192, 143, 144, 145, 146, 0, 0, + 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 198, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 0, 56, 57, 58, - 59, 142, 60, 143, 144, 145, 146, 147, 0, 0, - 148, 149, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, - 152, 153, 154, 155, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 0, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 0, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 0, 56, 57, 58, 59, 142, 60, 143, - 144, 145, 146, 147, 0, 0, 148, 149, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 137, 2, 3, 4, 150, 6, 7, 8, 9, - 10, 11, 0, 0, 0, 201, 152, 153, 154, 155, - 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 0, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 0, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 0, - 56, 57, 58, 59, 142, 60, 143, 144, 145, 146, - 147, 0, 0, 148, 149, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, - 0, 0, 150, 8, 9, 10, 11, 0, 0, 0, - 0, 0, 0, 152, 153, 154, 155, 0, 12, 13, + 41, 42, 0, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 0, 57, 58, + 59, 60, 133, 61, 134, 135, 136, 137, 138, 0, + 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 141, 6, 7, 8, 9, 10, 11, 0, 0, 0, + 0, 143, 144, 145, 146, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 0, 0, 0, 0, 0, 31, 32, - 33, 34, 35, 36, 0, 0, 0, 40, 41, 0, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 0, 56, 57, 58, 0, 109, - 60, 0, 0, 8, 9, 10, 11, 0, 0, 0, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 0, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 0, 57, 58, 59, 60, 103, + 61, 0, 0, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 0, 0, 0, 0, 110, 31, 32, - 33, 34, 35, 36, 0, 0, 0, 40, 41, 0, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 0, 56, 57, 58, 0, 142, - 60, 143, 144, 145, 146, 147, 0, 0, 148, 149, + 24, 25, 26, 0, 0, 0, 0, 104, 32, 33, + 34, 35, 36, 37, 0, 0, 0, 41, 42, 0, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 0, 57, 58, 59, 0, 133, + 61, 134, 135, 136, 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, - 151, 8, 9, 10, 11, 0, 0, 0, 152, 153, - 154, 155, 0, 0, 0, 0, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 141, 0, 0, + 142, 8, 9, 10, 11, 0, 0, 0, 143, 144, + 145, 146, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 0, 0, 0, 0, 0, 31, 32, 33, 34, - 35, 36, 0, 0, 0, 40, 41, 0, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 0, 56, 57, 58, 0, 142, 60, 143, - 144, 145, 146, 147, 0, 0, 148, 149, 0, 0, + 26, 0, 0, 0, 0, 0, 32, 33, 34, 35, + 36, 37, 0, 0, 0, 41, 42, 0, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 0, 57, 58, 59, 0, 133, 61, 134, + 135, 136, 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 150, 0, 0, 225, 8, - 9, 10, 11, 0, 0, 0, 152, 153, 154, 155, + 0, 0, 0, 0, 0, 141, 0, 0, 214, 8, + 9, 10, 11, 0, 0, 0, 143, 144, 145, 146, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, - 0, 0, 0, 0, 31, 32, 33, 34, 35, 36, - 0, 0, 0, 40, 41, 0, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 0, 142, 60, 143, 144, 145, - 146, 147, 0, 0, 148, 149, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 33, 34, 35, 36, 37, + 0, 0, 0, 41, 42, 0, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 0, 133, 61, 134, 135, 136, + 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 150, 8, 9, 10, 11, 0, 0, - 0, 0, 0, 281, 152, 153, 154, 155, 0, 12, + 0, 0, 0, 141, 8, 9, 10, 11, 0, 0, + 0, 0, 0, 270, 143, 144, 145, 146, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 0, 0, 0, 0, 0, 31, - 32, 33, 34, 35, 36, 0, 0, 0, 40, 41, - 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 0, 56, 57, 58, 0, - 142, 60, 143, 144, 145, 146, 147, 0, 0, 148, - 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, - 0, 306, 8, 9, 10, 11, 0, 0, 0, 152, - 153, 154, 155, 0, 0, 0, 0, 12, 13, 14, + 23, 24, 25, 26, 0, 0, 0, 0, 0, 32, + 33, 34, 35, 36, 37, 0, 0, 0, 41, 42, + 0, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 0, 57, 58, 59, 0, + 133, 61, 134, 135, 136, 137, 138, 0, 0, 139, + 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 141, 0, + 0, 295, 8, 9, 10, 11, 0, 0, 0, 143, + 144, 145, 146, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 0, 0, 0, 0, 0, 31, 32, 33, - 34, 35, 36, 0, 0, 0, 40, 41, 0, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 0, 56, 57, 58, 0, 142, 60, - 143, 144, 145, 146, 147, 0, 0, 148, 149, 0, + 25, 26, 0, 0, 0, 0, 0, 32, 33, 34, + 35, 36, 37, 0, 0, 0, 41, 42, 0, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 0, 57, 58, 59, 0, 133, 61, + 134, 135, 136, 137, 138, 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 150, 8, 9, 10, - 11, 0, 0, 0, 0, 0, 0, 152, 153, 154, - 155, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 0, 0, 0, 0, 0, 0, 141, 8, 9, 10, + 11, 0, 0, 0, 0, 0, 0, 143, 144, 145, + 146, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, - 0, 0, 31, 32, 33, 34, 35, 36, 0, 0, - 0, 40, 245, 0, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 0, 56, - 57, 58, 0, 142, 60, 143, 144, 145, 146, 147, - 0, 0, 148, 149, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 137, 2, 3, - 4, 150, 6, 7, 8, 9, 10, 11, 0, 0, - 0, 0, 152, 153, 154, 155, 0, 0, 0, 12, + 0, 0, 32, 33, 34, 35, 36, 37, 0, 0, + 0, 41, 234, 0, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 0, 57, + 58, 59, 0, 133, 61, 134, 135, 136, 137, 138, + 0, 0, 139, 140, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, 141, 6, 7, 8, 9, 10, 11, 0, 0, + 0, 0, 143, 144, 145, 146, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 0, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 0, 56, 57, 58, 59, - 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 137, 2, 3, 4, 0, 6, 7, 8, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 0, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 0, 57, 58, 59, 60, + 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 233, 12, 13, 14, 15, 16, 17, + 0, 0, 0, 222, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 0, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 0, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 59, 0, 60, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 137, 2, 3, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 0, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 60, 0, 61, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 11, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 270, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 259, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 0, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 0, 56, 57, 58, 59, - 0, 60, 0, 0, 0, 0, 0, 0, 0, 116, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 0, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 0, 57, 58, 59, 60, + 0, 61, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 344, 12, 13, 14, 15, 16, 17, + 0, 0, 0, 333, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 0, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 0, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 59, 0, 60, 1, 2, 3, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 0, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 60, 0, 61, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 0, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 0, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 0, 56, 57, 58, 59, - 0, 60, 137, 2, 3, 4, 0, 6, 7, 8, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 0, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 0, 57, 58, 59, 60, + 0, 61, 1, 2, 3, 4, 0, 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 0, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 0, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 59, 0, 60, 2, 3, 4, - 0, 0, 0, 8, 9, 10, 11, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 0, 0, 0, 0, 0, 31, 32, - 33, 34, 35, 36, 0, 0, 0, 40, 41, 0, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 0, 56, 57, 58, 0, 0, - 60, 8, 9, 10, 11, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 0, 0, 0, 0, 0, 31, 32, 33, 34, - 35, 36, 0, 0, 0, 40, 41, 0, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 0, 56, 57, 58, 0, 320, 60, 8, - 9, 10, 11, 321, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, - 0, 0, 0, 0, 31, 32, 33, 34, 35, 36, - 0, 0, 0, 40, 41, 0, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 0, 56, 57, 58, 0, 0, 60 + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 0, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 0, 57, 58, 59, 60, 0, 61, 8, 9, 10, + 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 32, 33, 34, 35, 36, 37, 0, 0, + 0, 41, 42, 0, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 0, 57, + 58, 59, 0, 309, 61, 8, 9, 10, 11, 310, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 0, 0, 0, 41, + 42, 0, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 0, 57, 58, 59, + 0, 0, 61 }; static const yytype_int16 yycheck[] = { - 0, 40, 94, 135, 150, 115, 0, 111, 115, 134, - 140, 120, 0, 70, 76, 375, 120, 353, 9, 116, - 213, 118, 104, 92, 134, 9, 1, 134, 1, 68, - 76, 77, 164, 87, 88, 106, 140, 347, 374, 224, - 106, 148, 149, 114, 404, 102, 114, 113, 194, 40, - 41, 42, 114, 183, 111, 105, 40, 41, 127, 43, - 167, 111, 108, 120, 105, 104, 111, 51, 122, 123, - 70, 196, 9, 73, 131, 184, 105, 108, 78, 183, - 184, 138, 111, 140, 78, 85, 196, 397, 106, 196, - 78, 130, 224, 403, 240, 113, 69, 106, 223, 76, - 105, 74, 102, 40, 41, 42, 111, 85, 86, 105, - 83, 111, 244, 223, 105, 111, 223, 104, 111, 108, - 120, 114, 268, 105, 309, 125, 183, 184, 106, 111, - 113, 131, 110, 279, 4, 5, 6, 283, 138, 108, - 140, 271, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 354, 137, 111, 137, 105, 114, 271, 300, 301, - 114, 111, 111, 358, 104, 114, 361, 309, 111, 111, - 305, 114, 114, 183, 184, 40, 41, 312, 9, 256, - 257, 258, 259, 76, 77, 305, 76, 77, 305, 384, - 89, 90, 312, 79, 80, 312, 105, 353, 40, 41, - 42, 83, 84, 213, 271, 119, 120, 121, 104, 40, - 41, 406, 43, 44, 111, 112, 358, 125, 374, 361, - 51, 52, 53, 9, 254, 255, 368, 252, 253, 124, - 365, 260, 261, 389, 126, 91, 93, 107, 114, 353, - 114, 104, 384, 104, 346, 365, 402, 114, 365, 104, - 112, 104, 104, 113, 40, 41, 107, 43, 44, 109, - 374, 271, 106, 106, 406, 51, 52, 53, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 288, 108, - 105, 113, 112, 107, 107, 113, 104, 113, 56, 111, - 76, 107, 113, 107, 104, 114, 105, 109, 105, 107, - 17, 114, 108, 114, 241, 262, 265, 263, 113, 264, - 103, 131, 379, 266, 96, 267, 131, 5, 187, 229, - 395, 348, 313, 403, 288, 348, 374, 78, -1, 378, - -1, -1, -1, -1, -1, -1, -1, 347, 348, -1, - -1, -1, -1, 353, 354, -1, -1, -1, -1, -1, + 0, 41, 71, 91, 126, 66, 204, 66, 141, 0, + 71, 131, 112, 0, 336, 92, 342, 364, 76, 106, + 105, 104, 108, 76, 77, 114, 111, 114, 97, 69, + 111, 106, 93, 155, 93, 105, 97, 363, 113, 125, + 106, 87, 88, 108, 105, 392, 105, 125, 108, 114, + 127, 112, 185, 112, 174, 108, 114, 106, 98, 99, + 129, 85, 86, 385, 113, 125, 66, 108, 129, 391, + 131, 71, 131, 213, 76, 175, 122, 123, 108, 139, + 140, 81, 106, 105, 84, 111, 110, 104, 114, 111, + 81, 213, 111, 93, 81, 114, 229, 97, 158, 114, + 105, 187, 105, 113, 105, 105, 111, 106, 111, 187, + 111, 233, 112, 174, 175, 174, 175, 117, 245, 246, + 247, 248, 105, 104, 257, 211, 212, 187, 111, 129, + 116, 131, 118, 211, 212, 268, 76, 77, 111, 272, + 260, 114, 105, 111, 111, 343, 114, 114, 4, 5, + 6, 211, 212, 119, 120, 121, 76, 77, 298, 83, + 84, 89, 90, 79, 80, 111, 112, 289, 290, 241, + 242, 104, 243, 244, 174, 175, 298, 126, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 249, 250, 260, + 125, 260, 124, 91, 204, 107, 93, 347, 114, 342, + 350, 114, 104, 104, 114, 301, 112, 107, 104, 104, + 109, 104, 56, 301, 106, 347, 105, 108, 350, 113, + 363, 107, 372, 113, 112, 357, 107, 107, 113, 111, + 104, 301, 107, 104, 377, 113, 105, 335, 114, 109, + 372, 105, 107, 17, 394, 108, 113, 390, 230, 251, + 260, 254, 114, 114, 252, 255, 97, 256, 354, 253, + 93, 97, 394, 5, 178, 218, 354, 277, 383, 302, + 337, 391, 277, 342, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 354, 337, 363, 81, -1, 368, + -1, -1, -1, 113, 363, -1, -1, 368, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 367, -1, -1, + -1, -1, -1, -1, -1, -1, 336, 337, -1, -1, + -1, -1, 342, 343, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 374, -1, -1, -1, -1, 379, + -1, -1, -1, 363, -1, -1, -1, -1, 368, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 385, -1, -1, -1, -1, + -1, 391, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 397, -1, -1, - -1, -1, -1, 403, 3, 4, 5, 6, 7, 8, + -1, -1, -1, 104, -1, -1, -1, 108, 109, -1, + -1, -1, -1, 114, 115, 116, 117, 118, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, + 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, + -1, -1, -1, 108, 109, -1, -1, -1, -1, 114, + 115, 116, 117, 118, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, -1, 43, 44, 45, 46, 47, 48, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, 108, - 109, -1, -1, -1, -1, 114, 115, 116, 117, 118, + -1, -1, -1, -1, -1, 114, 115, 116, 117, 118, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, -1, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 104, -1, -1, -1, 108, 109, -1, -1, -1, + -1, 104, -1, -1, -1, 108, -1, -1, -1, -1, -1, 114, 115, 116, 117, 118, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, -1, 43, 44, 45, 46, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, - -1, 108, -1, -1, -1, -1, -1, 114, 115, 116, + -1, -1, -1, -1, -1, -1, -1, 114, 115, 116, 117, 118, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, -1, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, 85, 86, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 104, -1, -1, -1, 108, -1, -1, - -1, -1, -1, 114, 115, 116, 117, 118, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, -1, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, -1, -1, - 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, - 115, 116, 117, 118, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, -1, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, -1, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, -1, -1, 85, 86, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, 6, 104, 8, 9, 10, 11, - 12, 13, -1, -1, -1, 114, 115, 116, 117, 118, - -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, - -1, -1, 104, 10, 11, 12, 13, -1, -1, -1, - -1, -1, -1, 115, 116, 117, 118, -1, 25, 26, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, + 4, 5, 6, 104, 8, 9, 10, 11, 12, 13, + -1, -1, -1, 114, 115, 116, 117, 118, -1, -1, + -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, -1, + -1, 85, 86, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, + 104, 8, 9, 10, 11, 12, 13, -1, -1, -1, + -1, 115, 116, 117, 118, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, 45, 46, - 47, 48, 49, 50, -1, -1, -1, 54, 55, -1, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, -1, 72, 73, 74, -1, 76, + 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, -1, -1, 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, @@ -1396,7 +1401,7 @@ static const yytype_int16 yycheck[] = 6, 104, 8, 9, 10, 11, 12, 13, -1, -1, -1, -1, 115, 116, 117, 118, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, -1, 43, 44, 45, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, @@ -1405,7 +1410,7 @@ static const yytype_int16 yycheck[] = 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, -1, 43, 44, 45, 46, 47, 48, 49, 50, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, -1, 77, -1, -1, -1, @@ -1413,7 +1418,7 @@ static const yytype_int16 yycheck[] = 6, -1, 8, 9, 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, -1, 43, 44, 45, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, @@ -1422,14 +1427,14 @@ static const yytype_int16 yycheck[] = 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, -1, 43, 44, 45, 46, 47, 48, 49, 50, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, -1, 77, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, -1, 43, 44, 45, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, @@ -1437,31 +1442,24 @@ static const yytype_int16 yycheck[] = 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, -1, 43, 44, 45, 46, 47, 48, 49, 50, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - -1, 72, 73, 74, 75, -1, 77, 4, 5, 6, - -1, -1, -1, 10, 11, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, -1, -1, -1, -1, -1, 45, 46, - 47, 48, 49, 50, -1, -1, -1, 54, 55, -1, - 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, -1, 72, 73, 74, -1, -1, - 77, 10, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, -1, -1, -1, -1, -1, 45, 46, 47, 48, - 49, 50, -1, -1, -1, 54, 55, -1, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, -1, 72, 73, 74, -1, 76, 77, 10, - 11, 12, 13, 82, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, -1, - -1, -1, -1, -1, 45, 46, 47, 48, 49, 50, - -1, -1, -1, 54, 55, -1, 57, 58, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - -1, 72, 73, 74, -1, -1, 77 + -1, 72, 73, 74, 75, -1, 77, 10, 11, 12, + 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, -1, -1, -1, + -1, -1, 45, 46, 47, 48, 49, 50, -1, -1, + -1, 54, 55, -1, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, -1, 72, + 73, 74, -1, 76, 77, 10, 11, 12, 13, 82, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, -1, -1, -1, -1, -1, + 45, 46, 47, 48, 49, 50, -1, -1, -1, 54, + 55, -1, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, + -1, -1, 77 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1470,46 +1468,45 @@ static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 72, 73, 74, 75, - 77, 160, 161, 162, 163, 164, 169, 170, 171, 172, - 174, 175, 176, 177, 178, 181, 182, 183, 218, 219, - 220, 44, 76, 172, 175, 177, 40, 41, 76, 77, - 108, 129, 104, 114, 221, 105, 111, 9, 40, 41, - 42, 166, 167, 173, 111, 114, 76, 129, 175, 76, - 114, 159, 176, 181, 175, 106, 0, 219, 175, 181, - 185, 108, 76, 179, 180, 108, 201, 166, 165, 168, - 176, 167, 129, 104, 106, 113, 108, 3, 174, 176, - 186, 187, 76, 78, 79, 80, 81, 82, 85, 86, - 104, 107, 115, 116, 117, 118, 130, 131, 132, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 158, 181, 114, 186, 184, 113, 105, 111, 14, 15, - 16, 18, 19, 20, 21, 22, 23, 24, 56, 108, - 109, 114, 141, 154, 155, 157, 160, 161, 181, 191, - 192, 193, 194, 202, 203, 204, 206, 208, 210, 217, - 129, 165, 168, 106, 113, 107, 158, 155, 190, 176, - 129, 188, 189, 109, 187, 141, 141, 157, 85, 86, - 106, 110, 105, 105, 111, 55, 155, 104, 141, 119, - 120, 121, 116, 118, 83, 84, 87, 88, 122, 123, - 89, 90, 126, 125, 124, 91, 93, 92, 127, 107, - 109, 186, 79, 80, 180, 114, 114, 212, 104, 104, - 114, 114, 157, 104, 158, 112, 104, 109, 195, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 113, - 156, 111, 114, 109, 192, 106, 107, 158, 190, 113, - 107, 188, 106, 111, 114, 76, 114, 105, 133, 157, - 76, 82, 136, 155, 141, 141, 141, 143, 143, 144, - 144, 145, 145, 145, 145, 146, 146, 147, 148, 149, - 150, 151, 152, 157, 109, 198, 199, 200, 213, 157, - 114, 157, 112, 211, 202, 155, 155, 158, 113, 107, - 190, 113, 114, 158, 189, 106, 114, 107, 112, 56, - 201, 193, 191, 203, 214, 105, 105, 157, 171, 174, - 209, 196, 107, 190, 113, 190, 107, 158, 155, 104, - 209, 215, 216, 198, 205, 207, 129, 105, 109, 190, - 107, 157, 114, 105, 17, 194, 113, 193, 197, 201, - 114, 105, 157, 197, 198, 190, 114 + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 72, 73, 74, + 75, 77, 160, 161, 162, 163, 164, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 181, 182, + 183, 218, 219, 220, 177, 76, 77, 108, 129, 104, + 114, 221, 105, 111, 165, 166, 167, 172, 176, 111, + 114, 76, 129, 76, 114, 159, 174, 176, 106, 0, + 219, 181, 185, 108, 76, 179, 180, 108, 201, 166, + 165, 167, 129, 129, 104, 106, 113, 108, 114, 172, + 176, 186, 187, 76, 78, 79, 80, 81, 82, 85, + 86, 104, 107, 115, 116, 117, 118, 130, 131, 132, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 158, 181, 114, 186, 184, 113, 105, 111, 14, + 15, 16, 18, 19, 20, 21, 22, 23, 24, 56, + 108, 109, 114, 141, 154, 155, 157, 160, 161, 181, + 191, 192, 193, 194, 202, 203, 204, 206, 208, 210, + 217, 106, 106, 113, 107, 158, 155, 190, 176, 129, + 188, 189, 109, 187, 141, 141, 157, 85, 86, 106, + 110, 105, 105, 111, 55, 155, 104, 141, 119, 120, + 121, 116, 118, 83, 84, 87, 88, 122, 123, 89, + 90, 126, 125, 124, 91, 93, 92, 127, 107, 109, + 186, 79, 80, 180, 114, 114, 212, 104, 104, 114, + 114, 157, 104, 158, 112, 104, 109, 195, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 113, 156, + 111, 114, 109, 192, 158, 107, 158, 190, 113, 107, + 188, 106, 111, 114, 76, 114, 105, 133, 157, 76, + 82, 136, 155, 141, 141, 141, 143, 143, 144, 144, + 145, 145, 145, 145, 146, 146, 147, 148, 149, 150, + 151, 152, 157, 109, 198, 199, 200, 213, 157, 114, + 157, 112, 211, 202, 155, 155, 107, 113, 107, 190, + 113, 114, 158, 189, 106, 114, 107, 112, 56, 201, + 193, 191, 203, 214, 105, 105, 157, 170, 172, 209, + 196, 190, 113, 190, 107, 158, 155, 104, 209, 215, + 216, 198, 205, 207, 129, 105, 109, 190, 107, 157, + 114, 105, 17, 194, 113, 193, 197, 201, 114, 105, + 157, 197, 198, 190, 114 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -1524,25 +1521,24 @@ static const yytype_uint8 yyr1[] = 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 157, 157, 158, 159, 160, 160, - 160, 160, 160, 160, 160, 161, 162, 162, 163, 163, - 164, 165, 165, 166, 166, 166, 166, 167, 167, 167, - 167, 168, 169, 169, 169, 169, 169, 169, 170, 170, - 170, 170, 170, 170, 170, 171, 171, 172, 172, 173, - 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, - 175, 175, 175, 175, 175, 175, 176, 176, 177, 177, - 177, 178, 179, 179, 180, 180, 180, 181, 181, 181, + 160, 160, 160, 160, 160, 160, 161, 162, 162, 163, + 163, 164, 165, 165, 166, 166, 166, 166, 167, 168, + 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, + 169, 170, 170, 171, 171, 172, 172, 173, 174, 174, + 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, + 175, 176, 177, 177, 177, 178, 179, 179, 180, 180, + 180, 181, 181, 181, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, - 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, - 182, 182, 182, 182, 182, 184, 183, 185, 183, 186, - 186, 187, 187, 188, 188, 189, 189, 190, 191, 192, - 192, 193, 193, 193, 193, 193, 193, 193, 194, 195, - 196, 194, 197, 197, 199, 198, 200, 198, 201, 201, - 202, 202, 203, 203, 204, 205, 205, 207, 206, 208, - 208, 209, 209, 211, 210, 212, 210, 213, 210, 214, - 214, 215, 215, 216, 216, 217, 217, 217, 217, 217, - 218, 218, 219, 219, 221, 220 + 182, 182, 182, 182, 182, 182, 182, 182, 182, 184, + 183, 185, 183, 186, 186, 187, 187, 188, 188, 189, + 189, 190, 191, 192, 192, 193, 193, 193, 193, 193, + 193, 193, 194, 195, 196, 194, 197, 197, 199, 198, + 200, 198, 201, 201, 202, 202, 203, 203, 204, 205, + 205, 207, 206, 208, 208, 209, 209, 211, 210, 212, + 210, 213, 210, 214, 214, 215, 215, 216, 216, 217, + 217, 217, 217, 217, 218, 218, 219, 219, 221, 220 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -1557,25 +1553,24 @@ static const yytype_uint8 yyr2[] = 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 5, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 2, 2, - 4, 5, 6, 9, 2, 2, 1, 1, 2, 3, - 3, 2, 5, 3, 2, 3, 2, 0, 1, 1, - 1, 1, 1, 3, 6, 7, 8, 5, 1, 2, - 5, 6, 7, 4, 2, 1, 2, 1, 1, 1, - 1, 1, 2, 1, 2, 1, 1, 2, 2, 3, - 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, - 1, 4, 1, 3, 1, 3, 3, 1, 3, 4, + 4, 5, 6, 9, 2, 3, 2, 1, 1, 2, + 3, 3, 2, 5, 2, 1, 2, 1, 1, 1, + 3, 6, 7, 8, 5, 1, 2, 5, 6, 7, + 4, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 1, 3, 1, 3, + 3, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 6, 0, 5, 1, - 2, 3, 4, 1, 3, 1, 4, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, - 0, 5, 1, 1, 0, 2, 0, 2, 2, 3, - 1, 2, 1, 2, 5, 3, 1, 0, 6, 3, - 2, 1, 4, 0, 6, 0, 8, 0, 7, 1, - 1, 1, 0, 2, 3, 2, 2, 2, 3, 2, - 1, 2, 1, 1, 0, 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 6, 0, 5, 1, 2, 3, 4, 1, 3, 1, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 0, 0, 5, 1, 1, 0, 2, + 0, 2, 2, 3, 1, 2, 1, 2, 5, 3, + 1, 0, 6, 3, 2, 1, 4, 0, 6, 0, + 8, 0, 7, 1, 1, 1, 0, 2, 3, 2, + 2, 2, 3, 2, 1, 2, 1, 1, 0, 3 }; @@ -2473,8 +2468,7 @@ yyreduce: case 17: { - if (context->integerErrorCheck((yyvsp[0].interm.intermTypedNode), "[]")) - context->recover(); + context->checkIsScalarInteger((yyvsp[0].interm.intermTypedNode), "[]"); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } @@ -2505,7 +2499,7 @@ yyreduce: case 20: { - ES3_ONLY("", (yylsp[0]), "methods"); + ES3_OR_NEWER("", (yylsp[0]), "methods"); (yyval.interm) = (yyvsp[0].interm); (yyval.interm).nodePair.node2 = (yyvsp[-2].interm.intermTypedNode); } @@ -2552,7 +2546,7 @@ yyreduce: const TType *type = new TType((yyvsp[0].interm.intermTypedNode)->getType()); (yyvsp[-1].interm.function)->addParameter(TConstParameter(type)); (yyval.interm).function = (yyvsp[-1].interm.function); - (yyval.interm).nodePair.node1 = context->intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode), (yylsp[0])); + (yyval.interm).nodePair.node1 = TIntermediate::MakeAggregate((yyvsp[0].interm.intermTypedNode), (yylsp[0])); } break; @@ -2580,7 +2574,7 @@ yyreduce: { if ((yyvsp[0].interm.type).array) { - ES3_ONLY("[]", (yylsp[0]), "array constructor"); + ES3_OR_NEWER("[]", (yylsp[0]), "array constructor"); } (yyval.interm.function) = context->addConstructorFunc((yyvsp[0].interm.type)); } @@ -2590,8 +2584,7 @@ yyreduce: case 29: { - if (context->reservedErrorCheck((yylsp[0]), *(yyvsp[0].lex).string)) - context->recover(); + context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string); const TType *type = TCache::getType(EbtVoid, EbpUndefined); TFunction *function = new TFunction((yyvsp[0].lex).string, type); (yyval.interm.function) = function; @@ -2602,8 +2595,7 @@ yyreduce: case 30: { - if (context->reservedErrorCheck((yylsp[0]), *(yyvsp[0].lex).string)) - context->recover(); + context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string); const TType *type = TCache::getType(EbtVoid, EbpUndefined); TFunction *function = new TFunction((yyvsp[0].lex).string, type); (yyval.interm.function) = function; @@ -2667,7 +2659,7 @@ yyreduce: case 38: { - ES3_ONLY("~", (yyloc), "bit-wise operator"); + ES3_OR_NEWER("~", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitwiseNot; } @@ -2698,7 +2690,7 @@ yyreduce: case 42: { - ES3_ONLY("%", (yylsp[-1]), "integer modulus operator"); + ES3_OR_NEWER("%", (yylsp[-1]), "integer modulus operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpIMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2735,7 +2727,7 @@ yyreduce: case 47: { - ES3_ONLY("<<", (yylsp[-1]), "bit-wise operator"); + ES3_OR_NEWER("<<", (yylsp[-1]), "bit-wise operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftLeft, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2744,7 +2736,7 @@ yyreduce: case 48: { - ES3_ONLY(">>", (yylsp[-1]), "bit-wise operator"); + ES3_OR_NEWER(">>", (yylsp[-1]), "bit-wise operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitShiftRight, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2819,7 +2811,7 @@ yyreduce: case 58: { - ES3_ONLY("&", (yylsp[-1]), "bit-wise operator"); + ES3_OR_NEWER("&", (yylsp[-1]), "bit-wise operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2834,7 +2826,7 @@ yyreduce: case 60: { - ES3_ONLY("^", (yylsp[-1]), "bit-wise operator"); + ES3_OR_NEWER("^", (yylsp[-1]), "bit-wise operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2849,7 +2841,7 @@ yyreduce: case 62: { - ES3_ONLY("|", (yylsp[-1]), "bit-wise operator"); + ES3_OR_NEWER("|", (yylsp[-1]), "bit-wise operator"); (yyval.interm.intermTypedNode) = context->addBinaryMath(EOpBitwiseOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2920,8 +2912,7 @@ yyreduce: case 72: { - if (context->lValueErrorCheck((yylsp[-1]), "assign", (yyvsp[-2].interm.intermTypedNode))) - context->recover(); + context->checkCanBeLValue((yylsp[-1]), "assign", (yyvsp[-2].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = context->addAssign((yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yylsp[-1])); } @@ -2948,7 +2939,7 @@ yyreduce: case 76: { - ES3_ONLY("%=", (yyloc), "integer modulus operator"); + ES3_OR_NEWER("%=", (yyloc), "integer modulus operator"); (yyval.interm).op = EOpIModAssign; } @@ -2969,7 +2960,7 @@ yyreduce: case 79: { - ES3_ONLY("<<=", (yyloc), "bit-wise operator"); + ES3_OR_NEWER("<<=", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitShiftLeftAssign; } @@ -2978,7 +2969,7 @@ yyreduce: case 80: { - ES3_ONLY(">>=", (yyloc), "bit-wise operator"); + ES3_OR_NEWER(">>=", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitShiftRightAssign; } @@ -2987,7 +2978,7 @@ yyreduce: case 81: { - ES3_ONLY("&=", (yyloc), "bit-wise operator"); + ES3_OR_NEWER("&=", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitwiseAndAssign; } @@ -2996,7 +2987,7 @@ yyreduce: case 82: { - ES3_ONLY("^=", (yyloc), "bit-wise operator"); + ES3_OR_NEWER("^=", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitwiseXorAssign; } @@ -3005,7 +2996,7 @@ yyreduce: case 83: { - ES3_ONLY("|=", (yyloc), "bit-wise operator"); + ES3_OR_NEWER("|=", (yyloc), "bit-wise operator"); (yyval.interm).op = EOpBitwiseOrAssign; } @@ -3030,8 +3021,7 @@ yyreduce: case 86: { - if (context->constErrorCheck((yyvsp[0].interm.intermTypedNode))) - context->recover(); + context->checkIsConst((yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } @@ -3040,8 +3030,7 @@ yyreduce: case 87: { - if (context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string)) - context->recover(); + context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string); (yyval.lex) = (yyvsp[-1].lex); } @@ -3071,11 +3060,9 @@ yyreduce: { if (((yyvsp[-2].interm.precision) == EbpHigh) && (context->getShaderType() == GL_FRAGMENT_SHADER) && !context->getFragmentPrecisionHigh()) { context->error((yylsp[-3]), "precision is not supported in fragment shader", "highp"); - context->recover(); } if (!context->symbolTable.setDefaultPrecision( (yyvsp[-1].interm.type), (yyvsp[-2].interm.precision) )) { - context->error((yylsp[-3]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[-1].interm.type).type)); - context->recover(); + context->error((yylsp[-3]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[-1].interm.type).getBasicType())); } (yyval.interm.intermNode) = 0; } @@ -3085,8 +3072,8 @@ yyreduce: case 91: { - ES3_ONLY(getQualifierString((yyvsp[-4].interm.type).qualifier), (yylsp[-4]), "interface blocks"); - (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[-4].interm.type), (yylsp[-3]), *(yyvsp[-3].lex).string, (yyvsp[-2].interm.fieldList), NULL, (yyloc), NULL, (yyloc)); + ES3_OR_NEWER((yyvsp[-3].lex).string->c_str(), (yylsp[-4]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-4].interm.typeQualifierBuilder), (yylsp[-3]), *(yyvsp[-3].lex).string, (yyvsp[-2].interm.fieldList), NULL, (yyloc), NULL, (yyloc)); } break; @@ -3094,8 +3081,8 @@ yyreduce: case 92: { - ES3_ONLY(getQualifierString((yyvsp[-5].interm.type).qualifier), (yylsp[-5]), "interface blocks"); - (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[-5].interm.type), (yylsp[-4]), *(yyvsp[-4].lex).string, (yyvsp[-3].interm.fieldList), (yyvsp[-1].lex).string, (yylsp[-1]), NULL, (yyloc)); + ES3_OR_NEWER((yyvsp[-4].lex).string->c_str(), (yylsp[-5]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-5].interm.typeQualifierBuilder), (yylsp[-4]), *(yyvsp[-4].lex).string, (yyvsp[-3].interm.fieldList), (yyvsp[-1].lex).string, (yylsp[-1]), NULL, (yyloc)); } break; @@ -3103,8 +3090,8 @@ yyreduce: case 93: { - ES3_ONLY(getQualifierString((yyvsp[-8].interm.type).qualifier), (yylsp[-8]), "interface blocks"); - (yyval.interm.intermNode) = context->addInterfaceBlock((yyvsp[-8].interm.type), (yylsp[-7]), *(yyvsp[-7].lex).string, (yyvsp[-6].interm.fieldList), (yyvsp[-4].lex).string, (yylsp[-4]), (yyvsp[-2].interm.intermTypedNode), (yylsp[-3])); + ES3_OR_NEWER((yyvsp[-7].lex).string->c_str(), (yylsp[-8]), "interface blocks"); + (yyval.interm.intermNode) = context->addInterfaceBlock(*(yyvsp[-8].interm.typeQualifierBuilder), (yylsp[-7]), *(yyvsp[-7].lex).string, (yyvsp[-6].interm.fieldList), (yyvsp[-4].lex).string, (yylsp[-4]), (yyvsp[-2].interm.intermTypedNode), (yylsp[-3])); } break; @@ -3112,7 +3099,7 @@ yyreduce: case 94: { - context->parseGlobalLayoutQualifier((yyvsp[-1].interm.type)); + context->parseGlobalLayoutQualifier(*(yyvsp[-1].interm.typeQualifierBuilder)); (yyval.interm.intermNode) = 0; } @@ -3121,7 +3108,7 @@ yyreduce: case 95: { - (yyval.interm).function = context->parseFunctionDeclarator((yylsp[0]), (yyvsp[-1].interm.function)); + (yyval.interm.intermNode) = context->parseInvariantDeclaration(*(yyvsp[-2].interm.typeQualifierBuilder), (yylsp[-1]), (yyvsp[-1].lex).string, (yyvsp[-1].lex).symbol); } break; @@ -3129,7 +3116,8 @@ yyreduce: case 96: { - (yyval.interm.function) = (yyvsp[0].interm.function); + (yyval.interm).function = context->parseFunctionDeclarator((yylsp[0]), (yyvsp[-1].interm.function)); + context->exitFunctionDeclaration(); } break; @@ -3145,6 +3133,14 @@ yyreduce: case 98: { + (yyval.interm.function) = (yyvsp[0].interm.function); + } + + break; + + case 99: + + { // Add the parameter (yyval.interm.function) = (yyvsp[-1].interm.function); if ((yyvsp[0].interm).param.type->getBasicType() != EbtVoid) @@ -3155,7 +3151,7 @@ yyreduce: break; - case 99: + case 100: { // @@ -3167,7 +3163,6 @@ yyreduce: // This parameter > first is void // context->error((yylsp[-1]), "cannot be an argument type except for '(void)'", "void"); - context->recover(); delete (yyvsp[0].interm).param.type; } else { // Add the parameter @@ -3178,44 +3173,40 @@ yyreduce: break; - case 100: + case 101: { (yyval.interm.function) = context->parseFunctionHeader((yyvsp[-2].interm.type), (yyvsp[-1].lex).string, (yylsp[-1])); context->symbolTable.push(); + context->enterFunctionDeclaration(); } break; - case 101: + case 102: { - if ((yyvsp[-1].interm.type).type == EbtVoid) { + if ((yyvsp[-1].interm.type).getBasicType() == EbtVoid) { context->error((yylsp[0]), "illegal use of type 'void'", (yyvsp[0].lex).string->c_str()); - context->recover(); } - if (context->reservedErrorCheck((yylsp[0]), *(yyvsp[0].lex).string)) - context->recover(); + context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string); TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))}; (yyval.interm).param = param; } break; - case 102: + case 103: { // Check that we can make an array out of this type - if (context->arrayTypeErrorCheck((yylsp[-2]), (yyvsp[-4].interm.type))) - context->recover(); + context->checkIsValidTypeForArray((yylsp[-2]), (yyvsp[-4].interm.type)); + + context->checkIsNotReserved((yylsp[-3]), *(yyvsp[-3].lex).string); - if (context->reservedErrorCheck((yylsp[-3]), *(yyvsp[-3].lex).string)) - context->recover(); + unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); - int size; - if (context->arraySizeErrorCheck((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode), size)) - context->recover(); (yyvsp[-4].interm.type).setArraySize(size); TType* type = new TType((yyvsp[-4].interm.type)); @@ -3225,24 +3216,11 @@ yyreduce: break; - case 103: - - { - (yyval.interm) = (yyvsp[0].interm); - if (context->paramErrorCheck((yylsp[0]), (yyvsp[-2].interm.qualifier), (yyvsp[-1].interm.qualifier), (yyval.interm).param.type)) - context->recover(); - } - - break; - case 104: { (yyval.interm) = (yyvsp[0].interm); - if (context->parameterSamplerErrorCheck((yylsp[0]), (yyvsp[-1].interm.qualifier), *(yyvsp[0].interm).param.type)) - context->recover(); - if (context->paramErrorCheck((yylsp[0]), EvqTemporary, (yyvsp[-1].interm.qualifier), (yyval.interm).param.type)) - context->recover(); + context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm).param.type); } break; @@ -3251,8 +3229,7 @@ yyreduce: { (yyval.interm) = (yyvsp[0].interm); - if (context->paramErrorCheck((yylsp[0]), (yyvsp[-2].interm.qualifier), (yyvsp[-1].interm.qualifier), (yyval.interm).param.type)) - context->recover(); + (yyval.interm).param.type->setQualifier(EvqIn); } break; @@ -3261,10 +3238,7 @@ yyreduce: { (yyval.interm) = (yyvsp[0].interm); - if (context->parameterSamplerErrorCheck((yylsp[0]), (yyvsp[-1].interm.qualifier), *(yyvsp[0].interm).param.type)) - context->recover(); - if (context->paramErrorCheck((yylsp[0]), EvqTemporary, (yyvsp[-1].interm.qualifier), (yyval.interm).param.type)) - context->recover(); + context->checkIsParameterQualifierValid((yylsp[0]), *(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm).param.type); } break; @@ -3272,7 +3246,8 @@ yyreduce: case 107: { - (yyval.interm.qualifier) = EvqIn; + (yyval.interm) = (yyvsp[0].interm); + (yyval.interm).param.type->setQualifier(EvqIn); } break; @@ -3280,7 +3255,8 @@ yyreduce: case 108: { - (yyval.interm.qualifier) = EvqIn; + TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; + (yyval.interm).param = param; } break; @@ -3288,7 +3264,7 @@ yyreduce: case 109: { - (yyval.interm.qualifier) = EvqOut; + (yyval.interm) = (yyvsp[0].interm); } break; @@ -3296,7 +3272,8 @@ yyreduce: case 110: { - (yyval.interm.qualifier) = EvqInOut; + (yyval.interm) = (yyvsp[-2].interm); + (yyval.interm).intermAggregate = context->parseDeclarator((yyval.interm).type, (yyvsp[-2].interm).intermAggregate, (yylsp[0]), *(yyvsp[0].lex).string); } break; @@ -3304,8 +3281,8 @@ yyreduce: case 111: { - TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; - (yyval.interm).param = param; + (yyval.interm) = (yyvsp[-5].interm); + (yyval.interm).intermAggregate = context->parseArrayDeclarator((yyval.interm).type, (yyvsp[-5].interm).intermAggregate, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); } break; @@ -3313,7 +3290,9 @@ yyreduce: case 112: { - (yyval.interm) = (yyvsp[0].interm); + ES3_OR_NEWER("[]", (yylsp[-4]), "implicitly sized array"); + (yyval.interm) = (yyvsp[-6].interm); + (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-6].interm).intermAggregate, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3321,8 +3300,9 @@ yyreduce: case 113: { - (yyval.interm) = (yyvsp[-2].interm); - (yyval.interm).intermAggregate = context->parseDeclarator((yyval.interm).type, (yyvsp[-2].interm).intermAggregate, (yylsp[0]), *(yyvsp[0].lex).string); + ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)"); + (yyval.interm) = (yyvsp[-7].interm); + (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-7].interm).intermAggregate, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3330,8 +3310,8 @@ yyreduce: case 114: { - (yyval.interm) = (yyvsp[-5].interm); - (yyval.interm).intermAggregate = context->parseArrayDeclarator((yyval.interm).type, (yyvsp[-5].interm).intermAggregate, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm) = (yyvsp[-4].interm); + (yyval.interm).intermAggregate = context->parseInitDeclarator((yyval.interm).type, (yyvsp[-4].interm).intermAggregate, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3339,9 +3319,8 @@ yyreduce: case 115: { - ES3_ONLY("[]", (yylsp[-4]), "implicitly sized array"); - (yyval.interm) = (yyvsp[-6].interm); - (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-6].interm).intermAggregate, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).type = (yyvsp[0].interm.type); + (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), ""); } break; @@ -3349,9 +3328,8 @@ yyreduce: case 116: { - ES3_ONLY("=", (yylsp[-1]), "first-class arrays (array initializer)"); - (yyval.interm) = (yyvsp[-7].interm); - (yyval.interm).intermAggregate = context->parseArrayInitDeclarator((yyval.interm).type, (yyvsp[-7].interm).intermAggregate, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).type = (yyvsp[-1].interm.type); + (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), *(yyvsp[0].lex).string); } break; @@ -3359,8 +3337,8 @@ yyreduce: case 117: { - (yyval.interm) = (yyvsp[-4].interm); - (yyval.interm).intermAggregate = context->parseInitDeclarator((yyval.interm).type, (yyvsp[-4].interm).intermAggregate, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).type = (yyvsp[-4].interm.type); + (yyval.interm).intermAggregate = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); } break; @@ -3368,8 +3346,9 @@ yyreduce: case 118: { - (yyval.interm).type = (yyvsp[0].interm.type); - (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), ""); + ES3_OR_NEWER("[]", (yylsp[-3]), "implicitly sized array"); + (yyval.interm).type = (yyvsp[-5].interm.type); + (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3377,8 +3356,9 @@ yyreduce: case 119: { - (yyval.interm).type = (yyvsp[-1].interm.type); - (yyval.interm).intermAggregate = context->parseSingleDeclaration((yyval.interm).type, (yylsp[0]), *(yyvsp[0].lex).string); + ES3_OR_NEWER("=", (yylsp[-1]), "first-class arrays (array initializer)"); + (yyval.interm).type = (yyvsp[-6].interm.type); + (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3386,8 +3366,8 @@ yyreduce: case 120: { - (yyval.interm).type = (yyvsp[-4].interm.type); - (yyval.interm).intermAggregate = context->parseSingleArrayDeclaration((yyval.interm).type, (yylsp[-3]), *(yyvsp[-3].lex).string, (yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm).type = (yyvsp[-3].interm.type); + (yyval.interm).intermAggregate = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); } break; @@ -3395,9 +3375,14 @@ yyreduce: case 121: { - ES3_ONLY("[]", (yylsp[-3]), "implicitly sized array"); - (yyval.interm).type = (yyvsp[-5].interm.type); - (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-4]), *(yyvsp[-4].lex).string, (yylsp[-3]), nullptr, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.type) = (yyvsp[0].interm.type); + + if ((yyvsp[0].interm.type).array) { + ES3_OR_NEWER("[]", (yylsp[0]), "first-class-array"); + if (context->getShaderVersion() != 300) { + (yyvsp[0].interm.type).clearArrayness(); + } + } } break; @@ -3405,9 +3390,7 @@ yyreduce: case 122: { - ES3_ONLY("=", (yylsp[-1]), "first-class arrays (array initializer)"); - (yyval.interm).type = (yyvsp[-6].interm.type); - (yyval.interm).intermAggregate = context->parseSingleArrayInitDeclaration((yyval.interm).type, (yylsp[-5]), *(yyvsp[-5].lex).string, (yylsp[-4]), (yyvsp[-3].interm.intermTypedNode), (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.type) = context->addFullySpecifiedType(*(yyvsp[-1].interm.typeQualifierBuilder), (yyvsp[0].interm.type)); } break; @@ -3415,8 +3398,7 @@ yyreduce: case 123: { - (yyval.interm).type = (yyvsp[-3].interm.type); - (yyval.interm).intermAggregate = context->parseSingleInitDeclaration((yyval.interm).type, (yylsp[-2]), *(yyvsp[-2].lex).string, (yylsp[-1]), (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.qualifier) = EvqSmooth; } break; @@ -3424,8 +3406,7 @@ yyreduce: case 124: { - // $$.type is not used in invariant declarations. - (yyval.interm).intermAggregate = context->parseInvariantDeclaration((yylsp[-1]), (yylsp[0]), (yyvsp[0].lex).string, (yyvsp[0].lex).symbol); + (yyval.interm.qualifier) = EvqFlat; } break; @@ -3433,14 +3414,8 @@ yyreduce: case 125: { - (yyval.interm.type) = (yyvsp[0].interm.type); - - if ((yyvsp[0].interm.type).array) { - ES3_ONLY("[]", (yylsp[0]), "first-class-array"); - if (context->getShaderVersion() != 300) { - (yyvsp[0].interm.type).clearArrayness(); - } - } + (yyval.interm.typeQualifierBuilder) = context->createTypeQualifierBuilder((yylsp[0])); + (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper)); } break; @@ -3448,7 +3423,8 @@ yyreduce: case 126: { - (yyval.interm.type) = context->addFullySpecifiedType((yyvsp[-1].interm.type).qualifier, (yyvsp[-1].interm.type).invariant, (yyvsp[-1].interm.type).layoutQualifier, (yyvsp[0].interm.type)); + (yyval.interm.typeQualifierBuilder) = (yyvsp[-1].interm.typeQualifierBuilder); + (yyval.interm.typeQualifierBuilder)->appendQualifier((yyvsp[0].interm.qualifierWrapper)); } break; @@ -3456,7 +3432,7 @@ yyreduce: case 127: { - (yyval.interm.type).qualifier = EvqSmooth; + // empty } break; @@ -3464,7 +3440,11 @@ yyreduce: case 128: { - (yyval.interm.type).qualifier = EvqFlat; + if (!context->declaringFunction() && (yyvsp[0].interm.qualifier) != EvqConst && !context->symbolTable.atGlobalLevel()) + { + context->error((yylsp[0]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[0].interm.qualifier))); + } + (yyval.interm.qualifierWrapper) = new TStorageQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0])); } break; @@ -3472,7 +3452,8 @@ yyreduce: case 129: { - (yyval.interm.qualifier) = EvqConst; + context->checkIsAtGlobalLevel((yylsp[0]), "layout"); + (yyval.interm.qualifierWrapper) = new TLayoutQualifierWrapper((yyvsp[0].interm.layoutQualifier), (yylsp[0])); } break; @@ -3480,11 +3461,7 @@ yyreduce: case 130: { - VERTEX_ONLY("attribute", (yylsp[0])); - ES2_ONLY("attribute", (yylsp[0])); - if (context->globalErrorCheck((yylsp[0]), context->symbolTable.atGlobalLevel(), "attribute")) - context->recover(); - (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yylsp[0])); + (yyval.interm.qualifierWrapper) = new TPrecisionQualifierWrapper((yyvsp[0].interm.precision), (yylsp[0])); } break; @@ -3492,13 +3469,7 @@ yyreduce: case 131: { - ES2_ONLY("varying", (yylsp[0])); - if (context->globalErrorCheck((yylsp[0]), context->symbolTable.atGlobalLevel(), "varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yylsp[0])); - else - (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yylsp[0])); + (yyval.interm.qualifierWrapper) = new TInterpolationQualifierWrapper((yyvsp[0].interm.qualifier), (yylsp[0])); } break; @@ -3506,14 +3477,8 @@ yyreduce: case 132: { - ES2_ONLY("varying", (yylsp[-1])); - if (context->globalErrorCheck((yylsp[-1]), context->symbolTable.atGlobalLevel(), "invariant varying")) - context->recover(); - if (context->getShaderType() == GL_VERTEX_SHADER) - (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yylsp[-1])); - else - (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yylsp[-1])); - (yyval.interm.type).invariant = true; + context->checkIsAtGlobalLevel((yylsp[0]), "invariant"); + (yyval.interm.qualifierWrapper) = new TInvariantQualifierWrapper((yylsp[0])); } break; @@ -3521,12 +3486,10 @@ yyreduce: case 133: { - if ((yyvsp[0].interm.type).qualifier != EvqConst && !context->symbolTable.atGlobalLevel()) - { - context->error((yylsp[0]), "Local variables can only use the const storage qualifier.", getQualifierString((yyvsp[0].interm.type).qualifier)); - context->recover(); - } - (yyval.interm.type).setBasic(EbtVoid, (yyvsp[0].interm.type).qualifier, (yylsp[0])); + VERTEX_ONLY("attribute", (yylsp[0])); + ES2_ONLY("attribute", (yylsp[0])); + context->checkIsAtGlobalLevel((yylsp[0]), "attribute"); + (yyval.interm.qualifier) = EvqAttribute; } break; @@ -3534,7 +3497,12 @@ yyreduce: case 134: { - (yyval.interm.type) = context->joinInterpolationQualifiers((yylsp[-1]), (yyvsp[-1].interm.type).qualifier, (yylsp[0]), (yyvsp[0].interm.type).qualifier); + ES2_ONLY("varying", (yylsp[0])); + context->checkIsAtGlobalLevel((yylsp[0]), "varying"); + if (context->getShaderType() == GL_VERTEX_SHADER) + (yyval.interm.qualifier) = EvqVaryingOut; + else + (yyval.interm.qualifier) = EvqVaryingIn; } break; @@ -3542,11 +3510,7 @@ yyreduce: case 135: { - context->error((yylsp[0]), "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier", getInterpolationString((yyvsp[0].interm.type).qualifier)); - context->recover(); - - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[0])); + (yyval.interm.qualifier) = EvqConst; } break; @@ -3554,8 +3518,24 @@ yyreduce: case 136: { - (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).layoutQualifier = (yyvsp[0].interm.layoutQualifier); + if (context->declaringFunction()) + { + (yyval.interm.qualifier) = EvqIn; + } + else if (context->getShaderType() == GL_FRAGMENT_SHADER) + { + ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier"); + (yyval.interm.qualifier) = EvqFragmentIn; + } + else if (context->getShaderType() == GL_VERTEX_SHADER) + { + ES3_OR_NEWER("in", (yylsp[0]), "storage qualifier"); + (yyval.interm.qualifier) = EvqVertexIn; + } + else + { + (yyval.interm.qualifier) = EvqComputeIn; + } } break; @@ -3563,8 +3543,23 @@ yyreduce: case 137: { - (yyval.interm.type).setBasic(EbtVoid, (yyvsp[0].interm.type).qualifier, (yylsp[0])); - (yyval.interm.type).layoutQualifier = (yyvsp[-1].interm.layoutQualifier); + if (context->declaringFunction()) + { + (yyval.interm.qualifier) = EvqOut; + } + else + { + ES3_OR_NEWER("out", (yylsp[0]), "storage qualifier"); + NON_COMPUTE_ONLY("out", (yylsp[0])); + if (context->getShaderType() == GL_FRAGMENT_SHADER) + { + (yyval.interm.qualifier) = EvqFragmentOut; + } + else + { + (yyval.interm.qualifier) = EvqVertexOut; + } + } } break; @@ -3572,9 +3567,11 @@ yyreduce: case 138: { - context->es3InvariantErrorCheck((yyvsp[0].interm.type).qualifier, (yylsp[-1])); - (yyval.interm.type).setBasic(EbtVoid, (yyvsp[0].interm.type).qualifier, (yylsp[0])); - (yyval.interm.type).invariant = true; + if (!context->declaringFunction()) + { + context->error((yylsp[0]), "invalid inout qualifier", "'inout' can be only used with function parameters"); + } + (yyval.interm.qualifier) = EvqInOut; } break; @@ -3582,9 +3579,8 @@ yyreduce: case 139: { - context->es3InvariantErrorCheck((yyvsp[0].interm.type).qualifier, (yylsp[-2])); - (yyval.interm.type) = context->joinInterpolationQualifiers((yylsp[-1]), (yyvsp[-1].interm.type).qualifier, (yylsp[0]), (yyvsp[0].interm.type).qualifier); - (yyval.interm.type).invariant = true; + ES3_OR_NEWER("centroid", (yylsp[0]), "storage qualifier"); + (yyval.interm.qualifier) = EvqCentroid; } break; @@ -3592,7 +3588,8 @@ yyreduce: case 140: { - (yyval.interm.type).qualifier = EvqConst; + context->checkIsAtGlobalLevel((yylsp[0]), "uniform"); + (yyval.interm.qualifier) = EvqUniform; } break; @@ -3600,8 +3597,11 @@ yyreduce: case 141: { - ES3_ONLY("in", (yylsp[0]), "storage qualifier"); - (yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn; + (yyval.interm.type) = (yyvsp[0].interm.type); + + if ((yyval.interm.type).precision == EbpUndefined) { + (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[0].interm.type).getBasicType()); + } } break; @@ -3609,8 +3609,7 @@ yyreduce: case 142: { - ES3_ONLY("out", (yylsp[0]), "storage qualifier"); - (yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut; + (yyval.interm.precision) = EbpHigh; } break; @@ -3618,13 +3617,7 @@ yyreduce: case 143: { - ES3_ONLY("centroid in", (yylsp[-1]), "storage qualifier"); - if (context->getShaderType() == GL_VERTEX_SHADER) - { - context->error((yylsp[-1]), "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader"); - context->recover(); - } - (yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn; + (yyval.interm.precision) = EbpMedium; } break; @@ -3632,13 +3625,7 @@ yyreduce: case 144: { - ES3_ONLY("centroid out", (yylsp[-1]), "storage qualifier"); - if (context->getShaderType() == GL_FRAGMENT_SHADER) - { - context->error((yylsp[-1]), "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader"); - context->recover(); - } - (yyval.interm.type).qualifier = (context->getShaderType() == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut; + (yyval.interm.precision) = EbpLow; } break; @@ -3646,9 +3633,8 @@ yyreduce: case 145: { - if (context->globalErrorCheck((yylsp[0]), context->symbolTable.atGlobalLevel(), "uniform")) - context->recover(); - (yyval.interm.type).qualifier = EvqUniform; + ES3_OR_NEWER("layout", (yylsp[-3]), "qualifier"); + (yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier); } break; @@ -3656,14 +3642,7 @@ yyreduce: case 146: { - (yyval.interm.type) = (yyvsp[0].interm.type); - - if ((yyval.interm.type).precision == EbpUndefined) { - (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[0].interm.type).type); - if (context->precisionErrorCheck((yylsp[0]), (yyval.interm.type).precision, (yyvsp[0].interm.type).type)) { - context->recover(); - } - } + (yyval.interm.layoutQualifier) = (yyvsp[0].interm.layoutQualifier); } break; @@ -3671,13 +3650,7 @@ yyreduce: case 147: { - (yyval.interm.type) = (yyvsp[0].interm.type); - (yyval.interm.type).precision = (yyvsp[-1].interm.precision); - - if (!SupportsPrecision((yyvsp[0].interm.type).type)) { - context->error((yylsp[-1]), "illegal type for precision qualifier", getBasicString((yyvsp[0].interm.type).type)); - context->recover(); - } + (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier), (yylsp[0])); } break; @@ -3685,7 +3658,7 @@ yyreduce: case 148: { - (yyval.interm.precision) = EbpHigh; + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[0].lex).string, (yylsp[0])); } break; @@ -3693,7 +3666,7 @@ yyreduce: case 149: { - (yyval.interm.precision) = EbpMedium; + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0])); } break; @@ -3701,7 +3674,7 @@ yyreduce: case 150: { - (yyval.interm.precision) = EbpLow; + (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), (yyvsp[0].lex).i, (yylsp[0])); } break; @@ -3709,8 +3682,7 @@ yyreduce: case 151: { - ES3_ONLY("layout", (yylsp[-3]), "qualifier"); - (yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier); + (yyval.interm.type).initialize((yyvsp[0].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); } break; @@ -3718,7 +3690,9 @@ yyreduce: case 152: { - (yyval.interm.layoutQualifier) = (yyvsp[0].interm.layoutQualifier); + ES3_OR_NEWER("[]", (yylsp[-1]), "implicitly sized array"); + (yyval.interm.type).initialize((yyvsp[-2].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + (yyval.interm.type).setArraySize(0); } break; @@ -3726,7 +3700,12 @@ yyreduce: case 153: { - (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[-2].interm.layoutQualifier), (yyvsp[0].interm.layoutQualifier)); + (yyval.interm.type).initialize((yyvsp[-3].interm.typeSpecifierNonArray), (context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary)); + if (context->checkIsValidTypeForArray((yylsp[-2]), (yyval.interm.type))) + { + unsigned int size = context->checkIsValidArraySize((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm.type).setArraySize(size); + } } break; @@ -3734,7 +3713,7 @@ yyreduce: case 154: { - (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[0].lex).string, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtVoid, (yylsp[0])); } break; @@ -3742,7 +3721,7 @@ yyreduce: case 155: { - (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), *(yyvsp[0].lex).string, (yyvsp[0].lex).i, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); } break; @@ -3750,7 +3729,7 @@ yyreduce: case 156: { - (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[-2].lex).string, (yylsp[-2]), *(yyvsp[0].lex).string, (yyvsp[0].lex).i, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); } break; @@ -3758,7 +3737,7 @@ yyreduce: case 157: { - (yyval.interm.type) = (yyvsp[0].interm.type); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); } break; @@ -3766,9 +3745,7 @@ yyreduce: case 158: { - ES3_ONLY("[]", (yylsp[-1]), "implicitly sized array"); - (yyval.interm.type) = (yyvsp[-2].interm.type); - (yyval.interm.type).setArraySize(0); + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); } break; @@ -3776,16 +3753,8 @@ yyreduce: case 159: { - (yyval.interm.type) = (yyvsp[-3].interm.type); - - if (context->arrayTypeErrorCheck((yylsp[-2]), (yyvsp[-3].interm.type))) - context->recover(); - else { - int size; - if (context->arraySizeErrorCheck((yylsp[-2]), (yyvsp[-1].interm.intermTypedNode), size)) - context->recover(); - (yyval.interm.type).setArraySize(size); - } + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); } break; @@ -3793,8 +3762,8 @@ yyreduce: case 160: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); } break; @@ -3802,8 +3771,8 @@ yyreduce: case 161: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); } break; @@ -3811,8 +3780,8 @@ yyreduce: case 162: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); } break; @@ -3820,8 +3789,8 @@ yyreduce: case 163: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); } break; @@ -3829,8 +3798,8 @@ yyreduce: case 164: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtBool, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); } break; @@ -3838,9 +3807,8 @@ yyreduce: case 165: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); } break; @@ -3848,9 +3816,8 @@ yyreduce: case 166: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); } break; @@ -3858,9 +3825,8 @@ yyreduce: case 167: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); } break; @@ -3868,9 +3834,8 @@ yyreduce: case 168: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(2); } break; @@ -3878,9 +3843,8 @@ yyreduce: case 169: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(3); } break; @@ -3888,9 +3852,8 @@ yyreduce: case 170: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUInt, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setAggregate(4); } break; @@ -3898,9 +3861,8 @@ yyreduce: case 171: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 2); } break; @@ -3908,9 +3870,8 @@ yyreduce: case 172: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 3); } break; @@ -3918,9 +3879,8 @@ yyreduce: case 173: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 4); } break; @@ -3928,9 +3888,8 @@ yyreduce: case 174: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 3); } break; @@ -3938,9 +3897,8 @@ yyreduce: case 175: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 2); } break; @@ -3948,9 +3906,8 @@ yyreduce: case 176: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUInt, qual, (yylsp[0])); - (yyval.interm.type).setAggregate(4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(2, 4); } break; @@ -3958,9 +3915,8 @@ yyreduce: case 177: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(2, 2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 2); } break; @@ -3968,9 +3924,8 @@ yyreduce: case 178: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(3, 3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(3, 4); } break; @@ -3978,9 +3933,8 @@ yyreduce: case 179: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(4, 4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtFloat, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).setMatrix(4, 3); } break; @@ -3988,9 +3942,7 @@ yyreduce: case 180: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(2, 3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2D, (yylsp[0])); } break; @@ -3998,9 +3950,7 @@ yyreduce: case 181: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(3, 2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler3D, (yylsp[0])); } break; @@ -4008,9 +3958,7 @@ yyreduce: case 182: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(2, 4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCube, (yylsp[0])); } break; @@ -4018,9 +3966,7 @@ yyreduce: case 183: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(4, 2); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArray, (yylsp[0])); } break; @@ -4028,9 +3974,7 @@ yyreduce: case 184: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(3, 4); + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2D, (yylsp[0])); } break; @@ -4038,9 +3982,7 @@ yyreduce: case 185: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[0])); - (yyval.interm.type).setMatrix(4, 3); + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler3D, (yylsp[0])); } break; @@ -4048,8 +3990,7 @@ yyreduce: case 186: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler2D, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtISamplerCube, (yylsp[0])); } break; @@ -4057,8 +3998,7 @@ yyreduce: case 187: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler3D, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtISampler2DArray, (yylsp[0])); } break; @@ -4066,8 +4006,7 @@ yyreduce: case 188: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2D, (yylsp[0])); } break; @@ -4075,8 +4014,7 @@ yyreduce: case 189: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler2DArray, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler3D, (yylsp[0])); } break; @@ -4084,8 +4022,7 @@ yyreduce: case 190: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtISampler2D, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSamplerCube, (yylsp[0])); } break; @@ -4093,8 +4030,7 @@ yyreduce: case 191: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtISampler3D, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtUSampler2DArray, (yylsp[0])); } break; @@ -4102,8 +4038,7 @@ yyreduce: case 192: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtISamplerCube, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DShadow, (yylsp[0])); } break; @@ -4111,8 +4046,7 @@ yyreduce: case 193: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtISampler2DArray, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerCubeShadow, (yylsp[0])); } break; @@ -4120,8 +4054,7 @@ yyreduce: case 194: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUSampler2D, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DArrayShadow, (yylsp[0])); } break; @@ -4129,94 +4062,35 @@ yyreduce: case 195: { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUSampler3D, qual, (yylsp[0])); - } - - break; - - case 196: - - { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUSamplerCube, qual, (yylsp[0])); - } - - break; - - case 197: - - { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtUSampler2DArray, qual, (yylsp[0])); - } - - break; - - case 198: - - { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler2DShadow, qual, (yylsp[0])); - } - - break; - - case 199: - - { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSamplerCubeShadow, qual, (yylsp[0])); - } - - break; - - case 200: - - { - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler2DArrayShadow, qual, (yylsp[0])); - } - - break; - - case 201: - - { if (!context->supportsExtension("GL_OES_EGL_image_external") && !context->supportsExtension("GL_NV_EGL_stream_consumer_external")) { context->error((yylsp[0]), "unsupported type", "samplerExternalOES"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSamplerExternalOES, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSamplerExternalOES, (yylsp[0])); } break; - case 202: + case 196: { if (!context->supportsExtension("GL_ARB_texture_rectangle")) { context->error((yylsp[0]), "unsupported type", "sampler2DRect"); - context->recover(); } - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).initialize(EbtSampler2DRect, (yylsp[0])); } break; - case 203: + case 197: { - (yyval.interm.type) = (yyvsp[0].interm.type); - (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + (yyval.interm.typeSpecifierNonArray) = (yyvsp[0].interm.typeSpecifierNonArray); } break; - case 204: + case 198: { // @@ -4224,42 +4098,41 @@ yyreduce: // type. // TType& structure = static_cast<TVariable*>((yyvsp[0].lex).symbol)->getType(); - TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; - (yyval.interm.type).setBasic(EbtStruct, qual, (yylsp[0])); - (yyval.interm.type).userDef = &structure; + (yyval.interm.typeSpecifierNonArray).initialize(EbtStruct, (yylsp[0])); + (yyval.interm.typeSpecifierNonArray).userDef = &structure; } break; - case 205: + case 199: - { if (context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string)) context->recover(); } + { context->enterStructDeclaration((yylsp[-1]), *(yyvsp[-1].lex).string); } break; - case 206: + case 200: { - (yyval.interm.type) = context->addStructure((yylsp[-5]), (yylsp[-4]), (yyvsp[-4].lex).string, (yyvsp[-1].interm.fieldList)); + (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-5]), (yylsp[-4]), (yyvsp[-4].lex).string, (yyvsp[-1].interm.fieldList)); } break; - case 207: + case 201: - { if (context->enterStructDeclaration((yylsp[0]), *(yyvsp[0].lex).string)) context->recover(); } + { context->enterStructDeclaration((yylsp[0]), *(yyvsp[0].lex).string); } break; - case 208: + case 202: { - (yyval.interm.type) = context->addStructure((yylsp[-4]), (yyloc), NewPoolTString(""), (yyvsp[-1].interm.fieldList)); + (yyval.interm.typeSpecifierNonArray) = context->addStructure((yylsp[-4]), (yyloc), NewPoolTString(""), (yyvsp[-1].interm.fieldList)); } break; - case 209: + case 203: { (yyval.interm.fieldList) = (yyvsp[0].interm.fieldList); @@ -4267,7 +4140,7 @@ yyreduce: break; - case 210: + case 204: { (yyval.interm.fieldList) = (yyvsp[-1].interm.fieldList); @@ -4276,7 +4149,6 @@ yyreduce: for (size_t j = 0; j < (yyval.interm.fieldList)->size(); ++j) { if ((*(yyval.interm.fieldList))[j]->name() == field->name()) { context->error((yylsp[0]), "duplicate field name in structure:", "struct", field->name().c_str()); - context->recover(); } } (yyval.interm.fieldList)->push_back(field); @@ -4285,7 +4157,7 @@ yyreduce: break; - case 211: + case 205: { (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList)); @@ -4293,18 +4165,16 @@ yyreduce: break; - case 212: + case 206: { // ES3 Only, but errors should be handled elsewhere - (yyvsp[-2].interm.type).qualifier = (yyvsp[-3].interm.type).qualifier; - (yyvsp[-2].interm.type).layoutQualifier = (yyvsp[-3].interm.type).layoutQualifier; - (yyval.interm.fieldList) = context->addStructDeclaratorList((yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList)); + (yyval.interm.fieldList) = context->addStructDeclaratorListWithQualifiers(*(yyvsp[-3].interm.typeQualifierBuilder), &(yyvsp[-2].interm.type), (yyvsp[-1].interm.fieldList)); } break; - case 213: + case 207: { (yyval.interm.fieldList) = NewPoolTFieldList(); @@ -4313,7 +4183,7 @@ yyreduce: break; - case 214: + case 208: { (yyval.interm.fieldList)->push_back((yyvsp[0].interm.field)); @@ -4321,11 +4191,10 @@ yyreduce: break; - case 215: + case 209: { - if (context->reservedErrorCheck((yylsp[0]), *(yyvsp[0].lex).string)) - context->recover(); + context->checkIsNotReserved((yylsp[0]), *(yyvsp[0].lex).string); TType* type = new TType(EbtVoid, EbpUndefined); (yyval.interm.field) = new TField(type, (yyvsp[0].lex).string, (yylsp[0])); @@ -4333,16 +4202,13 @@ yyreduce: break; - case 216: + case 210: { - if (context->reservedErrorCheck((yylsp[-3]), *(yyvsp[-3].lex).string)) - context->recover(); + context->checkIsNotReserved((yylsp[-3]), *(yyvsp[-3].lex).string); TType* type = new TType(EbtVoid, EbpUndefined); - int size; - if (context->arraySizeErrorCheck((yylsp[-1]), (yyvsp[-1].interm.intermTypedNode), size)) - context->recover(); + unsigned int size = context->checkIsValidArraySize((yylsp[-1]), (yyvsp[-1].interm.intermTypedNode)); type->setArraySize(size); (yyval.interm.field) = new TField(type, (yyvsp[-3].lex).string, (yylsp[-3])); @@ -4350,91 +4216,91 @@ yyreduce: break; - case 217: + case 211: { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } break; - case 218: + case 212: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 219: + case 213: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); } break; - case 220: + case 214: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 221: + case 215: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 222: + case 216: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 223: + case 217: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 224: + case 218: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermSwitch); } break; - case 225: + case 219: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermCase); } break; - case 226: + case 220: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 227: + case 221: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 228: + case 222: { (yyval.interm.intermAggregate) = 0; } break; - case 229: + case 223: { context->symbolTable.push(); } break; - case 230: + case 224: { context->symbolTable.pop(); } break; - case 231: + case 225: { if ((yyvsp[-2].interm.intermAggregate) != 0) { @@ -4446,43 +4312,43 @@ yyreduce: break; - case 232: + case 226: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); } break; - case 233: + case 227: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 234: + case 228: { context->symbolTable.push(); } break; - case 235: + case 229: { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermAggregate); } break; - case 236: + case 230: { context->symbolTable.push(); } break; - case 237: + case 231: { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } break; - case 238: + case 232: { (yyval.interm.intermAggregate) = 0; @@ -4490,7 +4356,7 @@ yyreduce: break; - case 239: + case 233: { if ((yyvsp[-1].interm.intermAggregate)) { @@ -4502,15 +4368,15 @@ yyreduce: break; - case 240: + case 234: { - (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[0].interm.intermNode), (yyloc)); + (yyval.interm.intermAggregate) = TIntermediate::MakeAggregate((yyvsp[0].interm.intermNode), (yyloc)); } break; - case 241: + case 235: { (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[-1].interm.intermAggregate), (yyvsp[0].interm.intermNode), (yyloc)); @@ -4518,29 +4384,28 @@ yyreduce: break; - case 242: + case 236: { (yyval.interm.intermNode) = 0; } break; - case 243: + case 237: { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[-1].interm.intermTypedNode)); } break; - case 244: + case 238: { - if (context->boolErrorCheck((yylsp[-4]), (yyvsp[-2].interm.intermTypedNode))) - context->recover(); - (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yylsp[-4])); + context->checkIsScalarBool((yylsp[-4]), (yyvsp[-2].interm.intermTypedNode)); + (yyval.interm.intermNode) = context->intermediate.addIfElse((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yylsp[-4])); } break; - case 245: + case 239: { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); @@ -4549,7 +4414,7 @@ yyreduce: break; - case 246: + case 240: { (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); @@ -4558,13 +4423,13 @@ yyreduce: break; - case 247: + case 241: { context->incrSwitchNestingLevel(); } break; - case 248: + case 242: { (yyval.interm.intermSwitch) = context->addSwitch((yyvsp[-3].interm.intermTypedNode), (yyvsp[0].interm.intermAggregate), (yylsp[-5])); @@ -4573,7 +4438,7 @@ yyreduce: break; - case 249: + case 243: { (yyval.interm.intermCase) = context->addCase((yyvsp[-1].interm.intermTypedNode), (yylsp[-2])); @@ -4581,7 +4446,7 @@ yyreduce: break; - case 250: + case 244: { (yyval.interm.intermCase) = context->addDefault((yylsp[-1])); @@ -4589,40 +4454,37 @@ yyreduce: break; - case 251: + case 245: { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); - if (context->boolErrorCheck((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode))) - context->recover(); + context->checkIsScalarBool((yyvsp[0].interm.intermTypedNode)->getLine(), (yyvsp[0].interm.intermTypedNode)); } break; - case 252: + case 246: { TIntermNode *intermNode; - if (context->boolErrorCheck((yylsp[-2]), (yyvsp[-3].interm.type))) - context->recover(); + context->checkIsScalarBool((yylsp[-2]), (yyvsp[-3].interm.type)); if (!context->executeInitializer((yylsp[-2]), *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), (yyvsp[0].interm.intermTypedNode), &intermNode)) (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); else { - context->recover(); (yyval.interm.intermTypedNode) = 0; } } break; - case 253: + case 247: { context->symbolTable.push(); context->incrLoopNestingLevel(); } break; - case 254: + case 248: { context->symbolTable.pop(); @@ -4632,17 +4494,16 @@ yyreduce: break; - case 255: + case 249: { context->incrLoopNestingLevel(); } break; - case 256: + case 250: { - if (context->boolErrorCheck((yylsp[0]), (yyvsp[-2].interm.intermTypedNode))) - context->recover(); + context->checkIsScalarBool((yylsp[0]), (yyvsp[-2].interm.intermTypedNode)); (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[-2].interm.intermTypedNode), 0, (yyvsp[-5].interm.intermNode), (yylsp[-4])); context->decrLoopNestingLevel(); @@ -4650,13 +4511,13 @@ yyreduce: break; - case 257: + case 251: { context->symbolTable.push(); context->incrLoopNestingLevel(); } break; - case 258: + case 252: { context->symbolTable.pop(); @@ -4666,7 +4527,7 @@ yyreduce: break; - case 259: + case 253: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); @@ -4674,7 +4535,7 @@ yyreduce: break; - case 260: + case 254: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); @@ -4682,7 +4543,7 @@ yyreduce: break; - case 261: + case 255: { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); @@ -4690,7 +4551,7 @@ yyreduce: break; - case 262: + case 256: { (yyval.interm.intermTypedNode) = 0; @@ -4698,7 +4559,7 @@ yyreduce: break; - case 263: + case 257: { (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); @@ -4707,7 +4568,7 @@ yyreduce: break; - case 264: + case 258: { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); @@ -4716,7 +4577,7 @@ yyreduce: break; - case 265: + case 259: { (yyval.interm.intermNode) = context->addBranch(EOpContinue, (yylsp[-1])); @@ -4724,7 +4585,7 @@ yyreduce: break; - case 266: + case 260: { (yyval.interm.intermNode) = context->addBranch(EOpBreak, (yylsp[-1])); @@ -4732,7 +4593,7 @@ yyreduce: break; - case 267: + case 261: { (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yylsp[-1])); @@ -4740,7 +4601,7 @@ yyreduce: break; - case 268: + case 262: { (yyval.interm.intermNode) = context->addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yylsp[-2])); @@ -4748,7 +4609,7 @@ yyreduce: break; - case 269: + case 263: { FRAG_ONLY("discard", (yylsp[-1])); @@ -4757,7 +4618,7 @@ yyreduce: break; - case 270: + case 264: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); @@ -4766,7 +4627,7 @@ yyreduce: break; - case 271: + case 265: { (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode), (yyloc)); @@ -4775,7 +4636,7 @@ yyreduce: break; - case 272: + case 266: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); @@ -4783,7 +4644,7 @@ yyreduce: break; - case 273: + case 267: { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); @@ -4791,7 +4652,7 @@ yyreduce: break; - case 274: + case 268: { context->parseFunctionPrototype((yylsp[0]), (yyvsp[0].interm).function, &(yyvsp[0].interm).intermAggregate); @@ -4799,7 +4660,7 @@ yyreduce: break; - case 275: + case 269: { (yyval.interm.intermNode) = context->addFunctionDefinition(*((yyvsp[-2].interm).function), (yyvsp[-2].interm).intermAggregate, (yyvsp[0].interm.intermAggregate), (yylsp[-2])); diff --git a/chromium/third_party/angle/src/compiler/translator/glslang_tab.h b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h index 7331594a448..d0e691d844f 100644 --- a/chromium/third_party/angle/src/compiler/translator/glslang_tab.h +++ b/chromium/third_party/angle/src/compiler/translator/glslang_tab.h @@ -208,6 +208,7 @@ union YYSTYPE TIntermCase* intermCase; }; union { + TTypeSpecifierNonArray typeSpecifierNonArray; TPublicType type; TPrecision precision; TLayoutQualifier layoutQualifier; @@ -216,6 +217,8 @@ union YYSTYPE TParameter param; TField* field; TFieldList* fieldList; + TQualifierWrapperBase *qualifierWrapper; + TTypeQualifierBuilder *typeQualifierBuilder; }; } interm; diff --git a/chromium/third_party/angle/src/compiler/translator/intermOut.cpp b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp index 6dca547f086..aed53d4ec4d 100644 --- a/chromium/third_party/angle/src/compiler/translator/intermOut.cpp +++ b/chromium/third_party/angle/src/compiler/translator/intermOut.cpp @@ -42,12 +42,15 @@ class TOutputTraverser : public TIntermTraverser protected: void visitSymbol(TIntermSymbol *) override; void visitConstantUnion(TIntermConstantUnion *) override; + bool visitSwizzle(Visit visit, TIntermSwizzle *node) override; bool visitBinary(Visit visit, TIntermBinary *) override; bool visitUnary(Visit visit, TIntermUnary *) override; - bool visitSelection(Visit visit, TIntermSelection *) override; + bool visitTernary(Visit visit, TIntermTernary *node) override; + bool visitIfElse(Visit visit, TIntermIfElse *node) override; bool visitAggregate(Visit visit, TIntermAggregate *) override; bool visitLoop(Visit visit, TIntermLoop *) override; bool visitBranch(Visit visit, TIntermBranch *) override; + // TODO: Add missing visit functions }; // @@ -82,6 +85,14 @@ void TOutputTraverser::visitSymbol(TIntermSymbol *node) sink << "(" << node->getCompleteString() << ")\n"; } +bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node) +{ + TInfoSinkBase &out = sink; + OutputTreeText(out, node, mDepth); + out << "vector swizzle"; + return true; +} + bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) { TInfoSinkBase& out = sink; @@ -151,9 +162,6 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) case EOpIndexDirectInterfaceBlock: out << "direct index for interface block"; break; - case EOpVectorSwizzle: - out << "vector swizzle"; - break; case EOpAdd: out << "add"; @@ -457,13 +465,13 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) return true; } -bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node) +bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node) { TInfoSinkBase &out = sink; OutputTreeText(out, node, mDepth); - out << "Test condition and select"; + out << "Ternary selection"; out << " (" << node->getCompleteString() << ")\n"; ++mDepth; @@ -473,6 +481,38 @@ bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection *node) node->getCondition()->traverse(this); OutputTreeText(sink, node, mDepth); + if (node->getTrueExpression()) + { + out << "true case\n"; + node->getTrueExpression()->traverse(this); + } + if (node->getFalseExpression()) + { + OutputTreeText(sink, node, mDepth); + out << "false case\n"; + node->getFalseExpression()->traverse(this); + } + + --mDepth; + + return false; +} + +bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node) +{ + TInfoSinkBase &out = sink; + + OutputTreeText(out, node, mDepth); + + out << "If test\n"; + + ++mDepth; + + OutputTreeText(sink, node, mDepth); + out << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(sink, node, mDepth); if (node->getTrueBlock()) { out << "true case\n"; diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp deleted file mode 100644 index 790974a2bf5..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/InfoSink.h" -#include "compiler/translator/ParseContext.h" -#include "compiler/translator/depgraph/DependencyGraphOutput.h" -#include "compiler/translator/timing/RestrictFragmentShaderTiming.h" - -RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink) - : mSink(sink) - , mNumErrors(0) -{ - // Sampling ops found only in fragment shaders. - mSamplingOps.insert("texture2D(s21;vf2;f1;"); - mSamplingOps.insert("texture2DProj(s21;vf3;f1;"); - mSamplingOps.insert("texture2DProj(s21;vf4;f1;"); - mSamplingOps.insert("textureCube(sC1;vf3;f1;"); - // Sampling ops found in both vertex and fragment shaders. - mSamplingOps.insert("texture2D(s21;vf2;"); - mSamplingOps.insert("texture2DProj(s21;vf3;"); - mSamplingOps.insert("texture2DProj(s21;vf4;"); - mSamplingOps.insert("textureCube(sC1;vf3;"); - // Sampling ops provided by OES_EGL_image_external. - mSamplingOps.insert("texture2D(1;vf2;"); - mSamplingOps.insert("texture2DProj(1;vf3;"); - mSamplingOps.insert("texture2DProj(1;vf4;"); - // Sampling ops provided by ARB_texture_rectangle. - mSamplingOps.insert("texture2DRect(1;vf2;"); - mSamplingOps.insert("texture2DRectProj(1;vf3;"); - mSamplingOps.insert("texture2DRectProj(1;vf4;"); - // Sampling ops provided by EXT_shader_texture_lod. - mSamplingOps.insert("texture2DLodEXT(1;vf2;f1;"); - mSamplingOps.insert("texture2DProjLodEXT(1;vf3;f1;"); - mSamplingOps.insert("texture2DProjLodEXT(1;vf4;f1;"); - mSamplingOps.insert("textureCubeLodEXT(1;vf4;f1;"); - mSamplingOps.insert("texture2DGradEXT(1;vf2;vf2;vf2;"); - mSamplingOps.insert("texture2DProjGradEXT(1;vf3;vf2;vf2;"); - mSamplingOps.insert("texture2DProjGradEXT(1;vf4;vf2;vf2;"); - mSamplingOps.insert("textureCubeGradEXT(1;vf3;vf3;vf3;"); -} - -// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc. -// can vary based on the value of the input arguments. If so, we should restrict those as well. -void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph) -{ - mNumErrors = 0; - - // FIXME(mvujovic): The dependency graph does not support user defined function calls right now, - // so we generate errors for them. - validateUserDefinedFunctionCallUsage(graph); - - // Starting from each sampler, traverse the dependency graph and generate an error each time we - // hit a node where sampler dependent values are not allowed. - for (auto samplerSymbol : graph.samplerSymbols()) - { - clearVisited(); - samplerSymbol->traverse(this); - } -} - -void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph) -{ - for (const auto* functionCall : graph.userDefinedFunctionCalls()) - { - beginError(functionCall->getIntermFunctionCall()); - mSink << "A call to a user defined function is not permitted.\n"; - } -} - -void RestrictFragmentShaderTiming::beginError(const TIntermNode* node) -{ - ++mNumErrors; - mSink.prefix(EPrefixError); - mSink.location(node->getLine()); -} - -bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const -{ - return !intermFunctionCall->isUserDefined() && - mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end(); -} - -void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter) -{ - // Texture cache access time might leak sensitive information. - // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a - // sampling operation. - if (isSamplingOp(parameter->getIntermFunctionCall())) { - switch (parameter->getArgumentNumber()) { - case 1: - // Second argument (coord) - beginError(parameter->getIntermFunctionCall()); - mSink << "An expression dependent on a sampler is not permitted to be the" - << " coordinate argument of a sampling operation.\n"; - break; - case 2: - // Third argument (bias) - beginError(parameter->getIntermFunctionCall()); - mSink << "An expression dependent on a sampler is not permitted to be the" - << " bias argument of a sampling operation.\n"; - break; - default: - // First argument (sampler) - break; - } - } -} - -void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection) -{ - beginError(selection->getIntermSelection()); - mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n"; -} - -void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop) -{ - beginError(loop->getIntermLoop()); - mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n"; -} - -void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp) -{ - beginError(logicalOp->getIntermLogicalOp()); - mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical " - << logicalOp->getOpString() - << " operator.\n"; -} diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h deleted file mode 100644 index b8c7e829564..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ -#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ - -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/depgraph/DependencyGraph.h" - -class TInfoSinkBase; - -class RestrictFragmentShaderTiming : TDependencyGraphTraverser -{ - public: - RestrictFragmentShaderTiming(TInfoSinkBase &sink); - void enforceRestrictions(const TDependencyGraph &graph); - int numErrors() const { return mNumErrors; } - - void visitArgument(TGraphArgument *parameter) override; - void visitSelection(TGraphSelection *selection) override; - void visitLoop(TGraphLoop *loop) override; - void visitLogicalOp(TGraphLogicalOp *logicalOp) override; - - private: - void beginError(const TIntermNode *node); - void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph); - bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const; - - TInfoSinkBase &mSink; - int mNumErrors; - - typedef std::set<TString> StringSet; - StringSet mSamplingOps; -}; - -#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp deleted file mode 100644 index 7c1208a2986..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#include "compiler/translator/timing/RestrictVertexShaderTiming.h" - -void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node) -{ - if (IsSampler(node->getBasicType())) { - ++mNumErrors; - mSink.message(EPrefixError, - node->getLine(), - "Samplers are not permitted in vertex shaders.\n"); - } -} diff --git a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h deleted file mode 100644 index 23a8217722e..00000000000 --- a/chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ -#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ - -#include "compiler/translator/IntermNode.h" -#include "compiler/translator/InfoSink.h" - -class TInfoSinkBase; - -class RestrictVertexShaderTiming : public TIntermTraverser { -public: - RestrictVertexShaderTiming(TInfoSinkBase& sink) - : TIntermTraverser(true, false, false) - , mSink(sink) - , mNumErrors(0) {} - - void enforceRestrictions(TIntermNode* root) { root->traverse(this); } - int numErrors() { return mNumErrors; } - - void visitSymbol(TIntermSymbol *) override; - -private: - TInfoSinkBase& mSink; - int mNumErrors; -}; - -#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ diff --git a/chromium/third_party/angle/src/compiler/translator/util.cpp b/chromium/third_party/angle/src/compiler/translator/util.cpp index 01311372066..d6339a87345 100644 --- a/chromium/third_party/angle/src/compiler/translator/util.cpp +++ b/chromium/third_party/angle/src/compiler/translator/util.cpp @@ -278,6 +278,215 @@ InterpolationType GetInterpolationType(TQualifier qualifier) } } +TType GetShaderVariableBasicType(const sh::ShaderVariable &var) +{ + switch (var.type) + { + case GL_FLOAT: + return TType(EbtFloat); + case GL_FLOAT_VEC2: + return TType(EbtFloat, 2); + case GL_FLOAT_VEC3: + return TType(EbtFloat, 3); + case GL_FLOAT_VEC4: + return TType(EbtFloat, 4); + case GL_FLOAT_MAT2: + return TType(EbtFloat, 2, 2); + case GL_FLOAT_MAT3: + return TType(EbtFloat, 3, 3); + case GL_FLOAT_MAT4: + return TType(EbtFloat, 4, 4); + case GL_FLOAT_MAT2x3: + return TType(EbtFloat, 2, 3); + case GL_FLOAT_MAT2x4: + return TType(EbtFloat, 2, 4); + case GL_FLOAT_MAT3x2: + return TType(EbtFloat, 3, 2); + case GL_FLOAT_MAT3x4: + return TType(EbtFloat, 3, 4); + case GL_FLOAT_MAT4x2: + return TType(EbtFloat, 4, 2); + case GL_FLOAT_MAT4x3: + return TType(EbtFloat, 4, 3); + case GL_INT: + return TType(EbtInt); + case GL_INT_VEC2: + return TType(EbtInt, 2); + case GL_INT_VEC3: + return TType(EbtInt, 3); + case GL_INT_VEC4: + return TType(EbtInt, 4); + case GL_UNSIGNED_INT: + return TType(EbtUInt); + case GL_UNSIGNED_INT_VEC2: + return TType(EbtUInt, 2); + case GL_UNSIGNED_INT_VEC3: + return TType(EbtUInt, 3); + case GL_UNSIGNED_INT_VEC4: + return TType(EbtUInt, 4); + default: + UNREACHABLE(); + return TType(); + } +} + +TType GetShaderVariableType(const sh::ShaderVariable &var) +{ + TType type; + if (var.isStruct()) + { + TFieldList *fields = new TFieldList; + TSourceLoc loc; + for (const auto &field : var.fields) + { + TType *fieldType = new TType(GetShaderVariableType(field)); + fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc)); + } + TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields); + + type.setBasicType(EbtStruct); + type.setStruct(structure); + } + else + { + type = GetShaderVariableBasicType(var); + } + + if (var.isArray()) + { + type.setArraySize(var.elementCount()); + } + return type; +} + +TOperator TypeToConstructorOperator(const TType &type) +{ + switch (type.getBasicType()) + { + case EbtFloat: + if (type.isMatrix()) + { + switch (type.getCols()) + { + case 2: + switch (type.getRows()) + { + case 2: + return EOpConstructMat2; + case 3: + return EOpConstructMat2x3; + case 4: + return EOpConstructMat2x4; + default: + break; + } + break; + + case 3: + switch (type.getRows()) + { + case 2: + return EOpConstructMat3x2; + case 3: + return EOpConstructMat3; + case 4: + return EOpConstructMat3x4; + default: + break; + } + break; + + case 4: + switch (type.getRows()) + { + case 2: + return EOpConstructMat4x2; + case 3: + return EOpConstructMat4x3; + case 4: + return EOpConstructMat4; + default: + break; + } + break; + } + } + else + { + switch (type.getNominalSize()) + { + case 1: + return EOpConstructFloat; + case 2: + return EOpConstructVec2; + case 3: + return EOpConstructVec3; + case 4: + return EOpConstructVec4; + default: + break; + } + } + break; + + case EbtInt: + switch (type.getNominalSize()) + { + case 1: + return EOpConstructInt; + case 2: + return EOpConstructIVec2; + case 3: + return EOpConstructIVec3; + case 4: + return EOpConstructIVec4; + default: + break; + } + break; + + case EbtUInt: + switch (type.getNominalSize()) + { + case 1: + return EOpConstructUInt; + case 2: + return EOpConstructUVec2; + case 3: + return EOpConstructUVec3; + case 4: + return EOpConstructUVec4; + default: + break; + } + break; + + case EbtBool: + switch (type.getNominalSize()) + { + case 1: + return EOpConstructBool; + case 2: + return EOpConstructBVec2; + case 3: + return EOpConstructBVec3; + case 4: + return EOpConstructBVec4; + default: + break; + } + break; + + case EbtStruct: + return EOpConstructStruct; + + default: + break; + } + + return EOpNull; +} + GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable) : mSymbolTable(symbolTable) { @@ -324,7 +533,7 @@ void GetVariableTraverser::traverse(const TType &type, VarT variable; variable.name = name.c_str(); - variable.arraySize = static_cast<unsigned int>(type.getArraySize()); + variable.arraySize = type.getArraySize(); if (!structure) { @@ -357,4 +566,52 @@ template void GetVariableTraverser::traverse(const TType &, const TString &, std template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *); +// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier +bool CanBeInvariantESSL1(TQualifier qualifier) +{ + return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) || + IsBuiltinOutputVariable(qualifier) || + (IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing); +} + +// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier +// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier) +{ + return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut || + IsBuiltinOutputVariable(qualifier); +} + +bool IsBuiltinOutputVariable(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqPosition: + case EvqPointSize: + case EvqFragDepth: + case EvqFragDepthEXT: + case EvqFragColor: + case EvqSecondaryFragColorEXT: + case EvqFragData: + case EvqSecondaryFragDataEXT: + return true; + default: + break; + } + return false; +} + +bool IsBuiltinFragmentInputVariable(TQualifier qualifier) +{ + switch (qualifier) + { + case EvqFragCoord: + case EvqPointCoord: + case EvqFrontFacing: + return true; + default: + break; + } + return false; } +} // namespace sh diff --git a/chromium/third_party/angle/src/compiler/translator/util.h b/chromium/third_party/angle/src/compiler/translator/util.h index ea7a35a352a..4c1713a8a85 100644 --- a/chromium/third_party/angle/src/compiler/translator/util.h +++ b/chromium/third_party/angle/src/compiler/translator/util.h @@ -12,6 +12,7 @@ #include "angle_gl.h" #include <GLSLANG/ShaderLang.h> +#include "compiler/translator/Operator.h" #include "compiler/translator/Types.h" // strtof_clamp is like strtof but @@ -37,6 +38,11 @@ bool IsVarying(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier); TString ArrayString(const TType &type); +TType GetShaderVariableBasicType(const sh::ShaderVariable &var); +TType GetShaderVariableType(const sh::ShaderVariable &var); + +TOperator TypeToConstructorOperator(const TType &type); + class GetVariableTraverser : angle::NonCopyable { public: @@ -60,6 +66,10 @@ class GetVariableTraverser : angle::NonCopyable const TSymbolTable &mSymbolTable; }; +bool IsBuiltinOutputVariable(TQualifier qualifier); +bool IsBuiltinFragmentInputVariable(TQualifier qualifier); +bool CanBeInvariantESSL1(TQualifier qualifier); +bool CanBeInvariantESSL3OrGreater(TQualifier qualifier); } #endif // COMPILER_TRANSLATOR_UTIL_H_ |