Merge branch 'master' into nvptx
This commit is contained in:
186
expr.cpp
186
expr.cpp
@@ -8097,23 +8097,6 @@ lGetOverloadCandidateMessage(const std::vector<Symbol *> &funcs,
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
lIsMatchToNonConstReference(const Type *callType, const Type *funcArgType) {
|
||||
return (CastType<ReferenceType>(funcArgType) &&
|
||||
(funcArgType->IsConstType() == false) &&
|
||||
Type::Equal(callType, funcArgType->GetReferenceTarget()));
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
lIsMatchToNonConstReferenceUnifToVarying(const Type *callType,
|
||||
const Type *funcArgType) {
|
||||
return (CastType<ReferenceType>(funcArgType) &&
|
||||
(funcArgType->IsConstType() == false) &&
|
||||
Type::Equal(callType->GetAsVaryingType(),
|
||||
funcArgType->GetReferenceTarget()));
|
||||
}
|
||||
|
||||
/** Helper function used for function overload resolution: returns true if
|
||||
converting the argument to the call type only requires a type
|
||||
conversion that won't lose information. Otherwise return false.
|
||||
@@ -8160,31 +8143,6 @@ lIsMatchWithTypeWidening(const Type *callType, const Type *funcArgType) {
|
||||
}
|
||||
|
||||
|
||||
/** Helper function used for function overload resolution: returns true if
|
||||
the call argument type and the function argument type match if we only
|
||||
do a uniform -> varying type conversion but otherwise have exactly the
|
||||
same type.
|
||||
*/
|
||||
static bool
|
||||
lIsMatchWithUniformToVarying(const Type *callType, const Type *funcArgType) {
|
||||
return (callType->IsUniformType() &&
|
||||
funcArgType->IsVaryingType() &&
|
||||
Type::EqualIgnoringConst(callType->GetAsVaryingType(), funcArgType));
|
||||
}
|
||||
|
||||
|
||||
/** Helper function used for function overload resolution: returns true if
|
||||
we can type convert from the call argument type to the function
|
||||
argument type, but without doing a uniform -> varying conversion.
|
||||
*/
|
||||
static bool
|
||||
lIsMatchWithTypeConvSameVariability(const Type *callType,
|
||||
const Type *funcArgType) {
|
||||
return (CanConvertTypes(callType, funcArgType) &&
|
||||
(callType->GetVariability() == funcArgType->GetVariability()));
|
||||
}
|
||||
|
||||
|
||||
/* Returns the set of function overloads that are potential matches, given
|
||||
argCount values being passed as arguments to the function call.
|
||||
*/
|
||||
@@ -8236,13 +8194,15 @@ int
|
||||
FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
|
||||
const std::vector<const Type *> &argTypes,
|
||||
const std::vector<bool> *argCouldBeNULL,
|
||||
const std::vector<bool> *argIsConstant) {
|
||||
const std::vector<bool> *argIsConstant,
|
||||
int * cost) {
|
||||
int costSum = 0;
|
||||
|
||||
// In computing the cost function, we only worry about the actual
|
||||
// argument types--using function default parameter values is free for
|
||||
// the purposes here...
|
||||
for (int i = 0; i < (int)argTypes.size(); ++i) {
|
||||
cost[i] = 0;
|
||||
// The cost imposed by this argument will be a multiple of
|
||||
// costScale, which has a value set so that for each of the cost
|
||||
// buckets, even if all of the function arguments undergo the next
|
||||
@@ -8255,51 +8215,105 @@ FunctionSymbolExpr::computeOverloadCost(const FunctionType *ftype,
|
||||
|
||||
if (Type::Equal(callType, fargType))
|
||||
// Perfect match: no cost
|
||||
costSum += 0;
|
||||
// Step "1" from documentation
|
||||
cost[i] += 0;
|
||||
else if (argCouldBeNULL && (*argCouldBeNULL)[i] &&
|
||||
lArgIsPointerType(fargType))
|
||||
// Passing NULL to a pointer-typed parameter is also a no-cost
|
||||
// operation
|
||||
costSum += 0;
|
||||
// Passing NULL to a pointer-typed parameter is also a no-cost operation
|
||||
// Step "1" from documentation
|
||||
cost[i] += 0;
|
||||
else {
|
||||
// If the argument is a compile-time constant, we'd like to
|
||||
// count the cost of various conversions as much lower than the
|
||||
// cost if it wasn't--so scale up the cost when this isn't the
|
||||
// case..
|
||||
if (argIsConstant == NULL || (*argIsConstant)[i] == false)
|
||||
costScale *= 128;
|
||||
costScale *= 512;
|
||||
|
||||
// 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 (CastType<ReferenceType>(callType) == NULL)
|
||||
callTypeNC = callType->GetAsNonConstType();
|
||||
if (CastType<ReferenceType>(fargType) == NULL)
|
||||
fargTypeNC = fargType->GetAsNonConstType();
|
||||
if (CastType<ReferenceType>(fargType)) {
|
||||
// Here we completely handle the case where fargType is reference.
|
||||
if (callType->IsConstType() && !fargType->IsConstType()) {
|
||||
// It is forbidden to pass const object to non-const reference (cvf -> vfr)
|
||||
return -1;
|
||||
}
|
||||
if (!callType->IsConstType() && fargType->IsConstType()) {
|
||||
// It is possible to pass (vf -> cvfr)
|
||||
// but it is worse than (vf -> vfr) or (cvf -> cvfr)
|
||||
// Step "3" from documentation
|
||||
cost[i] += 2 * costScale;
|
||||
}
|
||||
if (!Type::Equal(callType->GetReferenceTarget()->GetAsNonConstType(),
|
||||
fargType->GetReferenceTarget()->GetAsNonConstType())) {
|
||||
// Types under references must be equal completely.
|
||||
// vd -> vfr or vd -> cvfr are forbidden. (Although clang allows vd -> cvfr case.)
|
||||
return -1;
|
||||
}
|
||||
// penalty for equal types under reference (vf -> vfr is worse than vf -> vf)
|
||||
// Step "2" from documentation
|
||||
cost[i] += 2 * costScale;
|
||||
continue;
|
||||
}
|
||||
const Type *callTypeNP = callType;
|
||||
if (CastType<ReferenceType>(callType)) {
|
||||
callTypeNP = callType->GetReferenceTarget();
|
||||
// we can treat vfr as vf for callType with some penalty
|
||||
// Step "5" from documentation
|
||||
cost[i] += 2 * costScale;
|
||||
}
|
||||
|
||||
if (Type::Equal(callTypeNC, fargTypeNC))
|
||||
// Exact match (after dealing with references, above)
|
||||
costSum += 1 * costScale;
|
||||
// note: orig fargType for the next two...
|
||||
else if (lIsMatchToNonConstReference(callTypeNC, fargType))
|
||||
costSum += 2 * costScale;
|
||||
else if (lIsMatchToNonConstReferenceUnifToVarying(callTypeNC, fargType))
|
||||
costSum += 4 * costScale;
|
||||
else if (lIsMatchWithTypeWidening(callTypeNC, fargTypeNC))
|
||||
costSum += 8 * costScale;
|
||||
else if (lIsMatchWithUniformToVarying(callTypeNC, fargTypeNC))
|
||||
costSum += 16 * costScale;
|
||||
else if (lIsMatchWithTypeConvSameVariability(callTypeNC, fargTypeNC))
|
||||
costSum += 32 * costScale;
|
||||
else if (CanConvertTypes(callTypeNC, fargTypeNC))
|
||||
costSum += 64 * costScale;
|
||||
// Now we deal with references, so we can normalize to non-const types
|
||||
// because we're passing by value anyway, so const doesn't matter.
|
||||
const Type *callTypeNC = callTypeNP, *fargTypeNC = fargType;
|
||||
callTypeNC = callTypeNP->GetAsNonConstType();
|
||||
fargTypeNC = fargType->GetAsNonConstType();
|
||||
|
||||
// Now we forget about constants and references!
|
||||
if (Type::Equal(callTypeNC, fargTypeNC)) {
|
||||
// The best case: vf -> vf.
|
||||
// Step "4" from documentation
|
||||
cost[i] += 1 * costScale;
|
||||
continue;
|
||||
}
|
||||
if (lIsMatchWithTypeWidening(callTypeNC, fargTypeNC)) {
|
||||
// A little bit worse case: vf -> vd.
|
||||
// Step "6" from documentation
|
||||
cost[i] += 8 * costScale;
|
||||
continue;
|
||||
}
|
||||
if (fargType->IsVaryingType() && callType->IsUniformType()) {
|
||||
// Here we deal with brodcasting uniform to varying.
|
||||
// callType - varying and fargType - uniform is forbidden.
|
||||
if (Type::Equal(callTypeNC->GetAsVaryingType(), fargTypeNC)) {
|
||||
// uf -> vf is better than uf -> ui or uf -> ud
|
||||
// Step "7" from documentation
|
||||
cost[i] += 16 * costScale;
|
||||
continue;
|
||||
}
|
||||
if (lIsMatchWithTypeWidening(callTypeNC->GetAsVaryingType(), fargTypeNC)) {
|
||||
// uf -> vd is better than uf -> vi (128 < 128 + 64)
|
||||
// but worse than uf -> ui (128 > 64)
|
||||
// Step "9" from documentation
|
||||
cost[i] += 128 * costScale;
|
||||
continue;
|
||||
}
|
||||
// 128 + 64 is the max. uf -> vi is the worst case.
|
||||
// Step "10" from documentation
|
||||
cost[i] += 128 * costScale;
|
||||
}
|
||||
if (CanConvertTypes(callTypeNC, fargTypeNC))
|
||||
// two cases: the worst is 128 + 64: uf -> vi and
|
||||
// the only 64: (64 < 128) uf -> ui worse than uf -> vd
|
||||
// Step "8" from documentation
|
||||
cost[i] += 64 * costScale;
|
||||
else
|
||||
// Failure--no type conversion possible...
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)argTypes.size(); ++i) {
|
||||
costSum = costSum + cost[i];
|
||||
}
|
||||
return costSum;
|
||||
}
|
||||
|
||||
@@ -8334,6 +8348,7 @@ FunctionSymbolExpr::ResolveOverloads(SourcePos argPos,
|
||||
int bestMatchCost = 1<<30;
|
||||
std::vector<Symbol *> matches;
|
||||
std::vector<int> candidateCosts;
|
||||
std::vector<int*> candidateExpandCosts;
|
||||
|
||||
if (actualCandidates.size() == 0)
|
||||
goto failure;
|
||||
@@ -8343,9 +8358,12 @@ FunctionSymbolExpr::ResolveOverloads(SourcePos argPos,
|
||||
const FunctionType *ft =
|
||||
CastType<FunctionType>(actualCandidates[i]->type);
|
||||
AssertPos(pos, ft != NULL);
|
||||
int * cost = new int[argTypes.size()];
|
||||
candidateCosts.push_back(computeOverloadCost(ft, argTypes,
|
||||
argCouldBeNULL,
|
||||
argIsConstant));
|
||||
argIsConstant,
|
||||
cost));
|
||||
candidateExpandCosts.push_back(cost);
|
||||
}
|
||||
|
||||
// Find the best cost, and then the candidate or candidates that have
|
||||
@@ -8358,8 +8376,28 @@ FunctionSymbolExpr::ResolveOverloads(SourcePos argPos,
|
||||
if (bestMatchCost == (1<<30))
|
||||
goto failure;
|
||||
for (int i = 0; i < (int)candidateCosts.size(); ++i) {
|
||||
if (candidateCosts[i] == bestMatchCost)
|
||||
if (candidateCosts[i] == bestMatchCost) {
|
||||
for (int j = 0; j < (int)candidateCosts.size(); ++j) {
|
||||
for (int k = 0; k < argTypes.size(); k++) {
|
||||
if (candidateCosts[j] != -1 &&
|
||||
candidateExpandCosts[j][k] < candidateExpandCosts[i][k]) {
|
||||
std::vector<Symbol *> temp;
|
||||
temp.push_back(actualCandidates[i]);
|
||||
temp.push_back(actualCandidates[j]);
|
||||
std::string candidateMessage =
|
||||
lGetOverloadCandidateMessage(temp, argTypes, argCouldBeNULL);
|
||||
Warning(pos, "call to \"%s\" is ambiguous. "
|
||||
"This warning will be turned into error in the next ispc release.\n"
|
||||
"Please add explicit cast to arguments to have unambiguous match."
|
||||
"\n%s", funName, candidateMessage.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
matches.push_back(actualCandidates[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < (int)candidateExpandCosts.size(); ++i) {
|
||||
delete [] candidateExpandCosts[i];
|
||||
}
|
||||
|
||||
if (matches.size() == 1) {
|
||||
|
||||
Reference in New Issue
Block a user