1
0
mirror of https://github.com/cc65/cc65.git synced 2025-08-15 06:27:36 +00:00

New option and #pragma --local-strings that causes string literals to be

output immediately.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4504 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz
2009-12-08 20:35:24 +00:00
parent 2bca737f57
commit 7d94dc50a1
8 changed files with 113 additions and 35 deletions

View File

@@ -84,6 +84,7 @@ Long options:
--forget-inc-paths Forget include search paths --forget-inc-paths Forget include search paths
--help Help (this text) --help Help (this text)
--include-dir dir Set an include directory search path --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-space b Set space available for register variables
--register-vars Enable register variables --register-vars Enable register variables
--rodata-name seg Set the name of the RODATA segment --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. 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> <tag><tt>-o name</tt></tag>
Specify the name of the output file. If you don't specify a name, the 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> </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> <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 Switch optimization on or off. If the argument is "off", optimization is

View File

@@ -410,8 +410,8 @@ void FinishCompile (void)
Func = Func->NextSym; Func = Func->NextSym;
} }
/* Dump the literal pool */ /* Output the literal pool */
DumpLiteralPool (); OutputLiteralPool ();
/* Write imported/exported symbols */ /* Write imported/exported symbols */
EmitExternals (); EmitExternals ();

View File

@@ -51,6 +51,7 @@ unsigned RegisterSpace = 6; /* Space available for register vars */
/* Stackable options */ /* Stackable options */
IntStack WritableStrings = INTSTACK(0); /* Literal strings are r/w */ 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 InlineStdFuncs = INTSTACK(0); /* Inline some known functions */
IntStack EnableRegVars = INTSTACK(0); /* Enable register variables */ IntStack EnableRegVars = INTSTACK(0); /* Enable register variables */
IntStack AllowRegVarAddr = INTSTACK(0); /* Allow taking addresses of register vars */ IntStack AllowRegVarAddr = INTSTACK(0); /* Allow taking addresses of register vars */
@@ -62,4 +63,3 @@ IntStack Optimize = INTSTACK(0); /* Optimize flag */
IntStack CodeSizeFactor = INTSTACK(100);/* Size factor for generated code */ IntStack CodeSizeFactor = INTSTACK(100);/* Size factor for generated code */

View File

@@ -58,6 +58,7 @@ extern unsigned RegisterSpace; /* Space available for register
/* Stackable options */ /* Stackable options */
extern IntStack WritableStrings; /* Literal strings are r/w */ extern IntStack WritableStrings; /* Literal strings are r/w */
extern IntStack LocalStrings; /* Emit string literals immediately */
extern IntStack InlineStdFuncs; /* Inline some known functions */ extern IntStack InlineStdFuncs; /* Inline some known functions */
extern IntStack EnableRegVars; /* Enable register variables */ extern IntStack EnableRegVars; /* Enable register variables */
extern IntStack AllowRegVarAddr; /* Allow taking addresses of register vars */ extern IntStack AllowRegVarAddr; /* Allow taking addresses of register vars */

View File

