From 104ae3a54f88f79442cad292b8f57d32bdb0d87c Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 5 Jun 2004 11:35:53 +0000 Subject: [PATCH] Move the compiler stack pointer into its own module. Improved the inlining of standard C functions. Added more standard functions to inline. git-svn-id: svn://svn.cc65.org/cc65/trunk@3095 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/asmstmt.c | 1 + src/cc65/codegen.c | 12 +- src/cc65/codegen.h | 3 - src/cc65/expr.c | 3 +- src/cc65/expr.h | 5 +- src/cc65/exprdesc.c | 15 + src/cc65/exprdesc.h | 5 + src/cc65/function.c | 1 + src/cc65/locals.c | 3 +- src/cc65/make/gcc.mak | 1 + src/cc65/make/watcom.mak | 1 + src/cc65/stackptr.c | 57 +++ src/cc65/stackptr.h | 63 +++ src/cc65/stdfunc.c | 882 +++++++++++++++++++++++++++++++++++---- src/cc65/stmt.c | 11 +- src/cc65/swstmt.c | 5 +- src/cc65/symtab.c | 3 +- 17 files changed, 978 insertions(+), 93 deletions(-) create mode 100644 src/cc65/stackptr.c create mode 100644 src/cc65/stackptr.h diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index 8c66bcbd7..774d5ffa4 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -46,6 +46,7 @@ #include "function.h" #include "litpool.h" #include "scanner.h" +#include "stackptr.h" #include "symtab.h" #include "asmstmt.h" diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 5b75a764f..1854c4b8d 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -54,23 +54,13 @@ #include "error.h" #include "global.h" #include "segments.h" +#include "stackptr.h" #include "textseg.h" #include "util.h" #include "codegen.h" -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Compiler relative stack pointer */ -int StackPtr = 0; - - - /*****************************************************************************/ /* Helpers */ /*****************************************************************************/ diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 58e0217ef..815482fe4 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -85,9 +85,6 @@ -/* Compiler relative stackpointer */ -extern int StackPtr; - /* Forward */ struct StrBuf; diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 23f148e53..0057e272c 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -28,6 +28,7 @@ #include "macrotab.h" #include "preproc.h" #include "scanner.h" +#include "stackptr.h" #include "stdfunc.h" #include "symtab.h" #include "typecmp.h" @@ -97,7 +98,7 @@ static unsigned GlobalModeFlags (unsigned Flags) -static void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr) +void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr) /* Call an expression function with checks. */ { /* Remember the stack pointer */ diff --git a/src/cc65/expr.h b/src/cc65/expr.h index acf442986..c24a4dd2d 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -23,7 +23,10 @@ -void PushAddr (const ExprDesc* Expr); +void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr); +/* Call an expression function with checks. */ + +void PushAddr (const ExprDesc* Expr); /* If the expression contains an address that was somehow evaluated, * push this address on the stack. This is a helper function for all * sorts of implicit or explicit assignment functions where the lvalue diff --git a/src/cc65/exprdesc.c b/src/cc65/exprdesc.c index 7c498eda8..bb2571050 100644 --- a/src/cc65/exprdesc.c +++ b/src/cc65/exprdesc.c @@ -34,12 +34,14 @@ /* common */ +#include "check.h" #include "xsprintf.h" /* cc65 */ #include "asmlabel.h" #include "datatype.h" #include "error.h" +#include "stackptr.h" #include "symentry.h" #include "exprdesc.h" @@ -123,6 +125,19 @@ const char* ED_GetLabelName (const ExprDesc* Expr, long Offs) +int ED_GetStackOffs (const ExprDesc* Expr, int Offs) +/* Get the stack offset of an address on the stack in Expr taking into account + * an additional offset in Offs. + */ +{ + PRECONDITION (ED_IsLocStack (Expr)); + Offs += ((int) Expr->Val) - StackPtr; + CHECK (Offs >= 0); /* Cannot handle negative stack offsets */ + return Offs; +} + + + ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type) /* Make Expr an absolute const with the given value and type. */ { diff --git a/src/cc65/exprdesc.h b/src/cc65/exprdesc.h index 420f86b6c..99c0edbc9 100644 --- a/src/cc65/exprdesc.h +++ b/src/cc65/exprdesc.h @@ -229,6 +229,11 @@ const char* ED_GetLabelName (const ExprDesc* Expr, long Offs); * call to the function. */ +int ED_GetStackOffs (const ExprDesc* Expr, int Offs); +/* Get the stack offset of an address on the stack in Expr taking into account + * an additional offset in Offs. + */ + ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, type* Type); /* Make Expr an absolute const with the given value and type. */ diff --git a/src/cc65/function.c b/src/cc65/function.c index 505e6804a..d4409afba 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -48,6 +48,7 @@ #include "locals.h" #include "scanner.h" #include "segments.h" +#include "stackptr.h" #include "stmt.h" #include "symtab.h" #include "function.h" diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 44662577c..6805424fb 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -47,6 +47,7 @@ #include "function.h" #include "global.h" #include "locals.h" +#include "stackptr.h" #include "symtab.h" #include "typeconv.h" @@ -214,7 +215,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) /* If the value is not const, load it into the primary. * Otherwise pass the information to the code generator. - */ + */ if (ED_IsConstAbsInt (&Expr)) { Flags |= CF_CONST; } else { diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 8aaf2005c..18219a337 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -78,6 +78,7 @@ OBJS = anonname.o \ scanner.o \ scanstrbuf.o \ segments.o \ + stackptr.o \ stdfunc.o \ stdnames.o \ stmt.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index ca3bcb07e..6d032fe93 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -112,6 +112,7 @@ OBJS = anonname.obj \ scanner.obj \ scanstrbuf.obj \ segments.obj \ + stackptr.obj \ stdfunc.obj \ stdnames.obj \ stmt.obj \ diff --git a/src/cc65/stackptr.c b/src/cc65/stackptr.c new file mode 100644 index 000000000..24b474fbf --- /dev/null +++ b/src/cc65/stackptr.c @@ -0,0 +1,57 @@ +/*****************************************************************************/ +/* */ +/* stackptr.c */ +/* */ +/* Manage the parameter stack pointer */ +/* */ +/* */ +/* */ +/* (C) 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 */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* cc65 */ +#include "stackptr.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Compiler relative stackpointer */ +int StackPtr = 0; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + diff --git a/src/cc65/stackptr.h b/src/cc65/stackptr.h new file mode 100644 index 000000000..88e1735df --- /dev/null +++ b/src/cc65/stackptr.h @@ -0,0 +1,63 @@ +/*****************************************************************************/ +/* */ +/* stackptr.h */ +/* */ +/* Manage the parameter stack pointer */ +/* */ +/* */ +/* */ +/* (C) 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 */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef STACKPTR_H +#define STACKPTR_H + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Compiler relative stackpointer */ +extern int StackPtr; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +/* End of stackptr.h */ + +#endif + + + diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 9fa237c6e..7ba4e4bbd 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -41,6 +41,7 @@ #include "check.h" /* cc65 */ +#include "asmcode.h" #include "asmlabel.h" #include "codegen.h" #include "error.h" @@ -48,6 +49,7 @@ #include "global.h" #include "litpool.h" #include "scanner.h" +#include "stackptr.h" #include "stdfunc.h" #include "stdnames.h" #include "typeconv.h" @@ -60,13 +62,15 @@ +static void StdFunc_memcpy (FuncDesc*, ExprDesc*); static void StdFunc_memset (FuncDesc*, ExprDesc*); +static void StdFunc_strcpy (FuncDesc*, ExprDesc*); static void StdFunc_strlen (FuncDesc*, ExprDesc*); /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ @@ -78,12 +82,25 @@ static struct StdFuncDesc { const char* Name; void (*Handler) (FuncDesc*, ExprDesc*); } StdFuncs[] = { + { "memcpy", StdFunc_memcpy }, { "memset", StdFunc_memset }, + { "strcpy", StdFunc_strcpy }, { "strlen", StdFunc_strlen }, }; #define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs[0])) +typedef struct ArgDesc ArgDesc; +struct ArgDesc { + const type* ArgType; /* Required argument type */ + ExprDesc Expr; /* Argument expression */ + const type* Type; /* The original type before conversion */ + CodeMark Start; /* Start of the code for calculation */ + CodeMark Push; /* Start of argument push code */ + CodeMark End; /* End of the code for calculation+push */ + unsigned Flags; /* Code generation flags */ +}; + /*****************************************************************************/ @@ -100,40 +117,366 @@ static int CmpFunc (const void* Key, const void* Elem) -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. +static long ArrayElementCount (const ArgDesc* Arg) +/* Check if the type of the given argument is an array. If so, and if the + * element count is known, return it. In all other cases, return UNSPECIFIED. + */ +{ + long Count; + + if (IsTypeArray (Arg->Type)) { + Count = GetElementCount (Arg->Type); + if (Count == FLEXIBLE) { + /* Treat as unknown */ + Count = UNSPECIFIED; + } + } else { + Count = UNSPECIFIED; + } + return Count; +} + + + +static void ParseArg (ArgDesc* Arg, type* Type) +/* Parse one argument but do not push it onto the stack. Make all fields in + * Arg valid. */ { /* We have a prototype, so chars may be pushed as chars */ - unsigned Flags = CF_FORCECHAR; + Arg->Flags = CF_FORCECHAR; + + /* Remember the required argument type */ + Arg->ArgType = Type; + + /* Remember the current code position */ + Arg->Start = GetCodePos (); /* Read the expression we're going to pass to the function */ - hie1 (Arg); + ExprWithCheck (hie1, &Arg->Expr); + + /* Remember the actual argument type */ + Arg->Type = Arg->Expr.Type; /* Convert this expression to the expected type */ - TypeConversion (Arg, Type); + TypeConversion (&Arg->Expr, Type); /* If the value is a constant, set the flag, otherwise load it into the * primary register. */ - if (ED_IsConstAbsInt (Arg)) { + if (ED_IsConstAbsInt (&Arg->Expr)) { /* Remember that we have a constant value */ - Flags |= CF_CONST; + Arg->Flags |= CF_CONST; } else { /* Load into the primary */ - ExprLoad (CF_NONE, Arg); - ED_MakeRVal (Arg); + ExprLoad (CF_NONE, &Arg->Expr); } + /* Remember the following code position */ + Arg->End = Arg->Push = GetCodePos (); + /* Use the type of the argument for the push */ - return (Flags | TypeOf (Arg->Type)); + Arg->Flags |= TypeOf (Arg->Expr.Type); +} + + + +/*****************************************************************************/ +/* memcpy */ +/*****************************************************************************/ + + + +static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) +/* Handle the memcpy function */ +{ + /* Argument types */ + static type Arg1Type[] = { T_PTR, T_VOID, T_END }; /* void* */ + static type Arg2Type[] = { T_PTR, T_VOID|T_QUAL_CONST, T_END }; /* const void* */ + static type Arg3Type[] = { T_SIZE_T, T_END }; /* size_t */ + + CodeMark Start; + ArgDesc Arg1, Arg2, Arg3; + unsigned ParamSize = 0; + unsigned Label; + + /* Remember where we are now */ + Start = GetCodePos (); + + /* Argument #1 */ + ParseArg (&Arg1, Arg1Type); + g_push (Arg1.Flags, Arg1.Expr.Val); + Arg1.End = GetCodePos (); + ParamSize += SizeOf (Arg1Type); + ConsumeComma (); + + /* Argument #2 */ + ParseArg (&Arg2, Arg2Type); + g_push (Arg2.Flags, Arg2.Expr.Val); + Arg2.End = GetCodePos (); + ParamSize += SizeOf (Arg2Type); + ConsumeComma (); + + /* Argument #3. Since memcpy is a fastcall function, we must load the + * arg into the primary if it is not already there. This parameter is + * also ignored for the calculation of the parameter size, since it is + * not passed via the stack. + */ + ParseArg (&Arg3, Arg3Type); + if (Arg3.Flags & CF_CONST) { + ExprLoad (CF_FORCECHAR, &Arg3.Expr); + } + + /* Emit the actual function call. This will also cleanup the stack. */ + g_call (CF_FIXARGC, Func_memcpy, ParamSize); + + if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val == 0) { + + /* memcpy has been called with a count argument of zero */ + Warning ("Call to memcpy has no effect"); + + /* Remove all of the generated code but the load of the first + * argument, which is what memcpy returns. + */ + RemoveCode (Arg1.Push); + + /* Set the function result to the first argument */ + *Expr = Arg1.Expr; + + /* Bail out, no need for further improvements */ + goto ExitPoint; + } + + /* We've generated the complete code for the function now and know the + * types of all parameters. Check for situations where better code can + * be generated. If such a situation is detected, throw away the + * generated, and emit better code. + */ + if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) || + (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) && + ((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) || + (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)))) { + + int Reg1 = ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr); + int Reg2 = ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate memcpy code */ + if (Arg3.Expr.Val <= 127) { + + AddCodeLine ("ldy #$%02X", (unsigned char) (Arg3.Expr.Val-1)); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + if (Reg2) { + AddCodeLine ("lda (%s),y", ED_GetLabelName (&Arg2.Expr, 0)); + } else { + AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg2.Expr, 0)); + } + if (Reg1) { + AddCodeLine ("sta (%s),y", ED_GetLabelName (&Arg1.Expr, 0)); + } else { + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, 0)); + } + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + + } else { + + AddCodeLine ("ldy #$00"); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + if (Reg2) { + AddCodeLine ("lda (%s),y", ED_GetLabelName (&Arg2.Expr, 0)); + } else { + AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg2.Expr, 0)); + } + if (Reg1) { + AddCodeLine ("sta (%s),y", ED_GetLabelName (&Arg1.Expr, 0)); + } else { + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, 0)); + } + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) Arg3.Expr.Val); + AddCodeLine ("bne %s", LocalLabelName (Label)); + + } + + /* memcpy returns the address, so the result is actually identical + * to the first argument. + */ + *Expr = Arg1.Expr; + + } else if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr) && + ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) && + (Arg1.Expr.Val - StackPtr) + Arg3.Expr.Val < 256) { + + /* It is possible to just use one index register even if the stack + * offset is not zero, by adjusting the offset to the constant + * address accordingly. But we cannot do this if the data in + * question is in the register space or at an absolute address less + * than 256. Register space is zero page, which means that the + * address calculation could overflow in the linker. + */ + int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) && + !(ED_IsLocAbs (&Arg2.Expr) && Arg2.Expr.Val < 256); + + /* Calculate the real stack offset */ + int Offs = ED_GetStackOffs (&Arg1.Expr, 0); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate memcpy code */ + if (Arg3.Expr.Val <= 127) { + + if (Offs == 0 || AllowOneIndex) { + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val - 1)); + g_defcodelabel (Label); + AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg2.Expr, -Offs)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + } else { + AddCodeLine ("ldx #$%02X", (unsigned char) (Arg3.Expr.Val-1)); + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val - 1)); + g_defcodelabel (Label); + AddCodeLine ("lda %s,x", ED_GetLabelName (&Arg2.Expr, 0)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("dey"); + AddCodeLine ("dex"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + } + + } else { + + if (Offs == 0 || AllowOneIndex) { + AddCodeLine ("ldy #$%02X", (unsigned char) Offs); + g_defcodelabel (Label); + AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg2.Expr, -Offs)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val)); + AddCodeLine ("bne %s", LocalLabelName (Label)); + } else { + AddCodeLine ("ldx #$00"); + AddCodeLine ("ldy #$%02X", (unsigned char) Offs); + g_defcodelabel (Label); + AddCodeLine ("lda %s,x", ED_GetLabelName (&Arg2.Expr, 0)); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("inx"); + AddCodeLine ("cpx #$%02X", (unsigned char) Arg3.Expr.Val); + AddCodeLine ("bne %s", LocalLabelName (Label)); + } + + } + + /* memcpy returns the address, so the result is actually identical + * to the first argument. + */ + *Expr = Arg1.Expr; + + } else if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ED_IsRVal (&Arg2.Expr) && ED_IsLocStack (&Arg2.Expr) && + (Arg2.Expr.Val - StackPtr) + Arg3.Expr.Val < 256 && + ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) { + + /* It is possible to just use one index register even if the stack + * offset is not zero, by adjusting the offset to the constant + * address accordingly. But we cannot do this if the data in + * question is in the register space or at an absolute address less + * than 256. Register space is zero page, which means that the + * address calculation could overflow in the linker. + */ + int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) && + !(ED_IsLocAbs (&Arg1.Expr) && Arg1.Expr.Val < 256); + + /* Calculate the real stack offset */ + int Offs = ED_GetStackOffs (&Arg2.Expr, 0); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate memcpy code */ + if (Arg3.Expr.Val <= 127) { + + if (Offs == 0 || AllowOneIndex) { + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val - 1)); + g_defcodelabel (Label); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, -Offs)); + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + } else { + AddCodeLine ("ldx #$%02X", (unsigned char) (Arg3.Expr.Val-1)); + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val - 1)); + g_defcodelabel (Label); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,x", ED_GetLabelName (&Arg1.Expr, 0)); + AddCodeLine ("dey"); + AddCodeLine ("dex"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + } + + } else { + + if (Offs == 0 || AllowOneIndex) { + AddCodeLine ("ldy #$%02X", (unsigned char) Offs); + g_defcodelabel (Label); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, -Offs)); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val)); + AddCodeLine ("bne %s", LocalLabelName (Label)); + } else { + AddCodeLine ("ldx #$00"); + AddCodeLine ("ldy #$%02X", (unsigned char) Offs); + g_defcodelabel (Label); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,x", ED_GetLabelName (&Arg1.Expr, 0)); + AddCodeLine ("iny"); + AddCodeLine ("inx"); + AddCodeLine ("cpx #$%02X", (unsigned char) Arg3.Expr.Val); + AddCodeLine ("bne %s", LocalLabelName (Label)); + } + + } + + /* memcpy returns the address, so the result is actually identical + * to the first argument. + */ + *Expr = Arg1.Expr; + + } else { + + /* The function result is an rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Type = GetFuncReturn (Expr->Type); + + } + +ExitPoint: + /* We expect the closing brace */ + ConsumeRParen (); } /*****************************************************************************/ -/* Handle known functions */ +/* memset */ /*****************************************************************************/ @@ -144,29 +487,35 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) /* Argument types */ static type Arg1Type[] = { T_PTR, T_VOID, T_END }; /* void* */ static type Arg2Type[] = { T_INT, T_END }; /* int */ - static type Arg3Type[] = { T_UINT, T_END }; /* size_t */ + static type Arg3Type[] = { T_SIZE_T, T_END }; /* size_t */ - unsigned Flags; - ExprDesc Arg; + CodeMark Start; + ArgDesc Arg1, Arg2, Arg3; int MemSet = 1; /* Use real memset if true */ unsigned ParamSize = 0; + unsigned Label; + + /* Remember where we are now */ + Start = GetCodePos (); /* Argument #1 */ - Flags = ParseArg (Arg1Type, &Arg); - g_push (Flags, Arg.Val); + ParseArg (&Arg1, Arg1Type); + g_push (Arg1.Flags, Arg1.Expr.Val); + Arg1.End = GetCodePos (); ParamSize += SizeOf (Arg1Type); ConsumeComma (); /* Argument #2. This argument is special in that we will call another * function if it is a constant zero. */ - Flags = ParseArg (Arg2Type, &Arg); - if ((Flags & CF_CONST) != 0 && Arg.Val == 0) { + ParseArg (&Arg2, Arg2Type); + if ((Arg2.Flags & CF_CONST) != 0 && Arg2.Expr.Val == 0) { /* Don't call memset, call bzero instead */ MemSet = 0; } else { /* Push the argument */ - g_push (Flags, Arg.Val); + g_push (Arg2.Flags, Arg2.Expr.Val); + Arg2.End = GetCodePos (); ParamSize += SizeOf (Arg2Type); } ConsumeComma (); @@ -176,83 +525,453 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr) * also ignored for the calculation of the parameter size, since it is * not passed via the stack. */ - Flags = ParseArg (Arg3Type, &Arg); - if (Flags & CF_CONST) { - if (Arg.Val == 0) { - Warning ("Call to memset has no effect"); - } - ExprLoad (CF_FORCECHAR, &Arg); + ParseArg (&Arg3, Arg3Type); + if (Arg3.Flags & CF_CONST) { + ExprLoad (CF_FORCECHAR, &Arg3.Expr); + } + + /* Emit the actual function call. This will also cleanup the stack. */ + g_call (CF_FIXARGC, MemSet? Func_memset : Func__bzero, ParamSize); + + if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val == 0) { + + /* memset has been called with a count argument of zero */ + Warning ("Call to memset has no effect"); + + /* Remove all of the generated code but the load of the first + * argument, which is what memset returns. + */ + RemoveCode (Arg1.Push); + + /* Set the function result to the first argument */ + *Expr = Arg1.Expr; + + /* Bail out, no need for further improvements */ + goto ExitPoint; } - /* Emit the actual function call */ - g_call (CF_NONE, MemSet? Func_memset : Func__bzero, ParamSize); + /* We've generated the complete code for the function now and know the + * types of all parameters. Check for situations where better code can + * be generated. If such a situation is detected, throw away the + * generated, and emit better code. + * Note: Lots of improvements would be possible here, but I will + * concentrate on the most common case: memset with arguments 2 and 3 + * being constant numerical values. Some checks have shown that this + * covers nearly 90% of all memset calls. + */ + if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ED_IsConstAbsInt (&Arg2.Expr) && + ((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) || + (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)))) { + + int Reg = ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate memset code */ + if (Arg3.Expr.Val <= 127) { + + AddCodeLine ("ldy #$%02X", (unsigned char) (Arg3.Expr.Val-1)); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + if (Reg) { + AddCodeLine ("sta (%s),y", ED_GetLabelName (&Arg1.Expr, 0)); + } else { + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, 0)); + } + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + + } else { + + AddCodeLine ("ldy #$00"); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + if (Reg) { + AddCodeLine ("sta (%s),y", ED_GetLabelName (&Arg1.Expr, 0)); + } else { + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, 0)); + } + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) Arg3.Expr.Val); + AddCodeLine ("bne %s", LocalLabelName (Label)); + + } + + /* memset returns the address, so the result is actually identical + * to the first argument. + */ + *Expr = Arg1.Expr; + + } else if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ED_IsConstAbsInt (&Arg2.Expr) && + ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) && + (Arg1.Expr.Val - StackPtr) + Arg3.Expr.Val < 256) { + + /* Calculate the real stack offset */ + int Offs = ED_GetStackOffs (&Arg1.Expr, 0); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate memset code */ + AddCodeLine ("ldy #$%02X", (unsigned char) Offs); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + AddCodeLine ("sta (sp),y"); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) (Offs + Arg3.Expr.Val)); + AddCodeLine ("bne %s", LocalLabelName (Label)); + + /* memset returns the address, so the result is actually identical + * to the first argument. + */ + *Expr = Arg1.Expr; + + } else if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.Val <= 256 && + ED_IsConstAbsInt (&Arg2.Expr) && + (Arg2.Expr.Val != 0 || CodeSizeFactor > 200)) { + + /* Remove all of the generated code but the load of the first + * argument. + */ + RemoveCode (Arg1.Push); + + /* We need a label */ + Label = GetLocalLabel (); + + /* Generate code */ + AddCodeLine ("sta ptr1"); + AddCodeLine ("stx ptr1+1"); + if (Arg3.Expr.Val <= 127) { + AddCodeLine ("ldy #$%02X", (unsigned char) (Arg3.Expr.Val-1)); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + AddCodeLine ("sta (ptr1),y"); + AddCodeLine ("dey"); + AddCodeLine ("bpl %s", LocalLabelName (Label)); + } else { + AddCodeLine ("ldy #$00"); + AddCodeLine ("lda #$%02X", (unsigned char) Arg2.Expr.Val); + g_defcodelabel (Label); + AddCodeLine ("sta (ptr1),y"); + AddCodeLine ("iny"); + AddCodeLine ("cpy #$%02X", (unsigned char) Arg3.Expr.Val); + AddCodeLine ("bne %s", LocalLabelName (Label)); + } + + /* Load the function result pointer into a/x (x is still valid). This + * code will get removed by the optimizer if it is not used later. + */ + AddCodeLine ("lda ptr1"); + + /* The function result is an rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Type = GetFuncReturn (Expr->Type); + + } else { + + /* The function result is an rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Type = GetFuncReturn (Expr->Type); + + } +ExitPoint: /* We expect the closing brace */ ConsumeRParen (); +} + + + +/*****************************************************************************/ +/* strcpy */ +/*****************************************************************************/ + + + +static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr) +/* Handle the strcpy function */ +{ + /* Argument types */ + static type Arg1Type[] = { T_PTR, T_CHAR, T_END }; /* char* */ + static type Arg2Type[] = { T_PTR, T_CHAR|T_QUAL_CONST, T_END }; /* const char* */ + + CodeMark Start; + ArgDesc Arg1, Arg2; + unsigned ParamSize = 0; + long ECount; + unsigned L1; + + /* Setup the argument type string */ + Arg1Type[1] = GetDefaultChar (); + Arg2Type[1] = GetDefaultChar () | T_QUAL_CONST; + + /* Remember where we are now */ + Start = GetCodePos (); + + /* Argument #1 */ + ParseArg (&Arg1, Arg1Type); + g_push (Arg1.Flags, Arg1.Expr.Val); + Arg1.End = GetCodePos (); + ParamSize += SizeOf (Arg1Type); + ConsumeComma (); + + /* Argument #2. Since strcpy is a fastcall function, we must load the + * arg into the primary if it is not already there. This parameter is + * also ignored for the calculation of the parameter size, since it is + * not passed via the stack. + */ + ParseArg (&Arg2, Arg2Type); + if (Arg2.Flags & CF_CONST) { + ExprLoad (CF_FORCECHAR, &Arg2.Expr); + } + + /* Emit the actual function call. This will also cleanup the stack. */ + g_call (CF_FIXARGC, Func_strcpy, ParamSize); + + /* Get the element count of argument 2 if it is an array */ + ECount = ArrayElementCount (&Arg1); + + /* We've generated the complete code for the function now and know the + * types of all parameters. Check for situations where better code can + * be generated. If such a situation is detected, throw away the + * generated, and emit better code. + */ + if (((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) || + (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) && + ((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) || + (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr))) && + (IS_Get (&InlineStdFuncs) || + (ECount != UNSPECIFIED && ECount < 256))) { + + const char* Load; + const char* Store; + if (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr)) { + Load = "lda (%s),y"; + } else { + Load = "lda %s,y"; + } + if (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)) { + Store = "sta (%s),y"; + } else { + Store = "sta %s,y"; + } + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need labels */ + L1 = GetLocalLabel (); + + /* Generate strcpy code */ + AddCodeLine ("ldy #$FF"); + g_defcodelabel (L1); + AddCodeLine ("iny"); + AddCodeLine (Load, ED_GetLabelName (&Arg2.Expr, 0)); + AddCodeLine (Store, ED_GetLabelName (&Arg1.Expr, 0)); + AddCodeLine ("bne %s", LocalLabelName (L1)); + + /* strcpy returns argument #1 */ + *Expr = Arg1.Expr; + + } else if (ED_IsRVal (&Arg2.Expr) && ED_IsLocStack (&Arg2.Expr) && + StackPtr >= -255 && + ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) { + + /* It is possible to just use one index register even if the stack + * offset is not zero, by adjusting the offset to the constant + * address accordingly. But we cannot do this if the data in + * question is in the register space or at an absolute address less + * than 256. Register space is zero page, which means that the + * address calculation could overflow in the linker. + */ + int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) && + !(ED_IsLocAbs (&Arg1.Expr) && Arg1.Expr.Val < 256); + + /* Calculate the real stack offset */ + int Offs = ED_GetStackOffs (&Arg2.Expr, 0); + + /* Drop the generated code */ + RemoveCode (Start); + + /* We need labels */ + L1 = GetLocalLabel (); + + /* Generate strcpy code */ + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs - 1)); + if (Offs == 0 || AllowOneIndex) { + g_defcodelabel (L1); + AddCodeLine ("iny"); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,y", ED_GetLabelName (&Arg1.Expr, -Offs)); + } else { + AddCodeLine ("ldx #$FF"); + g_defcodelabel (L1); + AddCodeLine ("iny"); + AddCodeLine ("inx"); + AddCodeLine ("lda (sp),y"); + AddCodeLine ("sta %s,x", ED_GetLabelName (&Arg1.Expr, 0)); + } + AddCodeLine ("bne %s", LocalLabelName (L1)); + + /* strcpy returns argument #1 */ + *Expr = Arg1.Expr; + + } else if (ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr) && + ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) && + StackPtr >= -255) { + + /* It is possible to just use one index register even if the stack + * offset is not zero, by adjusting the offset to the constant + * address accordingly. But we cannot do this if the data in + * question is in the register space or at an absolute address less + * than 256. Register space is zero page, which means that the + * address calculation could overflow in the linker. + */ + int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) && + !(ED_IsLocAbs (&Arg2.Expr) && Arg2.Expr.Val < 256); + + /* Calculate the real stack offset */ + int Offs = ED_GetStackOffs (&Arg1.Expr, 0); + + /* Drop the generated code */ + RemoveCode (Start); - /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); - Expr->Type = GetFuncReturn (Expr->Type); + /* We need labels */ + L1 = GetLocalLabel (); + + /* Generate strcpy code */ + AddCodeLine ("ldy #$%02X", (unsigned char) (Offs - 1)); + if (Offs == 0 || AllowOneIndex) { + g_defcodelabel (L1); + AddCodeLine ("iny"); + AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg2.Expr, -Offs)); + AddCodeLine ("sta (sp),y"); + } else { + AddCodeLine ("ldx #$FF"); + g_defcodelabel (L1); + AddCodeLine ("iny"); + AddCodeLine ("inx"); + AddCodeLine ("lda %s,x", ED_GetLabelName (&Arg2.Expr, 0)); + AddCodeLine ("sta (sp),y"); + } + AddCodeLine ("bne %s", LocalLabelName (L1)); + + /* strcpy returns argument #1 */ + *Expr = Arg1.Expr; + + } else { + + /* The function result is an rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Type = GetFuncReturn (Expr->Type); + + } + + /* We expect the closing brace */ + ConsumeRParen (); } +/*****************************************************************************/ +/* strlen */ +/*****************************************************************************/ + + + static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) /* Handle the strlen function */ { static type ArgType[] = { T_PTR, T_SCHAR, T_END }; ExprDesc Arg; + int IsArray; + int IsPtr; + int IsByteIndex; + long ECount; unsigned L; + /* Setup the argument type string */ ArgType[1] = GetDefaultChar () | T_QUAL_CONST; /* Evaluate the parameter */ hie1 (&Arg); - /* We can generate special code for several locations */ - if (ED_IsLocConst (&Arg) && IsTypeArray (Arg.Type)) { + /* Check if the argument is an array. If so, remember the element count. + * Otherwise set the element count to undefined. + */ + IsArray = IsTypeArray (Arg.Type); + if (IsArray) { + ECount = GetElementCount (Arg.Type); + if (ECount == FLEXIBLE) { + /* Treat as unknown */ + ECount = UNSPECIFIED; + } + IsPtr = 0; + } else { + ECount = UNSPECIFIED; + IsPtr = IsTypePtr (Arg.Type); + } - /* Do type conversion */ - TypeConversion (&Arg, ArgType); + /* Check if the elements of an array can be addressed by a byte sized + * index. This is true if the size of the array is known and less than + * 256. + */ + IsByteIndex = (ECount != UNSPECIFIED && ECount < 256); - /* 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)) { + /* Do type conversion */ + TypeConversion (&Arg, ArgType); - /* Constant string literal */ - ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t); - ResetLiteralPoolOffs (Arg.Val); + /* 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) == 0) { - } else { + /* Constant string literal */ + ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t); + ResetLiteralPoolOffs (Arg.Val); - /* 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"); + /* We will inline strlen for arrays with constant addresses, if either the + * inlining was forced on the command line, or the array is smaller than + * 256, so the inlining is considered safe. + */ + } else if (ED_IsLocConst (&Arg) && IsArray && + (IS_Get (&InlineStdFuncs) || IsByteIndex)) { - /* The function result is an rvalue in the primary register */ - ED_MakeRValExpr (Expr); - Expr->Type = type_size_t; + /* 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 if (ED_IsLocStack (&Arg) && StackPtr >= -255 && IsTypeArray (Arg.Type)) { + /* We will inline strlen for arrays on the stack, if the array is + * completely within the reach of a byte sized index register. + */ + } else if (ED_IsLocStack (&Arg) && IsArray && IsByteIndex && + (Arg.Val - StackPtr) + ECount < 256) { /* Calculate the true stack offset */ - unsigned Offs = (unsigned) (Arg.Val - StackPtr); - - /* Do type conversion */ - TypeConversion (&Arg, ArgType); + int Offs = ED_GetStackOffs (&Arg, 0); /* Generate the strlen code */ L = GetLocalLabel (); @@ -270,10 +989,12 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) 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); + /* strlen for a string that is pointed to by a register variable will only + * get inlined if requested on the command line, since we cannot know how + * big the buffer actually is, so inlining is not always safe. + */ + } else if (ED_IsLocRegister (&Arg) && ED_IsLVal (&Arg) && IsPtr && + IS_Get (&InlineStdFuncs)) { /* Generate the strlen code */ L = GetLocalLabel (); @@ -289,10 +1010,29 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr) ED_MakeRValExpr (Expr); Expr->Type = type_size_t; - } else { + /* Last check: We will inline a generic strlen routine if inlining was + * requested on the command line, and the code size factor is more than + * 400 (code is 13 bytes vs. 3 for a jsr call). + */ + } else if (CodeSizeFactor > 400 && IS_Get (&InlineStdFuncs)) { - /* Do type conversion */ - TypeConversion (&Arg, ArgType); + /* Inline the function */ + L = GetLocalLabel (); + AddCodeLine ("sta ptr1"); + AddCodeLine ("stx ptr1+1"); + AddCodeLine ("ldy #$FF"); + g_defcodelabel (L); + AddCodeLine ("iny"); + AddCodeLine ("lda (ptr1),y"); + 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 { /* Load the expression into the primary */ ExprLoad (CF_NONE, &Arg); diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index cd4c53dc3..ad9892707 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -55,6 +55,7 @@ #include "loop.h" #include "pragma.h" #include "scanner.h" +#include "stackptr.h" #include "swstmt.h" #include "symtab.h" #include "stmt.h" @@ -516,7 +517,7 @@ int Statement (int* PendingToken) * NULL, the function will skip the token. */ { - ExprDesc lval; + ExprDesc Expr; int GotBreak; /* Assume no pending token */ @@ -590,7 +591,13 @@ int Statement (int* PendingToken) default: /* Actual statement */ - Expression0 (&lval); + ExprWithCheck (hie0, &Expr); + /* Load the result only if it is an lvalue and the type is + * marked as volatile. Otherwise the load is useless. + */ + if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) { + ExprLoad (CF_NONE, &Expr); + } CheckSemi (PendingToken); } } diff --git a/src/cc65/swstmt.c b/src/cc65/swstmt.c index 44cc25842..dc508d7f4 100644 --- a/src/cc65/swstmt.c +++ b/src/cc65/swstmt.c @@ -7,8 +7,8 @@ /* */ /* */ /* (C) 1998-2004 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* Römerstraße 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -50,6 +50,7 @@ #include "global.h" #include "loop.h" #include "scanner.h" +#include "stackptr.h" #include "stmt.h" #include "swstmt.h" diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index c3eca39d9..bbe26dff5 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -53,6 +53,7 @@ #include "error.h" #include "funcdesc.h" #include "global.h" +#include "stackptr.h" #include "symentry.h" #include "typecmp.h" #include "symtab.h" @@ -672,7 +673,7 @@ SymEntry* AddLocalSym (const char* Name, const type* Type, unsigned Flags, int O Entry->V.Offs = Offs; } else if ((Flags & SC_REGISTER) == SC_REGISTER) { Entry->V.R.RegOffs = Offs; - Entry->V.R.SaveOffs = StackPtr; /* ### Cleaner! */ + Entry->V.R.SaveOffs = StackPtr; } else if ((Flags & SC_STATIC) == SC_STATIC) { /* Generate the assembler name from the label number */ Entry->V.Label = Offs; -- 2.39.5