]> git.sur5r.net Git - cc65/commitdiff
New option and #pragma --local-strings that causes string literals to be
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 8 Dec 2009 20:35:24 +0000 (20:35 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 8 Dec 2009 20:35:24 +0000 (20:35 +0000)
output immediately.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4504 b7a2c559-68d2-44c3-8de9-860c34a00d81

doc/cc65.sgml
src/cc65/compile.c
src/cc65/global.c
src/cc65/global.h
src/cc65/litpool.c
src/cc65/litpool.h
src/cc65/main.c
src/cc65/pragma.c

index 6ae45dcacb5340c12c3fd48a495f8fb1c6d3b11a..fcbe186a2e07f0b475eac8443671f84378092d30 100644 (file)
@@ -84,6 +84,7 @@ Long options:
   --forget-inc-paths    Forget include search paths
   --help                Help (this text)
   --include-dir dir     Set an include directory search path
+  --local-strings       Emit string literals immediately
   --register-space b    Set space available for register variables
   --register-vars       Enable register variables
   --rodata-name seg     Set the name of the RODATA segment
@@ -192,6 +193,20 @@ Here is a description of all the command line options:
   Print the short option summary shown above.
 
 
+  <label id="option-local-strings">
+  <tag><tt>--local-strings</tt></tag>
+
+  Emit string literals to the data segment when they're encountered in the
+  source. The default is to keep string literals until end of assembly, merge
+  read only literals if possible, and then output the literals into the data
+  or rodata segment that is active at that point. Use of this option prevents
+  merging of duplicate strings, but the options that change the name of one of
+  the data segments will work.
+
+  You can also use <tt><ref id="pragma-local-strings"
+  name="#pragma&nbsp;local-strings"></tt> for fine grained control.
+
+
   <tag><tt>-o name</tt></tag>
 
   Specify the name of the output file. If you don't specify a name, the
@@ -868,6 +883,20 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
+<sect1><tt>#pragma local-strings ([push,] on|off)</tt><label id="pragma-local-strings"><p>
+
+  When "on", emit string literals to the data segment when they're encountered
+  in the source. The default ("off") is to keep string literals until end of
+  assembly, merge read only literals if possible, and then output the literals
+  into the data or rodata segment that is active at that point.
+
+  Using this <tt/#pragma/ it is possible to control the behaviour from within
+  the source. When <tt/#pragma local-strings/ is active, string literals are
+  output immediately, which means that they go into the currently active data
+  or rodata segment, but cannot be merged. When inactive, string literals are
+  remembered and output as a whole when translation is finished.
+
+
 <sect1><tt>#pragma optimize ([push,] on|off)</tt><label id="pragma-optimize"><p>
 
   Switch optimization on or off. If the argument is "off", optimization is
index 0fcbfdf42a8e76bf10bc4155b3784c83a5d72742..1a7862cf598d708227e2fe193f4e2c596f032ae6 100644 (file)
@@ -410,8 +410,8 @@ void FinishCompile (void)
         Func = Func->NextSym;
     }
 
-    /* Dump the literal pool */
-    DumpLiteralPool ();
+    /* Output the literal pool */
+    OutputLiteralPool ();
 
     /* Write imported/exported symbols */
     EmitExternals ();
index 28fb2355726a2ce4a095750878a14d4e15ebdf61..c11717b010df389e197ac57c109e239b546d1ce1 100644 (file)
@@ -51,6 +51,7 @@ unsigned      RegisterSpace     = 6;    /* Space available for register vars */
 
 /* Stackable options */
 IntStack WritableStrings    = INTSTACK(0);  /* Literal strings are r/w */
+IntStack LocalStrings       = INTSTACK(0);  /* Emit string literals immediately */
 IntStack InlineStdFuncs     = INTSTACK(0);  /* Inline some known functions */
 IntStack EnableRegVars      = INTSTACK(0);  /* Enable register variables */
 IntStack AllowRegVarAddr    = INTSTACK(0);  /* Allow taking addresses of register vars */
@@ -62,4 +63,3 @@ IntStack Optimize                 = INTSTACK(0);  /* Optimize flag */
 IntStack CodeSizeFactor            = INTSTACK(100);/* Size factor for generated code */
 
 
-
index 6b533be261e9467fe99476a94a2b159116b62120..fb3bce1d2cfbea993c4fe5c04a4c96c426766e2a 100644 (file)
@@ -58,6 +58,7 @@ extern unsigned         RegisterSpace;          /* Space available for register
 
 /* Stackable options */
 extern IntStack         WritableStrings;       /* Literal strings are r/w */