@@ -62,6 +62,7 @@
struct Literal { struct Literal {
unsigned Label; /* Asm label for this literal */ unsigned Label; /* Asm label for this literal */
int RefCount; /* Reference count */ int RefCount; /* Reference count */
int Output; /* True if output has been generated */
StrBuf Data; /* Literal data */ StrBuf Data; /* Literal data */
}; };
@@ -100,6 +101,7 @@ static Literal* NewLiteral (const void* Buf, unsigned Len)
/* Initialize the fields */ /* Initialize the fields */
L->Label = GetLocalLabel (); L->Label = GetLocalLabel ();
L->RefCount = 0; L->RefCount = 0;
L->Output = 0;
SB_Init (&L->Data); SB_Init (&L->Data);
SB_AppendBuf (&L->Data, Buf, Len); 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) Literal* UseLiteral (Literal* L)
/* Increase the reference counter for the literal and return it */ /* Increase the reference counter for the literal and return it */
{ {
/* Increase the reference count */
++L->RefCount; ++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; return L;
} }
@@ -133,7 +168,8 @@ Literal* UseLiteral (Literal* L)
void ReleaseLiteral (Literal* L) void ReleaseLiteral (Literal* L)
/* Decrement the reference counter for the literal */ /* 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 */ /* Get the literal */
Literal* L = CollAt (Source, I); Literal* L = CollAt (Source, I);
/* If it is referenced, add it to the Target pool, otherwise free it */ /* If it is referenced and not output, add it to the Target pool,
if (L->RefCount) { * otherwise free it
*/
if (L->RefCount && !L->Output) {
CollAppend (Target, L); CollAppend (Target, L);
} else { } else {
FreeLiteral (L); FreeLiteral (L);
@@ -302,8 +340,8 @@ void MoveLiteralPool (LiteralPool* LocalPool)
static void DumpWritableLiterals (Collection* Literals) static void OutputWritableLiterals (Collection* Literals)
/* Dump the given writable literals */ /* Output the given writable literals */
{ {
unsigned I; unsigned I;
@@ -318,30 +356,21 @@ static void DumpWritableLiterals (Collection* Literals)
/* Emit all literals that have a reference */ /* Emit all literals that have a reference */
for (I = 0; I < CollCount (Literals); ++I) { for (I = 0; I < CollCount (Literals); ++I) {
/* Get the next literal */ /* Get a pointer to the literal */
Literal* L = CollAt (Literals, I); Literal* L = CollAtUnchecked (Literals, I);
/* Ignore it, if it doesn't have references */ /* Output this one, if it has references and wasn't already output */
if (L->RefCount == 0) { if (L->RefCount > 0 && !L->Output) {
continue; 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) static void OutputReadOnlyLiterals (Collection* Literals)
/* Dump the given readonly literals merging (even partial) duplicates */ /* Output the given readonly literals merging (even partial) duplicates */
{ {
unsigned I; unsigned I;
@@ -365,8 +394,8 @@ static void DumpReadOnlyLiterals (Collection* Literals)
/* Get the next literal */ /* Get the next literal */
Literal* L = CollAt (Literals, I); Literal* L = CollAt (Literals, I);
/* Ignore it, if it doesn't have references */ /* Ignore it, if it doesn't have references or was already output */
if (L->RefCount == 0) { if (L->RefCount == 0 || L->Output) {
continue; continue;
} }
@@ -408,7 +437,6 @@ static void DumpReadOnlyLiterals (Collection* Literals)
/* This literal is part of a longer literal, merge them */ /* This literal is part of a longer literal, merge them */
g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L)); g_aliasdatalabel (L->Label, C->Label, GetLiteralSize (C) - GetLiteralSize (L));
} else { } else {
/* Define the label for the literal */ /* 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)); g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
} }
/* Mark the literal */
L->Output = 1;
} }
} }
void DumpLiteralPool (void) void OutputLiteralPool (void)
/* Dump the global literal pool */ /* Output the global literal pool */
{ {
/* Dump both sorts of literals */ /* Output both sorts of literals */
DumpWritableLiterals (&GlobalPool->WritableLiterals); OutputWritableLiterals (&GlobalPool->WritableLiterals);
DumpReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals); OutputReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
} }

View File

@@ -113,8 +113,8 @@ void MoveLiteralPool (LiteralPool* LocalPool);
* function will free LocalPool after moving the used string literals. * function will free LocalPool after moving the used string literals.
*/ */
void DumpLiteralPool (void); void OutputLiteralPool (void);
/* Dump the literal pool */ /* Output the literal pool */
Literal* AddLiteral (const char* S); Literal* AddLiteral (const char* S);
/* Add a literal string to the literal pool. Return the literal. */ /* Add a literal string to the literal pool. Return the literal. */

View File

@@ -121,7 +121,8 @@ static void Usage (void)
" --help\t\tHelp (this text)\n" " --help\t\tHelp (this text)\n"
" --include-dir dir\tSet an include directory search path\n" " --include-dir dir\tSet an include directory search path\n"
" --list-opt-steps\tList all optimizer steps and exit\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-space b\tSet space available for register variables\n"
" --register-vars\tEnable register variables\n" " --register-vars\tEnable register variables\n"
" --rodata-name seg\tSet the name of the RODATA segment\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) static void OptMemoryModel (const char* Opt, const char* Arg)
/* Set the memory model */ /* Set the memory model */
{ {
@@ -751,6 +761,7 @@ int main (int argc, char* argv[])
{ "--help", 0, OptHelp }, { "--help", 0, OptHelp },
{ "--include-dir", 1, OptIncludeDir }, { "--include-dir", 1, OptIncludeDir },
{ "--list-opt-steps", 0, OptListOptSteps }, { "--list-opt-steps", 0, OptListOptSteps },
{ "--local-strings", 0, OptLocalStrings },
{ "--memory-model", 1, OptMemoryModel }, { "--memory-model", 1, OptMemoryModel },
{ "--register-space", 1, OptRegisterSpace }, { "--register-space", 1, OptRegisterSpace },
{ "--register-vars", 0, OptRegisterVars }, { "--register-vars", 0, OptRegisterVars },

View File

@@ -73,6 +73,7 @@ typedef enum {
PRAGMA_CODESIZE, PRAGMA_CODESIZE,
PRAGMA_DATA_NAME, PRAGMA_DATA_NAME,
PRAGMA_DATASEG, /* obsolete */ PRAGMA_DATASEG, /* obsolete */
PRAGMA_LOCAL_STRINGS,
PRAGMA_OPTIMIZE, PRAGMA_OPTIMIZE,
PRAGMA_REGVARADDR, PRAGMA_REGVARADDR,
PRAGMA_REGISTER_VARS, PRAGMA_REGISTER_VARS,
@@ -104,6 +105,7 @@ static const struct Pragma {
{ "codesize", PRAGMA_CODESIZE }, { "codesize", PRAGMA_CODESIZE },
{ "data-name", PRAGMA_DATA_NAME }, { "data-name", PRAGMA_DATA_NAME },
{ "dataseg", PRAGMA_DATASEG }, /* obsolete */ { "dataseg", PRAGMA_DATASEG }, /* obsolete */
{ "local-strings", PRAGMA_LOCAL_STRINGS },
{ "optimize", PRAGMA_OPTIMIZE }, { "optimize", PRAGMA_OPTIMIZE },
{ "register-vars", PRAGMA_REGISTER_VARS }, { "register-vars", PRAGMA_REGISTER_VARS },
{ "regvaraddr", PRAGMA_REGVARADDR }, { "regvaraddr", PRAGMA_REGVARADDR },
@@ -727,6 +729,10 @@ static void ParsePragma (void)
SegNamePragma (&B, SEG_DATA); SegNamePragma (&B, SEG_DATA);
break; break;
case PRAGMA_LOCAL_STRINGS:
FlagPragma (&B, &LocalStrings);
break;
case PRAGMA_OPTIMIZE: case PRAGMA_OPTIMIZE:
FlagPragma (&B, &Optimize); FlagPragma (&B, &Optimize);
break; break;