mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 15:29:46 +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 */
|
||||
{
|
||||
/* 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 (funcargs >= 0) {
|
||||
|
||||
/* Drop stackframe if needed */
|
||||
/* Drop stackframe if needed. We can only drop 255 bytes at a time. */
|
||||
k += funcargs;
|
||||
if (k > 0) {
|
||||
if (k <= 8) {
|
||||
AddCodeLine ("jsr incsp%d", k);
|
||||
while (k > 0) {
|
||||
unsigned ToDrop = (k > 255)? 255 : k;
|
||||
if (ToDrop <= 8) {
|
||||
AddCodeLine ("jsr incsp%d", k);
|
||||
} else {
|
||||
CheckLocalOffs (k);
|
||||
ldyconst (k);
|
||||
AddCodeLine ("jsr addysp");
|
||||
ldyconst (ToDrop);
|
||||
AddCodeLine ("jsr addysp");
|
||||
}
|
||||
k -= ToDrop;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -488,6 +489,11 @@ void g_leave (void)
|
||||
AddCodeLine ("jsr leave");
|
||||
} else {
|
||||
/* We've a stack frame to drop */
|
||||
while (k > 255) {
|
||||
ldyconst (255);
|
||||
AddCodeLine ("jsr addysp");
|
||||
k -= 255;
|
||||
}
|
||||
ldyconst (k);
|
||||
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 */
|
||||
#endif
|
||||
|
||||
|
@ -455,13 +455,6 @@ void ExprLoad (unsigned Flags, ExprDesc* Expr)
|
||||
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 */
|
||||
int IsFuncPtr; /* Flag */
|
||||
int StdFunc; /* Standard function index */
|
||||
unsigned ParamSize; /* Number of parameter bytes */
|
||||
CodeMark Mark = 0; /* Initialize to keep gcc silent */
|
||||
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 */
|
||||
} 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 */
|
||||
HandleStdFunc (Func, Expr);
|
||||
goto ExitPoint;
|
||||
HandleStdFunc (StdFunc, Func, Expr);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@ -712,7 +707,7 @@ static void FunctionCall (ExprDesc* Expr)
|
||||
*/
|
||||
if (ParamSize == 0) {
|
||||
RemoveCode (Mark);
|
||||
pop (CF_PTR);
|
||||
pop (CF_PTR);
|
||||
PtrOnStack = 0;
|
||||
} else {
|
||||
/* 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 */
|
||||
ED_MakeRValExpr (Expr);
|
||||
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
|
||||
* action required).
|
||||
*/
|
||||
g_scale (CF_INT | CF_UNSIGNED, CheckedSizeOf (ElementType));
|
||||
g_scale (CF_INT, CheckedSizeOf (ElementType));
|
||||
|
||||
} else {
|
||||
|
||||
@ -1144,7 +1138,7 @@ static void ArrayRef (ExprDesc* Expr)
|
||||
/* The array base address is on stack and the subscript is in the
|
||||
* primary. Add both.
|
||||
*/
|
||||
g_add (CF_INT | CF_UNSIGNED, 0);
|
||||
g_add (CF_INT, 0);
|
||||
|
||||
} else {
|
||||
|
||||
@ -1182,7 +1176,7 @@ static void ArrayRef (ExprDesc* Expr)
|
||||
} else {
|
||||
if (ED_IsLocAbs (Expr)) {
|
||||
/* 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)) {
|
||||
/* Base address is a local variable address */
|
||||
if (IsTypeArray (Expr->Type)) {
|
||||
|
@ -33,8 +33,13 @@
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "xsprintf.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "asmlabel.h"
|
||||
#include "datatype.h"
|
||||
#include "error.h"
|
||||
#include "symentry.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)
|
||||
/* 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)
|
||||
#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)
|
||||
INLINE int ED_IsLocStack (const ExprDesc* Expr)
|
||||
/* 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)
|
||||
#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)
|
||||
INLINE int ED_IsLocExpr (const ExprDesc* Expr)
|
||||
/* 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)
|
||||
#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)
|
||||
INLINE int ED_IsLocConst (const ExprDesc* Expr)
|
||||
/* 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)
|
||||
#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);
|
||||
/* 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 CreateDep = 0; /* Create a dependency file */
|
||||
unsigned char ANSI = 0; /* Strict ANSI flag */
|
||||
unsigned char WriteableStrings = 0; /* Literal strings are r/w */
|
||||
unsigned char NoWarn = 0; /* Suppress warnings */
|
||||
unsigned char Optimize = 0; /* Optimize flag */
|
||||
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 */
|
||||
|
||||
/* Stackable options */
|
||||
IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */
|
||||
IntStack InlineStdFuncs = INTSTACK(0); /* Inline some known functions */
|
||||
IntStack EnableRegVars = INTSTACK(0); /* Enable register variables */
|
||||
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 CreateDep; /* Create a dependency file */
|
||||
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 Optimize; /* Optimize flag */
|
||||
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 */
|
||||
|
||||
/* Stackable options */
|
||||
extern IntStack WritableStrings; /* Literal strings are r/w */
|
||||
extern IntStack InlineStdFuncs; /* Inline some known functions */
|
||||
extern IntStack EnableRegVars; /* Enable register variables */
|
||||
extern IntStack AllowRegVarAddr; /* Allow taking addresses of register vars */
|
||||
|
@ -6,10 +6,10 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* (C) 1998-2004 Ullrich von Bassewitz */
|
||||
/* Römerstraße 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* This software is provided 'as-is', without any expressed or implied */
|
||||
@ -93,7 +93,7 @@ void DumpLiteralPool (void)
|
||||
}
|
||||
|
||||
/* Switch to the data segment */
|
||||
if (WriteableStrings) {
|
||||
if (IS_Get (&WritableStrings)) {
|
||||
g_usedata ();
|
||||
} else {
|
||||
g_userodata ();
|
||||
@ -168,7 +168,7 @@ void GetLiteralStrBuf (StrBuf* Target, unsigned Offs)
|
||||
/* Copy the string starting at Offs and lasting to the end of the buffer
|
||||
* into Target.
|
||||
*/
|
||||
{
|
||||
{
|
||||
CHECK (Offs <= SB_GetLen (&LiteralPool));
|
||||
SB_Slice (Target, &LiteralPool, Offs, SB_GetLen (&LiteralPool) - Offs);
|
||||
}
|
||||
|
@ -127,7 +127,8 @@ static void Usage (void)
|
||||
" --static-locals\tMake local variables static\n"
|
||||
" --target sys\t\tSet the target system\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);
|
||||
}
|
||||
|
||||
@ -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[])
|
||||
{
|
||||
/* Program long options */
|
||||
@ -691,6 +701,7 @@ int main (int argc, char* argv[])
|
||||
{ "--target", 1, OptTarget },
|
||||
{ "--verbose", 0, OptVerbose },
|
||||
{ "--version", 0, OptVersion },
|
||||
{ "--writable-strings", 0, OptWritableStrings },
|
||||
};
|
||||
|
||||
unsigned I;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "check.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "asmlabel.h"
|
||||
#include "codegen.h"
|
||||
#include "error.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 {
|
||||
const char* Name;
|
||||
void (*Handler) (FuncDesc*, ExprDesc*);
|
||||
} StdFuncs [] = {
|
||||
void (*Handler) (FuncDesc*, ExprDesc*);
|
||||
} StdFuncs[] = {
|
||||
{ "memset", StdFunc_memset },
|
||||
{ "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)
|
||||
/* Parse one argument but do not push it onto the stack. Return the code
|
||||
* 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)),
|
||||
ExprDesc* lval attribute ((unused)))
|
||||
static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
|
||||
/* Handle the memset function */
|
||||
{
|
||||
/* Argument types */
|
||||
@ -198,91 +189,123 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)),
|
||||
|
||||
/* We expect the closing brace */
|
||||
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)),
|
||||
ExprDesc* lval attribute ((unused)))
|
||||
static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
|
||||
/* Handle the strlen function */
|
||||
{
|
||||
static type ParamType[] = { T_PTR, T_SCHAR, T_END };
|
||||
ExprDesc Param;
|
||||
unsigned CodeFlags;
|
||||
unsigned long ParamName;
|
||||
static type ArgType[] = { T_PTR, T_SCHAR, T_END };
|
||||
ExprDesc Arg;
|
||||
unsigned L;
|
||||
|
||||
|
||||
/* 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 */
|
||||
hie1 (&Param);
|
||||
TypeConversion (&Param, ParamType);
|
||||
/* Evaluate the parameter */
|
||||
hie1 (&Arg);
|
||||
|
||||
/* Check if the parameter is a constant array of some type, or a numeric
|
||||
* address cast to a pointer.
|
||||
*/
|
||||
CodeFlags = 0;
|
||||
ParamName = Param.Name;
|
||||
if ((ED_IsLocConst (&Param) && IsTypeArray (Param.Type)) ||
|
||||
(ED_IsLocAbs (&Param) && IsTypePtr (Param.Type))) {
|
||||
/* We can generate special code for several locations */
|
||||
if (ED_IsLocConst (&Arg) && IsTypeArray (Arg.Type)) {
|
||||
|
||||
/* Check which type of constant it is */
|
||||
switch (ED_GetLoc (&Param)) {
|
||||
/* Do type conversion */
|
||||
TypeConversion (&Arg, ArgType);
|
||||
|
||||
case E_LOC_ABS:
|
||||
/* Numerical address */
|
||||
CodeFlags |= CF_CONST | CF_ABSOLUTE;
|
||||
break;
|
||||
/* If the expression is a literal, and if string literals are read
|
||||
* only, we can calculate the length of the string and remove it
|
||||
* from the literal pool. Otherwise we have to calculate the length
|
||||
* at runtime.
|
||||
*/
|
||||
if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings)) {
|
||||
|
||||
case E_LOC_GLOBAL:
|
||||
/* Global label */
|
||||
CodeFlags |= CF_CONST | CF_EXTERNAL;
|
||||
break;
|
||||
/* Constant string literal */
|
||||
ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t);
|
||||
ResetLiteralPoolOffs (Arg.Val);
|
||||
|
||||
case E_LOC_STATIC:
|
||||
/* Local symbol */
|
||||
CodeFlags |= CF_CONST | CF_STATIC;
|
||||
break;
|
||||
} else {
|
||||
|
||||
case E_LOC_REGISTER:
|
||||
/* Register variable */
|
||||
CodeFlags |= CF_CONST | CF_REGVAR;
|
||||
break;
|
||||
/* 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");
|
||||
|
||||
case E_LOC_LITERAL:
|
||||
/* A literal of some kind. If string literals are read only,
|
||||
* we can calculate the length of the string and remove it
|
||||
* 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;
|
||||
/* The function result is an rvalue in the primary register */
|
||||
ED_MakeRValExpr (Expr);
|
||||
Expr->Type = type_size_t;
|
||||
|
||||
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 {
|
||||
|
||||
/* Not an array with a constant address. Load parameter into primary */
|
||||
ExprLoad (CF_NONE, &Param);
|
||||
/* Do type conversion */
|
||||
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 */
|
||||
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
|
||||
* 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 */
|
||||
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. */
|
||||
{
|
||||
struct StdFuncDesc* D;
|
||||
|
||||
/* Get a pointer to the table entry */
|
||||
struct StdFuncDesc* D = FindFunc ((const char*) lval->Name);
|
||||
CHECK (D != 0);
|
||||
CHECK (Index >= 0 && Index < (int)FUNC_COUNT);
|
||||
D = StdFuncs + Index;
|
||||
|
||||
/* Call the handler function */
|
||||
D->Handler (F, lval);
|
||||
|
@ -6,10 +6,10 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 1998-2002 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@musoftware.de */
|
||||
/* (C) 1998-2004 Ullrich von Bassewitz */
|
||||
/* Römerstrasse 52 */
|
||||
/* D-70794 Filderstadt */
|
||||
/* EMail: uz@cc65.org */
|
||||
/* */
|
||||
/* */
|
||||
/* 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
|
||||
* 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. */
|
||||
|
||||
|
||||
|
@ -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_memset[] = "memset"; /* Asm name of "memset" */
|
||||
const char Func__bzero[] = "_bzero"; /* Asm name of "_bzero */
|
||||
const char Func_strlen[] = "strlen"; /* Asm name of "strlen" */
|
||||
|
||||
|
||||
|
||||
|
@ -43,10 +43,11 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
extern const char Func__bzero[]; /* Asm name of "_bzero" */
|
||||
extern const char Func_memcpy[]; /* Asm name of "memcpy" */
|
||||
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)
|
||||
#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);
|
||||
/* 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. */
|
||||
{
|
||||
type* OldType;
|
||||
|
Loading…
Reference in New Issue
Block a user