GLSL/SPV: Propagaet precision qualifier from function to return value.

When a return value's type has no precision qualification (e.g., the return
expression is formed from a constructor), and the formal function return type
has a precision qualification, back propagate that from the return type to the
type of the return value's expression.
This commit is contained in:
John Kessenich 2020-07-15 23:38:47 -06:00
parent 4f72970ed3
commit 3d2391fb25
7 changed files with 462 additions and 455 deletions

View file

@ -1231,6 +1231,7 @@ public:
TOperator getFlowOp() const { return flowOp; }
TIntermTyped* getExpression() const { return expression; }
void setExpression(TIntermTyped* pExpression) { expression = pExpression; }
void updatePrecision(TPrecisionQualifier parentPrecision);
protected:
TOperator flowOp;
TIntermTyped* expression;

View file

@ -2777,6 +2777,22 @@ TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expres
return node;
}
// Propagate precision from formal function return type to actual return type,
// and on to its subtree.
void TIntermBranch::updatePrecision(TPrecisionQualifier parentPrecision)
{
TIntermTyped* exp = getExpression();
if (exp == nullptr)
return;
if (exp->getBasicType() == EbtInt || exp->getBasicType() == EbtUint ||
exp->getBasicType() == EbtFloat || exp->getBasicType() == EbtFloat16) {
if (parentPrecision != EpqNone && exp->getQualifier().precision == EpqNone) {
exp->propagatePrecision(parentPrecision);
}
}
}
//
// This is to be executed after the final root is put on top by the parsing
// process.
@ -3284,9 +3300,11 @@ bool TIntermediate::promoteUnary(TIntermUnary& node)
return true;
}
// Propagate precision qualifiers *up* from children to parent.
void TIntermUnary::updatePrecision()
{
if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
if (operand->getQualifier().precision > getQualifier().precision)
getQualifier().precision = operand->getQualifier().precision;
}
@ -3782,9 +3800,12 @@ bool TIntermediate::promoteAggregate(TIntermAggregate& node)
return false;
}
// Propagate precision qualifiers *up* from children to parent, and then
// back *down* again to the children's subtrees.
void TIntermBinary::updatePrecision()
{
if (getBasicType() == EbtInt || getBasicType() == EbtUint || getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
if (getBasicType() == EbtInt || getBasicType() == EbtUint ||
getBasicType() == EbtFloat || getBasicType() == EbtFloat16) {
getQualifier().precision = std::max(right->getQualifier().precision, left->getQualifier().precision);
if (getQualifier().precision != EpqNone) {
left->propagatePrecision(getQualifier().precision);
@ -3793,9 +3814,14 @@ void TIntermBinary::updatePrecision()
}
}
// Recursively propagate precision qualifiers *down* the subtree of the current node,
// until reaching a node that already has a precision qualifier or otherwise does
// not participate in precision propagation.
void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
{
if (getQualifier().precision != EpqNone || (getBasicType() != EbtInt && getBasicType() != EbtUint && getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
if (getQualifier().precision != EpqNone ||
(getBasicType() != EbtInt && getBasicType() != EbtUint &&
getBasicType() != EbtFloat && getBasicType() != EbtFloat16))
return;
getQualifier().precision = newPrecision;

View file

@ -1415,23 +1415,28 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType
#endif
functionReturnsValue = true;
TIntermBranch* branch = nullptr;
if (currentFunctionType->getBasicType() == EbtVoid) {
error(loc, "void function cannot return a value", "return", "");
return intermediate.addBranch(EOpReturn, loc);
branch = intermediate.addBranch(EOpReturn, loc);
} else if (*currentFunctionType != value->getType()) {
TIntermTyped* converted = intermediate.addConversion(EOpReturn, *currentFunctionType, value);
if (converted) {
if (*currentFunctionType != converted->getType())
error(loc, "cannot convert return value to function return type", "return", "");
if (version < 420)
warn(loc, "type conversion on return values was not explicitly allowed until version 420", "return", "");
return intermediate.addBranch(EOpReturn, converted, loc);
warn(loc, "type conversion on return values was not explicitly allowed until version 420",
"return", "");
branch = intermediate.addBranch(EOpReturn, converted, loc);
} else {
error(loc, "type does not match, or is not convertible to, the function's return type", "return", "");
return intermediate.addBranch(EOpReturn, value, loc);
branch = intermediate.addBranch(EOpReturn, value, loc);
}
} else
return intermediate.addBranch(EOpReturn, value, loc);
branch = intermediate.addBranch(EOpReturn, value, loc);
branch->updatePrecision(currentFunctionType->getQualifier().precision);
return branch;
}
// See if the operation is being done in an illegal location.