Skip to content

Commit

Permalink
Merge pull request cc65#2522 from kugelfuhr/kugelfuhr/code-optimizations
Browse files Browse the repository at this point in the history
Improve generated code for AND/EOR/ORA
  • Loading branch information
mrdudz authored Oct 5, 2024
2 parents 270aa44 + 231ab41 commit 4dfbccf
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 17 deletions.
18 changes: 18 additions & 0 deletions src/cc65/codeent.c
Original file line number Diff line number Diff line change
Expand Up @@ -2445,6 +2445,24 @@ static char* RegContentDesc (const RegContents* RC, char* Buf)
sprintf (B, "Y:%02X ", RC->RegY);
}
B += 5;
if (RegValIsUnknown (RC->Ptr1Lo)) {
strcpy (B, "P1L:XX ");
} else {
sprintf (B, "P1L:%02X ", RC->Ptr1Lo);
}
B += 7;
if (RegValIsUnknown (RC->Ptr1Hi)) {
strcpy (B, "P1H:XX ");
} else {
sprintf (B, "P1H:%02X ", RC->Ptr1Hi);
}
B += 7;
if (RegValIsUnknown (RC->Tmp1)) {
strcpy (B, "T1:XX ");
} else {
sprintf (B, "T1:%02X ", RC->Tmp1);
}
B += 6;
if (PStatesAreUnknown (RC->PFlags, PSTATE_C)) {
strcpy (B, "~");
} else {
Expand Down
24 changes: 13 additions & 11 deletions src/cc65/codeinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,11 +560,8 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
*Use = REG_NONE;
}

/* Will destroy all registers */
*Chg = REG_ALL;

/* and will destroy all processor flags */
*Chg |= PSTATE_ALL;
/* Will destroy all registers and processor flags */
*Chg = (REG_ALL | PSTATE_ALL);

/* Done */
return FNCLS_GLOBAL;
Expand All @@ -577,8 +574,7 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
** are used mostly in inline assembly anyway.
*/
*Use = REG_ALL;
*Chg = REG_ALL;
*Chg |= PSTATE_ALL;
*Chg = (REG_ALL | PSTATE_ALL);
return FNCLS_NUMERIC;

} else {
Expand All @@ -605,8 +601,7 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
fprintf (stderr, "No info about internal function '%s'\n", Name);
}
*Use = REG_ALL;
*Chg = REG_ALL;
*Chg |= PSTATE_ALL;
*Chg = (REG_ALL | PSTATE_ALL);
}
return FNCLS_BUILTIN;
}
Expand All @@ -615,8 +610,7 @@ fncls_t GetFuncInfo (const char* Name, unsigned int* Use, unsigned int* Chg)
** registers and processor flags are changed
*/
*Use = REG_EAXY;
*Chg = REG_ALL;
*Chg |= PSTATE_ALL;
*Chg = (REG_ALL | PSTATE_ALL);

return FNCLS_UNKNOWN;
}
Expand Down Expand Up @@ -899,6 +893,14 @@ int RegEAXUsed (struct CodeSeg* S, unsigned Index)



int LoadFlagsUsed (struct CodeSeg* S, unsigned Index)
/* Check if one of the flags set by a register load (Z and N) are used. */
{
return (GetRegInfo (S, Index, PSTATE_ZN) & PSTATE_ZN) != 0;
}



unsigned GetKnownReg (unsigned Use, const RegContents* RC)
/* Return the register or zero page location from the set in Use, thats
** contents are known. If Use does not contain any register, or if the
Expand Down
3 changes: 3 additions & 0 deletions src/cc65/codeinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ int RegAXUsed (struct CodeSeg* S, unsigned Index);
int RegEAXUsed (struct CodeSeg* S, unsigned Index);
/* Check if any of the four bytes in EAX are used. */

int LoadFlagsUsed (struct CodeSeg* S, unsigned Index);
/* Check if one of the flags set by a register load (Z and N) are used. */

