Ejemplo n.º 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;
}
Ejemplo n.º 2
0
void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos)
/* Move a range of entries from one position to another. Start is the index
 * of the first entry to move, Count is the number of entries and NewPos is
 * the index of the target entry. The entry with the index Start will later
 * have the index NewPos. All entries with indices NewPos and above are
 * moved to higher indices. If the code block is moved to the end of the
 * current code, and if pending labels exist, these labels will get attached
 * to the first instruction of the moved block (the first one after the
 * current code end)
 */
{
    /* Transparently handle an empty range */
    if (Count == 0) {
        return;
    }

    /* If NewPos is at the end of the code segment, move any labels from the
     * label pool to the first instruction of the moved range.
     */
    if (NewPos == CS_GetEntryCount (S)) {
	CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start));
    }

    /* Move the code block to the destination */
    CollMoveMultiple (&S->Entries, Start, Count, NewPos);
}
Ejemplo n.º 3
0
int CS_RangeHasLabel (CodeSeg* S, unsigned Start, unsigned Count)
/* Return true if any of the code entries in the given range has a label
 * attached. If the code segment does not span the given range, check the
 * possible span instead.
 */
{
    unsigned EntryCount = CS_GetEntryCount(S);

    /* Adjust count. We expect at least Start to be valid. */
    CHECK (Start < EntryCount);
    if (Start + Count > EntryCount) {
    	Count = EntryCount - Start;
    }

    /* Check each entry. Since we have validated the index above, we may
     * use the unchecked access function in the loop which is faster.
     */
    while (Count--) {
	const CodeEntry* E = CollAtUnchecked (&S->Entries, Start++);
	if (CE_HasLabel (E)) {
	    return 1;
	}
    }

    /* No label in the complete range */
    return 0;
}
Ejemplo n.º 4
0
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted)
/* Determine register usage information for the instructions starting at the
** given index.
*/
{
    CodeEntry*      E;
    Collection      Visited;    /* Visited entries */
    unsigned        R;

    /* Get the code entry for the given index */
    if (Index >= CS_GetEntryCount (S)) {
        /* There is no such code entry */
        return REG_NONE;
    }
    E = CS_GetEntry (S, Index);

    /* Initialize the data structure used to collection information */
    InitCollection (&Visited);

    /* Call the recursive subfunction */
    R = GetRegInfo1 (S, E, Index, &Visited, REG_NONE, REG_NONE, Wanted);

    /* Delete the line collection */
    DoneCollection (&Visited);

    /* Return the registers used */
    return R;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
void CS_FreeRegInfo (CodeSeg* S)
/* Free register infos for all instructions */
{
    unsigned I;
    for (I = 0; I < CS_GetEntryCount (S); ++I) {
        CE_FreeRegInfo (CS_GetEntry(S, I));
    }
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
/* Delete all entries including the given one */
{
    /* Get the number of entries in this segment */
    unsigned Count = CS_GetEntryCount (S);

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

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

       	/* Check if this entry has a label reference */
       	if (E->JumpTo) {
       	    /* If the label is a label in the label pool and this is the last
       	     * reference to the label, remove the label from the pool.
       	     */
       	    CodeLabel* L = E->JumpTo;
       	    int Index = CollIndex (&S->Labels, L);
       	    if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
       	     	/* Delete it from the pool */
       	     	CollDelete (&S->Labels, Index);
       	    }

	    /* 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. Don't delete the label in this case, just make it
     * ownerless and move it to the label pool.
     */
    C = Count;
    while (Last < C--) {

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

    	/* Check if this entry has a label attached */
    	if (CE_HasLabel (E)) {
	    /* Move the labels to the pool and clear the owner pointer */
	    CS_MoveLabelsToPool (S, E);
	}

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

	/* Delete the entry itself */
	FreeCodeEntry (E);
    }
}
Ejemplo n.º 12
0
unsigned OptCmp1 (CodeSeg* S)
/* Search for the sequence
 *
 *  	ldx	xx
 *  	stx	tmp1
 *  	ora	tmp1
 *
 * and replace it by
 *
 *  	ora	xx
 */
{
    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_LDX               &&
	    !CS_RangeHasLabel (S, I+1, 2)       &&
	    CS_GetEntries (S, L+1, I+1, 2)	&&
       	    L[1]->OPC == OP65_STX	  	&&
	    strcmp (L[1]->Arg, "tmp1") == 0     &&
	    L[2]->OPC == OP65_ORA	    	&&
	    strcmp (L[2]->Arg, "tmp1") == 0) {

            CodeEntry* X;

	    /* Insert the ora instead */
            X = NewCodeEntry (OP65_ORA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
	    CS_InsertEntry (S, X, I);

	    /* Remove all other instructions */
	    CS_DelEntries (S, I+1, 3);

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

	}

	/* Next entry */
	++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Ejemplo n.º 13
0
unsigned OptStore4 (CodeSeg* S)
/* Search for the sequence
**
**      sta     xx
**      stx     yy
**      lda     xx
**      ldx     yy
**
** and remove the useless load, provided that the next insn doesn't use flags
** from the load.
*/
{
    unsigned Changes = 0;

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

        CodeEntry* L[5];

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

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

            /* 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;
}
Ejemplo n.º 14
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;
}
Ejemplo n.º 15
0
void CS_DelEntry (CodeSeg* S, unsigned Index)
/* Delete an entry from the code segment. This includes moving any associated
 * labels, removing references to labels and even removing the referenced labels
 * if the reference count drops to zero.
 * Note: Labels are moved forward if possible, that is, they are moved to the
 * next insn (not the preceeding one).
 */
{
    /* Get the code entry for the given index */
    CodeEntry* E = CS_GetEntry (S, Index);

    /* If the entry has a labels, we have to move this label to the next insn.
     * If there is no next insn, move the label into the code segement label
     * pool. The operation is further complicated by the fact that the next
     * insn may already have a label. In that case change all reference to
     * this label and delete the label instead of moving it.
     */
    unsigned Count = CE_GetLabelCount (E);
    if (Count > 0) {

     	/* The instruction has labels attached. Check if there is a next
     	 * instruction.
     	 */
     	if (Index == CS_GetEntryCount (S)-1) {

     	    /* No next instruction, move to the codeseg label pool */
     	    CS_MoveLabelsToPool (S, E);

     	} else {

     	    /* There is a next insn, get it */
     	    CodeEntry* N = CS_GetEntry (S, Index+1);

     	    /* Move labels to the next entry */
     	    CS_MoveLabels (S, E, N);

     	}
    }

    /* If this insn references a label, remove the reference. And, if the
     * the reference count for this label drops to zero, remove this label.
     */
    if (E->JumpTo) {
       	/* Remove the reference */
       	CS_RemoveLabelRef (S, E);
    }

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

    /* Delete the instruction itself */
    FreeCodeEntry (E);
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
unsigned OptSub1 (CodeSeg* S)
/* Search for the sequence
**
**      sbc     ...
**      bcs     L
**      dex
** L:
**
** and remove the handling of the high byte if X is not used later.
*/
{
    unsigned Changes = 0;

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

        CodeEntry* L[3];

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Ejemplo n.º 20
0
Archivo: codeopt.c Proyecto: coyxc/cc65
static unsigned OptLoad1 (CodeSeg* S)
/* Search for a call to ldaxysp where X is not used later and replace it by
** a load of just the A register.
*/
{
    unsigned I;
    unsigned Changes = 0;

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

        CodeEntry* E;

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

        /* Check for the sequence */
        if (CE_IsCallTo (E, "ldaxysp")          &&
            RegValIsKnown (E->RI->In.RegY)      &&
            !RegXUsed (S, I+1)) {

            CodeEntry* X;

            /* Reload the Y register */
            const char* Arg = MakeHexArg (E->RI->In.RegY - 1);
            X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
            CS_InsertEntry (S, X, I+1);

            /* Load from stack */
            X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI);
            CS_InsertEntry (S, X, I+2);

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Ejemplo n.º 21
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;
}
Ejemplo n.º 22
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;
}
Ejemplo n.º 23
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;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
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;
}
Ejemplo n.º 26
0
Archivo: codeopt.c Proyecto: coyxc/cc65
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;
}
Ejemplo n.º 27
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;
}
Ejemplo n.º 28
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;
}
Ejemplo n.º 29
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;
}
Ejemplo n.º 30
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;
}