/*****************************************************************************/ /* */ /* shiftexpr.c */ /* */ /* Parse the << and >> operators */ /* */ /* */ /* */ /* (C) 2004-2006 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 */ Type* EffType; /* Effective lhs type */ Type* ResultType; /* Type of the result */ unsigned ExprBits; /* Bits of the lhs operand */ unsigned GenFlags; /* Generator flags */ unsigned ltype; 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 type of the result */ ResultType = EffType = 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); if (ED_IsConstAbs (Expr)) { /* 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 */ 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. */ 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 || 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); /* 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); /* 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); /* Generate again code for the load, this time with the new type */ 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 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 a rvalue in the primary now */ ED_MakeRValExpr (Expr); Next: /* Set the type of the result */ Expr->Type = ResultType; } }