1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-29 10:29:30 +00:00

Move shift expression evaluation into a separate module. More checks and

improvements for shift expressions.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3138 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2004-06-29 20:44:01 +00:00
parent 31f85bc23e
commit 809d1408ce
5 changed files with 329 additions and 192 deletions

View File

@ -29,6 +29,7 @@
#include "macrotab.h"
#include "preproc.h"
#include "scanner.h"
#include "shiftexpr.h"
#include "stackptr.h"
#include "stdfunc.h"
#include "symtab.h"
@ -86,7 +87,7 @@ static unsigned GlobalModeFlags (unsigned Flags)
}
}
void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr)
/* Call an expression function with checks. */
@ -2281,196 +2282,6 @@ void hie8 (ExprDesc* Expr)
static void hie7 (ExprDesc* Expr)
/* Parse the << and >> operators. */
{
ExprDesc Expr2;
CodeMark Mark1;
CodeMark Mark2;
token_t Tok; /* The operator token */
unsigned ltype, rtype, flags;
int rconst; /* Operand is a constant */
/* Evaluate the lhs */
ExprWithCheck (hie8, Expr);
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
/* All operators that call this function expect an int on the lhs */
if (!IsClassInt (Expr->Type)) {
Error ("Integer expression expected");
ED_MakeConstAbsInt (Expr, 1);
}
/* Remember the operator token, then skip it */
Tok = CurTok.Tok;
NextToken ();
/* Get the lhs on stack */
Mark1 = GetCodePos ();
ltype = TypeOf (Expr->Type);
if (ED_IsConstAbs (Expr)) {
/* Constant value */
Mark2 = GetCodePos ();
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
Mark2 = GetCodePos ();
g_push (ltype, 0);
}
/* Get the right hand side */
ExprWithCheck (hie8, &Expr2);
/* Check the type of the rhs */
if (!IsClassInt (Expr2.Type)) {
Error ("Integer expression expected");
ED_MakeConstAbsInt (&Expr2, 1);
}
/* Check for a constant right side expression */
rconst = ED_IsConstAbs (&Expr2);
if (!rconst) {
/* Not constant, load into the primary */
LoadExpr (CF_NONE, &Expr2);
} else {
/* If the right hand side is constant, we can check a lot of
* things:
*/
/* If the shift count is zero, nothing happens */
if (Expr2.IVal == 0) {
/* Result is already in Expr, remove the generated code */
RemoveCode (Mark1);
pop (ltype);
/* Done */
goto Next;
}
/* If the left hand side is a constant, the result is constant */
if (ED_IsConstAbs (Expr)) {
/* Evaluate the result */
Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
/* Both operands are constant, remove the generated code */
RemoveCode (Mark1);
pop (ltype);
/* Done */
goto Next;
}
/* If we're shifting to the left, and the shift count is larger
* or equal than the bit count of the integer type, the result
* is zero.
*/
if (Tok == TOK_SHL && Expr2.IVal >= (long) SizeOf (Expr->Type) * 8) {
/* Set the result */
ED_MakeConstAbs (Expr, 0, Expr->Type);
/* Result is zero, remove the generated code */
RemoveCode (Mark1);
pop (ltype);
/* Done */
goto Next;
}
/* If we're shifting an integer or unsigned to the right, the
* lhs has a const address, and the shift count is larger than 8,
* we can load just the high byte as a char with the correct
* signedness, and reduce the shift count by 8. If the remaining
* shift count is zero, we're done.
*/
if (Tok == TOK_SHR &&
IsTypeInt (Expr->Type) &&
ED_IsLVal (Expr) &&
(ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) &&
Expr2.IVal >= 8) {
type* OldType;
/* Increase the address by one and decrease the shift count */
++Expr->IVal;
Expr2.IVal -= 8;
/* Replace the type of the expression temporarily by the
* corresponding char type.
*/
OldType = Expr->Type;
if (IsSignUnsigned (Expr->Type)) {
Expr->Type = type_uchar;
} else {
Expr->Type = type_schar;
}
/* Remove the generated load code */
RemoveCode (Mark1);
pop (ltype);
/* Generate again code for the load */
LoadExpr (CF_NONE, Expr);
/* Reset the type */
Expr->Type = OldType;
/* If the shift count is now zero, we're done */
if (Expr2.IVal == 0) {
/* Be sure to mark the value as in the primary */
goto Loaded;
}
/* Otherwise generate code to push the value */
Mark2 = GetCodePos ();
g_push (ltype, 0);
}
}
/* If the right hand side is a constant, remove the push of the
* primary register.
*/
rtype = TypeOf (Expr2.Type);
flags = 0;
if (rconst) {
flags |= CF_CONST;
rtype |= CF_CONST;
RemoveCode (Mark2);
pop (ltype);
ltype |= CF_REG; /* Value is in register */
}
/* Determine the type of the operation result. */
flags |= g_typeadjust (ltype, rtype);
/* Generate code */
switch (Tok) {
case TOK_SHL: g_asl (flags, Expr2.IVal); break;
case TOK_SHR: g_asr (flags, Expr2.IVal); break;
default: break;
}
Loaded:
/* We have a rvalue in the primary now */
ED_MakeRValExpr (Expr);
Next:
/* Get the type of the result */
Expr->Type = promoteint (Expr->Type, Expr2.Type);
}
}
static void hie6 (ExprDesc* Expr)
/* Handle greater-than type comparators */
{
@ -2481,7 +2292,7 @@ static void hie6 (ExprDesc* Expr)
{ TOK_GT, GEN_NOPUSH, g_gt },
{ TOK_INVALID, 0, 0 }
};
hie_compare (hie6_ops, Expr, hie7);
hie_compare (hie6_ops, Expr, ShiftExpr);
}

