Update function overload resolution logic.

Closer compatibility with C++: given a non-reference type, treat matching
to a non-const reference of that type as a better match than a const
reference of that type (rather than both being equal cost).

Issue #224.
This commit is contained in:
Matt Pharr
2012-04-03 10:40:41 -07:00
parent 4cd0cf1650
commit 391678a5b3
2 changed files with 67 additions and 16 deletions

View File

@@ -7498,6 +7498,23 @@ lPrintOverloadCandidates(SourcePos pos, const std::vector<Symbol *> &funcs,
} }
static bool
lIsMatchToNonConstReference(const Type *callType, const Type *funcArgType) {
return (dynamic_cast<const ReferenceType *>(funcArgType) &&
(funcArgType->IsConstType() == false) &&
Type::Equal(callType, funcArgType->GetReferenceTarget()));
}
static bool
lIsMatchToNonConstReferenceUnifToVarying(const Type *callType,
const Type *funcArgType) {
return (dynamic_cast<const ReferenceType *>(funcArgType) &&
(funcArgType->IsConstType() == false) &&
Type::Equal(callType->GetAsVaryingType(),
funcArgType->GetReferenceTarget()));
}
/** Helper function used for function overload resolution: returns true if /** Helper function used for function overload resolution: returns true if
converting the argument to the call type only requires a type converting the argument to the call type only requires a type
conversion that won't lose information. Otherwise return false. conversion that won't lose information. Otherwise return false.
@@ -7597,6 +7614,20 @@ FunctionSymbolExpr::getCandidateFunctions(int argCount) const {
} }
static bool
lArgIsPointerType(const Type *type) {
if (dynamic_cast<const PointerType *>(type) != NULL)
return true;
const ReferenceType *rt = dynamic_cast<const ReferenceType *>(type);
if (rt == NULL)
return false;
const Type *t = rt->GetReferenceTarget();
return (dynamic_cast<const PointerType *>(t) != NULL);
}
/** This function computes the value of a cost function that represents the /** This function computes the value of a cost function that represents the
cost of calling a function of the given type with arguments of the cost of calling a function of the given type with arguments of the
given types. If it's not possible to call the function, regardless of given types. If it's not possible to call the function, regardless of
@@ -7623,19 +7654,11 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
const Type *fargType = ftype->GetParameterType(i); const Type *fargType = ftype->GetParameterType(i);
const Type *callType = argTypes[i]; const Type *callType = argTypes[i];
// For convenience, normalize to non-const types (except for
// references, where const-ness matters). For all other types,
// we're passing by value anyway, so const doesn't matter.
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
callType = callType->GetAsNonConstType();
if (dynamic_cast<const ReferenceType *>(fargType) == NULL)
fargType = fargType->GetAsNonConstType();
if (Type::Equal(callType, fargType)) if (Type::Equal(callType, fargType))
// Perfect match: no cost // Perfect match: no cost
costSum += 0; costSum += 0;
else if (argCouldBeNULL && (*argCouldBeNULL)[i] && else if (argCouldBeNULL && (*argCouldBeNULL)[i] &&
dynamic_cast<const PointerType *>(fargType) != NULL) lArgIsPointerType(fargType))
// Passing NULL to a pointer-typed parameter is also a no-cost // Passing NULL to a pointer-typed parameter is also a no-cost
// operation // operation
costSum += 0; costSum += 0;
@@ -7645,19 +7668,33 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
// cost if it wasn't--so scale up the cost when this isn't the // cost if it wasn't--so scale up the cost when this isn't the
// case.. // case..
if (argIsConstant == NULL || (*argIsConstant)[i] == false) if (argIsConstant == NULL || (*argIsConstant)[i] == false)
costScale *= 32; costScale *= 128;
if (Type::Equal(callType, fargType)) // For convenience, normalize to non-const types (except for
// references, where const-ness matters). For all other types,
// we're passing by value anyway, so const doesn't matter.
const Type *callTypeNC = callType, *fargTypeNC = fargType;
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
callTypeNC = callType->GetAsNonConstType();
if (dynamic_cast<const ReferenceType *>(fargType) == NULL)
fargTypeNC = fargType->GetAsNonConstType();
if (Type::Equal(callTypeNC, fargTypeNC))
// Exact match (after dealing with references, above) // Exact match (after dealing with references, above)
costSum += 1 * costScale; costSum += 1 * costScale;
else if (lIsMatchWithTypeWidening(callType, fargType)) // note: orig fargType for the next two...
else if (lIsMatchToNonConstReference(callTypeNC, fargType))
costSum += 2 * costScale; costSum += 2 * costScale;
else if (lIsMatchWithUniformToVarying(callType, fargType)) else if (lIsMatchToNonConstReferenceUnifToVarying(callTypeNC, fargType))
costSum += 4 * costScale; costSum += 4 * costScale;
else if (lIsMatchWithTypeConvSameVariability(callType, fargType)) else if (lIsMatchWithTypeWidening(callTypeNC, fargTypeNC))
costSum += 8 * costScale; costSum += 8 * costScale;
else if (CanConvertTypes(callType, fargType)) else if (lIsMatchWithUniformToVarying(callTypeNC, fargTypeNC))
costSum += 16 * costScale; costSum += 16 * costScale;
else if (lIsMatchWithTypeConvSameVariability(callTypeNC, fargTypeNC))
costSum += 32 * costScale;
else if (CanConvertTypes(callTypeNC, fargTypeNC))
costSum += 64 * costScale;
else else
// Failure--no type conversion possible... // Failure--no type conversion possible...
return -1; return -1;

View File

@@ -0,0 +1,14 @@
export uniform int width() { return programCount; }
float foo(float &a) { return 1; }
float foo(const float &a) { return 2; }
export void f_f(uniform float RET[], uniform float aFOO[]) {
float x = 0;
RET[programIndex] = foo(x);
}
export void result(uniform float RET[]) {
RET[programIndex] = 1;
}