cc65/src/cc65/shiftexpr.c

245 lines
9.1 KiB
C

/*****************************************************************************/
/* */
/* shiftexpr.c */
/* */
/* Parse the << and >> operators */
/* */
/* */
/* */
/* (C) 2004-2006 Ullrich von Bassewitz */
/* Roemerstrasse 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. */
{
CodeMark Mark1;
CodeMark Mark2;
token_t Tok; /* The operator token */
const Type* ResultType; /* Type of the result */
unsigned ExprBits; /* Bits of the lhs operand */
unsigned GenFlags; /* Generator flags */
unsigned ltype;
int lconst; /* Operand is a constant */
int rconst; /* Operand is a constant */
/* Evaluate the lhs */
ExprWithCheck (hie8, Expr);
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
ExprDesc Expr2;
ED_Init (&Expr2);
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
/* 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 type of the result */
ResultType = IntPromotion (Expr->Type);
/* Prepare the code generator flags */
GenFlags = TypeOf (ResultType);
/* Calculate the number of bits the lhs operand has */
ExprBits = SizeOf (ResultType) * 8;
/* Get the lhs on stack */
GetCodePos (&Mark1);
ltype = TypeOf (Expr->Type);
lconst = ED_IsConstAbs (Expr);
if (lconst) {
/* Constant value */
GetCodePos (&Mark2);
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
GetCodePos (&Mark2);
g_push (ltype, 0);
}
/* Get the right hand side */
MarkedExprWithCheck (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) && ED_CodeRangeIsEmpty (&Expr2);
if (!rconst) {
/* Not constant, load into the primary */
LoadExpr (CF_NONE, &Expr2);
} else {
/* The rhs is a constant numeric value. */
GenFlags |= CF_CONST;
/* Remove the code that pushes the rhs onto the stack. */
RemoveCode (&Mark2);
/* 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) {
Warning ("Shift count '%ld' is negative", Expr2.IVal);
Expr2.IVal &= ExprBits - 1;
} else if (Expr2.IVal >= (long) ExprBits) {
Warning ("Shift count '%ld' >= width of type", Expr2.IVal);
Expr2.IVal &= ExprBits - 1;
}
/* If the shift count is zero, nothing happens. If the left hand
** side is a constant, the result is constant.
*/
if (Expr2.IVal == 0 || lconst) {
/* Set the type */
Expr->Type = ResultType;
if (lconst) {
/* 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;
}
/* Limit the calculated value to the range of its type */
LimitExprValue (Expr);
}
/* Result is already got, remove the generated code */
RemoveCode (&Mark1);
/* Done */
continue;
}
/* If we're shifting an integer or unsigned to the right, the lhs
** has a quasi-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 &&
IsClassInt (Expr->Type) &&
SizeOf (Expr->Type) == SIZEOF_INT &&
ED_IsLVal (Expr) &&
ED_IsLocQuasiConst (Expr) &&
Expr2.IVal >= 8) {
/* 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.
*/
if (IsSignUnsigned (Expr->Type)) {
Expr->Type = type_uchar;
} else {
Expr->Type = type_schar;
}
/* Remove the generated load code */
RemoveCode (&Mark1);
/* Generate again code for the load, this time with the new type */
LoadExpr (CF_NONE, Expr);
/* 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 MakeRVal;
}
}
}
/* Generate code */
switch (Tok) {
case TOK_SHL: g_asl (GenFlags, Expr2.IVal); break;
case TOK_SHR: g_asr (GenFlags, Expr2.IVal); break;
default: break;
}
MakeRVal:
/* We have an rvalue in the primary now */
ED_FinalizeRValLoad (Expr);
/* Set the type of the result */
Expr->Type = ResultType;
/* Propagate from subexpressions */
Expr->Flags |= Expr2.Flags & E_MASK_VIRAL;
}
}