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:
parent
31f85bc23e
commit
809d1408ce
5 changed files with 329 additions and 192 deletions
195
src/cc65/expr.c
195
src/cc65/expr.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ OBJS = anonname.o \
|
|||
scanner.o \
|
||||
scanstrbuf.o \
|
||||
segments.o \
|
||||
shiftexpr.o \
|
||||
stackptr.o \
|
||||
standard.o \
|
||||
stdfunc.o \
|
||||
|
|
|
@ -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
250
src/cc65/shiftexpr.c
Normal 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
74
src/cc65/shiftexpr.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue