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:
parent
2bb2ceec33
commit
6e34e386cb
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)) {
|
||||||
|
@ -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. */
|
||||||
{
|
{
|
||||||
|
@ -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. */
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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 ();
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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. */
|
||||||
|
|
||||||
|
|
||||||
|
@ -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" */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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" */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user