mirror of
https://github.com/cc65/cc65.git
synced 2025-01-16 13:31:16 +00:00
More source splitting.
Remove the -Wno-unused-parameter in favour of __atribute__((unused)). git-svn-id: svn://svn.cc65.org/cc65/trunk@986 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
0a6895ca05
commit
c8415fc17c
@ -190,7 +190,7 @@ static void ParseWordArg (StrBuf* T, unsigned Arg)
|
||||
|
||||
|
||||
|
||||
static void ParseLongArg (StrBuf* T, unsigned Arg)
|
||||
static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused)))
|
||||
/* Parse the %l format specifier */
|
||||
{
|
||||
ExprDesc Expr;
|
||||
|
@ -752,23 +752,15 @@ void g_getlocal (unsigned flags, int offs)
|
||||
AddCodeLine ("dey");
|
||||
AddCodeLine ("lda (sp),y");
|
||||
} else {
|
||||
if (offs) {
|
||||
ldyconst (offs+1);
|
||||
AddCodeLine ("jsr ldaxysp");
|
||||
} else {
|
||||
AddCodeLine ("jsr ldax0sp");
|
||||
}
|
||||
ldyconst (offs+1);
|
||||
AddCodeLine ("jsr ldaxysp");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CF_LONG:
|
||||
if (offs) {
|
||||
ldyconst (offs+3);
|
||||
AddCodeLine ("jsr ldeaxysp");
|
||||
} else {
|
||||
AddCodeLine ("jsr ldeax0sp");
|
||||
}
|
||||
ldyconst (offs+3);
|
||||
AddCodeLine ("jsr ldeaxysp");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -812,22 +804,14 @@ void g_getind (unsigned flags, unsigned offs)
|
||||
AddCodeLine ("iny");
|
||||
AddCodeLine ("ora (ptr1),y");
|
||||
} else {
|
||||
if (offs == 0) {
|
||||
AddCodeLine ("jsr ldaxi");
|
||||
} else {
|
||||
ldyconst (offs+1);
|
||||
AddCodeLine ("jsr ldaxidx");
|
||||
}
|
||||
ldyconst (offs+1);
|
||||
AddCodeLine ("jsr ldaxidx");
|
||||
}
|
||||
break;
|
||||
|
||||
case CF_LONG:
|
||||
if (offs == 0) {
|
||||
AddCodeLine ("jsr ldeaxi");
|
||||
} else {
|
||||
ldyconst (offs+3);
|
||||
AddCodeLine ("jsr ldeaxidx");
|
||||
}
|
||||
ldyconst (offs+3);
|
||||
AddCodeLine ("jsr ldeaxidx");
|
||||
if (flags & CF_TEST) {
|
||||
AddCodeLine ("jsr tsteax");
|
||||
}
|
||||
@ -1034,12 +1018,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val)
|
||||
if (Flags & CF_CONST) {
|
||||
g_getimmed (Flags, Val, 0);
|
||||
}
|
||||
if (Offs) {
|
||||
ldyconst (Offs);
|
||||
AddCodeLine ("jsr steaxysp");
|
||||
} else {
|
||||
AddCodeLine ("jsr steax0sp");
|
||||
}
|
||||
ldyconst (Offs);
|
||||
AddCodeLine ("jsr steaxysp");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1527,28 +1507,6 @@ void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Compares of ax with a variable with fixed address */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void g_cmplocal (unsigned flags, int offs)
|
||||
/* Compare a local variable to ax */
|
||||
{
|
||||
Internal ("g_cmplocal not implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
|
||||
/* Compare a static variable to ax */
|
||||
{
|
||||
Internal ("g_cmpstatic not implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Special op= functions */
|
||||
/*****************************************************************************/
|
||||
@ -1728,12 +1686,8 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val)
|
||||
if (flags & CF_CONST) {
|
||||
g_getimmed (flags, val, 0);
|
||||
}
|
||||
if (offs == 0) {
|
||||
AddCodeLine ("jsr laddeq0sp");
|
||||
} else {
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr laddeqysp");
|
||||
}
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr laddeqysp");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1881,12 +1835,8 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
|
||||
AddCodeLine ("ldy #<(%s)", lbuf);
|
||||
AddCodeLine ("sty ptr1");
|
||||
AddCodeLine ("ldy #>(%s+1)", lbuf);
|
||||
if (val == 1) {
|
||||
AddCodeLine ("jsr lsubeq1");
|
||||
} else {
|
||||
AddCodeLine ("lda #$%02X", (unsigned char)val);
|
||||
AddCodeLine ("jsr lsubeqa");
|
||||
}
|
||||
AddCodeLine ("lda #$%02X", (unsigned char)val);
|
||||
AddCodeLine ("jsr lsubeqa");
|
||||
} else {
|
||||
g_getstatic (flags, label, offs);
|
||||
g_dec (flags, val);
|
||||
@ -1945,24 +1895,16 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val)
|
||||
if (flags & CF_CONST) {
|
||||
g_getimmed (flags, val, 0);
|
||||
}
|
||||
if (offs == 0) {
|
||||
AddCodeLine ("jsr subeq0sp");
|
||||
} else {
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr subeqysp");
|
||||
}
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr subeqysp");
|
||||
break;
|
||||
|
||||
case CF_LONG:
|
||||
if (flags & CF_CONST) {
|
||||
g_getimmed (flags, val, 0);
|
||||
}
|
||||
if (offs == 0) {
|
||||
AddCodeLine ("jsr lsubeq0sp");
|
||||
} else {
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr lsubeqysp");
|
||||
}
|
||||
ldyconst (offs);
|
||||
AddCodeLine ("jsr lsubeqysp");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2037,7 +1979,7 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
|
||||
|
||||
|
||||
|
||||
void g_addaddr_local (unsigned flags, int offs)
|
||||
void g_addaddr_local (unsigned flags attribute ((unused)), int offs)
|
||||
/* Add the address of a local variable to ax */
|
||||
{
|
||||
unsigned L = 0;
|
||||
@ -2281,36 +2223,20 @@ void g_test (unsigned flags)
|
||||
void g_push (unsigned flags, unsigned long val)
|
||||
/* Push the primary register or a constant value onto the stack */
|
||||
{
|
||||
unsigned char hi;
|
||||
|
||||
if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
|
||||
|
||||
/* We have a constant 8 or 16 bit value */
|
||||
if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
|
||||
|
||||
/* Handle as 8 bit value */
|
||||
if (CodeSizeFactor >= 165 || val > 2) {
|
||||
ldaconst (val);
|
||||
AddCodeLine ("jsr pusha");
|
||||
} else {
|
||||
AddCodeLine ("jsr pushc%d", (int) val);
|
||||
}
|
||||
ldaconst (val);
|
||||
AddCodeLine ("jsr pusha");
|
||||
|
||||
} else {
|
||||
|
||||
/* Handle as 16 bit value */
|
||||
hi = (unsigned char) (val >> 8);
|
||||
if (val <= 7) {
|
||||
AddCodeLine ("jsr push%u", (unsigned) val);
|
||||
} else if (hi == 0 || hi == 0xFF) {
|
||||
/* Use special function */
|
||||
ldaconst (val);
|
||||
AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF");
|
||||
} else {
|
||||
/* Long way ... */
|
||||
g_getimmed (flags, val, 0);
|
||||
AddCodeLine ("jsr pushax");
|
||||
}
|
||||
g_getimmed (flags, val, 0);
|
||||
AddCodeLine ("jsr pushax");
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -2475,7 +2401,7 @@ void g_case (unsigned flags, unsigned label, unsigned long val)
|
||||
|
||||
|
||||
|
||||
void g_truejump (unsigned flags, unsigned label)
|
||||
void g_truejump (unsigned flags attribute ((unused)), unsigned label)
|
||||
/* Jump to label if zero flag clear */
|
||||
{
|
||||
AddCodeLine ("jne %s", LocalLabelName (label));
|
||||
@ -2483,7 +2409,7 @@ void g_truejump (unsigned flags, unsigned label)
|
||||
|
||||
|
||||
|
||||
void g_falsejump (unsigned flags, unsigned label)
|
||||
void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
|
||||
/* Jump to label if zero flag set */
|
||||
{
|
||||
AddCodeLine ("jeq %s", LocalLabelName (label));
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "coptadd.h"
|
||||
#include "coptcmp.h"
|
||||
#include "coptind.h"
|
||||
#include "coptneg.h"
|
||||
#include "coptstop.h"
|
||||
#include "coptsub.h"
|
||||
#include "copttest.h"
|
||||
@ -114,383 +115,6 @@ static unsigned OptShift1 (CodeSeg* S)
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* nega optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegA1 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for a ldx */
|
||||
if (E->OPC == OP65_LDX &&
|
||||
E->AM == AM65_IMM &&
|
||||
(E->Flags & CEF_NUMARG) != 0 &&
|
||||
E->Num == 0 &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OP65_LDA &&
|
||||
(L[0]->Use & REG_X) == 0 &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
CE_IsCall (L[1], "bnega") &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
/* Remove the ldx instruction */
|
||||
CS_DelEntry (S, I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegA2 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if ((E->OPC == OP65_ADC ||
|
||||
E->OPC == OP65_AND ||
|
||||
E->OPC == OP65_DEA ||
|
||||
E->OPC == OP65_EOR ||
|
||||
E->OPC == OP65_INA ||
|
||||
E->OPC == OP65_LDA ||
|
||||
E->OPC == OP65_ORA ||
|
||||
E->OPC == OP65_PLA ||
|
||||
E->OPC == OP65_SBC ||
|
||||
E->OPC == OP65_TXA ||
|
||||
E->OPC == OP65_TYA) &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
CE_IsCall (L[0], "bnega") &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+1);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* negax optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX1 (CodeSeg* S)
|
||||
/* On a call to bnegax, if X is zero, the result depends only on the value in
|
||||
* A, so change the call to a call to bnega. This will get further optimized
|
||||
* later if possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
/* Generate register info for this step */
|
||||
CS_GenRegInfo (S);
|
||||
|
||||
/* Walk over the entries */
|
||||
I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this is a call to bnegax, and if X is known and zero */
|
||||
if (E->RI->In.RegX == 0 &&
|
||||
CE_IsCall (E, "bnegax")) {
|
||||
|
||||
/* We're cheating somewhat here ... */
|
||||
E->Arg[5] = '\0';
|
||||
E->Use &= ~REG_X;
|
||||
|
||||
/* We had changes */
|
||||
++Changes;
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Free register info */
|
||||
CS_FreeRegInfo (S);
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda (xx),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (xx),y
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda (xx),y
|
||||
* dey
|
||||
* ora (xx),y
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[5];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_LDA &&
|
||||
E->AM == AM65_ZP_INDY &&
|
||||
CS_GetEntries (S, L, I+1, 5) &&
|
||||
L[0]->OPC == OP65_TAX &&
|
||||
L[1]->OPC == OP65_DEY &&
|
||||
L[2]->OPC == OP65_LDA &&
|
||||
L[2]->AM == AM65_ZP_INDY &&
|
||||
strcmp (L[2]->Arg, E->Arg) == 0 &&
|
||||
!CE_HasLabel (L[2]) &&
|
||||
CE_IsCall (L[3], "bnegax") &&
|
||||
!CE_HasLabel (L[3]) &&
|
||||
(L[4]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[4])) {
|
||||
|
||||
/* lda --> ora */
|
||||
CE_ReplaceOPC (L[2], OP65_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
|
||||
|
||||
/* Delete the entries no longer needed. Beware: Deleting entries
|
||||
* will change the indices.
|
||||
*/
|
||||
CS_DelEntry (S, I+4); /* jsr bnegax */
|
||||
CS_DelEntry (S, I+1); /* tax */
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX3 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda xx
|
||||
* ldx yy
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda xx
|
||||
* ora xx+1
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[3];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_LDA &&
|
||||
CS_GetEntries (S, L, I+1, 3) &&
|
||||
L[0]->OPC == OP65_LDX &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
CE_IsCall (L[1], "bnegax") &&
|
||||
!CE_HasLabel (L[1]) &&
|
||||
(L[2]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[2])) {
|
||||
|
||||
/* ldx --> ora */
|
||||
CE_ReplaceOPC (L[0], OP65_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+2);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptNegAX4 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_JSR &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OP65_JSR &&
|
||||
strncmp (L[0]->Arg,"bnega",5) == 0 &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
CodeEntry* X;
|
||||
|
||||
/* Check if we're calling bnega or bnegax */
|
||||
int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
|
||||
|
||||
/* Insert apropriate test code */
|
||||
if (ByteSized) {
|
||||
/* Test bytes */
|
||||
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+2);
|
||||
} else {
|
||||
/* Test words */
|
||||
X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+2);
|
||||
X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+3);
|
||||
}
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+1);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Optimize stores through pointers */
|
||||
/*****************************************************************************/
|
||||
@ -1403,7 +1027,118 @@ static unsigned OptDecouple (CodeSeg* S)
|
||||
|
||||
|
||||
|
||||
static unsigned OptSize (CodeSeg* S)
|
||||
static unsigned OptSize1 (CodeSeg* S)
|
||||
/* Do size optimization by calling special subroutines that preload registers.
|
||||
* This routine does not work standalone, it needs a following register load
|
||||
* removal pass.
|
||||
*/
|
||||
{
|
||||
#if 0
|
||||
static const char* Func = {
|
||||
"stax0sp", /* staxysp, y = 0 */
|
||||
"addeq0sp",
|
||||
"ldax0sp", /* ldaxysp, y = 1 */
|
||||
"ldeax0sp", /* ldeaxysp, y = 3 */
|
||||
"push0", /* pushax, a = 0, x = 0 */
|
||||
"pusha0", /* pushax, x = 0 */
|
||||
"pushaFF", /* pushax, x = ff */
|
||||
"pusha0sp", /* pushaysp, y = 0 */
|
||||
"tosadda0", /* tosaddax, x = 0 */
|
||||
"tosanda0", /* tosandax, x = 0 */
|
||||
"tosdiva0", /* tosdivax, x = 0 */
|
||||
"toseqa0", /* toseqax, x = 0 */
|
||||
"tosgea0", /* tosgeax, x = 0 */
|
||||
"tosgta0", /* tosgtax, x = 0 */
|
||||
"tosadd0ax", /* tosaddeax, sreg = 0 */
|
||||
"laddeqa", /* laddeq, sreg = 0, x = 0 */
|
||||
"laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */
|
||||
"laddeq0sp", /* laddeqysp, y = 0 */
|
||||
"tosand0ax", /* tosandeax, sreg = 0 */
|
||||
"ldaxi", /* ldaxidx, y = 1 */
|
||||
"ldeaxi", /* ldeaxidx, y = 3 */
|
||||
"ldeax0sp", /* ldeaxysp, y = 3 */
|
||||
"tosdiv0ax", /* tosdiveax, sreg = 0 */
|
||||
"toslea0", /* tosleax, x = 0 */
|
||||
"tosmod0ax", /* tosmodeax, sreg = 0 */
|
||||
"tosmul0ax", /* tosmuleax, sreg = 0 */
|
||||
"tosumul0ax", /* tosumuleax, sreg = 0 */
|
||||
"tosor0ax", /* tosoreax, sreg = 0 */
|
||||
"push0ax", /* pusheax, sreg = 0 */
|
||||
"tosrsub0ax", /* tosrsubeax, sreg = 0 */
|
||||
"tosshl0ax", /* tosshleax, sreg = 0 */
|
||||
"tosasl0ax", /* tosasleax, sreg = 0 */
|
||||
"tosshr0ax", /* tosshreax, sreg = 0 */
|
||||
"tosasr0ax", /* tosasreax, sreg = 0 */
|
||||
"tossub0ax", /* tossubeax, sreg = 0 */
|
||||
"lsubeqa", /* lsubeq, sreg = 0, x = 0 */
|
||||
"lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */
|
||||
"lsubeq0sp", /* lsubeqysp, y = 0 */
|
||||
"toslta0", /* tosltax, x = 0 */
|
||||
"tosudiv0ax", /* tosudiveax, sreg = 0 */
|
||||
"tosumod0ax", /* tosumodeax, sreg = 0 */
|
||||
"tosxor0ax", /* tosxoreax, sreg = 0 */
|
||||
"tosmoda0", /* tosmodax, x = 0 */
|
||||
"tosmula0", /* tosmulax, x = 0 */
|
||||
"tosumula0", /* tosumulax, x = 0 */
|
||||
"tosnea0", /* tosneax, x = 0 */
|
||||
"tosora0", /* tosorax, x = 0 */
|
||||
"push1", /* pushax, x = 0, a = 1 */
|
||||
"push2", /* pushax, x = 0, a = 2 */
|
||||
"push3", /* pushax, x = 0, a = 3 */
|
||||
"push4", /* pushax, x = 0, a = 4 */
|
||||
"push5", /* pushax, x = 0, a = 5 */
|
||||
"push6", /* pushax, x = 0, a = 6 */
|
||||
"push7", /* pushax, x = 0, a = 7 */
|
||||
"pushc0", /* pusha, a = 0 */
|
||||
"pushc1", /* pusha, a = 1 */
|
||||
"pushc2", /* pusha, a = 2 */
|
||||
"tosrsuba0", /* tosrsubax, x = 0 */
|
||||
"tosshla0", /* tosshlax, x = 0 */
|
||||
"tosasla0", /* tosaslax, x = 0 */
|
||||
"tosshra0", /* tosshrax, x = 0 */
|
||||
"tosasra0", /* tosasrax, x = 0 */
|
||||
"steax0sp", /* steaxsp, y = 0 */
|
||||
"tossuba0", /* tossubax, x = 0 */
|
||||
"subeq0sp", /* subeqysp, y = 0 */
|
||||
"tosudiva0", /* tosudivax, x = 0 */
|
||||
"tosugea0", /* tosugeax, x = 0 */
|
||||
"tosugta0", /* tosugtax, x = 0 */
|
||||
"tosulea0", /* tosuleax, x = 0 */
|
||||
"tosulta0", /* tosultax, x = 0 */
|
||||
"tosumoda0", /* tosumodax, x = 0 */
|
||||
"tosxora0", /* tosxorax, x = 0 */
|
||||
};
|
||||
#endif
|
||||
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
/* Generate register info for the following step */
|
||||
CS_GenRegInfo (S);
|
||||
|
||||
/* Walk over the entries */
|
||||
I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Free register info */
|
||||
CS_FreeRegInfo (S);
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned OptSize2 (CodeSeg* S)
|
||||
/* Do size optimization by using shorter code sequences, even if this
|
||||
* introduces relations between instructions. This step must be one of the
|
||||
* last steps, because it makes further work much more difficult.
|
||||
@ -1443,7 +1178,7 @@ static unsigned OptSize (CodeSeg* S)
|
||||
X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP65_LDX:
|
||||
@ -1564,7 +1299,8 @@ static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 0, 0, 0, 0
|
||||
static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptShift1 = { OptShift1, "OptShift1", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptSize = { OptSize, "OptSize", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptSize1 = { OptSize1, "OptSize1", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptSize2 = { OptSize2, "OptSize2", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptSub1 = { OptSub1, "OptSub1", 0, 0, 0, 0, 0 };
|
||||
@ -1602,22 +1338,23 @@ static OptFunc* OptFuncs[] = {
|
||||
&DOptNegAX2,
|
||||
&DOptNegAX3,
|
||||
&DOptNegAX4,
|
||||
&DOptPtrStore1,
|
||||
&DOptPtrStore2,
|
||||
&DOptPtrLoad1,
|
||||
&DOptPtrLoad2,
|
||||
&DOptPtrLoad3,
|
||||
&DOptPtrLoad4,
|
||||
&DOptPtrLoad5,
|
||||
&DOptPtrLoad6,
|
||||
&DOptPtrStore1,
|
||||
&DOptPtrStore2,
|
||||
&DOptRTS,
|
||||
&DOptRTSJumps,
|
||||
&DOptShift1,
|
||||
&DOptSize,
|
||||
&DOptSub1,
|
||||
&DOptSub2,
|
||||
&DOptSize1,
|
||||
&DOptSize2,
|
||||
&DOptStackOps,
|
||||
&DOptStoreLoad,
|
||||
&DOptSub1,
|
||||
&DOptSub2,
|
||||
&DOptTest1,
|
||||
&DOptTransfers,
|
||||
&DOptUnusedLoads,
|
||||
@ -1929,7 +1666,7 @@ static void RunOptGroup4 (CodeSeg* S)
|
||||
* if this does hinder further optimizations (no problem since we're
|
||||
* done soon).
|
||||
*/
|
||||
RunOptFunc (S, &DOptSize, 1);
|
||||
RunOptFunc (S, &DOptSize2, 1);
|
||||
|
||||
/* Run the jump target optimization again, since the size optimization
|
||||
* above may have opened new oportunities.
|
||||
|
@ -246,7 +246,7 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
|
||||
|
||||
|
||||
|
||||
static int IsImmCmp16 (CodeSeg* S, CodeEntry** L)
|
||||
static int IsImmCmp16 (CodeEntry** L)
|
||||
/* Check if the instructions at L are an immidiate compare of a/x:
|
||||
*
|
||||
*
|
||||
@ -405,7 +405,7 @@ unsigned OptBoolTrans (CodeSeg* S)
|
||||
/*****************************************************************************/
|
||||
/* Optimizations for compares */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned OptCmp1 (CodeSeg* S)
|
||||
@ -565,7 +565,7 @@ unsigned OptCmp3 (CodeSeg* S)
|
||||
CS_GetEntries (S, L, I+1, 5) &&
|
||||
L[0]->OPC == OP65_LDX &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
IsImmCmp16 (S, L+1)) {
|
||||
IsImmCmp16 (L+1)) {
|
||||
|
||||
if (L[1]->Num == 0 && L[3]->Num == 0) {
|
||||
/* The value is zero, we may use the simple code version. */
|
||||
@ -628,7 +628,7 @@ unsigned OptCmp4 (CodeSeg* S)
|
||||
CodeEntry* L[9];
|
||||
|
||||
/* Check for the sequence */
|
||||
if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
|
||||
if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) {
|
||||
|
||||
if (L[5]->Num == 0 && L[7]->Num == 0) {
|
||||
|
||||
|
419
src/cc65/coptneg.c
Normal file
419
src/cc65/coptneg.c
Normal file
@ -0,0 +1,419 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* coptneg.c */
|
||||
/* */
|
||||
/* Optimize negation sequences */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* cc65 */
|
||||
#include "codeent.h"
|
||||
#include "codeinfo.h"
|
||||
#include "coptneg.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* nega optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned OptNegA1 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for a ldx */
|
||||
if (E->OPC == OP65_LDX &&
|
||||
E->AM == AM65_IMM &&
|
||||
(E->Flags & CEF_NUMARG) != 0 &&
|
||||
E->Num == 0 &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OP65_LDA &&
|
||||
(L[0]->Use & REG_X) == 0 &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
CE_IsCall (L[1], "bnega") &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
/* Remove the ldx instruction */
|
||||
CS_DelEntry (S, I);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned OptNegA2 (CodeSeg* S)
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if ((E->OPC == OP65_ADC ||
|
||||
E->OPC == OP65_AND ||
|
||||
E->OPC == OP65_DEA ||
|
||||
E->OPC == OP65_EOR ||
|
||||
E->OPC == OP65_INA ||
|
||||
E->OPC == OP65_LDA ||
|
||||
E->OPC == OP65_ORA ||
|
||||
E->OPC == OP65_PLA ||
|
||||
E->OPC == OP65_SBC ||
|
||||
E->OPC == OP65_TXA ||
|
||||
E->OPC == OP65_TYA) &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
CE_IsCall (L[0], "bnega") &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+1);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* negax optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned OptNegAX1 (CodeSeg* S)
|
||||
/* On a call to bnegax, if X is zero, the result depends only on the value in
|
||||
* A, so change the call to a call to bnega. This will get further optimized
|
||||
* later if possible.
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
unsigned I;
|
||||
|
||||
/* Generate register info for this step */
|
||||
CS_GenRegInfo (S);
|
||||
|
||||
/* Walk over the entries */
|
||||
I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this is a call to bnegax, and if X is known and zero */
|
||||
if (E->RI->In.RegX == 0 &&
|
||||
CE_IsCall (E, "bnegax")) {
|
||||
|
||||
/* We're cheating somewhat here ... */
|
||||
E->Arg[5] = '\0';
|
||||
E->Use &= ~REG_X;
|
||||
|
||||
/* We had changes */
|
||||
++Changes;
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Free register info */
|
||||
CS_FreeRegInfo (S);
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned OptNegAX2 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda (xx),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (xx),y
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda (xx),y
|
||||
* dey
|
||||
* ora (xx),y
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[5];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_LDA &&
|
||||
E->AM == AM65_ZP_INDY &&
|
||||
CS_GetEntries (S, L, I+1, 5) &&
|
||||
L[0]->OPC == OP65_TAX &&
|
||||
L[1]->OPC == OP65_DEY &&
|
||||
L[2]->OPC == OP65_LDA &&
|
||||
L[2]->AM == AM65_ZP_INDY &&
|
||||
strcmp (L[2]->Arg, E->Arg) == 0 &&
|
||||
!CE_HasLabel (L[2]) &&
|
||||
CE_IsCall (L[3], "bnegax") &&
|
||||
!CE_HasLabel (L[3]) &&
|
||||
(L[4]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[4])) {
|
||||
|
||||
/* lda --> ora */
|
||||
CE_ReplaceOPC (L[2], OP65_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC));
|
||||
|
||||
/* Delete the entries no longer needed. Beware: Deleting entries
|
||||
* will change the indices.
|
||||
*/
|
||||
CS_DelEntry (S, I+4); /* jsr bnegax */
|
||||
CS_DelEntry (S, I+1); /* tax */
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned OptNegAX3 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda xx
|
||||
* ldx yy
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda xx
|
||||
* ora xx+1
|
||||
* jeq/jne ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[3];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_LDA &&
|
||||
CS_GetEntries (S, L, I+1, 3) &&
|
||||
L[0]->OPC == OP65_LDX &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
CE_IsCall (L[1], "bnegax") &&
|
||||
!CE_HasLabel (L[1]) &&
|
||||
(L[2]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[2])) {
|
||||
|
||||
/* ldx --> ora */
|
||||
CE_ReplaceOPC (L[0], OP65_ORA);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+2);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned OptNegAX4 (CodeSeg* S)
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[2];
|
||||
|
||||
/* Get next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_JSR &&
|
||||
CS_GetEntries (S, L, I+1, 2) &&
|
||||
L[0]->OPC == OP65_JSR &&
|
||||
strncmp (L[0]->Arg,"bnega",5) == 0 &&
|
||||
!CE_HasLabel (L[0]) &&
|
||||
(L[1]->Info & OF_ZBRA) != 0 &&
|
||||
!CE_HasLabel (L[1])) {
|
||||
|
||||
CodeEntry* X;
|
||||
|
||||
/* Check if we're calling bnega or bnegax */
|
||||
int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);
|
||||
|
||||
/* Insert apropriate test code */
|
||||
if (ByteSized) {
|
||||
/* Test bytes */
|
||||
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+2);
|
||||
} else {
|
||||
/* Test words */
|
||||
X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+2);
|
||||
X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
|
||||
CS_InsertEntry (S, X, I+3);
|
||||
}
|
||||
|
||||
/* Delete the subroutine call */
|
||||
CS_DelEntry (S, I+1);
|
||||
|
||||
/* Invert the branch */
|
||||
CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
140
src/cc65/coptneg.h
Normal file
140
src/cc65/coptneg.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* coptneg.h */
|
||||
/* */
|
||||
/* Optimize negation sequences */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (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 COPTNEG_H
|
||||
#define COPTNEG_H
|
||||
|
||||
|
||||
|
||||
/* cc65 */
|
||||
#include "codeseg.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* nega optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned OptNegA1 (CodeSeg* S);
|
||||
/* Check for
|
||||
*
|
||||
* ldx #$00
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
*
|
||||
* Remove the ldx if the lda does not use it.
|
||||
*/
|
||||
|
||||
unsigned OptNegA2 (CodeSeg* S);
|
||||
/* Check for
|
||||
*
|
||||
* lda ..
|
||||
* jsr bnega
|
||||
* jeq/jne ..
|
||||
*
|
||||
* Adjust the conditional branch and remove the call to the subroutine.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* negax optimizations */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
unsigned OptNegAX1 (CodeSeg* S);
|
||||
/* On a call to bnegax, if X is zero, the result depends only on the value in
|
||||
* A, so change the call to a call to bnega. This will get further optimized
|
||||
* later if possible.
|
||||
*/
|
||||
|
||||
unsigned OptNegAX2 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda (xx),y
|
||||
* tax
|
||||
* dey
|
||||
* lda (xx),y
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda (xx),y
|
||||
* dey
|
||||
* ora (xx),y
|
||||
* jeq/jne ...
|
||||
*/
|
||||
|
||||
unsigned OptNegAX3 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* lda xx
|
||||
* ldx yy
|
||||
* jsr bnegax
|
||||
* jne/jeq ...
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* lda xx
|
||||
* ora xx+1
|
||||
* jeq/jne ...
|
||||
*/
|
||||
|
||||
unsigned OptNegAX4 (CodeSeg* S);
|
||||
/* Search for the sequence:
|
||||
*
|
||||
* jsr xxx
|
||||
* jsr bnega(x)
|
||||
* jeq/jne ...
|
||||
*
|
||||
* and replace it by:
|
||||
*
|
||||
* jsr xxx
|
||||
* <boolean test>
|
||||
* jne/jeq ...
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of coptneg.h */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -463,7 +463,7 @@ static void MakeConstIntExpr (ExprDesc* Expr, long Value)
|
||||
{
|
||||
Expr->Flags = E_MCONST;
|
||||
Expr->Type = type_int;
|
||||
Expr->ConstVal = 1;
|
||||
Expr->ConstVal = Value;
|
||||
}
|
||||
|
||||
|
||||
@ -813,7 +813,7 @@ static void FunctionCall (int k, ExprDesc* lval)
|
||||
g_space (- (int) sizeofarg (CF_PTR));
|
||||
pop (CF_PTR);
|
||||
}
|
||||
|
||||
|
||||
/* Skip T_PTR */
|
||||
++lval->Type;
|
||||
|
||||
|
@ -277,7 +277,8 @@ static void CheckSegName (const char* Seg)
|
||||
|
||||
|
||||
|
||||
static void OptAddSource (const char* Opt, const char* Arg)
|
||||
static void OptAddSource (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Add source lines as comments in generated assembler file */
|
||||
{
|
||||
AddSource = 1;
|
||||
@ -285,7 +286,8 @@ static void OptAddSource (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptAnsi (const char* Opt, const char* Arg)
|
||||
static void OptAnsi (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Compile in strict ANSI mode */
|
||||
{
|
||||
ANSI = 1;
|
||||
@ -293,7 +295,7 @@ static void OptAnsi (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptBssName (const char* Opt, const char* Arg)
|
||||
static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Handle the --bss-name option */
|
||||
{
|
||||
/* Check for a valid name */
|
||||
@ -305,7 +307,8 @@ static void OptBssName (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptCheckStack (const char* Opt, const char* Arg)
|
||||
static void OptCheckStack (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Handle the --check-stack option */
|
||||
{
|
||||
CheckStack = 1;
|
||||
@ -313,7 +316,7 @@ static void OptCheckStack (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptCodeName (const char* Opt, const char* Arg)
|
||||
static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Handle the --code-name option */
|
||||
{
|
||||
/* Check for a valid name */
|
||||
@ -338,7 +341,8 @@ static void OptCodeSize (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptCreateDep (const char* Opt, const char* Arg)
|
||||
static void OptCreateDep (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Handle the --create-dep option */
|
||||
{
|
||||
CreateDep = 1;
|
||||
@ -354,13 +358,13 @@ static void OptCPU (const char* Opt, const char* Arg)
|
||||
} else if (strcmp (Arg, "65C02") == 0) {
|
||||
CPU = CPU_65C02;
|
||||
} else {
|
||||
AbEnd ("Invalid CPU: `%s'", Arg);
|
||||
AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptDataName (const char* Opt, const char* Arg)
|
||||
static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Handle the --data-name option */
|
||||
{
|
||||
/* Check for a valid name */
|
||||
@ -372,7 +376,8 @@ static void OptDataName (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptDebug (const char* Opt, const char* Arg)
|
||||
static void OptDebug (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Compiler debug mode */
|
||||
{
|
||||
Debug = 1;
|
||||
@ -380,7 +385,8 @@ static void OptDebug (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptDebugInfo (const char* Opt, const char* Arg)
|
||||
static void OptDebugInfo (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Add debug info to the object file */
|
||||
{
|
||||
DebugInfo = 1;
|
||||
@ -388,7 +394,7 @@ static void OptDebugInfo (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptDebugOpt (const char* Opt, const char* Arg)
|
||||
static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Debug optimization steps */
|
||||
{
|
||||
char Buf [128];
|
||||
@ -455,7 +461,7 @@ static void OptDebugOpt (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptDisableOpt (const char* Opt, const char* Arg)
|
||||
static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Disable an optimization step */
|
||||
{
|
||||
DisableOpt (Arg);
|
||||
@ -463,7 +469,7 @@ static void OptDisableOpt (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptEnableOpt (const char* Opt, const char* Arg)
|
||||
static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Enable an optimization step */
|
||||
{
|
||||
EnableOpt (Arg);
|
||||
@ -471,7 +477,8 @@ static void OptEnableOpt (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptHelp (const char* Opt, const char* Arg)
|
||||
static void OptHelp (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Print usage information and exit */
|
||||
{
|
||||
Usage ();
|
||||
@ -480,7 +487,7 @@ static void OptHelp (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptIncludeDir (const char* Opt, const char* Arg)
|
||||
static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Add an include search path */
|
||||
{
|
||||
AddIncludePath (Arg, INC_SYS | INC_USER);
|
||||
@ -488,7 +495,8 @@ static void OptIncludeDir (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptListOptSteps (const char* Opt, const char* Arg)
|
||||
static void OptListOptSteps (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* List all optimizer steps */
|
||||
{
|
||||
/* List the optimizer steps */
|
||||
@ -500,7 +508,7 @@ static void OptListOptSteps (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptRodataName (const char* Opt, const char* Arg)
|
||||
static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Handle the --rodata-name option */
|
||||
{
|
||||
/* Check for a valid name */
|
||||
@ -512,7 +520,8 @@ static void OptRodataName (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptSignedChars (const char* Opt, const char* Arg)
|
||||
static void OptSignedChars (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Make default characters signed */
|
||||
{
|
||||
SignedChars = 1;
|
||||
@ -520,7 +529,8 @@ static void OptSignedChars (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptStaticLocals (const char* Opt, const char* Arg)
|
||||
static void OptStaticLocals (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Place local variables in static storage */
|
||||
{
|
||||
StaticLocals = 1;
|
||||
@ -528,7 +538,7 @@ static void OptStaticLocals (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptTarget (const char* Opt, const char* Arg)
|
||||
static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Set the target system */
|
||||
{
|
||||
SetSys (Arg);
|
||||
@ -536,7 +546,8 @@ static void OptTarget (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptVerbose (const char* Opt, const char* Arg)
|
||||
static void OptVerbose (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Increase verbosity */
|
||||
{
|
||||
++Verbosity;
|
||||
@ -544,7 +555,8 @@ static void OptVerbose (const char* Opt, const char* Arg)
|
||||
|
||||
|
||||
|
||||
static void OptVersion (const char* Opt, const char* Arg)
|
||||
static void OptVersion (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Print the assembler version */
|
||||
{
|
||||
fprintf (stderr,
|
||||
|
@ -14,7 +14,7 @@ COMMON = ../common
|
||||
|
||||
# Default for the compiler lib search path as compiler define
|
||||
CDEFS=-DCC65_INC=\"/usr/lib/cc65/include/\"
|
||||
CFLAGS = -O2 -g -Wall -W -Wno-unused-parameter -I$(COMMON) $(CDEFS)
|
||||
CFLAGS = -O2 -g -Wall -W -I$(COMMON) $(CDEFS)
|
||||
CC=gcc
|
||||
EBIND=emxbind
|
||||
LDFLAGS=
|
||||
@ -36,6 +36,7 @@ OBJS = anonname.o \
|
||||
coptadd.o \
|
||||
coptcmp.o \
|
||||
coptind.o \
|
||||
coptneg.o \
|
||||
coptstop.o \
|
||||
coptsub.o \
|
||||
copttest.o \
|
||||
|
@ -81,6 +81,7 @@ OBJS = anonname.obj \
|
||||
coptadd.obj \
|
||||
coptcmp.obj \
|
||||
coptind.obj \
|
||||
coptneg.obj \
|
||||
coptstop.obj \
|
||||
coptsub.obj \
|
||||
copttest.obj \
|
||||
@ -155,6 +156,7 @@ FILE compile.obj
|
||||
FILE coptadd.obj
|
||||
FILE coptcmp.obj
|
||||
FILE coptind.obj
|
||||
FILE coptneg.obj
|
||||
FILE coptstop.obj
|
||||
FILE coptsub.obj
|
||||
FILE copttest.obj
|
||||
|
@ -107,7 +107,7 @@ static struct StdFuncDesc* FindFunc (const char* Name)
|
||||
|
||||
|
||||
|
||||
static void StdFunc_strlen (ExprDesc* lval)
|
||||
static void StdFunc_strlen (ExprDesc* lval attribute ((unused)))
|
||||
/* Handle the strlen function */
|
||||
{
|
||||
ExprDesc pval;
|
||||
|
Loading…
x
Reference in New Issue
Block a user