1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 07:29:33 +00:00

Rewrote literal handling. Literals are now saved together with other function

data, and at the end of compilation merged if possible. Literals for unused
functions are removed together with the function.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4501 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-12-05 22:39:45 +00:00
parent 9b7c16ec4c
commit 3976746735
19 changed files with 490 additions and 250 deletions

View File

@ -244,7 +244,7 @@ Here is a description of all the command line options:
better way is to declare characters explicitly as "signed" if needed. You
can also use <tt><ref id="pragma-signed-chars"
name="#pragma&nbsp;signed-chars"></tt> for better control of this option.
<label id="option--standard">
<tag><tt>--standard std</tt></tag>
@ -301,8 +301,8 @@ Here is a description of all the command line options:
Make string literals writable by placing them into the data segment instead
of the rodata segment. You can also use <tt><ref id="pragma-writable-strings"
name="#pragma&nbsp;writable-strings"></tt> to control this option on a
per function basis.
name="#pragma&nbsp;writable-strings"></tt> to control this option from within
the source file.
<label id="option-static-locals">
@ -979,9 +979,9 @@ parameter with the <tt/#pragma/.
<sect1><tt>#pragma writable-strings ([push,] on|off)</tt><label id="pragma-writable-strings"><p>
Changes the storage location of string literals. For historical reasons,
the C standard defines that string literals are of type "char[]", but
writing to such a literal causes undefined behaviour. Most compilers
Changes the storage location of string literals. For historical reasons,
the C standard defines that string literals are of type "char[]", but
writing to such a literal causes undefined behaviour. Most compilers
(including cc65) place string literals in the read-only data segment, which
may cause problems with old C code that writes to string literals.
@ -990,10 +990,6 @@ parameter with the <tt/#pragma/.
literals to be placed in the data segment so they can be written to without
worry.
Please note that the value of this flag that is in effect when a function
is encountered, determines where the literals are stored. Changing the
<tt/#pragma/ within a function doesn't have an effect for this function.
The <tt/#pragma/ understands the push and pop parameters as explained above.

View File