unsigned GetKnownReg (unsigned Use, const struct RegContents* RC);
/* Return the register or zero page location from the set in Use, thats
** contents are known. If Use does not contain any register, or if the
Expand Down
8 changes: 8 additions & 0 deletions src/cc65/codeopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ static OptFunc DOptBNegAX1 = { OptBNegAX1, "OptBNegAX1", 100, 0,
static OptFunc DOptBNegAX2 = { OptBNegAX2, "OptBNegAX2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBNegAX3 = { OptBNegAX3, "OptBNegAX3", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBNegAX4 = { OptBNegAX4, "OptBNegAX4", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBinOps = { OptBinOps, "OptBinOps", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptBoolCmp = { OptBoolCmp, "OptBoolCmp", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBoolTrans = { OptBoolTrans, "OptBoolTrans", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptBoolUnary1 = { OptBoolUnary1, "OptBoolUnary1", 40, 0, 0, 0, 0, 0 };
Expand Down Expand Up @@ -179,6 +180,7 @@ static OptFunc DOptPush1 = { OptPush1, "OptPush1", 65, 0,
static OptFunc DOptPush2 = { OptPush2, "OptPush2", 50, 0, 0, 0, 0, 0 };
static OptFunc DOptPushPop1 = { OptPushPop1, "OptPushPop1", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptPushPop2 = { OptPushPop2, "OptPushPop2", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptPushPop3 = { OptPushPop3, "OptPushPop3", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptRTS = { OptRTS, "OptRTS", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptRTSJumps1 = { OptRTSJumps1, "OptRTSJumps1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptRTSJumps2 = { OptRTSJumps2, "OptRTSJumps2", 100, 0, 0, 0, 0, 0 };
Expand Down Expand Up @@ -231,6 +233,7 @@ static OptFunc* OptFuncs[] = {
&DOptBNegAX2,
&DOptBNegAX3,
&DOptBNegAX4,
&DOptBinOps,
&DOptBoolCmp,
&DOptBoolTrans,
&DOptBoolUnary1,
Expand Down Expand Up @@ -292,6 +295,8 @@ static OptFunc* OptFuncs[] = {
&DOptPush1,
&DOptPush2,
&DOptPushPop1,
&DOptPushPop2,
&DOptPushPop3,
&DOptRTS,
&DOptRTSJumps1,
&DOptRTSJumps2,
Expand Down Expand Up @@ -740,9 +745,11 @@ static unsigned RunOptGroup3 (CodeSeg* S)
C += RunOptFunc (S, &DOptStore5, 1);
C += RunOptFunc (S, &DOptPushPop1, 1);
C += RunOptFunc (S, &DOptPushPop2, 1);
C += RunOptFunc (S, &DOptPushPop3, 1);
C += RunOptFunc (S, &DOptPrecalc, 1);
C += RunOptFunc (S, &DOptShiftBack, 1);
C += RunOptFunc (S, &DOptSignExtended, 1);
C += RunOptFunc (S, &DOptBinOps, 1);

Changes += C;

Expand Down Expand Up @@ -849,6 +856,7 @@ static unsigned RunOptGroup7 (CodeSeg* S)
Changes += RunOptFunc (S, &DOptUnusedStores, 1);
Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
Changes += RunOptFunc (S, &DOptStore5, 1);
Changes += RunOptFunc (S, &DOptTransfers1, 1);
}

C = RunOptFunc (S, &DOptSize2, 1);
Expand Down
110 changes: 105 additions & 5 deletions src/cc65/coptind.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ static short ZPRegVal (unsigned short Use, const RegContents* RC)


unsigned OptUnusedLoads (CodeSeg* S)
/* Remove loads of registers where the value loaded is not used later. */
/* Remove loads of or operations with registers where the value loaded or
** produced is not used later.
*/
{
unsigned Changes = 0;

Expand All @@ -164,17 +166,24 @@ unsigned OptUnusedLoads (CodeSeg* S)
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);

