unsigned OptSub3 (CodeSeg* S) /* Search for a call to decaxn and replace it by an 8 bit sub if the X register ** is not used later. */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* E; /* Get next entry */ E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_JSR && strncmp (E->Arg, "decax", 5) == 0 && IsDigit (E->Arg[5]) && E->Arg[6] == '\0' && !RegXUsed (S, I+1)) { CodeEntry* X; const char* Arg; /* Insert new code behind the sequence */ X = NewCodeEntry (OP65_SEC, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+1); Arg = MakeHexArg (E->Arg[5] - '0'); X = NewCodeEntry (OP65_SBC, AM65_IMM, Arg, 0, E->LI); CS_InsertEntry (S, X, I+2); /* Delete the old code */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
static unsigned OptLoad1 (CodeSeg* S) /* Search for a call to ldaxysp where X is not used later and replace it by ** a load of just the A register. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* E; /* Get next entry */ E = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (E, "ldaxysp") && RegValIsKnown (E->RI->In.RegY) && !RegXUsed (S, I+1)) { CodeEntry* X; /* Reload the Y register */ const char* Arg = MakeHexArg (E->RI->In.RegY - 1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); CS_InsertEntry (S, X, I+1); /* Load from stack */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI); CS_InsertEntry (S, X, I+2); /* Now remove the call to the subroutine */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptStore3 (CodeSeg* S) /* Search for a call to steaxysp. If the eax register is not used later, and ** the value is constant, just use the A register and store directly into the ** stack. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ 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; /* Check for the call */ if (CE_IsCallTo (E, "steaxysp") && RegValIsKnown (RI->In.RegA) && RegValIsKnown (RI->In.RegX) && RegValIsKnown (RI->In.RegY) && RegValIsKnown (RI->In.SRegLo) && RegValIsKnown (RI->In.SRegHi) && !RegEAXUsed (S, I+1)) { /* Get the register values */ unsigned char A = (unsigned char) RI->In.RegA; unsigned char X = (unsigned char) RI->In.RegX; unsigned char Y = (unsigned char) RI->In.RegY; unsigned char L = (unsigned char) RI->In.SRegLo; unsigned char H = (unsigned char) RI->In.SRegHi; /* Setup other variables */ unsigned Done = 0; CodeEntry* N; unsigned IP = I + 1; /* Insertion point */ /* Replace the store. We will not remove the loads, since this is ** too complex and will be done by other optimizer steps. */ N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (A), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x01; /* Check if we can store one of the other bytes */ if (A == X && (Done & 0x02) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x02; } if (A == L && (Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } if (A == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the second byte */ if ((Done & 0x02) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (X), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+1), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x02; } /* Check if we can store one of the other bytes */ if (X == L && (Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } if (X == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the third byte */ if ((Done & 0x04) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (L), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+2), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x04; } /* Check if we can store one of the other bytes */ if (L == H && (Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Store the fourth byte */ if ((Done & 0x08) == 0) { N = NewCodeEntry (OP65_LDA, AM65_IMM, MakeHexArg (H), 0, E->LI); CS_InsertEntry (S, N, IP++); N = NewCodeEntry (OP65_LDY, AM65_IMM, MakeHexArg (Y+3), 0, E->LI); CS_InsertEntry (S, N, IP++); InsertStore (S, &IP, E->LI); Done |= 0x08; } /* Remove the call */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
static unsigned OptStackPtrOps (CodeSeg* S) /* Merge adjacent calls to decsp into one. NOTE: This function won't merge all ** known cases! */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { unsigned Dec1; unsigned Dec2; const CodeEntry* N; /* Get the next entry */ const CodeEntry* E = CS_GetEntry (S, I); /* Check for decspn or subysp */ if (E->OPC == OP65_JSR && (Dec1 = IsDecSP (E)) > 0 && (N = CS_GetNextEntry (S, I)) != 0 && (Dec2 = IsDecSP (N)) > 0 && (Dec1 += Dec2) <= 255 && !CE_HasLabel (N)) { CodeEntry* X; char Buf[20]; /* We can combine the two */ if (Dec1 <= 8) { /* Insert a call to decsp */ xsprintf (Buf, sizeof (Buf), "decsp%u", Dec1); X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, N->LI); CS_InsertEntry (S, X, I+2); } else { /* Insert a call to subysp */ const char* Arg = MakeHexArg (Dec1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI); CS_InsertEntry (S, X, I+2); X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, N->LI); CS_InsertEntry (S, X, I+3); } /* Delete the old code */ CS_DelEntries (S, I, 2); /* Regenerate register info */ CS_GenRegInfo (S); /* Remember we had changes */ ++Changes; } else { /* Next entry */ ++I; } } /* Return the number of changes made */ return Changes; }
static unsigned OptDecouple (CodeSeg* S) /* Decouple operations, that is, do the following replacements: ** ** dex -> ldx #imm ** inx -> ldx #imm ** dey -> ldy #imm ** iny -> ldy #imm ** tax -> ldx #imm ** txa -> lda #imm ** tay -> ldy #imm ** tya -> lda #imm ** lda zp -> lda #imm ** ldx zp -> ldx #imm ** ldy zp -> ldy #imm ** ** Provided that the register values are known of course. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { const char* Arg; /* Get next entry and it's input register values */ CodeEntry* E = CS_GetEntry (S, I); const RegContents* In = &E->RI->In; /* Assume we have no replacement */ CodeEntry* X = 0; /* Check the instruction */ switch (E->OPC) { case OP65_DEA: if (RegValIsKnown (In->RegA)) { Arg = MakeHexArg ((In->RegA - 1) & 0xFF); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; case OP65_DEX: if (RegValIsKnown (In->RegX)) { Arg = MakeHexArg ((In->RegX - 1) & 0xFF); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_DEY: if (RegValIsKnown (In->RegY)) { Arg = MakeHexArg ((In->RegY - 1) & 0xFF); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } break; case OP65_INA: if (RegValIsKnown (In->RegA)) { Arg = MakeHexArg ((In->RegA + 1) & 0xFF); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; case OP65_INX: if (RegValIsKnown (In->RegX)) { Arg = MakeHexArg ((In->RegX + 1) & 0xFF); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_INY: if (RegValIsKnown (In->RegY)) { Arg = MakeHexArg ((In->RegY + 1) & 0xFF); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } break; case OP65_LDA: if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Arg = MakeHexArg (In->Tmp1); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_LO: Arg = MakeHexArg (In->Ptr1Lo); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_HI: Arg = MakeHexArg (In->Ptr1Hi); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_LO: Arg = MakeHexArg (In->SRegLo); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_HI: Arg = MakeHexArg (In->SRegHi); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); break; } } break; case OP65_LDX: if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use & REG_ZP, In)) { case REG_TMP1: Arg = MakeHexArg (In->Tmp1); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_LO: Arg = MakeHexArg (In->Ptr1Lo); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_HI: Arg = MakeHexArg (In->Ptr1Hi); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_LO: Arg = MakeHexArg (In->SRegLo); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_HI: Arg = MakeHexArg (In->SRegHi); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); break; } } break; case OP65_LDY: if (E->AM == AM65_ZP) { switch (GetKnownReg (E->Use, In)) { case REG_TMP1: Arg = MakeHexArg (In->Tmp1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_LO: Arg = MakeHexArg (In->Ptr1Lo); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); break; case REG_PTR1_HI: Arg = MakeHexArg (In->Ptr1Hi); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_LO: Arg = MakeHexArg (In->SRegLo); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); break; case REG_SREG_HI: Arg = MakeHexArg (In->SRegHi); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); break; } } break; case OP65_TAX: if (E->RI->In.RegA >= 0) { Arg = MakeHexArg (In->RegA); X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TAY: if (E->RI->In.RegA >= 0) { Arg = MakeHexArg (In->RegA); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TXA: if (E->RI->In.RegX >= 0) { Arg = MakeHexArg (In->RegX); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; case OP65_TYA: if (E->RI->In.RegY >= 0) { Arg = MakeHexArg (In->RegY); X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI); } break; default: /* Avoid gcc warnings */ break; } /* Insert the replacement if we have one */ if (X) { CS_InsertEntry (S, X, I+1); CS_DelEntry (S, I); ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptPush1 (CodeSeg* S) /* Given a sequence * * jsr ldaxysp * jsr pushax * * If a/x are not used later, and Y is known, replace that by * * ldy #xx+2 * jsr pushwysp * * saving 3 bytes and several cycles. */ { unsigned I; unsigned Changes = 0; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[2]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "ldaxysp") && RegValIsKnown (L[0]->RI->In.RegY) && L[0]->RI->In.RegY < 0xFE && (L[1] = CS_GetNextEntry (S, I)) != 0 && !CE_HasLabel (L[1]) && CE_IsCallTo (L[1], "pushax") && !RegAXUsed (S, I+2)) { /* Insert new code behind the pushax */ const char* Arg; CodeEntry* X; /* ldy #xx+1 */ Arg = MakeHexArg (L[0]->RI->In.RegY+2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+2); /* jsr pushwysp */ X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwysp", 0, L[1]->LI); CS_InsertEntry (S, X, I+3); /* Delete the old code */ CS_DelEntries (S, I, 2); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd1 (CodeSeg* S) /* Search for the sequence * * ldy #xx * jsr ldaxysp * jsr pushax * ldy #yy * jsr ldaxysp * jsr tosaddax * * and replace it by: * * ldy #xx-1 * lda (sp),y * ldy #yy-3 * clc * adc (sp),y * pha * ldy #xx * lda (sp),y * ldy #yy-2 * adc (sp),y * tax * pla */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[6]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CE_IsConstImm (L[0]) && !CS_RangeHasLabel (S, I+1, 5) && CS_GetEntries (S, L+1, I+1, 5) && CE_IsCallTo (L[1], "ldaxysp") && CE_IsCallTo (L[2], "pushax") && L[3]->OPC == OP65_LDY && CE_IsConstImm (L[3]) && CE_IsCallTo (L[4], "ldaxysp") && CE_IsCallTo (L[5], "tosaddax")) { CodeEntry* X; const char* Arg; /* Correct the stack of the first Y register load */ CE_SetNumArg (L[0], L[0]->Num - 1); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+1); /* ldy #yy-3 */ Arg = MakeHexArg (L[3]->Num - 3); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+2); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+3); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI); CS_InsertEntry (S, X, I+4); /* pha */ X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+5); /* ldy #xx (beware: L[0] has changed) */ Arg = MakeHexArg (L[0]->Num + 1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI); CS_InsertEntry (S, X, I+6); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+7); /* ldy #yy-2 */ Arg = MakeHexArg (L[3]->Num - 2); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI); CS_InsertEntry (S, X, I+8); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI); CS_InsertEntry (S, X, I+9); /* tax */ X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+10); /* pla */ X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[5]->LI); CS_InsertEntry (S, X, I+11); /* Delete the old code */ CS_DelEntries (S, I+12, 5); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd2 (CodeSeg* S) /* Search for the sequence * * ldy #xx * jsr ldaxysp * ldy #yy * jsr addeqysp * * and replace it by: * * ldy #xx-1 * lda (sp),y * ldy #yy * clc * adc (sp),y * sta (sp),y * ldy #xx * lda (sp),y * ldy #yy+1 * adc (sp),y * sta (sp),y * * provided that a/x is not used later. */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[4]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (L[0]->OPC == OP65_LDY && CE_IsConstImm (L[0]) && !CS_RangeHasLabel (S, I+1, 3) && CS_GetEntries (S, L+1, I+1, 3) && CE_IsCallTo (L[1], "ldaxysp") && L[2]->OPC == OP65_LDY && CE_IsConstImm (L[2]) && CE_IsCallTo (L[3], "addeqysp") && (GetRegInfo (S, I+4, REG_AX) & REG_AX) == 0) { /* Insert new code behind the addeqysp */ const char* Arg; CodeEntry* X; /* ldy #xx-1 */ Arg = MakeHexArg (L[0]->Num-1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+4); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+5); /* ldy #yy */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[2]->Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+6); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+8); /* sta (sp),y */ X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+9); /* ldy #xx */ X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI); CS_InsertEntry (S, X, I+10); /* lda (sp),y */ X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI); CS_InsertEntry (S, X, I+11); /* ldy #yy+1 */ Arg = MakeHexArg (L[2]->Num+1); X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[2]->LI); CS_InsertEntry (S, X, I+12); /* adc (sp),y */ X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+13); /* sta (sp),y */ X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI); CS_InsertEntry (S, X, I+14); /* Delete the old code */ CS_DelEntries (S, I, 4); /* Remember, we had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }