Esempio n. 1
0
unsigned OptShift2(CodeSeg* S)
/* A call to the asrax1 routines may get replaced by something simpler, if
 * X is not used later:
 *
 *      cmp     #$80
 *      ror     a
 *
 */
{
    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_TYPE (Shift) == SHIFT_TYPE_ASR        &&
            (Count = SHIFT_COUNT (Shift)) > 0           &&
            Count * 100 <= S->CodeSizeFactor    &&
            !RegXUsed (S, I+1)) {

            CodeEntry* X;
            unsigned J = I+1;

            /* Generate the replacement sequence */
            while (Count--) {
                /* cmp #$80 */
                X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, E->LI);
                CS_InsertEntry (S, X, J++);

                /* ror a */
                X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, E->LI);
                CS_InsertEntry (S, X, J++);
            }

            /* Delete the call to asrax */
            CS_DelEntry (S, I);

            /* Remember, we had changes */
            ++Changes;
    	}

    	/* Next entry */
    	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Esempio n. 2
0
unsigned OptNegAX1 (CodeSeg* S)
/* Search for a call to negax and replace it by
 *
 *      eor     #$FF
 *      clc
 *      adc     #$01
 *
 * if X isn't used later.
 */
{
    unsigned Changes = 0;
    unsigned I;

    /* Walk over the entries */
    I = 0;
    while (I < CS_GetEntryCount (S)) {

        /* Get next entry */
        CodeEntry* E = CS_GetEntry (S, I);

        /* Check if this is a call to negax, and if X isn't used later */
        if (CE_IsCallTo (E, "negax") && !RegXUsed (S, I+1)) {

            CodeEntry* X;

            /* Add replacement code behind */
            X = NewCodeEntry (OP65_EOR, AM65_IMM, "$FF", 0, E->LI);
            CS_InsertEntry (S, X, I+1);

            X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
            CS_InsertEntry (S, X, I+2);

            X = NewCodeEntry (OP65_ADC, AM65_IMM, "$01", 0, E->LI);
            CS_InsertEntry (S, X, I+3);

            /* Delete the call to negax */
            CS_DelEntry (S, I);

            /* Skip the generated code */
            I += 2;

            /* We had changes */
            ++Changes;
        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
unsigned OptSub1 (CodeSeg* S)
/* Search for the sequence
**
**      sbc     ...
**      bcs     L
**      dex
** L:
**
** and remove the handling of the high byte if X is not used later.
*/
{
    unsigned Changes = 0;

    /* Walk over the entries */
    unsigned I = 0;
    while (I < CS_GetEntryCount (S)) {

        CodeEntry* L[3];

        /* Get next entry */
        CodeEntry* E = CS_GetEntry (S, I);

        /* Check for the sequence */
        if (E->OPC == OP65_SBC                               &&
            CS_GetEntries (S, L, I+1, 3)                     &&
            (L[0]->OPC == OP65_BCS || L[0]->OPC == OP65_JCS) &&
            L[0]->JumpTo != 0                                &&
            !CE_HasLabel (L[0])                              &&
            L[1]->OPC == OP65_DEX                            &&
            !CE_HasLabel (L[1])                              &&
            L[0]->JumpTo->Owner == L[2]                      &&
            !RegXUsed (S, I+3)) {

            /* Remove the bcs/dex */
            CS_DelEntries (S, I+1, 2);

            /* Remember, we had changes */
            ++Changes;

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Esempio n. 5
0
File: codeopt.c Progetto: coyxc/cc65
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;
}
Esempio n. 6
0
unsigned OptStore5 (CodeSeg* S)
/* Search for the sequence
**
**      lda     foo
**      ldx     bar
**      sta     something
**      stx     something-else
**
** and replace it by
**
**      lda     foo
**      sta     something
**      lda     bar
**      sta     something-else
**
** if X is not used later. This replacement doesn't save any cycles or bytes,
** but it keeps the value of X, which may be reused 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_LDA                           &&
            !CS_RangeHasLabel (S, I+1, 3)                   &&
            CS_GetEntries (S, L+1, I+1, 3)                  &&
            L[1]->OPC == OP65_LDX                           &&
            L[2]->OPC == OP65_STA                           &&
            L[3]->OPC == OP65_STX                           &&
            !RegXUsed (S, I+4)) {

            CodeEntry* X;

            /* Insert the code after the sequence */
            X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
            CS_InsertEntry (S, X, I+4);
            X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
            CS_InsertEntry (S, X, I+5);

            /* Delete the old code */
            CS_DelEntry (S, I+3);
            CS_DelEntry (S, I+1);

            /* Remember, we had changes */
            ++Changes;
        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Esempio n. 7
0
File: codeopt.c Progetto: coyxc/cc65
static unsigned OptLoad2 (CodeSeg* S)
/* Replace calls to ldaxysp by inline code */
{
    unsigned I;
    unsigned Changes = 0;

    /* Walk over the entries */
    I = 0;
    while (I < CS_GetEntryCount (S)) {

        CodeEntry* L[3];

        /* Get next entry */
        L[0] = CS_GetEntry (S, I);

        /* Check for the sequence */
        if (CE_IsCallTo (L[0], "ldaxysp")) {

            CodeEntry* X;

            /* Followed by sta abs/stx abs? */
            if (CS_GetEntries (S, L+1, I+1, 2)                  &&
                L[1]->OPC == OP65_STA                           &&
                L[2]->OPC == OP65_STX                           &&
                (L[1]->Arg == 0                         ||
                 L[2]->Arg == 0                         ||
                 strcmp (L[1]->Arg, L[2]->Arg) != 0)            &&
                !CS_RangeHasLabel (S, I+1, 2)                   &&
                !RegXUsed (S, I+3)) {

                /* A/X are stored into memory somewhere and X is not used
                ** later
                */

                /* lda (sp),y */
                X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+3);

                /* sta abs */
                X = NewCodeEntry (OP65_STA, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
                CS_InsertEntry (S, X, I+4);

                /* dey */
                X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+5);

                /* lda (sp),y */
                X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+6);

                /* sta abs */
                X = NewCodeEntry (OP65_STA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
                CS_InsertEntry (S, X, I+7);

                /* Now remove the call to the subroutine and the sta/stx */
                CS_DelEntries (S, I, 3);

            } else {

                /* Standard replacement */

                /* lda (sp),y */
                X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+1);

                /* tax */
                X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+2);

                /* dey */
                X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+3);

                /* lda (sp),y */
                X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+4);

                /* 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;
}
Esempio n. 8
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;
}