mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +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:
parent
2bca737f57
commit
7d94dc50a1
@ -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 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
|
||||
|
@ -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 ();
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user