@ -38,7 +38,6 @@
/* cc65 */
#include "asmcode.h"
#include "codeopt.h"
#include "codeseg.h"
#include "dataseg.h"
#include "segments.h"
@ -124,12 +123,8 @@ void WriteAsmOutput (void)
SymTab = GetGlobalSymTab ();
Entry = SymTab->SymHead;
while (Entry) {
if (IsTypeFunc (Entry->Type) &&
SymIsDef (Entry) &&
(Entry->Flags & (SC_REF | SC_EXTERN)) != 0) {
/* Function which is defined and referenced or extern */
CS_MergeLabels (Entry->V.F.Seg->Code);
RunOpt (Entry->V.F.Seg->Code);
if (SymIsOutputFunc (Entry)) {
/* Function which is defined and referenced or extern */
OutputSegments (Entry->V.F.Seg);
}
Entry = Entry->NextSym;

View File

@ -321,8 +321,7 @@ static void ParseStrArg (StrBuf* T, unsigned Arg attribute ((unused)))
case TOK_SCONST:
/* String constant */
SB_AppendStr (T, GetLiteral (CurTok.IVal));
ResetLiteralPoolOffs (CurTok.IVal);
SB_Append (T, GetLiteralStrBuf (CurTok.SVal));
NextToken ();
break;
@ -347,14 +346,7 @@ static void ParseAsm (void)
/* Create a string buffer from the string literal */
StrBuf S = AUTO_STRBUF_INITIALIZER;
GetLiteralStrBuf (&S, CurTok.IVal);
/* Reset the string pointer, effectivly clearing the string from the
* string table. Since we're working with one token lookahead, this
* will fail if the next token is also a string token, but that's a
* syntax error anyway, because we expect a right paren.
*/
ResetLiteralPoolOffs (CurTok.IVal);
SB_Append (&S, GetLiteralStrBuf (CurTok.SVal));
/* Skip the string token */
NextToken ();

View File

@ -41,9 +41,9 @@
#include "check.h"
#include "cpu.h"
#include "strbuf.h"
#include "version.h"
#include "xmalloc.h"
#include "xsprintf.h"
#include "version.h"
/* cc65 */
#include "asmcode.h"
@ -346,6 +346,24 @@ void g_defdatalabel (unsigned label)
void g_aliasdatalabel (unsigned label, unsigned baselabel, long offs)
/* Define label as a local alias for baselabel+offs */
{
/* We need an intermediate buffer here since LocalLabelName uses a
* static buffer which changes with each call.
*/
StrBuf L = AUTO_STRBUF_INITIALIZER;
SB_AppendStr (&L, LocalLabelName (label));
SB_Terminate (&L);
AddDataLine ("%s\t:=\t%s+%ld",
SB_GetConstBuf (&L),
LocalLabelName (baselabel),
offs);
SB_Done (&L);
}
/*****************************************************************************/
/* Functions handling global labels */
/*****************************************************************************/

View File

@ -136,6 +136,9 @@ void g_defcodelabel (unsigned label);
void g_defdatalabel (unsigned label);
/* Define a local data label */
void g_aliasdatalabel (unsigned label, unsigned baselabel, long offs);
/* Define label as a local alias for baselabel+offs */
/*****************************************************************************/

View File

@ -46,6 +46,7 @@
#include "asmlabel.h"
#include "asmstmt.h"
#include "codegen.h"
#include "codeopt.h"
#include "compile.h"
#include "declare.h"
#include "error.h"
@ -373,30 +374,16 @@ void Compile (const char* FileName)
/* Close the output file */
CloseOutputFile ();
if (Debug) {
PrintMacroStats (stdout);
}
} else {
/* Ok, start the ball rolling... */
Parse ();
/* Dump the literal pool. */
DumpLiteralPool ();
/* Write imported/exported symbols */
EmitExternals ();
if (Debug) {
PrintLiteralPoolStats (stdout);
PrintMacroStats (stdout);
}
}
/* Leave the main lexical level */
LeaveGlobalLevel ();
if (Debug) {
PrintMacroStats (stdout);
}
/* Print an error report */
ErrorReport ();
@ -404,4 +391,34 @@ void Compile (const char* FileName)
void FinishCompile (void)
/* Emit literals, externals, do cleanup and optimizations */
{
SymTable* SymTab;
SymEntry* Func;
/* Walk over all functions, doing cleanup, optimizations ... */
SymTab = GetGlobalSymTab ();
Func = SymTab->SymHead;
while (Func) {
if (SymIsOutputFunc (Func)) {
/* Function which is defined and referenced or extern */
MoveLiteralPool (Func->V.F.LitPool);
CS_MergeLabels (Func->V.F.Seg->Code);
RunOpt (Func->V.F.Seg->Code);
}
Func = Func->NextSym;
}
/* Dump the literal pool */
DumpLiteralPool ();
/* Write imported/exported symbols */
EmitExternals ();
/* Leave the main lexical level */
LeaveGlobalLevel ();
}

View File

@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (C) 2000-2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/* (C) 2000-2009, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@ -47,6 +47,9 @@
void Compile (const char* FileName);
/* Top level compile routine. Will setup things and call the parser. */
void FinishCompile (void);
/* Emit literals, externals, do cleanup and optimizations */
/* End of compile.h */

View File

@ -1769,7 +1769,6 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
/* Char array initialized by string constant */
int NeedParen;
const char* Str;
/* If we initializer is enclosed in brackets, remember this fact and
* skip the opening bracket.
@ -1779,16 +1778,13 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
NextToken ();
}
/* Get the initializer string and its size */
Str = GetLiteral (CurTok.IVal);
Count = GetLiteralPoolOffs () - CurTok.IVal;
/* Translate into target charset */
TranslateLiteralPool (CurTok.IVal);
TranslateLiteral (CurTok.SVal);
/* If the array is one too small for the string literal, omit the
* trailing zero.
*/
Count = GetLiteralSize (CurTok.SVal);
if (ElementCount != UNSPECIFIED &&
ElementCount != FLEXIBLE &&
Count == ElementCount + 1) {
@ -1797,10 +1793,9 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
}
/* Output the data */
g_defbytes (Str, Count);
g_defbytes (GetLiteralStr (CurTok.SVal), Count);
/* Remove string from pool */
ResetLiteralPoolOffs (CurTok.IVal);
/* Skip the string */
NextToken ();
/* If the initializer was enclosed in curly braces, we need a closing

View File

@ -578,6 +578,7 @@ static void Primary (ExprDesc* E)
/* This is the lowest level of the expression parser. */
{
SymEntry* Sym;
Literal* L;
/* Initialize fields in the expression stucture */
ED_Init (E);
@ -748,10 +749,11 @@ static void Primary (ExprDesc* E)
case TOK_SCONST:
case TOK_WCSCONST:
/* String literal */
E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal);
L = UseLiteral (CurTok.SVal);
E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal));
E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
E->IVal = CurTok.IVal;
E->Name = GetLiteralPoolLabel ();
E->IVal = 0;
E->Name = GetLiteralLabel (CurTok.SVal);
NextToken ();
break;

