1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 19:29:37 +00:00

Moved some of the currently existing into a separate module.

git-svn-id: svn://svn.cc65.org/cc65/trunk@723 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-05-14 17:35:53 +00:00
parent a1da98103a
commit c9cb564b9b
5 changed files with 631 additions and 445 deletions

View File

@ -3466,6 +3466,14 @@ void g_lt (unsigned flags, unsigned long val)
break;
case CF_LONG:
if ((flags & CF_UNSIGNED) == 0 && val == 0) {
/* If we have a signed compare against zero, we only need to
* test the high byte.
*/
AddCodeLine ("lda sreg+1");
AddCodeLine ("jsr boollt");
return;
}
break;
default:
@ -3475,7 +3483,7 @@ void g_lt (unsigned flags, unsigned long val)
/* If we go here, we didn't emit code. Push the lhs on stack and fall
* into the normal, non-optimized stuff.
*/
g_push (flags & ~CF_CONST, 0);
g_push (flags & ~CF_CONST, 0);
}
@ -3589,27 +3597,27 @@ void g_gt (unsigned flags, unsigned long val)
if (flags & CF_UNSIGNED) {
/* If we have a compare > 0, we will replace it by
* != 0 here, since both are identical but the latter
* is easier to optimize.
*/
if ((val & 0xFFFF) == 0) {
AddCodeLine ("stx tmp1");
AddCodeLine ("ora tmp1");
AddCodeLine ("jsr boolne");
} else {
* is easier to optimize.
*/
if ((val & 0xFFFF) == 0) {
AddCodeLine ("stx tmp1");
AddCodeLine ("ora tmp1");
AddCodeLine ("jsr boolne");
} else {
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
AddCodeLine ("bne *+4");
AddCodeLine ("cmp #$%02X", (unsigned char)val);
AddCodeLine ("bne *+4");
AddCodeLine ("cmp #$%02X", (unsigned char)val);
AddCodeLine ("jsr boolugt");
}
return;
}
return;
}
break;
break;
case CF_LONG:
break;
break;
default:
typeerror (flags);
typeerror (flags);
}
/* If we go here, we didn't emit code. Push the lhs on stack and fall
@ -3662,20 +3670,37 @@ void g_ge (unsigned flags, unsigned long val)
/* FALLTHROUGH */
case CF_INT:
if ((flags & CF_UNSIGNED) == 0 && val == 0) {
/* If we have a signed compare against zero, we only need to
* test the high byte.
*/
AddCodeLine ("txa");
AddCodeLine ("jsr boolge");
return;
}
/* Direct code only for unsigned data types */
if (flags & CF_UNSIGNED) {
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
AddCodeLine ("bne *+4");
AddCodeLine ("cmp #$%02X", (unsigned char)val);
AddCodeLine ("jsr booluge");
return;
}
}
break;
case CF_LONG:
break;
if ((flags & CF_UNSIGNED) == 0 && val == 0) {
/* If we have a signed compare against zero, we only need to
* test the high byte.
*/
AddCodeLine ("lda sreg+1");
AddCodeLine ("jsr boolge");
return;
}
break;
default:
typeerror (flags);
typeerror (flags);
}
/* If we go here, we didn't emit code. Push the lhs on stack and fall

View File

@ -43,6 +43,7 @@
#include "asmlabel.h"
#include "codeent.h"
#include "codeinfo.h"
#include "coptind.h"
#include "error.h"
#include "global.h"
#include "codeopt.h"
@ -55,11 +56,6 @@
/* Counter for the number of changes in one run. The optimizer process is
* repeated until there are no more changes.
*/
static unsigned OptChanges;
/* Defines for the conditions in a compare */
typedef enum {
CMP_INV = -1,
@ -119,434 +115,24 @@ static cmp_t FindCmpCond (const char* Suffix)
/*****************************************************************************/
/* Remove dead jumps */
/*****************************************************************************/
static void OptDeadJumps (CodeSeg* S)
/* Remove dead jumps (jumps to the next instruction) */
{
CodeEntry* E;
unsigned I;
/* Get the number of entries, bail out if we have less than two entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get the next entry */
E = GetCodeEntry (S, I);
/* Check if it's a branch, if it has a local target, and if the target
* is the next instruction.
*/
if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
/* Delete the dead jump */
DelCodeEntry (S, I);
/* Keep the number of entries updated */
--Count;
/* Remember, we had changes */
++OptChanges;
} else {
/* Next entry */
++I;
}
}
}
/*****************************************************************************/
/* Remove dead code */
/*****************************************************************************/
static void OptDeadCode (CodeSeg* S)
/* Remove dead code (code that follows an unconditional jump or an rts/rti
* and has no label)
*/
{
unsigned I;
/* Get the number of entries, bail out if we have less than two entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's an unconditional branch, and if the next entry has
* no labels attached
*/
if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
/* Delete the next entry */
DelCodeEntry (S, I+1);
/* Keep the number of entries updated */
--Count;
/* Remember, we had changes */
++OptChanges;
} else {
/* Next entry */
++I;
}
}
}
/*****************************************************************************/
/* Optimize jump cascades */
/*****************************************************************************/
static void OptJumpCascades (CodeSeg* S)
/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
* replaced by a jump to the final location. This will in some cases produce
* worse code, because some jump targets are no longer reachable by short
* branches, but this is quite rare, so there are more advantages than
* disadvantages.
*/
{
unsigned I;
/* Get the number of entries, bail out if we have no entries */
unsigned Count = GetCodeEntryCount (S);
if (Count == 0) {
return;
}
/* Walk over all entries */
I = 0;
while (I < Count) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a branch, if it has a jump label, and if this jump
* label is not attached to the instruction itself.
*/
if ((E->Info & OF_BRA) != 0 && E->JumpTo != 0 && E->JumpTo->Owner != E) {
/* Get the label this insn is branching to */
CodeLabel* OldLabel = E->JumpTo;
/* Get the entry we're branching to */
CodeEntry* N = OldLabel->Owner;
/* If the entry we're branching to is not itself a branch, it is
* not what we're searching for.
*/
if ((N->Info & OF_BRA) == 0) {
goto NextEntry;
}
/* Check if we can use the final target label. This is the case,
* if the target branch is an absolut branch, or if it is a
* conditional branch checking the same condition as the first one.
*/
if ((N->Info & OF_UBRA) != 0 ||
((E->Info & OF_CBRA) != 0 &&
GetBranchCond (E->OPC) == GetBranchCond (N->OPC))) {
/* This is a jump cascade and we may jump to the final target.
* If we have a label, move the reference to this label. If
* we don't have a label, use the argument instead.
*/
if (N->JumpTo) {
/* Move the reference to the new insn */
MoveCodeLabelRef (S, E, N->JumpTo);
} else {
/* Remove the reference to the old label */
RemoveCodeLabelRef (S, E);
}
/* Use the new argument */
CodeEntrySetArg (E, N->Arg);
/* Use the usage information from the new instruction */
E->Use = N->Use;
E->Chg = N->Chg;
/* Remember, we had changes */
++OptChanges;
/* Done */
continue;
}
/* Check if both are conditional branches, and the condition of
* the second is the inverse of that of the first. In this case,
* the second branch will never be taken, and we may jump directly
* to the instruction behind this one.
*/
goto NextEntry;
}
NextEntry:
/* Next entry */
++I;
}
}
/*****************************************************************************/
/* Optimize jsr/rts */
/*****************************************************************************/
static void OptRTS (CodeSeg* S)
/* Optimize subroutine calls followed by an RTS. The subroutine call will get
* replaced by a jump. Don't bother to delete the RTS if it does not have a
* label, the dead code elimination should take care of it.
*/
{
unsigned I;
/* Get the number of entries, bail out if we have less than 2 entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a subroutine call and if the following insn is RTS */
if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
/* Change the jsr to a jmp and use the additional info for a jump */
E->OPC = OPC_JMP;
E->AM = AM_BRA;
E->Info = GetOPCInfo (OPC_JMP);
/* Remember, we had changes */
++OptChanges;
}
/* Next entry */
++I;
}
}
/*****************************************************************************/
/* Optimize jump targets */
/*****************************************************************************/
static void OptJumpTarget (CodeSeg* S)
/* If the instruction preceeding an unconditional branch is the same as the
* instruction preceeding the jump target, the jump target may be moved
* one entry back. This is a size optimization, since the instruction before
* the branch gets removed.
*/
{
CodeEntry* E1; /* Entry 1 */
CodeEntry* E2; /* Entry 2 */
CodeEntry* T1; /* Jump target entry 1 */
CodeEntry* T2; /* Jump target entry 2 */
CodeLabel* TL1; /* Target label 1 */
unsigned TI; /* Target index */
unsigned I;
/* Get the number of entries, bail out if we have not enough */
unsigned Count = GetCodeEntryCount (S);
if (Count < 3) {
return;
}
/* Walk over the entries */
I = 0;
while (I < Count-1) {
/* Get next entry */
E2 = GetCodeEntry (S, I+1);
/* Check if we have a jump or branch, and a matching label */
if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
/* Get the target instruction for the label */
T2 = E2->JumpTo->Owner;
/* Get the entry preceeding this one (if possible) */
TI = GetCodeEntryIndex (S, T2);
if (TI == 0) {
/* There is no entry before this one */
goto NextEntry;
}
T1 = GetCodeEntry (S, TI-1);
/* Get the entry preceeding the jump */
E1 = GetCodeEntry (S, I);
/* Check if both preceeding instructions are identical */
if (!CodeEntriesAreEqual (E1, T1)) {
/* Not equal, try next */
goto NextEntry;
}
/* Get the label for the instruction preceeding the jump target.
* This routine will create a new label if the instruction does
* not already have one.
*/
TL1 = GenCodeLabel (S, T1);
/* Change the jump target to point to this new label */
MoveCodeLabelRef (S, E2, TL1);
/* If the instruction preceeding the jump has labels attached,
* move references to this label to the new label.
*/
if (CodeEntryHasLabel (E1)) {
MoveCodeLabels (S, E1, T1);
}
/* Remove the entry preceeding the jump */
DelCodeEntry (S, I);
--Count;
/* Remember, we had changes */
++OptChanges;
}
NextEntry:
/* Next entry */
++I;
}
}
/*****************************************************************************/
/* Remove conditional jumps never taken */
/*****************************************************************************/
static void OptDeadCondBranches (CodeSeg* S)
/* If an immidiate load of a register is followed by a conditional jump that
* is never taken because the load of the register sets the flags in such a
* manner, remove the conditional branch.
*/
{
unsigned I;
/* Get the number of entries, bail out if we have not enough */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return;
}
/* Walk over the entries */
I = 0;
while (I < Count-1) {
/* Get next entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a register load */
if ((E->Info & OF_LOAD) != 0 && E->AM == AM_IMM && (E->Flags & CEF_NUMARG) != 0) {
bc_t BC;
/* Immidiate register load, get next instruction */
CodeEntry* N = GetCodeEntry (S, I+1);
/* Check if the following insn is a conditional branch or if it
* has a label attached.
*/
if ((N->Info & OF_CBRA) == 0 || CodeEntryHasLabel (E)) {
/* No conditional jump or label attached, bail out */
goto NextEntry;
}
/* Get the branch condition */
BC = GetBranchCond (N->OPC);
/* Check the argument against the branch condition */
if ((BC == BC_EQ && E->Num != 0) ||
(BC == BC_NE && E->Num == 0) ||
(BC == BC_PL && (E->Num & 0x80) != 0) ||
(BC == BC_MI && (E->Num & 0x80) == 0)) {
/* Remove the conditional branch */
DelCodeEntry (S, I+1);
--Count;
/* Remember, we had changes */
++OptChanges;
}
}
NextEntry:
/* Next entry */
++I;
}
}
/*****************************************************************************/
/* Remove calls to the bool transformer subroutines */
/*****************************************************************************/
static void OptBoolTransforms (CodeSeg* S)
static unsigned OptBoolTransforms (CodeSeg* S)
/* Try to remove the call to boolean transformer routines where the call is
* not really needed.
*/
{
unsigned Changes = 0;
unsigned I;
/* Get the number of entries, bail out if we have not enough */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return;
return 0;
}
/* Walk over the entries */
@ -640,7 +226,7 @@ static void OptBoolTransforms (CodeSeg* S)
--Count;
/* Remember, we had changes */
++OptChanges;
++Changes;
}
@ -649,6 +235,9 @@ NextEntry:
++I;
}
/* Return the number of changes made */
return Changes;
}
@ -662,7 +251,7 @@ NextEntry:
/* Table with all the optimization functions */
typedef struct OptFunc OptFunc;
struct OptFunc {
void (*Func) (CodeSeg*); /* Optimizer function */
unsigned (*Func) (CodeSeg*);/* Optimizer function */
const char* Name; /* Name of optimizer step */
char Disabled; /* True if pass disabled */
};
@ -691,7 +280,7 @@ static OptFunc OptFuncs [] = {
static OptFunc* FindOptStep (const char* Name)
/* Find an optimizer step by name in the table and return a pointer. Print an
* error and cann AbEnd if not found.
* error and call AbEnd if not found.
*/
{
unsigned I;
@ -732,7 +321,9 @@ void EnableOpt (const char* Name)
void RunOpt (CodeSeg* S)
/* Run the optimizer */
{
unsigned I;
unsigned Pass = 0;
unsigned OptChanges;
/* Print the name of the function we are working on */
if (S->Func) {
@ -743,9 +334,6 @@ void RunOpt (CodeSeg* S)
/* Repeat all steps until there are no more changes */
do {
unsigned I;
/* Reset the number of changes */
OptChanges = 0;
@ -763,9 +351,8 @@ void RunOpt (CodeSeg* S)
if (OptFuncs[I].Disabled) {
Print (stdout, 1, "Disabled\n");
} else {
unsigned Changes = OptChanges;
OptFuncs[I].Func (S);
Changes = OptChanges - Changes;
unsigned Changes = OptFuncs[I].Func (S);
OptChanges += Changes;
Print (stdout, 1, "%u Changes\n", Changes);
}
}

481
src/cc65/coptind.c Normal file
View File

@ -0,0 +1,481 @@
/*****************************************************************************/
/* */
/* coptind.c */
/* */
/* Environment independent low level optimizations */
/* */
/* */
/* */
/* (C) 2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
/* cc65 */
#include "codeent.h"
#include "codeinfo.h"
#include "codeopt.h"
#include "error.h"
#include "coptind.h"
/*****************************************************************************/
/* Remove dead jumps */
/*****************************************************************************/
unsigned OptDeadJumps (CodeSeg* S)
/* Remove dead jumps (jumps to the next instruction) */
{
unsigned Changes = 0;
CodeEntry* E;
unsigned I;
/* Get the number of entries, bail out if we have less than two entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return 0;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get the next entry */
E = GetCodeEntry (S, I);
/* Check if it's a branch, if it has a local target, and if the target
* is the next instruction.
*/
if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
/* Delete the dead jump */
DelCodeEntry (S, I);
/* Keep the number of entries updated */
--Count;
/* Remember, we had changes */
++Changes;
} else {
/* Next entry */
++I;
}
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/
/* Remove dead code */
/*****************************************************************************/
unsigned OptDeadCode (CodeSeg* S)
/* Remove dead code (code that follows an unconditional jump or an rts/rti
* and has no label)
*/
{
unsigned Changes = 0;
unsigned I;
/* Get the number of entries, bail out if we have less than two entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return 0;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's an unconditional branch, and if the next entry has
* no labels attached
*/
if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
/* Delete the next entry */
DelCodeEntry (S, I+1);
/* Keep the number of entries updated */
--Count;
/* Remember, we had changes */
++Changes;
} else {
/* Next entry */
++I;
}
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/
/* Optimize jump cascades */
/*****************************************************************************/
unsigned OptJumpCascades (CodeSeg* S)
/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
* replaced by a jump to the final location. This will in some cases produce
* worse code, because some jump targets are no longer reachable by short
* branches, but this is quite rare, so there are more advantages than
* disadvantages.
*/
{
unsigned Changes = 0;
unsigned I;
/* Get the number of entries, bail out if we have no entries */
unsigned Count = GetCodeEntryCount (S);
if (Count == 0) {
return 0;
}
/* Walk over all entries */
I = 0;
while (I < Count) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a branch, if it has a jump label, and if this jump
* label is not attached to the instruction itself.
*/
if ((E->Info & OF_BRA) != 0 && E->JumpTo != 0 && E->JumpTo->Owner != E) {
/* Get the label this insn is branching to */
CodeLabel* OldLabel = E->JumpTo;
/* Get the entry we're branching to */
CodeEntry* N = OldLabel->Owner;
/* If the entry we're branching to is not itself a branch, it is
* not what we're searching for.
*/
if ((N->Info & OF_BRA) == 0) {
goto NextEntry;
}
/* Check if we can use the final target label. This is the case,
* if the target branch is an absolut branch, or if it is a
* conditional branch checking the same condition as the first one.
*/
if ((N->Info & OF_UBRA) != 0 ||
((E->Info & OF_CBRA) != 0 &&
GetBranchCond (E->OPC) == GetBranchCond (N->OPC))) {
/* This is a jump cascade and we may jump to the final target.
* If we have a label, move the reference to this label. If
* we don't have a label, use the argument instead.
*/
if (N->JumpTo) {
/* Move the reference to the new insn */
MoveCodeLabelRef (S, E, N->JumpTo);
} else {
/* Remove the reference to the old label */
RemoveCodeLabelRef (S, E);
}
/* Use the new argument */
CodeEntrySetArg (E, N->Arg);
/* Use the usage information from the new instruction */
E->Use = N->Use;
E->Chg = N->Chg;
/* Remember, we had changes */
++Changes;
/* Done */
continue;
}
/* Check if both are conditional branches, and the condition of
* the second is the inverse of that of the first. In this case,
* the second branch will never be taken, and we may jump directly
* to the instruction behind this one.
*/
goto NextEntry;
}
NextEntry:
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/
/* Optimize jsr/rts */
/*****************************************************************************/
unsigned OptRTS (CodeSeg* S)
/* Optimize subroutine calls followed by an RTS. The subroutine call will get
* replaced by a jump. Don't bother to delete the RTS if it does not have a
* label, the dead code elimination should take care of it.
*/
{
unsigned Changes = 0;
unsigned I;
/* Get the number of entries, bail out if we have less than 2 entries */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return 0;
}
/* Walk over all entries minus the last one */
I = 0;
while (I < Count-1) {
/* Get this entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a subroutine call and if the following insn is RTS */
if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
/* Change the jsr to a jmp and use the additional info for a jump */
E->OPC = OPC_JMP;
E->AM = AM_BRA;
E->Info = GetOPCInfo (OPC_JMP);
/* Remember, we had changes */
++Changes;
}
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/
/* Optimize jump targets */
/*****************************************************************************/
unsigned OptJumpTarget (CodeSeg* S)
/* If the instruction preceeding an unconditional branch is the same as the
* instruction preceeding the jump target, the jump target may be moved
* one entry back. This is a size optimization, since the instruction before
* the branch gets removed.
*/
{
unsigned Changes = 0;
CodeEntry* E1; /* Entry 1 */
CodeEntry* E2; /* Entry 2 */
CodeEntry* T1; /* Jump target entry 1 */
CodeEntry* T2; /* Jump target entry 2 */
CodeLabel* TL1; /* Target label 1 */
unsigned TI; /* Target index */
unsigned I;
/* Get the number of entries, bail out if we have not enough */
unsigned Count = GetCodeEntryCount (S);
if (Count < 3) {
return 0;
}
/* Walk over the entries */
I = 0;
while (I < Count-1) {
/* Get next entry */
E2 = GetCodeEntry (S, I+1);
/* Check if we have a jump or branch, and a matching label */
if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
/* Get the target instruction for the label */
T2 = E2->JumpTo->Owner;
/* Get the entry preceeding this one (if possible) */
TI = GetCodeEntryIndex (S, T2);
if (TI == 0) {
/* There is no entry before this one */
goto NextEntry;
}
T1 = GetCodeEntry (S, TI-1);
/* Get the entry preceeding the jump */
E1 = GetCodeEntry (S, I);
/* Check if both preceeding instructions are identical */
if (!CodeEntriesAreEqual (E1, T1)) {
/* Not equal, try next */
goto NextEntry;
}
/* Get the label for the instruction preceeding the jump target.
* This routine will create a new label if the instruction does
* not already have one.
*/
TL1 = GenCodeLabel (S, T1);
/* Change the jump target to point to this new label */
MoveCodeLabelRef (S, E2, TL1);
/* If the instruction preceeding the jump has labels attached,
* move references to this label to the new label.
*/
if (CodeEntryHasLabel (E1)) {
MoveCodeLabels (S, E1, T1);
}
/* Remove the entry preceeding the jump */
DelCodeEntry (S, I);
--Count;
/* Remember, we had changes */
++Changes;
}
NextEntry:
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
/*****************************************************************************/
/* Remove conditional jumps never taken */
/*****************************************************************************/
unsigned OptDeadCondBranches (CodeSeg* S)
/* If an immidiate load of a register is followed by a conditional jump that
* is never taken because the load of the register sets the flags in such a
* manner, remove the conditional branch.
*/
{
unsigned Changes = 0;
unsigned I;
/* Get the number of entries, bail out if we have not enough */
unsigned Count = GetCodeEntryCount (S);
if (Count < 2) {
return 0;
}
/* Walk over the entries */
I = 0;
while (I < Count-1) {
/* Get next entry */
CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's a register load */
if ((E->Info & OF_LOAD) != 0 && E->AM == AM_IMM && (E->Flags & CEF_NUMARG) != 0) {
bc_t BC;
/* Immidiate register load, get next instruction */
CodeEntry* N = GetCodeEntry (S, I+1);
/* Check if the following insn is a conditional branch or if it
* has a label attached.
*/
if ((N->Info & OF_CBRA) == 0 || CodeEntryHasLabel (E)) {
/* No conditional jump or label attached, bail out */
goto NextEntry;
}
/* Get the branch condition */
BC = GetBranchCond (N->OPC);
/* Check the argument against the branch condition */
if ((BC == BC_EQ && E->Num != 0) ||
(BC == BC_NE && E->Num == 0) ||
(BC == BC_PL && (E->Num & 0x80) != 0) ||
(BC == BC_MI && (E->Num & 0x80) == 0)) {
/* Remove the conditional branch */
DelCodeEntry (S, I+1);
--Count;
/* Remember, we had changes */
++Changes;
}
}
NextEntry:
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}

92
src/cc65/coptind.h Normal file
View File

@ -0,0 +1,92 @@
/*****************************************************************************/
/* */
/* coptind.h */
/* */
/* Environment independent low level optimizations */
/* */
/* */
/* */
/* (C) 2001 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef COPTIND_H
#define COPTIND_H
#include "codeseg.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
unsigned OptDeadJumps (CodeSeg* S);
/* Remove dead jumps (jumps to the next instruction) */
unsigned OptDeadCode (CodeSeg* S);
/* Remove dead code (code that follows an unconditional jump or an rts/rti
* and has no label)
*/
unsigned OptJumpCascades (CodeSeg* S);
/* Optimize jump cascades (jumps to jumps). In such a case, the jump is
* replaced by a jump to the final location. This will in some cases produce
* worse code, because some jump targets are no longer reachable by short
* branches, but this is quite rare, so there are more advantages than
* disadvantages.
*/
unsigned OptRTS (CodeSeg* S);
/* Optimize subroutine calls followed by an RTS. The subroutine call will get
* replaced by a jump. Don't bother to delete the RTS if it does not have a
* label, the dead code elimination should take care of it.
*/
unsigned OptJumpTarget (CodeSeg* S);
/* If the instruction preceeding an unconditional branch is the same as the
* instruction preceeding the jump target, the jump target may be moved
* one entry back. This is a size optimization, since the instruction before
* the branch gets removed.
*/
unsigned OptDeadCondBranches (CodeSeg* S);
/* If an immidiate load of a register is followed by a conditional jump that
* is never taken because the load of the register sets the flags in such a
* manner, remove the conditional branch.
*/
/* End of coptind.h */
#endif

View File

@ -32,6 +32,7 @@ OBJS = anonname.o \
codeopt.o \
codeseg.o \
compile.o \
coptind.o \
cpu.o \
dataseg.o \
datatype.o \