X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=b0bc18d1481c5a4c3148c2506737e88002fc3e6c;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=298c7f6acbc1402ee2416972f3fbd9d623a8f866;hpb=9c5224165fe17e698a5530ee473087b479959161;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 298c7f6ac..b0bc18d14 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -109,12 +109,13 @@ void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) /* Do some checks if code generation is still constistent */ if (StackPtr != OldSP) { if (Debug) { - fprintf (stderr, - "Code generation messed up!\n" - "StackPtr is %d, should be %d", - StackPtr, OldSP); + Error ("Code generation messed up: " + "StackPtr is %d, should be %d", + StackPtr, OldSP); } else { - Internal ("StackPtr is %d, should be %d\n", StackPtr, OldSP); + Internal ("Code generation messed up: " + "StackPtr is %d, should be %d", + StackPtr, OldSP); } } } @@ -255,6 +256,18 @@ void PushAddr (const ExprDesc* Expr) +static void WarnConstCompareResult (void) +/* If the result of a comparison is constant, this is suspicious when not in + * preprocessor mode. + */ +{ + if (!Preprocessing) { + Warning ("Result of comparison is constant"); + } +} + + + /*****************************************************************************/ /* code */ /*****************************************************************************/ @@ -486,6 +499,12 @@ static void FunctionCall (ExprDesc* Expr) } } else { + /* Check function attributes */ + if (Expr->Sym && SymHasAttr (Expr->Sym, atNoReturn)) { + /* For now, handle as if a return statement was encountered */ + F_ReturnFound (CurrentFunc); + } + /* Check for known standard functions and inline them */ if (Expr->Name != 0) { int StdFunc = FindStdFunc ((const char*) Expr->Name); @@ -547,7 +566,7 @@ static void FunctionCall (ExprDesc* Expr) /* If we have a pointer on stack, remove it */ if (PtrOnStack) { - g_space (- (int) sizeofarg (CF_PTR)); + g_drop (SIZEOF_PTR); pop (CF_PTR); } @@ -742,10 +761,11 @@ static void Primary (ExprDesc* E) case TOK_SCONST: case TOK_WCSCONST: /* String literal */ - E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); + E->LVal = UseLiteral (CurTok.SVal); + E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal)); E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; - E->IVal = CurTok.IVal; - E->Name = LiteralPoolLabel; + E->IVal = 0; + E->Name = GetLiteralLabel (CurTok.SVal); NextToken (); break; @@ -870,7 +890,7 @@ static void ArrayRef (ExprDesc* Expr) ED_MakeConstAbsInt (&Subscript, 0); ElementType = Indirect (Expr->Type); } - + /* The element type has the combined qualifiers from itself and the array, * it is a member of (if any). */ @@ -1091,7 +1111,8 @@ static void StructRef (ExprDesc* Expr) NextToken (); if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1101,7 +1122,8 @@ static void StructRef (ExprDesc* Expr) Field = FindStructField (Expr->Type, Ident); if (Field == 0) { Error ("Struct/union has no field named `%s'", Ident); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1121,7 +1143,11 @@ static void StructRef (ExprDesc* Expr) Expr->IVal += Field->V.Offs; /* The type is the type of the field plus any qualifiers from the struct */ - Q = GetQualifier (Expr->Type); + if (IsClassStruct (Expr->Type)) { + Q = GetQualifier (Expr->Type); + } else { + Q = GetQualifier (Indirect (Expr->Type)); + } if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) { Expr->Type = Field->Type; } else { @@ -1891,18 +1917,23 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Helper function for the compare operators */ { ExprDesc Expr2; + CodeMark Mark0; CodeMark Mark1; CodeMark Mark2; const GenDesc* Gen; - token_t Tok; /* The operator token */ + token_t Tok; /* The operator token */ unsigned ltype; int rconst; /* Operand is a constant */ + GetCodePos (&Mark0); hienext (Expr); while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { + /* Remember the generator function */ + void (*GenFunc) (unsigned, unsigned long) = Gen->Func; + /* Remember the operator token, then skip it */ Tok = CurTok.Tok; NextToken (); @@ -1958,9 +1989,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* If the result is constant, this is suspicious when not in * preprocessor mode. */ - if (!Preprocessing) { - Warning ("Result of comparison is constant"); - } + WarnConstCompareResult (); /* Both operands are constant, remove the generated code */ RemoveCode (&Mark1); @@ -1998,7 +2027,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } } - } else { + } else { + + /* Determine the signedness of the operands */ + int LeftSigned = IsSignSigned (Expr->Type); + int RightSigned = IsSignSigned (Expr2.Type); /* If the right hand side is constant, and the generator function * expects the lhs in the primary, remove the push of the primary @@ -2013,27 +2046,180 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ } } - /* Determine the type of the operation result. If the left - * operand is of type char and the right is a constant, or - * if both operands are of type char, we will encode the - * operation as char operation. Otherwise the default - * promotions are used. - */ - if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) { - flags |= CF_CHAR; - if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) { - flags |= CF_UNSIGNED; - } - if (rconst) { - flags |= CF_FORCECHAR; - } + /* Determine the type of the operation. */ + if (IsTypeChar (Expr->Type) && rconst) { + + /* Left side is unsigned char, right side is constant. + * Determine the minimum and maximum values + */ + int LeftMin, LeftMax; + if (LeftSigned) { + LeftMin = -128; + LeftMax = 127; + } else { + LeftMin = 0; + LeftMax = 255; + } + /* An integer value is always represented as a signed in the + * ExprDesc structure. This may lead to false results below, + * if it is actually unsigned, but interpreted as signed + * because of the representation. Fortunately, in this case, + * the actual value doesn't matter, since it's always greater + * than what can be represented in a char. So correct the + * value accordingly. + */ + if (!RightSigned && Expr2.IVal < 0) { + /* Correct the value so it is an unsigned. It will then + * anyway match one of the cases below. + */ + Expr2.IVal = LeftMax + 1; + } + + /* Comparing a char against a constant may have a constant + * result. + */ + switch (Tok) { + + case TOK_EQ: + if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, 0); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_NE: + if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, 1); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_LT: + if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_LE: + if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_GE: + if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_GT: + if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + default: + Internal ("hie_compare: got token 0x%X\n", Tok); + } + + /* If the result is not already constant (as evaluated in the + * switch above), we can execute the operation as a char op, + * since the right side constant is in a valid range. + */ + flags |= (CF_CHAR | CF_FORCECHAR); + if (!LeftSigned) { + flags |= CF_UNSIGNED; + } + + } else if (IsTypeChar (Expr->Type) && IsTypeChar (Expr2.Type) && + GetSignedness (Expr->Type) == GetSignedness (Expr2.Type)) { + + /* Both are chars with the same signedness. We can encode the + * operation as a char operation. + */ + flags |= CF_CHAR; + if (rconst) { + flags |= CF_FORCECHAR; + } + if (!LeftSigned) { + flags |= CF_UNSIGNED; + } } else { - unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST); + unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST); flags |= g_typeadjust (ltype, rtype); } + /* If the left side is an unsigned and the right is a constant, + * we may be able to change the compares to something more + * effective. + */ + if (!LeftSigned && rconst) { + + switch (Tok) { + + case TOK_LT: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + * must be zero. + */ + GenFunc = g_eq; + Expr2.IVal = 0; + } + break; + + case TOK_LE: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + * must be zero. + */ + GenFunc = g_eq; + } + break; + + case TOK_GE: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + * must not be zero. + */ + GenFunc = g_ne; + Expr2.IVal = 0; + } + break; + + case TOK_GT: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + * must not be zero. + */ + GenFunc = g_ne; + } + break; + + default: + break; + + } + + } + /* Generate code */ - Gen->Func (flags, Expr2.IVal); + GenFunc (flags, Expr2.IVal); /* The result is an rvalue in the primary */ ED_MakeRValExpr (Expr); @@ -2042,7 +2228,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Result type is always int */ Expr->Type = type_int; - /* Condition codes are set */ +Done: /* Condition codes are set */ ED_TestDone (Expr); } }