From d65c02f3231eea37367aa66ebb92fc62051e09d1 Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Tue, 29 Nov 2011 17:22:22 -0800 Subject: [PATCH] Allow '0' to convert to a NULL pointer value. --- expr.cpp | 149 ++++++++++++++++++++++++++++++++++++++++--------------- expr.h | 15 +++++- 2 files changed, 122 insertions(+), 42 deletions(-) diff --git a/expr.cpp b/expr.cpp index c8c8bdfc..8b9e7042 100644 --- a/expr.cpp +++ b/expr.cpp @@ -135,6 +135,29 @@ lMaybeIssuePrecisionWarning(const AtomicType *toAtomicType, /////////////////////////////////////////////////////////////////////////// +static bool +lIsAllIntZeros(Expr *expr) { + const Type *type = expr->GetType(); + if (type == NULL || type->IsIntType() == false) + return false; + + ConstExpr *ce = dynamic_cast(expr); + if (ce == NULL) + return false; + + uint64_t vals[ISPC_MAX_NVEC]; + int count = ce->AsUInt64(vals); + if (count == 1) + return (vals[0] == 0); + else { + for (int i = 0; i < count; ++i) + if (vals[i] != 0) + return false; + } + return true; +} + + static bool lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr, bool failureOk, const char *errorMsgBase, SourcePos pos) { @@ -255,6 +278,21 @@ lDoTypeConv(const Type *fromType, const Type *toType, Expr **expr, return true; } + if (toPointerType != NULL && fromAtomicType != NULL && + fromAtomicType->IsIntType() && expr != NULL && + lIsAllIntZeros(*expr)) { + // We have a zero-valued integer expression, which can also be + // treated as a NULL pointer that can be converted to any other + // pointer type. + Expr *npe = new NullPointerExpr(pos); + if (lDoTypeConv(PointerType::Void, toType, &npe, + failureOk, errorMsgBase, pos)) { + *expr = npe; + return true; + } + return false; + } + // Convert from type T -> const T; just return a TypeCast expr, which // can handle this if (Type::Equal(toType, fromType->GetAsConstType())) @@ -1294,6 +1332,7 @@ BinaryExpr::GetType() const { // ptr - int -> ptr return type0; } + // otherwise fall through for these... assert(op == Lt || op == Gt || op == Le || op == Ge || op == Equal || op == NotEqual); @@ -1762,6 +1801,20 @@ BinaryExpr::TypeCheck() { case NotEqual: { const PointerType *pt0 = dynamic_cast(type0); const PointerType *pt1 = dynamic_cast(type1); + + // Convert '0' in expressions where the other expression is a + // pointer type to a NULL pointer. + if (pt0 != NULL && lIsAllIntZeros(arg1)) { + arg1 = new NullPointerExpr(pos); + type1 = arg1->GetType(); + pt1 = dynamic_cast(type1); + } + else if (pt1 != NULL && lIsAllIntZeros(arg0)) { + arg0 = new NullPointerExpr(pos); + type0 = arg1->GetType(); + pt0 = dynamic_cast(type0); + } + if (pt0 == NULL && pt1 == NULL) { if (!type0->IsBoolType() && !type0->IsNumericType()) { Error(arg0->pos, @@ -2613,6 +2666,7 @@ FunctionCallExpr::TypeCheck() { FunctionSymbolExpr *fse = dynamic_cast(func); if (fse != NULL) { std::vector argTypes; + std::vector argCouldBeNULL; for (unsigned int i = 0; i < args->exprs.size(); ++i) { if (args->exprs[i] == NULL) return NULL; @@ -2620,40 +2674,43 @@ FunctionCallExpr::TypeCheck() { if (t == NULL) return NULL; argTypes.push_back(t); + argCouldBeNULL.push_back(lIsAllIntZeros(args->exprs[i])); } - if (fse->ResolveOverloads(argTypes) == true) { - func = fse->TypeCheck(); + if (fse->ResolveOverloads(argTypes, &argCouldBeNULL) == false) + return NULL; - if (func != NULL) { - const PointerType *pt = - dynamic_cast(func->GetType()); - const FunctionType *ft = (pt == NULL) ? NULL : - dynamic_cast(pt->GetBaseType()); - if (ft != NULL) { - if (ft->isTask) { - if (!isLaunch) - Error(pos, "\"launch\" expression needed to call function " - "with \"task\" qualifier."); - if (!launchCountExpr) - return NULL; + func = fse->TypeCheck(); + if (func == NULL) + return NULL; - launchCountExpr = - TypeConvertExpr(launchCountExpr, AtomicType::UniformInt32, - "task launch count"); - if (launchCountExpr == NULL) - return NULL; - } - else { - if (isLaunch) - Error(pos, "\"launch\" expression illegal with non-\"task\"-" - "qualified function."); - assert(launchCountExpr == NULL); - } - } - else - Error(pos, "Valid function name must be used for function call."); - } + const PointerType *pt = + dynamic_cast(func->GetType()); + const FunctionType *ft = (pt == NULL) ? NULL : + dynamic_cast(pt->GetBaseType()); + if (ft == NULL) { + Error(pos, "Valid function name must be used for function call."); + return NULL; + } + + if (ft->isTask) { + if (!isLaunch) + Error(pos, "\"launch\" expression needed to call function " + "with \"task\" qualifier."); + if (!launchCountExpr) + return NULL; + + launchCountExpr = + TypeConvertExpr(launchCountExpr, AtomicType::UniformInt32, + "task launch count"); + if (launchCountExpr == NULL) + return NULL; + } + else { + if (isLaunch) + Error(pos, "\"launch\" expression illegal with non-\"task\"-" + "qualified function."); + assert(launchCountExpr == NULL); } } else { @@ -6368,7 +6425,8 @@ lGetBestMatch(std::vector > &matches) { */ bool FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *), - const std::vector &callTypes) { + const std::vector &callTypes, + const std::vector *argCouldBeNULL) { const char *funName = candidateFunctions->front()->name.c_str(); std::vector > matches; @@ -6402,7 +6460,17 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *), dynamic_cast(callTypes[i]) != NULL) return false; - int argCost = matchFunc(callTypes[i], paramType); + int argCost; + if (argCost == -1 && argCouldBeNULL != NULL && + (*argCouldBeNULL)[i] == true && + dynamic_cast(paramType) != NULL) + // If the passed argument value is zero and this is a + // pointer type, then it can convert to a NULL value of + // that pointer type. + argCost = 0; + else + argCost= matchFunc(callTypes[i], paramType); + if (argCost == -1) // If the predicate function returns -1, we have failed no // matter what else happens, so we stop trying @@ -6447,7 +6515,8 @@ FunctionSymbolExpr::tryResolve(int (*matchFunc)(const Type *, const Type *), bool -FunctionSymbolExpr::ResolveOverloads(const std::vector &argTypes) { +FunctionSymbolExpr::ResolveOverloads(const std::vector &argTypes, + const std::vector *argCouldBeNULL) { triedToResolve = true; // Functions with names that start with "__" should only be various @@ -6460,32 +6529,32 @@ FunctionSymbolExpr::ResolveOverloads(const std::vector &argTypes) // Is there an exact match that doesn't require any argument type // conversion (other than converting type -> reference type)? - if (tryResolve(lExactMatch, argTypes)) + if (tryResolve(lExactMatch, argTypes, argCouldBeNULL)) return true; if (exactMatchOnly == false) { // Try to find a single match ignoring references - if (tryResolve(lMatchIgnoringReferences, argTypes)) + if (tryResolve(lMatchIgnoringReferences, argTypes, argCouldBeNULL)) return true; // Try to find an exact match via type widening--i.e. int8 -> // int16, etc.--things that don't lose data. - if (tryResolve(lMatchWithTypeWidening, argTypes)) + if (tryResolve(lMatchWithTypeWidening, argTypes, argCouldBeNULL)) return true; // Next try to see if there's a match via just uniform -> varying // promotions. - if (tryResolve(lMatchIgnoringUniform, argTypes)) + if (tryResolve(lMatchIgnoringUniform, argTypes, argCouldBeNULL)) return true; // Try to find a match via type conversion, but don't change // unif->varying - if (tryResolve(lMatchWithTypeConvSameVariability, - argTypes)) + if (tryResolve(lMatchWithTypeConvSameVariability, argTypes, + argCouldBeNULL)) return true; // Last chance: try to find a match via arbitrary type conversion. - if (tryResolve(lMatchWithTypeConv, argTypes)) + if (tryResolve(lMatchWithTypeConv, argTypes, argCouldBeNULL)) return true; } diff --git a/expr.h b/expr.h index 4de7ddb1..8ef55396 100644 --- a/expr.h +++ b/expr.h @@ -625,12 +625,23 @@ public: int EstimateCost() const; llvm::Constant *GetConstant(const Type *type) const; - bool ResolveOverloads(const std::vector &argTypes); + /** Given the types of the function arguments, in the presence of + function overloading, this method resolves which actual function + the arguments match best. If the argCouldBeNULL parameter is + non-NULL, each element indicates whether the corresponding argument + is the number zero, indicating that it could be a NULL pointer. + This parameter may be NULL (for cases where overload resolution is + being done just given type information without the parameter + argument expressions being available. It returns true on success. + */ + bool ResolveOverloads(const std::vector &argTypes, + const std::vector *argCouldBeNULL = NULL); Symbol *GetMatchingFunction(); private: bool tryResolve(int (*matchFunc)(const Type *, const Type *), - const std::vector &argTypes); + const std::vector &argTypes, + const std::vector *argCouldBeNULL); /** Name of the function that is being called. */ std::string name;