1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-28 22:30:12 +00:00

Rewrote code generation for the strlen standard function. Added code for

other standard functions in several places.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3069 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2004-06-02 21:33:35 +00:00
parent 2bb2ceec33
commit 6e34e386cb
15 changed files with 282 additions and 188 deletions

View File

@ -464,21 +464,22 @@ void g_leave (void)
/* Function epilogue */ /* Function epilogue */
{ {
/* How many bytes of locals do we have to drop? */ /* How many bytes of locals do we have to drop? */
int k = -StackPtr; unsigned k = (unsigned) -StackPtr;
/* If we didn't have a variable argument list, don't call leave */ /* If we didn't have a variable argument list, don't call leave */
if (funcargs >= 0) { if (funcargs >= 0) {
/* Drop stackframe if needed */ /* Drop stackframe if needed. We can only drop 255 bytes at a time. */
k += funcargs; k += funcargs;
if (k > 0) { while (k > 0) {
if (k <= 8) { unsigned ToDrop = (k > 255)? 255 : k;
AddCodeLine ("jsr incsp%d", k); if (ToDrop <= 8) {
AddCodeLine ("jsr incsp%d", k);
} else { } else {
CheckLocalOffs (k); ldyconst (ToDrop);
ldyconst (k); AddCodeLine ("jsr addysp");
AddCodeLine ("jsr addysp");
} }
k -= ToDrop;
} }
} else { } else {
@ -488,6 +489,11 @@ void g_leave (void)
AddCodeLine ("jsr leave"); AddCodeLine ("jsr leave");
} else { } else {
/* We've a stack frame to drop */ /* We've a stack frame to drop */
while (k > 255) {
ldyconst (255);
AddCodeLine ("jsr addysp");
k -= 255;
}
ldyconst (k); ldyconst (k);
AddCodeLine ("jsr leavey"); AddCodeLine ("jsr leavey");
} }
@ -4279,53 +4285,3 @@ void g_asmcode (struct StrBuf* B)
/*****************************************************************************/
/* Inlined known functions */
/*****************************************************************************/
void g_strlen (unsigned flags, unsigned long val, long offs)
/* Inline the strlen() function */
{
/* We need a label in both cases */
unsigned label = GetLocalLabel ();
/* Two different encodings */
if (flags & CF_CONST) {
/* The address of the string is constant. Create the correct label name */
const char* lbuf = GetLabelName (flags, val, offs);
/* Generate the strlen code */
AddCodeLine ("ldy #$FF");
g_defcodelabel (label);
AddCodeLine ("iny");
AddCodeLine ("lda %s,y", lbuf);
AddCodeLine ("bne %s", LocalLabelName (label));
AddCodeLine ("tax");
AddCodeLine ("tya");
} else {
/* Address not constant but in primary */
if (CodeSizeFactor < 400) {
/* This is too much code, so call strlen instead of inlining */
AddCodeLine ("jsr _strlen");
} else {
/* Inline the function */
AddCodeLine ("sta ptr1");
AddCodeLine ("stx ptr1+1");
AddCodeLine ("ldy #$FF");
g_defcodelabel (label);
AddCodeLine ("iny");
AddCodeLine ("lda (ptr1),y");
AddCodeLine ("bne %s", LocalLabelName (label));
AddCodeLine ("tax");
AddCodeLine ("tya");
}
}
}

View File

@ -472,17 +472,6 @@ void g_asmcode (struct StrBuf* B);
/*****************************************************************************/
/* Inlined known functions */
/*****************************************************************************/
void g_strlen (unsigned flags, unsigned long val, long offs);
/* Inline the strlen() function */
/* End of codegen.h */ /* End of codegen.h */
#endif #endif

View File

@ -455,13 +455,6 @@ void ExprLoad (unsigned Flags, ExprDesc* Expr)
Expr->Test &= ~E_FORCETEST; Expr->Test &= ~E_FORCETEST;
} }
} }
#if 0
/* Regardless of the original contents, Expr is now an rvalue in the
* primary. ### Later...
*/
ED_MakeRValExpr (Expr);
#endif
} }
@ -637,6 +630,7 @@ static void FunctionCall (ExprDesc* Expr)
{ {
FuncDesc* Func; /* Function descriptor */ FuncDesc* Func; /* Function descriptor */
int IsFuncPtr; /* Flag */ int IsFuncPtr; /* Flag */
int StdFunc; /* Standard function index */
unsigned ParamSize; /* Number of parameter bytes */ unsigned ParamSize; /* Number of parameter bytes */
CodeMark Mark = 0; /* Initialize to keep gcc silent */ CodeMark Mark = 0; /* Initialize to keep gcc silent */
int PtrOffs = 0; /* Offset of function pointer on stack */ int PtrOffs = 0; /* Offset of function pointer on stack */
@ -682,11 +676,12 @@ static void FunctionCall (ExprDesc* Expr)
} }
/* Check for known standard functions and inline them if requested */ /* Check for known standard functions and inline them if requested */
} else if (IS_Get (&InlineStdFuncs) && IsStdFunc ((const char*) Expr->Name)) { } else if (IS_Get (&InlineStdFuncs) &&
(StdFunc = FindStdFunc ((const char*) Expr->Name)) >= 0) {
/* Inline this function */ /* Inline this function */
HandleStdFunc (Func, Expr); HandleStdFunc (StdFunc, Func, Expr);
goto ExitPoint; return;
} }
@ -712,7 +707,7 @@ static void FunctionCall (ExprDesc* Expr)
*/ */
if (ParamSize == 0) { if (ParamSize == 0) {
RemoveCode (Mark); RemoveCode (Mark);
pop (CF_PTR); pop (CF_PTR);
PtrOnStack = 0; PtrOnStack = 0;
} else { } else {
/* Load from the saved copy */ /* Load from the saved copy */
@ -752,7 +747,6 @@ static void FunctionCall (ExprDesc* Expr)
} }
ExitPoint:
/* The function result is an rvalue in the primary register */ /* The function result is an rvalue in the primary register */
ED_MakeRValExpr (Expr); ED_MakeRValExpr (Expr);
Expr->Type = GetFuncReturn (Expr->Type); Expr->Type = GetFuncReturn (Expr->Type);
@ -1110,7 +1104,7 @@ static void ArrayRef (ExprDesc* Expr)
* portion of the index (which is in (e)ax, so there's no further * portion of the index (which is in (e)ax, so there's no further
* action required). * action required).
*/ */
g_scale (CF_INT | CF_UNSIGNED, CheckedSizeOf (ElementType)); g_scale (CF_INT, CheckedSizeOf (ElementType));
} else { } else {
@ -1144,7 +1138,7 @@ static void ArrayRef (ExprDesc* Expr)
/* The array base address is on stack and the subscript is in the /* The array base address is on stack and the subscript is in the
* primary. Add both. * primary. Add both.
*/ */
g_add (CF_INT | CF_UNSIGNED, 0); g_add (CF_INT, 0);
} else { } else {
@ -1182,7 +1176,7 @@ static void ArrayRef (ExprDesc* Expr)
} else { } else {
if (ED_IsLocAbs (Expr)) { if (ED_IsLocAbs (Expr)) {
/* Constant numeric address. Just add it */ /* Constant numeric address. Just add it */
g_inc (CF_INT | CF_UNSIGNED, Expr->Val); g_inc (CF_INT, Expr->Val);
} else if (ED_IsLocStack (Expr)) { } else if (ED_IsLocStack (Expr)) {
/* Base address is a local variable address */ /* Base address is a local variable address */
if (IsTypeArray (Expr->Type)) { if (IsTypeArray (Expr->Type)) {

View File

@ -33,8 +33,13 @@
/* common */
#include "xsprintf.h"
/* cc65 */ /* cc65 */
#include "asmlabel.h"
#include "datatype.h" #include "datatype.h"
#include "error.h"
#include "symentry.h" #include "symentry.h"
#include "exprdesc.h" #include "exprdesc.h"
@ -60,6 +65,64 @@ ExprDesc* ED_Init (ExprDesc* Expr)
const char* ED_GetLabelName (const ExprDesc* Expr, long Offs)
/* Return the assembler label name of the given expression. Beware: This
* function may use a static buffer, so the name may get "lost" on the second
* call to the function.
*/
{
static char Buf[256];
/* Expr may have it's own offset, adjust Offs accordingly */
Offs += Expr->Val;
/* Generate a label depending on the location */
switch (ED_GetLoc (Expr)) {
case E_LOC_ABS:
/* Absolute: numeric address or const */
xsprintf (Buf, sizeof (Buf), "$%04X", (int)(Offs & 0xFFFF));
break;
case E_LOC_GLOBAL:
case E_LOC_STATIC:
/* Global or static variable */
if (Offs) {
xsprintf (Buf, sizeof (Buf), "%s%+ld",
SymGetAsmName (Expr->Sym), Offs);
} else {
xsprintf (Buf, sizeof (Buf), "%s",
SymGetAsmName (Expr->Sym));
}
break;
case E_LOC_REGISTER:
/* Register variable */
xsprintf (Buf, sizeof (Buf), "regbank+%u",
(unsigned)(Offs & 0xFFFFU));
break;
case E_LOC_LITERAL:
/* Literal in the literal pool */
if (Offs) {
xsprintf (Buf, sizeof (Buf), "%s%+ld",
LocalLabelName (Expr->Name), Offs);
} else {
xsprintf (Buf, sizeof (Buf), "%s",
LocalLabelName (Expr->Name));
}
break;
default:
Internal ("Invalid location in ED_GetLabelName: 0x%04X", ED_GetLoc (Expr));
}
/* Return a pointer to the static buffer */
return Buf;
}
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type) ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type)
/* Make Expr an absolute const with the given value and type. */ /* Make Expr an absolute const with the given value and type. */
{ {

View File

@ -123,6 +123,16 @@ INLINE int ED_IsLocAbs (const ExprDesc* Expr)
# define ED_IsLocAbs(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_ABS) # define ED_IsLocAbs(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_ABS)
#endif #endif
#if defined(HAVE_INLINE)
INLINE int ED_IsLocRegister (const ExprDesc* Expr)
/* Return true if the expression is located in a register */
{
return (Expr->Flags & E_MASK_LOC) == E_LOC_REGISTER;
}
#else
# define ED_IsLocRegister(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_REGISTER)
#endif
#if defined(HAVE_INLINE) #if defined(HAVE_INLINE)
INLINE int ED_IsLocStack (const ExprDesc* Expr) INLINE int ED_IsLocStack (const ExprDesc* Expr)
/* Return true if the expression is located on the stack */ /* Return true if the expression is located on the stack */
@ -133,6 +143,16 @@ INLINE int ED_IsLocStack (const ExprDesc* Expr)
# define ED_IsLocStack(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_STACK) # define ED_IsLocStack(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_STACK)
#endif #endif
#if defined(HAVE_INLINE)
INLINE int ED_IsLocPrimary (const ExprDesc* Expr)
/* Return true if the expression is an expression in the register pseudo variable */
{
return (Expr->Flags & E_MASK_LOC) == E_LOC_PRIMARY;
}
#else
# define ED_IsLocExpr(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_PRIMARY)
#endif
#if defined(HAVE_INLINE) #if defined(HAVE_INLINE)
INLINE int ED_IsLocExpr (const ExprDesc* Expr) INLINE int ED_IsLocExpr (const ExprDesc* Expr)
/* Return true if the expression is an expression in the primary */ /* Return true if the expression is an expression in the primary */
@ -143,6 +163,16 @@ INLINE int ED_IsLocExpr (const ExprDesc* Expr)
# define ED_IsLocExpr(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_EXPR) # define ED_IsLocExpr(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_EXPR)
#endif #endif
#if defined(HAVE_INLINE)
INLINE int ED_IsLocLiteral (const ExprDesc* Expr)
/* Return true if the expression is a string from the literal pool */
{
return (Expr->Flags & E_MASK_LOC) == E_LOC_LITERAL;
}
#else
# define ED_IsLocLiteral(Expr) (((Expr)->Flags & E_MASK_LOC) == E_LOC_LITERAL)
#endif
#if defined(HAVE_INLINE) #if defined(HAVE_INLINE)
INLINE int ED_IsLocConst (const ExprDesc* Expr) INLINE int ED_IsLocConst (const ExprDesc* Expr)
/* Return true if the expression is a constant location of some sort */ /* Return true if the expression is a constant location of some sort */
@ -193,6 +223,12 @@ INLINE void ED_MakeRVal (ExprDesc* Expr)
# define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0) # define ED_MakeRVal(Expr) do { (Expr)->Flags &= ~E_RTYPE_LVAL; } while (0)
#endif #endif
const char* ED_GetLabelName (const ExprDesc* Expr, long Offs);
/* Return the assembler label name of the given expression. Beware: This
* function may use a static buffer, so the name may get "lost" on the second
* call to the function.
*/
ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type); ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type);
/* Make Expr an absolute const with the given value and type. */ /* Make Expr an absolute const with the given value and type. */

View File

@ -47,7 +47,6 @@ unsigned char AddSource = 0; /* Add source lines as comments */
unsigned char DebugInfo = 0; /* Add debug info to the obj */ unsigned char DebugInfo = 0; /* Add debug info to the obj */
unsigned char CreateDep = 0; /* Create a dependency file */ unsigned char CreateDep = 0; /* Create a dependency file */
unsigned char ANSI = 0; /* Strict ANSI flag */ unsigned char ANSI = 0; /* Strict ANSI flag */
unsigned char WriteableStrings = 0; /* Literal strings are r/w */
unsigned char NoWarn = 0; /* Suppress warnings */ unsigned char NoWarn = 0; /* Suppress warnings */
unsigned char Optimize = 0; /* Optimize flag */ unsigned char Optimize = 0; /* Optimize flag */
unsigned long OptDisable = 0; /* Optimizer passes to disable */ unsigned long OptDisable = 0; /* Optimizer passes to disable */
@ -56,6 +55,7 @@ unsigned CodeSizeFactor = 100; /* Size factor for generated code */
unsigned RegisterSpace = 6; /* Space available for register vars */ unsigned RegisterSpace = 6; /* Space available for register vars */
/* Stackable options */ /* Stackable options */
IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */
IntStack InlineStdFuncs = INTSTACK(0); /* Inline some known functions */ IntStack InlineStdFuncs = INTSTACK(0); /* Inline some known functions */
IntStack EnableRegVars = INTSTACK(0); /* Enable register variables */ IntStack EnableRegVars = INTSTACK(0); /* Enable register variables */
IntStack AllowRegVarAddr = INTSTACK(0); /* Allow taking addresses of register vars */ IntStack AllowRegVarAddr = INTSTACK(0); /* Allow taking addresses of register vars */

View File

@ -53,7 +53,6 @@ extern unsigned char AddSource; /* Add source lines as comments */
extern unsigned char DebugInfo; /* Add debug info to the obj */ extern unsigned char DebugInfo; /* Add debug info to the obj */
extern unsigned char CreateDep; /* Create a dependency file */ extern unsigned char CreateDep; /* Create a dependency file */
extern unsigned char ANSI; /* Strict ANSI flag */ extern unsigned char ANSI; /* Strict ANSI flag */
extern unsigned char WriteableStrings; /* Literal strings are r/w */
extern unsigned char NoWarn; /* Suppress warnings */ extern unsigned char NoWarn; /* Suppress warnings */
extern unsigned char Optimize; /* Optimize flag */ extern unsigned char Optimize; /* Optimize flag */
extern unsigned long OptDisable; /* Optimizer passes to disable */ extern unsigned long OptDisable; /* Optimizer passes to disable */
@ -62,6 +61,7 @@ extern unsigned CodeSizeFactor; /* Size factor for generated code */
extern unsigned RegisterSpace; /* Space available for register vars */ extern unsigned RegisterSpace; /* Space available for register vars */
/* Stackable options */ /* Stackable options */
extern IntStack WritableStrings; /* Literal strings are r/w */
extern IntStack InlineStdFuncs; /* Inline some known functions */ extern IntStack InlineStdFuncs; /* Inline some known functions */
extern IntStack EnableRegVars; /* Enable register variables */ extern IntStack EnableRegVars; /* Enable register variables */
extern IntStack AllowRegVarAddr; /* Allow taking addresses of register vars */ extern IntStack AllowRegVarAddr; /* Allow taking addresses of register vars */

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998 Ullrich von Bassewitz */ /* (C) 1998-2004 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstraße 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -93,7 +93,7 @@ void DumpLiteralPool (void)
} }
/* Switch to the data segment */ /* Switch to the data segment */
if (WriteableStrings) { if (IS_Get (&WritableStrings)) {
g_usedata (); g_usedata ();
} else { } else {
g_userodata (); g_userodata ();

View File

@ -127,7 +127,8 @@ static void Usage (void)
" --static-locals\tMake local variables static\n" " --static-locals\tMake local variables static\n"
" --target sys\t\tSet the target system\n" " --target sys\t\tSet the target system\n"
" --verbose\t\tIncrease verbosity\n" " --verbose\t\tIncrease verbosity\n"
" --version\t\tPrint the compiler version number\n", " --version\t\tPrint the compiler version number\n"
" --writable-strings\tMake string literals writable\n",
ProgName); ProgName);
} }
@ -660,6 +661,15 @@ static void OptVersion (const char* Opt attribute ((unused)),
static void OptWritableStrings (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
/* Make string literals writable */
{
IS_Set (&WritableStrings, 1);
}
int main (int argc, char* argv[]) int main (int argc, char* argv[])
{ {
/* Program long options */ /* Program long options */
@ -691,6 +701,7 @@ int main (int argc, char* argv[])
{ "--target", 1, OptTarget }, { "--target", 1, OptTarget },
{ "--verbose", 0, OptVerbose }, { "--verbose", 0, OptVerbose },
{ "--version", 0, OptVersion }, { "--version", 0, OptVersion },
{ "--writable-strings", 0, OptWritableStrings },
}; };
unsigned I; unsigned I;

View File

@ -41,6 +41,7 @@
#include "check.h" #include "check.h"
/* cc65 */ /* cc65 */
#include "asmlabel.h"
#include "codegen.h" #include "codegen.h"
#include "error.h" #include "error.h"
#include "funcdesc.h" #include "funcdesc.h"
@ -54,7 +55,7 @@
/*****************************************************************************/ /*****************************************************************************/
/* Function forwards */ /* Function forwards */
/*****************************************************************************/ /*****************************************************************************/
@ -65,7 +66,7 @@ static void StdFunc_strlen (FuncDesc*, ExprDesc*);
/*****************************************************************************/ /*****************************************************************************/
/* Data */ /* Data */
/*****************************************************************************/ /*****************************************************************************/
@ -75,13 +76,14 @@ static void StdFunc_strlen (FuncDesc*, ExprDesc*);
*/ */
static struct StdFuncDesc { static struct StdFuncDesc {
const char* Name; const char* Name;
void (*Handler) (FuncDesc*, ExprDesc*); void (*Handler) (FuncDesc*, ExprDesc*);
} StdFuncs [] = { } StdFuncs[] = {
{ "memset", StdFunc_memset }, { "memset", StdFunc_memset },
{ "strlen", StdFunc_strlen }, { "strlen", StdFunc_strlen },
}; };
#define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs [0])) #define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs[0]))
/*****************************************************************************/ /*****************************************************************************/
@ -98,16 +100,6 @@ static int CmpFunc (const void* Key, const void* Elem)
static struct StdFuncDesc* FindFunc (const char* Name)
/* Find a function with the given name. Return a pointer to the descriptor if
* found, return NULL otherwise.
*/
{
return bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs [0]), CmpFunc);
}
static unsigned ParseArg (type* Type, ExprDesc* Arg) static unsigned ParseArg (type* Type, ExprDesc* Arg)
/* Parse one argument but do not push it onto the stack. Return the code /* Parse one argument but do not push it onto the stack. Return the code
* generator flags needed to do the actual push. * generator flags needed to do the actual push.
@ -146,8 +138,7 @@ static unsigned ParseArg (type* Type, ExprDesc* Arg)
static void StdFunc_memset (FuncDesc* F attribute ((unused)), static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
ExprDesc* lval attribute ((unused)))
/* Handle the memset function */ /* Handle the memset function */
{ {
/* Argument types */ /* Argument types */
@ -198,91 +189,123 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)),
/* We expect the closing brace */ /* We expect the closing brace */
ConsumeRParen (); ConsumeRParen ();
/* The function result is an rvalue in the primary register */
ED_MakeRValExpr (Expr);
Expr->Type = GetFuncReturn (Expr->Type);
} }
static void StdFunc_strlen (FuncDesc* F attribute ((unused)), static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
ExprDesc* lval attribute ((unused)))
/* Handle the strlen function */ /* Handle the strlen function */
{ {
static type ParamType[] = { T_PTR, T_SCHAR, T_END }; static type ArgType[] = { T_PTR, T_SCHAR, T_END };
ExprDesc Param; ExprDesc Arg;
unsigned CodeFlags; unsigned L;
unsigned long ParamName;
/* Setup the argument type string */ /* Setup the argument type string */
ParamType[1] = GetDefaultChar () | T_QUAL_CONST; ArgType[1] = GetDefaultChar () | T_QUAL_CONST;
/* Fetch the parameter and convert it to the type needed */ /* Evaluate the parameter */
hie1 (&Param); hie1 (&Arg);
TypeConversion (&Param, ParamType);
/* Check if the parameter is a constant array of some type, or a numeric /* We can generate special code for several locations */
* address cast to a pointer. if (ED_IsLocConst (&Arg) && IsTypeArray (Arg.Type)) {
*/
CodeFlags = 0;
ParamName = Param.Name;
if ((ED_IsLocConst (&Param) && IsTypeArray (Param.Type)) ||
(ED_IsLocAbs (&Param) && IsTypePtr (Param.Type))) {
/* Check which type of constant it is */ /* Do type conversion */
switch (ED_GetLoc (&Param)) { TypeConversion (&Arg, ArgType);
case E_LOC_ABS: /* If the expression is a literal, and if string literals are read
/* Numerical address */ * only, we can calculate the length of the string and remove it
CodeFlags |= CF_CONST | CF_ABSOLUTE; * from the literal pool. Otherwise we have to calculate the length
break; * at runtime.
*/
if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings)) {
case E_LOC_GLOBAL: /* Constant string literal */
/* Global label */ ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t);
CodeFlags |= CF_CONST | CF_EXTERNAL; ResetLiteralPoolOffs (Arg.Val);
break;
case E_LOC_STATIC: } else {
/* Local symbol */
CodeFlags |= CF_CONST | CF_STATIC;
break;
case E_LOC_REGISTER: /* Generate the strlen code */
/* Register variable */ L = GetLocalLabel ();
CodeFlags |= CF_CONST | CF_REGVAR; AddCodeLine ("ldy #$FF");
break; g_defcodelabel (L);
AddCodeLine ("iny");
AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg, 0));
AddCodeLine ("bne %s", LocalLabelName (L));
AddCodeLine ("tax");
AddCodeLine ("tya");
case E_LOC_LITERAL: /* The function result is an rvalue in the primary register */
/* A literal of some kind. If string literals are read only, ED_MakeRValExpr (Expr);
* we can calculate the length of the string and remove it Expr->Type = type_size_t;
* from the literal pool. Otherwise we have to calculate the
* length at runtime.
*/
if (!WriteableStrings) {
/* String literals are const */
ExprDesc Length;
ED_MakeConstAbsInt (&Length, strlen (GetLiteral (Param.Val)));
ResetLiteralPoolOffs (Param.Val);
ExprLoad (CF_NONE, &Length);
goto ExitPoint;
} else {
CodeFlags |= CF_CONST | CF_STATIC;
ParamName = LiteralPoolLabel;
}
break;
default:
Internal ("Unknown constant type: %04X", Param.Flags);
} }
} else if (ED_IsLocStack (&Arg) && StackPtr >= -255 && IsTypeArray (Arg.Type)) {
/* Calculate the true stack offset */
unsigned Offs = (unsigned) (Arg.Val - StackPtr);
/* Do type conversion */
TypeConversion (&Arg, ArgType);
/* Generate the strlen code */
L = GetLocalLabel ();
AddCodeLine ("ldx #$FF");
AddCodeLine ("ldy #$%02X", (unsigned char) (Offs-1));
g_defcodelabel (L);
AddCodeLine ("inx");
AddCodeLine ("iny");
AddCodeLine ("lda (sp),y");
AddCodeLine ("bne %s", LocalLabelName (L));
AddCodeLine ("txa");
AddCodeLine ("ldx #$00");
/* The function result is an rvalue in the primary register */
ED_MakeRValExpr (Expr);
Expr->Type = type_size_t;
} else if (ED_IsLocRegister (&Arg) && ED_IsLVal (&Arg) && IsTypePtr (Arg.Type)) {
/* Do type conversion */
TypeConversion (&Arg, ArgType);
/* Generate the strlen code */
L = GetLocalLabel ();
AddCodeLine ("ldy #$FF");
g_defcodelabel (L);
AddCodeLine ("iny");
AddCodeLine ("lda (%s),y", ED_GetLabelName (&Arg, 0));
AddCodeLine ("bne %s", LocalLabelName (L));
AddCodeLine ("tax");
AddCodeLine ("tya");
/* The function result is an rvalue in the primary register */
ED_MakeRValExpr (Expr);
Expr->Type = type_size_t;
} else { } else {
/* Not an array with a constant address. Load parameter into primary */ /* Do type conversion */
ExprLoad (CF_NONE, &Param); TypeConversion (&Arg, ArgType);
/* Load the expression into the primary */
ExprLoad (CF_NONE, &Arg);
/* Call the strlen function */
AddCodeLine ("jsr _%s", Func_strlen);
/* The function result is an rvalue in the primary register */
ED_MakeRValExpr (Expr);
Expr->Type = type_size_t;
} }
/* Generate the strlen code */
g_strlen (CodeFlags, ParamName, Param.Val);
ExitPoint:
/* We expect the closing brace */ /* We expect the closing brace */
ConsumeRParen (); ConsumeRParen ();
} }
@ -295,23 +318,33 @@ ExitPoint:
int IsStdFunc (const char* Name) int FindStdFunc (const char* Name)
/* Determine if the given function is a known standard function that may be /* Determine if the given function is a known standard function that may be
* called in a special way. * called in a special way. If so, return the index, otherwise return -1.
*/ */
{ {
/* Look into the table for known names */ /* Look into the table for known names */
return FindFunc (Name) != 0; struct StdFuncDesc* D =
bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs[0]), CmpFunc);
/* Return the function index or -1 */
if (D == 0) {
return -1;
} else {
return D - StdFuncs;
}
} }
void HandleStdFunc (FuncDesc* F, ExprDesc* lval) void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval)
/* Generate code for a known standard function. */ /* Generate code for a known standard function. */
{ {
struct StdFuncDesc* D;
/* Get a pointer to the table entry */ /* Get a pointer to the table entry */
struct StdFuncDesc* D = FindFunc ((const char*) lval->Name); CHECK (Index >= 0 && Index < (int)FUNC_COUNT);
CHECK (D != 0); D = StdFuncs + Index;
/* Call the handler function */ /* Call the handler function */
D->Handler (F, lval); D->Handler (F, lval);

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2002 Ullrich von Bassewitz */ /* (C) 1998-2004 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -50,12 +50,12 @@
int IsStdFunc (const char* Name); int FindStdFunc (const char* Name);
/* Determine if the given function is a known standard function that may be /* Determine if the given function is a known standard function that may be
* called in a special way. * called in a special way. If so, return the index, otherwise return -1.
*/ */
void HandleStdFunc (struct FuncDesc* F, ExprDesc* lval); void HandleStdFunc (int Index, struct FuncDesc* F, ExprDesc* lval);
/* Generate code for a known standard function. */ /* Generate code for a known standard function. */

View File

@ -43,9 +43,10 @@
const char Func__bzero[] = "_bzero"; /* Asm name of "_bzero" */
const char Func_memcpy[] = "memcpy"; /* Asm name of "memcpy" */ const char Func_memcpy[] = "memcpy"; /* Asm name of "memcpy" */
const char Func_memset[] = "memset"; /* Asm name of "memset" */ const char Func_memset[] = "memset"; /* Asm name of "memset" */
const char Func__bzero[] = "_bzero"; /* Asm name of "_bzero */ const char Func_strlen[] = "strlen"; /* Asm name of "strlen" */

View File

@ -44,9 +44,10 @@
extern const char Func__bzero[]; /* Asm name of "_bzero" */
extern const char Func_memcpy[]; /* Asm name of "memcpy" */ extern const char Func_memcpy[]; /* Asm name of "memcpy" */
extern const char Func_memset[]; /* Asm name of "memset" */ extern const char Func_memset[]; /* Asm name of "memset" */
extern const char Func__bzero[]; /* Asm name of "_bzero */ extern const char Func_strlen[]; /* Asm name of "strlen" */

View File

@ -197,6 +197,16 @@ INLINE int SymIsRegVar (const SymEntry* Sym)
# define SymIsRegVar(Sym) (((Sym)->Flags & (SC_REGISTER|SC_TYPE)) == SC_REGISTER) # define SymIsRegVar(Sym) (((Sym)->Flags & (SC_REGISTER|SC_TYPE)) == SC_REGISTER)
#endif #endif
#if defined(HAVE_INLINE)
INLINE const char* SymGetAsmName (const SymEntry* Sym)
/* Return the assembler label name for the symbol (beware: may be NULL!) */
{
return Sym->AsmName;
}
#else
# define SymGetAsmName(Sym) ((Sym)->AsmName)
#endif
void CvtRegVarToAuto (SymEntry* Sym); void CvtRegVarToAuto (SymEntry* Sym);
/* Convert a register variable to an auto variable */ /* Convert a register variable to an auto variable */

View File

@ -68,7 +68,7 @@ static void DoPtrConversions (ExprDesc* Expr)
static void DoConversion (ExprDesc* Expr, type* NewType) static void DoConversion (ExprDesc* Expr, const type* NewType)
/* Emit code to convert the given expression to a new type. */ /* Emit code to convert the given expression to a new type. */
{ {
type* OldType; type* OldType;