+extern IntStack         LocalStrings;           /* Emit string literals immediately */
 extern IntStack         InlineStdFuncs;                /* Inline some known functions */
 extern IntStack         EnableRegVars;         /* Enable register variables */
 extern IntStack         AllowRegVarAddr;       /* Allow taking addresses of register vars */
index 6f345662193417c1e96184de3b60f8e9654a435f..3d3aee745f3cfb458d755c3ede9b3a8b92020eda 100644 (file)
@@ -62,6 +62,7 @@
 struct Literal {
     unsigned    Label;                  /* Asm label for this literal */
     int         RefCount;               /* Reference count */
+    int         Output;                 /* True if output has been generated */
     StrBuf      Data;                   /* Literal data */
 };
 
@@ -100,6 +101,7 @@ static Literal* NewLiteral (const void* Buf, unsigned Len)
     /* Initialize the fields */
     L->Label    = GetLocalLabel ();
     L->RefCount = 0;
+    L->Output   = 0;
     SB_Init (&L->Data);
     SB_AppendBuf (&L->Data, Buf, Len);
 
@@ -121,10 +123,43 @@ static void FreeLiteral (Literal* L)
 
 
 
+static void OutputLiteral (Literal* L)
+/* Output one literal to the currently active data segment */
+{
+    /* Translate the literal into the target charset */
+    TranslateLiteral (L);
+
+    /* Define the label for the literal */
+    g_defdatalabel (L->Label);
+
+    /* Output the literal data */
+    g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
+
+    /* Mark the literal as output */
+    L->Output = 1;
+}
+
+
+
 Literal* UseLiteral (Literal* L)
 /* Increase the reference counter for the literal and return it */
 {
+    /* Increase the reference count */
     ++L->RefCount;
+
+    /* If --local-strings was given, immediately output the literal */
+    if (IS_Get (&LocalStrings)) {
+        /* Switch to the proper data segment */
+        if (IS_Get (&WritableStrings)) {
+            g_usedata ();
+        } else {
+            g_userodata ();
+        }
+        /* Output the literal */
+        OutputLiteral (L);
+    }
+
+    /* Return the literal */
     return L;
 }
 
@@ -133,7 +168,8 @@ Literal* UseLiteral (Literal* L)
 void ReleaseLiteral (Literal* L)
 /* Decrement the reference counter for the literal */
 {
-    CHECK (--L->RefCount >= 0);
+    --L->RefCount;
+    CHECK (L->RefCount >= 0 && (L->RefCount > 0 || !L->Output));
 }
 
 
@@ -276,8 +312,10 @@ static void MoveLiterals (Collection* Source, Collection* Target)
         /* Get the literal */
         Literal* L = CollAt (Source, I);
 
-        /* If it is referenced, add it to the Target pool, otherwise free it */
-        if (L->RefCount) {
+        /* If it is referenced and not output, add it to the Target pool,
+         * otherwise free it
+         */
+        if (L->RefCount && !L->Output) {
             CollAppend (Target, L);
         } else {
             FreeLiteral (L);
@@ -302,8 +340,8 @@ void MoveLiteralPool (LiteralPool* LocalPool)
 
 
 
-static void DumpWritableLiterals (Collection* Literals)
-/* Dump the given writable literals */
+static void OutputWritableLiterals (Collection* Literals)
+/* Output the given writable literals */
 {
     unsigned I;
 
@@ -318,30 +356,21 @@ static void DumpWritableLiterals (Collection* Literals)
     /* Emit all literals that have a reference */
     for (I = 0; I < CollCount (Literals); ++I) {
 
-        /* Get the next literal */
-        Literal* L = CollAt (Literals, I);
+        /* Get a pointer to the literal */
+        Literal* L = CollAtUnchecked (Literals, I);
 
-        /* Ignore it, if it doesn't have references */
-        if (L->RefCount == 0) {
-            continue;
+        /* Output this one, if it has references and wasn't already output */
+        if (L->RefCount > 0 && !L->Output) {
+            OutputLiteral (L);
         }
 
-        /* Translate the literal into the target charset */
-        TranslateLiteral (L);
-
-        /* Define the label for the literal */
-        g_defdatalabel (L->Label);
-
-        /* Output the literal data */
-        g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
-
     }
 }
 
 
 
-static void DumpReadOnlyLiterals (Collection* Literals)
-/* Dump the given readonly literals merging (even partial) duplicates */
+static void OutputReadOnlyLiterals (Collection* Literals)
+/* Output the given readonly literals merging (even partial) duplicates */
 {
     unsigned I;
 
@@ -365,8 +394,8 @@ static void DumpReadOnlyLiterals (Collection* Literals)
         /* Get the next literal */
         Literal* L = CollAt (Literals, I);
 
-        /* Ignore it, if it doesn't have references */
-        if (L->RefCount == 0) {
+        /* Ignore it, if it doesn't have references or was already output */
+        if (L->RefCount == 0 || L->Output) {
             continue;
         }
 
@@ -408,7 +437,6 @@ static void DumpReadOnlyLiterals (Collection* Literals)
             /* This literal is part of a longer literal, merge them */
             g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L));
 
-
         } else {
 
             /* Define the label for the literal */
@@ -418,17 +446,20 @@ static void DumpReadOnlyLiterals (Collection* Literals)
             g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
 
         }
+
+        /* Mark the literal */
+        L->Output = 1;
     }
 }
 
 
 
