summaryrefslogtreecommitdiff
path: root/chromium/third_party/angle/src/compiler/translator
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/angle/src/compiler/translator')
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.cpp10
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ASTMetadataHLSL.h6
-rw-r--r--chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.cpp59
-rw-r--r--chromium/third_party/angle/src/compiler/translator/AddAndTrueToLoopCondition.h20
-rw-r--r--chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.cpp77
-rw-r--r--chromium/third_party/angle/src/compiler/translator/AddDefaultReturnStatements.h22
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ArrayReturnValueToOutParameter.cpp14
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BaseTypes.h86
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp106
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BreakVariableAliasingInInnerLoops.h23
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp99
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h11
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp53
-rw-r--r--chromium/third_party/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h6
-rw-r--r--chromium/third_party/angle/src/compiler/translator/CallDAG.cpp107
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Compiler.cpp326
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Compiler.h64
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ConstantUnion.cpp590
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ConstantUnion.h368
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DeferGlobalInitializers.cpp8
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Diagnostics.cpp25
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Diagnostics.h7
-rw-r--r--chromium/third_party/angle/src/compiler/translator/DirectiveHandler.cpp3
-rw-r--r--chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.cpp141
-rw-r--r--chromium/third_party/angle/src/compiler/translator/EmulateGLFragColorBroadcast.h29
-rw-r--r--chromium/third_party/angle/src/compiler/translator/EmulatePrecision.cpp582
-rw-r--r--chromium/third_party/angle/src/compiler/translator/EmulatePrecision.h6
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.cpp154
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ExpandIntegerPowExpressions.h28
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Initialize.cpp266
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeVariables.cpp115
-rw-r--r--chromium/third_party/angle/src/compiler/translator/InitializeVariables.h42
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermNode.cpp2451
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermNode.h309
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.cpp115
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermNodePatternMatcher.h53
-rw-r--r--chromium/third_party/angle/src/compiler/translator/IntermTraverse.cpp97
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Intermediate.cpp209
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Intermediate.h39
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Operator.cpp30
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Operator.h5
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.cpp228
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputGLSLBase.h6
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputHLSL.cpp143
-rw-r--r--chromium/third_party/angle/src/compiler/translator/OutputHLSL.h21
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ParseContext.cpp2305
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ParseContext.h209
-rw-r--r--chromium/third_party/angle/src/compiler/translator/PoolAlloc.cpp94
-rw-r--r--chromium/third_party/angle/src/compiler/translator/PoolAlloc.h18
-rw-r--r--chromium/third_party/angle/src/compiler/translator/PruneEmptyDeclarations.cpp21
-rw-r--r--chromium/third_party/angle/src/compiler/translator/QualifierTypes.cpp646
-rw-r--r--chromium/third_party/angle/src/compiler/translator/QualifierTypes.h170
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RecordConstantPrecision.cpp2
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemoveDynamicIndexing.cpp44
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemovePow.cpp21
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp9
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RemoveSwitchFallThrough.h3
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RenameFunction.h36
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteDoWhile.cpp11
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteElseBlocks.cpp48
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.cpp171
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteTexelFetchOffset.h30
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp112
-rw-r--r--chromium/third_party/angle/src/compiler/translator/RewriteUnaryMinusOperatorInt.h20
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp28
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SeparateArrayInitialization.cpp6
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SeparateExpressionsReturningArrays.cpp93
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ShaderLang.cpp66
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ShaderVars.cpp89
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.cpp282
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SimplifyLoopConditions.h23
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.cpp160
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SplitSequenceOperator.h24
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SymbolTable.cpp8
-rw-r--r--chromium/third_party/angle/src/compiler/translator/SymbolTable.h71
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.cpp61
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TextureFunctionHLSL.h4
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorESSL.cpp31
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorESSL.h5
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp82
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorGLSL.h7
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.cpp69
-rw-r--r--chromium/third_party/angle/src/compiler/translator/TranslatorHLSL.h5
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Types.cpp158
-rw-r--r--chromium/third_party/angle/src/compiler/translator/Types.h163
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp15
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UnfoldShortCircuitToIf.cpp352
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UniformHLSL.cpp8
-rw-r--r--chromium/third_party/angle/src/compiler/translator/UtilsHLSL.cpp2
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateOutputs.cpp2
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateSwitch.cpp10
-rw-r--r--chromium/third_party/angle/src/compiler/translator/ValidateSwitch.h3
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariableInfo.cpp123
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariableInfo.h11
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariablePacker.cpp20
-rw-r--r--chromium/third_party/angle/src/compiler/translator/VariablePacker.h47
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.cpp95
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraph.h199
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.cpp255
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h199
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.cpp64
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h31
-rw-r--r--chromium/third_party/angle/src/compiler/translator/depgraph/DependencyGraphTraverse.cpp69
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang.l5
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang.y584
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_lex.cpp5
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_tab.cpp1925
-rw-r--r--chromium/third_party/angle/src/compiler/translator/glslang_tab.h3
-rw-r--r--chromium/third_party/angle/src/compiler/translator/intermOut.cpp52
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp130
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h39
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.cpp17
-rw-r--r--chromium/third_party/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h32
-rw-r--r--chromium/third_party/angle/src/compiler/translator/util.cpp259
-rw-r--r--chromium/third_party/angle/src/compiler/translator/util.h10
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 &parameter, FloatTypeUnaryFunc builtinFunc,
- TInfoSink &infoSink, TConstantUnion *result) const
+void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
+ 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 &parameter, FloatTypeUnaryFunc builtinFunc, TInfoSink &infoSink, TConstantUnion *result) const;
+ void foldFloatTypeUnary(const TConstantUnion &parameter,
+ 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 &param = 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 &currentQualifier =
+ 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 &map;
#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_