Esempio n. 1
0
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);

    }

}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}