From c9cb564b9bf5e91cef70cc7941f8f3465f0abc70 Mon Sep 17 00:00:00 2001 From: cuz Date: Mon, 14 May 2001 17:35:53 +0000 Subject: [PATCH] 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 --- src/cc65/codegen.c | 61 ++++-- src/cc65/codeopt.c | 441 ++------------------------------------ src/cc65/coptind.c | 481 ++++++++++++++++++++++++++++++++++++++++++ src/cc65/coptind.h | 92 ++++++++ src/cc65/make/gcc.mak | 1 + 5 files changed, 631 insertions(+), 445 deletions(-) create mode 100644 src/cc65/coptind.c create mode 100644 src/cc65/coptind.h diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 81273b013..898ce17fb 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -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 diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index b52212dbb..c97cfa06f 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -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); } } diff --git a/src/cc65/coptind.c b/src/cc65/coptind.c new file mode 100644 index 000000000..f01546d1f --- /dev/null +++ b/src/cc65/coptind.c @@ -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 + +/* 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; +} + + + diff --git a/src/cc65/coptind.h b/src/cc65/coptind.h new file mode 100644 index 000000000..bcb9e5a40 --- /dev/null +++ b/src/cc65/coptind.h @@ -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 + + + diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index d24e87cfe..1f34b4c28 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -32,6 +32,7 @@ OBJS = anonname.o \ codeopt.o \ codeseg.o \ compile.o \ + coptind.o \ cpu.o \ dataseg.o \ datatype.o \