/* Check if it's a register load or transfer insn */
if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 &&
(N = CS_GetNextEntry (S, I)) != 0 &&
!CE_UseLoadFlags (N)) {
/* Check if this is one of the instruction we can operate on */
int IsOp = (E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 ||
E->OPC == OP65_AND ||
E->OPC == OP65_EOR ||
E->OPC == OP65_ORA;

/* Check for the necessary preconditions */
if (IsOp && (N = CS_GetNextEntry (S, I)) != 0 && !LoadFlagsUsed (S, I+1)) {

/* Check which sort of load or transfer it is */
unsigned R;
switch (E->OPC) {
case OP65_AND:
case OP65_DEA:
case OP65_EOR:
case OP65_INA:
case OP65_LDA:
case OP65_ORA:
case OP65_TXA:
case OP65_TYA: R = REG_A; break;
case OP65_DEX:
Expand Down Expand Up @@ -1342,6 +1351,97 @@ unsigned OptPushPop2 (CodeSeg* S)



unsigned OptPushPop3 (CodeSeg* S)
/* Remove a pha/pla sequence where the contents of A are known */
{
unsigned Changes = 0;
unsigned Pha = 0; /* Index of PHA insn */
unsigned Pla = 0; /* Index of PLA insn */
CodeEntry* PhaEntry = 0; /* Pointer to PHA */

enum {
Searching,
FoundPha,
FoundPla
} State = Searching;

/* Walk over the entries. Look for a PHA instruction where the contents
** of A is known followed by a PLA later.
*/
unsigned I = 0;
while (I < CS_GetEntryCount (S)) {

/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);

/* Get the input registers */
const RegInfo* RI = E->RI;


const char* Arg;
CodeEntry* X;
switch (State) {

case Searching:
if (E->OPC == OP65_PHA && RegValIsKnown (RI->In.RegA)) {
/* Found start of sequence */
Pha = I;
PhaEntry = E;
State = FoundPha;
}
break;

case FoundPha:
/* Check for several things that abort the sequence:
** - End of the basic block
** - Another PHA or any other stack manipulating instruction
** If we find something that aborts the sequence, start over
** searching for the next PHA.
*/
if (CE_HasLabel (E)) {
/* Switch back to searching at this instruction */
State = Searching;
continue;
}
if (E->OPC == OP65_PHA) {
/* Start over at this instruction */
State = Searching;
continue;
}
if (E->OPC == OP65_PHP || E->OPC == OP65_PLP || E->OPC == OP65_TXS) {
/* Start over at the next instruction */
State = Searching;
} else if (E->OPC == OP65_PLA) {
/* Switch state. This will also switch to the next insn
** which is ok.
*/
Pla = I;
State = FoundPla;
}
break;

case FoundPla:
/* We found the sequence we were looking for. Replace it. */
Arg = MakeHexArg (PhaEntry->RI->In.RegA);
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
CS_InsertEntry (S, X, Pla + 1);
CS_DelEntry (S, Pla);
CS_DelEntry (S, Pha);
++Changes;
State = Searching;
break;
}

/* Next entry */
++I;
}

/* Return the number of changes made */
return Changes;
}



unsigned OptPrecalc (CodeSeg* S)
/* Replace immediate operations with the accu where the current contents are
** known by a load of the final value.
Expand Down
7 changes: 6 additions & 1 deletion src/cc65/coptind.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@


unsigned OptUnusedLoads (CodeSeg* S);
/* Remove loads of registers where the value loaded is not used later. */
/* Remove loads of or operations with registers where the value loaded or
** produced is not used later.
*/

unsigned OptUnusedStores (CodeSeg* S);
/* Remove stores into zero page registers that aren't used later */
Expand Down Expand Up @@ -91,6 +93,9 @@ unsigned OptPushPop1 (CodeSeg* S);
unsigned OptPushPop2 (CodeSeg* S);
/* Remove a PHP/PLP sequence were no processor flags changed inside */

unsigned OptPushPop3 (CodeSeg* S);
/* Remove a pha/pla sequence where the contents of A are known */

unsigned OptPrecalc (CodeSeg* S);
/* Replace immediate operations with the accu where the current contents are
** known by a load of the final value.
Expand Down
Loading

0 comments on commit 4dfbccf

Please sign in to comment.