1
0
mirror of https://github.com/cc65/cc65.git synced 2024-07-10 23:29:05 +00:00

Trace register usage, remove duplicate loads

git-svn-id: svn://svn.cc65.org/cc65/trunk@793 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-07-16 16:32:14 +00:00
parent 38f076a59e
commit f98db88f36
4 changed files with 435 additions and 12 deletions

View File

@ -1296,6 +1296,7 @@ static OptFunc OptFuncs [] = {
{ OptCmp5, "OptCmp5", 0 },
/* Remove unused loads */
{ OptUnusedLoads, "OptUnusedLoads", 0 },
{ OptDuplicateLoads, "OptDuplicateLoads", 0 },
/* Optimize branch distance */
{ OptBranchDist, "OptBranchDist", 0 },
};

View File

@ -44,6 +44,32 @@
/*****************************************************************************/
/* Macros */
/*****************************************************************************/
/* Macro to increment and decrement register contents if they're valid */
#define INC(reg,val) if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
#define DEC(reg,val) if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
/*****************************************************************************/
/* Helpers */
/*****************************************************************************/
static int IsKnownImm (const CodeEntry* E)
/* Return true if the argument of E is a known immediate value */
{
return (E->AM == AM65_IMM && (E->Flags & CEF_NUMARG) != 0);
}
/*****************************************************************************/
/* Replace jumps to RTS by RTS */
/*****************************************************************************/
@ -606,20 +632,20 @@ unsigned OptUnusedLoads (CodeSeg* S)
/* Check which sort of load or transfer it is */
unsigned R;
switch (E->OPC) {
case OP65_TXA:
case OP65_TYA:
case OP65_LDA: R = REG_A; break;
case OP65_TAX:
case OP65_TXA:
case OP65_TYA:
case OP65_LDA: R = REG_A; break;
case OP65_TAX:
case OP65_LDX: R = REG_X; break;
case OP65_TAY:
case OP65_LDY: R = REG_Y; break;
default: goto NextEntry; /* OOPS */
case OP65_TAY:
case OP65_LDY: R = REG_Y; break;
default: goto NextEntry; /* OOPS */
}
/* Get register usage and check if the register value is used later */
if ((GetRegInfo (S, I+1) & R) == 0) {
/* Register value is not used, remove the load */
/* Register value is not used, remove the load */
CS_DelEntry (S, I);
/* Remember, we had changes */
@ -629,8 +655,400 @@ unsigned OptUnusedLoads (CodeSeg* S)
}
NextEntry:
/* Next entry */
++I;
/* Next entry */
++I;
}
/* Return the number of changes made */
return Changes;
}
unsigned OptDuplicateLoads (CodeSeg* S)
/* Remove loads of registers where the value loaded is already in the register. */
{
unsigned Changes = 0;
/* Remember the last load instructions for all registers */
int RegA = -1;
int RegX = -1;
int RegY = -1;
/* Walk over the entries */
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {
unsigned char Use, Chg;
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
/* Assume we won't delete the entry */
int Delete = 0;
/* If this entry has a label attached, remove all knownledge about the
* register contents. This may be improved but for now it's ok.
*/
if (CE_HasLabel (E)) {
RegA = RegX = RegY = -1;
}
/* Handle the different instructions */
switch (E->OPC) {
case OP65_ADC:
/* We don't know the value of the carry, so the result is
* always unknown.
*/
RegA = -1;
break;
case OP65_AND:
if (RegA >= 0) {
if (IsKnownImm (E)) {
RegA &= (int) E->Num;
} else {
RegA = -1;
}
}
break;
case OP65_ASL:
if (RegA >= 0) {
RegA = (RegA << 1) & 0xFF;
}
break;
case OP65_BCC:
break;
case OP65_BCS:
break;
case OP65_BEQ:
break;
case OP65_BIT:
break;
case OP65_BMI:
break;
case OP65_BNE:
break;
case OP65_BPL:
break;
case OP65_BRA:
break;
case OP65_BRK:
break;
case OP65_BVC:
break;
case OP65_BVS:
break;
case OP65_CLC:
break;
case OP65_CLD:
break;
case OP65_CLI:
break;
case OP65_CLV:
break;
case OP65_CMP:
break;
case OP65_CPX:
break;
case OP65_CPY:
break;
case OP65_DEA:
DEC (RegA, 1);
break;
case OP65_DEC:
break;
case OP65_DEX:
DEC (RegX, 1);
break;
case OP65_DEY:
DEC (RegY, 1);
break;
case OP65_EOR:
if (RegA >= 0) {
if (IsKnownImm (E)) {
RegA ^= (int) E->Num;
} else {
RegA = -1;
}
}
break;
case OP65_INA:
INC (RegA, 1);
break;
case OP65_INC:
break;
case OP65_INX:
INC (RegX, 1);
break;
case OP65_INY:
INC (RegY, 1);
break;
case OP65_JCC:
break;
case OP65_JCS:
break;
case OP65_JEQ:
break;
case OP65_JMI:
break;
case OP65_JMP:
break;
case OP65_JNE:
break;
case OP65_JPL:
break;
case OP65_JSR:
/* Get the code info for the function */
GetFuncInfo (E->Arg, &Use, &Chg);
if (Chg & REG_A) {
RegA = -1;
}
if (Chg & REG_X) {
RegX = -1;
}
if (Chg & REG_Y) {
RegY = -1;
}
break;
case OP65_JVC:
break;
case OP65_JVS:
break;
case OP65_LDA:
if (IsKnownImm (E)) {
CodeEntry* N = CS_GetNextEntry (S, I);
if (RegA >= 0 && RegA == E->Num && N && (N->Info & OF_FBRA) == 0) {
Delete = 1;
} else {
RegA = (unsigned char) E->Num;
}
} else {
/* A is now unknown */
RegA = -1;
}
break;
case OP65_LDX:
if (IsKnownImm (E)) {
CodeEntry* N = CS_GetNextEntry (S, I);
if (RegX >= 0 && RegX == E->Num && N && (N->Info & OF_FBRA) == 0) {
Delete = 1;
} else {
RegX = (unsigned char) E->Num;
}
} else {
/* X is now unknown */
RegX = -1;
}
break;
case OP65_LDY:
if (IsKnownImm (E)) {
CodeEntry* N = CS_GetNextEntry (S, I);
if (RegY >= 0 && RegY == E->Num && N && (N->Info & OF_FBRA) == 0) {
Delete = 1;
} else {
RegY = (unsigned char) E->Num;
}
} else {
/* Y is now unknown */
RegY = -1;
}
break;
case OP65_LSR:
if (RegA >= 0) {
RegA = (RegA >> 1) & 0xFF;
}
break;
case OP65_NOP:
break;
case OP65_ORA:
if (RegA >= 0) {
if (IsKnownImm (E)) {
RegA |= (unsigned char) E->Num;
} else {
/* A is now unknown */
RegA = -1;
}
}
break;
case OP65_PHA:
break;
case OP65_PHP:
break;
case OP65_PHX:
break;
case OP65_PHY:
break;
case OP65_PLA:
RegA = -1;
break;
case OP65_PLP:
break;
case OP65_PLX:
RegX = -1;
break;
case OP65_PLY:
RegY = -1;
break;
case OP65_ROL:
RegA = -1;
break;
case OP65_ROR:
RegA = -1;
break;
case OP65_RTI:
break;
case OP65_RTS:
break;
case OP65_SBC:
RegA = -1;
break;
case OP65_SEC:
break;
case OP65_SED:
break;
case OP65_SEI:
break;
case OP65_STA:
break;
case OP65_STX:
/* If the value in the X register is known and the same as
* that in the A register, replace the store by a STA. The
* optimizer will then remove the load instruction for X
* later. STX does support the zeropage,y addressing mode,
* so be sure to check for that.
*/
if (RegX >= 0 && RegX == RegA &&
E->AM != AM65_ABSY && E->AM != AM65_ZPY) {
/* Use the A register instead */
CE_ReplaceOPC (E, OP65_STA);
}
break;
case OP65_STY:
/* If the value in the Y register is known and the same as
* that in the A register, replace the store by a STA. The
* optimizer will then remove the load instruction for Y
* later.
*/
if (RegY >= 0 && RegY == RegA) {
CE_ReplaceOPC (E, OP65_STA);
}
break;
case OP65_TAX:
RegX = RegA;
break;
case OP65_TAY:
RegY = RegA;
break;
case OP65_TRB:
break;
case OP65_TSB:
break;
case OP65_TSX:
RegX = -1;
break;
case OP65_TXA:
RegA = RegX;
break;
case OP65_TXS:
break;
case OP65_TYA:
RegA = RegY;
break;
default:
break;
}
/* Delete the entry if requested */
if (Delete) {
/* Register value is not used, remove the load */
CS_DelEntry (S, I);
/* Remember, we had changes */
++Changes;
} else {
/* Next entry */
++I;
}
}
@ -678,7 +1096,7 @@ unsigned OptBranchDist (CodeSeg* S)
unsigned J = I;
while (J < TI) {
CodeEntry* N = CS_GetEntry (S, J++);
Distance += N->Size;
Distance += N->Size;
}
} else {
/* Backward branch */

View File

@ -51,7 +51,7 @@
unsigned OptRTSJumps (CodeSeg* S);
/* Replace jumps to RTS by RTS */
unsigned OptDeadJumps (CodeSeg* S);
unsigned OptDeadJumps (CodeSeg* S);
/* Remove dead jumps (jumps to the next instruction) */
unsigned OptDeadCode (CodeSeg* S);
@ -89,6 +89,9 @@ unsigned OptCondBranches (CodeSeg* S);
unsigned OptUnusedLoads (CodeSeg* S);
/* Remove loads of registers where the value loaded is not used later. */
unsigned OptDuplicateLoads (CodeSeg* S);
/* Remove loads of registers where the value loaded is already in the register. */
unsigned OptBranchDist (CodeSeg* S);
/* Change branches for the distance needed. */

View File

@ -169,6 +169,7 @@ typedef enum {
AM65_IMM, /* immidiate */
AM65_ZP, /* zeropage */
AM65_ZPX, /* zeropage,X */
AM65_ZPY, /* zeropage,Y */
AM65_ABS, /* absolute */
AM65_ABSX, /* absolute,X */
AM65_ABSY, /* absolute,Y */