From d0674b170681aeb4b2a9fbfd5b67165caa9df909 Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Mon, 25 Jul 2011 23:36:05 +0100 Subject: [PATCH] When doing << or >> operators, don't convert the return type to the type of the shift amount. Fixes issue #73. Previously, if we had e.g. an int16 type that was being shifted left by 1, then the constant integer 1 would come in as an int32, we'd convert the int16 to an int32, and then we'd do the shift. Now, for shifts, the type of the expression is always the same as the type of the value being shifted. --- expr.cpp | 37 ++++++++++++++++++++++++++----------- expr.h | 2 +- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/expr.cpp b/expr.cpp index 5eb0ce34..22f04101 100644 --- a/expr.cpp +++ b/expr.cpp @@ -119,13 +119,14 @@ lMaybeIssuePrecisionWarning(const AtomicType *toAtomicType, errorMsgBase); break; default: - FATAL("logic error in lMaybeIssuePrecisionWarning"); + FATAL("logic error in lMaybeIssuePrecisionWarning()"); } } Expr * -Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk) { +Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk, + bool issuePrecisionWarnings) { /* This function is way too long and complex. Is type conversion stuff always this messy, or can this be cleaned up somehow? */ assert(failureOk || errorMsgBase != NULL); @@ -313,7 +314,7 @@ Expr::TypeConv(const Type *toType, const char *errorMsgBase, bool failureOk) { return NULL; } - if (!failureOk) + if (!failureOk && issuePrecisionWarnings) lMaybeIssuePrecisionWarning(toAtomicType, fromAtomicType, pos, errorMsgBase); @@ -1010,6 +1011,7 @@ BinaryExpr::GetType() const { return lMatchingBoolType(promotedType); case Shl: case Shr: + return type1->IsVaryingType() ? type0->GetAsVaryingType() : type0; case BitAnd: case BitXor: case BitOr: @@ -1309,15 +1311,28 @@ BinaryExpr::TypeCheck() { return NULL; } - const Type *promotedType = Type::MoreGeneralType(type0, type1, arg0->pos, - "binary bit op"); - if (promotedType == NULL) - return NULL; + if (op == Shl || op == Shr) { + bool isVarying = (type0->IsVaryingType() || + type1->IsVaryingType()); + if (isVarying) { + arg0 = arg0->TypeConv(type0->GetAsVaryingType(), "shift operator"); + type0 = arg0->GetType(); + } + arg1 = arg1->TypeConv(type0, "shift operator", false, false); + if (arg1 == NULL) + return NULL; + } + else { + const Type *promotedType = Type::MoreGeneralType(type0, type1, arg0->pos, + "binary bit op"); + if (promotedType == NULL) + return NULL; - arg0 = arg0->TypeConv(promotedType, "binary bit op"); - arg1 = arg1->TypeConv(promotedType, "binary bit op"); - if (arg0 == NULL || arg1 == NULL) - return NULL; + arg0 = arg0->TypeConv(promotedType, "binary bit op"); + arg1 = arg1->TypeConv(promotedType, "binary bit op"); + if (arg0 == NULL || arg1 == NULL) + return NULL; + } return this; } case Add: diff --git a/expr.h b/expr.h index 92eb53bf..9be0aec7 100644 --- a/expr.h +++ b/expr.h @@ -97,7 +97,7 @@ public: 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 failureOk = false, bool issuePrecisionWarnings = true); };