HLSL: Support {...} initializer lists that are too short.
This commit is contained in:
@@ -1896,7 +1896,8 @@ bool HlslGrammar::acceptExpression(TIntermTyped*& node)
|
||||
}
|
||||
|
||||
// initializer
|
||||
// : LEFT_BRACE initializer_list RIGHT_BRACE
|
||||
// : LEFT_BRACE RIGHT_BRACE
|
||||
// | LEFT_BRACE initializer_list RIGHT_BRACE
|
||||
//
|
||||
// initializer_list
|
||||
// : assignment_expression COMMA assignment_expression COMMA ...
|
||||
@@ -1907,8 +1908,15 @@ bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
|
||||
if (! acceptTokenClass(EHTokLeftBrace))
|
||||
return false;
|
||||
|
||||
// initializer_list
|
||||
// RIGHT_BRACE
|
||||
TSourceLoc loc = token.loc;
|
||||
if (acceptTokenClass(EHTokRightBrace)) {
|
||||
// a zero-length initializer list
|
||||
node = intermediate.makeAggregate(loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
// initializer_list
|
||||
node = nullptr;
|
||||
do {
|
||||
// assignment_expression
|
||||
|
||||
@@ -4594,7 +4594,8 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm
|
||||
// constructor-style subtree, allowing the rest of the code to operate
|
||||
// identically for both kinds of initializers.
|
||||
//
|
||||
initializer = convertInitializerList(loc, variable->getType(), initializer);
|
||||
if (initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull)
|
||||
initializer = convertInitializerList(loc, variable->getType(), initializer);
|
||||
if (! initializer) {
|
||||
// error recovery; don't leave const without constant values
|
||||
if (qualifier == EvqConst)
|
||||
@@ -4679,8 +4680,15 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
|
||||
// see if we have bottomed out in the tree within the initializer-list part
|
||||
TIntermAggregate* initList = initializer->getAsAggregate();
|
||||
if (! initList || initList->getOp() != EOpNull)
|
||||
return initializer;
|
||||
if (! initList || initList->getOp() != EOpNull) {
|
||||
// We don't have a list, but if it's a scalar and the 'type' is a
|
||||
// composite, we need to lengthen below to make it useful.
|
||||
// Otherwise, this is an already formed object to initialize with.
|
||||
if (type.isScalar() || !initializer->getType().isScalar())
|
||||
return initializer;
|
||||
else
|
||||
initList = intermediate.makeAggregate(initializer);
|
||||
}
|
||||
|
||||
// Of the initializer-list set of nodes, need to process bottom up,
|
||||
// so recurse deep, then process on the way up.
|
||||
@@ -4694,7 +4702,8 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
arrayType.newArraySizes(*type.getArraySizes()); // but get a fresh copy of the array information, to edit below
|
||||
|
||||
// edit array sizes to fill in unsized dimensions
|
||||
arrayType.changeOuterArraySize((int)initList->getSequence().size());
|
||||
if (type.isImplicitlySizedArray())
|
||||
arrayType.changeOuterArraySize((int)initList->getSequence().size());
|
||||
TIntermTyped* firstInit = initList->getSequence()[0]->getAsTyped();
|
||||
if (arrayType.isArrayOfArrays() && firstInit->getType().isArray() &&
|
||||
arrayType.getArraySizes().getNumDims() == firstInit->getType().getArraySizes()->getNumDims() + 1) {
|
||||
@@ -4704,8 +4713,12 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
}
|
||||
}
|
||||
|
||||
// lengthen list to be long enough
|
||||
lengthenList(loc, initList->getSequence(), arrayType.getOuterArraySize());
|
||||
|
||||
// recursively process each element
|
||||
TType elementType(arrayType, 0); // dereferenced type
|
||||
for (size_t i = 0; i < initList->getSequence().size(); ++i) {
|
||||
for (int i = 0; i < arrayType.getOuterArraySize(); ++i) {
|
||||
initList->getSequence()[i] = convertInitializerList(loc, elementType, initList->getSequence()[i]->getAsTyped());
|
||||
if (initList->getSequence()[i] == nullptr)
|
||||
return nullptr;
|
||||
@@ -4713,6 +4726,9 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
|
||||
return addConstructor(loc, initList, arrayType);
|
||||
} else if (type.isStruct()) {
|
||||
// lengthen list to be long enough
|
||||
lengthenList(loc, initList->getSequence(), type.getStruct()->size());
|
||||
|
||||
if (type.getStruct()->size() != initList->getSequence().size()) {
|
||||
error(loc, "wrong number of structure members", "initializer list", "");
|
||||
return nullptr;
|
||||
@@ -4728,6 +4744,9 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
// a series of rows and columns. We can just use the list directly as
|
||||
// a constructor; no further processing needed.
|
||||
} else {
|
||||
// lengthen list to be long enough
|
||||
lengthenList(loc, initList->getSequence(), type.getMatrixCols());
|
||||
|
||||
if (type.getMatrixCols() != (int)initList->getSequence().size()) {
|
||||
error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str());
|
||||
return nullptr;
|
||||
@@ -4740,6 +4759,10 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
}
|
||||
}
|
||||
} else if (type.isVector()) {
|
||||
// lengthen list to be long enough
|
||||
lengthenList(loc, initList->getSequence(), type.getVectorSize());
|
||||
|
||||
// error check; we're at bottom, so work is finished below
|
||||
if (type.getVectorSize() != (int)initList->getSequence().size()) {
|
||||
error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str());
|
||||
return nullptr;
|
||||
@@ -4749,7 +4772,7 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
error(loc, "scalar expected one element:", "initializer list", type.getCompleteString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
@@ -4761,9 +4784,19 @@ TIntermTyped* HlslParseContext::convertInitializerList(const TSourceLoc& loc, co
|
||||
emulatedConstructorArguments = initList->getSequence()[0];
|
||||
else
|
||||
emulatedConstructorArguments = initList;
|
||||
|
||||
return addConstructor(loc, emulatedConstructorArguments, type);
|
||||
}
|
||||
|
||||
// Lengthen list to be long enough to cover any gap from the current list size
|
||||
// to 'size'. If the list is longer, do nothing.
|
||||
// The value to lengthen with is the default for short lists.
|
||||
void HlslParseContext::lengthenList(const TSourceLoc& loc, TIntermSequence& list, int size)
|
||||
{
|
||||
for (int c = (int)list.size(); c < size; ++c)
|
||||
list.push_back(intermediate.addConstantUnion(0, loc));
|
||||
}
|
||||
|
||||
//
|
||||
// Test for the correctness of the parameters passed to various constructor functions
|
||||
// and also convert them to the right data type, if allowed and required.
|
||||
|
||||
@@ -128,6 +128,7 @@ public:
|
||||
const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
|
||||
void declareTypedef(const TSourceLoc&, TString& identifier, const TType&, TArraySizes* typeArray = 0);
|
||||
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, TType&, TIntermTyped* initializer = 0);
|
||||
void lengthenList(const TSourceLoc&, TIntermSequence& list, int size);
|
||||
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&);
|
||||
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
|
||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
|
||||
|
||||
Reference in New Issue
Block a user