Beispiel #1
0
unsigned OptStore1 (CodeSeg* S)
/* Search for the sequence
**
**      ldy     #n
**      jsr     staxysp
**      ldy     #n+1
**      jsr     ldaxysp
**
** and remove the useless load.
*/
{
    unsigned Changes = 0;

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

        CodeEntry* L[4];

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

        /* Check for the sequence */
        if (L[0]->OPC == OP65_LDY                           &&
            CE_IsConstImm (L[0])                            &&
            L[0]->Num < 0xFF                                &&
            !CS_RangeHasLabel (S, I+1, 3)                   &&
            CS_GetEntries (S, L+1, I+1, 3)                  &&
            CE_IsCallTo (L[1], "staxysp")                   &&
            L[2]->OPC == OP65_LDY                           &&
            CE_IsKnownImm (L[2], L[0]->Num + 1)             &&
            CE_IsCallTo (L[3], "ldaxysp")) {

            /* Register has already the correct value, remove the loads */
            CS_DelEntries (S, I+2, 2);

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #2
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 #3
0
unsigned Opt65C02BitOps (CodeSeg* S)
/* Use special bit op instructions of the C02 */
{
    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)) {

	CodeEntry* L[3];

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

	/* Check for the sequence */
	if (L[0]->OPC == OP65_LDA      	       	                &&
            (L[0]->AM == AM65_ZP || L[0]->AM == AM65_ABS)       &&
            !CS_RangeHasLabel (S, I+1, 2)                       &&
            CS_GetEntries (S, L+1, I+1, 2)                      &&
            (L[1]->OPC == OP65_AND || L[1]->OPC == OP65_ORA)    &&
            CE_IsConstImm (L[1])                                &&
            L[2]->OPC == OP65_STA                               &&
            L[2]->AM == L[0]->AM                                &&
            strcmp (L[2]->Arg, L[0]->Arg) == 0                  &&
            !RegAUsed (S, I+3)) {

            char Buf[32];
            CodeEntry* X;

            /* Use TRB for AND and TSB for ORA */
            if (L[1]->OPC == OP65_AND) {

                /* LDA #XX */
                sprintf (Buf, "$%02X", (int) ((~L[1]->Num) & 0xFF));
                X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI);
                CS_InsertEntry (S, X, I+3);

                /* TRB */
                X = NewCodeEntry (OP65_TRB, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+4);

            } else {

                /* LDA #XX */
                sprintf (Buf, "$%02X", (int) L[1]->Num);
                X = NewCodeEntry (OP65_LDA, AM65_IMM, Buf, 0, L[1]->LI);
                CS_InsertEntry (S, X, I+3);

                /* TSB */
                X = NewCodeEntry (OP65_TSB, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
                CS_InsertEntry (S, X, I+4);
            }

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

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

     	/* Next entry */
	++I;

    }

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

    /* Return the number of changes made */
    return Changes;
}
Beispiel #4
0
void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
/* Generate register info for this instruction. If an old info exists, it is
** overwritten.
*/
{
    /* Pointers to the register contents */
    RegContents* In;
    RegContents* Out;

    /* Function register usage */
    unsigned short Use, Chg;

    /* If we don't have a register info struct, allocate one. */
    if (E->RI == 0) {
        E->RI = NewRegInfo (InputRegs);
    } else {
        if (InputRegs) {
            E->RI->In  = *InputRegs;
        } else {
            RC_Invalidate (&E->RI->In);
        }
        E->RI->Out2 = E->RI->Out = E->RI->In;
    }

    /* Get pointers to the register contents */
    In  = &E->RI->In;
    Out = &E->RI->Out;

    /* Handle the different instructions */
    switch (E->OPC) {

        case OP65_ADC:
            /* We don't know the value of the carry, so the result is
            ** always unknown.
            */
            Out->RegA = UNKNOWN_REGVAL;
            break;

        case OP65_AND:
            if (RegValIsKnown (In->RegA)) {
                if (CE_IsConstImm (E)) {
                    Out->RegA = In->RegA & (short) E->Num;
                } else if (E->AM == AM65_ZP) {
                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
                        case REG_TMP1:
                            Out->RegA = In->RegA & In->Tmp1;
                            break;
                        case REG_PTR1_LO:
                            Out->RegA = In->RegA & In->Ptr1Lo;
                            break;
                        case REG_PTR1_HI:
                            Out->RegA = In->RegA & In->Ptr1Hi;
                            break;
                        case REG_SREG_LO:
                            Out->RegA = In->RegA & In->SRegLo;
                            break;
                        case REG_SREG_HI:
                            Out->RegA = In->RegA & In->SRegHi;
                            break;
                        default:
                            Out->RegA = UNKNOWN_REGVAL;
                            break;
                    }
                } else {
                    Out->RegA = UNKNOWN_REGVAL;
                }
            } else if (CE_IsKnownImm (E, 0)) {
                /* A and $00 does always give zero */
                Out->RegA = 0;
            }
            break;

        case OP65_ASL:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA << 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 << 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo << 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi << 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo << 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi << 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_BCC:
            break;

        case OP65_BCS:
            break;

        case OP65_BEQ:
            break;

        case OP65_BIT:
            break;

        case OP65_BMI:
            break;

        case OP65_BNE:
            break;

        case OP65_BPL:
            break;

        case OP65_BRA:
            break;

        case OP65_BRK:
            break;

        case OP65_BVC:
            break;

        case OP65_BVS:
            break;

        case OP65_CLC:
            break;

        case OP65_CLD:
            break;

        case OP65_CLI:
            break;

        case OP65_CLV:
            break;

        case OP65_CMP:
            break;

        case OP65_CPX:
            break;

        case OP65_CPY:
            break;

        case OP65_DEA:
            if (RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA - 1) & 0xFF;
            }
            break;

        case OP65_DEC:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA - 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 - 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo - 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi - 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo - 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi - 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_DEX:
            if (RegValIsKnown (In->RegX)) {
                Out->RegX = (In->RegX - 1) & 0xFF;
            }
            break;

        case OP65_DEY:
            if (RegValIsKnown (In->RegY)) {
                Out->RegY = (In->RegY - 1) & 0xFF;
            }
            break;

        case OP65_EOR:
            if (RegValIsKnown (In->RegA)) {
                if (CE_IsConstImm (E)) {
                    Out->RegA = In->RegA ^ (short) E->Num;
                } else if (E->AM == AM65_ZP) {
                    switch (GetKnownReg (E->Use & REG_ZP, In)) {
                        case REG_TMP1:
                            Out->RegA = In->RegA ^ In->Tmp1;
                            break;
                        case REG_PTR1_LO:
                            Out->RegA = In->RegA ^ In->Ptr1Lo;
                            break;
                        case REG_PTR1_HI:
                            Out->RegA = In->RegA ^ In->Ptr1Hi;
                            break;
                        case REG_SREG_LO:
                            Out->RegA = In->RegA ^ In->SRegLo;
                            break;
                        case REG_SREG_HI:
                            Out->RegA = In->RegA ^ In->SRegHi;
                            break;
                        default:
                            Out->RegA = UNKNOWN_REGVAL;
                            break;
                    }
                } else {
                    Out->RegA = UNKNOWN_REGVAL;
                }
            }
            break;

        case OP65_INA:
            if (RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA + 1) & 0xFF;
            }
            break;

        case OP65_INC:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA + 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Chg & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->Tmp1 = (In->Tmp1 + 1) & 0xFF;
                        break;
                    case REG_PTR1_LO:
                        Out->Ptr1Lo = (In->Ptr1Lo + 1) & 0xFF;
                        break;
                    case REG_PTR1_HI:
                        Out->Ptr1Hi = (In->Ptr1Hi + 1) & 0xFF;
                        break;
                    case REG_SREG_LO:
                        Out->SRegLo = (In->SRegLo + 1) & 0xFF;
                        break;
                    case REG_SREG_HI:
                        Out->SRegHi = (In->SRegHi + 1) & 0xFF;
                        break;
                }
            } else if (E->AM == AM65_ZPX) {
                /* Invalidates all ZP registers */
                RC_InvalidateZP (Out);
            }
            break;

        case OP65_INX:
            if (RegValIsKnown (In->RegX)) {
                Out->RegX = (In->RegX + 1) & 0xFF;
            }
            break;

        case OP65_INY:
            if (RegValIsKnown (In->RegY)) {
                Out->RegY = (In->RegY + 1) & 0xFF;
            }
            break;

        case OP65_JCC:
            break;

        case OP65_JCS:
            break;

        case OP65_JEQ:
            break;

        case OP65_JMI:
            break;

        case OP65_JMP:
            break;

        case OP65_JNE:
            break;

        case OP65_JPL:
            break;

        case OP65_JSR:
            /* Get the code info for the function */
            GetFuncInfo (E->Arg, &Use, &Chg);
            if (Chg & REG_A) {
                Out->RegA = UNKNOWN_REGVAL;
            }
            if (Chg & REG_X) {
                Out->RegX = UNKNOWN_REGVAL;
            }
            if (Chg & REG_Y) {
                Out->RegY = UNKNOWN_REGVAL;
            }
            if (Chg & REG_TMP1) {
                Out->Tmp1 = UNKNOWN_REGVAL;
            }
            if (Chg & REG_PTR1_LO) {
                Out->Ptr1Lo = UNKNOWN_REGVAL;
            }
            if (Chg & REG_PTR1_HI) {
                Out->Ptr1Hi = UNKNOWN_REGVAL;
            }
            if (Chg & REG_SREG_LO) {
                Out->SRegLo = UNKNOWN_REGVAL;
            }
            if (Chg & REG_SREG_HI) {
                Out->SRegHi = UNKNOWN_REGVAL;
            }
            /* ## FIXME: Quick hack for some known functions: */
            if (strcmp (E->Arg, "complax") == 0) {
                if (RegValIsKnown (In->RegA)) {
                    Out->RegA = (In->RegA ^ 0xFF);
                }
                if (RegValIsKnown (In->RegX)) {
                    Out->RegX = (In->RegX ^ 0xFF);
                }
            } else if (strcmp (E->Arg, "tosandax") == 0) {
                if (In->RegA == 0) {
                    Out->RegA = 0;
                }
                if (In->RegX == 0) {
                    Out->RegX = 0;
                }
            } else if (strcmp (E->Arg, "tosaslax") == 0) {
                if (RegValIsKnown (In->RegA) && (In->RegA & 0x0F) >= 8) {
                    printf ("Hey!\n");
                    Out->RegA = 0;
                }
            } else if (strcmp (E->Arg, "tosorax") == 0) {
                if (In->RegA == 0xFF) {
                    Out->RegA = 0xFF;
                }
                if (In->RegX == 0xFF) {
                    Out->RegX = 0xFF;
                }
            } else if (strcmp (E->Arg, "tosshlax") == 0) {
                if ((In->RegA & 0x0F) >= 8) {
                    Out->RegA = 0;
                }
            } else if (FindBoolCmpCond (E->Arg) != CMP_INV ||
                       FindTosCmpCond (E->Arg) != CMP_INV) {
                /* Result is boolean value, so X is zero on output */
                Out->RegX = 0;
            }
            break;

        case OP65_JVC:
            break;

        case OP65_JVS:
            break;

        case OP65_LDA:
            if (CE_IsConstImm (E)) {
                Out->RegA = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegA = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegA = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegA = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegA = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegA = In->SRegHi;
                        break;
                    default:
                        Out->RegA = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* A is now unknown */
                Out->RegA = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LDX:
            if (CE_IsConstImm (E)) {
                Out->RegX = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegX = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegX = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegX = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegX = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegX = In->SRegHi;
                        break;
                    default:
                        Out->RegX = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* X is now unknown */
                Out->RegX = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LDY:
            if (CE_IsConstImm (E)) {
                Out->RegY = (unsigned char) E->Num;
            } else if (E->AM == AM65_ZP) {
                switch (GetKnownReg (E->Use & REG_ZP, In)) {
                    case REG_TMP1:
                        Out->RegY = In->Tmp1;
                        break;
                    case REG_PTR1_LO:
                        Out->RegY = In->Ptr1Lo;
                        break;
                    case REG_PTR1_HI:
                        Out->RegY = In->Ptr1Hi;
                        break;
                    case REG_SREG_LO:
                        Out->RegY = In->SRegLo;
                        break;
                    case REG_SREG_HI:
                        Out->RegY = In->SRegHi;
                        break;
                    default:
                        Out->RegY = UNKNOWN_REGVAL;
                        break;
                }
            } else {
                /* Y is now unknown */
                Out->RegY = UNKNOWN_REGVAL;
            }
            break;

        case OP65_LSR:
            if (E->AM == AM65_ACC && RegValIsKnown (In->RegA)) {
                Out->RegA = (In->RegA >> 1) & 0xFF;
            } else if (E->AM == AM65_ZP) {
Beispiel #5
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;
}
Beispiel #6
0
void CS_GenRegInfo (CodeSeg* S)
/* Generate register infos for all instructions */
{
    unsigned I;
    RegContents Regs;		/* Initial register contents */
    RegContents* CurrentRegs;   /* Current register contents */
    int WasJump;                /* True if last insn was a jump */
    int Done;                   /* All runs done flag */

    /* Be sure to delete all register infos */
    CS_FreeRegInfo (S);

    /* We may need two runs to get back references right */
    do {

	/* Assume we're done after this run */
	Done = 1;

	/* On entry, the register contents are unknown */
	RC_Invalidate (&Regs);
	CurrentRegs = &Regs;

	/* Walk over all insns and note just the changes from one insn to the
	 * next one.
	 */
	WasJump = 0;
	for (I = 0; I < CS_GetEntryCount (S); ++I) {

	    CodeEntry* P;

	    /* Get the next instruction */
	    CodeEntry* E = CollAtUnchecked (&S->Entries, I);

	    /* If the instruction has a label, we need some special handling */
	    unsigned LabelCount = CE_GetLabelCount (E);
	    if (LabelCount > 0) {

		/* Loop over all entry points that jump here. If these entry
		 * points already have register info, check if all values are
		 * known and identical. If all values are identical, and the
		 * preceeding instruction was not an unconditional branch, check
		 * if the register value on exit of the preceeding instruction
		 * is also identical. If all these values are identical, the
		 * value of a register is known, otherwise it is unknown.
		 */
		CodeLabel* Label = CE_GetLabel (E, 0);
		unsigned Entry;
		if (WasJump) {
		    /* Preceeding insn was an unconditional branch */
		    CodeEntry* J = CL_GetRef(Label, 0);
		    if (J->RI) {
			Regs = J->RI->Out2;
		    } else {
			RC_Invalidate (&Regs);
		    }
		    Entry = 1;
		} else {
		    Regs = *CurrentRegs;
		    Entry = 0;
		}

		while (Entry < CL_GetRefCount (Label)) {
		    /* Get this entry */
		    CodeEntry* J = CL_GetRef (Label, Entry);
		    if (J->RI == 0) {
			/* No register info for this entry. This means that the
			 * instruction that jumps here is at higher addresses and
			 * the jump is a backward jump. We need a second run to
			 * get the register info right in this case. Until then,
			 * assume unknown register contents.
			 */
			Done = 0;
			RC_Invalidate (&Regs);
			break;
		    }
		    if (J->RI->Out2.RegA != Regs.RegA) {
	 		Regs.RegA = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.RegX != Regs.RegX) {
			Regs.RegX = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.RegY != Regs.RegY) {
			Regs.RegY = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.SRegLo != Regs.SRegLo) {
			Regs.SRegLo = UNKNOWN_REGVAL;
		    }
		    if (J->RI->Out2.SRegHi != Regs.SRegHi) {
			Regs.SRegHi = UNKNOWN_REGVAL;
		    }
       	       	    if (J->RI->Out2.Tmp1 != Regs.Tmp1) {
			Regs.Tmp1 = UNKNOWN_REGVAL;
		    }
		    ++Entry;
		}

		/* Use this register info */
		CurrentRegs = &Regs;

	    }

	    /* Generate register info for this instruction */
	    CE_GenRegInfo (E, CurrentRegs);

	    /* Remember for the next insn if this insn was an uncondition branch */
	    WasJump = (E->Info & OF_UBRA) != 0;

	    /* Output registers for this insn are input for the next */
	    CurrentRegs = &E->RI->Out;

	    /* If this insn is a branch on zero flag, we may have more info on
	     * register contents for one of both flow directions, but only if
	     * there is a previous instruction.
	     */
	    if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) {

		/* Get the branch condition */
		bc_t BC = GetBranchCond (E->OPC);

		/* Check the previous instruction */
		switch (P->OPC) {

	 	    case OP65_ADC:
		    case OP65_AND:
		    case OP65_DEA:
		    case OP65_EOR:
		    case OP65_INA:
		    case OP65_LDA:
		    case OP65_ORA:
		    case OP65_PLA:
		    case OP65_SBC:
			/* A is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = 0;
		      	} else {
			    E->RI->Out.RegA = 0;
			}
			break;

		    case OP65_CMP:
			/* If this is an immidiate compare, the A register has
			 * the value of the compare later.
			 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegA = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegA = (unsigned char)P->Num;
		      	    }
    			}
			break;

		    case OP65_CPX:
			/* If this is an immidiate compare, the X register has
			 * the value of the compare later.
			 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegX = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegX = (unsigned char)P->Num;
			    }
			}
			break;

		    case OP65_CPY:
			/* If this is an immidiate compare, the Y register has
			 * the value of the compare later.
	 		 */
			if (CE_IsConstImm (P)) {
			    if (BC == BC_EQ) {
				E->RI->Out2.RegY = (unsigned char)P->Num;
			    } else {
				E->RI->Out.RegY = (unsigned char)P->Num;
			    }
			}
			break;

		    case OP65_DEX:
		    case OP65_INX:
		    case OP65_LDX:
		    case OP65_PLX:
			/* X is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegX = 0;
			} else {
			    E->RI->Out.RegX = 0;
		      	}
			break;

		    case OP65_DEY:
		    case OP65_INY:
    		    case OP65_LDY:
		    case OP65_PLY:
			/* X is zero in one execution flow direction */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegY = 0;
			} else {
			    E->RI->Out.RegY = 0;
			}
			break;

		    case OP65_TAX:
		    case OP65_TXA:
			/* If the branch is a beq, both A and X are zero at the
			 * branch target, otherwise they are zero at the next
			 * insn.
			 */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = E->RI->Out2.RegX = 0;
			} else {
			    E->RI->Out.RegA = E->RI->Out.RegX = 0;
			}
			break;

		    case OP65_TAY:
		    case OP65_TYA:
			/* If the branch is a beq, both A and Y are zero at the
			 * branch target, otherwise they are zero at the next
			 * insn.
			 */
			if (BC == BC_EQ) {
			    E->RI->Out2.RegA = E->RI->Out2.RegY = 0;
			} else {
			    E->RI->Out.RegA = E->RI->Out.RegY = 0;
			}
			break;

		    default:
			break;

		}
	    }
	}
    } while (!Done);

}
Beispiel #7
0
unsigned OptBNegAX2 (CodeSeg* S)
/* Search for the sequence:
 *
 *      ldy     #xx
 *      jsr     ldaxysp
 *      jsr     bnegax
 *      jne/jeq ...
 *
 * and replace it by
 *
 *      ldy     #xx
 *      lda     (sp),y
 *      dey
 *      ora     (sp),y
 *      jeq/jne ...
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[4];

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

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

            CodeEntry* X;

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

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

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

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

            /* Delete the entries no longer needed. */
            CS_DelEntries (S, I+4, 2);

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #8
0
unsigned OptSize2 (CodeSeg* S)
/* Do size optimization by using shorter code sequences, even if this
 * introduces relations between instructions. This step must be one of the
 * last steps, because it makes further work much more difficult.
 */
{
    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);

        /* Get the input registers */
        const RegContents* In = &E->RI->In;

	/* Assume we have no replacement */
	CodeEntry* X = 0;

	/* Check the instruction */
	switch (E->OPC) {

	    case OP65_LDA:
	        if (CE_IsConstImm (E)) {
		    short Val = (short) E->Num;
		    if (Val == In->RegX) {
		    	X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, E->LI);
		    } else if (Val == In->RegY) {
		    	X = NewCodeEntry (OP65_TYA, AM65_IMP, 0, 0, E->LI);
		    } else if (RegValIsKnown (In->RegA) && (CPUIsets[CPU] & CPU_ISET_65SC02) != 0) {
		    	if (Val == ((In->RegA - 1) & 0xFF)) {
		     	    X = NewCodeEntry (OP65_DEA, AM65_IMP, 0, 0, E->LI);
		    	} else if (Val == ((In->RegA + 1) & 0xFF)) {
		    	    X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI);
	      	    	}
		    }
	      	}
	        break;

	    case OP65_LDX:
	        if (CE_IsConstImm (E)) {
		    short Val = (short) E->Num;
		    if (RegValIsKnown (In->RegX) && Val == ((In->RegX - 1) & 0xFF)) {
			X = NewCodeEntry (OP65_DEX, AM65_IMP, 0, 0, E->LI);
       	       	    } else if (RegValIsKnown (In->RegX) && Val == ((In->RegX + 1) & 0xFF)) {
			X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
		    } else if (Val == In->RegA) {
			X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, E->LI);
                    }
		}
	        break;

       	    case OP65_LDY:
	        if (CE_IsConstImm (E)) {
		    short Val = (short) E->Num;
		    if (RegValIsKnown (In->RegY) && Val == ((In->RegY - 1) & 0xFF)) {
			X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, E->LI);
		    } else if (RegValIsKnown (In->RegY) && Val == ((In->RegY + 1) & 0xFF)) {
			X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, E->LI);
		    } else if (Val == In->RegA) {
			X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 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 #9
0
unsigned OptAdd1 (CodeSeg* S)
/* Search for the sequence
 *
 *      ldy     #xx
 *      jsr     ldaxysp
 *      jsr     pushax
 *      ldy     #yy
 *      jsr     ldaxysp
 *      jsr     tosaddax
 *
 * and replace it by:
 *
 *      ldy     #xx-1
 *      lda     (sp),y
 *      ldy     #yy-3
 *      clc
 *      adc     (sp),y
 *      pha
 *      ldy     #xx
 *      lda     (sp),y
 *      ldy     #yy-2
 *      adc     (sp),y
 *      tax
 *      pla
 */
{
    unsigned Changes = 0;

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

     	CodeEntry* L[6];

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

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

	    CodeEntry* X;
            const char* Arg;

       	    /* Correct the stack of the first Y register load */
	    CE_SetNumArg (L[0], L[0]->Num - 1);

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

            /* ldy #yy-3 */
	    Arg = MakeHexArg (L[3]->Num - 3);
            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
	    CS_InsertEntry (S, X, I+2);

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

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

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

            /* ldy #xx (beware: L[0] has changed) */
	    Arg = MakeHexArg (L[0]->Num + 1);
            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
	    CS_InsertEntry (S, X, I+6);

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

            /* ldy #yy-2 */
	    Arg = MakeHexArg (L[3]->Num - 2);
            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
	    CS_InsertEntry (S, X, I+8);

	    /* adc (sp),y */
	    X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
	    CS_InsertEntry (S, X, I+9);

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

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

	    /* Delete the old code */
	    CS_DelEntries (S, I+12, 5);

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

	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #10
0
unsigned OptAdd2 (CodeSeg* S)
/* Search for the sequence
 *
 *     	ldy     #xx
 *      jsr     ldaxysp
 *      ldy     #yy
 *      jsr     addeqysp
 *
 * and replace it by:
 *
 *      ldy     #xx-1
 *      lda     (sp),y
 *      ldy     #yy
 *      clc
 *      adc     (sp),y
 *      sta     (sp),y
 *      ldy     #xx
 *      lda     (sp),y
 *      ldy     #yy+1
 *      adc     (sp),y
 *      sta     (sp),y
 *
 * provided that a/x is not used later.
 */
{
    unsigned Changes = 0;

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

     	CodeEntry* L[4];

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

     	/* Check for the sequence */
	if (L[0]->OPC == OP65_LDY               &&
	    CE_IsConstImm (L[0])                &&
	    !CS_RangeHasLabel (S, I+1, 3)       &&
       	    CS_GetEntries (S, L+1, I+1, 3)   	&&
	    CE_IsCallTo (L[1], "ldaxysp")       &&
       	    L[2]->OPC == OP65_LDY               &&
	    CE_IsConstImm (L[2])                &&
       	    CE_IsCallTo (L[3], "addeqysp")      &&
       	    (GetRegInfo (S, I+4, REG_AX) & REG_AX) == 0) {

	    /* Insert new code behind the addeqysp */
	    const char* Arg;
	    CodeEntry* X;

	    /* ldy     #xx-1 */
	    Arg = MakeHexArg (L[0]->Num-1);
	    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI);
	    CS_InsertEntry (S, X, I+4);

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

	    /* ldy     #yy */
	    X = NewCodeEntry (OP65_LDY, AM65_IMM, L[2]->Arg, 0, L[2]->LI);
	    CS_InsertEntry (S, X, I+6);

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

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

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

	    /* ldy     #xx */
	    X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
	    CS_InsertEntry (S, X, I+10);

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

	    /* ldy     #yy+1 */
	    Arg = MakeHexArg (L[2]->Num+1);
	    X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[2]->LI);
	    CS_InsertEntry (S, X, I+12);

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

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

	    /* Delete the old code */
	    CS_DelEntries (S, I, 4);

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

	}

	/* Next entry */
	++I;

    }

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