* as const.
*/
unsigned flags = TypeOf (rhst);
- if (rhs->e_flags & E_MCONST) {
+ if (rhs->e_flags == E_MCONST) {
flags |= CF_CONST;
}
return g_typeadjust (TypeOf (lhst) | CF_CONST, flags);
}
} else if (IsClassInt (rhst)) {
/* Int to pointer assignment is valid only for constant zero */
- if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) {
+ if (rhs->e_flags != E_MCONST || rhs->e_const != 0) {
Warning ("Converting integer to pointer without a cast");
}
} else if (IsTypeFuncPtr (lhst) && IsTypeFunc(rhst)) {
case E_TLIT:
/* a literal of some kind */
- g_defdata (CF_STATIC, LiteralLabel, lval->e_const);
+ g_defdata (CF_STATIC, LiteralPoolLabel, lval->e_const);
break;
default:
case E_TLIT:
/* Literal string */
- g_getimmed (CF_STATIC, LiteralLabel, lval->e_const);
+ g_getimmed (CF_STATIC, LiteralPoolLabel, lval->e_const);
break;
default:
{
SymEntry* Entry;
- return curtok == TOK_LPAREN && (
- (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) ||
- (nxttok == TOK_CONST) ||
- (nxttok == TOK_IDENT &&
- (Entry = FindSym (NextTok.Ident)) != 0 &&
- IsTypeDef (Entry))
- );
+ return CurTok.Tok == TOK_LPAREN && (
+ (NextTok.Tok >= TOK_FIRSTTYPE && NextTok.Tok <= TOK_LASTTYPE) ||
+ (NextTok.Tok == TOK_CONST) ||
+ (NextTok.Tok == TOK_IDENT &&
+ (Entry = FindSym (NextTok.Ident)) != 0 &&
+ IsTypeDef (Entry)));
}
}
if (lval->e_test & E_FORCETEST) { /* we testing this value? */
/* debug... */
- AddCodeHint ("forcetest");
flags |= TypeOf (lval->e_tptr);
g_test (flags); /* yes, force a test */
lval->e_test &= ~E_FORCETEST;
}
-static void callfunction (struct expent* lval)
-/* Perform a function call. Called from hie11, this routine will
- * either call the named function, or if the supplied ptr is zero,
- * will call the contents of P.
+
+static unsigned FunctionParamList (FuncDesc* Func)
+/* Parse a function parameter list and pass the parameters to the called
+ * function. Depending on several criteria this may be done by just pushing
+ * each parameter separately, or creating the parameter frame once and then
+ * storing into this frame.
+ * The function returns the size of the parameters pushed.
*/
{
- struct expent lval2;
- FuncDesc* Func; /* Function descriptor */
- int Ellipsis; /* True if we have an open param list */
- SymEntry* Param; /* Current formal parameter */
- unsigned ParamCount; /* Actual parameter count */
- unsigned ParamSize; /* Number of parameter bytes */
- unsigned Flags;
- unsigned CFlags;
- CodeMark Mark;
-
-
- /* Get a pointer to the function descriptor from the type string */
- Func = GetFuncDesc (lval->e_tptr);
-
- /* Initialize vars to keep gcc silent */
- Param = 0;
- Mark = 0;
+ struct expent lval;
- /* Check if this is a function pointer. If so, save it. If not, check for
- * special known library functions that may be inlined.
+ /* Initialize variables */
+ SymEntry* Param = 0; /* Keep gcc silent */
+ unsigned ParamSize = 0; /* Size of parameters pushed */
+ unsigned ParamCount = 0; /* Number of parameters pushed */
+ unsigned FrameSize = 0; /* Size of parameter frame */
+ unsigned FrameParams = 0; /* Number of params in frame */
+ int FrameOffs = 0; /* Offset into parameter frame */
+ int Ellipsis = 0; /* Function is variadic */
+
+ /* As an optimization, we may allocate the complete parameter frame at
+ * once instead of pushing each parameter as it comes. We may do that,
+ * if...
+ *
+ * - optimizations that increase code size are enabled (allocating the
+ * stack frame at once gives usually larger code).
+ * - we have more than one parameter to push (don't count the last param
+ * for __fastcall__ functions).
*/
- if (lval->e_flags & E_MEXPR) {
- /* Function pointer is in primary register, save it */
- Mark = GetCodePos ();
- g_save (CF_PTR);
- } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) {
- /* Inline this function */
- HandleStdFunc (lval);
- return;
+ if (CodeSizeFactor >= 200) {
+
+ /* Calculate the number and size of the parameters */
+ FrameParams = Func->ParamCount;
+ FrameSize = Func->ParamSize;
+ if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) {
+ /* Last parameter is not pushed */
+ const SymEntry* LastParam = Func->SymTab->SymTail;
+ FrameSize -= SizeOf (LastParam->Type);
+ --FrameParams;
+ }
+
+ /* Do we have more than one parameter in the frame? */
+ if (FrameParams > 1) {
+ /* Okeydokey, setup the frame */
+ FrameOffs = oursp;
+ g_space (FrameSize);
+ oursp -= FrameSize;
+ } else {
+ /* Don't use a preallocated frame */
+ FrameSize = 0;
+ }
}
/* Parse the actual parameter list */
- ParamSize = 0;
- ParamCount = 0;
- Ellipsis = 0;
- while (curtok != TOK_RPAREN) {
+ while (CurTok.Tok != TOK_RPAREN) {
- /* Add a hint for the optimizer */
- AddCodeHint ("param:start");
+ unsigned CFlags;
+ unsigned Flags;
- /* Count arguments */
- ++ParamCount;
+ /* Count arguments */
+ ++ParamCount;
/* Fetch the pointer to the next argument, check for too many args */
if (ParamCount <= Func->ParamCount) {
}
} else if (!Ellipsis) {
/* Too many arguments. Do we have an open param list? */
- if ((Func->Flags & FD_ELLIPSIS) == 0) {
+ if ((Func->Flags & FD_VARIADIC) == 0) {
/* End of param list reached, no ellipsis */
Error ("Too many arguments in function call");
}
if (!Ellipsis && SizeOf (Param->Type) == 1) {
CFlags = CF_FORCECHAR;
}
- Flags = 0;
- if (evalexpr (CFlags, hie1, &lval2) == 0) {
+ Flags = CF_NONE;
+ if (evalexpr (CFlags, hie1, &lval) == 0) {
/* A constant value */
Flags |= CF_CONST;
}
*/
if (!Ellipsis) {
/* Promote the argument if needed */
- assignadjust (Param->Type, &lval2);
+ assignadjust (Param->Type, &lval);
/* If we have a prototype, chars may be pushed as chars */
Flags |= CF_FORCECHAR;
}
/* Use the type of the argument for the push */
- Flags |= TypeOf (lval2.e_tptr);
+ Flags |= TypeOf (lval.e_tptr);
/* If this is a fastcall function, don't push the last argument */
if (ParamCount == Func->ParamCount && (Func->Flags & FD_FASTCALL) != 0) {
* the primary.
*/
if (Flags & CF_CONST) {
- exprhs (CF_FORCECHAR, 0, &lval2);
+ exprhs (CF_FORCECHAR, 0, &lval);
}
} else {
- /* Push the argument, count the argument size */
- g_push (Flags, lval2.e_const);
- ParamSize += sizeofarg (Flags);
- }
+ unsigned ArgSize = sizeofarg (Flags);
+ if (FrameSize > 0) {
+ /* We have the space already allocated, store in the frame */
+ CHECK (FrameSize >= ArgSize);
+ FrameSize -= ArgSize;
+ FrameOffs -= ArgSize;
+ /* Store */
+ g_putlocal (Flags | CF_NOKEEP, FrameOffs, lval.e_const);
+ } else {
+ /* Push the argument */
+ g_push (Flags, lval.e_const);
+ }
- /* Add an optimizer hint */
- AddCodeHint ("param:end");
+ /* Calculate total parameter size */
+ ParamSize += ArgSize;
+ }
/* Check for end of argument list */
- if (curtok != TOK_COMMA) {
+ if (CurTok.Tok != TOK_COMMA) {
break;
}
NextToken ();
}
- /* We need the closing bracket here */
- ConsumeRParen ();
-
/* Check if we had enough parameters */
if (ParamCount < Func->ParamCount) {
Error ("Too few arguments in function call");
}
+ /* The function returns the size of all parameters pushed onto the stack.
+ * However, if there are parameters missing (which is an error and was
+ * flagged by the compiler) AND a stack frame was preallocated above,
+ * we would loose track of the stackpointer and generate an internal error
+ * later. So we correct the value by the parameters that should have been
+ * pushed to avoid an internal compiler error. Since an error was
+ * generated before, no code will be output anyway.
+ */
+ return ParamSize + FrameSize;
+}
+
+
+
+static void CallFunction (struct expent* lval)
+/* Perform a function call. Called from hie11, this routine will
+ * either call the named function, or the function pointer in a/x.
+ */
+{
+ FuncDesc* Func; /* Function descriptor */
+ unsigned ParamSize; /* Number of parameter bytes */
+ CodeMark Mark;
+
+
+ /* Get a pointer to the function descriptor from the type string */
+ Func = GetFuncDesc (lval->e_tptr);
+
+ /* Initialize vars to keep gcc silent */
+ Mark = 0;
+
+ /* Check if this is a function pointer. If so, save it. If not, check for
+ * special known library functions that may be inlined.
+ */
+ if (lval->e_flags & E_MEXPR) {
+ /* Function pointer is in primary register, save it */
+ Mark = GetCodePos ();
+ g_save (CF_PTR);
+ } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) {
+ /* Inline this function */
+ HandleStdFunc (lval);
+ return;
+ }
+
+ /* Parse the parameter list */
+ ParamSize = FunctionParamList (Func);
+
+ /* We need the closing bracket here */
+ ConsumeRParen ();
+
/* */
if (lval->e_flags & E_MEXPR) {
/* Function called via pointer: Restore it and call function */
}
g_callind (TypeOf (lval->e_tptr), ParamSize);
} else {
- g_call (TypeOf (lval->e_tptr), (char*) lval->e_name, ParamSize);
+ g_call (TypeOf (lval->e_tptr), (const char*) lval->e_name, ParamSize);
}
}
ConsumeLParen ();
/* String literal */
- if (curtok != TOK_SCONST) {
+ if (CurTok.Tok != TOK_SCONST) {
Error ("String literal expected");
} else {
- /* Write the string directly into the output, followed by a newline */
- AddCodeLine (GetLiteral (curval));
+
+ /* The string literal may consist of more than one line of assembler
+ * code. Separate the single lines and output the code.
+ */
+ const char* S = GetLiteral (CurTok.IVal);
+ while (*S) {
+
+ /* Allow lines up to 256 bytes */
+ const char* E = strchr (S, '\n');
+ if (E) {
+ /* Found a newline */
+ g_asmcode (S, E-S);
+ S = E+1;
+ } else {
+ int Len = strlen (S);
+ g_asmcode (S, Len);
+ S += Len;
+ }
+ }
/* Reset the string pointer, effectivly clearing the string from the
* string table. Since we're working with one token lookahead, this
* will fail if the next token is also a string token, but that's a
* syntax error anyway, because we expect a right paren.
*/
- ResetLiteralOffs (curval);
+ ResetLiteralPoolOffs (CurTok.IVal);
}
/* Skip the string token */
lval->e_test = 0;
/* Character and integer constants. */
- if (curtok == TOK_ICONST || curtok == TOK_CCONST) {
+ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
lval->e_flags = E_MCONST | E_TCONST;
- lval->e_tptr = curtype;
- lval->e_const = curval;
+ lval->e_tptr = CurTok.Type;
+ lval->e_const = CurTok.IVal;
NextToken ();
return 0;
}
/* Process parenthesized subexpression by calling the whole parser
* recursively.
*/
- if (curtok == TOK_LPAREN) {
+ if (CurTok.Tok == TOK_LPAREN) {
NextToken ();
memset (lval, 0, sizeof (*lval)); /* Remove any attributes */
k = hie0 (lval);
}
/* Identifier? */
- if (curtok == TOK_IDENT) {
+ if (CurTok.Tok == TOK_IDENT) {
SymEntry* Sym;
ident Ident;
NextToken ();
/* IDENT is either an auto-declared function or an undefined variable. */
- if (curtok == TOK_LPAREN) {
+ if (CurTok.Tok == TOK_LPAREN) {
/* Declare a function returning int. For that purpose, prepare a
* function signature for a function having an empty param list
* and returning int.
}
/* String literal? */
- if (curtok == TOK_SCONST) {
+ if (CurTok.Tok == TOK_SCONST) {
lval->e_flags = E_MCONST | E_TLIT;
- lval->e_const = curval;
- lval->e_tptr = GetCharArrayType (strlen (GetLiteral (curval)));
+ lval->e_const = CurTok.IVal;
+ lval->e_tptr = GetCharArrayType (strlen (GetLiteral (CurTok.IVal)));
NextToken ();
return 0;
}
/* ASM statement? */
- if (curtok == TOK_ASM) {
+ if (CurTok.Tok == TOK_ASM) {
doasm ();
lval->e_tptr = type_void;
lval->e_flags = E_MEXPR;
}
/* __AX__ and __EAX__ pseudo values? */
- if (curtok == TOK_AX || curtok == TOK_EAX) {
- lval->e_tptr = (curtok == TOK_AX)? type_uint : type_ulong;
+ if (CurTok.Tok == TOK_AX || CurTok.Tok == TOK_EAX) {
+ lval->e_tptr = (CurTok.Tok == TOK_AX)? type_uint : type_ulong;
lval->e_flags = E_MREG;
lval->e_test &= ~E_CC;
lval->e_const = 0;
/* Skip the token and check for an identifier */
NextToken ();
- if (curtok != TOK_IDENT) {
+ if (CurTok.Tok != TOK_IDENT) {
Error ("Identifier expected");
lval->e_tptr = type_int;
return 0;
k = primary (lval);
- if (curtok < TOK_LBRACK || curtok > TOK_PTR_REF) {
+ if (CurTok.Tok < TOK_LBRACK || CurTok.Tok > TOK_PTR_REF) {
/* Not for us */
return k;
}
while (1) {
- if (curtok == TOK_LBRACK) {
+ if (CurTok.Tok == TOK_LBRACK) {
/* Array reference */
k = arrayref (k, lval);
- } else if (curtok == TOK_LPAREN) {
+ } else if (CurTok.Tok == TOK_LPAREN) {
/* Function call. Skip the opening parenthesis */
NextToken ();
++lval->e_tptr; /* Skip T_PTR */
lval->e_flags |= E_MEXPR;
}
- callfunction (lval);
+ CallFunction (lval);
lval->e_flags = E_MEXPR;
lval->e_tptr += DECODE_SIZE + 1; /* Set to result */
} else {
}
k = 0;
- } else if (curtok == TOK_DOT) {
+ } else if (CurTok.Tok == TOK_DOT) {
if (!IsClassStruct (lval->e_tptr)) {
Error ("Struct expected");
}
k = structref (0, lval);
- } else if (curtok == TOK_PTR_REF) {
+ } else if (CurTok.Tok == TOK_PTR_REF) {
tptr = lval->e_tptr;
if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) {
g_putstatic (flags, lval->e_name, lval->e_const);
} else if (f & E_MLOCAL) {
- g_putlocal (flags, lval->e_const);
+ g_putlocal (flags, lval->e_const, 0);
} else if (f == E_MEOFFS) {
g_putind (flags, lval->e_const);
} else if (f != E_MREG) {
NextToken ();
k = hie10 (lval);
- if (k == 0 && lval->e_flags & E_MCONST) {
+ if (k == 0 && (lval->e_flags & E_MCONST) != 0) {
/* Value is constant */
switch (tok) {
- case TOK_MINUS: lval->e_const = -lval->e_const; break;
+ case TOK_MINUS: lval->e_const = -lval->e_const; break;
case TOK_PLUS: break;
case TOK_COMP: lval->e_const = ~lval->e_const; break;
default: Internal ("Unexpected token: %d", tok);
int k;
type* t;
- switch (curtok) {
+ switch (CurTok.Tok) {
case TOK_INC:
pre_incdec (lval, g_inc);
case TOK_PLUS:
case TOK_MINUS:
case TOK_COMP:
- unaryop (curtok, lval);
+ unaryop (CurTok.Tok, lval);
return 0;
case TOK_BOOL_NOT:
}
k = hie11 (lval);
- switch (curtok) {
+ switch (CurTok.Tok) {
case TOK_INC:
post_incdec (lval, k, g_inc);
return 0;
k = hienext (lval);
*UsedGen = 0;
- while ((Gen = FindGen (curtok, ops)) != 0) {
+ while ((Gen = FindGen (CurTok.Tok, ops)) != 0) {
/* Tell the caller that we handled it's ops */
*UsedGen = 1;
}
/* Remember the operator token, then skip it */
- tok = curtok;
+ tok = CurTok.Tok;
NextToken ();
/* Get the lhs on stack */
k = hienext (lval);
- while ((Gen = FindGen (curtok, ops)) != 0) {
+ while ((Gen = FindGen (CurTok.Tok, ops)) != 0) {
/* Remember the operator token, then skip it */
- tok = curtok;
+ tok = CurTok.Tok;
NextToken ();
/* Get the lhs on stack */
flags = 0;
/* Check for constness on both sides */
- if (k == 0 && lval->e_flags == E_MCONST) {
+ if (k == 0 && (lval->e_flags & E_MCONST) != 0) {
/* The left hand side is a constant. Good. Get rhs */
if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
}
/* Result is constant, condition codes not set */
- lval->e_test = E_MCONST;
+ lval->e_test &= ~E_CC;
} else {
rhst = lval2.e_tptr;
/* Check left hand side */
- if (k == 0 && lval->e_flags & E_MCONST) {
+ if (k == 0 && (lval->e_flags & E_MCONST) != 0) {
/* Both sides are constant, remove generated code */
RemoveCode (Mark1);
}
/* Result is constant, condition codes not set */
- lval->e_flags = E_MCONST;
+ /* lval->e_flags = E_MCONST; ### */
lval->e_test &= ~E_CC;
} else {
/* Process + and - binary operators. */
{
int k = hie9 (lval);
- while (curtok == TOK_PLUS || curtok == TOK_MINUS) {
+ while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) {
- if (curtok == TOK_PLUS) {
+ if (CurTok.Tok == TOK_PLUS) {
parseadd (k, lval);
} else {
parsesub (k, lval);
struct expent lval2;
k = hie2 (lval);
- if (curtok == TOK_BOOL_AND) {
+ if (CurTok.Tok == TOK_BOOL_AND) {
/* Tell our caller that we're evaluating a boolean */
*BoolOp = 1;
/* Get a label that we will use for false expressions */
- lab = GetLabel ();
+ lab = GetLocalLabel ();
/* If the expr hasn't set condition codes, set the force-test flag */
if ((lval->e_test & E_CC) == 0) {
g_falsejump (CF_NONE, lab);
/* Parse more boolean and's */
- while (curtok == TOK_BOOL_AND) {
+ while (CurTok.Tok == TOK_BOOL_AND) {
/* Skip the && */
NextToken ();
exprhs (CF_FORCECHAR, k, &lval2);
/* Do short circuit evaluation */
- if (curtok == TOK_BOOL_AND) {
+ if (CurTok.Tok == TOK_BOOL_AND) {
g_falsejump (CF_NONE, lab);
} else {
/* Last expression - will evaluate to true */
}
/* Define the false jump label here */
- g_defloclabel (lab);
+ g_defcodelabel (lab);
/* Define the label */
lval->e_flags = E_MEXPR;
unsigned DoneLab;
/* Get a label */
- TrueLab = GetLabel ();
+ TrueLab = GetLocalLabel ();
/* Call the next level parser */
k = hieAnd (lval, TrueLab, &BoolOp);
/* Any boolean or's? */
- if (curtok == TOK_BOOL_OR) {
+ if (CurTok.Tok == TOK_BOOL_OR) {
/* If the expr hasn't set condition codes, set the force-test flag */
if ((lval->e_test & E_CC) == 0) {
BoolOp = 1;
/* while there's more expr */
- while (curtok == TOK_BOOL_OR) {
+ while (CurTok.Tok == TOK_BOOL_OR) {
/* skip the || */
NextToken ();
*/
#if 0
/* Seems this sometimes generates wrong code */
- if (curtok == TOK_BOOL_OR && !AndOp) {
+ if (CurTok.Tok == TOK_BOOL_OR && !AndOp) {
g_truejump (CF_NONE, TrueLab);
}
#else
/* If we really had boolean ops, generate the end sequence */
if (BoolOp) {
- DoneLab = GetLabel ();
+ DoneLab = GetLocalLabel ();
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
g_falsejump (CF_NONE, DoneLab);
- g_defloclabel (TrueLab);
+ g_defcodelabel (TrueLab);
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
- g_defloclabel (DoneLab);
+ g_defcodelabel (DoneLab);
}
return k;
}
k = hieOr (lval);
- if (curtok == TOK_QUEST) {
+ if (CurTok.Tok == TOK_QUEST) {
NextToken ();
if ((lval->e_test & E_CC) == 0) {
/* Condition codes not set, force a test */
lval->e_test |= E_FORCETEST;
}
exprhs (CF_NONE, k, lval);
- labf = GetLabel ();
+ labf = GetLocalLabel ();
g_falsejump (CF_NONE, labf);
/* Parse second and third expression */
expression1 (&lval2);
- labt = GetLabel ();
+ labt = GetLocalLabel ();
ConsumeColon ();
g_jump (labt);
- g_defloclabel (labf);
+ g_defcodelabel (labf);
expression1 (&lval3);
/* Check if any conversions are needed, if so, do them.
/* Setup a new label so that the expr3 code will jump around
* the type cast code for expr2.
*/
- labf = GetLabel (); /* Get new label */
+ labf = GetLocalLabel (); /* Get new label */
Mark1 = GetCodePos (); /* Remember current position */
g_jump (labf); /* Jump around code */
/* The jump for expr2 goes here */
- g_defloclabel (labt);
+ g_defcodelabel (labt);
/* Create the typecast code for expr2 */
Mark2 = GetCodePos (); /* Remember position */
g_typecast (TypeOf (rtype), TypeOf (type2));
- /* If the typecast did not produce code, remove the jump,
- * otherwise output the label.
- */
- if (GetCodePos() == Mark2) {
- RemoveCode (Mark1); /* Remove code */
- } else {
- /* We have typecast code, output label */
- g_defloclabel (labf);
- labt = 0; /* Mark other label as invalid */
- }
+ /* Jump here around the typecase code. */
+ g_defcodelabel (labf);
+ labt = 0; /* Mark other label as invalid */
} else if (IsClassPtr (type2) && IsClassPtr (type3)) {
/* Must point to same type */
/* If we don't have the label defined until now, do it */
if (labt) {
- g_defloclabel (labt);
+ g_defcodelabel (labt);
}
/* Setup the target expression */
/* cc65 does not have full support for handling structs by value. Since
* assigning structs is one of the more useful operations from this
- * familiy, allow it here.
+ * family, allow it here.
*/
if (IsClassStruct (ltype)) {
int k;
k = hieQuest (lval);
- switch (curtok) {
+ switch (CurTok.Tok) {
case TOK_RPAREN:
case TOK_SEMI:
int k;
k = hie1 (lval);
- while (curtok == TOK_COMMA) {
+ while (CurTok.Tok == TOK_COMMA) {
NextToken ();
k = hie1 (lval);
}
/* Load the value into the primary register */
exprhs (CF_FORCECHAR, k, &lval);
- /* Check for the closing brace */
- ConsumeRParen ();
-
/* Generate the jump */
if (cond) {
g_truejump (CF_NONE, label);
* compiler itself is one big hack...): If a semicolon follows, we
* don't have a statement and may omit the jump.
*/
- if (curtok != TOK_SEMI) {
+ if (CurTok.Tok != TOK_SEMI) {
g_falsejump (CF_NONE, label);
}
}
+
+ /* Check for the closing brace */
+ ConsumeRParen ();
}