static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond) /* Helper function for the replacement of routines that return a boolean * followed by a conditional jump. Instead of the boolean value, the condition * codes are evaluated directly. * I is the index of the conditional branch, the sequence is already checked * to be correct. */ { CodeEntry* N; CodeLabel* L; /* Get the entry */ CodeEntry* E = CS_GetEntry (S, I); /* Replace the conditional branch */ switch (Cond) { case CMP_EQ: CE_ReplaceOPC (E, OP65_JEQ); break; case CMP_NE: CE_ReplaceOPC (E, OP65_JNE); break; case CMP_GT: /* Replace by * beq @L * jpl Target * @L: ... */ if ((N = CS_GetNextEntry (S, I)) == 0) { /* No such entry */ Internal ("Invalid program flow"); } L = CS_GenLabel (S, N); N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I); CE_ReplaceOPC (E, OP65_JPL); break; case CMP_GE: CE_ReplaceOPC (E, OP65_JPL); break; case CMP_LT: CE_ReplaceOPC (E, OP65_JMI); break; case CMP_LE: /* Replace by * jmi Target * jeq Target */ CE_ReplaceOPC (E, OP65_JMI); L = E->JumpTo; N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I+1); break; case CMP_UGT: /* Replace by * beq @L * jcs Target * @L: ... */ if ((N = CS_GetNextEntry (S, I)) == 0) { /* No such entry */ Internal ("Invalid program flow"); } L = CS_GenLabel (S, N); N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I); CE_ReplaceOPC (E, OP65_JCS); break; case CMP_UGE: CE_ReplaceOPC (E, OP65_JCS); break; case CMP_ULT: CE_ReplaceOPC (E, OP65_JCC); break; case CMP_ULE: /* Replace by * jcc Target * jeq Target */ CE_ReplaceOPC (E, OP65_JCC); L = E->JumpTo; N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, N, I+1); break; default: Internal ("Unknown jump condition: %d", Cond); } }
unsigned OptNegAX2 (CodeSeg* S) /* Search for a call to negax and replace it by * * ldx #$FF * eor #$FF * clc * adc #$01 * bne L1 * inx * L1: * * if X is known and zero on entry. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* P; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check if this is a call to negax, and if X is known and zero */ if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "negax") && (P = CS_GetNextEntry (S, I)) != 0) { CodeEntry* X; CodeLabel* L; /* Add replacement code behind */ /* ldx #$FF */ X = NewCodeEntry (OP65_LDX, AM65_IMM, "$FF", 0, E->LI); CS_InsertEntry (S, X, I+1); /* eor #$FF */ X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI); CS_InsertEntry (S, X, I+2); /* clc */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+3); /* adc #$01 */ X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI); CS_InsertEntry (S, X, I+4); /* Get the label attached to the insn following the call */ L = CS_GenLabel (S, P); /* bne L */ X = NewCodeEntry (OP65_BNE, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, X, I+5); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+6); /* Delete the call to negax */ CS_DelEntry (S, I); /* Skip the generated code */ I += 5; /* We had changes */ ++Changes; } /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptShift1 (CodeSeg* S) /* A call to the shlaxN routine may get replaced by one or more asl insns * if the value of X is not used later. If X is used later, but it is zero * on entry and it's a shift by one, it may get replaced by: * * asl a * bcc L1 * inx * L1: * */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { unsigned Shift; CodeEntry* N; CodeEntry* X; CodeLabel* L; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_JSR && (Shift = GetShift (E->Arg)) != SHIFT_NONE && SHIFT_DIR (Shift) == SHIFT_DIR_LEFT) { unsigned Count = SHIFT_COUNT (Shift); if (!RegXUsed (S, I+1)) { if (Count == SHIFT_COUNT_Y) { CodeLabel* L; if (S->CodeSizeFactor < 200) { goto NextEntry; } /* Change into * * L1: asl a * dey * bpl L1 * ror a */ /* asl a */ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+1); L = CS_GenLabel (S, X); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+2); /* bpl L1 */ X = NewCodeEntry (OP65_BPL, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, X, I+3); /* ror a */ X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+4); } else { /* Insert shift insns */ while (Count--) { X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+1); } } } else if (E->RI->In.RegX == 0 && Count == 1 && (N = CS_GetNextEntry (S, I)) != 0) { /* asl a */ X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+1); /* bcc L1 */ L = CS_GenLabel (S, N); X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, X, I+2); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+3); } else { /* We won't handle this one */ goto NextEntry; } /* Delete the call to shlax */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } NextEntry: /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptShift4 (CodeSeg* S) /* Calls to the asraxN or shraxN routines may get replaced by one or more lsr * insns if the value of X is zero. */ { unsigned Changes = 0; unsigned I; /* Walk over the entries */ I = 0; while (I < CS_GetEntryCount (S)) { unsigned Shift; unsigned Count; /* Get next entry */ CodeEntry* E = CS_GetEntry (S, I); /* Check for the sequence */ if (E->OPC == OP65_JSR && (Shift = GetShift (E->Arg)) != SHIFT_NONE && SHIFT_DIR (Shift) == SHIFT_DIR_RIGHT && E->RI->In.RegX == 0) { CodeEntry* X; /* Shift count may be in Y */ Count = SHIFT_COUNT (Shift); if (Count == SHIFT_COUNT_Y) { CodeLabel* L; if (S->CodeSizeFactor < 200) { /* Not acceptable */ goto NextEntry; } /* Generate: * * L1: lsr a * dey * bpl L1 * rol a * * A negative shift count or one that is greater or equal than * the bit width of the left operand (which is promoted to * integer before the operation) causes undefined behaviour, so * above transformation is safe. */ /* lsr a */ X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+1); L = CS_GenLabel (S, X); /* dey */ X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI); CS_InsertEntry (S, X, I+2); /* bpl L1 */ X = NewCodeEntry (OP65_BPL, AM65_BRA, L->Name, L, E->LI); CS_InsertEntry (S, X, I+3); /* rol a */ X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+4); } else { /* Insert shift insns */ while (Count--) { X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI); CS_InsertEntry (S, X, I+1); } } /* Delete the call to shrax */ CS_DelEntry (S, I); /* Remember, we had changes */ ++Changes; } NextEntry: /* Next entry */ ++I; } /* Return the number of changes made */ return Changes; }
unsigned OptAdd3 (CodeSeg* S) /* Search for the sequence * * jsr pushax * ldx #$00 * lda xxx * jsr tosaddax * * and replace it by * * clc * adc xxx * bcc L1 * inx * L1: */ { unsigned Changes = 0; /* Walk over the entries */ unsigned I = 0; while (I < CS_GetEntryCount (S)) { CodeEntry* L[5]; /* Get next entry */ L[0] = CS_GetEntry (S, I); /* Check for the sequence */ if (CE_IsCallTo (L[0], "pushax") && CS_GetEntries (S, L+1, I+1, 4) && !CS_RangeHasLabel (S, I+1, 3) && L[1]->OPC == OP65_LDX && CE_IsKnownImm (L[1], 0) && L[2]->OPC == OP65_LDA && CE_IsCallTo (L[3], "tosaddax")) { CodeEntry* X; CodeLabel* Label; /* Insert new code behind the sequence */ X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+4); /* adc xxx */ X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI); CS_InsertEntry (S, X, I+5); /* bcc L1 */ Label = CS_GenLabel (S, L[4]); X = NewCodeEntry (OP65_BCC, AM65_BRA, Label->Name, Label, L[3]->LI); CS_InsertEntry (S, X, I+6); /* inx */ X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[3]->LI); CS_InsertEntry (S, X, I+7); /* 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; }