mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 19:29:37 +00:00
Allow enabling/disabline optimizer steps by file
git-svn-id: svn://svn.cc65.org/cc65/trunk@831 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
750cf445f7
commit
d341565ddc
@ -1662,67 +1662,78 @@ static unsigned OptPtrLoad2 (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Types of optimization steps */
|
||||||
|
enum {
|
||||||
|
optPre, /* Repeated once */
|
||||||
|
optPreMain, /* Repeated more than once */
|
||||||
|
optMain, /* dito */
|
||||||
|
optPostMain, /* dito */
|
||||||
|
optPost /* Repeated once */
|
||||||
|
};
|
||||||
|
|
||||||
/* Table with all the optimization functions */
|
/* Table with all the optimization functions */
|
||||||
typedef struct OptFunc OptFunc;
|
typedef struct OptFunc OptFunc;
|
||||||
struct OptFunc {
|
struct OptFunc {
|
||||||
unsigned (*Func) (CodeSeg*);/* Optimizer function */
|
unsigned (*Func) (CodeSeg*); /* Optimizer function */
|
||||||
const char* Name; /* Name of optimizer step */
|
const char* Name; /* Name of optimizer step */
|
||||||
char Disabled; /* True if pass disabled */
|
unsigned char Type; /* Type of this step */
|
||||||
|
char Disabled; /* True if pass disabled */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Macro that builds a table entry */
|
||||||
|
#define OptEntry(func,type) { func, #func, type, 0 }
|
||||||
|
|
||||||
|
/* Table with optimizer steps */
|
||||||
/* Table with optimizer steps - are called in this order */
|
|
||||||
static OptFunc OptFuncs [] = {
|
static OptFunc OptFuncs [] = {
|
||||||
/* Optimizes stores through pointers */
|
/* Optimizes stores through pointers */
|
||||||
{ OptPtrStore1, "OptPtrStore1", 0 },
|
OptEntry (OptPtrStore1, optPre),
|
||||||
/* Optimize loads through pointers */
|
/* Optimize loads through pointers */
|
||||||
{ OptPtrLoad1, "OptPtrLoad1", 0 },
|
OptEntry (OptPtrLoad1, optMain),
|
||||||
{ OptPtrLoad2, "OptPtrLoad2", 0 },
|
OptEntry (OptPtrLoad2, optMain),
|
||||||
/* Optimize subtractions */
|
|
||||||
{ OptSub1, "OptSub1", 0 },
|
|
||||||
{ OptSub2, "OptSub2", 0 },
|
|
||||||
/* Optimize additions */
|
|
||||||
{ OptAdd1, "OptAdd1", 0 },
|
|
||||||
/* Optimize jump cascades */
|
|
||||||
{ OptJumpCascades, "OptJumpCascades", 0 },
|
|
||||||
/* Remove dead jumps */
|
|
||||||
{ OptDeadJumps, "OptDeadJumps", 0 },
|
|
||||||
/* Change jsr/rts to jmp */
|
|
||||||
{ OptRTS, "OptRTS", 0 },
|
|
||||||
/* Remove dead code */
|
|
||||||
{ OptDeadCode, "OptDeadCode", 0 },
|
|
||||||
/* Optimize jump targets */
|
|
||||||
{ OptJumpTarget, "OptJumpTarget", 0 },
|
|
||||||
/* Optimize conditional branches */
|
|
||||||
{ OptCondBranches, "OptCondBranches", 0 },
|
|
||||||
/* Replace jumps to RTS by RTS */
|
|
||||||
{ OptRTSJumps, "OptRTSJumps", 0 },
|
|
||||||
/* Remove calls to the bool transformer subroutines */
|
|
||||||
{ OptBoolTransforms, "OptBoolTransforms", 0 },
|
|
||||||
/* Optimize calls to nega */
|
/* Optimize calls to nega */
|
||||||
{ OptNegA1, "OptNegA1", 0 },
|
OptEntry (OptNegA1, optPre),
|
||||||
{ OptNegA2, "OptNegA2", 0 },
|
OptEntry (OptNegA2, optPre),
|
||||||
/* Optimize calls to negax */
|
/* Optimize calls to negax */
|
||||||
{ OptNegAX1, "OptNegAX1", 0 },
|
OptEntry (OptNegAX1, optPre),
|
||||||
{ OptNegAX2, "OptNegAX2", 0 },
|
OptEntry (OptNegAX2, optPre),
|
||||||
{ OptNegAX3, "OptNegAX3", 0 },
|
OptEntry (OptNegAX3, optPre),
|
||||||
{ OptNegAX4, "OptNegAX4", 0 },
|
OptEntry (OptNegAX4, optPre),
|
||||||
|
/* Optimize subtractions */
|
||||||
|
OptEntry (OptSub1, optMain),
|
||||||
|
OptEntry (OptSub2, optMain),
|
||||||
|
/* Optimize additions */
|
||||||
|
OptEntry (OptAdd1, optMain),
|
||||||
|
/* Optimize jump cascades */
|
||||||
|
OptEntry (OptJumpCascades, optMain),
|
||||||
|
/* Remove dead jumps */
|
||||||
|
OptEntry (OptDeadJumps, optMain),
|
||||||
|
/* Change jsr/rts to jmp */
|
||||||
|
OptEntry (OptRTS, optMain),
|
||||||
|
/* Remove dead code */
|
||||||
|
OptEntry (OptDeadCode, optMain),
|
||||||
|
/* Optimize jump targets */
|
||||||
|
OptEntry (OptJumpTarget, optMain),
|
||||||
|
/* Optimize conditional branches */
|
||||||
|
OptEntry (OptCondBranches, optMain),
|
||||||
|
/* Replace jumps to RTS by RTS */
|
||||||
|
OptEntry (OptRTSJumps, optMain),
|
||||||
|
/* Remove calls to the bool transformer subroutines */
|
||||||
|
OptEntry (OptBoolTransforms, optMain),
|
||||||
/* Optimize compares */
|
/* Optimize compares */
|
||||||
{ OptCmp1, "OptCmp1", 0 },
|
OptEntry (OptCmp1, optMain),
|
||||||
{ OptCmp2, "OptCmp2", 0 },
|
OptEntry (OptCmp2, optMain),
|
||||||
{ OptCmp3, "OptCmp3", 0 },
|
OptEntry (OptCmp3, optMain),
|
||||||
{ OptCmp4, "OptCmp4", 0 },
|
OptEntry (OptCmp4, optMain),
|
||||||
{ OptCmp5, "OptCmp5", 0 },
|
OptEntry (OptCmp5, optMain),
|
||||||
{ OptCmp6, "OptCmp6", 0 },
|
OptEntry (OptCmp6, optMain),
|
||||||
/* Optimize tests */
|
/* Optimize tests */
|
||||||
{ OptTest1, "OptTest1", 0 },
|
OptEntry (OptTest1, optMain),
|
||||||
/* Remove unused loads */
|
/* Remove unused loads */
|
||||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
OptEntry (OptUnusedLoads, optMain),
|
||||||
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },
|
OptEntry (OptDuplicateLoads, optMain),
|
||||||
{ OptStoreLoad, "OptStoreLoad", 0 },
|
OptEntry (OptStoreLoad, optMain),
|
||||||
/* Optimize branch distance */
|
/* Optimize branch distance */
|
||||||
{ OptBranchDist, "OptBranchDist", 0 },
|
OptEntry (OptBranchDist, optMain),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1756,7 +1767,7 @@ void DisableOpt (const char* Name)
|
|||||||
unsigned I;
|
unsigned I;
|
||||||
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||||
OptFuncs[I].Disabled = 1;
|
OptFuncs[I].Disabled = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
OptFunc* F = FindOptStep (Name);
|
OptFunc* F = FindOptStep (Name);
|
||||||
F->Disabled = 1;
|
F->Disabled = 1;
|
||||||
@ -1781,13 +1792,66 @@ void EnableOpt (const char* Name)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RunOpt (CodeSeg* S)
|
void ListOptSteps (FILE* F)
|
||||||
/* Run the optimizer */
|
/* List all optimization steps */
|
||||||
|
{
|
||||||
|
unsigned I;
|
||||||
|
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||||
|
fprintf (F, "%s\n", OptFuncs[I].Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void RepeatOptStep (CodeSeg* S, unsigned char Type, unsigned Max)
|
||||||
|
/* Repeat the optimizer step of type Type at may Max times */
|
||||||
{
|
{
|
||||||
unsigned I;
|
unsigned I;
|
||||||
unsigned Pass = 0;
|
unsigned Pass = 0;
|
||||||
unsigned OptChanges;
|
unsigned OptChanges;
|
||||||
|
|
||||||
|
/* Repeat max times of until there are no more changes */
|
||||||
|
do {
|
||||||
|
/* Reset the number of changes */
|
||||||
|
OptChanges = 0;
|
||||||
|
|
||||||
|
/* Keep the user hapy */
|
||||||
|
Print (stdout, 1, " Optimizer pass %u:\n", ++Pass);
|
||||||
|
|
||||||
|
/* Run all optimization steps */
|
||||||
|
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||||
|
|
||||||
|
/* Get the table entry */
|
||||||
|
const OptFunc* F = OptFuncs + I;
|
||||||
|
|
||||||
|
/* Check if the type matches */
|
||||||
|
if (F->Type != Type) {
|
||||||
|
/* Skip it */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the name of the following optimizer step */
|
||||||
|
Print (stdout, 1, " %s:%*s", F->Name, (int) (30-strlen(F->Name)), "");
|
||||||
|
|
||||||
|
/* Check if the step is disabled */
|
||||||
|
if (F->Disabled) {
|
||||||
|
Print (stdout, 1, "Disabled\n");
|
||||||
|
} else {
|
||||||
|
unsigned Changes = F->Func (S);
|
||||||
|
OptChanges += Changes;
|
||||||
|
Print (stdout, 1, "%u Changes\n", Changes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (--Max > 0 && OptChanges > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RunOpt (CodeSeg* S)
|
||||||
|
/* Run the optimizer */
|
||||||
|
{
|
||||||
|
|
||||||
/* If we shouldn't run the optimizer, bail out */
|
/* If we shouldn't run the optimizer, bail out */
|
||||||
if (!Optimize) {
|
if (!Optimize) {
|
||||||
return;
|
return;
|
||||||
@ -1801,31 +1865,11 @@ void RunOpt (CodeSeg* S)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Repeat all steps until there are no more changes */
|
/* Repeat all steps until there are no more changes */
|
||||||
do {
|
RepeatOptStep (S, optPre, 1);
|
||||||
/* Reset the number of changes */
|
RepeatOptStep (S, optPreMain, 0xFFFF);
|
||||||
OptChanges = 0;
|
RepeatOptStep (S, optMain, 0xFFFF);
|
||||||
|
RepeatOptStep (S, optPostMain, 0xFFFF);
|
||||||
/* Keep the user hapy */
|
RepeatOptStep (S, optPost, 1);
|
||||||
Print (stdout, 1, " Optimizer pass %u:\n", ++Pass);
|
|
||||||
|
|
||||||
/* Run all optimization steps */
|
|
||||||
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
|
||||||
|
|
||||||
/* Print the name of the following optimizer step */
|
|
||||||
Print (stdout, 1, " %s:%*s", OptFuncs[I].Name,
|
|
||||||
(int) (30-strlen(OptFuncs[I].Name)), "");
|
|
||||||
|
|
||||||
/* Check if the step is disabled */
|
|
||||||
if (OptFuncs[I].Disabled) {
|
|
||||||
Print (stdout, 1, "Disabled\n");
|
|
||||||
} else {
|
|
||||||
unsigned Changes = OptFuncs[I].Func (S);
|
|
||||||
OptChanges += Changes;
|
|
||||||
Print (stdout, 1, "%u Changes\n", Changes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (OptChanges > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,12 +43,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Data */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -61,6 +55,9 @@ void DisableOpt (const char* Name);
|
|||||||
void EnableOpt (const char* Name);
|
void EnableOpt (const char* Name);
|
||||||
/* Enable the optimization with the given name */
|
/* Enable the optimization with the given name */
|
||||||
|
|
||||||
|
void ListOptSteps (FILE* F);
|
||||||
|
/* List all optimization steps */
|
||||||
|
|
||||||
void RunOpt (CodeSeg* S);
|
void RunOpt (CodeSeg* S);
|
||||||
/* Run the optimizer */
|
/* Run the optimizer */
|
||||||
|
|
||||||
|
@ -104,10 +104,12 @@ static void Usage (void)
|
|||||||
" --data-name seg\tSet the name of the DATA segment\n"
|
" --data-name seg\tSet the name of the DATA segment\n"
|
||||||
" --debug\t\tDebug mode\n"
|
" --debug\t\tDebug mode\n"
|
||||||
" --debug-info\t\tAdd debug info to object file\n"
|
" --debug-info\t\tAdd debug info to object file\n"
|
||||||
|
" --debug-opt name\tDebug optimization steps\n"
|
||||||
" --disable-opt name\tDisable an optimization step\n"
|
" --disable-opt name\tDisable an optimization step\n"
|
||||||
" --enable-opt name\tEnable an optimization step\n"
|
" --enable-opt name\tEnable an optimization step\n"
|
||||||
" --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\n"
|
||||||
" --rodata-name seg\tSet the name of the RODATA segment\n"
|
" --rodata-name seg\tSet the name of the RODATA segment\n"
|
||||||
" --signed-chars\tDefault characters are signed\n"
|
" --signed-chars\tDefault characters are signed\n"
|
||||||
" --static-locals\tMake local variables static\n"
|
" --static-locals\tMake local variables static\n"
|
||||||
@ -380,6 +382,73 @@ static void OptDebugInfo (const char* Opt, const char* Arg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OptDebugOpt (const char* Opt, const char* Arg)
|
||||||
|
/* Debug optimization steps */
|
||||||
|
{
|
||||||
|
char Buf [128];
|
||||||
|
char* Line;
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
FILE* F = fopen (Arg, "r");
|
||||||
|
if (F == 0) {
|
||||||
|
AbEnd ("Cannot open `%s': %s", Arg, strerror (errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read line by line, ignore empty lines and switch optimization
|
||||||
|
* steps on/off.
|
||||||
|
*/
|
||||||
|
while (fgets (Buf, sizeof (Buf), F) != 0) {
|
||||||
|
|
||||||
|
/* Remove trailing control chars. This will also remove the
|
||||||
|
* trailing newline.
|
||||||
|
*/
|
||||||
|
unsigned Len = strlen (Buf);
|
||||||
|
while (Len > 0 && IsControl (Buf[Len-1])) {
|
||||||
|
--Len;
|
||||||
|
}
|
||||||
|
Buf[Len] = '\0';
|
||||||
|
|
||||||
|
/* Get a pointer to the buffer and remove leading white space */
|
||||||
|
Line = Buf;
|
||||||
|
while (IsBlank (*Line)) {
|
||||||
|
++Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the first character and enable/disable the step or
|
||||||
|
* ignore the line
|
||||||
|
*/
|
||||||
|
switch (*Line) {
|
||||||
|
|
||||||
|
case '\0':
|
||||||
|
case '#':
|
||||||
|
case ';':
|
||||||
|
/* Empty or comment line */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
DisableOpt (Line+1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
++Line;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
default:
|
||||||
|
EnableOpt (Line);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the file, no error check here since we were just reading and
|
||||||
|
* this is only a debug function.
|
||||||
|
*/
|
||||||
|
(void) fclose (F);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptDisableOpt (const char* Opt, const char* Arg)
|
static void OptDisableOpt (const char* Opt, const char* Arg)
|
||||||
/* Disable an optimization step */
|
/* Disable an optimization step */
|
||||||
{
|
{
|
||||||
@ -413,6 +482,14 @@ static void OptIncludeDir (const char* Opt, const char* Arg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void OptListOptSteps (const char* Opt, const char* Arg)
|
||||||
|
/* List all optimizer steps */
|
||||||
|
{
|
||||||
|
ListOptSteps (stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void OptRodataName (const char* Opt, const char* Arg)
|
static void OptRodataName (const char* Opt, const char* Arg)
|
||||||
/* Handle the --rodata-name option */
|
/* Handle the --rodata-name option */
|
||||||
{
|
{
|
||||||
@ -482,10 +559,12 @@ int main (int argc, char* argv[])
|
|||||||
{ "--data-name", 1, OptDataName },
|
{ "--data-name", 1, OptDataName },
|
||||||
{ "--debug", 0, OptDebug },
|
{ "--debug", 0, OptDebug },
|
||||||
{ "--debug-info", 0, OptDebugInfo },
|
{ "--debug-info", 0, OptDebugInfo },
|
||||||
|
{ "--debug-opt", 1, OptDebugOpt },
|
||||||
{ "--disable-opt", 1, OptDisableOpt },
|
{ "--disable-opt", 1, OptDisableOpt },
|
||||||
{ "--enable-opt", 1, OptEnableOpt, },
|
{ "--enable-opt", 1, OptEnableOpt, },
|
||||||
{ "--help", 0, OptHelp },
|
{ "--help", 0, OptHelp },
|
||||||
{ "--include-dir", 1, OptIncludeDir },
|
{ "--include-dir", 1, OptIncludeDir },
|
||||||
|
{ "--list-opt-steps", 0, OptListOptSteps },
|
||||||
{ "--rodata-name", 1, OptRodataName },
|
{ "--rodata-name", 1, OptRodataName },
|
||||||
{ "--signed-chars", 0, OptSignedChars },
|
{ "--signed-chars", 0, OptSignedChars },
|
||||||
{ "--static-locals", 0, OptStaticLocals },
|
{ "--static-locals", 0, OptStaticLocals },
|
||||||
|
Loading…
Reference in New Issue
Block a user