Be able to determine if two types can be converted without requiring an Expr *.
The Expr::TypeConv() method has been replaced with both a CanConvertTypes() routine that indicates whether one type can be converted to another and a TypeConvertExpr() routine that provides the same functionality as Expr::TypeConv() used to.
This commit is contained in:
17
ctx.cpp
17
ctx.cpp
@@ -652,18 +652,19 @@ FunctionEmitContext::CurrentLanesReturned(Expr *expr, bool doCoherenceCheck) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (expr == NULL) {
|
if (expr == NULL) {
|
||||||
Error(funcStartPos,
|
Error(funcStartPos, "Must provide return value for return "
|
||||||
"Must provide return value for return statement for non-void function.");
|
"statement for non-void function.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a masked store to store the value of the expression in the
|
expr = TypeConvertExpr(expr, returnType, "return statement");
|
||||||
// return value memory; this preserves the return values from other
|
if (expr != NULL) {
|
||||||
// lanes that may have executed return statements previously.
|
llvm::Value *retVal = expr->GetValue(this);
|
||||||
Expr *r = expr->TypeConv(returnType, "return statement");
|
|
||||||
if (r != NULL) {
|
|
||||||
llvm::Value *retVal = r->GetValue(this);
|
|
||||||
if (retVal != NULL)
|
if (retVal != NULL)
|
||||||
|
// Use a masked store to store the value of the expression
|
||||||
|
// in the return value memory; this preserves the return
|
||||||
|
// values from other lanes that may have executed return
|
||||||
|
// statements previously.
|
||||||
StoreInst(retVal, returnValuePtr, GetInternalMask(), returnType);
|
StoreInst(retVal, returnValuePtr, GetInternalMask(), returnType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
339
expr.cpp
339
expr.cpp
@@ -125,33 +125,34 @@ lMaybeIssuePrecisionWarning(const AtomicType *toAtomicType,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Expr *
|
///////////////////////////////////////////////////////////////////////////
|
||||||
Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|
||||||
bool issuePrecisionWarnings) {
|
static bool
|
||||||
|
lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr,
|
||||||
|
bool failureOk, const char *errorMsgBase, SourcePos pos) {
|
||||||
/* This function is way too long and complex. Is type conversion stuff
|
/* This function is way too long and complex. Is type conversion stuff
|
||||||
always this messy, or can this be cleaned up somehow? */
|
always this messy, or can this be cleaned up somehow? */
|
||||||
assert(failureOk || errorMsgBase != NULL);
|
assert(failureOk || errorMsgBase != NULL);
|
||||||
|
|
||||||
const Type *fromType = GetType();
|
|
||||||
if (toType == NULL || fromType == NULL)
|
if (toType == NULL || fromType == NULL)
|
||||||
return this;
|
return false;
|
||||||
|
|
||||||
// The types are equal; there's nothing to do
|
// The types are equal; there's nothing to do
|
||||||
if (Type::Equal(toType, fromType))
|
if (Type::Equal(toType, fromType))
|
||||||
return this;
|
return true;
|
||||||
|
|
||||||
if (fromType == AtomicType::Void) {
|
if (fromType == AtomicType::Void) {
|
||||||
if (!failureOk)
|
if (!failureOk)
|
||||||
Error(pos, "Can't convert from \"void\" to \"%s\" for %s.",
|
Error(pos, "Can't convert from \"void\" to \"%s\" for %s.",
|
||||||
toType->GetString().c_str(), errorMsgBase);
|
toType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toType == AtomicType::Void) {
|
if (toType == AtomicType::Void) {
|
||||||
if (!failureOk)
|
if (!failureOk)
|
||||||
Error(pos, "Can't convert type \"%s\" to \"void\" for %s.",
|
Error(pos, "Can't convert type \"%s\" to \"void\" for %s.",
|
||||||
fromType->GetString().c_str(), errorMsgBase);
|
fromType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toType->IsUniformType() && fromType->IsVaryingType()) {
|
if (toType->IsUniformType() && fromType->IsVaryingType()) {
|
||||||
@@ -159,13 +160,24 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
Error(pos, "Can't convert from varying type \"%s\" to uniform "
|
Error(pos, "Can't convert from varying type \"%s\" to uniform "
|
||||||
"type \"%s\" for %s.", fromType->GetString().c_str(),
|
"type \"%s\" for %s.", fromType->GetString().c_str(),
|
||||||
toType->GetString().c_str(), errorMsgBase);
|
toType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ArrayType *toArrayType = dynamic_cast<const ArrayType *>(toType);
|
||||||
|
const ArrayType *fromArrayType = dynamic_cast<const ArrayType *>(fromType);
|
||||||
|
const VectorType *toVectorType = dynamic_cast<const VectorType *>(toType);
|
||||||
|
const VectorType *fromVectorType = dynamic_cast<const VectorType *>(fromType);
|
||||||
|
const StructType *toStructType = dynamic_cast<const StructType *>(toType);
|
||||||
|
const StructType *fromStructType = dynamic_cast<const StructType *>(fromType);
|
||||||
|
const EnumType *toEnumType = dynamic_cast<const EnumType *>(toType);
|
||||||
|
const EnumType *fromEnumType = dynamic_cast<const EnumType *>(fromType);
|
||||||
|
const AtomicType *toAtomicType = dynamic_cast<const AtomicType *>(toType);
|
||||||
|
const AtomicType *fromAtomicType = dynamic_cast<const AtomicType *>(fromType);
|
||||||
|
|
||||||
// Convert from type T -> const T; just return a TypeCast expr, which
|
// Convert from type T -> const T; just return a TypeCast expr, which
|
||||||
// can handle this
|
// can handle this
|
||||||
if (Type::Equal(toType, fromType->GetAsConstType()))
|
if (Type::Equal(toType, fromType->GetAsConstType()))
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
|
|
||||||
if (dynamic_cast<const ReferenceType *>(fromType)) {
|
if (dynamic_cast<const ReferenceType *>(fromType)) {
|
||||||
if (dynamic_cast<const ReferenceType *>(toType)) {
|
if (dynamic_cast<const ReferenceType *>(toType)) {
|
||||||
@@ -173,75 +185,91 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
// this is handled by TypeCastExpr
|
// this is handled by TypeCastExpr
|
||||||
if (Type::Equal(toType->GetReferenceTarget(),
|
if (Type::Equal(toType->GetReferenceTarget(),
|
||||||
fromType->GetReferenceTarget()->GetAsConstType()))
|
fromType->GetReferenceTarget()->GetAsConstType()))
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
|
|
||||||
|
const ArrayType *atFrom =
|
||||||
|
dynamic_cast<const ArrayType *>(fromType->GetReferenceTarget());
|
||||||
|
const ArrayType *atTo =
|
||||||
|
dynamic_cast<const ArrayType *>(toType->GetReferenceTarget());
|
||||||
|
|
||||||
const ArrayType *atFrom = dynamic_cast<const ArrayType *>(fromType->GetReferenceTarget());
|
|
||||||
const ArrayType *atTo = dynamic_cast<const ArrayType *>(toType->GetReferenceTarget());
|
|
||||||
if (atFrom != NULL && atTo != NULL &&
|
if (atFrom != NULL && atTo != NULL &&
|
||||||
Type::Equal(atFrom->GetElementType(), atTo->GetElementType()))
|
Type::Equal(atFrom->GetElementType(), atTo->GetElementType())) {
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (!failureOk)
|
if (!failureOk)
|
||||||
Error(pos, "Can't convert between incompatible reference types \"%s\" "
|
Error(pos, "Can't convert between incompatible reference types \"%s\" "
|
||||||
"and \"%s\" for %s.", fromType->GetString().c_str(),
|
"and \"%s\" for %s.", fromType->GetString().c_str(),
|
||||||
toType->GetString().c_str(), errorMsgBase);
|
toType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// convert from a reference T -> T
|
// convert from a reference T -> T
|
||||||
Expr *fromExpr = new DereferenceExpr(this, pos);
|
if (expr != NULL) {
|
||||||
if (fromExpr->GetType() == NULL)
|
Expr *drExpr = new DereferenceExpr(*expr, pos);
|
||||||
return NULL;
|
if (lDoTypeConv(drExpr->GetType(), toType, &drExpr, failureOk,
|
||||||
return fromExpr->TypeConv(toType, errorMsgBase, failureOk);
|
errorMsgBase, pos) == true) {
|
||||||
|
*expr = drExpr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return lDoTypeConv(fromType->GetReferenceTarget(), toType, NULL,
|
||||||
|
failureOk, errorMsgBase, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<const ReferenceType *>(toType)) {
|
else if (dynamic_cast<const ReferenceType *>(toType)) {
|
||||||
// T -> reference T
|
// T -> reference T
|
||||||
Expr *fromExpr = new ReferenceExpr(this, pos);
|
if (expr != NULL) {
|
||||||
if (fromExpr->GetType() == NULL)
|
Expr *rExpr = new ReferenceExpr(*expr, pos);
|
||||||
return NULL;
|
if (lDoTypeConv(rExpr->GetType(), toType, &rExpr, failureOk,
|
||||||
return fromExpr->TypeConv(toType, errorMsgBase, failureOk);
|
errorMsgBase, pos) == true) {
|
||||||
|
*expr = rExpr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return lDoTypeConv(new ReferenceType(fromType, toType->IsConstType()),
|
||||||
|
toType, NULL, failureOk, errorMsgBase, pos);
|
||||||
}
|
}
|
||||||
else if (Type::Equal(toType, fromType->GetAsNonConstType()))
|
else if (Type::Equal(toType, fromType->GetAsNonConstType()))
|
||||||
// convert: const T -> T (as long as T isn't a reference)
|
// convert: const T -> T (as long as T isn't a reference)
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
|
|
||||||
fromType = fromType->GetReferenceTarget();
|
fromType = fromType->GetReferenceTarget();
|
||||||
toType = toType->GetReferenceTarget();
|
toType = toType->GetReferenceTarget();
|
||||||
// I don't think this is necessary
|
|
||||||
//CO if (Type::Equal(toType, fromType))
|
|
||||||
//CO return fromExpr;
|
|
||||||
|
|
||||||
const ArrayType *toArrayType = dynamic_cast<const ArrayType *>(toType);
|
|
||||||
const ArrayType *fromArrayType = dynamic_cast<const ArrayType *>(fromType);
|
|
||||||
if (toArrayType && fromArrayType) {
|
if (toArrayType && fromArrayType) {
|
||||||
if (Type::Equal(toArrayType->GetElementType(),
|
if (Type::Equal(toArrayType->GetElementType(),
|
||||||
fromArrayType->GetElementType())) {
|
fromArrayType->GetElementType())) {
|
||||||
// the case of different element counts should have returned
|
// the case of different element counts should have returned
|
||||||
// out earlier, yes??
|
// out earlier, yes??
|
||||||
assert(toArrayType->GetElementCount() != fromArrayType->GetElementCount());
|
assert(toArrayType->GetElementCount() != fromArrayType->GetElementCount());
|
||||||
return new TypeCastExpr(new ReferenceType(toType, false), this,
|
if (expr != NULL)
|
||||||
false, pos);
|
*expr = new TypeCastExpr(new ReferenceType(toType, false),
|
||||||
|
*expr, false, pos);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (Type::Equal(toArrayType->GetElementType(),
|
else if (Type::Equal(toArrayType->GetElementType(),
|
||||||
fromArrayType->GetElementType()->GetAsConstType())) {
|
fromArrayType->GetElementType()->GetAsConstType())) {
|
||||||
// T[x] -> const T[x]
|
// T[x] -> const T[x]
|
||||||
return new TypeCastExpr(new ReferenceType(toType, false), this,
|
if (expr != NULL)
|
||||||
false, pos);
|
*expr = new TypeCastExpr(new ReferenceType(toType, false),
|
||||||
|
*expr, false, pos);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!failureOk)
|
if (!failureOk)
|
||||||
Error(pos, "Array type \"%s\" can't be converted to type \"%s\" for %s.",
|
Error(pos, "Array type \"%s\" can't be converted to type \"%s\" for %s.",
|
||||||
fromType->GetString().c_str(), toType->GetString().c_str(),
|
fromType->GetString().c_str(), toType->GetString().c_str(),
|
||||||
errorMsgBase);
|
errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VectorType *toVectorType = dynamic_cast<const VectorType *>(toType);
|
|
||||||
const VectorType *fromVectorType = dynamic_cast<const VectorType *>(fromType);
|
|
||||||
if (toVectorType && fromVectorType) {
|
if (toVectorType && fromVectorType) {
|
||||||
// converting e.g. int<n> -> float<n>
|
// converting e.g. int<n> -> float<n>
|
||||||
if (fromVectorType->GetElementCount() != toVectorType->GetElementCount()) {
|
if (fromVectorType->GetElementCount() != toVectorType->GetElementCount()) {
|
||||||
@@ -249,13 +277,11 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
Error(pos, "Can't convert between differently sized vector types "
|
Error(pos, "Can't convert between differently sized vector types "
|
||||||
"\"%s\" -> \"%s\" for %s.", fromType->GetString().c_str(),
|
"\"%s\" -> \"%s\" for %s.", fromType->GetString().c_str(),
|
||||||
toType->GetString().c_str(), errorMsgBase);
|
toType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StructType *toStructType = dynamic_cast<const StructType *>(toType);
|
|
||||||
const StructType *fromStructType = dynamic_cast<const StructType *>(fromType);
|
|
||||||
if (toStructType && fromStructType) {
|
if (toStructType && fromStructType) {
|
||||||
if (!Type::Equal(toStructType->GetAsUniformType()->GetAsConstType(),
|
if (!Type::Equal(toStructType->GetAsUniformType()->GetAsConstType(),
|
||||||
fromStructType->GetAsUniformType()->GetAsConstType())) {
|
fromStructType->GetAsUniformType()->GetAsConstType())) {
|
||||||
@@ -263,14 +289,11 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
Error(pos, "Can't convert between different struct types "
|
Error(pos, "Can't convert between different struct types "
|
||||||
"\"%s\" -> \"%s\".", fromStructType->GetString().c_str(),
|
"\"%s\" -> \"%s\".", fromStructType->GetString().c_str(),
|
||||||
toStructType->GetString().c_str());
|
toStructType->GetString().c_str());
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
goto typecast_ok;
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnumType *toEnumType = dynamic_cast<const EnumType *>(toType);
|
|
||||||
const EnumType *fromEnumType = dynamic_cast<const EnumType *>(fromType);
|
|
||||||
if (toEnumType != NULL && fromEnumType != NULL) {
|
if (toEnumType != NULL && fromEnumType != NULL) {
|
||||||
// No implicit conversions between different enum types
|
// No implicit conversions between different enum types
|
||||||
if (!Type::Equal(toEnumType->GetAsUniformType()->GetAsConstType(),
|
if (!Type::Equal(toEnumType->GetAsUniformType()->GetAsConstType(),
|
||||||
@@ -279,19 +302,15 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
Error(pos, "Can't convert between different enum types "
|
Error(pos, "Can't convert between different enum types "
|
||||||
"\"%s\" -> \"%s\".", fromEnumType->GetString().c_str(),
|
"\"%s\" -> \"%s\".", fromEnumType->GetString().c_str(),
|
||||||
toEnumType->GetString().c_str());
|
toEnumType->GetString().c_str());
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
goto typecast_ok;
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AtomicType *toAtomicType = dynamic_cast<const AtomicType *>(toType);
|
|
||||||
const AtomicType *fromAtomicType = dynamic_cast<const AtomicType *>(fromType);
|
|
||||||
|
|
||||||
// enum -> atomic (integer, generally...) is always ok
|
// enum -> atomic (integer, generally...) is always ok
|
||||||
if (fromEnumType != NULL) {
|
if (fromEnumType != NULL) {
|
||||||
assert(toAtomicType != NULL || toVectorType != NULL);
|
assert(toAtomicType != NULL || toVectorType != NULL);
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from here on out, the from type can only be atomic something or
|
// from here on out, the from type can only be atomic something or
|
||||||
@@ -301,12 +320,12 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
Error(pos, "Type conversion only possible from atomic types, not "
|
Error(pos, "Type conversion only possible from atomic types, not "
|
||||||
"from \"%s\" to \"%s\", for %s.", fromType->GetString().c_str(),
|
"from \"%s\" to \"%s\", for %s.", fromType->GetString().c_str(),
|
||||||
toType->GetString().c_str(), errorMsgBase);
|
toType->GetString().c_str(), errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scalar -> short-vector conversions
|
// scalar -> short-vector conversions
|
||||||
if (toVectorType != NULL)
|
if (toVectorType != NULL)
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
goto typecast_ok;
|
||||||
|
|
||||||
// ok, it better be a scalar->scalar conversion of some sort by now
|
// ok, it better be a scalar->scalar conversion of some sort by now
|
||||||
if (toAtomicType == NULL) {
|
if (toAtomicType == NULL) {
|
||||||
@@ -315,17 +334,34 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk,
|
|||||||
"from \"%s\" to \"%s\", for %s.",
|
"from \"%s\" to \"%s\", for %s.",
|
||||||
fromType->GetString().c_str(), toType->GetString().c_str(),
|
fromType->GetString().c_str(), toType->GetString().c_str(),
|
||||||
errorMsgBase);
|
errorMsgBase);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
typecast_ok:
|
||||||
// Disable: it's not clear this is actually all that useful
|
if (expr != NULL)
|
||||||
if (!failureOk && issuePrecisionWarnings)
|
*expr = new TypeCastExpr(toType, *expr, false, pos);
|
||||||
lMaybeIssuePrecisionWarning(toAtomicType, fromAtomicType, pos,
|
return true;
|
||||||
errorMsgBase);
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return new TypeCastExpr(toType, this, false, pos);
|
|
||||||
|
bool
|
||||||
|
CanConvertTypes(const Type *fromType, const Type *toType) {
|
||||||
|
return lDoTypeConv(fromType, toType, NULL, true, NULL, SourcePos());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Expr *
|
||||||
|
TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase) {
|
||||||
|
if (expr == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const Type *fromType = expr->GetType();
|
||||||
|
Expr *e = expr;
|
||||||
|
if (lDoTypeConv(fromType, toType, &e, false, errorMsgBase,
|
||||||
|
expr->pos))
|
||||||
|
return e;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -770,8 +806,8 @@ UnaryExpr::TypeCheck() {
|
|||||||
}
|
}
|
||||||
else if (op == LogicalNot) {
|
else if (op == LogicalNot) {
|
||||||
const Type *boolType = lMatchingBoolType(type);
|
const Type *boolType = lMatchingBoolType(type);
|
||||||
expr = expr->TypeConv(boolType, "logical not");
|
expr = TypeConvertExpr(expr, boolType, "logical not");
|
||||||
if (!expr)
|
if (expr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (op == BitNot) {
|
else if (op == BitNot) {
|
||||||
@@ -1383,10 +1419,13 @@ BinaryExpr::TypeCheck() {
|
|||||||
bool isVarying = (type0->IsVaryingType() ||
|
bool isVarying = (type0->IsVaryingType() ||
|
||||||
type1->IsVaryingType());
|
type1->IsVaryingType());
|
||||||
if (isVarying) {
|
if (isVarying) {
|
||||||
arg0 = arg0->TypeConv(type0->GetAsVaryingType(), "shift operator");
|
arg0 = TypeConvertExpr(arg0, type0->GetAsVaryingType(),
|
||||||
|
"shift operator");
|
||||||
|
if (arg0 == NULL)
|
||||||
|
return NULL;
|
||||||
type0 = arg0->GetType();
|
type0 = arg0->GetType();
|
||||||
}
|
}
|
||||||
arg1 = arg1->TypeConv(type0, "shift operator", false, false);
|
arg1 = TypeConvertExpr(arg1, type0, "shift operator");
|
||||||
if (arg1 == NULL)
|
if (arg1 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1396,8 +1435,8 @@ BinaryExpr::TypeCheck() {
|
|||||||
if (promotedType == NULL)
|
if (promotedType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
arg0 = arg0->TypeConv(promotedType, "binary bit op");
|
arg0 = TypeConvertExpr(arg0, promotedType, "binary bit op");
|
||||||
arg1 = arg1->TypeConv(promotedType, "binary bit op");
|
arg1 = TypeConvertExpr(arg1, promotedType, "binary bit op");
|
||||||
if (arg0 == NULL || arg1 == NULL)
|
if (arg0 == NULL || arg1 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1431,9 +1470,9 @@ BinaryExpr::TypeCheck() {
|
|||||||
if (promotedType == NULL)
|
if (promotedType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
arg0 = arg0->TypeConv(promotedType, lOpString(op));
|
arg0 = TypeConvertExpr(arg0, promotedType, lOpString(op));
|
||||||
arg1 = arg1->TypeConv(promotedType, lOpString(op));
|
arg1 = TypeConvertExpr(arg1, promotedType, lOpString(op));
|
||||||
if (!arg0 || !arg1)
|
if (arg0 == NULL || arg1 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -1459,9 +1498,9 @@ BinaryExpr::TypeCheck() {
|
|||||||
if (promotedType == NULL)
|
if (promotedType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
arg0 = arg0->TypeConv(promotedType, lOpString(op));
|
arg0 = TypeConvertExpr(arg0, promotedType, lOpString(op));
|
||||||
arg1 = arg1->TypeConv(promotedType, lOpString(op));
|
arg1 = TypeConvertExpr(arg1, promotedType, lOpString(op));
|
||||||
if (!arg0 || !arg1)
|
if (arg0 == NULL || arg1 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -1490,10 +1529,10 @@ BinaryExpr::TypeCheck() {
|
|||||||
destType = new VectorType(boolType, vtype1->GetElementCount());
|
destType = new VectorType(boolType, vtype1->GetElementCount());
|
||||||
else
|
else
|
||||||
destType = boolType;
|
destType = boolType;
|
||||||
|
|
||||||
arg0 = arg0->TypeConv(destType, lOpString(op));
|
arg0 = TypeConvertExpr(arg0, destType, lOpString(op));
|
||||||
arg1 = arg1->TypeConv(destType, lOpString(op));
|
arg1 = TypeConvertExpr(arg1, destType, lOpString(op));
|
||||||
if (!arg0 || !arg1)
|
if (arg0 == NULL || arg1 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -1726,9 +1765,11 @@ AssignExpr::TypeCheck() {
|
|||||||
lvalue = lvalue->TypeCheck();
|
lvalue = lvalue->TypeCheck();
|
||||||
if (rvalue != NULL)
|
if (rvalue != NULL)
|
||||||
rvalue = rvalue->TypeCheck();
|
rvalue = rvalue->TypeCheck();
|
||||||
if (rvalue != NULL && lvalue != NULL)
|
if (lvalue == NULL || rvalue == NULL)
|
||||||
rvalue = rvalue->TypeConv(lvalue->GetType(), "assignment");
|
return NULL;
|
||||||
if (rvalue == NULL || lvalue == NULL)
|
|
||||||
|
rvalue = TypeConvertExpr(rvalue, lvalue->GetType(), "assignment");
|
||||||
|
if (rvalue == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (lvalue->GetType()->IsConstType()) {
|
if (lvalue->GetType()->IsConstType()) {
|
||||||
@@ -1982,8 +2023,8 @@ SelectExpr::TypeCheck() {
|
|||||||
const Type *testType = test->GetType();
|
const Type *testType = test->GetType();
|
||||||
if (testType == NULL)
|
if (testType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
test = test->TypeConv(lMatchingBoolType(testType), "select");
|
test = TypeConvertExpr(test, lMatchingBoolType(testType), "select");
|
||||||
if (testType == NULL)
|
if (test == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
testType = test->GetType();
|
testType = test->GetType();
|
||||||
|
|
||||||
@@ -1994,9 +2035,9 @@ SelectExpr::TypeCheck() {
|
|||||||
if (promotedType == NULL)
|
if (promotedType == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
expr1 = expr1->TypeConv(promotedType, "select");
|
expr1 = TypeConvertExpr(expr1, promotedType, "select");
|
||||||
expr2 = expr2->TypeConv(promotedType, "select");
|
expr2 = TypeConvertExpr(expr2, promotedType, "select");
|
||||||
if (!expr1 || !expr2)
|
if (expr1 == NULL || expr2 == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -2099,7 +2140,8 @@ FunctionCallExpr::GetValue(FunctionEmitContext *ctx) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do whatever type conversion is needed
|
// Do whatever type conversion is needed
|
||||||
argExpr = argExpr->TypeConv(argTypes[i], "function call argument");
|
argExpr = TypeConvertExpr(argExpr, argTypes[i],
|
||||||
|
"function call argument");
|
||||||
// The function overload resolution code should have ensured that
|
// The function overload resolution code should have ensured that
|
||||||
// we can successfully do any type conversions needed here.
|
// we can successfully do any type conversions needed here.
|
||||||
assert(argExpr != NULL);
|
assert(argExpr != NULL);
|
||||||
@@ -2112,13 +2154,11 @@ FunctionCallExpr::GetValue(FunctionEmitContext *ctx) const {
|
|||||||
// FIXME: should we do this during type checking?
|
// FIXME: should we do this during type checking?
|
||||||
const std::vector<ConstExpr *> &argumentDefaults = ft->GetArgumentDefaults();
|
const std::vector<ConstExpr *> &argumentDefaults = ft->GetArgumentDefaults();
|
||||||
for (unsigned int i = callargs.size(); i < argumentDefaults.size(); ++i) {
|
for (unsigned int i = callargs.size(); i < argumentDefaults.size(); ++i) {
|
||||||
assert(argumentDefaults[i] != NULL);
|
Expr * d = TypeConvertExpr(argumentDefaults[i], argTypes[i],
|
||||||
Expr *defaultExpr = argumentDefaults[i]->TypeConv(argTypes[i],
|
"function call default argument");
|
||||||
"function call default argument");
|
if (d == NULL)
|
||||||
if (defaultExpr == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
callargs.push_back(d);
|
||||||
callargs.push_back(defaultExpr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now evaluate the values of all of the parameters being passed. We
|
// Now evaluate the values of all of the parameters being passed. We
|
||||||
@@ -2256,7 +2296,17 @@ FunctionCallExpr::TypeCheck() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fse->ResolveOverloads(args->exprs) == true) {
|
std::vector<const Type *> argTypes;
|
||||||
|
for (unsigned int i = 0; i < args->exprs.size(); ++i) {
|
||||||
|
if (args->exprs[i] == NULL)
|
||||||
|
return NULL;
|
||||||
|
const Type *t = args->exprs[i]->GetType();
|
||||||
|
if (t == NULL)
|
||||||
|
return NULL;
|
||||||
|
argTypes.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fse->ResolveOverloads(argTypes) == true) {
|
||||||
func = fse->TypeCheck();
|
func = fse->TypeCheck();
|
||||||
|
|
||||||
if (func != NULL) {
|
if (func != NULL) {
|
||||||
@@ -2271,9 +2321,9 @@ FunctionCallExpr::TypeCheck() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
launchCountExpr =
|
launchCountExpr =
|
||||||
launchCountExpr->TypeConv(AtomicType::UniformInt32,
|
TypeConvertExpr(launchCountExpr, AtomicType::UniformInt32,
|
||||||
"task launch count");
|
"task launch count");
|
||||||
if (!launchCountExpr)
|
if (launchCountExpr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -2621,8 +2671,8 @@ IndexExpr::TypeCheck() {
|
|||||||
!g->opt.disableUniformMemoryOptimizations);
|
!g->opt.disableUniformMemoryOptimizations);
|
||||||
const Type *indexType = isUniform ? AtomicType::UniformInt32 :
|
const Type *indexType = isUniform ? AtomicType::UniformInt32 :
|
||||||
AtomicType::VaryingInt32;
|
AtomicType::VaryingInt32;
|
||||||
index = index->TypeConv(indexType, "array index");
|
index = TypeConvertExpr(index, indexType, "array index");
|
||||||
if (!index)
|
if (index == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -5191,16 +5241,16 @@ lPrintFunctionOverloads(const std::string &name,
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lPrintPassedTypes(const char *funName, const std::vector<Expr *> &argExprs) {
|
lPrintPassedTypes(const char *funName,
|
||||||
|
const std::vector<const Type *> &argTypes) {
|
||||||
fprintf(stderr, "Passed types: %*c(", (int)strlen(funName), ' ');
|
fprintf(stderr, "Passed types: %*c(", (int)strlen(funName), ' ');
|
||||||
for (unsigned int i = 0; i < argExprs.size(); ++i) {
|
for (unsigned int i = 0; i < argTypes.size(); ++i) {
|
||||||
const Type *t;
|
if (argTypes[i] != NULL)
|
||||||
if (argExprs[i] != NULL && (t = argExprs[i]->GetType()) != NULL)
|
fprintf(stderr, "%s%s", argTypes[i]->GetString().c_str(),
|
||||||
fprintf(stderr, "%s%s", t->GetString().c_str(),
|
(i < argTypes.size()-1) ? ", " : ")\n\n");
|
||||||
(i < argExprs.size()-1) ? ", " : ")\n\n");
|
|
||||||
else
|
else
|
||||||
fprintf(stderr, "(unknown type)%s",
|
fprintf(stderr, "(unknown type)%s",
|
||||||
(i < argExprs.size()-1) ? ", " : ")\n\n");
|
(i < argTypes.size()-1) ? ", " : ")\n\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5211,9 +5261,7 @@ lPrintPassedTypes(const char *funName, const std::vector<Expr *> &argExprs) {
|
|||||||
failure.
|
failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lExactMatch(Expr *callArg, const Type *funcArgType) {
|
lExactMatch(const Type *callType, const Type *funcArgType) {
|
||||||
const Type *callType = callArg->GetType();
|
|
||||||
|
|
||||||
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
||||||
callType = callType->GetAsNonConstType();
|
callType = callType->GetAsNonConstType();
|
||||||
if (dynamic_cast<const ReferenceType *>(funcArgType) != NULL &&
|
if (dynamic_cast<const ReferenceType *>(funcArgType) != NULL &&
|
||||||
@@ -5229,12 +5277,12 @@ lExactMatch(Expr *callArg, const Type *funcArgType) {
|
|||||||
modulo conversion to a reference type if needed.
|
modulo conversion to a reference type if needed.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lMatchIgnoringReferences(Expr *callArg, const Type *funcArgType) {
|
lMatchIgnoringReferences(const Type *callType, const Type *funcArgType) {
|
||||||
int prev = lExactMatch(callArg, funcArgType);
|
int prev = lExactMatch(callType, funcArgType);
|
||||||
if (prev != -1)
|
if (prev != -1)
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
const Type *callType = callArg->GetType()->GetReferenceTarget();
|
callType = callType->GetReferenceTarget();
|
||||||
if (funcArgType->IsConstType())
|
if (funcArgType->IsConstType())
|
||||||
callType = callType->GetAsConstType();
|
callType = callType->GetAsConstType();
|
||||||
|
|
||||||
@@ -5247,12 +5295,11 @@ lMatchIgnoringReferences(Expr *callArg, const Type *funcArgType) {
|
|||||||
conversion that won't lose information. Otherwise reports failure.
|
conversion that won't lose information. Otherwise reports failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lMatchWithTypeWidening(Expr *callArg, const Type *funcArgType) {
|
lMatchWithTypeWidening(const Type *callType, const Type *funcArgType) {
|
||||||
int prev = lMatchIgnoringReferences(callArg, funcArgType);
|
int prev = lMatchIgnoringReferences(callType, funcArgType);
|
||||||
if (prev != -1)
|
if (prev != -1)
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
const Type *callType = callArg->GetType();
|
|
||||||
const AtomicType *callAt = dynamic_cast<const AtomicType *>(callType);
|
const AtomicType *callAt = dynamic_cast<const AtomicType *>(callType);
|
||||||
const AtomicType *funcAt = dynamic_cast<const AtomicType *>(funcArgType);
|
const AtomicType *funcAt = dynamic_cast<const AtomicType *>(funcArgType);
|
||||||
if (callAt == NULL || funcAt == NULL)
|
if (callAt == NULL || funcAt == NULL)
|
||||||
@@ -5299,12 +5346,11 @@ lMatchWithTypeWidening(Expr *callArg, const Type *funcArgType) {
|
|||||||
exactly the same type.
|
exactly the same type.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lMatchIgnoringUniform(Expr *callArg, const Type *funcArgType) {
|
lMatchIgnoringUniform(const Type *callType, const Type *funcArgType) {
|
||||||
int prev = lMatchWithTypeWidening(callArg, funcArgType);
|
int prev = lMatchWithTypeWidening(callType, funcArgType);
|
||||||
if (prev != -1)
|
if (prev != -1)
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
const Type *callType = callArg->GetType();
|
|
||||||
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
if (dynamic_cast<const ReferenceType *>(callType) == NULL)
|
||||||
callType = callType->GetAsNonConstType();
|
callType = callType->GetAsNonConstType();
|
||||||
|
|
||||||
@@ -5319,15 +5365,14 @@ lMatchIgnoringUniform(Expr *callArg, const Type *funcArgType) {
|
|||||||
argument type, but without doing a uniform -> varying conversion.
|
argument type, but without doing a uniform -> varying conversion.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lMatchWithTypeConvSameVariability(Expr *callArg, const Type *funcArgType) {
|
lMatchWithTypeConvSameVariability(const Type *callType,
|
||||||
int prev = lMatchIgnoringUniform(callArg, funcArgType);
|
const Type *funcArgType) {
|
||||||
|
int prev = lMatchIgnoringUniform(callType, funcArgType);
|
||||||
if (prev != -1)
|
if (prev != -1)
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
Expr *te = callArg->TypeConv(funcArgType,
|
if (CanConvertTypes(callType, funcArgType) &&
|
||||||
"function call argument", true);
|
(callType->IsUniformType() == funcArgType->IsUniformType()))
|
||||||
if (te != NULL &&
|
|
||||||
te->GetType()->IsUniformType() == callArg->GetType()->IsUniformType())
|
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
@@ -5339,14 +5384,12 @@ lMatchWithTypeConvSameVariability(Expr *callArg, const Type *funcArgType) {
|
|||||||
argument type to the function argument type.
|
argument type to the function argument type.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lMatchWithTypeConv(Expr *callArg, const Type *funcArgType) {
|
lMatchWithTypeConv(const Type *callType, const Type *funcArgType) {
|
||||||
int prev = lMatchWithTypeConvSameVariability(callArg, funcArgType);
|
int prev = lMatchWithTypeConvSameVariability(callType, funcArgType);
|
||||||
if (prev != -1)
|
if (prev != -1)
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
Expr *te = callArg->TypeConv(funcArgType,
|
return CanConvertTypes(callType, funcArgType) ? 0 : -1;
|
||||||
"function call argument", true);
|
|
||||||
return (te != NULL) ? 0 : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -5383,8 +5426,8 @@ lGetBestMatch(std::vector<std::pair<int, Symbol *> > &matches) {
|
|||||||
finding multiple ambiguous matches.
|
finding multiple ambiguous matches.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
FunctionSymbolExpr::tryResolve(int (*matchFunc)(Expr *, const Type *),
|
FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *),
|
||||||
const std::vector<Expr *> &callArgs) {
|
const std::vector<const Type *> &callTypes) {
|
||||||
const char *funName = candidateFunctions->front()->name.c_str();
|
const char *funName = candidateFunctions->front()->name.c_str();
|
||||||
|
|
||||||
std::vector<std::pair<int, Symbol *> > matches;
|
std::vector<std::pair<int, Symbol *> > matches;
|
||||||
@@ -5401,7 +5444,7 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(Expr *, const Type *),
|
|||||||
|
|
||||||
// There's no way to match if the caller is passing more arguments
|
// There's no way to match if the caller is passing more arguments
|
||||||
// than this function instance takes.
|
// than this function instance takes.
|
||||||
if (callArgs.size() > funcArgTypes.size())
|
if (callTypes.size() > funcArgTypes.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@@ -5410,23 +5453,23 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(Expr *, const Type *),
|
|||||||
// function than are passed, if the function has default argument
|
// function than are passed, if the function has default argument
|
||||||
// values. This case is handled below.
|
// values. This case is handled below.
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
for (i = 0; i < callArgs.size(); ++i) {
|
for (i = 0; i < callTypes.size(); ++i) {
|
||||||
// This may happen if there's an error earlier in compilation.
|
// This may happen if there's an error earlier in compilation.
|
||||||
// It's kind of a silly to redundantly discover this for each
|
// It's kind of a silly to redundantly discover this for each
|
||||||
// potential match versus detecting this earlier in the
|
// potential match versus detecting this earlier in the
|
||||||
// matching process and just giving up.
|
// matching process and just giving up.
|
||||||
if (!callArgs[i] || !callArgs[i]->GetType() || !funcArgTypes[i] ||
|
if (callTypes[i] == NULL || funcArgTypes[i] == NULL ||
|
||||||
dynamic_cast<const FunctionType *>(callArgs[i]->GetType()) != NULL)
|
dynamic_cast<const FunctionType *>(callTypes[i]) != NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int argCost = matchFunc(callArgs[i], funcArgTypes[i]);
|
int argCost = matchFunc(callTypes[i], funcArgTypes[i]);
|
||||||
if (argCost == -1)
|
if (argCost == -1)
|
||||||
// If the predicate function returns -1, we have failed no
|
// If the predicate function returns -1, we have failed no
|
||||||
// matter what else happens, so we stop trying
|
// matter what else happens, so we stop trying
|
||||||
break;
|
break;
|
||||||
cost += argCost;
|
cost += argCost;
|
||||||
}
|
}
|
||||||
if (i == callArgs.size()) {
|
if (i == callTypes.size()) {
|
||||||
// All of the arguments matched!
|
// All of the arguments matched!
|
||||||
if (i == funcArgTypes.size())
|
if (i == funcArgTypes.size())
|
||||||
// And we have exactly as many arguments as the function
|
// And we have exactly as many arguments as the function
|
||||||
@@ -5454,7 +5497,7 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(Expr *, const Type *),
|
|||||||
Error(pos, "Multiple overloaded instances of function \"%s\" matched.",
|
Error(pos, "Multiple overloaded instances of function \"%s\" matched.",
|
||||||
funName);
|
funName);
|
||||||
lPrintFunctionOverloads(funName, matches);
|
lPrintFunctionOverloads(funName, matches);
|
||||||
lPrintPassedTypes(funName, callArgs);
|
lPrintPassedTypes(funName, callTypes);
|
||||||
// Stop trying to find more matches after an ambigious set of
|
// Stop trying to find more matches after an ambigious set of
|
||||||
// matches.
|
// matches.
|
||||||
return true;
|
return true;
|
||||||
@@ -5463,7 +5506,7 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(Expr *, const Type *),
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FunctionSymbolExpr::ResolveOverloads(const std::vector<Expr *> &callArgs) {
|
FunctionSymbolExpr::ResolveOverloads(const std::vector<const Type *> &argTypes) {
|
||||||
// Functions with names that start with "__" should only be various
|
// Functions with names that start with "__" should only be various
|
||||||
// builtins. For those, we'll demand an exact match, since we'll
|
// builtins. For those, we'll demand an exact match, since we'll
|
||||||
// expect whichever function in stdlib.ispc is calling out to one of
|
// expect whichever function in stdlib.ispc is calling out to one of
|
||||||
@@ -5474,32 +5517,32 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector<Expr *> &callArgs) {
|
|||||||
|
|
||||||
// Is there an exact match that doesn't require any argument type
|
// Is there an exact match that doesn't require any argument type
|
||||||
// conversion (other than converting type -> reference type)?
|
// conversion (other than converting type -> reference type)?
|
||||||
if (tryResolve(lExactMatch, callArgs))
|
if (tryResolve(lExactMatch, argTypes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (exactMatchOnly == false) {
|
if (exactMatchOnly == false) {
|
||||||
// Try to find a single match ignoring references
|
// Try to find a single match ignoring references
|
||||||
if (tryResolve(lMatchIgnoringReferences, callArgs))
|
if (tryResolve(lMatchIgnoringReferences, argTypes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Try to find an exact match via type widening--i.e. int8 ->
|
// Try to find an exact match via type widening--i.e. int8 ->
|
||||||
// int16, etc.--things that don't lose data.
|
// int16, etc.--things that don't lose data.
|
||||||
if (tryResolve(lMatchWithTypeWidening, callArgs))
|
if (tryResolve(lMatchWithTypeWidening, argTypes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Next try to see if there's a match via just uniform -> varying
|
// Next try to see if there's a match via just uniform -> varying
|
||||||
// promotions.
|
// promotions.
|
||||||
if (tryResolve(lMatchIgnoringUniform, callArgs))
|
if (tryResolve(lMatchIgnoringUniform, argTypes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Try to find a match via type conversion, but don't change
|
// Try to find a match via type conversion, but don't change
|
||||||
// unif->varying
|
// unif->varying
|
||||||
if (tryResolve(lMatchWithTypeConvSameVariability,
|
if (tryResolve(lMatchWithTypeConvSameVariability,
|
||||||
callArgs))
|
argTypes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Last chance: try to find a match via arbitrary type conversion.
|
// Last chance: try to find a match via arbitrary type conversion.
|
||||||
if (tryResolve(lMatchWithTypeConv, callArgs))
|
if (tryResolve(lMatchWithTypeConv, argTypes))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5508,7 +5551,7 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector<Expr *> &callArgs) {
|
|||||||
Error(pos, "Unable to find matching overload for call to function \"%s\"%s.",
|
Error(pos, "Unable to find matching overload for call to function \"%s\"%s.",
|
||||||
funName, exactMatchOnly ? " only considering exact matches" : "");
|
funName, exactMatchOnly ? " only considering exact matches" : "");
|
||||||
lPrintFunctionOverloads(funName, *candidateFunctions);
|
lPrintFunctionOverloads(funName, *candidateFunctions);
|
||||||
lPrintPassedTypes(funName, callArgs);
|
lPrintPassedTypes(funName, argTypes);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
expr.h
29
expr.h
@@ -89,14 +89,6 @@ public:
|
|||||||
|
|
||||||
/** Prints the expression to standard output (used for debugging). */
|
/** Prints the expression to standard output (used for debugging). */
|
||||||
virtual void Print() const = 0;
|
virtual void Print() const = 0;
|
||||||
|
|
||||||
/** This method tries to convert the expression to the given type. In
|
|
||||||
the event of failure, if the failureOk parameter is true, then no
|
|
||||||
error is issued. If failureOk is false, then an error is printed
|
|
||||||
that incorporates the given error message string. In either
|
|
||||||
failure case, NULL is returned. */
|
|
||||||
Expr *TypeConv(const Type *type, const char *errorMsgBase = NULL,
|
|
||||||
bool failureOk = false, bool issuePrecisionWarnings = true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -577,12 +569,12 @@ public:
|
|||||||
void Print() const;
|
void Print() const;
|
||||||
int EstimateCost() const;
|
int EstimateCost() const;
|
||||||
|
|
||||||
bool ResolveOverloads(const std::vector<Expr *> &args);
|
bool ResolveOverloads(const std::vector<const Type *> &argTypes);
|
||||||
Symbol *GetMatchingFunction();
|
Symbol *GetMatchingFunction();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool tryResolve(int (*matchFunc)(Expr *, const Type *),
|
bool tryResolve(int (*matchFunc)(const Type *, const Type *),
|
||||||
const std::vector<Expr *> &args);
|
const std::vector<const Type *> &argTypes);
|
||||||
|
|
||||||
/** Name of the function that is being called. */
|
/** Name of the function that is being called. */
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -611,4 +603,19 @@ public:
|
|||||||
int EstimateCost() const;
|
int EstimateCost() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** This function indicates whether it's legal to convert from fromType to
|
||||||
|
toType.
|
||||||
|
*/
|
||||||
|
bool CanConvertTypes(const Type *fromType, const Type *toType);
|
||||||
|
|
||||||
|
/** This function attempts to convert the given expression to the given
|
||||||
|
type, returning a pointer to a new expression that is the result. If
|
||||||
|
the required type conversion is illegal, it returns NULL and prints an
|
||||||
|
error message using the provided string to indicate the context for
|
||||||
|
which type conversion was being applied (e.g. "function call
|
||||||
|
parameter").
|
||||||
|
*/
|
||||||
|
Expr *TypeConvertExpr(Expr *expr, const Type *toType, const char *errorMsgBase);
|
||||||
|
|
||||||
#endif // ISPC_EXPR_H
|
#endif // ISPC_EXPR_H
|
||||||
|
|||||||
@@ -256,8 +256,8 @@ Module::AddGlobalVariable(Symbol *sym, Expr *initExpr, bool isConst) {
|
|||||||
// ExprList; they don't have types per se / can't type
|
// ExprList; they don't have types per se / can't type
|
||||||
// convert themselves anyway.)
|
// convert themselves anyway.)
|
||||||
if (dynamic_cast<ExprList *>(initExpr) == NULL)
|
if (dynamic_cast<ExprList *>(initExpr) == NULL)
|
||||||
initExpr = initExpr->TypeConv(sym->type, "initializer");
|
initExpr = TypeConvertExpr(initExpr, sym->type, "initializer");
|
||||||
|
|
||||||
if (initExpr != NULL) {
|
if (initExpr != NULL) {
|
||||||
initExpr = initExpr->Optimize();
|
initExpr = initExpr->Optimize();
|
||||||
// Fingers crossed, now let's see if we've got a
|
// Fingers crossed, now let's see if we've got a
|
||||||
|
|||||||
18
stmt.cpp
18
stmt.cpp
@@ -146,9 +146,9 @@ lInitSymbol(llvm::Value *lvalue, const char *symName, const Type *type,
|
|||||||
// ExprList, then we'll see if we can type convert it to the type of
|
// ExprList, then we'll see if we can type convert it to the type of
|
||||||
// the variable.
|
// the variable.
|
||||||
if (dynamic_cast<ExprList *>(initExpr) == NULL) {
|
if (dynamic_cast<ExprList *>(initExpr) == NULL) {
|
||||||
Expr *tcInit = initExpr->TypeConv(type, "inititalizer", true);
|
initExpr = TypeConvertExpr(initExpr, type, "initializer");
|
||||||
if (tcInit != NULL) {
|
if (initExpr != NULL) {
|
||||||
llvm::Value *initializerValue = tcInit->GetValue(ctx);
|
llvm::Value *initializerValue = initExpr->GetValue(ctx);
|
||||||
if (initializerValue != NULL)
|
if (initializerValue != NULL)
|
||||||
// Bingo; store the value in the variable's storage
|
// Bingo; store the value in the variable's storage
|
||||||
ctx->StoreInst(initializerValue, lvalue);
|
ctx->StoreInst(initializerValue, lvalue);
|
||||||
@@ -380,10 +380,14 @@ DeclStmt::TypeCheck() {
|
|||||||
if (dynamic_cast<const AtomicType *>(type) != NULL ||
|
if (dynamic_cast<const AtomicType *>(type) != NULL ||
|
||||||
dynamic_cast<const EnumType *>(type) != NULL) {
|
dynamic_cast<const EnumType *>(type) != NULL) {
|
||||||
// If it's an expr list with an atomic type, we'll later issue
|
// If it's an expr list with an atomic type, we'll later issue
|
||||||
// an error. Need to leave decl->initExpr as is in that case so it
|
// an error. Need to leave vars[i].init as is in that case so
|
||||||
// is in fact caught later, though.
|
// it is in fact caught later, though.
|
||||||
if (dynamic_cast<ExprList *>(vars[i].init) == NULL)
|
if (dynamic_cast<ExprList *>(vars[i].init) == NULL) {
|
||||||
vars[i].init = vars[i].init->TypeConv(type, "initializer");
|
vars[i].init = TypeConvertExpr(vars[i].init, type,
|
||||||
|
"initializer");
|
||||||
|
if (vars[i].init == NULL)
|
||||||
|
encounteredError = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return encounteredError ? NULL : this;
|
return encounteredError ? NULL : this;
|
||||||
|
|||||||
Reference in New Issue
Block a user