Beispiel #1
0
unsigned OptBNegAX1 (CodeSeg* S)
/* On a call to bnegax, if X is zero, the result depends only on the value in
 * A, so change the call to a call to bnega. This will get further optimized
 * later if possible.
 */
{
    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 bnegax, and if X is known and zero */
        if (E->RI->In.RegX == 0 && CE_IsCallTo (E, "bnegax")) {

            CodeEntry* X = NewCodeEntry (OP65_JSR, AM65_ABS, "bnega", 0, E->LI);
            CS_InsertEntry (S, X, I+1);
            CS_DelEntry (S, I);

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

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #2
0
unsigned OptCmp6 (CodeSeg* S)
/* Search for calls to compare subroutines followed by a conditional branch
 * and replace them by cheaper versions, since the branch means that the
 * boolean value returned by these routines is not needed (we may also check
 * that explicitly, but for the current code generator it is always true).
 */
{
    unsigned Changes = 0;

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

	CodeEntry* N;
	cmp_t Cond;

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

     	/* Check for the sequence */
       	if (E->OPC == OP65_JSR 	    		        &&
	    (Cond = FindTosCmpCond (E->Arg)) != CMP_INV	&&
	    (N = CS_GetNextEntry (S, I)) != 0           &&
	    (N->Info & OF_ZBRA) != 0                    &&
       	    !CE_HasLabel (N)) {

       	    /* The tos... functions will return a boolean value in a/x and
	     * the Z flag says if this value is zero or not. We will call
	     * a cheaper subroutine instead, one that does not return a
	     * boolean value but only valid flags. Note: jeq jumps if
	     * the condition is not met, jne jumps if the condition is met.
     	     * Invert the code if we jump on condition not met.
    	     */
       	    if (GetBranchCond (N->OPC) == BC_EQ) {
	       	/* Jumps if condition false, invert condition */
	       	Cond = CmpInvertTab [Cond];
  	    }

	    /* Replace the subroutine call. */
	    E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
	    CS_InsertEntry (S, E, I+1);
	    CS_DelEntry (S, I);

	    /* Replace the conditional branch */
	    ReplaceCmp (S, I+1, Cond);

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

	}

  	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #3
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;
}
Beispiel #4
0
unsigned OptBNegAX3 (CodeSeg* S)
/* Search for the sequence:
 *
 *      lda     xx
 *      ldx     yy
 *      jsr     bnegax
 *      jne/jeq ...
 *
 * and replace it by
 *
 *      lda     xx
 *      ora     xx+1
 *      jeq/jne ...
 */
{
    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_LDA                  &&
            CS_GetEntries (S, L, I+1, 3)        &&
            L[0]->OPC == OP65_LDX               &&
            !CE_HasLabel (L[0])                 &&
            CE_IsCallTo (L[1], "bnegax")        &&
            !CE_HasLabel (L[1])                 &&
            (L[2]->Info & OF_ZBRA) != 0         &&
            !CE_HasLabel (L[2])) {

            /* ldx --> ora */
            CE_ReplaceOPC (L[0], OP65_ORA);

            /* Invert the branch */
            CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC));

            /* Delete the subroutine call */
            CS_DelEntry (S, I+2);

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #5
0
unsigned OptBNegA2 (CodeSeg* S)
/* Check for
 *
 *      lda     ..
 *      jsr     bnega
 *      jeq/jne ..
 *
 * Adjust the conditional branch and remove the call to the subroutine.
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[2];

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

        /* Check for the sequence */
        if ((E->OPC == OP65_ADC ||
             E->OPC == OP65_AND ||
             E->OPC == OP65_DEA ||
             E->OPC == OP65_EOR ||
             E->OPC == OP65_INA ||
             E->OPC == OP65_LDA ||
             E->OPC == OP65_ORA ||
             E->OPC == OP65_PLA ||
             E->OPC == OP65_SBC ||
             E->OPC == OP65_TXA ||
             E->OPC == OP65_TYA)                &&
            CS_GetEntries (S, L, I+1, 2)        &&
            CE_IsCallTo (L[0], "bnega")         &&
            !CE_HasLabel (L[0])                 &&
            (L[1]->Info & OF_ZBRA) != 0         &&
            !CE_HasLabel (L[1])) {

            /* Invert the branch */
            CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));

            /* Delete the subroutine call */
            CS_DelEntry (S, I+1);

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #6
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;
}
Beispiel #7
0
unsigned OptBoolTrans (CodeSeg* S)
/* Try to remove the call to boolean transformer routines where the call is
 * not really needed.
 */
{
    unsigned Changes = 0;

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

	CodeEntry* N;
	cmp_t Cond;

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

	/* Check for a boolean transformer */
	if (E->OPC == OP65_JSR                           &&
	    (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
	    (N = CS_GetNextEntry (S, I)) != 0            &&
	    (N->Info & OF_ZBRA) != 0) {

	    /* Make the boolean transformer unnecessary by changing the
	     * the conditional jump to evaluate the condition flags that
	     * are set after the compare directly. Note: jeq jumps if
	     * the condition is not met, jne jumps if the condition is met.
     	     * Invert the code if we jump on condition not met.
	     */
       	    if (GetBranchCond (N->OPC) == BC_EQ) {
	       	/* Jumps if condition false, invert condition */
	       	Cond = CmpInvertTab [Cond];
  	    }

	    /* Check if we can replace the code by something better */
	    ReplaceCmp (S, I+1, Cond);

	    /* Remove the call to the bool transformer */
	    CS_DelEntry (S, I);

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

	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #8
0
void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count)
/* Delete a range of code entries. This includes removing references to labels,
 * labels attached to the entries and so on.
 */
{
    /* Start deleting the entries from the rear, because this involves less
     * memory moving.
     */
    while (Count--) {
   	CS_DelEntry (S, Start + Count);
    }
}
Beispiel #9
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
unsigned OptBNegA1 (CodeSeg* S)
/* Check for
 *
 *      ldx     #$00
 *      lda     ..
 *      jsr     bnega
 *
 * Remove the ldx if the lda does not use it.
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[2];

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

        /* Check for a ldx */
        if (E->OPC == OP65_LDX                  &&
            E->AM == AM65_IMM                   &&
            (E->Flags & CEF_NUMARG) != 0        &&
            E->Num == 0                         &&
            CS_GetEntries (S, L, I+1, 2)        &&
            L[0]->OPC == OP65_LDA               &&
            (L[0]->Use & REG_X) == 0            &&
            !CE_HasLabel (L[0])                 &&
            CE_IsCallTo (L[1], "bnega")         &&
            !CE_HasLabel (L[1])) {

            /* Remove the ldx instruction */
            CS_DelEntry (S, I);

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #12
0
unsigned Opt65C02Stores (CodeSeg* S)
/* Use STZ where possible */
{
    unsigned Changes = 0;
    unsigned I;

    /* Generate register info for this step */
    CS_GenRegInfo (S);

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

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

	/* Check for a store with a register value of zero and an addressing
	 * mode available with STZ.
	 */
       	if (((E->OPC == OP65_STA && E->RI->In.RegA == 0) ||
	     (E->OPC == OP65_STX && E->RI->In.RegX == 0) ||
	     (E->OPC == OP65_STY && E->RI->In.RegY == 0))     	&&
            (E->AM == AM65_ZP  || E->AM == AM65_ABS ||
             E->AM == AM65_ZPX || E->AM == AM65_ABSX)) {

            /* Replace by STZ */
            CodeEntry* X = NewCodeEntry (OP65_STZ, E->AM, E->Arg, 0, E->LI);
            CS_InsertEntry (S, X, I+1);

            /* Delete the old stuff */
            CS_DelEntry (S, I);

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

     	/* Next entry */
	++I;

    }

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Beispiel #13
0
unsigned Opt65C02Ind (CodeSeg* S)
/* Try to use the indirect addressing mode where possible */
{
    unsigned Changes = 0;
    unsigned I;

    /* Generate register info for this step */
    CS_GenRegInfo (S);

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

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

       	/* Check for addressing mode indirect indexed Y where Y is zero.
	 * Note: All opcodes that are available as (zp),y are also available
	 * as (zp), so we can ignore the actual opcode here.
	 */
	if (E->AM == AM65_ZP_INDY && E->RI->In.RegY == 0) {

	    /* Replace it by indirect addressing mode */
	    CodeEntry* X = NewCodeEntry (E->OPC, AM65_ZP_IND, E->Arg, 0, E->LI);
	    CS_InsertEntry (S, X, I+1);
	    CS_DelEntry (S, I);

	    /* We had changes */
	    ++Changes;

	}

     	/* Next entry */
	++I;

    }

    /* Free register info */
    CS_FreeRegInfo (S);

    /* Return the number of changes made */
    return Changes;
}
Beispiel #14
0
unsigned OptCmp7 (CodeSeg* S)
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
 * used later.
 */
{
    unsigned Changes = 0;

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

       	CodeEntry* L[2];

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

       	/* Check for the sequence */
       	if ((E->OPC == OP65_LDX)                        &&
       	    CS_GetEntries (S, L, I+1, 2)                &&
       	    L[0]->OPC == OP65_TXA                       &&
       	    !CE_HasLabel (L[0])                         &&
       	    (L[1]->Info & OF_FBRA) != 0                 &&
       	    !CE_HasLabel (L[1])                         &&
	    !RegAUsed (S, I+3)) {

	    /* Remove the txa */
	    CS_DelEntry (S, I+1);

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

	}

  	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #15
0
unsigned OptTest2 (CodeSeg* S)
/* Search for an inc/dec operation followed by a load and a conditional
 * branch based on the flags from the load. Remove the load if the insn
 * isn't used later.
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[3];

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

        /* Check if it's the sequence we're searching for */
        if ((L[0]->OPC == OP65_INC || L[0]->OPC == OP65_DEC)    &&
            CS_GetEntries (S, L+1, I+1, 2)                      &&
            !CE_HasLabel (L[1])                                 &&
            (L[1]->Info & OF_LOAD) != 0                         &&
            (L[2]->Info & OF_FBRA) != 0                         &&
            L[1]->AM == L[0]->AM                                &&
            strcmp (L[0]->Arg, L[1]->Arg) == 0                  &&
            (GetRegInfo (S, I+2, L[1]->Chg) & L[1]->Chg) == 0) {

            /* Remove the load */
            CS_DelEntry (S, I+1);
             ++Changes;
        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #16
0
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;
}
Beispiel #17
0
unsigned OptTest1 (CodeSeg* S)
/* Given a sequence
 *
 *     stx     xxx
 *     ora     xxx
 *     beq/bne ...
 *
 * If X is zero, the sequence may be changed to
 *
 *     cmp     #$00
 *     beq/bne ...
 *
 * which may be optimized further by another step.
 *
 * If A is zero, the sequence may be changed to
 *
 *     txa
 *     beq/bne ...
 *
 */
{
    unsigned Changes = 0;
    unsigned I;

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

        CodeEntry* L[3];

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

        /* Check if it's the sequence we're searching for */
        if (L[0]->OPC == OP65_STX              &&
            CS_GetEntries (S, L+1, I+1, 2)     &&
            !CE_HasLabel (L[1])                &&
            L[1]->OPC == OP65_ORA              &&
            strcmp (L[0]->Arg, L[1]->Arg) == 0 &&
            !CE_HasLabel (L[2])                &&
            (L[2]->Info & OF_ZBRA) != 0) {

            /* Check if X is zero */
            if (L[0]->RI->In.RegX == 0) {

                /* Insert the compare */
                CodeEntry* N = NewCodeEntry (OP65_CMP, AM65_IMM, "$00", 0, L[0]->LI);
                CS_InsertEntry (S, N, I+2);

                /* Remove the two other insns */
                CS_DelEntry (S, I+1);
                CS_DelEntry (S, I);

                /* We had changes */
                ++Changes;

            /* Check if A is zero */
            } else if (L[1]->RI->In.RegA == 0) {

                /* Insert the txa */
                CodeEntry* N = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[1]->LI);
                CS_InsertEntry (S, N, I+2);

                /* Remove the two other insns */
                CS_DelEntry (S, I+1);
                CS_DelEntry (S, I);

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

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #18
0
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;
}
Beispiel #19
0
static unsigned OptLoad3 (CodeSeg* S)
/* Remove repeated loads from one and the same memory location */
{
    unsigned Changes = 0;
    CodeEntry* Load = 0;

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

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

        /* Forget a preceeding load if we have a label */
        if (Load && CE_HasLabel (E)) {
            Load = 0;
        }

        /* Check if this insn is a load */
        if (E->Info & OF_LOAD) {

            CodeEntry* N;

            /* If we had a preceeding load that is identical, remove this one.
            ** If it is not identical, or we didn't have one, remember it.
            */
            if (Load != 0                               &&
                E->OPC == Load->OPC                     &&
                E->AM == Load->AM                       &&
                ((E->Arg == 0 && Load->Arg == 0) ||
                 strcmp (E->Arg, Load->Arg) == 0)       &&
                (N = CS_GetNextEntry (S, I)) != 0       &&
                (N->Info & OF_CBRA) == 0) {

                /* Now remove the call to the subroutine */
                CS_DelEntry (S, I);

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

                /* Next insn */
                continue;

            } else {

                Load = E;

            }

        } else if ((E->Info & OF_CMP) == 0 && (E->Info & OF_CBRA) == 0) {
            /* Forget the first load on occurance of any insn we don't like */
            Load = 0;
        }

        /* Next entry */
        ++I;
    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #20
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;
}
Beispiel #21
0
unsigned OptCmp9 (CodeSeg* S)
/* Search for the sequence
 *
 *    sbc       xx
 *    bvs/bvc   L
 *    eor       #$80
 * L: asl       a
 *    bcc/bcs   somewhere
 *
 * If A is not used later (which should be the case), we can branch on the N
 * flag instead of the carry flag and remove the asl.
 */
{
    unsigned Changes = 0;
    unsigned I;

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

       	CodeEntry* L[5];

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

     	/* Check for the sequence */
       	if (L[0]->OPC == OP65_SBC                       &&
       	    CS_GetEntries (S, L+1, I+1, 4)	        &&
            (L[1]->OPC == OP65_BVC              ||
             L[1]->OPC == OP65_BVS)                     &&
            L[1]->JumpTo != 0                           &&
            L[1]->JumpTo->Owner == L[3]                 &&
            L[2]->OPC == OP65_EOR                       &&
            CE_IsKnownImm (L[2], 0x80)                  &&
            L[3]->OPC == OP65_ASL                       &&
            L[3]->AM == AM65_ACC                        &&
            (L[4]->OPC == OP65_BCC              ||
             L[4]->OPC == OP65_BCS              ||
             L[4]->OPC == OP65_JCC              ||
             L[4]->OPC == OP65_JCS)                     &&
            !CE_HasLabel (L[4])                         &&
            !RegAUsed (S, I+4)) {

	    /* Replace the branch condition */
	    switch (GetBranchCond (L[4]->OPC)) {
                case BC_CC:     CE_ReplaceOPC (L[4], OP65_JPL); break;
                case BC_CS:     CE_ReplaceOPC (L[4], OP65_JMI); break;
                default:        Internal ("Unknown branch condition in OptCmp9");
            }

            /* Delete the asl insn */
            CS_DelEntry (S, I+3);

            /* Next sequence is somewhat ahead (if any) */
            I += 3;

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

     	/* Next entry */
	++I;
    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #22
0
unsigned OptSub2 (CodeSeg* S)
/* Search for the sequence
**
**      lda     xx
**      sec
**      sta     tmp1
**      lda     yy
**      sbc     tmp1
**      sta     yy
**
** and replace it by
**
**      sec
**      lda     yy
**      sbc     xx
**      sta     yy
*/
{
    unsigned Changes = 0;

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

        CodeEntry* L[5];

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

        /* Check for the sequence */
        if (E->OPC == OP65_LDA                             &&
            !CS_RangeHasLabel (S, I+1, 5)                  &&
            CS_GetEntries (S, L, I+1, 5)                   &&
            L[0]->OPC == OP65_SEC                          &&
            L[1]->OPC == OP65_STA                          &&
            strcmp (L[1]->Arg, "tmp1") == 0                &&
            L[2]->OPC == OP65_LDA                          &&
            L[3]->OPC == OP65_SBC                          &&
            strcmp (L[3]->Arg, "tmp1") == 0                &&
            L[4]->OPC == OP65_STA                          &&
            strcmp (L[4]->Arg, L[2]->Arg) == 0) {

            /* Remove the store to tmp1 */
            CS_DelEntry (S, I+2);

            /* Remove the subtraction */
            CS_DelEntry (S, I+3);

            /* Move the lda to the position of the subtraction and change the
            ** op to SBC.
            */
            CS_MoveEntry (S, I, I+3);
            CE_ReplaceOPC (E, OP65_SBC);

            /* If the sequence head had a label, move this label back to the
            ** head.
            */
            if (CE_HasLabel (E)) {
                CS_MoveLabels (S, E, L[0]);
            }

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #23
0
unsigned OptShift6 (CodeSeg* S)
/* Inline the shift subroutines. */
{
    unsigned Changes = 0;

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

        unsigned   Shift;
        unsigned   Count;
        CodeEntry* X;
        unsigned   IP;

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

     	/* Check for a call to one of the shift routine */
	if (E->OPC == OP65_JSR                          &&
            (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
            SHIFT_DIR (Shift) == SHIFT_DIR_LEFT         &&
            (Count = SHIFT_COUNT (Shift)) > 0) {

            /* Code is:
             *
             *      stx     tmp1
             *      asl     a
             *      rol     tmp1
             *      (repeat ShiftCount-1 times)
             *      ldx     tmp1
             *
             * which makes 4 + 3 * ShiftCount bytes, compared to the original
             * 3 bytes for the subroutine call. However, in most cases, the
             * final load of the X register gets merged with some other insn
             * and replaces a txa, so for a shift count of 1, we get a factor
             * of 200, which matches nicely the CodeSizeFactor enabled with -Oi
             */
            if (Count > 1 || S->CodeSizeFactor > 200) {
                unsigned Size = 4 + 3 * Count;
                if ((Size * 100 / 3) > S->CodeSizeFactor) {
                    /* Not acceptable */
                    goto NextEntry;
                }
            }

            /* Inline the code. Insertion point is behind the subroutine call */
            IP = (I + 1);

            /* stx tmp1 */
            X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, E->LI);
            CS_InsertEntry (S, X, IP++);

            while (Count--) {
                /* asl a */
                X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
                CS_InsertEntry (S, X, IP++);

                /* rol tmp1 */
                X = NewCodeEntry (OP65_ROL, AM65_ZP, "tmp1", 0, E->LI);
                CS_InsertEntry (S, X, IP++);
            }

            /* ldx tmp1 */
            X = NewCodeEntry (OP65_LDX, AM65_ZP, "tmp1", 0, E->LI);
            CS_InsertEntry (S, X, IP++);

            /* Remove the subroutine call */
            CS_DelEntry (S, I);

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

NextEntry:
	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #24
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;
}
Beispiel #25
0
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;
}
Beispiel #26
0
unsigned OptBNegAX4 (CodeSeg* S)
/* Search for the sequence:
 *
 *      jsr     xxx
 *      jsr     bnega(x)
 *      jeq/jne ...
 *
 * and replace it by:
 *
 *      jsr     xxx
 *      <boolean test>
 *      jne/jeq ...
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[2];

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

        /* Check for the sequence */
        if (E->OPC == OP65_JSR                  &&
            CS_GetEntries (S, L, I+1, 2)        &&
            L[0]->OPC == OP65_JSR               &&
            strncmp (L[0]->Arg,"bnega",5) == 0  &&
            !CE_HasLabel (L[0])                 &&
            (L[1]->Info & OF_ZBRA) != 0         &&
            !CE_HasLabel (L[1])) {

            CodeEntry* X;

            /* Check if we're calling bnega or bnegax */
            int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0);

            /* Insert apropriate test code */
            if (ByteSized) {
                /* Test bytes */
                X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+2);
            } else {
                /* Test words */
                X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+2);
                X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI);
                CS_InsertEntry (S, X, I+3);
            }

            /* Delete the subroutine call */
            CS_DelEntry (S, I+1);

            /* Invert the branch */
            CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC));

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #27
0
unsigned OptCmp3 (CodeSeg* S)
/* Search for
 *
 *     	lda/and/ora/eor	...
 *  	cmp #$00
 *  	jeq/jne
 * or
 *     	lda/and/ora/eor	...
 *  	cmp #$00
 *  	jsr boolxx
 *
 * and remove the cmp.
 */
{
    unsigned Changes = 0;

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

	CodeEntry* L[3];

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

     	/* Check for the sequence */
       	if ((L[0]->OPC == OP65_ADC ||
       	     L[0]->OPC == OP65_AND ||
             L[0]->OPC == OP65_ASL ||
       	     L[0]->OPC == OP65_DEA ||
       	     L[0]->OPC == OP65_EOR ||
       	     L[0]->OPC == OP65_INA ||
       	     L[0]->OPC == OP65_LDA ||
             L[0]->OPC == OP65_LSR ||
       	     L[0]->OPC == OP65_ORA ||
       	     L[0]->OPC == OP65_PLA ||
       	     L[0]->OPC == OP65_SBC ||
       	     L[0]->OPC == OP65_TXA ||
       	     L[0]->OPC == OP65_TYA)         &&
	    !CS_RangeHasLabel (S, I+1, 2)   &&
	    CS_GetEntries (S, L+1, I+1, 2)  &&
	    L[1]->OPC == OP65_CMP           &&
	    CE_IsKnownImm (L[1], 0)) {

            int Delete = 0;

	    /* Check for the call to boolxx. We only remove the compare if
       	     * the carry flag is not evaluated later, because the load will
             * not set the carry flag.
	     */
	    if (L[2]->OPC == OP65_JSR) {
	    	switch (FindBoolCmpCond (L[2]->Arg)) {

	    	    case CMP_EQ:
	    	    case CMP_NE:
	    	    case CMP_GT:
	    	    case CMP_GE:
	    	    case CMP_LT:
	    	    case CMP_LE:
	    	        /* Remove the compare */
                        Delete = 1;
	    	        break;

	    	    case CMP_UGT:
	     	    case CMP_UGE:
	    	    case CMP_ULT:
	    	    case CMP_ULE:
	    	    case CMP_INV:
	    	        /* Leave it alone */
	    	        break;
	    	}

	    } else if ((L[2]->Info & OF_FBRA) != 0) {
                /* The following insn branches on the condition of the load,
                 * so the compare instruction might be removed. For safety,
                 * do some more checks if the carry isn't used later, since
                 * the compare does set the carry, but the load does not.
                 */
                CodeEntry* E;
                CodeEntry* N;
                if ((E = CS_GetNextEntry (S, I+2)) != 0         &&
                    L[2]->JumpTo != 0                           &&
                    (N = L[2]->JumpTo->Owner) != 0              &&
                    N->OPC != OP65_BCC                          &&
                    N->OPC != OP65_BCS                          &&
                    N->OPC != OP65_JCC                          &&
                    N->OPC != OP65_JCS                          &&
                    (N->OPC != OP65_JSR                 ||
                    FindBoolCmpCond (N->Arg) == CMP_INV)) {

                    /* The following insn branches on the condition of a load,
                     * and there's no use of the carry flag in sight, so the
                     * compare instruction can be removed.
                     */
                    Delete = 1;
                }
            }

            /* Delete the compare if we can */
            if (Delete) {
                CS_DelEntry (S, I+1);
                ++Changes;
            }
	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #28
0
unsigned OptCmp8 (CodeSeg* S)
/* Check for register compares where the contents of the register and therefore
 * the result of the compare is known.
 */
{
    unsigned Changes = 0;
    unsigned I;

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

	int RegVal;

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

     	/* Check for a compare against an immediate value */
       	if ((E->Info & OF_CMP) != 0           &&
	    (RegVal = GetCmpRegVal (E)) >= 0  &&
	    CE_IsConstImm (E)) {

	    /* We are able to evaluate the compare at compile time. Check if
	     * one or more branches are ahead.
	     */
	    unsigned JumpsChanged = 0;
	    CodeEntry* N;
	    while ((N = CS_GetNextEntry (S, I)) != 0 &&   /* Followed by something.. */
	       	   (N->Info & OF_CBRA) != 0          &&   /* ..that is a cond branch.. */
	       	   !CE_HasLabel (N)) {                    /* ..and has no label */

	       	/* Evaluate the branch condition */
	       	int Cond;
     		switch (GetBranchCond (N->OPC)) {
     	       	    case BC_CC:
     	       	        Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_CS:
     	       	        Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_EQ:
     	       	        Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
     	       	        break;

     	       	    case BC_MI:
       	       	        Cond = ((signed char)RegVal) < ((signed char)E->Num);
     	       	        break;

     	       	    case BC_NE:
     	       	        Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
	       	        break;

	       	    case BC_PL:
       	       	        Cond = ((signed char)RegVal) >= ((signed char)E->Num);
	       	        break;

	       	    case BC_VC:
	       	    case BC_VS:
		        /* Not set by the compare operation, bail out (Note:
			 * Just skipping anything here is rather stupid, but
			 * the sequence is never generated by the compiler,
			 * so it's quite safe to skip).
			 */
		        goto NextEntry;

		    default:
		        Internal ("Unknown branch condition");

		}

	       	/* If the condition is false, we may remove the jump. Otherwise
	       	 * the branch will always be taken, so we may replace it by a
	       	 * jump (and bail out).
	       	 */
		if (!Cond) {
		    CS_DelEntry (S, I+1);
		} else {
		    CodeLabel* L = N->JumpTo;
		    const char* LabelName = L? L->Name : N->Arg;
		    CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, LabelName, L, N->LI);
		    CS_InsertEntry (S, X, I+2);
		    CS_DelEntry (S, I+1);
		}

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

	    /* If we have made changes above, we may also remove the compare */
	    if (JumpsChanged) {
		CS_DelEntry (S, I);
	    }

	}

NextEntry:
     	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #29
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;
}
Beispiel #30
0
unsigned OptCmp5 (CodeSeg* S)
/* Optimize compares of local variables:
 *
 *      ldy     #o
 *      jsr     ldaxysp
 *      cpx     #a
 *      bne     L1
 *   	cmp 	#b
 *      jne/jeq L2
 */
{
    unsigned Changes = 0;

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

	CodeEntry* L[6];

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

     	/* Check for the sequence */
	if (L[0]->OPC == OP65_LDY           &&
	    CE_IsConstImm (L[0])            &&
	    CS_GetEntries (S, L+1, I+1, 5)  &&
	    !CE_HasLabel (L[1])             &&
	    CE_IsCallTo (L[1], "ldaxysp")   &&
	    IsImmCmp16 (L+2)) {

       	    if ((L[5]->Info & OF_FBRA) != 0 && L[2]->Num == 0 && L[4]->Num == 0) {

		CodeEntry* X;
		char Buf[20];

		/* The value is zero, we may use the simple code version:
	    	 *      ldy     #o-1
	    	 *      lda     (sp),y
	    	 *      ldy     #o
	    	 *      ora    	(sp),y
		 *      jne/jeq ...
		 */
		sprintf (Buf, "$%02X", (int)(L[0]->Num-1));
		X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI);
		CS_InsertEntry (S, X, I+1);

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

		X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
		CS_InsertEntry (S, X, I+3);

		X = NewCodeEntry (OP65_ORA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
		CS_InsertEntry (S, X, I+4);

		CS_DelEntries (S, I+5, 3);   /* cpx/bne/cmp */
		CS_DelEntry (S, I);          /* ldy */

       	    } else {

		CodeEntry* X;
		char Buf[20];

		/* Change the code to just use the A register. Move the load
		 * of the low byte after the first branch if possible:
		 *
		 *      ldy     #o
		 *      lda     (sp),y
		 *      cmp     #a
		 *      bne     L1
		 *      ldy     #o-1
		 *      lda     (sp),y
		 *   	cmp	#b
		 *      jne/jeq ...
		 */
		X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
		CS_InsertEntry (S, X, I+3);

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

		X = NewCodeEntry (OP65_CMP, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
		CS_InsertEntry (S, X, I+5);

		sprintf (Buf, "$%02X", (int)(L[0]->Num-1));
		X = NewCodeEntry (OP65_LDY, AM65_IMM, Buf, 0, L[0]->LI);
		CS_InsertEntry (S, X, I+7);

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

		CS_DelEntries (S, I, 3);          /* ldy/jsr/cpx */

	    }

	    ++Changes;
	}

    	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}