Beispiel #1
0
unsigned OptPush2 (CodeSeg* S)
/* A sequence
 *
 *     jsr     ldaxidx
 *     jsr     pushax
 *
 * may get replaced by
 *
 *     jsr     pushwidx
 *
 */
{
    unsigned I;
    unsigned Changes = 0;

    /* Generate register info */
    CS_GenRegInfo (S);

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

     	CodeEntry* L[2];

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

     	/* Check for the sequence */
       	if (CE_IsCallTo (L[0], "ldaxidx")               &&
            (L[1] = CS_GetNextEntry (S, I)) != 0        &&
            !CE_HasLabel (L[1])                         &&
       	    CE_IsCallTo (L[1], "pushax")) {

	    /* Insert new code behind the pushax */
	    CodeEntry* X;

	    /* jsr pushwidx */
	    X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwidx", 0, L[1]->LI);
	    CS_InsertEntry (S, X, I+2);

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

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

	}

	/* Next entry */
	++I;

    }

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

    /* 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 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 #4
0
static unsigned OptStackPtrOps (CodeSeg* S)
/* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
** known cases!
*/
{
    unsigned Changes = 0;
    unsigned I;

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

        unsigned Dec1;
        unsigned Dec2;
        const CodeEntry* N;

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

        /* Check for decspn or subysp */
        if (E->OPC == OP65_JSR                          &&
            (Dec1 = IsDecSP (E)) > 0                    &&
            (N = CS_GetNextEntry (S, I)) != 0           &&
            (Dec2 = IsDecSP (N)) > 0                    &&
            (Dec1 += Dec2) <= 255                       &&
            !CE_HasLabel (N)) {

            CodeEntry* X;
            char Buf[20];

            /* We can combine the two */
            if (Dec1 <= 8) {
                /* Insert a call to decsp */
                xsprintf (Buf, sizeof (Buf), "decsp%u", Dec1);
                X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, N->LI);
                CS_InsertEntry (S, X, I+2);
            } else {
                /* Insert a call to subysp */
                const char* Arg = MakeHexArg (Dec1);
                X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
                CS_InsertEntry (S, X, I+2);
                X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, N->LI);
                CS_InsertEntry (S, X, I+3);
            }

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

            /* Regenerate register info */
            CS_GenRegInfo (S);

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

        } else {

            /* Next entry */
            ++I;
        }

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #5
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 #6
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 #7
0
static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
/* Helper function for the replacement of routines that return a boolean
 * followed by a conditional jump. Instead of the boolean value, the condition
 * codes are evaluated directly.
 * I is the index of the conditional branch, the sequence is already checked
 * to be correct.
 */
{
    CodeEntry* N;
    CodeLabel* L;

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

    /* Replace the conditional branch */
    switch (Cond) {

	case CMP_EQ:
	    CE_ReplaceOPC (E, OP65_JEQ);
	    break;

	case CMP_NE:
	    CE_ReplaceOPC (E, OP65_JNE);
	    break;

	case CMP_GT:
	    /* Replace by
	     *     beq @L
	     *     jpl Target
	     * @L: ...
	     */
	    if ((N = CS_GetNextEntry (S, I)) == 0) {
	    	/* No such entry */
	    	Internal ("Invalid program flow");
	    }
	    L = CS_GenLabel (S, N);
	    N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
	    CS_InsertEntry (S, N, I);
	    CE_ReplaceOPC (E, OP65_JPL);
	    break;

	case CMP_GE:
	    CE_ReplaceOPC (E, OP65_JPL);
	    break;

	case CMP_LT:
	    CE_ReplaceOPC (E, OP65_JMI);
	    break;

	case CMP_LE:
	    /* Replace by
	     * 	   jmi Target
	     *     jeq Target
	     */
	    CE_ReplaceOPC (E, OP65_JMI);
	    L = E->JumpTo;
	    N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
	    CS_InsertEntry (S, N, I+1);
	    break;

	case CMP_UGT:
	    /* Replace by
	     *     beq @L
	     *     jcs Target
	     * @L: ...
	     */
	    if ((N = CS_GetNextEntry (S, I)) == 0) {
	       	/* No such entry */
	       	Internal ("Invalid program flow");
	    }
	    L = CS_GenLabel (S, N);
	    N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
	    CS_InsertEntry (S, N, I);
	    CE_ReplaceOPC (E, OP65_JCS);
	    break;

	case CMP_UGE:
	    CE_ReplaceOPC (E, OP65_JCS);
	    break;

	case CMP_ULT:
	    CE_ReplaceOPC (E, OP65_JCC);
	    break;

	case CMP_ULE:
	    /* Replace by
	     * 	   jcc Target
	     *     jeq Target
	     */
	    CE_ReplaceOPC (E, OP65_JCC);
	    L = E->JumpTo;
	    N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
	    CS_InsertEntry (S, N, I+1);
	    break;

	default:
	    Internal ("Unknown jump condition: %d", Cond);

    }

}
Beispiel #8
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 #9
0
unsigned OptPush1 (CodeSeg* S)
/* Given a sequence
 *
 *     jsr     ldaxysp
 *     jsr     pushax
 *
 * If a/x are not used later, and Y is known, replace that by
 *
 *     ldy     #xx+2
 *     jsr     pushwysp
 *
 * saving 3 bytes and several cycles.
 */
{
    unsigned I;
    unsigned Changes = 0;

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

     	CodeEntry* L[2];

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

     	/* Check for the sequence */
       	if (CE_IsCallTo (L[0], "ldaxysp")               &&
            RegValIsKnown (L[0]->RI->In.RegY)           &&
            L[0]->RI->In.RegY < 0xFE                    &&
            (L[1] = CS_GetNextEntry (S, I)) != 0        &&
            !CE_HasLabel (L[1])                         &&
       	    CE_IsCallTo (L[1], "pushax")                &&
       	    !RegAXUsed (S, I+2)) {

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

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

	    /* jsr pushwysp */
	    X = NewCodeEntry (OP65_JSR, AM65_ABS, "pushwysp", 0, L[1]->LI);
	    CS_InsertEntry (S, X, I+3);

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

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

	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #10
0
void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
/* Delete all entries between first and last, both inclusive. The function
 * can only handle basic blocks (First is the only entry, Last the only exit)
 * and no open labels. It will call FAIL if any of these preconditions are
 * violated.
 */
{
    unsigned   I;
    CodeEntry* FirstEntry;

    /* Do some sanity checks */
    CHECK (First <= Last && Last < CS_GetEntryCount (S));

    /* If Last is actually the last insn, call CS_DelCodeAfter instead, which
     * is more flexible in this case.
     */
    if (Last == CS_GetEntryCount (S) - 1) {
        CS_DelCodeAfter (S, First);
        return;
    }

    /* Get the first entry and check if it has any labels. If it has, move
     * them to the insn following Last. If Last is the last insn of the code
     * segment, make them ownerless and move them to the label pool.
     */
    FirstEntry = CS_GetEntry (S, First);
    if (CE_HasLabel (FirstEntry)) {
        /* Get the entry following last */
        CodeEntry* FollowingEntry = CS_GetNextEntry (S, Last);
        if (FollowingEntry) {
            /* There is an entry after Last - move the labels */
            CS_MoveLabels (S, FirstEntry, FollowingEntry);
        } else {
     	    /* Move the labels to the pool and clear the owner pointer */
     	    CS_MoveLabelsToPool (S, FirstEntry);
        }
    }

    /* First pass: Delete all references to labels. If the reference count
     * for a label drops to zero, delete it.
     */
    for (I = Last; I >= First; --I) {

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

       	/* Check if this entry has a label reference */
       	if (E->JumpTo) {

       	    /* If the label is a label in the label pool, this is an error */
       	    CodeLabel* L = E->JumpTo;
       	    CHECK (CollIndex (&S->Labels, L) < 0);

 	    /* Remove the reference to the label */
 	    CS_RemoveLabelRef (S, E);
 	}
    }

    /* Second pass: Delete the instructions. If a label attached to an
     * instruction still has references, it must be references from outside
     * the deleted area, which is an error.
     */
    for (I = Last; I >= First; --I) {

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

       	/* Check if this entry has a label attached */
    	CHECK (!CE_HasLabel (E));

	/* Delete the pointer to the entry */
	CollDelete (&S->Entries, I);

	/* Delete the entry itself */
	FreeCodeEntry (E);
    }
}
Beispiel #11
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 #12
0
unsigned OptShift1 (CodeSeg* S)
/* A call to the shlaxN routine may get replaced by one or more asl insns
 * if the value of X is not used later. If X is used later, but it is zero
 * on entry and it's a shift by one, it may get replaced by:
 *
 *      asl     a
 *      bcc     L1
 *      inx
 *  L1:
 *
 */
{
    unsigned Changes = 0;
    unsigned I;

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

        unsigned   Shift;
        CodeEntry* N;
        CodeEntry* X;
        CodeLabel* L;

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

     	/* Check for the sequence */
	if (E->OPC == OP65_JSR                          &&
            (Shift = GetShift (E->Arg)) != SHIFT_NONE   &&
            SHIFT_DIR (Shift) == SHIFT_DIR_LEFT) {


            unsigned Count = SHIFT_COUNT (Shift);
            if (!RegXUsed (S, I+1)) {

                if (Count == SHIFT_COUNT_Y) {

                    CodeLabel* L;

                    if (S->CodeSizeFactor < 200) {
                        goto NextEntry;
                    }

                    /* Change into
                     *
                     * L1:  asl     a
                     *      dey
                     *      bpl     L1
                     *      ror     a
                     */

                    /* asl a */
                    X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
                    CS_InsertEntry (S, X, I+1);
                    L = CS_GenLabel (S, X);

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

                    /* bpl L1 */
                    X = NewCodeEntry (OP65_BPL, AM65_BRA, L->Name, L, E->LI);
                    CS_InsertEntry (S, X, I+3);

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

                } else {
                    /* Insert shift insns */
                    while (Count--) {
                        X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
                        CS_InsertEntry (S, X, I+1);
                    }
                }

            } else if (E->RI->In.RegX == 0              &&
                       Count == 1                       &&
                       (N = CS_GetNextEntry (S, I)) != 0) {

                /* asl a */
                X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
                CS_InsertEntry (S, X, I+1);

                /* bcc L1 */
                L = CS_GenLabel (S, N);
                X = NewCodeEntry (OP65_BCC, AM65_BRA, L->Name, L, E->LI);
                CS_InsertEntry (S, X, I+2);

                /* inx */
                X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, E->LI);
                CS_InsertEntry (S, X, I+3);

            } else {

                /* We won't handle this one */
                goto NextEntry;

            }

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

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

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

    }

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