Implement GL_NV_cooperative_matrix

This commit is contained in:
Jeff Bolz 2019-02-19 13:10:32 -06:00
parent ec484527b6
commit 4605e2ed2b
37 changed files with 5630 additions and 4211 deletions

138
glslang/MachineIndependent/ParseHelper.cpp Executable file → Normal file
View file

@ -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