static OptFunc DOptSub1 = { OptSub1, "OptSub1", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptSub2 = { OptSub2, "OptSub2", 100, 0, 0, 0, 0, 0 };
static OptFunc DOptTest1 = { OptTest1, "OptTest1", 100, 0, 0, 0, 0, 0 };
-static OptFunc DOptTransfers = { OptTransfers, "OptTransfers", 0, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers1 = { OptTransfers1, "OptTransfers1", 0, 0, 0, 0, 0, 0 };
+static OptFunc DOptTransfers2 = { OptTransfers2, "OptTransfers2", 60, 0, 0, 0, 0, 0 };
static OptFunc DOptUnusedLoads = { OptUnusedLoads, "OptUnusedLoads", 0, 0, 0, 0, 0, 0 };
static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores", 0, 0, 0, 0, 0, 0 };
&DOptSub1,
&DOptSub2,
&DOptTest1,
- &DOptTransfers,
+ &DOptTransfers1,
+ &DOptTransfers2,
&DOptUnusedLoads,
&DOptUnusedStores,
};
/* Write a header */
fprintf (F,
- "; Optimizer Total Last Total Last\n"
- "; Step Runs Runs Chg Chg\n");
+ "; Optimizer Total Last Total Last\n"
+ "; Step Runs Runs Chg Chg\n");
/* Write the data */
for (I = 0; I < OPTFUNC_COUNT; ++I) {
const OptFunc* O = OptFuncs[I];
fprintf (F,
- "%-20s %6lu %6lu %6lu %6lu\n",
+ "%-20s %10lu %10lu %10lu %10lu\n",
O->Name,
O->TotalRuns,
O->LastRuns,
C += RunOptFunc (S, &DOptUnusedStores, 1);
C += RunOptFunc (S, &DOptDupLoads, 1);
C += RunOptFunc (S, &DOptStoreLoad, 1);
- C += RunOptFunc (S, &DOptTransfers, 1);
+ C += RunOptFunc (S, &DOptTransfers1, 1);
C += RunOptFunc (S, &DOptPushPop, 1);
Changes += C;
Changes += RunOptFunc (S, &DOptPush1, 1);
Changes += RunOptFunc (S, &DOptPush2, 1);
Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
+ Changes += RunOptFunc (S, &DOptTransfers2, 1);
/* Return the number of changes */
return Changes;
-unsigned OptTransfers (CodeSeg* S)
+unsigned OptTransfers1 (CodeSeg* S)
/* Remove transfers from one register to another and back */
{
unsigned Changes = 0;
/* Get next entry */
CodeEntry* E = CS_GetEntry (S, I);
- /* Check if it is a store instruction followed by a load from the
- * same address which is itself not followed by a conditional branch.
- */
+ /* Check if we have two transfer instructions */
if ((E->Info & OF_XFR) != 0 &&
(N = CS_GetNextEntry (S, I)) != 0 &&
!CE_HasLabel (N) &&
+unsigned OptTransfers2 (CodeSeg* S)
+/* Replace loads followed by a register transfer by a load with the second
+ * register if possible.
+ */
+{
+ unsigned Changes = 0;
+
+ /* Walk over the entries */
+ unsigned I = 0;
+ while (I < CS_GetEntryCount (S)) {
+
+ CodeEntry* N;
+
+ /* Get next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if we have a load followed by a transfer where the loaded
+ * register is not used later.
+ */
+ if ((E->Info & OF_LOAD) != 0 &&
+ (N = CS_GetNextEntry (S, I)) != 0 &&
+ !CE_HasLabel (N) &&
+ (N->Info & OF_XFR) != 0 &&
+ GetRegInfo (S, I+2, E->Chg) != E->Chg) {
+
+ CodeEntry* X = 0;
+
+ if (E->OPC == OP65_LDA && N->OPC == OP65_TAX) {
+ /* LDA/TAX - check for the right addressing modes */
+ if (E->AM == AM65_IMM ||
+ E->AM == AM65_ZP ||
+ E->AM == AM65_ABS ||
+ E->AM == AM65_ABSY) {
+ /* Replace */
+ X = NewCodeEntry (OP65_LDX, E->AM, E->Arg, 0, N->LI);
+ }
+ } else if (E->OPC == OP65_LDA && N->OPC == OP65_TAY) {
+ /* LDA/TAY - check for the right addressing modes */
+ if (E->AM == AM65_IMM ||
+ E->AM == AM65_ZP ||
+ E->AM == AM65_ZPX ||
+ E->AM == AM65_ABS ||
+ E->AM == AM65_ABSX) {
+ /* Replace */
+ X = NewCodeEntry (OP65_LDY, E->AM, E->Arg, 0, N->LI);
+ }
+ } else if (E->OPC == OP65_LDY && N->OPC == OP65_TYA) {
+ /* LDY/TYA. LDA supports all addressing modes LDY does */
+ X = NewCodeEntry (OP65_LDA, E->AM, E->Arg, 0, N->LI);
+ } else if (E->OPC == OP65_LDX && N->OPC == OP65_TXA) {
+ /* LDX/TXA. LDA doesn't support zp,y, so we must map it to
+ * abs,y instead.
+ */
+ am_t AM = (E->AM == AM65_ZPY)? AM65_ABSY : E->AM;
+ X = NewCodeEntry (OP65_LDA, AM, E->Arg, 0, N->LI);
+ }
+
+ /* If we have a load entry, add it and remove the old stuff */
+ if (X) {
+ CS_InsertEntry (S, X, I+2);
+ CS_DelEntries (S, I, 2);
+ ++Changes;
+ --I; /* Correct for one entry less */
+ }
+ }
+
+ /* Next entry */
+ ++I;
+ }
+
+ /* Return the number of changes made */
+ return Changes;
+}
+
+
+
unsigned OptPushPop (CodeSeg* S)
/* Remove a PHA/PLA sequence were A is not used later */
{
} else if (E->AM == AM65_ZP) {
int R = ZPRegVal (E->Use, In);
if (RegValIsKnown (R)) {
- printf ("A: %02X tmp1: %02X\n", In->RegA, R);
/* Accu EOR zp with known contents */
Arg = MakeHexArg (In->RegA ^ R);
}
unsigned OptStoreLoad (CodeSeg* S);
/* Remove a store followed by a load from the same location. */
-unsigned OptTransfers (CodeSeg* S);
+unsigned OptTransfers1 (CodeSeg* S);
/* Remove transfers from one register to another and back */
+unsigned OptTransfers2 (CodeSeg* S);
+/* Replace loads followed by a register transfer by a load with the second
+ * register if possible.
+ */
+
unsigned OptPushPop (CodeSeg* S);
/* Remove a PHA/PLA sequence were A is not used later */