View File

@ -78,6 +78,7 @@ OBJS = anonname.o \
scanner.o \
scanstrbuf.o \
segments.o \
shiftexpr.o \
stackptr.o \
standard.o \
stdfunc.o \

View File

@ -113,6 +113,7 @@ OBJS = anonname.obj \
scanner.obj \
scanstrbuf.obj \
segments.obj \
shiftexpr.obj \
stackptr.obj \
standard.obj \
stdfunc.obj \

250
src/cc65/shiftexpr.c Normal file
View File

@ -0,0 +1,250 @@
/*****************************************************************************/
/* */
/* shiftexpr.c */
/* */
/* Parse the << and >> operators */
/* */
/* */
/* */
/* (C) 2004 Ullrich von Bassewitz */
/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* cc65 */
#include "asmcode.h"
#include "codegen.h"
#include "datatype.h"
#include "error.h"
#include "expr.h"
#include "exprdesc.h"
#include "loadexpr.h"
#include "scanner.h"
#include "shiftexpr.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void ShiftExpr (struct ExprDesc* Expr)
/* Parse the << and >> operators. */
{
ExprDesc Expr2;
CodeMark Mark1;
CodeMark Mark2;
token_t Tok; /* The operator token */
unsigned ExprBits; /* Bits of the lhs operand */
unsigned ltype, rtype, flags;
int rconst; /* Operand is a constant */
/* Evaluate the lhs */
ExprWithCheck (hie8, Expr);
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
/* All operators that call this function expect an int on the lhs */
if (!IsClassInt (Expr->Type)) {
Error ("Integer expression expected");
ED_MakeConstAbsInt (Expr, 1);
}
/* Remember the operator token, then skip it */
Tok = CurTok.Tok;
NextToken ();
/* Calculate the number of bits the lhs operand has */
ExprBits = SizeOf (Expr->Type) * 8;
/* Get the lhs on stack */
Mark1 = GetCodePos ();
ltype = TypeOf (Expr->Type);
if (ED_IsConstAbs (Expr)) {
/* Constant value */
Mark2 = GetCodePos ();
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
Mark2 = GetCodePos ();
g_push (ltype, 0);
}
/* Get the right hand side */
ExprWithCheck (hie8, &Expr2);
/* Check the type of the rhs */
if (!IsClassInt (Expr2.Type)) {
Error ("Integer expression expected");
ED_MakeConstAbsInt (&Expr2, 1);
}
/* Check for a constant right side expression */
rconst = ED_IsConstAbs (&Expr2);
if (!rconst) {
/* Not constant, load into the primary */
LoadExpr (CF_NONE, &Expr2);
} else {
/* The rhs is a constant numeric value */
/* If the shift count is greater or equal than the bit count of
* the operand, the behaviour is undefined according to the
* standard.
*/
if (Expr2.IVal < 0 || Expr2.IVal >= (long) ExprBits) {
Warning ("Shift count too large for operand type");
Expr2.IVal &= ExprBits - 1;
}
/* If the shift count is zero, nothing happens */
if (Expr2.IVal == 0) {
/* Result is already in Expr, remove the generated code */
RemoveCode (Mark1);
pop (ltype);
/* Done */
goto Next;
}
/* If the left hand side is a constant, the result is constant */
if (ED_IsConstAbs (Expr)) {
/* Evaluate the result */
switch (Tok) {
case TOK_SHL: Expr->IVal <<= Expr2.IVal; break;
case TOK_SHR: Expr->IVal >>= Expr2.IVal; break;
default: /* Shutup gcc */ break;
}
/* Both operands are constant, remove the generated code */
RemoveCode (Mark1);
pop (ltype);
/* Done */
goto Next;
}
/* If we're shifting an integer or unsigned to the right, the
* lhs has a const address, and the shift count is larger than 8,
* we can load just the high byte as a char with the correct
* signedness, and reduce the shift count by 8. If the remaining
* shift count is zero, we're done.
*/
if (Tok == TOK_SHR &&
IsTypeInt (Expr->Type) &&
ED_IsLVal (Expr) &&
(ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) &&
Expr2.IVal >= 8) {
type* OldType;
/* Increase the address by one and decrease the shift count */
++Expr->IVal;
Expr2.IVal -= 8;
/* Replace the type of the expression temporarily by the
* corresponding char type.
*/
OldType = Expr->Type;
if (IsSignUnsigned (Expr->Type)) {
Expr->Type = type_uchar;
} else {
Expr->Type = type_schar;
}
/* Remove the generated load code */
RemoveCode (Mark1);
pop (ltype);
/* Generate again code for the load */
LoadExpr (CF_NONE, Expr);
/* Reset the type */
Expr->Type = OldType;
/* If the shift count is now zero, we're done */
if (Expr2.IVal == 0) {
/* Be sure to mark the value as in the primary */
goto Loaded;
}
/* Otherwise generate code to push the value */
Mark2 = GetCodePos ();
g_push (ltype, 0);
}
}
/* If the right hand side is a constant, remove the push of the
* primary register.
*/
rtype = TypeOf (Expr2.Type);
flags = 0;
if (rconst) {
flags |= CF_CONST;
rtype |= CF_CONST;
RemoveCode (Mark2);
pop (ltype);
ltype |= CF_REG; /* Value is in register */
}
/* Determine the type of the operation result. */
flags |= g_typeadjust (ltype, rtype);
/* Generate code */
switch (Tok) {
case TOK_SHL: g_asl (flags, Expr2.IVal); break;
case TOK_SHR: g_asr (flags, Expr2.IVal); break;
default: break;
}
Loaded:
/* We have a rvalue in the primary now */
ED_MakeRValExpr (Expr);
Next:
/* Get the type of the result */
Expr->Type = IntPromotion (Expr->Type);
}
}

74
src/cc65/shiftexpr.h Normal file
View File

@ -0,0 +1,74 @@
/*****************************************************************************/
/* */
/* shiftexpr.h */
/* */
/* Parse the << and >> operators */
/* */
/* */
/* */
/* (C) 2004 Ullrich von Bassewitz */
/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef SHIFTEXPR_H
#define SHIFTEXPT_H
/* common */
#include "intstack.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Forward */
struct ExprDesc;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void ShiftExpr (struct ExprDesc* Expr);
/* Parse the << and >> operators. */
/* End of shiftexpr.h */
#endif