-void DumpLiteralPool (void)
-/* Dump the global literal pool */
+void OutputLiteralPool (void)
+/* Output the global literal pool */
 {
-    /* Dump both sorts of literals */
-    DumpWritableLiterals (&GlobalPool->WritableLiterals);
-    DumpReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
+    /* Output both sorts of literals */
+    OutputWritableLiterals (&GlobalPool->WritableLiterals);
+    OutputReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
 }
 
 
index f89ffda8b625a4e1682ffd0947c149dc7ff3adda..a71c5841447ffe4aa2ce0f1a842e264967ce434d 100644 (file)
@@ -113,8 +113,8 @@ void MoveLiteralPool (LiteralPool* LocalPool);
  * function will free LocalPool after moving the used string literals.
  */
 
-void DumpLiteralPool (void);
-/* Dump the literal pool */
+void OutputLiteralPool (void);
+/* Output the literal pool */
 
 Literal* AddLiteral (const char* S);
 /* Add a literal string to the literal pool. Return the literal. */
index a0f570d215a5a01907fee569541747845bd093c8..ed3c987ab5309417a0bd0a750129406839825654 100644 (file)
@@ -121,7 +121,8 @@ static void Usage (void)
             "  --help\t\tHelp (this text)\n"
             "  --include-dir dir\tSet an include directory search path\n"
             "  --list-opt-steps\tList all optimizer steps and exit\n"
-            "  --memory-model model\tSet the memory model\n"
+            "  --local-strings\tEmit string literals immediately\n"
+            "  --memory-model model\tSet the memory model\n"       
             "  --register-space b\tSet space available for register variables\n"
             "  --register-vars\tEnable register variables\n"
             "  --rodata-name seg\tSet the name of the RODATA segment\n"
@@ -556,6 +557,15 @@ static void OptListOptSteps (const char* Opt attribute ((unused)),
 
 
 
+static void OptLocalStrings (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
+/* Emit string literals immediately */
+{
+    IS_Set (&LocalStrings, 1);
+}
+
+
+
 static void OptMemoryModel (const char* Opt, const char* Arg)
 /* Set the memory model */
 {
@@ -751,6 +761,7 @@ int main (int argc, char* argv[])
        { "--help",             0,      OptHelp                 },
        { "--include-dir",      1,      OptIncludeDir           },
        { "--list-opt-steps",   0,      OptListOptSteps         },
+        { "--local-strings",    0,      OptLocalStrings         },
         { "--memory-model",     1,      OptMemoryModel          },
         { "--register-space",   1,      OptRegisterSpace        },
         { "--register-vars",    0,      OptRegisterVars         },
index 9ca49313771548f1745660d02577e2f4c6d857e0..608ef7e6d03db81ab588ea64c6453f8c07faa9b4 100644 (file)
@@ -73,6 +73,7 @@ typedef enum {
     PRAGMA_CODESIZE,
     PRAGMA_DATA_NAME,
     PRAGMA_DATASEG,                                     /* obsolete */
+    PRAGMA_LOCAL_STRINGS,
     PRAGMA_OPTIMIZE,
     PRAGMA_REGVARADDR,
     PRAGMA_REGISTER_VARS,
@@ -104,6 +105,7 @@ static const struct Pragma {
     { "codesize",               PRAGMA_CODESIZE         },
     { "data-name",              PRAGMA_DATA_NAME        },
     { "dataseg",                PRAGMA_DATASEG         },      /* obsolete */
+    { "local-strings",          PRAGMA_LOCAL_STRINGS    },
     { "optimize",               PRAGMA_OPTIMIZE         },
     { "register-vars",          PRAGMA_REGISTER_VARS    },
     { "regvaraddr",             PRAGMA_REGVARADDR      },
@@ -727,6 +729,10 @@ static void ParsePragma (void)
            SegNamePragma (&B, SEG_DATA);
            break;
 
+        case PRAGMA_LOCAL_STRINGS:
+            FlagPragma (&B, &LocalStrings);
+            break;
+
         case PRAGMA_OPTIMIZE:
             FlagPragma (&B, &Optimize);
             break;