Non-functional. Rationalizations enabling future generalizations:

- Use much simpler method to update implicit array sizes.
  The previous overly complicated method was error prone.
- Rationalize all use of unsized arrays.
- Combine decorations when generating SPIR-V, to simplify
  adding extensions.
This commit is contained in:
John Kessenich
2018-03-28 18:01:20 -06:00
parent 2316924b09
commit ead8622484
25 changed files with 563 additions and 583 deletions

View File

@@ -2569,8 +2569,8 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
TArraySizes* arraySizes = nullptr;
acceptArraySpecifier(arraySizes);
if (arraySizes) {
if (arraySizes->isImplicit()) {
parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", "");
if (arraySizes->hasUnsized()) {
parseContext.error(token.loc, "function parameter requires array size", "[]", "");
return false;
}

View File

@@ -829,6 +829,9 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc,
} else {
// at least one of base and index is variable...
if (index->getQualifier().isFrontEndConstant())
checkIndex(loc, base->getType(), indexValue);
if (base->getType().isScalarOrVec1())
result = base;
else if (base->getAsSymbolNode() && wasFlattened(base)) {
@@ -839,14 +842,11 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc,
flattened = (result != base);
} else {
if (index->getQualifier().isFrontEndConstant()) {
if (base->getType().isImplicitlySizedArray())
updateImplicitArraySize(loc, base, indexValue);
else
checkIndex(loc, base->getType(), indexValue);
if (base->getType().isUnsizedArray())
base->getWritableType().updateImplicitArraySize(indexValue + 1);
result = intermediate.addIndex(EOpIndexDirect, base, index, loc);
} else {
} else
result = intermediate.addIndex(EOpIndexIndirect, base, index, loc);
}
}
}
@@ -1318,7 +1318,7 @@ int HlslParseContext::flattenArray(const TVariable& variable, const TType& type,
TFlattenData& flattenData, TString name, bool linkage,
const TQualifier& outerQualifier)
{
assert(type.isArray() && !type.isImplicitlySizedArray());
assert(type.isSizedArray());
const int size = type.getOuterArraySize();
const TType dereferencedType(type, 0);
@@ -3442,16 +3442,16 @@ void HlslParseContext::decomposeStructBufferMethods(const TSourceLoc& loc, TInte
TIntermAggregate* body = nullptr;
// Length output:
if (argArray->getType().isRuntimeSizedArray()) {
TIntermTyped* lengthCall = intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, argArray,
argNumItems->getType());
TIntermTyped* assign = intermediate.addAssign(EOpAssign, argNumItems, lengthCall, loc);
body = intermediate.growAggregate(body, assign, loc);
} else {
if (argArray->getType().isSizedArray()) {
const int length = argArray->getType().getOuterArraySize();
TIntermTyped* assign = intermediate.addAssign(EOpAssign, argNumItems,
intermediate.addConstantUnion(length, loc, true), loc);
body = intermediate.growAggregate(body, assign, loc);
} else {
TIntermTyped* lengthCall = intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, argArray,
argNumItems->getType());
TIntermTyped* assign = intermediate.addAssign(EOpAssign, argNumItems, lengthCall, loc);
body = intermediate.growAggregate(body, assign, loc);
}
// Stride output:
@@ -6295,7 +6295,7 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node
bool arrayArg = false;
for (int arg = 0; arg < function.getParamCount(); ++arg) {
if (function[arg].type->isArray()) {
if (! function[arg].type->isExplicitlySizedArray()) {
if (function[arg].type->isUnsizedArray()) {
// Can't construct from an unsized array.
error(loc, "array argument must be sized", "constructor", "");
return true;
@@ -6330,11 +6330,10 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node
return true;
}
if (type.isImplicitlySizedArray()) {
if (type.isUnsizedArray()) {
// auto adapt the constructor type to the number of arguments
type.changeOuterArraySize(function.getParamCount());
} else if (type.getOuterArraySize() != function.getParamCount() &&
type.computeNumComponents() > size) {
} else if (type.getOuterArraySize() != function.getParamCount() && type.computeNumComponents() > size) {
error(loc, "array constructor needs one argument per array element", "constructor", "");
return true;
}
@@ -6352,7 +6351,7 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node
return true;
}
if (arraySizes.isInnerImplicit()) {
if (arraySizes.isInnerUnsized()) {
// "Arrays of arrays ..., and the size for any dimension is optional"
// That means we need to adopt (from the first argument) the other array sizes into the type.
for (int d = 1; d < arraySizes.getNumDims(); ++d) {
@@ -6607,7 +6606,7 @@ void HlslParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr,
//
void HlslParseContext::arraySizeRequiredCheck(const TSourceLoc& loc, const TArraySizes& arraySizes)
{
if (arraySizes.isImplicit())
if (arraySizes.hasUnsized())
error(loc, "array size required", "", "");
}
@@ -6667,7 +6666,7 @@ void HlslParseContext::declareArray(const TSourceLoc& loc, const TString& identi
// redeclareBuiltinVariable() should have already done the copyUp()
TType& existingType = symbol->getWritableType();
if (existingType.isExplicitlySizedArray()) {
if (existingType.isSizedArray()) {
// be more lenient for input arrays to geometry shaders and tessellation control outputs,
// where the redeclaration is the same size
return;
@@ -6676,52 +6675,6 @@ void HlslParseContext::declareArray(const TSourceLoc& loc, const TString& identi
existingType.updateArraySizes(type);
}
void HlslParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode *node, int index)
{
// maybe there is nothing to do...
TIntermTyped* typedNode = node->getAsTyped();
if (typedNode->getType().getImplicitArraySize() > index)
return;
// something to do...
// Figure out what symbol to lookup, as we will use its type to edit for the size change,
// as that type will be shared through shallow copies for future references.
TSymbol* symbol = nullptr;
int blockIndex = -1;
const TString* lookupName = nullptr;
if (node->getAsSymbolNode())
lookupName = &node->getAsSymbolNode()->getName();
else if (node->getAsBinaryNode()) {
const TIntermBinary* deref = node->getAsBinaryNode();
// This has to be the result of a block dereference, unless it's bad shader code
// If it's a uniform block, then an error will be issued elsewhere, but
// return early now to avoid crashing later in this function.
if (! deref->getLeft()->getAsSymbolNode() || deref->getLeft()->getBasicType() != EbtBlock ||
deref->getLeft()->getType().getQualifier().storage == EvqUniform ||
deref->getRight()->getAsConstantUnion() == nullptr)
return;
blockIndex = deref->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
lookupName = &deref->getLeft()->getAsSymbolNode()->getName();
if (IsAnonymous(*lookupName))
lookupName = &(*deref->getLeft()->getType().getStruct())[blockIndex].type->getFieldName();
}
// Lookup the symbol, should only fail if shader code is incorrect
symbol = symbolTable.find(*lookupName);
if (symbol == nullptr)
return;
if (symbol->getAsFunction()) {
error(loc, "array variable name expected", symbol->getName().c_str(), "");
return;
}
symbol->getWritableType().setImplicitArraySize(index + 1);
}
//
// Enforce non-initializer type/qualifier rules.
//
@@ -6785,7 +6738,7 @@ TIntermTyped* HlslParseContext::indexStructBufferContent(const TSourceLoc& loc,
//
TType* HlslParseContext::getStructBufferContentType(const TType& type) const
{
if (type.getBasicType() != EbtBlock)
if (type.getBasicType() != EbtBlock || type.getQualifier().storage != EvqBuffer)
return nullptr;
const int memberCount = (int)type.getStruct()->size();
@@ -6793,7 +6746,7 @@ TType* HlslParseContext::getStructBufferContentType(const TType& type) const
TType* contentType = (*type.getStruct())[memberCount-1].type;
return contentType->isRuntimeSizedArray() ? contentType : nullptr;
return contentType->isUnsizedArray() ? contentType : nullptr;
}
//
@@ -7922,8 +7875,7 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm
}
// Fix outer arrayness if variable is unsized, getting size from the initializer
if (initializer->getType().isExplicitlySizedArray() &&
variable->getType().isImplicitlySizedArray())
if (initializer->getType().isSizedArray() && variable->getType().isUnsizedArray())
variable->getWritableType().changeOuterArraySize(initializer->getType().getOuterArraySize());
// Inner arrayness can also get set by an initializer
@@ -8025,7 +7977,7 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
arrayType.copyArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below
// edit array sizes to fill in unsized dimensions
if (type.isImplicitlySizedArray())
if (type.isUnsizedArray())
arrayType.changeOuterArraySize((int)initList->getSequence().size());
// set unsized array dimensions that can be derived from the initializer's first element
@@ -9621,7 +9573,7 @@ void HlslParseContext::addPatchConstantInvocation()
const TType& type = *patchConstantFunction[param].type;
const TBuiltInVariable biType = patchConstantFunction[param].getDeclaredBuiltIn();
return type.isArray() && !type.isRuntimeSizedArray() && biType == EbvOutputPatch;
return type.isSizedArray() && biType == EbvOutputPatch;
};
// We will perform these steps. Each is in a scoped block for separation: they could

View File

@@ -164,8 +164,6 @@ public:
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&);
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
void nestLooping() { ++loopNestingLevel; }
void unnestLooping() { --loopNestingLevel; }
void nestAnnotations() { ++annotationNestingLevel; }