View File

@ -359,7 +359,7 @@ static void F_RestoreRegVars (Function* F)
}
/*****************************************************************************/
/* code */
/*****************************************************************************/
@ -542,9 +542,8 @@ void NewFunc (SymEntry* Func)
/* Eat the closing brace */
ConsumeRCurly ();
/* Dump the literal pool, the restore the old one */
DumpLiteralPool ();
PopLiteralPool ();
/* Restore the old literal pool, remembering the one for the function */
Func->V.F.LitPool = PopLiteralPool ();
/* Switch back to the old segments */
PopSegments ();

View File

@ -1,6 +1,6 @@
/*****************************************************************************/
/* */
/* litpool.c */
/* litpool.c */
/* */
/* Literal string handling for the cc65 C compiler */
/* */
@ -34,8 +34,10 @@
#include <stdio.h>
#include <string.h>
/* common */
#include "attrib.h"
#include "check.h"
#include "coll.h"
#include "tgttrans.h"
@ -56,20 +58,23 @@
/* Forward for struct SymEntry */
struct SymEntry;
/* Definition of the literal pool */
typedef struct LiteralPool LiteralPool;
struct LiteralPool {
int Writable; /* True if strings are writable */
unsigned Label; /* Pool asm label */
struct SymEntry* Func; /* Function that contains the pool */
StrBuf Pool; /* The pool itself */
/* Definition of a literal */
struct Literal {
unsigned Label; /* Asm label for this literal */
int RefCount; /* Reference count */
StrBuf Data; /* Literal data */
};
/* The current literal pool */
static LiteralPool* LP = 0;
/* Definition of the literal pool */
struct LiteralPool {
struct SymEntry* Func; /* Function that owns the pool */
Collection WritableLiterals; /* Writable literals in the pool */
Collection ReadOnlyLiterals; /* Readonly literals in the pool */
};
/* The global and current literal pool */
static LiteralPool* GlobalPool = 0;
static LiteralPool* LP = 0;
/* Stack that contains the nested literal pools. Since TOS is in LiteralPool
* and functions aren't nested in C, the maximum depth is 1. I'm using a
@ -80,6 +85,99 @@ static Collection LPStack = STATIC_COLLECTION_INITIALIZER;
/*****************************************************************************/
/* struct Literal */
/*****************************************************************************/
static Literal* NewLiteral (const void* Buf, unsigned Len)
/* Create a new literal and return it */
{
/* Allocate memory */
Literal* L = xmalloc (sizeof (*L));
/* Initialize the fields */
L->Label = GetLocalLabel ();
L->RefCount = 0;
SB_Init (&L->Data);
SB_AppendBuf (&L->Data, Buf, Len);
/* Return the new literal */
return L;
}
static void FreeLiteral (Literal* L)
/* Free a literal */
{
/* Free the literal data */
SB_Done (&L->Data);
/* Free the structure itself */
xfree (L);
}
Literal* UseLiteral (Literal* L)
/* Increase the reference counter for the literal and return it */
{
++L->RefCount;
return L;
}
void ReleaseLiteral (Literal* L)
/* Decrement the reference counter for the literal */
{
CHECK (--L->RefCount >= 0);
}
void TranslateLiteral (Literal* L)
/* Translate a literal into the target charset. */
{
TgtTranslateBuf (SB_GetBuf (&L->Data), SB_GetLen (&L->Data));
}
unsigned GetLiteralLabel (const Literal* L)
/* Return the asm label for a literal */
{
return L->Label;
}
const char* GetLiteralStr (const Literal* L)
/* Return the data for a literal as pointer to char */
{
return SB_GetConstBuf (&L->Data);
}
const StrBuf* GetLiteralStrBuf (const Literal* L)
/* Return the data for a literal as pointer to the string buffer */
{
return &L->Data;
}
unsigned GetLiteralSize (const Literal* L)
/* Get the size of a literal string */
{
return SB_GetLen (&L->Data);
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@ -93,10 +191,9 @@ static LiteralPool* NewLiteralPool (struct SymEntry* Func)
LiteralPool* LP = xmalloc (sizeof (*LP));
/* Initialize the fields */
LP->Writable = IS_Get (&WritableStrings);
LP->Label = GetLocalLabel ();
LP->Func = Func;
SB_Init (&LP->Pool);
InitCollection (&LP->WritableLiterals);
InitCollection (&LP->ReadOnlyLiterals);
/* Return the new pool */
return LP;
@ -107,8 +204,9 @@ static LiteralPool* NewLiteralPool (struct SymEntry* Func)
static void FreeLiteralPool (LiteralPool* LP)
/* Free a LiteralPool structure */
{
/* Free the string buffer contained within the struct */
SB_Done (&LP->Pool);
/* Free the collections contained within the struct */
DoneCollection (&LP->WritableLiterals);
DoneCollection (&LP->ReadOnlyLiterals);
/* Free the struct itself */
xfree (LP);
@ -116,11 +214,21 @@ static void FreeLiteralPool (LiteralPool* LP)
static int Compare (void* Data attribute ((unused)),
const void* Left, const void* Right)
/* Compare function used when sorting the literal pool */
{
/* Larger strings are considered "smaller" */
return (int) GetLiteralSize (Right) - (int) GetLiteralSize (Left);
}
void InitLiteralPool (void)
/* Initialize the literal pool */
{
/* Create a new pool */
LP = NewLiteralPool (0);
/* Create the global literal pool */
GlobalPool = LP = NewLiteralPool (0);
}
@ -140,144 +248,225 @@ void PushLiteralPool (struct SymEntry* Func)
void PopLiteralPool (void)
/* Free the current literal pool and restore the one from TOS */
LiteralPool* PopLiteralPool (void)
/* Pop the last literal pool from TOS and activate it. Return the old
* literal pool.
*/
{
/* Free the current literal pool */
FreeLiteralPool (LP);
/* Remember the current literal pool */
LiteralPool* Old = LP;
/* Pop one from stack */
LP = CollPop (&LPStack);
/* Return the old one */
return Old;
}
void TranslateLiteralPool (unsigned Offs)
/* Translate the literals starting from the given offset into the target
* charset.
static void MoveLiterals (Collection* Source, Collection* Target)
/* Move referenced literals from Source to Target, delete unreferenced ones */
{
unsigned I;
/* Move referenced literals, remove unreferenced ones */
for (I = 0; I < CollCount (Source); ++I) {
/* Get the literal */
Literal* L = CollAt (Source, I);
/* If it is referenced, add it to the Target pool, otherwise free it */
if (L->RefCount) {
CollAppend (Target, L);
} else {
FreeLiteral (L);
}
}
}
void MoveLiteralPool (LiteralPool* LocalPool)
/* Move all referenced literals in LocalPool to the global literal pool. This
* function will free LocalPool after moving the used string literals.
*/
{
TgtTranslateBuf (SB_GetBuf (&LP->Pool) + Offs, SB_GetLen (&LP->Pool) - Offs);
/* Move the literals */
MoveLiterals (&LocalPool->WritableLiterals, &GlobalPool->WritableLiterals);
MoveLiterals (&LocalPool->ReadOnlyLiterals, &GlobalPool->ReadOnlyLiterals);
/* Free the local literal pool */
FreeLiteralPool (LocalPool);
}
static void DumpWritableLiterals (Collection* Literals)
/* Dump the given writable literals */
{
unsigned I;
/* If nothing there, exit... */
if (CollCount (Literals) == 0) {
return;
}
/* Switch to the correct segment */
g_usedata ();
/* Emit all literals that have a reference */
for (I = 0; I < CollCount (Literals); ++I) {
/* Get the next literal */
Literal* L = CollAt (Literals, I);
/* Ignore it, if it doesn't have references */
if (L->RefCount == 0) {
continue;
}
/* 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 */
{
unsigned I;
/* If nothing there, exit... */
if (CollCount (Literals) == 0) {
return;
}
/* Switch to the correct segment */
g_userodata ();
/* Sort the literal pool by literal size. Larger strings go first */
CollSort (Literals, Compare, 0);
/* Emit all literals that have a reference */
for (I = 0; I < CollCount (Literals); ++I) {
unsigned J;
Literal* C;
/* Get the next literal */
Literal* L = CollAt (Literals, I);
/* Ignore it, if it doesn't have references */
if (L->RefCount == 0) {
continue;
}
/* Translate the literal into the target charset */
TranslateLiteral (L);
/* Check if this literal is part of another one. Since the literals
* are sorted by size (larger ones first), it can only be part of a
* literal with a smaller index.
* Beware: Only check literals that have actually been referenced.
*/
C = 0;
for (J = 0; J < I; ++J) {
const void* D;
/* Get a pointer to the compare literal */
Literal* L2 = CollAt (Literals, J);
/* Ignore literals that have no reference */
if (L2->RefCount == 0) {
continue;
}
/* Get a pointer to the data */
D = SB_GetConstBuf (&L2->Data) + SB_GetLen (&L2->Data) - SB_GetLen (&L->Data);
/* Compare the data */
if (memcmp (D, SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data)) == 0) {
/* Remember the literal and terminate the loop */
C = L2;
break;
}
}
/* Check if we found a match */
if (C != 0) {
/* 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_defdatalabel (L->Label);
/* Output the literal data */
g_defbytes (SB_GetConstBuf (&L->Data), SB_GetLen (&L->Data));
}
}
}
void DumpLiteralPool (void)
/* Dump the literal pool */
/* Dump the global literal pool */
{
/* If nothing there, exit... */
if (SB_GetLen (&LP->Pool) == 0) {
return;
}
/* Switch to the correct segment */
if (LP->Writable) {
g_usedata ();
} else {
g_userodata ();
}
/* Define the label */
g_defdatalabel (LP->Label);
/* Translate the buffer contents into the target charset */
TranslateLiteralPool (0);
/* Output the buffer data */
g_defbytes (SB_GetConstBuf (&LP->Pool), SB_GetLen (&LP->Pool));
/* Dump both sorts of literals */
DumpWritableLiterals (&GlobalPool->WritableLiterals);
DumpReadOnlyLiterals (&GlobalPool->ReadOnlyLiterals);
}
unsigned GetLiteralPoolLabel (void)
/* Return the asm label for the current literal pool */
{
return LP->Label;
}
unsigned GetLiteralPoolOffs (void)
/* Return the current offset into the literal pool */
{
return SB_GetLen (&LP->Pool);
}
void ResetLiteralPoolOffs (unsigned Offs)
/* Reset the offset into the literal pool to some earlier value, effectively
* removing values from the pool.
*/
{
CHECK (Offs <= SB_GetLen (&LP->Pool));
SB_Cut (&LP->Pool, Offs);
}
unsigned AddLiteral (const char* S)
/* Add a literal string to the literal pool. Return the starting offset into
* the pool
*/
Literal* AddLiteral (const char* S)
/* Add a literal string to the literal pool. Return the literal. */
{
return AddLiteralBuf (S, strlen (S) + 1);
}
unsigned AddLiteralBuf (const void* Buf, unsigned Len)
Literal* AddLiteralBuf (const void* Buf, unsigned Len)
/* Add a buffer containing a literal string to the literal pool. Return the
* starting offset into the pool for this string.
* literal.
*/
{
/* Remember the starting offset */
unsigned Start = SB_GetLen (&LP->Pool);
/* Create a new literal */
Literal* L = NewLiteral (Buf, Len);
/* Append the buffer */
SB_AppendBuf (&LP->Pool, Buf, Len);
/* Add the literal to the correct pool */
if (IS_Get (&WritableStrings)) {
CollAppend (&LP->WritableLiterals, L);
} else {
CollAppend (&LP->ReadOnlyLiterals, L);
}
/* Return the starting offset */
return Start;
/* Return the new literal */
return L;
}
unsigned AddLiteralStr (const StrBuf* S)
/* Add a literal string to the literal pool. Return the starting offset into
* the pool for this string.
*/
Literal* AddLiteralStr (const StrBuf* S)
/* Add a literal string to the literal pool. Return the literal. */
{
return AddLiteralBuf (SB_GetConstBuf (S), SB_GetLen (S));
}
const char* GetLiteral (unsigned Offs)
/* Get a pointer to the literal with the given offset in the pool */
{
CHECK (Offs < SB_GetLen (&LP->Pool));
return SB_GetConstBuf (&LP->Pool) + Offs;
}
void GetLiteralStrBuf (StrBuf* Target, unsigned Offs)
/* Copy the string starting at Offs and lasting to the end of the buffer
* into Target.
*/
{
CHECK (Offs <= SB_GetLen (&LP->Pool));
SB_Slice (Target, &LP->Pool, Offs, SB_GetLen (&LP->Pool) - Offs);
}
void PrintLiteralPoolStats (FILE* F)
/* Print statistics about the literal space used */
{
fprintf (F, "Literal space used: %u bytes\n", SB_GetLen (&LP->Pool));
}

View File

@ -54,10 +54,45 @@
/* Forward for struct SymEntry */
struct SymEntry;
/* Forward for a literal */
typedef struct Literal Literal;
/* Forward for a literal pool */
typedef struct LiteralPool LiteralPool;
/*****************************************************************************/
/* Code */
/* struct Literal */
/*****************************************************************************/
Literal* UseLiteral (Literal* L);
/* Increase the reference counter for the literal and return it */
void ReleaseLiteral (Literal* L);
/* Decrement the reference counter for the literal */
void TranslateLiteral (Literal* L);
/* Translate a literal into the target charset. */
unsigned GetLiteralLabel (const Literal* L);
/* Return the asm label for a literal */
const char* GetLiteralStr (const Literal* L);
/* Return the data for a literal as pointer to char */
const StrBuf* GetLiteralStrBuf (const Literal* L);
/* Return the data for a literal as pointer to the string buffer */
unsigned GetLiteralSize (const Literal* L);
/* Get the size of a literal string */
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@ -68,53 +103,29 @@ void InitLiteralPool (void);
void PushLiteralPool (struct SymEntry* Func);
/* Push the current literal pool onto the stack and create a new one */
void PopLiteralPool (void);
/* Free the current literal pool and restore the one from TOS */
LiteralPool* PopLiteralPool (void);
/* Pop the last literal pool from TOS and activate it. Return the old
* literal pool.
*/
void TranslateLiteralPool (unsigned Offs);
/* Translate the literals starting from the given offset into the target
* charset.
void MoveLiteralPool (LiteralPool* LocalPool);
/* Move all referenced literals in LocalPool to the global literal pool. This
* function will free LocalPool after moving the used string literals.
*/
void DumpLiteralPool (void);
/* Dump the literal pool */
unsigned GetLiteralPoolLabel (void);
/* Return the asm label for the current literal pool */
Literal* AddLiteral (const char* S);
/* Add a literal string to the literal pool. Return the literal. */
unsigned GetLiteralPoolOffs (void);
/* Return the current offset into the literal pool */
void ResetLiteralPoolOffs (unsigned Offs);
/* Reset the offset into the literal pool to some earlier value, effectively
* removing values from the pool.
*/
unsigned AddLiteral (const char* S);
/* Add a literal string to the literal pool. Return the starting offset into
* the pool for this string.
*/
unsigned AddLiteralBuf (const void* Buf, unsigned Len);
Literal* AddLiteralBuf (const void* Buf, unsigned Len);
/* Add a buffer containing a literal string to the literal pool. Return the
* starting offset into the pool for this string.
* literal.
*/
unsigned AddLiteralStr (const StrBuf* S);
/* Add a literal string to the literal pool. Return the starting offset into
* the pool for this string.
*/
const char* GetLiteral (unsigned Offs);
/* Get a pointer to the literal with the given offset in the pool */
void GetLiteralStrBuf (StrBuf* Target, unsigned Offs);
/* Copy the string starting at Offs and lasting to the end of the buffer
* into Target.
*/
void PrintLiteralPoolStats (FILE* F);
/* Print statistics about the literal space used */
Literal* AddLiteralStr (const StrBuf* S);
/* Add a literal string to the literal pool. Return the literal. */

View File

@ -938,10 +938,13 @@ int main (int argc, char* argv[])
/* Create the output file if we didn't had any errors */
if (PreprocessOnly == 0 && (ErrorCount == 0 || Debug)) {
/* Open the file */
/* Emit literals, externals, do cleanup and optimizations */
FinishCompile ();
/* Open the file */
OpenOutputFile ();
/* Write the output to the file */
/* Write the output to the file */
WriteAsmOutput ();
Print (stdout, 1, "Wrote output to `%s'\n", OutputFilename);

View File

@ -652,14 +652,7 @@ static void ParsePragma (void)
/* Create a string buffer from the string literal */
StrBuf B = AUTO_STRBUF_INITIALIZER;
GetLiteralStrBuf (&B, CurTok.IVal);
/* Reset the string pointer, effectivly clearing the string from the
* string table. Since we're working with one token lookahead, this
* will fail if the next token is also a string token, but that's a
* syntax error anyway, because we expect a right paren.
*/
ResetLiteralPoolOffs (CurTok.IVal);
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
/* Skip the string token */
NextToken ();

View File

@ -454,7 +454,7 @@ static void StringConst (void)
SB_AppendChar (&S, '\0');
/* Add the whole string to the literal pool */
NextTok.IVal = AddLiteralStr (&S);
NextTok.SVal = AddLiteralStr (&S);
/* Free the buffer */
SB_Done (&S);
@ -760,7 +760,7 @@ void NextToken (void)
if (token[0] == '_' && token[1] == '_') {
/* Special symbols */
if (strcmp (token+2, "FILE__") == 0) {
NextTok.IVal = AddLiteral (GetCurrentFile());
NextTok.SVal = AddLiteral (GetCurrentFile());
NextTok.Tok = TOK_SCONST;
return;
} else if (strcmp (token+2, "LINE__") == 0) {
@ -771,7 +771,7 @@ void NextToken (void)
} else if (strcmp (token+2, "func__") == 0) {
/* __func__ is only defined in functions */
if (CurrentFunc) {
NextTok.IVal = AddLiteral (F_GetFuncName (CurrentFunc));
NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
NextTok.Tok = TOK_SCONST;
return;
}

View File

@ -186,20 +186,24 @@ typedef enum token_t {
/*****************************************************************************/
/* data */
/* Data */
/*****************************************************************************/
/* Token stuff */
/* Forward for struct Literal */
struct Literal;
/* Token stuff */
typedef struct Token Token;
struct Token {
token_t Tok; /* The token itself */
long IVal; /* The integer attribute */
Double FVal; /* The float attribute */
ident Ident; /* Identifier if IDENT */
LineInfo* LI; /* Source line where the token comes from */
Type* Type; /* Type if integer or float constant */
token_t Tok; /* The token itself */
long IVal; /* The integer attribute */
Double FVal; /* The float attribute */
struct Literal* SVal; /* String literal is any */
ident Ident; /* Identifier if IDENT */
LineInfo* LI; /* Source line where the token comes from */
Type* Type; /* Type if integer or float constant */
};
extern Token CurTok; /* The current token */
@ -208,7 +212,7 @@ extern Token NextTok; /* The next token */
/*****************************************************************************/
/* code */
/* Code */
/*****************************************************************************/

View File

@ -933,7 +933,8 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
/* Do type conversion */
TypeConversion (&Arg, ArgType);
#if 0
/* If the expression is a literal, and if string literals are read
* only, we can calculate the length of the string and remove it
* from the literal pool. Otherwise we have to calculate the length
@ -942,14 +943,15 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings) == 0) {
/* Constant string literal */
ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.IVal)), type_size_t);
ResetLiteralPoolOffs (Arg.IVal);
ED_MakeConstAbs (Expr, GetLiteralSize (GetLiteral (Arg.IVal)), type_size_t);
/* We will inline strlen for arrays with constant addresses, if either the
* inlining was forced on the command line, or the array is smaller than
* 256, so the inlining is considered safe.
*/
} else if (ED_IsLocConst (&Arg) && IsArray &&
} else
#endif
if (ED_IsLocConst (&Arg) && IsArray &&
(IS_Get (&InlineStdFuncs) || IsByteIndex)) {
/* Generate the strlen code */

View File

@ -153,6 +153,19 @@ void DumpSymEntry (FILE* F, const SymEntry* E)
int SymIsOutputFunc (const SymEntry* Sym)
/* Return true if this is a function that must be output */
{
/* Symbol must be a function which is defined and either extern or
* static and referenced.
*/
return IsTypeFunc (Sym->Type) &&
SymIsDef (Sym) &&
(Sym->Flags & (SC_REF | SC_EXTERN));
}
const DeclAttr* SymGetAttr (const SymEntry* Sym, DeclAttrType AttrType)
/* Return an attribute for this symbol or NULL if the attribute does not exist */
{

View File

@ -57,6 +57,7 @@
struct Segments;
struct LiteralPool;
@ -147,6 +148,7 @@ struct SymEntry {
struct {
struct FuncDesc* Func; /* Function descriptor */
struct Segments* Seg; /* Segments for this function */
struct LiteralPool* LitPool; /* Literal pool for this function */
} F;
} V;
@ -221,6 +223,9 @@ INLINE int SymIsRegVar (const SymEntry* Sym)
# define SymIsRegVar(Sym) (((Sym)->Flags & (SC_REGISTER|SC_TYPE)) == SC_REGISTER)
#endif
int SymIsOutputFunc (const SymEntry* Sym);
/* Return true if this is a function that must be output */
#if defined(HAVE_INLINE)
INLINE const char* SymGetAsmName (const SymEntry* Sym)
/* Return the assembler label name for the symbol (beware: may be NULL!) */
@ -238,7 +243,7 @@ const DeclAttr* SymGetAttr (const SymEntry* Sym, DeclAttrType AttrType);
INLINE int SymHasAttr (const SymEntry* Sym, DeclAttrType A)
/* Return true if the symbol has the given attribute */
{
return (SymGetAttr (Sym, A) != 0);
return (SymGetAttr (Sym, A) != 0);
}
#else
# define SymHasAttr(Sym, A) (SymGetAttr (Sym, A) != 0)