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:
@@ -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 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
|
||||||
|
@@ -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 ();
|
||||||
|
@@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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. */
|
||||||
|
@@ -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 },
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user