/* */
/* */
/* */
-/* (C) 2000-2001 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
+/* (C) 2000-2004 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
#include "check.h"
/* cc65 */
+#include "asmcode.h"
#include "codeopt.h"
#include "codeseg.h"
#include "dataseg.h"
#include "segments.h"
+#include "stackptr.h"
#include "symtab.h"
-#include "asmcode.h"
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-CodeMark GetCodePos (void)
+void GetCodePos (CodeMark* M)
/* Get a marker pointing to the current output position */
{
- return CS_GetEntryCount (CS->Code);
+ M->Pos = CS_GetEntryCount (CS->Code);
+ M->SP = StackPtr;
}
-void RemoveCode (CodeMark M)
+void RemoveCode (const CodeMark* M)
/* Remove all code after the given code marker */
{
- CS_DelCodeAfter (CS->Code, M);
+ CS_DelCodeAfter (CS->Code, M->Pos);
+ StackPtr = M->SP;
}
-void MoveCode (CodeMark Start, CodeMark End, CodeMark Target)
+void MoveCode (const CodeMark* Start, const CodeMark* End, const CodeMark* Target)
/* Move the code between Start (inclusive) and End (exclusive) to
- * (before) Target.
+ * (before) Target. The code marks aren't updated.
*/
{
- CS_MoveEntries (CS->Code, Start, End - Start, Target);
+ CS_MoveEntries (CS->Code, Start->Pos, End->Pos - Start->Pos, Target->Pos);
+}
+
+
+
+int CodeRangeIsEmpty (const CodeMark* Start, const CodeMark* End)
+/* Return true if the given code range is empty (no code between Start and End) */
+{
+ int Empty;
+ PRECONDITION (Start->Pos >= End->Pos);
+ Empty = (Start->Pos == End->Pos);
+ if (Empty) {
+ /* Safety */
+ CHECK (Start->SP == End->SP);
+ }
+ return Empty;
}
/* */
/* */
/* */
-/* (C) 2000-2001 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
+/* (C) 2000-2004 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* Marker for an assembler code position */
-typedef unsigned CodeMark;
+typedef struct {
+ unsigned Pos; /* Code position */
+ int SP; /* Stack pointer at this position */
+} CodeMark;
-CodeMark GetCodePos (void);
+void GetCodePos (CodeMark* M);
/* Get a marker pointing to the current output position */
-void RemoveCode (CodeMark M);
+void RemoveCode (const CodeMark* M);
/* Remove all code after the given code marker */
-void MoveCode (CodeMark Start, CodeMark End, CodeMark Target);
+void MoveCode (const CodeMark* Start, const CodeMark* End, const CodeMark* Target);
/* Move the code between Start (inclusive) and End (exclusive) to
- * (before) Target.
+ * (before) Target. The code marks aren't updated.
*/
+int CodeRangeIsEmpty (const CodeMark* Start, const CodeMark* End);
+/* Return true if the given code range is empty (no code between Start and End) */
+
void WriteOutput (FILE* F);
/* Write the final output to a file */
int IsFuncPtr; /* Flag */
int StdFunc; /* Standard function index */
unsigned ParamSize; /* Number of parameter bytes */
- CodeMark Mark = 0; /* Initialize to keep gcc silent */
+ CodeMark Mark;
int PtrOffs = 0; /* Offset of function pointer on stack */
int IsFastCall = 0; /* True if it's a fast call function */
int PtrOnStack = 0; /* True if a pointer copy is on stack */
ED_MakeRValExpr (Expr);
/* Remember the code position */
- Mark = GetCodePos ();
+ GetCodePos (&Mark);
/* Push the pointer onto the stack and remember the offset */
g_push (CF_PTR, 0);
* stack pointer.
*/
if (ParamSize == 0) {
- RemoveCode (Mark);
- pop (CF_PTR);
+ RemoveCode (&Mark);
PtrOnStack = 0;
} else {
/* Load from the saved copy */
ConstBaseAddr = (ED_IsLocConst (Expr) || ED_IsLocStack (Expr));
/* If we have a constant base, we delay the address fetch */
- Mark1 = GetCodePos ();
- Mark2 = 0; /* Silence gcc */
+ GetCodePos (&Mark1);
if (!ConstBaseAddr) {
/* Get a pointer to the array into the primary */
LoadExpr (CF_NONE, Expr);
* bit, even if this value is greater, since we cannot handle
* other than 16bit stuff when doing indexing.
*/
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (CF_PTR, 0);
}
* since we can generate expression+offset.
*/
if (!ConstBaseAddr) {
- RemoveCode (Mark2);
- pop (CF_PTR);
+ RemoveCode (&Mark2);
} else {
/* Get an array pointer into the primary */
LoadExpr (CF_NONE, Expr);
SubScript.IVal *= CheckedSizeOf (ElementType);
/* Remove the address load code */
- RemoveCode (Mark1);
+ RemoveCode (&Mark1);
/* In case of an array, we can adjust the offset of the expression
* already in Expr. If the base address was a constant, we can even
} else {
/* Array subscript is not constant. Load it into the primary */
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
LoadExpr (CF_NONE, &SubScript);
/* Do scaling */
} else {
Flags = CF_INT;
}
- RemoveCode (Mark2);
+ RemoveCode (&Mark2);
/* Get a pointer to the array into the primary. */
LoadExpr (CF_NONE, Expr);
ConsumeRParen ();
} else {
/* Remember the output queue pointer */
- CodeMark Mark = GetCodePos ();
+ CodeMark Mark;
+ GetCodePos (&Mark);
hie10 (Expr);
Size = CheckedSizeOf (Expr->Type);
/* Remove any generated code */
- RemoveCode (Mark);
+ RemoveCode (&Mark);
}
ED_MakeConstAbs (Expr, Size, type_size_t);
ED_MarkAsUntested (Expr);
NextToken ();
/* Get the lhs on stack */
- Mark1 = GetCodePos ();
+ GetCodePos (&Mark1);
ltype = TypeOf (Expr->Type);
if (ED_IsConstAbs (Expr)) {
/* Constant value */
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype, 0);
}
if (ED_IsConstAbs (Expr) && rconst) {
/* Both operands are constant, remove the generated code */
- RemoveCode (Mark1);
- pop (ltype);
+ RemoveCode (&Mark1);
/* Evaluate the result */
Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
Error ("Modulo operation with zero");
}
if ((Gen->Flags & GEN_NOPUSH) != 0) {
- RemoveCode (Mark2);
- pop (ltype);
+ RemoveCode (&Mark2);
ltype |= CF_REG; /* Value is in register */
}
}
NextToken ();
/* Get the lhs on stack */
- Mark1 = GetCodePos ();
+ GetCodePos (&Mark1);
ltype = TypeOf (Expr->Type);
if (ED_IsConstAbs (Expr)) {
/* Constant value */
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype, 0);
}
if (ED_IsConstAbs (Expr) && rconst) {
/* Both operands are constant, remove the generated code */
- RemoveCode (Mark1);
- pop (ltype);
+ RemoveCode (&Mark1);
/* Evaluate the result */
Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal);
if (rconst) {
flags |= CF_CONST;
if ((Gen->Flags & GEN_NOPUSH) != 0) {
- RemoveCode (Mark2);
- pop (ltype);
+ RemoveCode (&Mark2);
ltype |= CF_REG; /* Value is in register */
}
}
/* Left hand side is not constant. Get the value onto the stack. */
LoadExpr (CF_NONE, Expr); /* --> primary register */
- Mark = GetCodePos ();
+ GetCodePos (&Mark);
g_push (TypeOf (Expr->Type), 0); /* --> stack */
/* Evaluate the rhs */
rhst = Expr2.Type;
/* Remove pushed value from stack */
- RemoveCode (Mark);
- pop (TypeOf (Expr->Type));
+ RemoveCode (&Mark);
/* Check for pointer arithmetic */
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
rscale = 1; /* Scale by 1, that is, don't scale */
/* Remember the output queue position, then bring the value onto the stack */
- Mark1 = GetCodePos ();
+ GetCodePos (&Mark1);
LoadExpr (CF_NONE, Expr); /* --> primary register */
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (TypeOf (lhst), 0); /* --> stack */
/* Parse the right hand side */
if (ED_IsConstAbs (Expr)) {
/* Both sides are constant, remove generated code */
- RemoveCode (Mark1);
- pop (TypeOf (lhst)); /* Clean up the stack */
+ RemoveCode (&Mark1);
/* Check for pointer arithmetic */
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
/* Left hand side is not constant, right hand side is.
* Remove pushed value from stack.
*/
- RemoveCode (Mark2);
- pop (TypeOf (lhst));
+ RemoveCode (&Mark2);
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
/* Left is pointer, right is int, must scale rhs */
LoadExpr (CF_NONE, Expr);
/* Bring the lhs on stack */
- Mark = GetCodePos ();
+ GetCodePos (&Mark);
g_push (flags, 0);
/* Evaluate the rhs */
if (evalexpr (CF_NONE, hie1, &Expr2) == 0) {
- /* The resulting value is a constant. If the generator has the NOPUSH
- * flag set, don't push the lhs.
- */
- if (Gen->Flags & GEN_NOPUSH) {
- RemoveCode (Mark);
- pop (flags);
+ /* The resulting value is a constant. If the generator has the NOPUSH
+ * flag set, don't push the lhs.
+ */
+ if (Gen->Flags & GEN_NOPUSH) {
+ RemoveCode (&Mark);
}
if (MustScale) {
/* lhs is a pointer, scale rhs */
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
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 ltype, rtype, flags;
+ unsigned GenFlags; /* Generator flags */
+ unsigned ltype;
int rconst; /* Operand is a constant */
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 (Expr->Type) * 8;
+ ExprBits = SizeOf (ResultType) * 8;
/* Get the lhs on stack */
- Mark1 = GetCodePos ();
- ltype = TypeOf (Expr->Type);
+ GetCodePos (&Mark1);
+ ltype = TypeOf (Expr->Type);
if (ED_IsConstAbs (Expr)) {
/* Constant value */
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype | CF_CONST, Expr->IVal);
} else {
/* Value not constant */
LoadExpr (CF_NONE, Expr);
- Mark2 = GetCodePos ();
+ GetCodePos (&Mark2);
g_push (ltype, 0);
}
} else {
- /* The rhs is a constant numeric value */
+ /* 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
if (Expr2.IVal == 0) {
/* Result is already in Expr, remove the generated code */
- RemoveCode (Mark1);
- pop (ltype);
+ RemoveCode (&Mark1);
/* Done */
goto Next;
}
/* Both operands are constant, remove the generated code */
- RemoveCode (Mark1);
- pop (ltype);
+ RemoveCode (&Mark1);
/* Done */
goto Next;
}
/* Remove the generated load code */
- RemoveCode (Mark1);
- pop (ltype);
+ RemoveCode (&Mark1);
/* Generate again code for the load */
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 Loaded;
+ goto MakeRVal;
}
-
- /* 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;
+ case TOK_SHL: g_asl (GenFlags, Expr2.IVal); break;
+ case TOK_SHR: g_asr (GenFlags, Expr2.IVal); break;
+ default: break;
}
-Loaded:
+MakeRVal:
/* We have a rvalue in the primary now */
ED_MakeRValExpr (Expr);
Next:
- /* Get the type of the result */
- Expr->Type = IntPromotion (Expr->Type);
+ /* Set the type of the result */
+ Expr->Type = ResultType;
}
}
+void SP_Push (const type* T)
+/* Adjust the stackpointer for a push of an argument of the given type */
+{
+ StackPtr -= SizeOf (T);
+}
+
+
+
+void SP_Pop (const type* T)
+/* Adjust the stackpointer for a pop of an argument of the given type */
+{
+ StackPtr += SizeOf (T);
+}
+
+
+
+
#define STACKPTR_H
+
+/* cc65 */
+#include "datatype.h"
+
+
/*****************************************************************************/
/* Data */
+void SP_Push (const type* T);
+/* Adjust the stackpointer for a push of an argument of the given type */
+
+void SP_Pop (const type* T);
+/* Adjust the stackpointer for a pop of an argument of the given type */
+
+
+
/* End of stackptr.h */
#endif
Arg->ArgType = Type;
/* Remember the current code position */
- Arg->Start = GetCodePos ();
+ GetCodePos (&Arg->Start);
/* Read the expression we're going to pass to the function */
ExprWithCheck (hie1, &Arg->Expr);
}
/* Remember the following code position */
- Arg->End = Arg->Push = GetCodePos ();
+ GetCodePos (&Arg->Push);
+ GetCodePos (&Arg->End);
/* Use the type of the argument for the push */
Arg->Flags |= TypeOf (Arg->Expr.Type);
unsigned Label;
/* Remember where we are now */
- Start = GetCodePos ();
+ GetCodePos (&Start);
/* Argument #1 */
ParseArg (&Arg1, Arg1Type);
g_push (Arg1.Flags, Arg1.Expr.IVal);
- Arg1.End = GetCodePos ();
+ GetCodePos (&Arg1.End);
ParamSize += SizeOf (Arg1Type);
ConsumeComma ();
/* Argument #2 */
ParseArg (&Arg2, Arg2Type);
g_push (Arg2.Flags, Arg2.Expr.IVal);
- Arg2.End = GetCodePos ();
+ GetCodePos (&Arg2.End);
ParamSize += SizeOf (Arg2Type);
ConsumeComma ();
/* Remove all of the generated code but the load of the first
* argument, which is what memcpy returns.
*/
- RemoveCode (Arg1.Push);
+ RemoveCode (&Arg1.Push);
/* Set the function result to the first argument */
*Expr = Arg1.Expr;
int Reg2 = ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need a label */
Label = GetLocalLabel ();
int Offs = ED_GetStackOffs (&Arg1.Expr, 0);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need a label */
Label = GetLocalLabel ();
int Offs = ED_GetStackOffs (&Arg2.Expr, 0);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need a label */
Label = GetLocalLabel ();
unsigned Label;
/* Remember where we are now */
- Start = GetCodePos ();
+ GetCodePos (&Start);
/* Argument #1 */
ParseArg (&Arg1, Arg1Type);
g_push (Arg1.Flags, Arg1.Expr.IVal);
- Arg1.End = GetCodePos ();
+ GetCodePos (&Arg1.End);
ParamSize += SizeOf (Arg1Type);
ConsumeComma ();
} else {
/* Push the argument */
g_push (Arg2.Flags, Arg2.Expr.IVal);
- Arg2.End = GetCodePos ();
+ GetCodePos (&Arg2.End);
ParamSize += SizeOf (Arg2Type);
}
ConsumeComma ();
/* Remove all of the generated code but the load of the first
* argument, which is what memset returns.
*/
- RemoveCode (Arg1.Push);
+ RemoveCode (&Arg1.Push);
/* Set the function result to the first argument */
*Expr = Arg1.Expr;
int Reg = ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need a label */
Label = GetLocalLabel ();
int Offs = ED_GetStackOffs (&Arg1.Expr, 0);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need a label */
Label = GetLocalLabel ();
/* Remove all of the generated code but the load of the first
* argument.
*/
- RemoveCode (Arg1.Push);
+ RemoveCode (&Arg1.Push);
/* We need a label */
Label = GetLocalLabel ();
Arg2Type[1] = GetDefaultChar () | T_QUAL_CONST;
/* Remember where we are now */
- Start = GetCodePos ();
+ GetCodePos (&Start);
/* Argument #1 */
ParseArg (&Arg1, Arg1Type);
g_push (Arg1.Flags, Arg1.Expr.IVal);
- Arg1.End = GetCodePos ();
+ GetCodePos (&Arg1.End);
ParamSize += SizeOf (Arg1Type);
ConsumeComma ();
}
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need labels */
L1 = GetLocalLabel ();
int Offs = ED_GetStackOffs (&Arg2.Expr, 0);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need labels */
L1 = GetLocalLabel ();
int Offs = ED_GetStackOffs (&Arg1.Expr, 0);
/* Drop the generated code */
- RemoveCode (Start);
+ RemoveCode (&Start);
/* We need labels */
L1 = GetLocalLabel ();
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
ConsumeSemi ();
/* Remember the start of the increment expression */
- IncExprStart = GetCodePos();
+ GetCodePos (&IncExprStart);
/* Label for the increment expression */
g_defcodelabel (IncLabel);
g_jump (TestLabel);
/* Remember the end of the increment expression */
- IncExprEnd = GetCodePos();
+ GetCodePos (&IncExprEnd);
/* Skip the closing paren */
ConsumeRParen ();
* the loop body.
*/
if (HaveIncExpr) {
- MoveCode (IncExprStart, IncExprEnd, GetCodePos());
+ CodeMark Here;
+ GetCodePos (&Here);
+ MoveCode (&IncExprStart, &IncExprEnd, &Here);
} else {
/* Jump back to the increment expression */
g_jump (IncLabel);
{
ExprDesc Expr;
int GotBreak;
- CodeMark Start;
+ CodeMark Start, End;
/* Assume no pending token */
if (PendingToken) {
default:
/* Remember the current code position */
- Start = GetCodePos ();
+ GetCodePos (&Start);
/* Actual statement */
ExprWithCheck (hie0, &Expr);
/* Load the result only if it is an lvalue and the type is
LoadExpr (CF_NONE, &Expr);
}
/* If the statement didn't generate code, and is not of type
- * void, emit a warning
- */
- if (GetCodePos () == Start && !IsTypeVoid (Expr.Type)) {
+ * void, emit a warning.
+ */
+ GetCodePos (&End);
+ if (CodeRangeIsEmpty (&Start, &End) && !IsTypeVoid (Expr.Type)) {
Warning ("Statement has no effect");
}
CheckSemi (PendingToken);
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
/* Remember the current code position. We will move the switch code
* to this position later.
*/
- CaseCodeStart = GetCodePos();
+ GetCodePos (&CaseCodeStart);
/* Opening curly brace */
ConsumeLCurly ();
} else {
- CodeMark SwitchCodeStart;
+ CodeMark SwitchCodeStart, SwitchCodeEnd;
/* If the last statement did not have a break, we may have an open
* label (maybe from an if or similar). Emitting code and then moving
}
/* Remember the current position */
- SwitchCodeStart = GetCodePos();
+ GetCodePos (&SwitchCodeStart);
/* Output the switch code label */
g_defcodelabel (SwitchCodeLabel);
g_switch (Nodes, DefaultLabel? DefaultLabel : ExitLabel, Depth);
/* Move the code to the front */
- MoveCode (SwitchCodeStart, GetCodePos(), CaseCodeStart);
+ GetCodePos (&SwitchCodeEnd);
+ MoveCode (&SwitchCodeStart, &SwitchCodeEnd, &CaseCodeStart);
}