Beispiel #1
0
unsigned OptBNegA2 (CodeSeg* S)
/* Check for
 *
 *      lda     ..
 *      jsr     bnega
 *      jeq/jne ..
 *
 * Adjust the conditional branch and remove the call to the subroutine.
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[2];

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

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #2
0
unsigned OptBNegAX3 (CodeSeg* S)
/* Search for the sequence:
 *
 *      lda     xx
 *      ldx     yy
 *      jsr     bnegax
 *      jne/jeq ...
 *
 * and replace it by
 *
 *      lda     xx
 *      ora     xx+1
 *      jeq/jne ...
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[3];

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

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

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #3
0
unsigned OptBNegA1 (CodeSeg* S)
/* Check for
 *
 *      ldx     #$00
 *      lda     ..
 *      jsr     bnega
 *
 * Remove the ldx if the lda does not use it.
 */
{
    unsigned Changes = 0;

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

        CodeEntry* L[2];

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #4
0
unsigned OptSub1 (CodeSeg* S)
/* Search for the sequence
**
**      sbc     ...
**      bcs     L
**      dex
** L:
**
** and remove the handling of the high byte if X is not used later.
*/
{
    unsigned Changes = 0;

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

        CodeEntry* L[3];

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #5
0
CodeLabel* CS_GenLabel (CodeSeg* S, struct CodeEntry* E)
/* If the code entry E does already have a label, return it. Otherwise
 * create a new label, attach it to E and return it.
 */
{
    CodeLabel* L;

    if (CE_HasLabel (E)) {

	/* Get the label from this entry */
	L = CE_GetLabel (E, 0);

    } else {

	/* Get a new name */
	const char* Name = LocalLabelName (GetLocalLabel ());

	/* Generate the hash over the name */
	unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;

	/* Create a new label */
	L = CS_NewCodeLabel (S, Name, Hash);

	/* Attach this label to the code entry */
	CE_AttachLabel (E, L);

    }

    /* Return the label */
    return L;
}
Beispiel #6
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;
}
Beispiel #7
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 #8
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 #9
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);
    }
}
Beispiel #10
0
static int IsImmCmp16 (CodeEntry** L)
/* Check if the instructions at L are an immidiate compare of a/x:
 *
 *
 */
{
    return (L[0]->OPC == OP65_CPX                              &&
	    L[0]->AM == AM65_IMM                               &&
	    (L[0]->Flags & CEF_NUMARG) != 0                    &&
	    !CE_HasLabel (L[0])                                &&
	    (L[1]->OPC == OP65_JNE || L[1]->OPC == OP65_BNE)   &&
       	    L[1]->JumpTo != 0                                  &&
	    !CE_HasLabel (L[1])                                &&
       	    L[2]->OPC == OP65_CMP                              &&
	    L[2]->AM == AM65_IMM                               &&
	    (L[2]->Flags & CEF_NUMARG) != 0                    &&
	    (L[3]->Info & OF_CBRA) != 0                        &&
	    L[3]->JumpTo != 0                                  &&
	    (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
}
Beispiel #11
0
unsigned OptCmp7 (CodeSeg* S)
/* Search for a sequence ldx/txa/branch and remove the txa if A is not
 * used later.
 */
{
    unsigned Changes = 0;

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

       	CodeEntry* L[2];

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

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

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

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

	}

  	/* Next entry */
	++I;

    }

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

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

        CodeEntry* L[3];

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

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

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

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #13
0
void CS_MoveLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
/* Move all labels from Old to New. The routine will move the labels itself
 * if New does not have any labels, and move references if there is at least
 * a label for new. If references are moved, the old label is deleted
 * afterwards.
 */
{
    /* Get the number of labels to move */
    unsigned OldLabelCount = CE_GetLabelCount (Old);

    /* Does the new entry have itself a label? */
    if (CE_HasLabel (New)) {

	/* The new entry does already have a label - move references */
	CodeLabel* NewLabel = CE_GetLabel (New, 0);
	while (OldLabelCount--) {

	    /* Get the next label */
	    CodeLabel* OldLabel = CE_GetLabel (Old, OldLabelCount);

	    /* Move references */
	    CL_MoveRefs (OldLabel, NewLabel);

	    /* Delete the label */
	    CS_DelLabel (S, OldLabel);

     	}

    } else {

	/* The new entry does not have a label, just move them */
	while (OldLabelCount--) {

	    /* Move the label to the new entry */
	    CE_MoveLabel (CE_GetLabel (Old, OldLabelCount), New);

	}

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

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

       	CodeEntry* L[5];

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

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

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

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

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

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

     	/* Next entry */
	++I;
    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #17
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 #18
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 #19
0
unsigned OptCmp4 (CodeSeg* S)
/* Search for
 *
 *  	lda	x
 *  	ldx	y
 *  	cpx 	#a
 *  	bne 	L1
 *  	cmp 	#b
 * L1: 	jne/jeq	L2
 *
 * If a is zero, we may remove the compare. If a and b are both zero, we may
 * replace it by the sequence
 *
 *  	lda 	x
 *  	ora 	x+1
 *  	jne/jeq ...
 *
 * L1 may be either the label at the branch instruction, or the target label
 * of this instruction.
 */
{
    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_GetEntries (S, L, I+1, 5)     &&
	    L[0]->OPC == OP65_LDX            &&
	    !CE_HasLabel (L[0])              &&
      	    IsImmCmp16 (L+1)                 &&
	    !RegAXUsed (S, I+6)) {

      	    if ((L[4]->Info & OF_FBRA) != 0 && L[1]->Num == 0 && L[3]->Num == 0) {
		/* The value is zero, we may use the simple code version. */
		CE_ReplaceOPC (L[0], OP65_ORA);
		CS_DelEntries (S, I+2, 3);
       	    } else {
		/* Move the lda instruction after the first branch. This will
		 * improve speed, since the load is delayed after the first
		 * test.
		 */
		CS_MoveEntry (S, I, I+4);

		/* We will replace the ldx/cpx by lda/cmp */
	    	CE_ReplaceOPC (L[0], OP65_LDA);
		CE_ReplaceOPC (L[1], OP65_CMP);

		/* Beware: If the first LDA instruction had a label, we have
	     	 * to move this label to the top of the sequence again.
		 */
		if (CE_HasLabel (E)) {
		    CS_MoveLabels (S, E, L[0]);
		}

	    }

	    ++Changes;
	}

	/* Next entry */
	++I;

    }

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

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

        CodeEntry* L[2];

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

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

            CodeEntry* X;

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

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

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

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

        CodeEntry* L[3];

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

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

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

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

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

                /* We had changes */
                ++Changes;

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

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

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

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

        /* Next entry */
        ++I;

    }

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

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

        CodeEntry* L[5];

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

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

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

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

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

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

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

        }

        /* Next entry */
        ++I;

    }

    /* Return the number of changes made */
    return Changes;
}
Beispiel #23
0
unsigned 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 #24
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;
}