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:
parent
4f72970ed3
commit
3d2391fb25
7 changed files with 462 additions and 455 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue