]> git.sur5r.net Git - cc65/commitdiff
Move the compiler stack pointer into its own module.
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 Jun 2004 11:35:53 +0000 (11:35 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 Jun 2004 11:35:53 +0000 (11:35 +0000)
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

17 files changed:
src/cc65/asmstmt.c
src/cc65/codegen.c
src/cc65/codegen.h
src/cc65/expr.c
src/cc65/expr.h
src/cc65/exprdesc.c
src/cc65/exprdesc.h
src/cc65/function.c
src/cc65/locals.c
src/cc65/make/gcc.mak
src/cc65/make/watcom.mak
src/cc65/stackptr.c [new file with mode: 0644]
src/cc65/stackptr.h [new file with mode: 0644]
src/cc65/stdfunc.c
src/cc65/stmt.c
src/cc65/swstmt.c
src/cc65/symtab.c

index 8c66bcbd77267dce042bc2d7f7c6d4a37d8cdc36..774d5ffa46979b8c501d220b0d196fad8f39bfab 100644 (file)
@@ -46,6 +46,7 @@
 #include "function.h"
 #include "litpool.h"
 #include "scanner.h"
+#include "stackptr.h"
 #include "symtab.h"
 #include "asmstmt.h"
 
index 5b75a764f3baee61859db853cd3438d5c6d54a4f..1854c4b8d38accdfa57bba791eef9d697b6c0ce5 100644 (file)
 #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                                  */
 /*****************************************************************************/
index 58e0217ef1f56b4f4024123155a7f753f9aff5d0..815482fe48cf7ee9a50032bac8eb137fa083f71b 100644 (file)
@@ -85,9 +85,6 @@
 
 
 
-/* Compiler relative stackpointer */
-extern int StackPtr;
-
 /* Forward */
 struct StrBuf;
 
index 23f148e53791a5aff47b6192dbcc0d8a68758fc1..0057e272c4c750212082c1013ba23a4e8697a0f9 100644 (file)
@@ -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 */
index acf442986c576b91379c7be6beae399773a7aab1..c24a4dd2d6b64d8298d6de374051f7172b6eee38 100644 (file)
 
 
 
-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
index 7c498eda8ece670b5b657ff62c76d77a2c3ba6c8..bb257105079beb7cef03a1f96e50c426d0468373 100644 (file)
 
 
 /* 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. */
 {
index 420f86b6cde75dcf78f506cadfa86992c27c125f..99c0edbc9f1b2c18bea9b33c2c4edc2b44202ad6 100644 (file)
@@ -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. */
 
index 505e6804a5a64e7d8eca49fe05a6bfb5cf016e5e..d4409afbab95f4c3554425d5cf42bddd77f2e881 100644 (file)
@@ -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"
index 44662577c70500affc4d1ca6d6834e30e44abaa9..6805424fb8c7297273cd9db955f46c17d864ee13 100644 (file)
@@ -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 {
index 8aaf2005ca9a24bc6ccdd4ccb3f4210d3ff73de3..18219a337a0f8773529af47b1ac825d72716c00e 100644 (file)
@@ -78,6 +78,7 @@ OBJS =        anonname.o      \
        scanner.o       \
         scanstrbuf.o    \
        segments.o      \
+        stackptr.o      \
        stdfunc.o       \
         stdnames.o      \
         stmt.o                 \
index ca3bcb07eefdbc785bd40d62452250b41cfb0323..6d032fe9328a45de19d8c4b6ebd4bcf01e3a8294 100644 (file)
@@ -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 (file)
index 0000000..24b474f
--- /dev/null
@@ -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 (file)
index 0000000..88e1735
--- /dev/null
@@ -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
+
+
+
index 9fa237c6e39ac6153858878bb92e2114c5bb8e38..7ba4e4bbd155114b868d8ae2b0064f43a586fb82 100644 (file)
@@ -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"
 
 
 
+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);
index cd4c53dc30b7b617a1aca84c2e462cbf8ebea85b..ad9892707fbc520ad36d961dff69da47a7e445a5 100644 (file)
@@ -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);
        }
     }
index 44cc258425272b0b4cf74d28ae808ba9e2b9c8f0..dc508d7f44b49d72b881fdd562ad6447031d9959 100644 (file)
@@ -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"
 
index c3eca39d9b0c4bc5b73fb723b0c4755495bb8538..bbe26dff527691dae60b987683898f380b2452a2 100644 (file)
@@ -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;