HLSL: Add shape conversions for scalar -> vector assigments.

Also, this allows turning on the error check for a failed assigment
when parsing.

This makes 39 HLSL tests have a working assignment that was previously
silently dropped, due to lack of this functionality.
This commit is contained in:
John Kessenich 2016-07-28 17:53:56 -06:00
parent a26a5170a3
commit fea226ba43
46 changed files with 2571 additions and 1413 deletions

View file

@ -98,6 +98,8 @@ TIntermSymbol* TIntermediate::addSymbol(const TType& type, const TSourceLoc& loc
//
// Returns the added node.
//
// Returns nullptr if the working conversions and promotions could not be found.
//
TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
{
// No operations work on blocks
@ -161,29 +163,38 @@ TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIn
//
// Returns the added node.
//
// Returns nullptr if the 'right' type could not be converted to match the 'left' type,
// or the resulting operation cannot be properly promoted.
//
TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc loc)
{
// No block assignment
if (left->getType().getBasicType() == EbtBlock || right->getType().getBasicType() == EbtBlock)
return 0;
return nullptr;
//
// Like adding binary math, except the conversion can only go
// from right to left.
//
// convert base types, nullptr return means not possible
right = addConversion(op, left->getType(), right);
if (right == nullptr)
return nullptr;
// convert shape
right = addShapeConversion(op, left->getType(), right);
// build the node
TIntermBinary* node = new TIntermBinary(op);
if (loc.line == 0)
loc = left->getLoc();
node->setLoc(loc);
TIntermTyped* child = addConversion(op, left->getType(), right);
if (child == 0)
return 0;
node->setLeft(left);
node->setRight(child);
node->setRight(right);
if (! node->promote())
return 0;
return nullptr;
node->updatePrecision();
@ -414,6 +425,9 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o
// Returns a node representing the conversion, which could be the same
// node passed in if no conversion was needed.
//
// Generally, this is focused on basic type conversion, not shape conversion.
// See addShapeConversion().
//
// Return 0 if a conversion can't be done.
//
TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
@ -681,6 +695,50 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
return newNode;
}
// Convert the node's shape of type for the given type, as allowed by the
// operation involved: 'op'.
//
// Generally, the AST represents allowed GLSL shapes, so this isn't needed
// for GLSL. Bad shapes are caught in conversion or promotion.
//
// Return 'node' if no conversion was done. Promotion handles final shape
// checking.
//
TIntermTyped* TIntermediate::addShapeConversion(TOperator op, const TType& type, TIntermTyped* node)
{
// some source languages don't do this
switch (source) {
case EShSourceHlsl:
break;
case EShSourceGlsl:
default:
return node;
}
// some operations don't do this
switch (op) {
case EOpAssign:
break;
default:
return node;
}
// structures and arrays don't change shape, either to or from
if (node->getType().isStruct() || node->getType().isArray() ||
type.isStruct() || type.isArray())
return node;
// The new node that handles the conversion
TIntermTyped* conversionNode = node;
TOperator constructorOp = mapTypeToConstructorOp(type);
// scalar -> smeared -> vector
if (type.isVector() && node->getType().isScalar())
return setAggregateOperator(node, constructorOp, type, node->getLoc());
return node;
}
//
// See if the 'from' type is allowed to be implicitly converted to the
// 'to' type. This is not about vector/array/struct, only about basic type.