|
|
@@ -275,6 +275,12 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector<TString>&
|
|
|
if (tokens.size() != 1)
|
|
|
error(loc, "extra tokens", "#pragma", "");
|
|
|
intermediate.setUseVulkanMemoryModel();
|
|
|
+ } else if (spvVersion.spv > 0 && tokens[0].compare("use_variable_pointers") == 0) {
|
|
|
+ if (tokens.size() != 1)
|
|
|
+ error(loc, "extra tokens", "#pragma", "");
|
|
|
+ if (spvVersion.spv < glslang::EShTargetSpv_1_3)
|
|
|
+ error(loc, "requires SPIR-V 1.3", "#pragma use_variable_pointers", "");
|
|
|
+ intermediate.setUseVariablePointers();
|
|
|
} else if (tokens[0].compare("once") == 0) {
|
|
|
warn(loc, "not implemented", "#pragma once", "");
|
|
|
} else if (tokens[0].compare("glslang_binary_double_output") == 0)
|
|
|
@@ -371,7 +377,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn
|
|
|
// basic type checks...
|
|
|
variableCheck(base);
|
|
|
|
|
|
- if (! base->isArray() && ! base->isMatrix() && ! base->isVector()) {
|
|
|
+ if (! base->isArray() && ! base->isMatrix() && ! base->isVector() && ! base->getType().isCoopMat()) {
|
|
|
if (base->getAsSymbolNode())
|
|
|
error(loc, " left of '[' is not of type array, matrix, or vector ", base->getAsSymbolNode()->getName().c_str(), "");
|
|
|
else
|
|
|
@@ -767,7 +773,7 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|
|
const char* feature = ".length() on vectors and matrices";
|
|
|
requireProfile(loc, ~EEsProfile, feature);
|
|
|
profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, feature);
|
|
|
- } else {
|
|
|
+ } else if (!base->getType().isCoopMat()) {
|
|
|
error(loc, "does not operate on this type:", field.c_str(), base->getType().getCompleteString().c_str());
|
|
|
|
|
|
return base;
|
|
|
@@ -784,6 +790,11 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm
|
|
|
return base;
|
|
|
}
|
|
|
|
|
|
+ if (base->getType().isCoopMat()) {
|
|
|
+ error(loc, "cannot apply to a cooperative matrix type:", ".", field.c_str());
|
|
|
+ return base;
|
|
|
+ }
|
|
|
+
|
|
|
// It's neither an array nor .length() if we get here,
|
|
|
// leaving swizzles and struct/block dereferences.
|
|
|
|
|
|
@@ -1204,6 +1215,13 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
|
|
|
}
|
|
|
result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
|
|
|
}
|
|
|
+
|
|
|
+ if (result->getAsTyped()->getType().isCoopMat() &&
|
|
|
+ !result->getAsTyped()->getType().isParameterized()) {
|
|
|
+ assert(fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAdd);
|
|
|
+
|
|
|
+ result->setType(result->getAsAggregate()->getSequence()[2]->getAsTyped()->getType());
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1430,6 +1448,8 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction
|
|
|
length = type.getMatrixCols();
|
|
|
else if (type.isVector())
|
|
|
length = type.getVectorSize();
|
|
|
+ else if (type.isCoopMat())
|
|
|
+ return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt));
|
|
|
else {
|
|
|
// we should not get here, because earlier semantic checking should have prevented this path
|
|
|
error(loc, ".length()", "unexpected use of .length()", "");
|
|
|
@@ -1456,7 +1476,8 @@ void TParseContext::addInputArgumentConversions(const TFunction& function, TInte
|
|
|
// means take 'arguments' itself as the one argument.
|
|
|
TIntermTyped* arg = function.getParamCount() == 1 ? arguments->getAsTyped() : (aggregate ? aggregate->getSequence()[i]->getAsTyped() : arguments->getAsTyped());
|
|
|
if (*function[i].type != arg->getType()) {
|
|
|
- if (function[i].type->getQualifier().isParamInput()) {
|
|
|
+ if (function[i].type->getQualifier().isParamInput() &&
|
|
|
+ !function[i].type->isCoopMat()) {
|
|
|
// In-qualified arguments just need an extra node added above the argument to
|
|
|
// convert to the correct type.
|
|
|
arg = intermediate.addConversion(EOpFunctionCall, *function[i].type, arg);
|
|
|
@@ -1524,7 +1545,14 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct
|
|
|
if (function[i].type->getQualifier().isParamOutput()) {
|
|
|
// Out-qualified arguments need to use the topology set up above.
|
|
|
// do the " ...(tempArg, ...), arg = tempArg" bit from above
|
|
|
- TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type);
|
|
|
+ TType paramType;
|
|
|
+ paramType.shallowCopy(*function[i].type);
|
|
|
+ if (arguments[i]->getAsTyped()->getType().isParameterized() &&
|
|
|
+ !paramType.isParameterized()) {
|
|
|
+ paramType.shallowCopy(arguments[i]->getAsTyped()->getType());
|
|
|
+ paramType.copyTypeParameters(*arguments[i]->getAsTyped()->getType().getTypeParameters());
|
|
|
+ }
|
|
|
+ TVariable* tempArg = makeInternalVariable("tempArg", paramType);
|
|
|
tempArg->getWritableType().getQualifier().makeTemporary();
|
|
|
TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc());
|
|
|
TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc());
|
|
|
@@ -2913,6 +2941,16 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ if (type.isCoopMat() && function.getParamCount() != 1) {
|
|
|
+ error(loc, "wrong number of arguments", "constructor", "");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (type.isCoopMat() &&
|
|
|
+ !(function[0].type->isScalar() || function[0].type->isCoopMat())) {
|
|
|
+ error(loc, "Cooperative matrix constructor argument must be scalar or cooperative matrix", "constructor", "");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
TIntermTyped* typed = node->getAsTyped();
|
|
|
if (typed == nullptr) {
|
|
|
error(loc, "constructor argument does not have a type", "constructor", "");
|
|
|
@@ -3534,7 +3572,7 @@ bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType bas
|
|
|
//
|
|
|
// Do size checking for an array type's size.
|
|
|
//
|
|
|
-void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair)
|
|
|
+void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair, const char *sizeType)
|
|
|
{
|
|
|
bool isConst = false;
|
|
|
sizePair.node = nullptr;
|
|
|
@@ -3554,18 +3592,24 @@ void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TA
|
|
|
TIntermSymbol* symbol = expr->getAsSymbolNode();
|
|
|
if (symbol && symbol->getConstArray().size() > 0)
|
|
|
size = symbol->getConstArray()[0].getIConst();
|
|
|
+ } else if (expr->getAsUnaryNode() &&
|
|
|
+ expr->getAsUnaryNode()->getOp() == glslang::EOpArrayLength &&
|
|
|
+ expr->getAsUnaryNode()->getOperand()->getType().isCoopMat()) {
|
|
|
+ isConst = true;
|
|
|
+ size = 1;
|
|
|
+ sizePair.node = expr->getAsUnaryNode();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
sizePair.size = size;
|
|
|
|
|
|
if (! isConst || (expr->getBasicType() != EbtInt && expr->getBasicType() != EbtUint)) {
|
|
|
- error(loc, "array size must be a constant integer expression", "", "");
|
|
|
+ error(loc, sizeType, "", "must be a constant integer expression");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (size <= 0) {
|
|
|
- error(loc, "array size must be a positive integer", "", "");
|
|
|
+ error(loc, sizeType, "", "must be a positive integer");
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
@@ -3623,7 +3667,7 @@ bool TParseContext::arrayError(const TSourceLoc& loc, const TType& type)
|
|
|
//
|
|
|
void TParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes)
|
|
|
{
|
|
|
- if (arraySizes.hasUnsized())
|
|
|
+ if (!parsingBuiltins && arraySizes.hasUnsized())
|
|
|
error(loc, "array size required", "", "");
|
|
|
}
|
|
|
|
|
|
@@ -3660,7 +3704,8 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua
|
|
|
arraySizes->clearInnerUnsized();
|
|
|
}
|
|
|
|
|
|
- if (arraySizes->isInnerSpecialization())
|
|
|
+ if (arraySizes->isInnerSpecialization() &&
|
|
|
+ (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal && qualifier.storage != EvqShared && qualifier.storage != EvqConst))
|
|
|
error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", "");
|
|
|
|
|
|
// desktop always allows outer-dimension-unsized variable arrays,
|
|
|
@@ -6035,9 +6080,18 @@ const TFunction* TParseContext::findFunction400(const TSourceLoc& loc, const TFu
|
|
|
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
|
|
|
|
|
// can 'from' convert to 'to'?
|
|
|
- const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool {
|
|
|
+ const auto convertible = [this,builtIn](const TType& from, const TType& to, TOperator, int) -> bool {
|
|
|
if (from == to)
|
|
|
return true;
|
|
|
+ if (from.coopMatParameterOK(to))
|
|
|
+ return true;
|
|
|
+ // Allow a sized array to be passed through an unsized array parameter, for coopMatLoad/Store functions
|
|
|
+ if (builtIn && from.isArray() && to.isUnsizedArray()) {
|
|
|
+ TType fromElementType(from, 0);
|
|
|
+ TType toElementType(to, 0);
|
|
|
+ if (fromElementType == toElementType)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
|
|
|
return false;
|
|
|
return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
|
|
|
@@ -6100,9 +6154,18 @@ const TFunction* TParseContext::findFunctionExplicitTypes(const TSourceLoc& loc,
|
|
|
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
|
|
|
|
|
// can 'from' convert to 'to'?
|
|
|
- const auto convertible = [this](const TType& from, const TType& to, TOperator, int) -> bool {
|
|
|
+ const auto convertible = [this,builtIn](const TType& from, const TType& to, TOperator, int) -> bool {
|
|
|
if (from == to)
|
|
|
return true;
|
|
|
+ if (from.coopMatParameterOK(to))
|
|
|
+ return true;
|
|
|
+ // Allow a sized array to be passed through an unsized array parameter, for coopMatLoad/Store functions
|
|
|
+ if (builtIn && from.isArray() && to.isUnsizedArray()) {
|
|
|
+ TType fromElementType(from, 0);
|
|
|
+ TType toElementType(to, 0);
|
|
|
+ if (fromElementType == toElementType)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
if (from.isArray() || to.isArray() || ! from.sameElementShape(to))
|
|
|
return false;
|
|
|
return intermediate.canImplicitlyPromote(from.getBasicType(), to.getBasicType());
|
|
|
@@ -6194,6 +6257,25 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|
|
type.copyArrayInnerSizes(publicType.arraySizes);
|
|
|
arrayOfArrayVersionCheck(loc, type.getArraySizes());
|
|
|
|
|
|
+ if (type.isCoopMat()) {
|
|
|
+ intermediate.setUseVulkanMemoryModel();
|
|
|
+ intermediate.setUseStorageBuffer();
|
|
|
+
|
|
|
+ if (!publicType.typeParameters || publicType.typeParameters->getNumDims() != 4) {
|
|
|
+ error(loc, "expected four type parameters", identifier.c_str(), "");
|
|
|
+ }
|
|
|
+ if (publicType.typeParameters &&
|
|
|
+ publicType.typeParameters->getDimSize(0) != 16 &&
|
|
|
+ publicType.typeParameters->getDimSize(0) != 32 &&
|
|
|
+ publicType.typeParameters->getDimSize(0) != 64) {
|
|
|
+ error(loc, "expected 16, 32, or 64 bits for first type parameter", identifier.c_str(), "");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (publicType.typeParameters && publicType.typeParameters->getNumDims() != 0) {
|
|
|
+ error(loc, "unexpected type parameters", identifier.c_str(), "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (voidErrorCheck(loc, identifier, type.getBasicType()))
|
|
|
return nullptr;
|
|
|
|
|
|
@@ -6218,6 +6300,10 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden
|
|
|
requireInt8Arithmetic(loc, "qualifier", "(u)int8 types can only be in uniform block or buffer storage");
|
|
|
}
|
|
|
|
|
|
+ if (type.getQualifier().storage == EvqShared &&
|
|
|
+ type.containsCoopMat())
|
|
|
+ error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", "");
|
|
|
+
|
|
|
if (identifier != "gl_FragCoord" && (publicType.shaderQualifiers.originUpperLeft || publicType.shaderQualifiers.pixelCenterInteger))
|
|
|
error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", "");
|
|
|
if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.layoutDepth != EldNone)
|
|
|
@@ -6809,6 +6895,33 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
+ case EOpConstructCooperativeMatrix:
|
|
|
+ if (!node->getType().isCoopMat()) {
|
|
|
+ if (type.getBasicType() != node->getType().getBasicType()) {
|
|
|
+ node = intermediate.addConversion(type.getBasicType(), node);
|
|
|
+ }
|
|
|
+ node = intermediate.setAggregateOperator(node, EOpConstructCooperativeMatrix, type, node->getLoc());
|
|
|
+ } else {
|
|
|
+ switch (type.getBasicType()) {
|
|
|
+ default:
|
|
|
+ assert(0);
|
|
|
+ break;
|
|
|
+ case EbtFloat:
|
|
|
+ assert(node->getType().getBasicType() == EbtFloat16);
|
|
|
+ node = intermediate.addUnaryNode(EOpConvFloat16ToFloat, node, node->getLoc(), type);
|
|
|
+ break;
|
|
|
+ case EbtFloat16:
|
|
|
+ assert(node->getType().getBasicType() == EbtFloat);
|
|
|
+ node = intermediate.addUnaryNode(EOpConvFloatToFloat16, node, node->getLoc(), type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // If it's a (non-specialization) constant, it must be folded.
|
|
|
+ if (node->getAsUnaryNode()->getOperand()->getAsConstantUnion())
|
|
|
+ return node->getAsUnaryNode()->getOperand()->getAsConstantUnion()->fold(op, node->getType());
|
|
|
+ }
|
|
|
+
|
|
|
+ return node;
|
|
|
+
|
|
|
default:
|
|
|
error(loc, "unsupported construction", "", "");
|
|
|
|
|
|
@@ -6895,6 +7008,9 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|
|
|
|
|
if (memberType.containsOpaque())
|
|
|
error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), "");
|
|
|
+
|
|
|
+ if (memberType.containsCoopMat())
|
|
|
+ error(memberLoc, "member of block cannot be or contain a cooperative matrix type", typeList[member].type->getFieldName().c_str(), "");
|
|
|
}
|
|
|
|
|
|
// This might be a redeclaration of a built-in block. If so, redeclareBuiltinBlock() will
|