--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
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
</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
Func = Func->NextSym;
}
- /* Dump the literal pool */
- DumpLiteralPool ();
+ /* Output the literal pool */
+ OutputLiteralPool ();
/* Write imported/exported symbols */
EmitExternals ();
/* 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 */
IntStack CodeSizeFactor = INTSTACK(100);/* Size factor for generated code */
-
/* 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 */
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 */
};
/* Initialize the fields */
L->Label = GetLocalLabel ();
L->RefCount = 0;
+ L->Output = 0;
SB_Init (&L->Data);
SB_AppendBuf (&L->Data, Buf, Len);
+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;
}
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));
}
/* 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);
-static void DumpWritableLiterals (Collection* Literals)
-/* Dump the given writable literals */
+static void OutputWritableLiterals (Collection* Literals)
+/* Output the given writable literals */
{
unsigned I;
/* 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;
/* 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;
}
/* 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 */
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);
}
* 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. */
" --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"
+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 */
{
{ "--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 },
PRAGMA_CODESIZE,
PRAGMA_DATA_NAME,
PRAGMA_DATASEG, /* obsolete */
+ PRAGMA_LOCAL_STRINGS,
PRAGMA_OPTIMIZE,
PRAGMA_REGVARADDR,
PRAGMA_REGISTER_VARS,
{ "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 },
SegNamePragma (&B, SEG_DATA);
break;
+ case PRAGMA_LOCAL_STRINGS:
+ FlagPragma (&B, &LocalStrings);
+ break;
+
case PRAGMA_OPTIMIZE:
FlagPragma (&B, &Optimize);
break;