summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/compiler/translator/ParseContext.cpp
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-07-18 08:24:24 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-07-18 08:24:24 +0200
commitfc61780b35af913801d72086456f493f63197da6 (patch)
treef85891288a7bd988da9f0f15ae64e5c63f00d493 /gfx/angle/src/compiler/translator/ParseContext.cpp
parent69f7f9e5f1475891ce11cc4f431692f965b0cd30 (diff)
parent50d3e596bbe89c95615f96eb71f6bc5be737a1db (diff)
downloadUXP-fc61780b35af913801d72086456f493f63197da6.tar
UXP-fc61780b35af913801d72086456f493f63197da6.tar.gz
UXP-fc61780b35af913801d72086456f493f63197da6.tar.lz
UXP-fc61780b35af913801d72086456f493f63197da6.tar.xz
UXP-fc61780b35af913801d72086456f493f63197da6.zip
Merge commit '50d3e596bbe89c95615f96eb71f6bc5be737a1db' into Basilisk-releasev2018.07.18
# Conflicts: # browser/app/profile/firefox.js # browser/components/preferences/jar.mn
Diffstat (limited to 'gfx/angle/src/compiler/translator/ParseContext.cpp')
-rwxr-xr-xgfx/angle/src/compiler/translator/ParseContext.cpp1775
1 files changed, 717 insertions, 1058 deletions
diff --git a/gfx/angle/src/compiler/translator/ParseContext.cpp b/gfx/angle/src/compiler/translator/ParseContext.cpp
index 4ad597c4f..5e15eea24 100755
--- a/gfx/angle/src/compiler/translator/ParseContext.cpp
+++ b/gfx/angle/src/compiler/translator/ParseContext.cpp
@@ -16,102 +16,12 @@
#include "compiler/translator/ValidateGlobalInitializer.h"
#include "compiler/translator/util.h"
-namespace sh
-{
-
///////////////////////////////////////////////////////////////////////
//
// Sub- vector and matrix fields
//
////////////////////////////////////////////////////////////////////////
-namespace
-{
-
-const int kWebGLMaxStructNesting = 4;
-
-bool ContainsSampler(const TType &type)
-{
- if (IsSampler(type.getBasicType()))
- return true;
-
- if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
- {
- const TFieldList &fields = type.getStruct()->fields();
- for (unsigned int i = 0; i < fields.size(); ++i)
- {
- if (ContainsSampler(*fields[i]->type()))
- return true;
- }
- }
-
- return false;
-}
-
-bool ContainsImage(const TType &type)
-{
- if (IsImage(type.getBasicType()))
- return true;
-
- if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
- {
- const TFieldList &fields = type.getStruct()->fields();
- for (unsigned int i = 0; i < fields.size(); ++i)
- {
- if (ContainsImage(*fields[i]->type()))
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace
-
-TParseContext::TParseContext(TSymbolTable &symt,
- TExtensionBehavior &ext,
- sh::GLenum type,
- ShShaderSpec spec,
- ShCompileOptions options,
- bool checksPrecErrors,
- TInfoSink &is,
- const ShBuiltInResources &resources)
- : intermediate(),
- symbolTable(symt),
- mDeferredSingleDeclarationErrorCheck(false),
- mShaderType(type),
- mShaderSpec(spec),
- mCompileOptions(options),
- mShaderVersion(100),
- mTreeRoot(nullptr),
- mLoopNestingLevel(0),
- mStructNestingLevel(0),
- mSwitchNestingLevel(0),
- mCurrentFunctionType(nullptr),
- mFunctionReturnsValue(false),
- mChecksPrecisionErrors(checksPrecErrors),
- mFragmentPrecisionHighOnESSL1(false),
- mDefaultMatrixPacking(EmpColumnMajor),
- mDefaultBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared),
- mDiagnostics(is),
- mDirectiveHandler(ext,
- mDiagnostics,
- mShaderVersion,
- mShaderType,
- resources.WEBGL_debug_shader_precision == 1),
- mPreprocessor(&mDiagnostics, &mDirectiveHandler),
- mScanner(nullptr),
- mUsesFragData(false),
- mUsesFragColor(false),
- mUsesSecondaryOutputs(false),
- mMinProgramTexelOffset(resources.MinProgramTexelOffset),
- mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
- mComputeShaderLocalSizeDeclared(false),
- mDeclaringFunction(false)
-{
- mComputeShaderLocalSize.fill(-1);
-}
-
//
// Look at a '.' field selector string and change it into offsets
// for a vector.
@@ -303,12 +213,6 @@ void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
{
if (!mChecksPrecisionErrors)
return;
-
- if (precision != EbpUndefined && !SupportsPrecision(type))
- {
- error(line, "illegal type for precision qualifier", getBasicString(type));
- }
-
if (precision == EbpUndefined)
{
switch (type)
@@ -327,11 +231,6 @@ void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
error(line, "No precision specified (sampler)", "");
return;
}
- if (IsImage(type))
- {
- error(line, "No precision specified (image)", "");
- return;
- }
}
}
}
@@ -342,18 +241,6 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
{
TIntermSymbol *symNode = node->getAsSymbolNode();
TIntermBinary *binaryNode = node->getAsBinaryNode();
- TIntermSwizzle *swizzleNode = node->getAsSwizzleNode();
-
- if (swizzleNode)
- {
- 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)
{
@@ -364,10 +251,34 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
case EOpIndexDirectStruct:
case EOpIndexDirectInterfaceBlock:
return checkCanBeLValue(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ {
+ bool ok = checkCanBeLValue(line, op, binaryNode->getLeft());
+ if (ok)
+ {
+ int offsetCount[4] = {0, 0, 0, 0};
+
+ TIntermAggregate *swizzleOffsets = binaryNode->getRight()->getAsAggregate();
+
+ for (const auto &offset : *swizzleOffsets->getSequence())
+ {
+ int value = offset->getAsTyped()->getAsConstantUnion()->getIConst(0);
+ offsetCount[value]++;
+ if (offsetCount[value] > 1)
+ {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+ return false;
+ }
+ }
+ }
+
+ return ok;
+ }
default:
break;
}
error(line, " l-value required", op);
+
return false;
}
@@ -441,10 +352,6 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
{
message = "can't modify a sampler";
}
- if (IsImage(node->getBasicType()))
- {
- message = "can't modify an image";
- }
}
if (message == 0 && binaryNode == 0 && symNode == 0)
@@ -528,7 +435,7 @@ bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &id
error(line, reservedErrMsg, "gl_");
return false;
}
- if (sh::IsWebGLBasedSpec(mShaderSpec))
+ if (IsWebGLBasedSpec(mShaderSpec))
{
if (identifier.compare(0, 6, "webgl_") == 0)
{
@@ -540,6 +447,11 @@ bool TParseContext::checkIsNotReserved(const TSourceLoc &line, const TString &id
error(line, reservedErrMsg, "_webgl_");
return false;
}
+ if (mShaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0)
+ {
+ error(line, reservedErrMsg, "css_");
+ return false;
+ }
}
if (identifier.find("__") != TString::npos)
{
@@ -675,11 +587,6 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
error(line, "cannot convert a sampler", "constructor");
return false;
}
- if (op != EOpConstructStruct && IsImage(argTyped->getBasicType()))
- {
- error(line, "cannot convert an image", "constructor");
- return false;
- }
if (argTyped->getBasicType() == EbtVoid)
{
error(line, "cannot convert a void", "constructor");
@@ -754,19 +661,19 @@ void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TIntermTyped
// or not.
void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType)
{
- if (pType.getBasicType() != EbtBool || pType.isAggregate())
+ if (pType.type != EbtBool || pType.isAggregate())
{
error(line, "boolean expression expected", "");
}
}
bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
- const TTypeSpecifierNonArray &pType,
+ const TPublicType &pType,
const char *reason)
{
if (pType.type == EbtStruct)
{
- if (ContainsSampler(*pType.userDef))
+ if (containsSampler(*pType.userDef))
{
error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
return false;
@@ -783,31 +690,6 @@ bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
return true;
}
-bool TParseContext::checkIsNotImage(const TSourceLoc &line,
- const TTypeSpecifierNonArray &pType,
- const char *reason)
-{
- if (pType.type == EbtStruct)
- {
- if (ContainsImage(*pType.userDef))
- {
- error(line, reason, getBasicString(pType.type), "(structure contains an image)");
-
- return false;
- }
-
- return true;
- }
- else if (IsImage(pType.type))
- {
- error(line, reason, getBasicString(pType.type));
-
- return false;
- }
-
- return true;
-}
-
void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line,
const TPublicType &pType)
{
@@ -828,34 +710,33 @@ void TParseContext::checkLocationIsNotSpecified(const TSourceLoc &location,
}
}
-void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
- TQualifier qualifier,
- const TType &type)
-{
- checkOutParameterIsNotSampler(line, qualifier, type);
- checkOutParameterIsNotImage(line, qualifier, type);
-}
-
void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type)
{
- ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
- if (IsSampler(type.getBasicType()))
+ if ((qualifier == EvqOut || qualifier == EvqInOut) && type.getBasicType() != EbtStruct &&
+ IsSampler(type.getBasicType()))
{
error(line, "samplers cannot be output parameters", type.getBasicString());
}
}
-void TParseContext::checkOutParameterIsNotImage(const TSourceLoc &line,
- TQualifier qualifier,
- const TType &type)
+bool TParseContext::containsSampler(const TType &type)
{
- ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
- if (IsImage(type.getBasicType()))
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
{
- error(line, "images cannot be output parameters", type.getBasicString());
+ const TFieldList &fields = type.getStruct()->fields();
+ for (unsigned int i = 0; i < fields.size(); ++i)
+ {
+ if (containsSampler(*fields[i]->type()))
+ return true;
+ }
}
+
+ return false;
}
// Do size checking for an array type's size.
@@ -942,7 +823,7 @@ bool TParseContext::checkIsValidTypeForArray(const TSourceLoc &line, const TPubl
// In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
// In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section
// 4.3.4).
- if (mShaderVersion >= 300 && elementType.getBasicType() == EbtStruct &&
+ if (mShaderVersion >= 300 && elementType.type == EbtStruct &&
sh::IsVarying(elementType.qualifier))
{
error(line, "cannot declare arrays of structs of this qualifier",
@@ -1047,33 +928,27 @@ bool TParseContext::declareVariable(const TSourceLoc &line,
return true;
}
-void TParseContext::checkIsParameterQualifierValid(
- const TSourceLoc &line,
- const TTypeQualifierBuilder &typeQualifierBuilder,
- TType *type)
+void TParseContext::checkIsParameterQualifierValid(const TSourceLoc &line,
+ TQualifier qualifier,
+ TQualifier paramQualifier,
+ TType *type)
{
- TTypeQualifier typeQualifier = typeQualifierBuilder.getParameterTypeQualifier(&mDiagnostics);
-
- if (typeQualifier.qualifier == EvqOut || typeQualifier.qualifier == EvqInOut)
+ if (qualifier != EvqConst && qualifier != EvqTemporary)
{
- checkOutParameterIsNotOpaqueType(line, typeQualifier.qualifier, *type);
- }
-
- if (!IsImage(type->getBasicType()))
- {
- checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, line);
+ error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
+ return;
}
- else
+ if (qualifier == EvqConst && paramQualifier != EvqIn)
{
- type->setMemoryQualifier(typeQualifier.memoryQualifier);
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier),
+ getQualifierString(paramQualifier));
+ return;
}
- type->setQualifier(typeQualifier.qualifier);
-
- if (typeQualifier.precision != EbpUndefined)
- {
- type->setPrecision(typeQualifier.precision);
- }
+ if (qualifier == EvqConst)
+ type->setQualifier(EvqConstReadOnly);
+ else
+ type->setQualifier(paramQualifier);
}
bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &extension)
@@ -1113,7 +988,7 @@ void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
case EvqVertexIn:
case EvqFragmentOut:
case EvqComputeIn:
- if (publicType.getBasicType() == EbtStruct)
+ if (publicType.type == EbtStruct)
{
error(identifierLocation, "cannot be used with a structure",
getQualifierString(publicType.qualifier));
@@ -1125,14 +1000,7 @@ void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
}
if (publicType.qualifier != EvqUniform &&
- !checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
- "samplers must be uniform"))
- {
- return;
- }
- if (publicType.qualifier != EvqUniform &&
- !checkIsNotImage(identifierLocation, publicType.typeSpecifierNonArray,
- "images must be uniform"))
+ !checkIsNotSampler(identifierLocation, publicType, "samplers must be uniform"))
{
return;
}
@@ -1160,89 +1028,6 @@ void TParseContext::singleDeclarationErrorCheck(const TPublicType &publicType,
{
checkLocationIsNotSpecified(identifierLocation, publicType.layoutQualifier);
}
-
- if (IsImage(publicType.getBasicType()))
- {
-
- switch (layoutQualifier.imageInternalFormat)
- {
- case EiifRGBA32F:
- case EiifRGBA16F:
- case EiifR32F:
- case EiifRGBA8:
- case EiifRGBA8_SNORM:
- if (!IsFloatImage(publicType.getBasicType()))
- {
- error(identifierLocation,
- "internal image format requires a floating image type",
- getBasicString(publicType.getBasicType()));
- return;
- }
- break;
- case EiifRGBA32I:
- case EiifRGBA16I:
- case EiifRGBA8I:
- case EiifR32I:
- if (!IsIntegerImage(publicType.getBasicType()))
- {
- error(identifierLocation,
- "internal image format requires an integer image type",
- getBasicString(publicType.getBasicType()));
- return;
- }
- break;
- case EiifRGBA32UI:
- case EiifRGBA16UI:
- case EiifRGBA8UI:
- case EiifR32UI:
- if (!IsUnsignedImage(publicType.getBasicType()))
- {
- error(identifierLocation,
- "internal image format requires an unsigned image type",
- getBasicString(publicType.getBasicType()));
- return;
- }
- break;
- case EiifUnspecified:
- error(identifierLocation, "layout qualifier", "No image internal format specified");
- return;
- default:
- error(identifierLocation, "layout qualifier", "unrecognized token");
- return;
- }
-
- // GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
- switch (layoutQualifier.imageInternalFormat)
- {
- case EiifR32F:
- case EiifR32I:
- case EiifR32UI:
- break;
- default:
- if (!publicType.memoryQualifier.readonly && !publicType.memoryQualifier.writeonly)
- {
- error(identifierLocation, "layout qualifier",
- "Except for images with the r32f, r32i and r32ui format qualifiers, "
- "image variables must be qualified readonly and/or writeonly");
- return;
- }
- break;
- }
- }
- else
- {
-
- if (!checkInternalFormatIsNotSpecified(identifierLocation,
- layoutQualifier.imageInternalFormat))
- {
- return;
- }
-
- if (!checkIsMemoryQualifierNotSpecified(publicType.memoryQualifier, identifierLocation))
- {
- return;
- }
- }
}
void TParseContext::checkLayoutQualifierSupported(const TSourceLoc &location,
@@ -1273,18 +1058,6 @@ bool TParseContext::checkWorkGroupSizeIsNotSpecified(const TSourceLoc &location,
return true;
}
-bool TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location,
- TLayoutImageInternalFormat internalFormat)
-{
- if (internalFormat != EiifUnspecified)
- {
- error(location, "invalid layout qualifier:", getImageInternalFormatString(internalFormat),
- "only valid when used with images");
- return false;
- }
- return true;
-}
-
void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
TIntermAggregate *fnCall)
{
@@ -1304,27 +1077,12 @@ void TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate,
}
}
-void TParseContext::checkInvariantVariableQualifier(bool invariant,
- const TQualifier qualifier,
- const TSourceLoc &invariantLocation)
+void TParseContext::checkInvariantIsOutVariableES3(const TQualifier qualifier,
+ const TSourceLoc &invariantLocation)
{
- 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
+ if (!sh::IsVaryingOut(qualifier) && qualifier != EvqFragmentOut)
{
- if (!sh::CanBeInvariantESSL3OrGreater(qualifier))
- {
- error(invariantLocation, "Cannot be qualified as invariant.", "invariant");
- }
+ error(invariantLocation, "Only out variables can be invariant.", "invariant");
}
}
@@ -1522,26 +1280,15 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
const TString &identifier,
const TPublicType &pType,
TIntermTyped *initializer,
- TIntermBinary **initNode)
+ TIntermNode **intermNode)
{
- ASSERT(initNode != nullptr);
- ASSERT(*initNode == nullptr);
+ ASSERT(intermNode != nullptr);
TType type = TType(pType);
TVariable *variable = nullptr;
if (type.isUnsizedArray())
{
- // We have not checked yet whether the initializer actually is an array or not.
- if (initializer->isArray())
- {
- type.setArraySize(initializer->getArraySize());
- }
- else
- {
- // Having a non-array initializer for an unsized array will result in an error later,
- // so we don't generate an error message here.
- type.setArraySize(1u);
- }
+ type.setArraySize(initializer->getArraySize());
}
if (!declareVariable(line, identifier, type, &variable))
{
@@ -1607,7 +1354,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
if (initializer->getAsConstantUnion())
{
variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
- *initNode = nullptr;
+ *intermNode = nullptr;
return false;
}
else if (initializer->getAsSymbolNode())
@@ -1620,7 +1367,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
if (constArray)
{
variable->shareConstPointer(constArray);
- *initNode = nullptr;
+ *intermNode = nullptr;
return false;
}
}
@@ -1628,8 +1375,8 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
TIntermSymbol *intermSymbol = intermediate.addSymbol(
variable->getUniqueId(), variable->getName(), variable->getType(), line);
- *initNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
- if (*initNode == nullptr)
+ *intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (*intermNode == nullptr)
{
assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
return true;
@@ -1638,80 +1385,51 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
return false;
}
-void TParseContext::addFullySpecifiedType(TPublicType *typeSpecifier)
-{
- checkPrecisionSpecified(typeSpecifier->getLine(), typeSpecifier->precision,
- typeSpecifier->getBasicType());
-
- if (mShaderVersion < 300 && typeSpecifier->array)
- {
- error(typeSpecifier->getLine(), "not supported", "first-class array");
- typeSpecifier->clearArrayness();
- }
-}
-
-TPublicType TParseContext::addFullySpecifiedType(const TTypeQualifierBuilder &typeQualifierBuilder,
+TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier,
+ bool invariant,
+ TLayoutQualifier layoutQualifier,
const TPublicType &typeSpecifier)
{
- TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
-
TPublicType returnType = typeSpecifier;
- returnType.qualifier = typeQualifier.qualifier;
- returnType.invariant = typeQualifier.invariant;
- returnType.layoutQualifier = typeQualifier.layoutQualifier;
- returnType.memoryQualifier = typeQualifier.memoryQualifier;
- returnType.precision = typeSpecifier.precision;
-
- if (typeQualifier.precision != EbpUndefined)
- {
- returnType.precision = typeQualifier.precision;
- }
+ returnType.qualifier = qualifier;
+ returnType.invariant = invariant;
+ returnType.layoutQualifier = layoutQualifier;
- checkPrecisionSpecified(typeSpecifier.getLine(), returnType.precision,
- typeSpecifier.getBasicType());
-
- checkInvariantVariableQualifier(returnType.invariant, returnType.qualifier,
- typeSpecifier.getLine());
-
- checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), returnType.layoutQualifier);
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.line, layoutQualifier);
if (mShaderVersion < 300)
{
if (typeSpecifier.array)
{
- error(typeSpecifier.getLine(), "not supported", "first-class array");
+ error(typeSpecifier.line, "not supported", "first-class array");
returnType.clearArrayness();
}
- if (returnType.qualifier == EvqAttribute &&
- (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
+ if (qualifier == EvqAttribute &&
+ (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
- error(typeSpecifier.getLine(), "cannot be bool or int",
- getQualifierString(returnType.qualifier));
+ error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
}
- if ((returnType.qualifier == EvqVaryingIn || returnType.qualifier == EvqVaryingOut) &&
- (typeSpecifier.getBasicType() == EbtBool || typeSpecifier.getBasicType() == EbtInt))
+ if ((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
+ (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
- error(typeSpecifier.getLine(), "cannot be bool or int",
- getQualifierString(returnType.qualifier));
+ error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
}
}
else
{
- if (!returnType.layoutQualifier.isEmpty())
+ if (!layoutQualifier.isEmpty())
{
- checkIsAtGlobalLevel(typeSpecifier.getLine(), "layout");
+ checkIsAtGlobalLevel(typeSpecifier.line, "layout");
}
- if (sh::IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn ||
- returnType.qualifier == EvqFragmentOut)
+ if (sh::IsVarying(qualifier) || qualifier == EvqVertexIn || qualifier == EvqFragmentOut)
{
- checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier,
- typeSpecifier.getLine());
+ checkInputOutputTypeIsValidES3(qualifier, typeSpecifier, typeSpecifier.line);
}
- if (returnType.qualifier == EvqComputeIn)
+ if (qualifier == EvqComputeIn)
{
- error(typeSpecifier.getLine(), "'in' can be only used to specify the local group size",
+ error(typeSpecifier.line, "'in' can be only used to specify the local group size",
"in");
}
}
@@ -1724,7 +1442,7 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
const TSourceLoc &qualifierLocation)
{
// An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
- if (type.getBasicType() == EbtBool)
+ if (type.type == EbtBool)
{
error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
}
@@ -1742,7 +1460,7 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
return;
case EvqFragmentOut:
// ESSL 3.00 section 4.3.6
- if (type.typeSpecifierNonArray.isMatrix())
+ if (type.isMatrix())
{
error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
}
@@ -1755,15 +1473,15 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
// Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
// restrictions.
bool typeContainsIntegers =
- (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt ||
- type.isStructureContainingType(EbtInt) || type.isStructureContainingType(EbtUInt));
+ (type.type == EbtInt || type.type == EbtUInt || type.isStructureContainingType(EbtInt) ||
+ type.isStructureContainingType(EbtUInt));
if (typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
{
error(qualifierLocation, "must use 'flat' interpolation here",
getQualifierString(qualifier));
}
- if (type.getBasicType() == EbtStruct)
+ if (type.type == EbtStruct)
{
// ESSL 3.00 sections 4.3.4 and 4.3.6.
// These restrictions are only implied by the ESSL 3.00 spec, but
@@ -1791,57 +1509,9 @@ void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
}
}
-void TParseContext::checkLocalVariableConstStorageQualifier(const TQualifierWrapperBase &qualifier)
-{
- if (qualifier.getType() == QtStorage)
- {
- const TStorageQualifierWrapper &storageQualifier =
- static_cast<const TStorageQualifierWrapper &>(qualifier);
- if (!declaringFunction() && storageQualifier.getQualifier() != EvqConst &&
- !symbolTable.atGlobalLevel())
- {
- error(storageQualifier.getLine(),
- "Local variables can only use the const storage qualifier.",
- storageQualifier.getQualifierString().c_str());
- }
- }
-}
-
-bool TParseContext::checkIsMemoryQualifierNotSpecified(const TMemoryQualifier &memoryQualifier,
- const TSourceLoc &location)
-{
- if (memoryQualifier.readonly)
- {
- error(location, "Only allowed with images.", "readonly");
- return false;
- }
- if (memoryQualifier.writeonly)
- {
- error(location, "Only allowed with images.", "writeonly");
- return false;
- }
- if (memoryQualifier.coherent)
- {
- error(location, "Only allowed with images.", "coherent");
- return false;
- }
- if (memoryQualifier.restrictQualifier)
- {
- error(location, "Only allowed with images.", "restrict");
- return false;
- }
- if (memoryQualifier.volatileQualifier)
- {
- error(location, "Only allowed with images.", "volatile");
- return false;
- }
- return true;
-}
-
-TIntermDeclaration *TParseContext::parseSingleDeclaration(
- TPublicType &publicType,
- const TSourceLoc &identifierOrTypeLocation,
- const TString &identifier)
+TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierOrTypeLocation,
+ const TString &identifier)
{
TType type(publicType);
if ((mCompileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) &&
@@ -1877,9 +1547,6 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
mDeferredSingleDeclarationErrorCheck = emptyDeclaration;
- TIntermDeclaration *declaration = new TIntermDeclaration();
- declaration->setLine(identifierOrTypeLocation);
-
if (emptyDeclaration)
{
if (publicType.isUnsizedArray())
@@ -1900,23 +1567,17 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
declareVariable(identifierOrTypeLocation, identifier, type, &variable);
if (variable && symbol)
- {
symbol->setId(variable->getUniqueId());
- }
}
- // We append the symbol even if the declaration is empty, mainly because of struct declarations
- // that may just declare a type.
- declaration->appendDeclarator(symbol);
-
- return declaration;
+ return intermediate.makeAggregate(symbol, identifierOrTypeLocation);
}
-TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- const TSourceLoc &indexLocation,
- TIntermTyped *indexExpression)
+TIntermAggregate *TParseContext::parseSingleArrayDeclaration(TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression)
{
mDeferredSingleDeclarationErrorCheck = false;
@@ -1936,44 +1597,38 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &publ
TVariable *variable = nullptr;
declareVariable(identifierLocation, identifier, arrayType, &variable);
- TIntermDeclaration *declaration = new TIntermDeclaration();
- declaration->setLine(identifierLocation);
-
TIntermSymbol *symbol = intermediate.addSymbol(0, identifier, arrayType, identifierLocation);
if (variable && symbol)
- {
symbol->setId(variable->getUniqueId());
- declaration->appendDeclarator(symbol);
- }
- return declaration;
+ return intermediate.makeAggregate(symbol, identifierLocation);
}
-TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- const TSourceLoc &initLocation,
- TIntermTyped *initializer)
+TIntermAggregate *TParseContext::parseSingleInitDeclaration(const TPublicType &publicType,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
{
mDeferredSingleDeclarationErrorCheck = false;
singleDeclarationErrorCheck(publicType, identifierLocation);
- TIntermDeclaration *declaration = new TIntermDeclaration();
- declaration->setLine(identifierLocation);
-
- TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
- if (initNode)
- {
- declaration->appendDeclarator(initNode);
- }
+ //
+ // Build intermediate representation
+ //
+ return intermNode ? intermediate.makeAggregate(intermNode, initLocation) : nullptr;
+ }
+ else
+ {
+ return nullptr;
}
- return declaration;
}
-TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
+TIntermAggregate *TParseContext::parseSingleArrayInitDeclaration(
TPublicType &publicType,
const TSourceLoc &identifierLocation,
const TString &identifier,
@@ -2001,81 +1656,58 @@ TIntermDeclaration *TParseContext::parseSingleArrayInitDeclaration(
// This ensures useless error messages regarding the variable's non-arrayness won't follow.
arrayType.setArraySize(size);
- TIntermDeclaration *declaration = new TIntermDeclaration();
- declaration->setLine(identifierLocation);
-
// initNode will correspond to the whole of "type b[n] = initializer".
- TIntermBinary *initNode = nullptr;
+ TIntermNode *initNode = nullptr;
if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
- if (initNode)
- {
- declaration->appendDeclarator(initNode);
- }
+ return initNode ? intermediate.makeAggregate(initNode, initLocation) : nullptr;
}
-
- return declaration;
-}
-
-TIntermAggregate *TParseContext::parseInvariantDeclaration(
- const TTypeQualifierBuilder &typeQualifierBuilder,
- const TSourceLoc &identifierLoc,
- const TString *identifier,
- const TSymbol *symbol)
-{
- TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
-
- if (!typeQualifier.invariant)
+ else
{
- error(identifierLoc, "Expected invariant", identifier->c_str());
return nullptr;
}
- if (!checkIsAtGlobalLevel(identifierLoc, "invariant varying"))
- {
+}
+
+TIntermAggregate *TParseContext::parseInvariantDeclaration(const TSourceLoc &invariantLoc,
+ const TSourceLoc &identifierLoc,
+ const TString *identifier,
+ const TSymbol *symbol)
+{
+ // invariant declaration
+ if (!checkIsAtGlobalLevel(invariantLoc, "invariant varying"))
return nullptr;
- }
+
if (!symbol)
{
error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str());
return nullptr;
}
- if (!IsQualifierUnspecified(typeQualifier.qualifier))
- {
- error(identifierLoc, "invariant declaration specifies qualifier",
- getQualifierString(typeQualifier.qualifier));
- }
- if (typeQualifier.precision != EbpUndefined)
- {
- error(identifierLoc, "invariant declaration specifies precision",
- getPrecisionString(typeQualifier.precision));
- }
- if (!typeQualifier.layoutQualifier.isEmpty())
+ else
{
- 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);
- checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
-
- symbolTable.addInvariantVarying(std::string(identifier->c_str()));
-
- TIntermSymbol *intermSymbol =
- intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
+ const TString kGlFrontFacing("gl_FrontFacing");
+ if (*identifier == kGlFrontFacing)
+ {
+ error(identifierLoc, "identifier should not be declared as invariant",
+ identifier->c_str());
+ return nullptr;
+ }
+ symbolTable.addInvariantVarying(std::string(identifier->c_str()));
+ const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol);
+ ASSERT(variable);
+ const TType &type = variable->getType();
+ TIntermSymbol *intermSymbol =
+ intermediate.addSymbol(variable->getUniqueId(), *identifier, type, identifierLoc);
- TIntermAggregate *aggregate = TIntermediate::MakeAggregate(intermSymbol, identifierLoc);
- aggregate->setOp(EOpInvariantDeclaration);
- return aggregate;
+ TIntermAggregate *aggregate = intermediate.makeAggregate(intermSymbol, identifierLoc);
+ aggregate->setOp(EOpInvariantDeclaration);
+ return aggregate;
+ }
}
-void TParseContext::parseDeclarator(TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- TIntermDeclaration *declarationOut)
+TIntermAggregate *TParseContext::parseDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
// not performed.
@@ -2095,18 +1727,17 @@ void TParseContext::parseDeclarator(TPublicType &publicType,
TIntermSymbol *symbol =
intermediate.addSymbol(0, identifier, TType(publicType), identifierLocation);
if (variable && symbol)
- {
symbol->setId(variable->getUniqueId());
- declarationOut->appendDeclarator(symbol);
- }
+
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
-void TParseContext::parseArrayDeclarator(TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- const TSourceLoc &arrayLocation,
- TIntermTyped *indexExpression,
- TIntermDeclaration *declarationOut)
+TIntermAggregate *TParseContext::parseArrayDeclarator(TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &arrayLocation,
+ TIntermTyped *indexExpression)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
// not performed.
@@ -2134,16 +1765,18 @@ void TParseContext::parseArrayDeclarator(TPublicType &publicType,
if (variable && symbol)
symbol->setId(variable->getUniqueId());
- declarationOut->appendDeclarator(symbol);
+ return intermediate.growAggregate(aggregateDeclaration, symbol, identifierLocation);
}
+
+ return nullptr;
}
-void TParseContext::parseInitDeclarator(const TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- const TSourceLoc &initLocation,
- TIntermTyped *initializer,
- TIntermDeclaration *declarationOut)
+TIntermAggregate *TParseContext::parseInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
// not performed.
@@ -2155,27 +1788,35 @@ void TParseContext::parseInitDeclarator(const TPublicType &publicType,
checkDeclaratorLocationIsNotSpecified(identifierLocation, publicType);
- TIntermBinary *initNode = nullptr;
- if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &initNode))
+ TIntermNode *intermNode = nullptr;
+ if (!executeInitializer(identifierLocation, identifier, publicType, initializer, &intermNode))
{
//
// build the intermediate representation
//
- if (initNode)
+ if (intermNode)
{
- declarationOut->appendDeclarator(initNode);
+ return intermediate.growAggregate(aggregateDeclaration, intermNode, initLocation);
}
+ else
+ {
+ return aggregateDeclaration;
+ }
+ }
+ else
+ {
+ return nullptr;
}
}
-void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
- const TSourceLoc &identifierLocation,
- const TString &identifier,
- const TSourceLoc &indexLocation,
- TIntermTyped *indexExpression,
- const TSourceLoc &initLocation,
- TIntermTyped *initializer,
- TIntermDeclaration *declarationOut)
+TIntermAggregate *TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
+ TIntermAggregate *aggregateDeclaration,
+ const TSourceLoc &identifierLocation,
+ const TString &identifier,
+ const TSourceLoc &indexLocation,
+ TIntermTyped *indexExpression,
+ const TSourceLoc &initLocation,
+ TIntermTyped *initializer)
{
// If the declaration starting this declarator list was empty (example: int,), some checks were
// not performed.
@@ -2203,24 +1844,28 @@ void TParseContext::parseArrayInitDeclarator(const TPublicType &publicType,
arrayType.setArraySize(size);
// initNode will correspond to the whole of "b[n] = initializer".
- TIntermBinary *initNode = nullptr;
+ TIntermNode *initNode = nullptr;
if (!executeInitializer(identifierLocation, identifier, arrayType, initializer, &initNode))
{
if (initNode)
{
- declarationOut->appendDeclarator(initNode);
+ return intermediate.growAggregate(aggregateDeclaration, initNode, initLocation);
+ }
+ else
+ {
+ return aggregateDeclaration;
}
}
+ else
+ {
+ return nullptr;
+ }
}
-void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
+void TParseContext::parseGlobalLayoutQualifier(const TPublicType &typeQualifier)
{
- TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
- checkInvariantVariableQualifier(typeQualifier.invariant, typeQualifier.qualifier,
- typeQualifier.line);
-
// It should never be the case, but some strange parser errors can send us here.
if (layoutQualifier.isEmpty())
{
@@ -2234,10 +1879,6 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
return;
}
- checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
-
- checkInternalFormatIsNotSpecified(typeQualifier.line, layoutQualifier.imageInternalFormat);
-
if (typeQualifier.qualifier == EvqComputeIn)
{
if (mComputeShaderLocalSizeDeclared &&
@@ -2325,31 +1966,30 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
}
}
-TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &parsedFunction,
+TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction &function,
const TSourceLoc &location)
{
- // Note: function found from the symbol table could be the same as parsedFunction if this is the
- // first declaration. Either way the instance in the symbol table is used to track whether the
- // function is declared multiple times.
- TFunction *function = static_cast<TFunction *>(
- symbolTable.find(parsedFunction.getMangledName(), getShaderVersion()));
- if (function->hasPrototypeDeclaration() && mShaderVersion == 100)
+ // Note: symbolTableFunction could be the same as function if this is the first declaration.
+ // Either way the instance in the symbol table is used to track whether the function is declared
+ // multiple times.
+ TFunction *symbolTableFunction =
+ static_cast<TFunction *>(symbolTable.find(function.getMangledName(), getShaderVersion()));
+ if (symbolTableFunction->hasPrototypeDeclaration() && mShaderVersion == 100)
{
// 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");
}
- function->setHasPrototypeDeclaration();
+ symbolTableFunction->setHasPrototypeDeclaration();
TIntermAggregate *prototype = new TIntermAggregate;
- // TODO(oetuaho@nvidia.com): Instead of converting the function information here, the node could
- // point to the data that already exists in the symbol table.
- prototype->setType(function->getReturnType());
- prototype->getFunctionSymbolInfo()->setFromFunction(*function);
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getMangledName());
+ prototype->setFunctionId(function.getUniqueId());
- for (size_t i = 0; i < function->getParamCount(); i++)
+ for (size_t i = 0; i < function.getParamCount(); i++)
{
- const TConstParameter &param = function->getParam(i);
+ const TConstParameter &param = function.getParam(i);
if (param.name != 0)
{
TVariable variable(param.name, *param.type);
@@ -2378,83 +2018,71 @@ TIntermAggregate *TParseContext::addFunctionPrototypeDeclaration(const TFunction
return prototype;
}
-TIntermFunctionDefinition *TParseContext::addFunctionDefinition(
- const TFunction &function,
- TIntermAggregate *functionParameters,
- TIntermBlock *functionBody,
- const TSourceLoc &location)
+TIntermAggregate *TParseContext::addFunctionDefinition(const TFunction &function,
+ TIntermAggregate *functionPrototype,
+ TIntermAggregate *functionBody,
+ const TSourceLoc &location)
{
- // Check that non-void functions have at least one return statement.
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
if (mCurrentFunctionType->getBasicType() != EbtVoid && !mFunctionReturnsValue)
{
error(location, "function does not return a value:", "", function.getName().c_str());
}
- if (functionBody == nullptr)
- {
- functionBody = new TIntermBlock();
- functionBody->setLine(location);
- }
- TIntermFunctionDefinition *functionNode =
- new TIntermFunctionDefinition(function.getReturnType(), functionParameters, functionBody);
- functionNode->setLine(location);
-
- functionNode->getFunctionSymbolInfo()->setFromFunction(function);
+ 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());
symbolTable.pop();
- return functionNode;
+ return aggregate;
}
-void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
- TFunction **function,
- TIntermAggregate **aggregateOut)
+void TParseContext::parseFunctionPrototype(const TSourceLoc &location,
+ TFunction *function,
+ TIntermAggregate **aggregateOut)
{
- ASSERT(function);
- ASSERT(*function);
const TSymbol *builtIn =
- symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
+ symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
if (builtIn)
{
- error(location, "built-in functions cannot be redefined", (*function)->getName().c_str());
+ error(location, "built-in functions cannot be redefined", function->getName().c_str());
}
- else
- {
- TFunction *prevDec = static_cast<TFunction *>(
- symbolTable.find((*function)->getMangledName(), getShaderVersion()));
-
- // Note: 'prevDec' could be 'function' if this is the first time we've seen function as it
- // would have just been put in the symbol table. Otherwise, we're looking up an earlier
- // occurance.
- if (*function != prevDec)
- {
- // Swap the parameters of the previous declaration to the parameters of the function
- // definition (parameter names may differ).
- prevDec->swapParameters(**function);
-
- // The function definition will share the same symbol as any previous declaration.
- *function = prevDec;
- }
-
- if ((*function)->isDefined())
- {
- error(location, "function already has a body", (*function)->getName().c_str());
- }
- (*function)->setDefined();
+ TFunction *prevDec =
+ static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined())
+ {
+ // Then this function already has a body.
+ error(location, "function already has a body", function->getName().c_str());
}
+ prevDec->setDefined();
+ //
+ // Overload the unique ID of the definition to be the same unique ID as the declaration.
+ // Eventually we will probably want to have only a single definition and just swap the
+ // arguments to be the definition's arguments.
+ //
+ function->setUniqueId(prevDec->getUniqueId());
// Raise error message if main function takes any parameters or return anything other than void
- if ((*function)->getName() == "main")
+ if (function->getName() == "main")
{
- if ((*function)->getParamCount() > 0)
+ if (function->getParamCount() > 0)
{
- error(location, "function cannot take any parameter(s)",
- (*function)->getName().c_str());
+ error(location, "function cannot take any parameter(s)", function->getName().c_str());
}
- if ((*function)->getReturnType().getBasicType() != EbtVoid)
+ if (function->getReturnType().getBasicType() != EbtVoid)
{
- error(location, "", (*function)->getReturnType().getBasicString(),
+ error(location, "", function->getReturnType().getBasicString(),
"main function cannot return a value");
}
}
@@ -2462,7 +2090,7 @@ void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
//
// Remember the return type for later checking for RETURN statements.
//
- mCurrentFunctionType = &((*function)->getReturnType());
+ mCurrentFunctionType = &(prevDec->getReturnType());
mFunctionReturnsValue = false;
//
@@ -2474,9 +2102,9 @@ void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
// knows where to find parameters.
//
TIntermAggregate *paramNodes = new TIntermAggregate;
- for (size_t i = 0; i < (*function)->getParamCount(); i++)
+ for (size_t i = 0; i < function->getParamCount(); i++)
{
- const TConstParameter &param = (*function)->getParam(i);
+ const TConstParameter &param = function->getParam(i);
if (param.name != 0)
{
TVariable *variable = new TVariable(param.name, *param.type);
@@ -2534,7 +2162,7 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
{
if (prevDec->getReturnType() != function->getReturnType())
{
- error(location, "function must have the same return type in all of its declarations",
+ error(location, "overloaded functions must have the same return type",
function->getReturnType().getBasicString());
}
for (size_t i = 0; i < prevDec->getParamCount(); ++i)
@@ -2542,8 +2170,7 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
if (prevDec->getParam(i).type->getQualifier() !=
function->getParam(i).type->getQualifier())
{
- error(location,
- "function must have the same parameter qualifiers in all of its declarations",
+ error(location, "overloaded functions must have the same parameter qualifiers",
function->getParam(i).type->getQualifierString());
}
}
@@ -2563,7 +2190,9 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
else
{
// Insert the unmangled name to detect potential future redefinition as a variable.
- symbolTable.getOuterLevel()->insertUnmangled(function);
+ TFunction *newFunction =
+ new TFunction(NewPoolTString(function->getName().c_str()), &function->getReturnType());
+ symbolTable.getOuterLevel()->insertUnmangled(newFunction);
}
// We're at the inner scope level of the function's arguments and body statement.
@@ -2591,10 +2220,8 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
{
error(location, "no qualifiers allowed for function return", "layout");
}
- // make sure a sampler or an image is not involved as well...
- checkIsNotSampler(location, type.typeSpecifierNonArray,
- "samplers can't be function return values");
- checkIsNotImage(location, type.typeSpecifierNonArray, "images can't be function return values");
+ // make sure a sampler is not involved as well...
+ checkIsNotSampler(location, type, "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
@@ -2616,14 +2243,14 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
{
TPublicType publicType = publicTypeIn;
- if (publicType.isStructSpecifier())
+ if (publicType.isStructSpecifier)
{
- error(publicType.getLine(), "constructor can't be a structure definition",
- getBasicString(publicType.getBasicType()));
+ error(publicType.line, "constructor can't be a structure definition",
+ getBasicString(publicType.type));
}
TOperator op = EOpNull;
- if (publicType.getUserDef())
+ if (publicType.userDef)
{
op = EOpConstructStruct;
}
@@ -2632,9 +2259,8 @@ TFunction *TParseContext::addConstructorFunc(const TPublicType &publicTypeIn)
op = sh::TypeToConstructorOperator(TType(publicType));
if (op == EOpNull)
{
- error(publicType.getLine(), "cannot construct this type",
- getBasicString(publicType.getBasicType()));
- publicType.setBasicType(EbtFloat);
+ error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
+ publicType.type = EbtFloat;
op = EOpConstructFloat;
}
}
@@ -2657,12 +2283,6 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
TType type = fnCall->getReturnType();
if (type.isUnsizedArray())
{
- if (fnCall->getParamCount() == 0)
- {
- error(line, "implicitly sized array constructor must have at least one argument", "[]");
- type.setArraySize(1u);
- return TIntermTyped::CreateZero(type);
- }
type.setArraySize(static_cast<unsigned int>(fnCall->getParamCount()));
}
bool constType = true;
@@ -2702,7 +2322,7 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
constructor->setType(type);
- TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor, &mDiagnostics);
+ TIntermTyped *constConstructor = intermediate.foldAggregateBuiltIn(constructor);
if (constConstructor)
{
return constConstructor;
@@ -2711,36 +2331,118 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments,
return constructor;
}
+// This function returns vector field(s) being accessed from a constant vector.
+TIntermConstantUnion *TParseContext::foldVectorSwizzle(TVectorFields &fields,
+ TIntermConstantUnion *baseNode,
+ const TSourceLoc &location)
+{
+ const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
+ ASSERT(unionArray);
+
+ TConstantUnion *constArray = new TConstantUnion[fields.num];
+ const auto &type = baseNode->getType();
+
+ for (int i = 0; i < fields.num; i++)
+ {
+ // Out-of-range indices should already be checked.
+ ASSERT(fields.offsets[i] < type.getNominalSize());
+ constArray[i] = unionArray[fields.offsets[i]];
+ }
+ return intermediate.addConstantUnion(constArray, type, location);
+}
+
+// This function returns the column vector being accessed from a constant matrix.
+TIntermConstantUnion *TParseContext::foldMatrixSubscript(int index,
+ TIntermConstantUnion *baseNode,
+ const TSourceLoc &location)
+{
+ ASSERT(index < baseNode->getType().getCols());
+
+ const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
+ int size = baseNode->getType().getRows();
+ return intermediate.addConstantUnion(&unionArray[size * index], baseNode->getType(), location);
+}
+
+// This function returns an element of an array accessed from a constant array.
+TIntermConstantUnion *TParseContext::foldArraySubscript(int index,
+ TIntermConstantUnion *baseNode,
+ const TSourceLoc &location)
+{
+ ASSERT(index < static_cast<int>(baseNode->getArraySize()));
+
+ TType arrayElementType = baseNode->getType();
+ arrayElementType.clearArrayness();
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ const TConstantUnion *unionArray = baseNode->getUnionArrayPointer();
+ return intermediate.addConstantUnion(&unionArray[arrayElementSize * index], baseNode->getType(),
+ location);
+}
+
+//
+// This function returns the value of a particular field inside a constant structure from the symbol
+// table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or
+// addConstStructFromAggr function and returns the parse-tree with the values of the embedded/nested
+// struct.
+//
+TIntermTyped *TParseContext::addConstStruct(const TString &identifier,
+ TIntermTyped *node,
+ const TSourceLoc &line)
+{
+ const TFieldList &fields = node->getType().getStruct()->fields();
+ size_t instanceSize = 0;
+
+ for (size_t index = 0; index < fields.size(); ++index)
+ {
+ if (fields[index]->name() == identifier)
+ {
+ break;
+ }
+ else
+ {
+ instanceSize += fields[index]->type()->getObjectSize();
+ }
+ }
+
+ TIntermTyped *typedNode;
+ TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
+ if (tempConstantNode)
+ {
+ const TConstantUnion *constArray = tempConstantNode->getUnionArrayPointer();
+
+ // type will be changed in the calling function
+ typedNode = intermediate.addConstantUnion(constArray + instanceSize,
+ tempConstantNode->getType(), line);
+ }
+ else
+ {
+ error(line, "Cannot offset into the structure", "Error");
+ return nullptr;
+ }
+
+ return typedNode;
+}
+
//
// Interface/uniform blocks
//
-TIntermDeclaration *TParseContext::addInterfaceBlock(
- const TTypeQualifierBuilder &typeQualifierBuilder,
- const TSourceLoc &nameLine,
- const TString &blockName,
- TFieldList *fieldList,
- const TString *instanceName,
- const TSourceLoc &instanceLine,
- TIntermTyped *arrayIndex,
- const TSourceLoc &arrayIndexLine)
+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)
{
checkIsNotReserved(nameLine, blockName);
- TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
-
if (typeQualifier.qualifier != EvqUniform)
{
error(typeQualifier.line, "invalid qualifier:", getQualifierString(typeQualifier.qualifier),
"interface blocks must be uniform");
}
- if (typeQualifier.invariant)
- {
- error(typeQualifier.line, "invalid qualifier on interface block member", "invariant");
- }
-
- checkIsMemoryQualifierNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
-
TLayoutQualifier blockLayoutQualifier = typeQualifier.layoutQualifier;
checkLocationIsNotSpecified(typeQualifier.line, blockLayoutQualifier);
@@ -2756,8 +2458,6 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
checkWorkGroupSizeIsNotSpecified(nameLine, blockLayoutQualifier);
- checkInternalFormatIsNotSpecified(nameLine, blockLayoutQualifier.imageInternalFormat);
-
TSymbol *blockNameSymbol = new TInterfaceBlockName(&blockName);
if (!symbolTable.declare(blockNameSymbol))
{
@@ -2775,12 +2475,6 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
"sampler types are not allowed in interface blocks");
}
- if (IsImage(fieldType->getBasicType()))
- {
- error(field->line(), "unsupported type", fieldType->getBasicString(),
- "image types are not allowed in interface blocks");
- }
-
const TQualifier qualifier = fieldType->getQualifier();
switch (qualifier)
{
@@ -2793,11 +2487,6 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
break;
}
- if (fieldType->isInvariant())
- {
- error(field->line(), "invalid qualifier on interface block member", "invariant");
- }
-
// check layout qualifiers
TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
@@ -2876,14 +2565,13 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
symbolName = instanceTypeDef->getName();
}
- TIntermSymbol *blockSymbol =
- intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line);
- TIntermDeclaration *declaration = new TIntermDeclaration();
- declaration->appendDeclarator(blockSymbol);
- declaration->setLine(nameLine);
+ TIntermAggregate *aggregate = intermediate.makeAggregate(
+ intermediate.addSymbol(symbolId, symbolName, interfaceBlockType, typeQualifier.line),
+ nameLine);
+ aggregate->setOp(EOpDeclaration);
exitStructDeclaration();
- return declaration;
+ return aggregate;
}
void TParseContext::enterStructDeclaration(const TSourceLoc &line, const TString &identifier)
@@ -2904,9 +2592,15 @@ void TParseContext::exitStructDeclaration()
--mStructNestingLevel;
}
+namespace
+{
+const int kWebGLMaxStructNesting = 4;
+
+} // namespace
+
void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const TField &field)
{
- if (!sh::IsWebGLBasedSpec(mShaderSpec))
+ if (!IsWebGLBasedSpec(mShaderSpec))
{
return;
}
@@ -2936,6 +2630,8 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
const TSourceLoc &location,
TIntermTyped *indexExpression)
{
+ TIntermTyped *indexedExpression = NULL;
+
if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
{
if (baseExpression->getAsSymbolNode())
@@ -2947,11 +2643,6 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
{
error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
}
-
- TConstantUnion *unionArray = new TConstantUnion[1];
- unionArray->setFConst(0.0f);
- return intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst),
- location);
}
TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
@@ -2981,78 +2672,151 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
if (indexConstantUnion)
{
- // 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.
+ // 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.
bool outOfRangeIndexIsError = indexExpression->getQualifier() == EvqConst;
int index = indexConstantUnion->getIConst(0);
+ if (!baseExpression->isArray())
+ {
+ // Array checks are done later because a different error message might be generated
+ // based on the index in some cases.
+ if (baseExpression->isVector())
+ {
+ index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getNominalSize(),
+ "vector field selection out of range", "[]");
+ }
+ else if (baseExpression->isMatrix())
+ {
+ index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getType().getCols(),
+ "matrix field selection out of range", "[]");
+ }
+ }
- int safeIndex = -1;
-
- if (baseExpression->isArray())
+ TIntermConstantUnion *baseConstantUnion = baseExpression->getAsConstantUnion();
+ if (baseConstantUnion)
{
- if (baseExpression->getQualifier() == EvqFragData && index > 0)
+ if (baseExpression->isArray())
{
- if (mShaderSpec == SH_WEBGL2_SPEC)
+ index = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getArraySize(),
+ "array index out of range", "[]");
+ // Constant folding for array indexing.
+ indexedExpression = foldArraySubscript(index, baseConstantUnion, location);
+ }
+ else if (baseExpression->isVector())
+ {
+ // Constant folding for vector indexing - reusing vector swizzle folding.
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = index;
+ indexedExpression = foldVectorSwizzle(fields, baseConstantUnion, location);
+ }
+ else if (baseExpression->isMatrix())
+ {
+ // Constant folding for matrix indexing.
+ indexedExpression = foldMatrixSubscript(index, baseConstantUnion, location);
+ }
+ }
+ else
+ {
+ int safeIndex = -1;
+
+ if (baseExpression->isArray())
+ {
+ if (baseExpression->getQualifier() == EvqFragData && index > 0)
{
- // Error has been already generated if index is not const.
- if (indexExpression->getQualifier() == EvqConst)
+ if (mShaderSpec == SH_WEBGL2_SPEC)
{
- error(location, "", "[",
- "array index for gl_FragData must be constant zero");
+ // Error has been already generated if index is not const.
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ error(location, "", "[",
+ "array index for gl_FragData must be constant zero");
+ }
+ safeIndex = 0;
+ }
+ else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
+ {
+ outOfRangeError(outOfRangeIndexIsError, location, "", "[",
+ "array index for gl_FragData must be zero when "
+ "GL_EXT_draw_buffers is disabled");
+ safeIndex = 0;
}
- safeIndex = 0;
}
- else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
+ // Only do generic out-of-range check if similar error hasn't already been reported.
+ if (safeIndex < 0)
{
- outOfRangeError(outOfRangeIndexIsError, location, "", "[",
- "array index for gl_FragData must be zero when "
- "GL_EXT_draw_buffers is disabled");
- safeIndex = 0;
+ safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
+ baseExpression->getArraySize(),
+ "array index out of range", "[]");
}
}
- // Only do generic out-of-range check if similar error hasn't already been reported.
- if (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 != -1)
{
- safeIndex = checkIndexOutOfRange(outOfRangeIndexIsError, location, index,
- baseExpression->getArraySize(),
- "array index out of range", "[]");
+ TConstantUnion *safeConstantUnion = new TConstantUnion();
+ safeConstantUnion->setIConst(safeIndex);
+ indexConstantUnion->replaceConstantUnion(safeConstantUnion);
}
- }
- 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", "[]");
- }
- 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);
+ indexedExpression =
+ intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
}
+ }
+ 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));
+ }
+ else
+ {
+ indexedExpression->setType(baseExpression->getType());
+ }
- return intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location,
- &mDiagnostics);
+ if (baseExpression->getType().getQualifier() == EvqConst &&
+ indexExpression->getType().getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
}
else
{
- return intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location,
- &mDiagnostics);
+ indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
}
+
+ return indexedExpression;
}
int TParseContext::checkIndexOutOfRange(bool outOfRangeIndexIsError,
@@ -3085,10 +2849,11 @@ 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", ".");
- return baseExpression;
}
if (baseExpression->isVector())
@@ -3101,19 +2866,41 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
fields.offsets[0] = 0;
}
- return TIntermediate::AddSwizzle(baseExpression, fields, dotLocation);
+ if (baseExpression->getAsConstantUnion())
+ {
+ // constant folding for vector fields
+ indexedExpression =
+ foldVectorSwizzle(fields, baseExpression->getAsConstantUnion(), fieldLocation);
+ }
+ else
+ {
+ TIntermTyped *index = intermediate.addSwizzle(fields, fieldLocation);
+ indexedExpression =
+ intermediate.addIndex(EOpVectorSwizzle, baseExpression, index, dotLocation);
+ }
+ if (indexedExpression == nullptr)
+ {
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ // Note that the qualifier set here will be corrected later.
+ indexedExpression->setType(TType(baseExpression->getBasicType(),
+ baseExpression->getPrecision(), EvqTemporary,
+ static_cast<unsigned char>(fields.num)));
+ }
}
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");
- return baseExpression;
+ indexedExpression = baseExpression;
}
else
{
- bool fieldFound = false;
unsigned int i;
for (i = 0; i < fields.size(); ++i)
{
@@ -3125,29 +2912,47 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
if (fieldFound)
{
- TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
- index->setLine(fieldLocation);
- return intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index,
- dotLocation, &mDiagnostics);
+ if (baseExpression->getAsConstantUnion())
+ {
+ indexedExpression = addConstStruct(fieldString, baseExpression, dotLocation);
+ if (indexedExpression == 0)
+ {
+ indexedExpression = baseExpression;
+ }
+ else
+ {
+ indexedExpression->setType(*fields[i]->type());
+ }
+ }
+ else
+ {
+ TConstantUnion *unionArray = new TConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped *index = intermediate.addConstantUnion(
+ unionArray, *fields[i]->type(), fieldLocation);
+ indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression,
+ index, dotLocation);
+ indexedExpression->setType(*fields[i]->type());
+ }
}
else
{
error(dotLocation, " no such field in structure", fieldString.c_str());
- return baseExpression;
+ indexedExpression = baseExpression;
}
}
}
else if (baseExpression->isInterfaceBlock())
{
+ bool fieldFound = false;
const TFieldList &fields = baseExpression->getType().getInterfaceBlock()->fields();
if (fields.empty())
{
error(dotLocation, "interface block has no fields", "Internal Error");
- return baseExpression;
+ indexedExpression = baseExpression;
}
else
{
- bool fieldFound = false;
unsigned int i;
for (i = 0; i < fields.size(); ++i)
{
@@ -3159,15 +2964,18 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
}
if (fieldFound)
{
- TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
- index->setLine(fieldLocation);
- return intermediate.addIndex(EOpIndexDirectInterfaceBlock, baseExpression, index,
- dotLocation, &mDiagnostics);
+ 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());
}
else
{
error(dotLocation, " no such field in interface block", fieldString.c_str());
- return baseExpression;
+ indexedExpression = baseExpression;
}
}
}
@@ -3185,8 +2993,19 @@ TIntermTyped *TParseContext::addFieldSelectionExpression(TIntermTyped *baseExpre
"side",
fieldString.c_str());
}
- return baseExpression;
+ indexedExpression = baseExpression;
+ }
+
+ if (baseExpression->getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
}
+ else
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ return indexedExpression;
}
TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
@@ -3196,18 +3015,10 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
if (qualifierType == "shared")
{
- if (sh::IsWebGLBasedSpec(mShaderSpec))
- {
- error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "shared");
- }
qualifier.blockStorage = EbsShared;
}
else if (qualifierType == "packed")
{
- if (sh::IsWebGLBasedSpec(mShaderSpec))
- {
- error(qualifierTypeLine, "Only std140 layout is allowed in WebGL", "packed");
- }
qualifier.blockStorage = EbsPacked;
}
else if (qualifierType == "std140")
@@ -3227,72 +3038,6 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str(),
"location requires an argument");
}
- else if (qualifierType == "rgba32f")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA32F;
- }
- else if (qualifierType == "rgba16f")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA16F;
- }
- else if (qualifierType == "r32f")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifR32F;
- }
- else if (qualifierType == "rgba8")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA8;
- }
- else if (qualifierType == "rgba8_snorm")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA8_SNORM;
- }
- else if (qualifierType == "rgba32i")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA32I;
- }
- else if (qualifierType == "rgba16i")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA16I;
- }
- else if (qualifierType == "rgba8i")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA8I;
- }
- else if (qualifierType == "r32i")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifR32I;
- }
- else if (qualifierType == "rgba32ui")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA32UI;
- }
- else if (qualifierType == "rgba16ui")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA16UI;
- }
- else if (qualifierType == "rgba8ui")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifRGBA8UI;
- }
- else if (qualifierType == "r32ui")
- {
- checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
- qualifier.imageInternalFormat = EiifR32UI;
- }
-
else
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
@@ -3338,7 +3083,6 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
else
{
qualifier.location = intValue;
- qualifier.locationsSpecified = 1;
}
}
else if (qualifierType == "local_size_x")
@@ -3364,48 +3108,106 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
return qualifier;
}
-TTypeQualifierBuilder *TParseContext::createTypeQualifierBuilder(const TSourceLoc &loc)
-{
- return new TTypeQualifierBuilder(
- new TStorageQualifierWrapper(symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary, loc),
- mShaderVersion);
-}
-
TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier,
TLayoutQualifier rightQualifier,
const TSourceLoc &rightQualifierLocation)
{
- return sh::JoinLayoutQualifiers(leftQualifier, rightQualifier, rightQualifierLocation,
- &mDiagnostics);
+ TLayoutQualifier joinedQualifier = leftQualifier;
+
+ if (rightQualifier.location != -1)
+ {
+ joinedQualifier.location = rightQualifier.location;
+ }
+ if (rightQualifier.matrixPacking != EmpUnspecified)
+ {
+ joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
+ }
+ if (rightQualifier.blockStorage != EbsUnspecified)
+ {
+ joinedQualifier.blockStorage = rightQualifier.blockStorage;
+ }
+
+ for (size_t i = 0u; i < rightQualifier.localSize.size(); ++i)
+ {
+ if (rightQualifier.localSize[i] != -1)
+ {
+ if (joinedQualifier.localSize[i] != -1 &&
+ joinedQualifier.localSize[i] != rightQualifier.localSize[i])
+ {
+ error(rightQualifierLocation,
+ "Cannot have multiple different work group size specifiers",
+ getWorkGroupSizeString(i));
+ }
+ joinedQualifier.localSize[i] = rightQualifier.localSize[i];
+ }
+ }
+
+ return joinedQualifier;
}
-TFieldList *TParseContext::addStructDeclaratorListWithQualifiers(
- const TTypeQualifierBuilder &typeQualifierBuilder,
- TPublicType *typeSpecifier,
- TFieldList *fieldList)
+TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpolationLoc,
+ TQualifier interpolationQualifier,
+ const TSourceLoc &storageLoc,
+ TQualifier storageQualifier)
{
- TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(&mDiagnostics);
+ TQualifier mergedQualifier = EvqSmoothIn;
- typeSpecifier->qualifier = typeQualifier.qualifier;
- typeSpecifier->layoutQualifier = typeQualifier.layoutQualifier;
- typeSpecifier->memoryQualifier = typeQualifier.memoryQualifier;
- typeSpecifier->invariant = typeQualifier.invariant;
- if (typeQualifier.precision != EbpUndefined)
+ if (storageQualifier == EvqFragmentIn)
{
- typeSpecifier->precision = typeQualifier.precision;
+ 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();
}
- return addStructDeclaratorList(*typeSpecifier, fieldList);
+ else
+ {
+ error(interpolationLoc,
+ "interpolation qualifier requires a fragment 'in' or vertex 'out' storage qualifier",
+ getInterpolationString(interpolationQualifier));
+
+ mergedQualifier = storageQualifier;
+ }
+
+ TPublicType type;
+ type.setBasic(EbtVoid, mergedQualifier, storageLoc);
+ return type;
}
TFieldList *TParseContext::addStructDeclaratorList(const TPublicType &typeSpecifier,
TFieldList *fieldList)
{
- checkPrecisionSpecified(typeSpecifier.getLine(), typeSpecifier.precision,
- typeSpecifier.getBasicType());
+ checkIsNonVoid(typeSpecifier.line, (*fieldList)[0]->name(), typeSpecifier.type);
- checkIsNonVoid(typeSpecifier.getLine(), (*fieldList)[0]->name(), typeSpecifier.getBasicType());
-
- checkWorkGroupSizeIsNotSpecified(typeSpecifier.getLine(), typeSpecifier.layoutQualifier);
+ checkWorkGroupSizeIsNotSpecified(typeSpecifier.line, typeSpecifier.layoutQualifier);
for (unsigned int i = 0; i < fieldList->size(); ++i)
{
@@ -3413,43 +3215,42 @@ 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.getBasicType());
- type->setPrimarySize(typeSpecifier.getPrimarySize());
- type->setSecondarySize(typeSpecifier.getSecondarySize());
+ type->setBasicType(typeSpecifier.type);
+ type->setPrimarySize(typeSpecifier.primarySize);
+ type->setSecondarySize(typeSpecifier.secondarySize);
type->setPrecision(typeSpecifier.precision);
type->setQualifier(typeSpecifier.qualifier);
type->setLayoutQualifier(typeSpecifier.layoutQualifier);
- type->setMemoryQualifier(typeSpecifier.memoryQualifier);
- type->setInvariant(typeSpecifier.invariant);
// don't allow arrays of arrays
if (type->isArray())
{
- checkIsValidTypeForArray(typeSpecifier.getLine(), typeSpecifier);
+ checkIsValidTypeForArray(typeSpecifier.line, typeSpecifier);
}
if (typeSpecifier.array)
type->setArraySize(static_cast<unsigned int>(typeSpecifier.arraySize));
- if (typeSpecifier.getUserDef())
+ if (typeSpecifier.userDef)
{
- type->setStruct(typeSpecifier.getUserDef()->getStruct());
+ type->setStruct(typeSpecifier.userDef->getStruct());
}
- checkIsBelowStructNestingLimit(typeSpecifier.getLine(), *(*fieldList)[i]);
+ checkIsBelowStructNestingLimit(typeSpecifier.line, *(*fieldList)[i]);
}
return fieldList;
}
-TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
- const TSourceLoc &nameLine,
- const TString *structName,
- TFieldList *fieldList)
+TPublicType TParseContext::addStructure(const TSourceLoc &structLine,
+ const TSourceLoc &nameLine,
+ const TString *structName,
+ TFieldList *fieldList)
{
TStructure *structure = new TStructure(structName, fieldList);
TType *structureType = new TType(structure);
// 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())
@@ -3477,31 +3278,19 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
getQualifierString(qualifier));
break;
}
- if (field.type()->isInvariant())
- {
- error(field.line(), "invalid qualifier on struct member", "invariant");
- }
- if (IsImage(field.type()->getBasicType()))
- {
- error(field.line(), "disallowed type in struct", field.type()->getBasicString());
- }
-
- checkIsMemoryQualifierNotSpecified(field.type()->getMemoryQualifier(), field.line());
-
- checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
}
- TTypeSpecifierNonArray typeSpecifierNonArray;
- typeSpecifierNonArray.initialize(EbtStruct, structLine);
- typeSpecifierNonArray.userDef = structureType;
- typeSpecifierNonArray.isStructSpecifier = true;
+ TPublicType publicType;
+ publicType.setBasic(EbtStruct, EvqTemporary, structLine);
+ publicType.userDef = structureType;
+ publicType.isStructSpecifier = true;
exitStructDeclaration();
- return typeSpecifierNonArray;
+ return publicType;
}
TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init,
- TIntermBlock *statementList,
+ TIntermAggregate *statementList,
const TSourceLoc &loc)
{
TBasicType switchType = init->getBasicType();
@@ -3613,7 +3402,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op,
case EOpNegative:
case EOpPositive:
if (child->getBasicType() == EbtStruct || child->getBasicType() == EbtBool ||
- child->isArray() || IsOpaqueType(child->getBasicType()))
+ child->isArray() || IsSampler(child->getBasicType()))
{
return nullptr;
}
@@ -3622,14 +3411,7 @@ TIntermTyped *TParseContext::createUnaryMath(TOperator op,
break;
}
- TIntermUnary *node = new TIntermUnary(op, child);
- node->setLine(loc);
-
- TIntermTyped *foldedNode = node->fold(&mDiagnostics);
- if (foldedNode)
- return foldedNode;
-
- return node;
+ return intermediate.addUnaryMath(op, child, loc, funcReturnType);
}
TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc)
@@ -3778,14 +3560,6 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
GetOperatorString(op));
return false;
}
-
- if ((op == EOpAssign || op == EOpInitialize) &&
- left->getType().isStructureContainingImages())
- {
- error(loc, "undefined operation for structs containing images",
- GetOperatorString(op));
- return false;
- }
case EOpLessThan:
case EOpGreaterThan:
case EOpLessThanEqual:
@@ -3916,12 +3690,10 @@ TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op,
case EOpLogicalAnd:
ASSERT(!left->isArray() && !right->isArray() && !left->getType().getStruct() &&
!right->getType().getStruct());
- if (left->getBasicType() != EbtBool || !left->isScalar() || !right->isScalar())
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isVector())
{
return nullptr;
}
- // Basic types matching should have been already checked.
- ASSERT(right->getBasicType() == EbtBool);
break;
case EOpAdd:
case EOpSub:
@@ -4000,10 +3772,10 @@ TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op,
return node;
}
-TIntermBinary *TParseContext::createAssign(TOperator op,
- TIntermTyped *left,
- TIntermTyped *right,
- const TSourceLoc &loc)
+TIntermTyped *TParseContext::createAssign(TOperator op,
+ TIntermTyped *left,
+ TIntermTyped *right,
+ const TSourceLoc &loc)
{
if (binaryOpCommonCheck(op, left, right, loc))
{
@@ -4053,7 +3825,7 @@ TIntermTyped *TParseContext::addComma(TIntermTyped *left,
",");
}
- return TIntermediate::AddComma(left, right, loc, mShaderVersion);
+ return intermediate.addComma(left, right, loc, mShaderVersion);
}
TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
@@ -4105,7 +3877,7 @@ TIntermBranch *TParseContext::addBranch(TOperator op,
void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
{
ASSERT(!functionCall->isUserDefined());
- const TString &name = functionCall->getFunctionSymbolInfo()->getName();
+ const TString &name = functionCall->getName();
TIntermNode *offset = nullptr;
TIntermSequence *arguments = functionCall->getSequence();
if (name.compare(0, 16, "texelFetchOffset") == 0 ||
@@ -4153,99 +3925,6 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
}
}
-// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
-void TParseContext::checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall)
-{
- ASSERT(!functionCall->isUserDefined());
- const TString &name = functionCall->getFunctionSymbolInfo()->getName();
-
- if (name.compare(0, 5, "image") == 0)
- {
- TIntermSequence *arguments = functionCall->getSequence();
- TIntermNode *imageNode = (*arguments)[0];
- TIntermSymbol *imageSymbol = imageNode->getAsSymbolNode();
-
- const TMemoryQualifier &memoryQualifier = imageSymbol->getMemoryQualifier();
-
- if (name.compare(5, 5, "Store") == 0)
- {
- if (memoryQualifier.readonly)
- {
- error(imageNode->getLine(),
- "'imageStore' cannot be used with images qualified as 'readonly'",
- imageSymbol->getSymbol().c_str());
- }
- }
- else if (name.compare(5, 4, "Load") == 0)
- {
- if (memoryQualifier.writeonly)
- {
- error(imageNode->getLine(),
- "'imageLoad' cannot be used with images qualified as 'writeonly'",
- imageSymbol->getSymbol().c_str());
- }
- }
- }
-}
-
-// GLSL ES 3.10 Revision 4, 13.51 Matching of Memory Qualifiers in Function Parameters
-void TParseContext::checkImageMemoryAccessForUserDefinedFunctions(
- const TFunction *functionDefinition,
- const TIntermAggregate *functionCall)
-{
- ASSERT(functionCall->isUserDefined());
-
- const TIntermSequence &arguments = *functionCall->getSequence();
-
- ASSERT(functionDefinition->getParamCount() == arguments.size());
-
- for (size_t i = 0; i < arguments.size(); ++i)
- {
- const TType &functionArgumentType = arguments[i]->getAsTyped()->getType();
- const TType &functionParameterType = *functionDefinition->getParam(i).type;
- ASSERT(functionArgumentType.getBasicType() == functionParameterType.getBasicType());
-
- if (IsImage(functionArgumentType.getBasicType()))
- {
- const TMemoryQualifier &functionArgumentMemoryQualifier =
- functionArgumentType.getMemoryQualifier();
- const TMemoryQualifier &functionParameterMemoryQualifier =
- functionParameterType.getMemoryQualifier();
- if (functionArgumentMemoryQualifier.readonly &&
- !functionParameterMemoryQualifier.readonly)
- {
- error(functionCall->getLine(),
- "Function call discards the 'readonly' qualifier from image",
- arguments[i]->getAsSymbolNode()->getSymbol().c_str());
- }
-
- if (functionArgumentMemoryQualifier.writeonly &&
- !functionParameterMemoryQualifier.writeonly)
- {
- error(functionCall->getLine(),
- "Function call discards the 'writeonly' qualifier from image",
- arguments[i]->getAsSymbolNode()->getSymbol().c_str());
- }
-
- if (functionArgumentMemoryQualifier.coherent &&
- !functionParameterMemoryQualifier.coherent)
- {
- error(functionCall->getLine(),
- "Function call discards the 'coherent' qualifier from image",
- arguments[i]->getAsSymbolNode()->getSymbol().c_str());
- }
-
- if (functionArgumentMemoryQualifier.volatileQualifier &&
- !functionParameterMemoryQualifier.volatileQualifier)
- {
- error(functionCall->getLine(),
- "Function call discards the 'volatile' qualifier from image",
- arguments[i]->getAsSymbolNode()->getSymbol().c_str());
- }
- }
- }
-}
-
TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
TIntermNode *paramNode,
TIntermNode *thisNode,
@@ -4361,8 +4040,7 @@ 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, &mDiagnostics);
+ TIntermTyped *foldedNode = intermediate.foldAggregateBuiltIn(aggregate);
if (foldedNode)
{
callNode = foldedNode;
@@ -4387,20 +4065,15 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
// if builtIn == true, it's definitely a builtIn function with EOpNull
if (!builtIn)
aggregate->setUserDefined();
- aggregate->getFunctionSymbolInfo()->setFromFunction(*fnCandidate);
+ aggregate->setName(fnCandidate->getMangledName());
+ aggregate->setFunctionId(fnCandidate->getUniqueId());
- // This needs to happen after the function info including name is set
+ // This needs to happen after the name is set
if (builtIn)
{
aggregate->setBuiltInFunctionPrecision();
checkTextureOffsetConst(aggregate);
-
- checkImageMemoryAccessForBuiltinFunctions(aggregate);
- }
- else
- {
- checkImageMemoryAccessForUserDefinedFunctions(fnCandidate, aggregate);
}
callNode = aggregate;
@@ -4422,46 +4095,34 @@ TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall,
}
TIntermTyped *TParseContext::addTernarySelection(TIntermTyped *cond,
- TIntermTyped *trueExpression,
- TIntermTyped *falseExpression,
+ TIntermTyped *trueBlock,
+ TIntermTyped *falseBlock,
const TSourceLoc &loc)
{
checkIsScalarBool(loc, cond);
- if (trueExpression->getType() != falseExpression->getType())
+ if (trueBlock->getType() != falseBlock->getType())
{
- binaryOpError(loc, ":", trueExpression->getCompleteString(),
- falseExpression->getCompleteString());
- return falseExpression;
+ binaryOpError(loc, ":", trueBlock->getCompleteString(), falseBlock->getCompleteString());
+ return falseBlock;
}
- if (IsOpaqueType(trueExpression->getBasicType()))
- {
- // ESSL 1.00 section 4.1.7
- // ESSL 3.00 section 4.1.7
- // Opaque/sampler types are not allowed in most types of expressions, including ternary.
- // Note that structs containing opaque types don't need to be checked as structs are
- // forbidden below.
- error(loc, "ternary operator is not allowed for opaque types", ":");
- 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 (trueExpression->isArray() || trueExpression->getBasicType() == EbtStruct)
+ if (trueBlock->isArray() || trueBlock->getBasicType() == EbtStruct)
{
error(loc, "ternary operator is not allowed for structures or arrays", ":");
- return falseExpression;
+ return falseBlock;
}
// 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)
+ if (mShaderSpec == SH_WEBGL2_SPEC && trueBlock->getBasicType() == EbtVoid)
{
error(loc, "ternary operator is not allowed for void", ":");
- return falseExpression;
+ return falseBlock;
}
- return TIntermediate::AddTernarySelection(cond, trueExpression, falseExpression, loc);
+ return intermediate.addSelection(cond, trueBlock, falseBlock, loc);
}
//
@@ -4488,5 +4149,3 @@ int PaParseStrings(size_t count,
return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
}
-
-} // namespace sh