diff options
Diffstat (limited to 'gfx/angle/src/compiler/translator/ParseContext.cpp')
-rwxr-xr-x | gfx/angle/src/compiler/translator/ParseContext.cpp | 1775 |
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 ¶m = function->getParam(i); + const TConstParameter ¶m = 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 ¶m = (*function)->getParam(i); + const TConstParameter ¶m = 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 |