-static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const char* Arg)
-/* Checks a range of code entries if there are any memory accesses to Arg.
- * Note: This function is not 100% safe, because there is more than one way
- * to express a memory location ("foo" and "foo+0" comes to mind) and there
- * may be other accesses through pointers. For the code generated by cc65 and
- * for the purpose of the caller (OptPushPop) it is assumed to be safe enough
- * however.
- */
+static int MemAccess (CodeSeg* S, unsigned From, unsigned To, const CodeEntry* N)
+/* Checks a range of code entries if there are any memory accesses to N->Arg */
{
+ /* Get the length of the argument */
+ unsigned NLen = strlen (N->Arg);
+
+ /* What to check for? */
+ enum {
+ None = 0x00,
+ Base = 0x01, /* Check for location without "+1" */
+ Word = 0x02, /* Check for location with "+1" added */
+ } What = None;
+
+
+ /* If the argument of N is a zero page location that ends with "+1", we
+ * must also check for word accesses to the location without +1.
+ */
+ if (N->AM == AM65_ZP && NLen > 2 && strcmp (N->Arg + NLen - 2, "+1") == 0) {
+ What |= Base;
+ }
+
+ /* If the argument is zero page indirect, we must also check for accesses
+ * to "arg+1"
+ */
+ if (N->AM == AM65_ZP_INDY || N->AM == AM65_ZPX_IND || N->AM == AM65_ZP_IND) {
+ What |= Word;
+ }
+
/* Walk over all code entries */
while (From <= To) {
/* Get the next entry */
CodeEntry* E = CS_GetEntry (S, From);
- /* For simplicity, we just check if there is an argument and if this
- * argument equals Arg.
+ /* Check if there is an argument and if this argument equals Arg in
+ * some variants.
*/
- if (E->Arg && strcmp (E->Arg, Arg) == 0) {
- /* Found an access */
- return 1;
+ if (E->Arg[0] != '\0') {
+
+ unsigned ELen;
+
+ if (strcmp (E->Arg, N->Arg) == 0) {
+ /* Found an access */
+ return 1;
+ }
+
+ ELen = strlen (E->Arg);
+ if ((What & Base) != 0) {
+ if (ELen == NLen - 2 && strncmp (E->Arg, N->Arg, NLen-2) == 0) {
+ /* Found an access */
+ return 1;
+ }
+ }
+
+ if ((What & Word) != 0) {
+ if (ELen == NLen + 2 && strncmp (E->Arg, N->Arg, NLen) == 0 &&
+ E->Arg[NLen] == '+' && E->Arg[NLen+1] == '1') {
+ /* Found an access */
+ return 1;
+ }
+ }
}
/* Next entry */
* not already have one.
*/
TL1 = CS_GenLabel (S, T1);
- printf ("Generated label %s\n", TL1->Name);
/* Change the jump target to point to this new label */
CS_MoveLabelRef (S, E2, TL1);
+unsigned OptJumpTarget3 (CodeSeg* S)
+/* Jumps to load instructions of a register, that do already have the matching
+ * register contents may skip the load instruction, since it's job is already
+ * done.
+ */
+{
+ 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)) {
+
+ unsigned J, K;
+ CodeEntry* N;
+
+ /* New jump label */
+ CodeLabel* LN = 0;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this is a load insn with a label */
+ if ((E->Info & OF_LOAD) != 0 &&
+ CE_IsConstImm (E) &&
+ CE_HasLabel (E) &&
+ (N = CS_GetNextEntry (S, I)) != 0) {
+
+ /* Walk over all insn that jump here */
+ for (J = 0; J < CE_GetLabelCount (E); ++J) {
+
+ /* Get the label */
+ CodeLabel* L = CE_GetLabel (E, J);
+ for (K = 0; K < CL_GetRefCount (L); ++K) {
+
+ /* Get the entry that jumps here */
+ CodeEntry* Jump = CL_GetRef (L, K);
+
+ /* Get the register info from this insn */
+ short Val = RegVal (E->Chg, &Jump->RI->Out2);
+
+ /* Check if the outgoing value is the one thatr's loaded */
+ if (Val == (unsigned char) E->Num) {
+
+ /* Ok, skip the insn. First, generate a label */
+ if (LN == 0) {
+ LN = CS_GenLabel (S, N);
+ }
+
+ /* Change the jump target to point to this new label */
+ CS_MoveLabelRef (S, Jump, LN);
+
+ /* Remember that we had changes */
+ ++Changes;
+ }
+ }
+ }
+
+ }
+
+ /* Next entry */
+ ++I;
+ }
+
+ /* Free register info */
+ CS_FreeRegInfo (S);
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
/*****************************************************************************/
/* Optimize conditional branches */
/*****************************************************************************/
break;
case OP65_STA:
- /* If we store into a known zero page location, and this
+ /* If we store into a known zero page location, and this
* location does already contain the value to be stored,
* remove the store.
*/
* that in the A register, replace the store by a STA. The
* optimizer will then remove the load instruction for Y
* later. If replacement by A is not possible try a
- * replacement by X, but check for invalid addressing modes
+ * replacement by X, but check for invalid addressing modes
* in this case.
*/
} else if (RegValIsKnown (In->RegY)) {
!CE_UseLoadFlags (N)) {
/* Value is identical and not followed by a branch */
Delete = 1;
- }
- break;
+ }
+ break;
- case OP65_TYA:
+ case OP65_TYA:
if (RegValIsKnown (In->RegY) &&
In->RegY == In->RegA &&
- (N = CS_GetNextEntry (S, I)) != 0 &&
+ (N = CS_GetNextEntry (S, I)) != 0 &&
!CE_UseLoadFlags (N)) {
- /* Value is identical and not followed by a branch */
- Delete = 1;
- }
- break;
+ /* Value is identical and not followed by a branch */
+ Delete = 1;
+ }
+ break;
- default:
- break;
+ default:
+ break;
- }
+ }
- /* Delete the entry if requested */
- if (Delete) {
+ /* Delete the entry if requested */
+ if (Delete) {
- /* Register value is not used, remove the load */
- CS_DelEntry (S, I);
+ /* Register value is not used, remove the load */
+ CS_DelEntry (S, I);
- /* Remember, we had changes */
- ++Changes;
+ /* Remember, we had changes */
+ ++Changes;
- } else {
+ } else {
- /* Next entry */
- ++I;
+ /* Next entry */
+ ++I;
- }
+ }
}
StoreEntry->AM == AM65_ZP) &&
(StoreEntry->AM != AM65_ZP ||
(StoreEntry->Chg & UsedRegs) == 0) &&
- !MemAccess (S, Xfer+1, Store-1, StoreEntry->Arg)) {
+ !MemAccess (S, Xfer+1, Store-1, StoreEntry)) {
/* Generate the replacement store insn */
CodeEntry* X = 0;
(LoadEntry->AM == AM65_ABS ||
LoadEntry->AM == AM65_ZP ||
LoadEntry->AM == AM65_IMM) &&
- !MemAccess (S, Load+1, Xfer-1, LoadEntry->Arg)) {
+ !MemAccess (S, Load+1, Xfer-1, LoadEntry)) {
/* Generate the replacement load insn */
CodeEntry* X = 0;
*/
if (E->OPC == OP65_STA &&
!RegAUsed (S, I+1) &&
- !MemAccess (S, Push+1, Pop-1, E->Arg)) {
+ !MemAccess (S, Push+1, Pop-1, E)) {
/* Insert a STA after the PHA */
X = NewCodeEntry (E->OPC, E->AM, E->Arg, E->JumpTo, E->LI);